diff --git a/CMakeLists.txt b/CMakeLists.txt index 422b8f9..95428c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,297 +1,298 @@ #----------------------------------------------------------------------------- # This is the root RTToolbox CMakeList file. #----------------------------------------------------------------------------- PROJECT(RTToolbox) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11.2) IF(CMAKE_BACKWARDS_COMPATIBILITY GREATER 2.8.11.2) SET(CMAKE_BACKWARDS_COMPATIBILITY 2.8.11.2 CACHE STRING "Latest version of CMake when this project was released." FORCE) ENDIF(CMAKE_BACKWARDS_COMPATIBILITY GREATER 2.8.11.2) # RTToolbox version number. SET(RTToolbox_VERSION_MAJOR "4") SET(RTToolbox_VERSION_MINOR "1") SET(RTToolbox_VERSION_PATCH "0") # Version string should not include patch level. The major.minor is # enough to distinguish available features of the toolbox. SET(RTToolbox_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}") SET(RTToolbox_FULL_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}") # default build type SET(CMAKE_BUILD_TYPE Release) MARK_AS_ADVANCED(BUILD_SHARED_LIBS) IF (WIN32) IF (MSVC_VERSION LESS 1600) MESSAGE(FATAL_ERROR "RTToolbox requires at least Visual Studio 2010.") ENDIF(MSVC_VERSION LESS 1600) add_definitions(-D_SCL_SECURE_NO_WARNINGS) ELSE (WIN32) IF (CMAKE_COMPILER_IS_GNUCC) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0) MESSAGE(AUTHOR_WARNING "RTToolbox was only tested with GCC 4.6 and GCC 4.9. You are using GCC " ${CMAKE_CXX_COMPILER_VERSION} ". This compiler version might not work.") ENDIF() ENDIF() ENDIF(WIN32) IF (NOT (CMAKE_MAJOR_VERSION LESS 3)) IF(COMMAND CMAKE_POLICY) # Enable old CMake behaviour when dealing with export_library_dependencies(). # This is necessary to avoid warnings in CMake versions # greater than 3.0 # See http://www.cmake.org/cmake/help/v3.0/policy/CMP0033.html CMAKE_POLICY(SET CMP0033 OLD) ENDIF(COMMAND CMAKE_POLICY) ENDIF() #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(cmake/MacroParseArguments.cmake) include(cmake/rttbMacroCreateModuleConf.cmake) include(cmake/rttbMacroCreateModule.cmake) include(cmake/rttbMacroCreateApplication.cmake) include(cmake/rttbMacroCheckModule.cmake) include(cmake/rttbMacroUseModule.cmake) include(cmake/rttbMacroCreateTestModule.cmake) include(cmake/rttbFunctionOrganizeSources.cmake) +include(cmake/rttbMacroCreateApplicationTests.cmake) #----------------------------------------------------------------------------- # Basis config RTTB module infrastructure #----------------------------------------------------------------------------- set(RTTB_MODULES_CONF_DIR ${RTToolbox_BINARY_DIR}/modulesConf CACHE INTERNAL "Modules Conf") set(RTTB_MODULES_PACKAGE_DEPENDS_DIR ${RTToolbox_SOURCE_DIR}/cmake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${RTTB_MODULES_PACKAGE_DEPENDS_DIR}) #----------------------------------------------------------------------------- # Testing setup # Configure Dart testing support. This should be done before any # MESSAGE(FATAL_ERROR ...) commands are invoked. #----------------------------------------------------------------------------- SET(CTEST_NEW_FORMAT 1) INCLUDE(CTest) ENABLE_TESTING() IF(BUILD_TESTING) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/RemoveTemporaryFiles.cmake.in ${RTToolbox_BINARY_DIR}/cmake/RemoveTemporaryFiles.cmake @ONLY IMMEDIATE) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/rttbSampleBuildTest.cmake.in ${RTToolbox_BINARY_DIR}/cmake/rttbSampleBuildTest.cmake @ONLY) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/CTestCustom.ctest.in ${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest @ONLY) FILE(WRITE ${RTToolbox_BINARY_DIR}/CTestCustom.cmake "INCLUDE(\"${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest\")\n") SET(BUILDNAME "${BUILDNAME}" CACHE STRING "Name of build on the dashboard") MARK_AS_ADVANCED(BUILDNAME) ENDIF(BUILD_TESTING) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- IF(NOT LIBRARY_OUTPUT_PATH) SET (LIBRARY_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") ENDIF(NOT LIBRARY_OUTPUT_PATH) IF(NOT EXECUTABLE_OUTPUT_PATH) SET (EXECUTABLE_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") ENDIF(NOT EXECUTABLE_OUTPUT_PATH) MARK_AS_ADVANCED(EXECUTABLE_OUTPUT_PATH LIBRARY_OUTPUT_PATH) MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) SET(RTToolbox_LIBRARY_PATH "${LIBRARY_OUTPUT_PATH}") SET(RTToolbox_EXECUTABLE_PATH "${EXECUTABLE_OUTPUT_PATH}") #----------------------------------------------------------------------------- # Find Doxygen. #----------------------------------------------------------------------------- FIND_PROGRAM(DOXYGEN_EXECUTABLE "doxygen") #----------------------------------------------------------------------------- # Installation vars. # RTToolbox_INSTALL_BIN_DIR - binary dir (executables) # RTToolbox_INSTALL_LIB_DIR - library dir (libs) # RTToolbox_INSTALL_INCLUDE_DIR - include dir (headers) # RTToolbox_INSTALL_NO_DEVELOPMENT - do not install development files # RTToolbox_INSTALL_NO_RUNTIME - do not install runtime files # RTToolbox_INSTALL_NO_DOCUMENTATION - do not install documentation files # Remark: needs directory are stored with no leading slash (CMake 2.4 and newer) #----------------------------------------------------------------------------- IF(NOT RTTOOLBOX_INSTALL_BIN_DIR) SET(RTTOOLBOX_INSTALL_BIN_DIR "bin") ENDIF(NOT RTTOOLBOX_INSTALL_BIN_DIR) IF(NOT RTTOOLBOX_INSTALL_LIB_DIR) SET(RTTOOLBOX_INSTALL_LIB_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_LIB_DIR) IF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) SET(RTTOOLBOX_INSTALL_PACKAGE_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) IF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) SET(RTTOOLBOX_INSTALL_INCLUDE_DIR "include") ENDIF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_DEVELOPMENT 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) IF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) SET(RTTOOLBOX_INSTALL_NO_RUNTIME 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) IF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_DOCUMENTATION 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES) IF(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ELSE(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ENDIF(RTTOOLBOX_BUILD_SHARED_LIBS) # set RTToolbox_DIR so it can be used by subprojects SET(RTToolbox_DIR "${CMAKE_BINARY_DIR}" CACHE INTERNAL "RTToolbox dir to be used by subprojects") #----------------------------------------------------------------------------- # DCMTK MT-Flag treat #----------------------------------------------------------------------------- option(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT "This enforces the whole RTToolbox to be compiled with /MT,/MTd to be compliant with DCMTK" OFF) string(FIND ${CMAKE_GENERATOR} "Visual Studio" RTTB_VS_USED) if(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT AND RTTB_VS_USED EQUAL 0) message(STATUS "Enforce DCMTK compliance: /MT and /MTd flags are used") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) message(STATUS "CMAKE_C_FLAGS_DEBUG set to: ${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) message(STATUS "CMAKE_C_FLAGS_RELEASE set to: ${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_C_FLAGS_MINSIZEREL set to: ${CMAKE_C_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_C_FLAGS_RELWITHDEBINFO set to: ${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) message(STATUS "CMAKE_CXX_FLAGS_DEBUG set to: ${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) message(STATUS "CMAKE_CXX_FLAGS_RELEASE set to: ${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_CXX_FLAGS_MINSIZEREL set to: ${CMAKE_CXX_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO set to: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") endif() #----------------------------------------------------------------------------- # Advanced RTToolbox configuration #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # RTToolbox build configuration options. IF (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." OFF) ELSE (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." ON) ENDIF (WIN32) IF(BUILD_SHARED_LIBS) IF(WIN32) MESSAGE(FATAL_ERROR "RTToolbox currently does not support a dynamic build on Windows. We are working on that...") ENDIF(WIN32) ELSE(BUILD_SHARED_LIBS) IF(UNIX) MESSAGE(FATAL_ERROR "RTToolbox currently does not support a static build on unix like systems. We are working on that...") ENDIF(UNIX) ENDIF(BUILD_SHARED_LIBS) SET(RTToolbox_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) IF(NOT RTToolbox_NO_LIBRARY_VERSION) # This setting of SOVERSION assumes that any API change # will increment either the minor or major version number of RTToolbox. SET(RTToolbox_LIBRARY_PROPERTIES VERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}" SOVERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}" ) ENDIF(NOT RTToolbox_NO_LIBRARY_VERSION) #----------------------------------------------------------------------------- # Configure files with settings for use by the build. # #----------------------------------------------------------------------------- CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/RTToolboxConfigure.h.in ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h DESTINATION ${RTTOOLBOX_INSTALL_INCLUDE_DIR} COMPONENT Development) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) #----------------------------------------------------------------------------- # The entire RTToolbox tree should use the same include path #----------------------------------------------------------------------------- #Default include dir. Others dirs will be defined by activated subprojects INCLUDE_DIRECTORIES(${RTToolbox_BINARY_DIR}) LINK_DIRECTORIES(${LIBARY_OUTPUT_PATH}) #Prepare the correct target information export by the subprojects SET(RTToolbox_TARGETS_FILE "${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake") FILE(WRITE ${RTToolbox_TARGETS_FILE} "# Generated by CMake, do not edit!") #----------------------------------------------------------------------------- # Dispatch the build into the proper subdirectories. #----------------------------------------------------------------------------- MESSAGE (STATUS "generating Project RTToolbox") ADD_SUBDIRECTORY (code) ADD_SUBDIRECTORY (demoapps) IF (BUILD_TESTING) ADD_SUBDIRECTORY (testing) ENDIF (BUILD_TESTING) ADD_SUBDIRECTORY (documentation) #----------------------------------------------------------------------------- # Help other projects use RTToolbox. #----------------------------------------------------------------------------- EXPORT(PACKAGE RTToolbox) # Copy the UseRTToolbox.cmake file to the binary tree for backward compatability. CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/UseRTToolbox.cmake.in ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake COPYONLY IMMEDIATE) # Save library dependencies. EXPORT_LIBRARY_DEPENDENCIES(${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake) # Create the RTToolboxConfig.cmake file containing the RTToolbox configuration. INCLUDE (${RTToolbox_SOURCE_DIR}/rttbGenerateRTToolboxConfig.cmake) IF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfig.cmake ${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake ${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake DESTINATION ${RTTOOLBOX_INSTALL_PACKAGE_DIR} COMPONENT Development ) ENDIF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) diff --git a/cmake/rttbMacroCreateApplicationTests.cmake b/cmake/rttbMacroCreateApplicationTests.cmake new file mode 100644 index 0000000..2bd5b89 --- /dev/null +++ b/cmake/rttbMacroCreateApplicationTests.cmake @@ -0,0 +1,76 @@ +################################################################## +# +# RTTB_CREATE_APPLICATION_TESTS +# +#! Creates tests for a APP. +#! +#! USAGE: +#! +#! \code +#! RTTB_CREATE_APPLICATION_TESTS( +#! [INCLUDE_DIRS ] +#! [DEPENDS ] +#! [PACKAGE_DEPENDS ] +#! \endcode +#! +#! \param APP_NAME_IN The name for the new APP +# +################################################################## + +MACRO(RTTB_CREATE_APPLICATION_TESTS APP_NAME_IN) + MACRO_PARSE_ARGUMENTS(APP + "INCLUDE_DIRS;DEPENDS;PACKAGE_DEPENDS;ADDITIONAL_LIBS" + "HEADER_TESTS" + ${ARGN}) + + SET(APP_NAME "rttb${APP_NAME_IN}Tests") + + IF(BUILD_TESTING) + MESSAGE(STATUS "configuring Tests ${APP_NAME}...") + # first of all we check for the dependencies + RTTB_CHECK_MODULE(_MISSING_DEP ${APP_DEPENDS}) + IF(_MISSING_DEP) + MESSAGE("APP ${APP_NAME} won't be built, missing dependency: ${_MISSING_DEP}") + SET(APP_IS_ENABLED 0) + ELSE(_MISSING_DEP) + SET(APP_IS_ENABLED 1) + # now check for every package if it is enabled. This overlaps a bit with + # RTTB_CHECK_MODULE ... + FOREACH(_package ${APP_PACKAGE_DEPENDS}) + IF((DEFINED RTTB_USE_${_package}) AND NOT (RTTB_USE_${_package})) + MESSAGE("APP ${APP_NAME} won't be built. Turn on RTTB_USE_${_package} if you want to use it.") + SET(APP_IS_ENABLED 0) + ENDIF() + ENDFOREACH() + + SET(DEPENDS "${APP_DEPENDS}") + SET(DEPENDS_BEFORE "not initialized") + SET(PACKAGE_DEPENDS "${APP_PACKAGE_DEPENDS}") + RTTB_USE_MODULE("${APP_DEPENDS}") + + # ok, now create the APP itself + INCLUDE_DIRECTORIES(. ${ALL_INCLUDE_DIRECTORIES}) + INCLUDE(files.cmake) + + SET(APP_TESTS ${CXX_TEST_PATH}/${APP_NAME}) + + ORGANIZE_SOURCES(SOURCE ${CPP_FILES} + HEADER ${H_FILES} + TXX ${TXX_FILES} + DOC ${DOX_FILES} + ) + + IF(ALL_LIBRARY_DIRS) + # LINK_DIRECTORIES applies only to targets which are added after the call to LINK_DIRECTORIES + LINK_DIRECTORIES(${ALL_LIBRARY_DIRS}) + ENDIF(ALL_LIBRARY_DIRS) + + ADD_EXECUTABLE(${APP_NAME} ${CPP_FILES}) + + IF(ALL_LIBRARIES) + TARGET_LINK_LIBRARIES(${APP_NAME} ${ALL_LIBRARIES}) + ENDIF(ALL_LIBRARIES) + + ENDIF(_MISSING_DEP) + ENDIF(BUILD_TESTING) +ENDMACRO(RTTB_CREATE_APPLICATION_TESTS) \ No newline at end of file diff --git a/demoapps/CMakeLists.txt b/demoapps/CMakeLists.txt index cd4f7a1..388b9c9 100644 --- a/demoapps/CMakeLists.txt +++ b/demoapps/CMakeLists.txt @@ -1,20 +1,25 @@ MESSAGE(STATUS "processing RTToolbox demo apps") OPTION(BUILD_DemoApp_DoseAcc "Determine if the demo application DoseAcc will be generated." OFF) IF(BUILD_DemoApp_DoseAcc) ADD_SUBDIRECTORY(DoseAcc) ENDIF(BUILD_DemoApp_DoseAcc) OPTION(BUILD_DemoApp_DoseMap "Determine if the demo application DoseMap will be generated." OFF) IF(BUILD_DemoApp_DoseMap) ADD_SUBDIRECTORY(DoseMap) ENDIF(BUILD_DemoApp_DoseMap) +OPTION(BUILD_DemoApp_DoseTool "Determine if the demo application DoseTool will be generated." OFF) +IF(BUILD_DemoApp_DoseTool) +ADD_SUBDIRECTORY(DoseTool) +ENDIF(BUILD_DemoApp_DoseTool) OPTION(BUILD_DemoApp_VoxelizerTool "Determine if the demo application VoxelizerTool will be generated." OFF) IF(BUILD_DemoApp_VoxelizerTool) ADD_SUBDIRECTORY(VoxelizerTool) ENDIF(BUILD_DemoApp_VoxelizerTool) + OPTION(BUILD_DemoApp_BioModelCalc "Determine if the demo application BioModelCalc will be generated." OFF) IF(BUILD_DemoApp_BioModelCalc) ADD_SUBDIRECTORY(BioModelCalc) ENDIF(BUILD_DemoApp_BioModelCalc) diff --git a/demoapps/DoseTool/CMakeLists.txt b/demoapps/DoseTool/CMakeLists.txt new file mode 100644 index 0000000..d505a04 --- /dev/null +++ b/demoapps/DoseTool/CMakeLists.txt @@ -0,0 +1,3 @@ +MESSAGE (STATUS "generating demo app: DoseTool - calculating dose statistics of a structure") + +RTTB_CREATE_APPLICATION(DoseTool DEPENDS RTTBCore RTTBITKIO RTTBVirtuosIO RTTBDicomIO RTTBHelaxIO RTTBMasks RTTBMasks RTTBBoostMask RTTBOtherIO RTTBAlgorithms PACKAGE_DEPENDS ArgumentParsingLib) \ No newline at end of file diff --git a/demoapps/DoseTool/DoseTool.cpp b/demoapps/DoseTool/DoseTool.cpp new file mode 100644 index 0000000..309bce6 --- /dev/null +++ b/demoapps/DoseTool/DoseTool.cpp @@ -0,0 +1,142 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1066 $ (last changed revision) +// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + +#include "DoseToolApplicationData.h" +#include "DoseToolHelper.h" +#include "DoseToolCmdLineParser.h" + +#include "boost/shared_ptr.hpp" +#include "boost/make_shared.hpp" + +#include "RTToolboxConfigure.h" + +#include "rttbException.h" + +rttb::apps::doseTool::ApplicationData appData; + +int main(int argc, const char** argv) +{ + int result = 0; + + boost::shared_ptr argParser; + + try + { + std::string appName = "DoseTool"; + std::string appVersion = RTTB_FULL_VERSION_STRING; + + argParser = boost::make_shared(argc, argv, appName, appVersion); + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + return -1; + } + + // This is vital. The application needs to exit if the "help" or "version" parameter is set + // because this means the other parameters won't be parsed. + + if (argParser->isSet(argParser->OPTION_HELP) || argParser->isSet(argParser->OPTION_VERSION)) + { + return 0; + } + + rttb::apps::doseTool::populateAppData(argParser, appData); + + std::cout << std::endl << "*******************************************" << std::endl; + std::cout << "Dose file: " << appData._doseFileName << std::endl; + std::cout << "Struct file: " << appData._structFileName << std::endl; + std::cout << "Output file: " << appData._outputFileName << std::endl; + std::cout << "Struct name: " << appData._structNameRegex << std::endl; + + + try + { + appData._dose = rttb::apps::doseTool::loadDose(appData._doseFileName, appData._doseLoadStyle); + } + catch (rttb::core::Exception& e) + { + std::cerr << "RTTB Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 1; + } + catch (const std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 1; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading dose image." << std::endl; + return 1; + } + + //loading of structure file not necessary in ITK case as it can be used directly as mask input. + if (appData._structLoadStyle.front() != "itk") + { + try + { + appData._struct = rttb::apps::doseTool::loadStruct(appData._structFileName, appData._structLoadStyle); + } + catch (rttb::core::Exception& e) + { + std::cerr << "RTTB Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 2; + } + catch (const std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 2; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading struct image." << std::endl; + return 2; + } + } + + try + { + rttb::apps::doseTool::processData(appData); + } + catch (rttb::core::Exception& e) + { + std::cerr << "RTTB Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 3; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 3; + } + catch (...) + { + std::cerr << "Error!!! unknown error while processing the data or writing the image." << std::endl; + return 3; + } + + return result; +} diff --git a/demoapps/DoseTool/DoseToolApplicationData.cpp b/demoapps/DoseTool/DoseToolApplicationData.cpp new file mode 100644 index 0000000..88c65fb --- /dev/null +++ b/demoapps/DoseTool/DoseToolApplicationData.cpp @@ -0,0 +1,72 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1066 $ (last changed revision) +// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + +#include "DoseToolApplicationData.h" + +namespace rttb +{ + namespace apps + { + namespace doseTool + { + ApplicationData:: + ApplicationData() + { + this->reset(); + } + + void + ApplicationData:: + reset() + { + _doseFileName = ""; + _structFileName = ""; + _structNameRegex = ""; + _structNameActual = ""; + _outputFileName = ""; + _computeComplexDoseStatistics = false; + _allowSelfIntersection = false; + } + + void populateAppData(boost::shared_ptr argParser, ApplicationData& appData) + { + appData._doseFileName = argParser->get(argParser->OPTION_DOSE_FILE); + appData._doseLoadStyle = argParser->get >(argParser->OPTION_DOSE_LOAD_STYLE); + appData._structFileName = argParser->get(argParser->OPTION_STRUCT_FILE); + appData._structLoadStyle = argParser->get >(argParser->OPTION_STRUCT_LOAD_STYLE); + appData._structNameRegex = argParser->get(argParser->OPTION_STRUCT_NAME); + appData._outputFileName = argParser->get(argParser->OPTION_OUTPUT_FILE); + appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); + appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); + + if (argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) + { + appData._prescribedDose = argParser->get(argParser->OPTION_PRESCRIBED_DOSE); + } + else + { + appData._prescribedDose = 1.0; + } + } + + } + } +} diff --git a/demoapps/DoseTool/DoseToolApplicationData.h b/demoapps/DoseTool/DoseToolApplicationData.h new file mode 100644 index 0000000..66dc12d --- /dev/null +++ b/demoapps/DoseTool/DoseToolApplicationData.h @@ -0,0 +1,76 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1070 $ (last changed revision) +// @date $Date: 2015-08-19 14:50:28 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + + +#ifndef __DOSETOOL_APPLICATION_DATA_H +#define __DOSETOOL_APPLICATION_DATA_H + +#include + +#include "rttbDoseAccessorInterface.h" +#include "rttbStructureSetGeneratorInterface.h" +#include "DoseToolCmdLineParser.h" + +namespace rttb +{ + namespace apps + { + namespace doseTool + { + /*! @class ApplicationData + @brief Class for storing all relevant variables needed in DoseTool + */ + class ApplicationData + { + public: + /**Vector of arguments used to specify the loading style (always the first argument) + * and, if needed, additional arguments for the specified loading style (e.g. location of the + * Virtuos plan file for the Virtuos IO style). + */ + typedef std::vector LoadingStyleArgType; + core::DoseAccessorInterface::DoseAccessorPointer _dose; + core::StructureSetGeneratorInterface::StructureSetPointer _struct; + std::string _structNameRegex; + std::string _structNameActual; + unsigned int _structIndex; + std::string _doseFileName; + std::string _structFileName; + LoadingStyleArgType _doseLoadStyle; + LoadingStyleArgType _structLoadStyle; + bool _computeComplexDoseStatistics; + DoseTypeGy _prescribedDose; + std::string _outputFileName; + bool _allowSelfIntersection; + + /*! @brief Resets the variables. _prescribedDose is set to 1.0 because it produces no exception then (as it is not needed). Consistency checks are done in DoseToolCmdLineParser::validateInput() + */ + void reset(); + + ApplicationData(); + }; + /*! @brief Reads the necessary arguments from the DoseToolCmdLineParser and writes them in the respective variables of ApplicationData. + */ + void populateAppData(boost::shared_ptr argParser, ApplicationData& appData); + + } + } +} +#endif diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.cpp b/demoapps/DoseTool/DoseToolCmdLineParser.cpp new file mode 100644 index 0000000..afffdc8 --- /dev/null +++ b/demoapps/DoseTool/DoseToolCmdLineParser.cpp @@ -0,0 +1,158 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1066 $ (last changed revision) +// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + +#include "DoseToolCmdLineParser.h" + +namespace rttb +{ + namespace apps + { + namespace doseTool + { + + DoseToolCmdLineParser::DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, + const std::string& version) : + CmdLineParserBase(name, version) + { + typedef double DoseTypeGy; + addOption(OPTION_DOSE_FILE, OPTION_GROUP_REQUIRED, + "The name of the dose file. Can be omitted if used as " + "positional argument (see above).", 'd', true); + addOption(OPTION_STRUCT_FILE, OPTION_GROUP_REQUIRED, + "The name of the struct file. Can be omitted if used as " + "positional argument (see above).", 's', true); + addOptionWithDefaultValue(OPTION_OUTPUT_FILE, OPTION_GROUP_REQUIRED, + "The name of the output file. Can be omitted if used as " + "positional argument (see above).", "output.xml", "output.xml", 'o', true); + addOptionWithDefaultValue(OPTION_STRUCT_NAME, OPTION_GROUP_REQUIRED, + "The name of the struct as regular expression. Can be omitted if used as " + "positional argument or with itk struct loadingStyle (see above).", "", "", 'n', true); + addPositionalOption(OPTION_DOSE_FILE, 1); + addPositionalOption(OPTION_STRUCT_FILE, 1); + addPositionalOption(OPTION_STRUCT_NAME, 1); + addPositionalOption(OPTION_OUTPUT_FILE, 1); + + std::vector defaultLoadingStyle; + defaultLoadingStyle.push_back("dicom"); + addOptionWithDefaultValue >(OPTION_DOSE_LOAD_STYLE, OPTION_GROUP_REQUIRED, + "The loading style for the dose. Available styles are:\n" + "\"dicom\": normal dicom dose\n" + "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle virtuos myFavorite.pln\")\n" + "\"itk\": use itk image loading\n\"helax\": load a helax dose (choosing this style, the dose path should only be a directory).", + defaultLoadingStyle, defaultLoadingStyle.at(0), + 't', true, true); + addOptionWithDefaultValue >(OPTION_STRUCT_LOAD_STYLE, OPTION_GROUP_REQUIRED, + "The loading style for the dose. Available styles are:\n" + "\"dicom\": normal dicom dose\n" + "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle virtuos myFavorite.pln\")\n" + "\"itk\": use itk image loading.", + defaultLoadingStyle, defaultLoadingStyle.at(0), + 'u', true, true); + + addOption(OPTION_COMPLEX_STATISTICS, OPTION_GROUP_OPTIONAL, + "If the complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) should be computed.", 'x'); + addOption(OPTION_PRESCRIBED_DOSE, OPTION_GROUP_OPTIONAL, + "The prescribed dose in Gy.", 'p'); + addOption(OPTION_ALLOW_SELF_INTERSECTION_STRUCT, OPTION_GROUP_OPTIONAL, + "If a struct file contains self intersecting contours: Allow the processing of these structures and ignore potential problems." + "WARNING: only use this parameter if you know what you are doing.", 'a'); + + parse(argc, argv); + } + + void DoseToolCmdLineParser::validateInput() const + { + std::vector doseLoadStyle = get >(OPTION_DOSE_LOAD_STYLE); + std::string doseLoadStyleAbbreviation = doseLoadStyle.at(0); + + if (doseLoadStyleAbbreviation != "dicom" && doseLoadStyleAbbreviation != "virtuos" && doseLoadStyleAbbreviation != "itk" + && doseLoadStyleAbbreviation != "helax") + { + throw cmdlineparsing::InvalidConstraintException("Unknown load style for dose file:" + doseLoadStyleAbbreviation + + ".\nPlease refer to the help for valid loading style settings."); + } + + if (doseLoadStyleAbbreviation == "virtuos") + { + if (doseLoadStyle.size() < 2) + { + throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io style argument."); + } + } + + std::vector structLoadStyle = get >(OPTION_STRUCT_LOAD_STYLE); + std::string structLoadStyleAbbreviation = structLoadStyle.at(0); + + if (structLoadStyleAbbreviation != "dicom" && structLoadStyleAbbreviation != "virtuos" + && structLoadStyleAbbreviation != "itk") + { + throw cmdlineparsing::InvalidConstraintException("Unknown load style for struct file:" + structLoadStyleAbbreviation + + ".\nPlease refer to the help for valid loading style settings."); + } + + if (structLoadStyleAbbreviation == "dicom" || structLoadStyleAbbreviation == "virtuos" + || structLoadStyleAbbreviation == "helax") + { + if (get(OPTION_STRUCT_NAME) == "") + { + throw cmdlineparsing::InvalidConstraintException("The struct name (--name) has to be defined for dicom, virtuos or helax struct files."); + } + } + + if (structLoadStyleAbbreviation == "virtuos") + { + if (structLoadStyle.size() < 2) + { + throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos struct file. CTX file is missing. Specify CTX file as 2nd io style argument."); + } + } + + if (isSet(OPTION_COMPLEX_STATISTICS)) + { + if (!isSet(OPTION_PRESCRIBED_DOSE)) + { + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--prescribedDose) has to be set for computation of complex dose statistics."); + } + else + { + if (get(OPTION_PRESCRIBED_DOSE) <= 0) + { + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--prescribedDose) has to be >0!"); + } + } + } + } + + void DoseToolCmdLineParser::printHelp() const + { + cmdlineparsing::CmdLineParserBase::printHelp(); + std::cout << "Example:" << std::endl << std::endl; + std::cout << m_programName << + " dose.dcm struct.dcm Liver result.xml" << + std::endl << std::endl; + std::cout << + "This will calculate the Dose statistic for liver using \"dose.dcm\" and the struct file \"struct.dcm\" and will write the result to \"result.xml\". " + << std::endl; + } + + } + } +} diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.h b/demoapps/DoseTool/DoseToolCmdLineParser.h new file mode 100644 index 0000000..2c4a319 --- /dev/null +++ b/demoapps/DoseTool/DoseToolCmdLineParser.h @@ -0,0 +1,63 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1066 $ (last changed revision) +// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + +#ifndef __DOSETOOL_CMD_LINE_PARSER +#define __DOSETOOL_CMD_LINE_PARSER + +#include "CmdLineParserBase.h" +namespace rttb +{ + namespace apps + { + namespace doseTool + { + /*! @class BioModelCmdLineParser + @brief Argument parsing is parametrized here based on ArgParserLib + @see cmdlineparsing::CmdLineParserBase + */ + class DoseToolCmdLineParser : public cmdlineparsing::CmdLineParserBase + { + public: + DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version); + void validateInput() const; + void printHelp() const; + + // Option groups + const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; + const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; + + // Parameters + const std::string OPTION_DOSE_FILE = "doseFile"; + const std::string OPTION_STRUCT_FILE = "structFile"; + const std::string OPTION_STRUCT_NAME = "structName"; + const std::string OPTION_OUTPUT_FILE = "outputFile"; + const std::string OPTION_DOSE_LOAD_STYLE = "doseLoadStyle"; + const std::string OPTION_STRUCT_LOAD_STYLE = "structLoadStyle"; + const std::string OPTION_COMPLEX_STATISTICS = "complexStatistics"; + const std::string OPTION_PRESCRIBED_DOSE = "prescribedDose"; + const std::string OPTION_ALLOW_SELF_INTERSECTION_STRUCT = "allowSelfIntersection"; + }; + + } + } +} + +#endif \ No newline at end of file diff --git a/demoapps/DoseTool/DoseToolHelper.cpp b/demoapps/DoseTool/DoseToolHelper.cpp new file mode 100644 index 0000000..4b89ea9 --- /dev/null +++ b/demoapps/DoseTool/DoseToolHelper.cpp @@ -0,0 +1,251 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1095 $ (last changed revision) +// @date $Date: 2015-09-11 11:12:40 +0200 (Fr, 11 Sep 2015) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + + +#include "DoseToolHelper.h" + +#include "boost/make_shared.hpp" +#include "boost/shared_ptr.hpp" +#include "boost/property_tree/ptree.hpp" + +#include "rttbExceptionMacros.h" + +#include "rttbVirtuosPlanFileDoseAccessorGenerator.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomHelaxFileDoseAccessorGenerator.h" +#include "rttbITKImageFileAccessorGenerator.h" +#include "rttbStructureSetGeneratorInterface.h" +#include "rttbDicomFileStructureSetGenerator.h" +#include "rttbVirtuosFileStructureSetGenerator.h" +#include "rttbITKImageFileMaskAccessorGenerator.h" +#include "rttbDoseStatisticsCalculator.h" +#include "rttbBoostMaskAccessor.h" +#include "rttbGenericMaskedDoseIterator.h" +#include "rttbDoseStatisticsXMLWriter.h" +#include "rttbVOIindexIdentifier.h" + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseTool::loadDose(const std::string& fileName, + const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args) +{ + rttb::core::DoseAccessorInterface::DoseAccessorPointer result; + + std::cout << std::endl << "read dose file... "; + + if (args.empty() || args[0] == "dicom") + { + std::cout << "use RTTB dicom IO... "; + result = loadDicomDose(fileName); + } + else if (args[0] == "helax") + { + std::cout << "use RTTB Helax IO... "; + result = loadHelaxDose(fileName); + } + else if (args[0] == "itk") + { + std::cout << "use RTTB itk IO... "; + result = loadITKDose(fileName); + } + else if (args[0] == "virtuos") + { + if (args.size() < 2) + { + rttbDefaultExceptionStaticMacro( << + "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); + } + + std::cout << "use RTTB virtuos IO... " << std::endl; + std::cout << " virtuos plan file: " << args[1] << " ... "; + result = loadVirtuosDose(fileName, args[1]); + } + else + { + rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " + << args[0]); + } + + std::cout << "done." << std::endl; + + return result; +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseTool::loadDicomDose(const std::string& fileName) +{ + rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseTool::loadHelaxDose(const std::string& path) +{ + rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseTool::loadITKDose(const std::string& fileName) +{ + rttb::io::itk::ITKImageFileAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseTool::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) +{ + rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadStruct( + const std::string& fileName, const ApplicationData::LoadingStyleArgType& args) +{ + rttb::core::StructureSetGeneratorInterface::StructureSetPointer result; + + std::cout << std::endl << "read struct file... "; + + if (args.empty() || args[0] == "dicom") + { + std::cout << "use RTTB dicom IO... "; + result = loadDicomStruct(fileName); + } + else if (args[0] == "virtuos") + { + std::cout << "use RTTB virtuos IO... " << std::endl; + std::cout << " virtuos CTX file: " << args[1] << " ... "; + result = loadVirtuosStruct(fileName, args[1]); + } + else + { + rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " + << args[0]); + } + + std::cout << "done." << std::endl; + + return result; +} + +rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadDicomStruct( + const std::string& fileName) +{ + rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); + return generator.generateStructureSet(); +} + +rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadVirtuosStruct( + const std::string& fileName, const std::string& ctxFileName) +{ + rttb::io::virtuos::VirtuosFileStructureSetGenerator generator(fileName, ctxFileName.c_str()); + return generator.generateStructureSet(); +} + + +void +rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) +{ + std::cout << std::endl << "generating mask... "; + core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr = generateMask(appData); + + core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator(maskAccessorPtr, + appData._dose)); + std::cout << "done." << std::endl; + + std::cout << std::endl << "computing dose statistics... "; + algorithms::DoseStatistics::DoseStatisticsPointer statistics = computeDoseStatistics(spDoseIterator, + appData._computeComplexDoseStatistics); + std::cout << "done." << std::endl; + + std::cout << std::endl << "writing dose statistics to file... "; + writeDoseStatisticsFile(statistics, appData); + std::cout << "done." << std::endl; +}; + +void rttb::apps::doseTool::determineStructIndex(rttb::apps::doseTool::ApplicationData& appData) +{ + unsigned int index = rttb::masks::VOIindexIdentifier::getIndexByVoiName(appData._struct, appData._structNameRegex); + appData._structIndex = index; + appData._structNameActual = appData._struct->getStructure(index)->getLabel(); +} + + +rttb::core::MaskAccessorInterface::MaskAccessorPointer rttb::apps::doseTool::generateMask( + rttb::apps::doseTool::ApplicationData& appData) +{ + core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr; + + if (appData._structLoadStyle.front() == "itk") + { + maskAccessorPtr = rttb::io::itk::ITKImageFileMaskAccessorGenerator(appData._structFileName).generateMaskAccessor(); + } + else + { + determineStructIndex(appData); + bool strict = !appData._allowSelfIntersection; + maskAccessorPtr = + boost::make_shared + (appData._struct->getStructure(appData._structIndex), appData._dose->getGeometricInfo(), strict); + } + + maskAccessorPtr->updateMask(); + return maskAccessorPtr; +} + +rttb::core::DoseIteratorInterface::DoseIteratorPointer rttb::apps::doseTool::generateMaskedDoseIterator( + rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, + rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr) +{ + boost::shared_ptr maskedDoseIterator = + boost::make_shared(maskAccessorPtr, doseAccessorPtr); + rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator(maskedDoseIterator); + return doseIterator; +} + +rttb::algorithms::DoseStatistics::DoseStatisticsPointer rttb::apps::doseTool::computeDoseStatistics( + core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool computeComplexDoseStatistics) +{ + rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); + return doseStatsCalculator.calculateDoseStatistics(computeComplexDoseStatistics); +} + +void rttb::apps::doseTool::writeDoseStatisticsFile(rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, + rttb::apps::doseTool::ApplicationData& appData) +{ + boost::property_tree::ptree originalTree = rttb::io::other::writeDoseStatistics(statistics, appData._prescribedDose); + + //add config part to xml + originalTree.add("statistics.config.requestedStructRegex", appData._structNameRegex); + originalTree.add("statistics.config.structName", appData._structNameActual); + originalTree.add("statistics.config.doseUID", appData._dose->getUID()); + originalTree.add("statistics.config.doseFile", appData._doseFileName); + originalTree.add("statistics.config.structFile", appData._structFileName); + + boost::property_tree::ptree reorderedTree, configTree, resultsTree; + configTree = originalTree.get_child("statistics.config"); + resultsTree = originalTree.get_child("statistics.results"); + reorderedTree.add_child("statistics.config", configTree); + reorderedTree.add_child("statistics.results", resultsTree); + + boost::property_tree::write_xml(appData._outputFileName, reorderedTree, std::locale(), + boost::property_tree::xml_writer_make_settings('\t', 1)); + +} diff --git a/demoapps/DoseTool/DoseToolHelper.h b/demoapps/DoseTool/DoseToolHelper.h new file mode 100644 index 0000000..48dd667 --- /dev/null +++ b/demoapps/DoseTool/DoseToolHelper.h @@ -0,0 +1,117 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 1066 $ (last changed revision) +// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + +#ifndef __DOSETOOL_HELPER_H +#define __DOSETOOL_HELPER_H + +#include "DoseToolApplicationData.h" +#include "rttbDoseAccessorInterface.h" +#include "rttbDoseIteratorInterface.h" +#include "rttbMaskAccessorInterface.h" +#include "rttbDoseStatistics.h" + +namespace rttb +{ + namespace apps + { + namespace doseTool + { + /*! @brief loads a dose from a file based on the loadingStyle. + @exception Throws an rttb::Exception if loading fails + */ + core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, + const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); + /*! @brief loads a dicom dose from a file. + @exception Throws an rttb::Exception if loading fails + @sa DicomFileDoseAccessorGenerator + */ + core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); + /*! @brief loads a helax dose from a file. + @exception Throws an rttb::Exception if loading fails + @sa DicomHelaxFileDoseAccessorGenerator + */ + core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); + /*! @brief loads an itk dose from a file. + @exception Throws an rttb::Exception if loading fails. + @details Might be of all formats that ITK know (*.mhd, *.nrrd, ...). The absolute image values are taken as dose. + @sa ITKImageFileAccessorGenerator + */ + core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); + + /*! @brief loads a virtuos dose from a file. + @exception Throws an rttb::Exception if loading fails + @sa VirtuosPlanFileDoseAccessorGenerator + */ + core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, + const std::string& planFileName); + + /*! @brief loads a struct from a file based on the loadingStyle. + @exception Throws an rttb::Exception if loading fails + @details voxelized itk images are read in generateMask() directly + */ + core::StructureSetGeneratorInterface::StructureSetPointer loadStruct(const std::string& fileName, + const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); + + /*! @brief loads a dicom struct from a file. + @exception Throws an rttb::Exception if loading fails + @sa DicomFileStructureSetGenerator + */ + core::StructureSetGeneratorInterface::StructureSetPointer loadDicomStruct(const std::string& fileName); + + /*! @brief loads a virtuos struct from a file. + @exception Throws an rttb::Exception if loading fails + @sa VirtuosPlanFileDoseAccessorGenerator + */ + core::StructureSetGeneratorInterface::StructureSetPointer loadVirtuosStruct(const std::string& fileName, + const std::string& ctxFileName); + + /*! @brief Contains the business logic of processing all information to calculate the dose statistics and writing them to an xml file. + @details Uses appData for the input data and the correct configuration. + */ + void processData(ApplicationData& appData); + + /*! @brief Searches for the struct index based on the regex + */ + void determineStructIndex(ApplicationData& appData); + + /*! @brief Generates a mask from the struct file by using the boostAccessor. In case of itk image, it directly loads the voxelized image. + */ + core::MaskAccessorInterface::MaskAccessorPointer generateMask(ApplicationData& appData); + + algorithms::DoseStatistics::DoseStatisticsPointer computeDoseStatistics(core::DoseIteratorInterface::DoseIteratorPointer + doseIterator, bool computeComplexDoseStatistics); + + /*! @brief Writes the dose statistics as XML to a file + @details adds a .... part to the RTTB generated xml where the used files and struct names are stored. + */ + void writeDoseStatisticsFile(algorithms::DoseStatistics::DoseStatisticsPointer statistics, + rttb::apps::doseTool::ApplicationData& appData); + + core::DoseIteratorInterface::DoseIteratorPointer generateMaskedDoseIterator( + core::MaskAccessorInterface::MaskAccessorPointer + maskAccessorPtr, core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr); + + } + } +} + + +#endif diff --git a/demoapps/DoseTool/files.cmake b/demoapps/DoseTool/files.cmake new file mode 100644 index 0000000..c957cda --- /dev/null +++ b/demoapps/DoseTool/files.cmake @@ -0,0 +1,12 @@ +SET(CPP_FILES +DoseTool.cpp +DoseToolHelper.cpp +DoseToolApplicationData.cpp +DoseToolCmdLineParser.cpp +) + +SET(H_FILES +DoseToolHelper.h +DoseToolApplicationData.h +DoseToolCmdLineParser.h +) diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index 2d56829..ecffee2 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -1,70 +1,70 @@ MESSAGE(STATUS "processing RTToolbox testing code") # Testing branch PROJECT(RTTBTesting) #----------------------------------------------------------------------------- # Find Litmus. #----------------------------------------------------------------------------- MESSAGE(STATUS "searching Litmus") FIND_PACKAGE(Litmus) IF(Litmus_FOUND) INCLUDE(${Litmus_USE_FILE}) SET(ADDITIONAL_TEST_INCLUDES ${Litmus_USE_FILE}) ELSE(Litmus_FOUND) MESSAGE(FATAL_ERROR "Cannot build without Litmus. Please set Litmus_DIR.") ENDIF(Litmus_FOUND) #----------------------------------------------------------------------------- # Configure Testing branch #----------------------------------------------------------------------------- MAKE_DIRECTORY(${RTTBTesting_BINARY_DIR}/Temporary) MESSAGE(STATUS "Process All Tests...") #----------------------------------------------------------------------------- # Include sub directories #----------------------------------------------------------------------------- OPTION(BUILD_RTToolbox_core_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_Test_examples "build project on/off" OFF) OPTION(BUILD_RTToolbox_algorithms_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_models_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_io_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_masks_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_interpolation_Tester "build project on/off" OFF) -OPTION(BUILD_RTToolbox_demoapps_VoxelizerTool_Tester "build project on/off" OFF) +OPTION(BUILD_RTToolbox_demoapps_Tester "build project on/off" OFF) IF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) ADD_SUBDIRECTORY(core) ENDIF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) ADD_SUBDIRECTORY(examples) ENDIF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) IF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) ADD_SUBDIRECTORY(algorithms) ENDIF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) ADD_SUBDIRECTORY(models) ENDIF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) ADD_SUBDIRECTORY(io) ENDIF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) ADD_SUBDIRECTORY(masks) ENDIF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) ADD_SUBDIRECTORY(interpolation) ENDIF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) -IF(${BUILD_RTToolbox_demoapps_VoxelizerTool_Tester} STREQUAL ON) -ADD_SUBDIRECTORY(demoapps/VoxelizerTool) -ENDIF(${BUILD_RTToolbox_demoapps_VoxelizerTool_Tester} STREQUAL ON) +IF(${BUILD_RTToolbox_demoapps_Tester} STREQUAL ON) +ADD_SUBDIRECTORY(demoapps) +ENDIF(${BUILD_RTToolbox_demoapps_Tester} STREQUAL ON) diff --git a/testing/demoapps/CMakeLists.txt b/testing/demoapps/CMakeLists.txt new file mode 100644 index 0000000..0de5b53 --- /dev/null +++ b/testing/demoapps/CMakeLists.txt @@ -0,0 +1,13 @@ + + MESSAGE (STATUS "Process All demoapps Tests...") + + #----------------------------------------------------------------------------- + # Include sub directories + #----------------------------------------------------------------------------- +IF(BUILD_DemoApp_DoseTool) + ADD_SUBDIRECTORY (DoseTool) +ENDIF(BUILD_DemoApp_DoseTool) + +IF(BUILD_DemoApp_VoxelizerTool) + ADD_SUBDIRECTORY (VoxelizerTool) +ENDIF(BUILD_DemoApp_VoxelizerTool) diff --git a/testing/demoapps/DoseTool/CMakeLists.txt b/testing/demoapps/DoseTool/CMakeLists.txt new file mode 100644 index 0000000..3840e5e --- /dev/null +++ b/testing/demoapps/DoseTool/CMakeLists.txt @@ -0,0 +1,32 @@ +#----------------------------------------------------------------------------- +# Setup the system information test. Write out some basic failsafe +# information in case the test doesn't run. +#----------------------------------------------------------------------------- + + +SET(DOSETOOL_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbDoseToolTests) + +SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) + +SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) + + +#----------------------------------------------------------------------------- + +IF(MSVC) + ADD_DEFINITIONS(/bigobj) +ENDIF() + +ADD_TEST(DoseToolBasicUsageTest ${DOSETOOL_TEST} DoseToolBasicUsageTest) +ADD_TEST(DoseToolInvalidParametersTest ${DOSETOOL_TEST} DoseToolInvalidParametersTest) +ADD_TEST(DoseToolVirtuosDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolVirtuosDoseTest "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.pln" + "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.ctx.gz" "HERZ" + "${TEST_DATA_ROOT}/DoseStatistics/virtuos.xml" "${TEST_DATA_ROOT}/DoseStatistics/virtuosComplex.xml") +ADD_TEST(DoseToolDicomDoseDicomStructTest ${DOSETOOL_TEST} DoseToolDicomDoseTest "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "Nodes" +"${TEST_DATA_ROOT}/DoseStatistics/dicom.xml" "${TEST_DATA_ROOT}/DoseStatistics/dicomComplex.xml") +ADD_TEST(DoseToolITKDoseDicomStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/dicompylerTestDose.mhd" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "" "Nodes" +"${TEST_DATA_ROOT}/DoseStatistics/itkDicomStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkDicomStructComplex.xml") +ADD_TEST(DoseToolITKDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/virtuosTestDose.mhd" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" + "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.ctx.gz" "HERZ" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStructComplex.xml") + +RTTB_CREATE_APPLICATION_TESTS(DoseTool PACKAGE_DEPENDS Litmus BoostBinaries) diff --git a/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp b/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp new file mode 100644 index 0000000..841710e --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp @@ -0,0 +1,70 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include + +#include "litCheckMacros.h" + +#include "boost/filesystem.hpp" + +namespace rttb +{ + namespace testing + { + + //path to the current running directory. DoseTool is in the same directory (Debug/Release) + extern const char* _callingAppPath; + + int DoseToolBasicUsageTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + const std::string doseToolExe = "DoseTool.exe"; + + boost::filesystem::path callingPath(_callingAppPath); + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; + + //call without parameters + std::cout << "Command line call: " + voxelizerToolExeWithPath << std::endl; + CHECK_EQUAL(system(voxelizerToolExeWithPath.c_str()), -1); + + //call with help parameters + std::string helpCommandShort = voxelizerToolExeWithPath + " -h"; + std::string helpCommandLong = voxelizerToolExeWithPath + " --help"; + std::cout << "Command line call: " + helpCommandShort << std::endl; + CHECK_EQUAL(system(helpCommandShort.c_str()), 0); + std::cout << "Command line call: " + helpCommandLong << std::endl; + CHECK_EQUAL(system(helpCommandLong.c_str()), 0); + + //call with version parameter + std::string versionCommandShort = voxelizerToolExeWithPath + " -v"; + std::string versionCommandLong = voxelizerToolExeWithPath + " --version"; + std::cout << "Command line call: " + versionCommandShort << std::endl; + CHECK_EQUAL(system(versionCommandShort.c_str()), 0); + std::cout << "Command line call: " + versionCommandLong << std::endl; + CHECK_EQUAL(system(versionCommandLong.c_str()), 0); + + //call with + + RETURN_AND_REPORT_TEST_SUCCESS; + } + } //namespace testing +} //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp new file mode 100644 index 0000000..afd2c0e --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp @@ -0,0 +1,135 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include +#include +#include + +#include "litCheckMacros.h" + +#include "boost/filesystem.hpp" +#include "boost/algorithm/string.hpp" + +namespace rttb +{ + namespace testing + { + + //path to the current running directory. DoseTool is in the same directory (Debug/Release) + extern const char* _callingAppPath; + + static std::string readFile(const std::string& filename); + + int DoseToolDicomDoseTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + const std::string doseToolExe = "DoseTool.exe"; + std::string doseFilename; + std::string planFilename; + std::string structFilename; + std::string ctxFilename; + std::string structName; + std::string referenceXMLFilename; + std::string referenceXMLComplexFilename; + + boost::filesystem::path callingPath(_callingAppPath); + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; + + if (argc > 5) + { + doseFilename = argv[1]; + structFilename = argv[2]; + structName = argv[3]; + referenceXMLFilename = argv[4]; + referenceXMLComplexFilename = argv[5]; + } + + std::string defaultOutputFilename = "dicomOutput.xml"; + std::string complexOutputFilename = "dicomOutputComplex.xml"; + + std::string baseCommand = voxelizerToolExeWithPath; + baseCommand += " -d " + doseFilename; + baseCommand += " -s " + structFilename; + + if (structName != "") + { + baseCommand += " -n " + structName; + } + else + { + baseCommand += " -u itk "; + } + + std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); + + std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + //prescribed dose is 14 Gy + complexDoseStatisticsCommand += " -x -p 14"; + + std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); + + //check if file exists + CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); + CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); + + //check if file is the same than reference file + std::string defaultAsIs = readFile(defaultOutputFilename); + std::string defaultExpected = readFile(referenceXMLFilename); + //add doseFile and structFile + std::string emptyDoseFileTag = ""; + std::string validDoseFileTag = "" + doseFilename + ""; + boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); + + std::string emptyStructFileTag = ""; + std::string validStructFileTag = "" + structFilename + ""; + boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(defaultAsIs, defaultExpected); + + //add doseFile and structFile + std::string complexAsIs = readFile(complexOutputFilename); + std::string complexExpected = readFile(referenceXMLComplexFilename); + + boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); + boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(complexAsIs, complexExpected); + + //delete file again + CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); + CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + std::string readFile(const std::string& filename) + { + std::ifstream fileStream(filename); + std::string content((std::istreambuf_iterator(fileStream)), + (std::istreambuf_iterator())); + return content; + } + } //namespace testing +} //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp new file mode 100644 index 0000000..98f0045 --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp @@ -0,0 +1,142 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include +#include +#include + +#include "litCheckMacros.h" + +#include "boost/filesystem.hpp" +#include "boost/algorithm/string.hpp" + +namespace rttb +{ + namespace testing + { + + //path to the current running directory. DoseTool is in the same directory (Debug/Release) + extern const char* _callingAppPath; + + static std::string readFile(const std::string& filename); + + int DoseToolITKDoseTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + const std::string doseToolExe = "DoseTool.exe"; + std::string doseFilename; + std::string planFilename; + std::string structFilename; + std::string ctxFilename; + std::string structName; + std::string referenceXMLFilename; + std::string referenceXMLComplexFilename; + + boost::filesystem::path callingPath(_callingAppPath); + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; + + if (argc > 6) + { + doseFilename = argv[1]; + structFilename = argv[2]; + ctxFilename = argv[3]; + structName = argv[4]; + referenceXMLFilename = argv[5]; + referenceXMLComplexFilename = argv[6]; + } + + std::string defaultOutputFilename = "itkOutput.xml"; + std::string complexOutputFilename = "itkOutputComplex.xml"; + + std::string baseCommand = voxelizerToolExeWithPath; + baseCommand += " -d " + doseFilename; + baseCommand += " -s " + structFilename; + baseCommand += " -t itk "; + + if (structName != "") + { + baseCommand += " -n " + structName; + + if (ctxFilename != "") + { + baseCommand += " -u virtuos " + ctxFilename; + } + } + else + { + baseCommand += " -u itk "; + } + + std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); + + std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + //prescribed dose is 14 Gy + complexDoseStatisticsCommand += " -x -p 14"; + + std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); + + //check if file exists + CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); + CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); + + //check if file is the same than reference file + std::string defaultAsIs = readFile(defaultOutputFilename); + std::string defaultExpected = readFile(referenceXMLFilename); + //add doseFile and structFile + std::string emptyDoseFileTag = ""; + std::string validDoseFileTag = "" + doseFilename + ""; + boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); + + std::string emptyStructFileTag = ""; + std::string validStructFileTag = "" + structFilename + ""; + boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(defaultAsIs, defaultExpected); + + //add doseFile and structFile + std::string complexAsIs = readFile(complexOutputFilename); + std::string complexExpected = readFile(referenceXMLComplexFilename); + + boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); + boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(complexAsIs, complexExpected); + + //delete file again + CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); + CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + std::string readFile(const std::string& filename) + { + std::ifstream fileStream(filename); + std::string content((std::istreambuf_iterator(fileStream)), + (std::istreambuf_iterator())); + return content; + } + } //namespace testing +} //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp new file mode 100644 index 0000000..6a68a8a --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp @@ -0,0 +1,97 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include + +#include "litCheckMacros.h" + +#include "boost/filesystem.hpp" + +namespace rttb +{ + namespace testing + { + + //path to the current running directory. DoseTool is in the same directory (Debug/Release) + extern const char* _callingAppPath; + + int DoseToolInvalidParametersTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + const std::string doseToolExe = "DoseTool.exe"; + + boost::filesystem::path callingPath(_callingAppPath); + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; + + //call with too few parameters + std::string toofewParametersCommand = voxelizerToolExeWithPath; + toofewParametersCommand += " -d test"; + toofewParametersCommand += " -s test"; + std::cout << "Command line call: " + toofewParametersCommand << std::endl; + CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); + + toofewParametersCommand = voxelizerToolExeWithPath; + toofewParametersCommand += " -s test"; + toofewParametersCommand += " -n test"; + std::cout << "Command line call: " + toofewParametersCommand << std::endl; + CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); + + toofewParametersCommand = voxelizerToolExeWithPath; + toofewParametersCommand += " test"; + toofewParametersCommand += " test"; + std::cout << "Command line call: " + toofewParametersCommand << std::endl; + CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); + + //call with invalid dose load option + std::string minimalCLI = voxelizerToolExeWithPath + " test test test "; + std::string invalidDoseLoadOption = minimalCLI; + invalidDoseLoadOption += "-t wrongOption"; + std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; + CHECK_EQUAL(system(invalidDoseLoadOption.c_str()), -1); + + //call with invalid struct load option + std::string invalidStructLoadOption = minimalCLI; + invalidStructLoadOption += "-u wrongOption"; + std::cout << "Command line call: " + invalidStructLoadOption << std::endl; + CHECK_EQUAL(system(invalidStructLoadOption.c_str()), -1); + + //call with virtuos dose load option, but without plan/ctx + std::string invalidVirtuosDoseLoadOption = minimalCLI; + invalidVirtuosDoseLoadOption += "-u virtuos"; + std::cout << "Command line call: " + invalidVirtuosDoseLoadOption << std::endl; + CHECK_EQUAL(system(invalidVirtuosDoseLoadOption.c_str()), -1); + + std::string invalidVirtuosStructLoadOption = minimalCLI; + invalidVirtuosStructLoadOption += "-t virtuos"; + std::cout << "Command line call: " + invalidVirtuosStructLoadOption << std::endl; + CHECK_EQUAL(system(invalidVirtuosStructLoadOption.c_str()), -1); + + //call with complex dose statistics, but without prescribed dose + std::string complexDoseWithoutPrescribedDoseCommand = minimalCLI; + complexDoseWithoutPrescribedDoseCommand += "-x"; + std::cout << "Command line call: " + complexDoseWithoutPrescribedDoseCommand << std::endl; + CHECK_EQUAL(system(complexDoseWithoutPrescribedDoseCommand.c_str()), -1); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + } //namespace testing +} //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolTests.cpp b/testing/demoapps/DoseTool/DoseToolTests.cpp new file mode 100644 index 0000000..cbafbad --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolTests.cpp @@ -0,0 +1,71 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called registerTests() +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#include "litMultiTestsMain.h" + +namespace rttb +{ + namespace testing + { + + const char* _callingAppPath = NULL; + + void registerTests() + { + LIT_REGISTER_TEST(DoseToolBasicUsageTest); + LIT_REGISTER_TEST(DoseToolInvalidParametersTest); + LIT_REGISTER_TEST(DoseToolVirtuosDoseTest); + LIT_REGISTER_TEST(DoseToolDicomDoseTest); + LIT_REGISTER_TEST(DoseToolITKDoseTest); + } + + } //namespace testing +} //namespace map + + +int main(int argc, char* argv[]) +{ + int result = 0; + + rttb::testing::registerTests(); + + if (argc > 0) + { + rttb::testing::_callingAppPath = argv[0]; + } + + try + { + result = lit::multiTestsMain(argc, argv); + } + catch (...) + { + result = -1; + } + + return result; +} diff --git a/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp new file mode 100644 index 0000000..42b8b57 --- /dev/null +++ b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp @@ -0,0 +1,130 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// 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. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 771 $ (last changed revision) +// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include +#include +#include + +#include "litCheckMacros.h" + +#include "boost/filesystem.hpp" +#include "boost/algorithm/string.hpp" + +namespace rttb +{ + namespace testing + { + + //path to the current running directory. DoseTool is in the same directory (Debug/Release) + extern const char* _callingAppPath; + + static std::string readFile(const std::string& filename); + + int DoseToolVirtuosDoseTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + const std::string doseToolExe = "DoseTool.exe"; + std::string doseFilename; + std::string planFilename; + std::string structFilename; + std::string ctxFilename; + std::string structName; + std::string referenceXMLFilename; + std::string referenceXMLComplexFilename; + + boost::filesystem::path callingPath(_callingAppPath); + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; + + if (argc > 7) + { + doseFilename = argv[1]; + planFilename = argv[2]; + structFilename = argv[3]; + ctxFilename = argv[4]; + structName = argv[5]; + referenceXMLFilename = argv[6]; + referenceXMLComplexFilename = argv[7]; + } + + std::string defaultOutputFilename = "virtuosOutput.xml"; + std::string complexOutputFilename = "virtuosOutputComplex.xml"; + + std::string baseCommand = voxelizerToolExeWithPath; + baseCommand += " -d " + doseFilename; + baseCommand += " -t virtuos " + planFilename; + baseCommand += " -s " + structFilename; + baseCommand += " -u virtuos " + ctxFilename; + baseCommand += " -n " + structName; + std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); + + std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + //prescribed dose is 50 Gy + complexDoseStatisticsCommand += " -x -p 50"; + + std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; + CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); + + //check if file exists + CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); + CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); + + //check if file is the same than reference file + std::string defaultAsIs = readFile(defaultOutputFilename); + std::string defaultExpected = readFile(referenceXMLFilename); + //add doseFile and structFile + std::string emptyDoseFileTag = ""; + std::string validDoseFileTag = "" + doseFilename + ""; + boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); + + std::string emptyStructFileTag = ""; + std::string validStructFileTag = "" + structFilename + ""; + boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(defaultAsIs, defaultExpected); + + //add doseFile and structFile + std::string complexAsIs = readFile(complexOutputFilename); + std::string complexExpected = readFile(referenceXMLComplexFilename); + + boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); + boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); + + CHECK_EQUAL(complexAsIs, complexExpected); + + //delete file again + CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); + CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + std::string readFile(const std::string& filename) + { + std::ifstream fileStream(filename); + std::string content((std::istreambuf_iterator(fileStream)), + (std::istreambuf_iterator())); + return content; + } + } //namespace testing +} //namespace rttb diff --git a/testing/demoapps/DoseTool/files.cmake b/testing/demoapps/DoseTool/files.cmake new file mode 100644 index 0000000..7bf5153 --- /dev/null +++ b/testing/demoapps/DoseTool/files.cmake @@ -0,0 +1,11 @@ +SET(CPP_FILES + DoseToolBasicUsageTest.cpp + DoseToolInvalidParametersTest.cpp + DoseToolVirtuosDoseTest.cpp + DoseToolDicomDoseTest.cpp + DoseToolITKDoseTest.cpp + DoseToolTests.cpp + ) + +SET(H_FILES +) diff --git a/testing/io/itk/CMakeLists.txt b/testing/io/itk/CMakeLists.txt index 45b04ef..3e11bc6 100644 --- a/testing/io/itk/CMakeLists.txt +++ b/testing/io/itk/CMakeLists.txt @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(ITKIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbITKIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(ITKDoseAccessorGeneratorTest ${ITKIO_TEST} ITKDoseAccessorGeneratorTest -"${TEST_DATA_ROOT}/MatchPointLogo.mhd") +"${TEST_DATA_ROOT}/ITK/MatchPointLogo.mhd") -ADD_TEST(ITKIOTest ${ITKIO_TEST} ITKIOTest -"${TEST_DATA_ROOT}/MatchPointLogo.mhd") +ADD_TEST(ITKIOTest ${ITKIO_TEST} ITKIOTest +"${TEST_DATA_ROOT}/ITK/MatchPointLogo.mhd") -ADD_TEST(ITKDoseAccessorConverterTest ${ITKIO_TEST} ITKDoseAccessorConverterTest - "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" "${TEST_DATA_ROOT}/MatchPointLogo.mhd" ) - - ADD_TEST(ITKBioModelAccessorConverterTest ${ITKIO_TEST} ITKBioModelAccessorConverterTest +ADD_TEST(ITKDoseAccessorConverterTest ${ITKIO_TEST} ITKDoseAccessorConverterTest + "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" "${TEST_DATA_ROOT}/ITK/MatchPointLogo.mhd" ) + + ADD_TEST(ITKBioModelAccessorConverterTest ${ITKIO_TEST} ITKBioModelAccessorConverterTest "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm") ADD_TEST(ITKMaskAccessorGeneratorTest ${ITKIO_TEST} ITKMaskAccessorGeneratorTest -"${TEST_DATA_ROOT}/MatchPointLogo.mhd") +"${TEST_DATA_ROOT}/ITK/MatchPointLogo.mhd") ADD_TEST(ITKMaskAccessorConverterTest ${ITKIO_TEST} ITKMaskAccessorConverterTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" - "${TEST_DATA_ROOT}/MatchPointLogo.mhd") + "${TEST_DATA_ROOT}/ITK/MatchPointLogo.mhd") RTTB_CREATE_TEST_MODULE(rttbITKIO DEPENDS RTTBITKIO RTTBDicomIO RTTBMasks RTTBOTBMask RTTBModels PACKAGE_DEPENDS Boost Litmus MatchPoint ITK DCMTK)