diff --git a/RTToolboxConfigure.h.in b/RTToolboxConfigure.h.in index 34f0556..7e87ea3 100644 --- a/RTToolboxConfigure.h.in +++ b/RTToolboxConfigure.h.in @@ -1,102 +1,94 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ SIDT RT Interface // // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// -// Subversion HeadURL: $HeadURL: http://sidt-hpc1/dkfz_repository/NotMeVisLab/SIDT/RTToolbox/branch/restructure/RTToolboxConfigure.h.in $ -*/ //---------------------------------------------------------- // !!!EXPERIMENTAL CODE!!! // // This code may not be used for release. // Add #define SIDT_ENFORCE_MATURE_CODE to any release module // to ensure this policy. //---------------------------------------------------------- #ifdef SIDT_ENFORCE_MATURE_CODE - #error “This code is marked as experimental code. It must not be used because this build enforces mature code.” + #error "This code is marked as experimental code. It must not be used because this build enforces mature code." #endif #ifndef SIDT_CONTAINS_EXPERIMENTAL_CODE #define SIDT_CONTAINS_EXPERIMENTAL_CODE 1 #endif /*! @def RTTB_BUILD_SHARED_LIBS * This define indicates if RTTB will be build as static library (define RTTB_STATIC) or as DLL (define RTTB_DLL). * By default RTTB_BUILD_SHARED_LIBS is not defined. */ #cmakedefine RTTB_BUILD_SHARED_LIBS #ifdef RTTB_BUILD_SHARED_LIBS #define RTTB_DLL #else #define RTTB_STATIC #endif #ifndef __RTTB_CONFIGURE_H #define __RTTB_CONFIGURE_H /*! @def RTTB_BUILD_SHARED_LIBS * This define indicates if RTTB will be build as static library (define RTTB_STATIC) or as DLL (define RTTB_DLL). * By default RTTB_BUILD_SHARED_LIBS is not defined. */ #cmakedefine RTTB_BUILD_SHARED_LIBS #ifdef RTTB_BUILD_SHARED_LIBS #define RTTB_DLL #else #define RTTB_STATIC #endif /*! @def RTTB_ENFORCE_MATURE_CODE * This define controls if RTToolbox should force the whole build to be mature code. * Mature code convention is part of the SIDT coding styles. * Projects that use RTToolbox are able to ensure with SIDT_ENFORCE_MATURE_CODE * that used code is guaranteed to be tested and reviewed regarding the strict * SIDT coding styles.\n * RTTB_ENFORCE_MATURE_CODE can be used to ensure that strictness when prebuilding * static or dynamic libraries. * @remark This definition should by configured via the advance options in CMake. */ #cmakedefine RTTB_ENFORCE_MATURE_CODE #ifdef RTTB_ENFORCE_MATURE_CODE #define SIDT_ENFORCE_MATURE_CODE #endif /*! @def RTTB_DISABLE_ITK_IO_FACTORY_AUTO_REGISTER * This define controls if RTToolbox should disable the auto * register functionality of the itk io factory, when RTToolbox * io reader and writer classes are used. * This is needed in cases where RTToolbox is build "dynamic" and * used in an application that also uses the ITK shared objects * under Windows systems (e.g. MITK). Loading and unloading RTToolbox * shared objects in such an application would lead to an corrupted * itk factory stack, because its implementation is not fail safe * in this scenario. * @remark This definition should by configured via the advance options in CMake. */ #cmakedefine RTTB_DISABLE_ITK_IO_FACTORY_AUTO_REGISTER #define RTTB_VERSION_MAJOR @RTToolbox_VERSION_MAJOR@ #define RTTB_VERSION_MINOR @RTToolbox_VERSION_MINOR@ #define RTTB_VERSION_PATCH @RTToolbox_VERSION_PATCH@ #define RTTB_VERSION_STRING "@RTToolbox_VERSION_STRING@" #define RTTB_FULL_VERSION_STRING "@RTToolbox_FULL_VERSION_STRING@" #endif diff --git a/apps/BioModelCalc/BioModelCalc.cpp b/apps/BioModelCalc/BioModelCalc.cpp index 0cb4fad..8bbd785 100644 --- a/apps/BioModelCalc/BioModelCalc.cpp +++ b/apps/BioModelCalc/BioModelCalc.cpp @@ -1,155 +1,149 @@ // ----------------------------------------------------------------------- // 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: 1334 $ (last changed revision) -// @date $Date: 2016-04-22 11:13:22 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "BioModelCalcApplicationData.h" #include "BioModelCalcHelper.h" #include "BioModelCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbException.h" #include "rttbDoseLoader.cpp" int main(int argc, const char** argv) { int result = 0; rttb::apps::bioModelCalc::ApplicationData appData; boost::shared_ptr argParser; const std::string appCategory = "RT-Toolbox App"; const std::string appName = "BioModelCalc"; const std::string appDesc = "An App to calculate the Linear quadratic (LQ) BioModel. The GUI for this app is currently under development and in an experimental state."; const std::string appContributor = "SIDT@DKFZ"; const std::string appVersion = RTTB_FULL_VERSION_STRING; try { argParser = boost::make_shared(argc, argv, appName, appVersion, appDesc, appContributor, appCategory); } 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) || argParser->isSet(argParser->OPTION_XML)) { return 0; } rttb::apps::bioModelCalc::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose file: " << appData._doseFileName << std::endl; std::cout << "Bio model output file: " << appData._outputFileName << std::endl; std::cout << "Model: " << appData._model << std::endl; std::cout << "Model parameters: "; for (size_t i = 0; i < appData._modelParameters.size(); i++) { if (i != 0) { std::cout << ", "; } std::cout << appData._modelParameters.at(i); } for (size_t i = 0; i < appData._modelParameterMapsFilename.size(); i++) { if (i != 0) { std::cout << ", "; } std::cout << appData._modelParameterMapsFilename.at(i); } std::cout << std::endl; std::cout << "Dose scaling: " << appData._doseScaling << std::endl; if (argParser->isSet(argParser->OPTION_N_FRACTIONS)){ std::cout << "#Fractions: " << appData._nFractions << std::endl; } std::cout << std::endl; std::cout << std::endl << "read dose file... "; try { appData._dose = rttb::io::utils::loadDose(appData._doseFileName, appData._doseLoadStyle); for (const auto& filename : appData._modelParameterMapsFilename){ appData._modelParameterMaps.push_front(rttb::io::utils::loadDose(filename, appData._parameterMapsLoadStyle)); } std::cout << "done." << std::endl; } 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 input image." << std::endl; return 1; } try { rttb::apps::bioModelCalc::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while calculating the bioModel or writing the image." << std::endl; return 2; } return result; } diff --git a/apps/BioModelCalc/BioModelCalcHelper.cpp b/apps/BioModelCalc/BioModelCalcHelper.cpp index d87a645..bfe7da7 100644 --- a/apps/BioModelCalc/BioModelCalcHelper.cpp +++ b/apps/BioModelCalc/BioModelCalcHelper.cpp @@ -1,96 +1,89 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "BioModelCalcHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "rttbExceptionMacros.h" #include "BioModelCalcApplicationData.h" #include "rttbITKImageAccessorConverter.h" #include "rttbImageWriter.h" #include "rttbLQModelAccessor.h" void rttb::apps::bioModelCalc::processData(rttb::apps::bioModelCalc::ApplicationData& appData) { rttb::core::DoseAccessorInterface::Pointer outputAccessor; std::cout << std::endl << "generate biomodel... "; rttb::core::AccessorInterface::Pointer bioModelAccessor; if (!appData._modelParameters.empty()){ bioModelAccessor = generateBioModel(appData._dose, appData._model, appData._modelParameters, appData._nFractions, appData._doseScaling); } else { bioModelAccessor = generateBioModelWithMaps(appData._dose, appData._model, appData._modelParameterMaps, appData._nFractions, appData._doseScaling); } std::cout << "done." << std::endl; std::cout << std::endl << "generate output image... "; io::itk::ITKImageAccessorConverter converter(bioModelAccessor); converter.setFailOnInvalidIDs(true); converter.process(); io::itk::ITKImageAccessorConverter::ITKImageType::Pointer itkImage = converter.getITKImage(); std::cout << "done." << std::endl; std::cout << std::endl << "write output image... "; io::itk::ImageWriter writer(appData._outputFileName, itkImage.GetPointer()); writer.writeFile(); std::cout << "done." << std::endl; } rttb::core::AccessorInterface::Pointer rttb::apps::bioModelCalc::generateBioModel( rttb::core::DoseAccessorInterface::Pointer dose, const std::string& model, const std::vector& modelParameters, unsigned int nFractions, double doseScaling) { if (model == "LQ") { return boost::make_shared(dose, modelParameters.at(0), modelParameters.at(1), nFractions, doseScaling); } else { rttbDefaultExceptionStaticMacro( << "Unknown model selected. Cannot load data. Selected model: " << model); } } rttb::core::AccessorInterface::Pointer rttb::apps::bioModelCalc::generateBioModelWithMaps( rttb::core::DoseAccessorInterface::Pointer dose, const std::string& model, const std::deque& modelParameterMaps, unsigned int nFractions, double doseScaling) { if (model == "LQ") { return boost::make_shared(dose, modelParameterMaps.at(0), modelParameterMaps.at(1), nFractions, doseScaling); } else { rttbDefaultExceptionStaticMacro(<< "Unknown model selected. Cannot load data. Selected model: " << model); } } diff --git a/apps/BioModelCalc/BioModelCalcHelper.h b/apps/BioModelCalc/BioModelCalcHelper.h index a4078e2..41d5c75 100644 --- a/apps/BioModelCalc/BioModelCalcHelper.h +++ b/apps/BioModelCalc/BioModelCalcHelper.h @@ -1,53 +1,47 @@ // ----------------------------------------------------------------------- // 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: 1210 $ (last changed revision) -// @date $Date: 2015-11-24 15:52:45 +0100 (Di, 24 Nov 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __BIO_MODEL_CALC_HELPER_H #define __BIO_MODEL_CALC_HELPER_H #include #include "rttbAccessorInterface.h" #include "rttbDoseAccessorInterface.h" namespace rttb { namespace apps { namespace bioModelCalc { class ApplicationData; void processData(ApplicationData& appData); core::AccessorInterface::Pointer generateBioModel( core::DoseAccessorInterface::Pointer dose, const std::string& model, const std::vector& modelParameters, unsigned int nFractions=1, double doseScaling = 1.0); rttb::core::AccessorInterface::Pointer generateBioModelWithMaps( rttb::core::DoseAccessorInterface::Pointer dose, const std::string& model, const std::deque& modelParameterMaps, unsigned int nFractions = 1, double doseScaling = 1.0); } } } #endif diff --git a/apps/BioModelCalc/BioModelCmdLineParser.h b/apps/BioModelCalc/BioModelCmdLineParser.h index 355f939..ae57fd3 100644 --- a/apps/BioModelCalc/BioModelCmdLineParser.h +++ b/apps/BioModelCalc/BioModelCmdLineParser.h @@ -1,43 +1,58 @@ +// ----------------------------------------------------------------------- +// 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. +// +//------------------------------------------------------------------------ + #ifndef __BIO_MODEL_CMD_LINE_PARSER #define __BIO_MODEL_CMD_LINE_PARSER #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace bioModelCalc { /*! @class BioModelCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class BioModelCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: BioModelCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version, const std::string& description, const std::string& contributor, const std::string& category); 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 = "dose"; const std::string OPTION_OUTPUT_FILE = "outputFile"; const std::string OPTION_MODEL = "model"; const std::string OPTION_MODEL_PARAMETERS = "modelParameters"; const std::string OPTION_MODEL_PARAMETER_MAPS = "modelParameterMaps"; const std::string OPTION_LOAD_STYLE = "loadStyle"; const std::string OPTION_LOAD_STYLE_PARAMETER_MAPS = "loadStyleParameterMaps"; const std::string OPTION_DOSE_SCALING = "doseScaling"; const std::string OPTION_N_FRACTIONS = "nFractions"; }; } } } #endif \ No newline at end of file diff --git a/apps/DoseAcc/DoseAcc.cpp b/apps/DoseAcc/DoseAcc.cpp index d068d6f..7f60cd5 100644 --- a/apps/DoseAcc/DoseAcc.cpp +++ b/apps/DoseAcc/DoseAcc.cpp @@ -1,179 +1,173 @@ // ----------------------------------------------------------------------- // 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: 1107 $ (last changed revision) -// @date $Date: 2015-09-17 12:47:41 +0200 (Do, 17 Sep 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "DoseAccApplicationData.h" #include "DoseAccHelper.h" #include "DoseAccCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbDoseLoader.cpp" int main(int argc, const char** argv) { int result = 0; rttb::apps::doseAcc::ApplicationData appData; boost::shared_ptr argParser; const std::string appCategory = "RT-Toolbox App"; const std::string appName = "DoseAcc"; const std::string appDesc = "An App to accumulate two doses. The GUI for this app is currently under development and in an experimental state."; const std::string appContributor = "SIDT@DKFZ"; const std::string appVersion = RTTB_FULL_VERSION_STRING; try { argParser = boost::make_shared(argc, argv, appName, appVersion, appDesc, appContributor, appCategory); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return 5; } // 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) || argParser->isSet(argParser->OPTION_XML)) { return 0; } rttb::apps::doseAcc::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose 1 file: " << appData._dose1FileName << std::endl; std::cout << "Dose 2 file: " << appData._dose2FileName << std::endl; std::cout << "Dose output file: " << appData._outputFileName << std::endl; if (!(appData._regFileName.empty())) { std::cout << "Registration file: " << appData._regFileName << std::endl; } std::cout << "Dose 1 weight: " << appData._weightDose1 << std::endl; std::cout << "Dose 2 weight: " << appData._weightDose2 << std::endl; std::cout << "Operator: " << appData._operator << std::endl; std::cout << std::endl << "read dose file... "; try { appData._dose1 = rttb::io::utils::loadDose(appData._dose1FileName, appData._dose1LoadStyle); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } try { appData._dose2 = rttb::io::utils::loadDose(appData._dose2FileName, appData._dose2LoadStyle); std::cout << "done." << std::endl; } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } if (!(appData._regFileName.empty())) { try { appData._spReg = rttb::apps::doseAcc::loadRegistration(appData._regFileName); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 5; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 5; } catch (...) { std::cerr << "Error!!! unknown error while reading registration file." << std::endl; return 5; } } try { rttb::apps::doseAcc::processData(appData); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 9; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 9; } catch (...) { std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; return 9; } std::cout << std::endl; return result; } diff --git a/apps/DoseAcc/DoseAccCmdLineParser.h b/apps/DoseAcc/DoseAccCmdLineParser.h index 237e204..70b1c1d 100644 --- a/apps/DoseAcc/DoseAccCmdLineParser.h +++ b/apps/DoseAcc/DoseAccCmdLineParser.h @@ -1,65 +1,60 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSEACC_CMD_LINE_PARSER #define __DOSEACC_CMD_LINE_PARSER #include "CmdLineParserBase.h" + namespace rttb { namespace apps { namespace doseAcc { /*! @class DoseAccCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class DoseAccCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: DoseAccCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version, const std::string& description, const std::string& contributor, const std::string& category); void validateInput() const override; void printHelp() const override; // Option groups const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; // Parameters const std::string OPTION_DOSE1_FILENAME = "dose1"; const std::string OPTION_DOSE2_FILENAME = "dose2"; const std::string OPTION_OUTPUT_FILENAME = "output"; const std::string OPTION_INTERPOLATOR = "interpolator"; const std::string OPTION_WEIGHT1 = "weight1"; const std::string OPTION_WEIGHT2 = "weight2"; const std::string OPTION_REGISTRATION_FILENAME = "registration"; const std::string OPTION_LOAD_STYLE_DOSE1 = "loadStyle1"; const std::string OPTION_LOAD_STYLE_DOSE2 = "loadStyle2"; const std::string OPTION_OPERATOR = "operator"; }; } } } #endif \ No newline at end of file diff --git a/apps/DoseAcc/DoseAccHelper.cpp b/apps/DoseAcc/DoseAccHelper.cpp index 0a5eac7..20dfecd 100644 --- a/apps/DoseAcc/DoseAccHelper.cpp +++ b/apps/DoseAcc/DoseAccHelper.cpp @@ -1,172 +1,165 @@ // ----------------------------------------------------------------------- // 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: 1132 $ (last changed revision) -// @date $Date: 2015-10-06 14:48:56 +0200 (Di, 06 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "DoseAccHelper.h" #include "boost/make_shared.hpp" #include "mapRegistrationFileReader.h" #include "rttbExceptionMacros.h" #include "rttbITKImageAccessorConverter.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbMatchPointTransformation.h" #include "rttbLinearInterpolation.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbRosuMappableDoseAccessor.h" #include "rttbArithmetic.h" #include "rttbBinaryFunctorAccessor.h" #include "rttbImageWriter.h" rttb::apps::doseAcc::ApplicationData::RegistrationType::Pointer rttb::apps::doseAcc::loadRegistration(const std::string& fileName) { map::io::RegistrationFileReader::Pointer spRegReader = map::io::RegistrationFileReader::New(); map::io::RegistrationFileReader::LoadedRegistrationPointer spReg; std::cout << std::endl << "read registration file... "; spReg = spRegReader->read(fileName); std::cout << "done." << std::endl; ApplicationData::RegistrationType::Pointer resultPtr = dynamic_cast(spReg.GetPointer()); if (resultPtr.IsNull()) { rttbDefaultExceptionStaticMacro( << "Loaded registration cannot be used. Only 3D 3D registrations are allowed."); } return resultPtr; }; rttb::core::DoseAccessorInterface::Pointer generateNNMappableAccessor( const rttb::core::GeometricInfo& geoInfoTargetImage, const rttb::core::DoseAccessorInterface::Pointer doseMovingImage, const rttb::interpolation::TransformationInterface::Pointer aTransformation) { auto interpolate = boost::make_shared(); return boost::make_shared(geoInfoTargetImage, doseMovingImage, aTransformation, interpolate); } rttb::core::DoseAccessorInterface::Pointer generateLinearMappableAccessor( const rttb::core::GeometricInfo& geoInfoTargetImage, const rttb::core::DoseAccessorInterface::Pointer doseMovingImage, const rttb::interpolation::TransformationInterface::Pointer aTransformation) { auto interpolate = boost::make_shared(); return boost::make_shared(geoInfoTargetImage, doseMovingImage, aTransformation, interpolate); } rttb::core::DoseAccessorInterface::Pointer generateRosuMappableAccessor( const rttb::core::GeometricInfo& geoInfoTargetImage, const rttb::core::DoseAccessorInterface::Pointer doseMovingImage, const rttb::interpolation::TransformationInterface::Pointer aTransformation) { return boost::make_shared(geoInfoTargetImage, doseMovingImage, aTransformation); } /**Private helper function for processData(). Generates a suitable output accessor * (depending on the configuration in appData a suitable accessor pipeline is established) * which performs the accumulation of the doses and returns the output.to */ rttb::core::DoseAccessorInterface::Pointer assembleOutputAccessor(rttb::apps::doseAcc::ApplicationData& appData) { rttb::core::DoseAccessorInterface::Pointer dose2Accessor = appData._dose2; if (appData._spReg.IsNotNull()) { auto transform = boost::make_shared(appData._spReg); if (appData._interpolatorName == "rosu") { dose2Accessor = generateRosuMappableAccessor(appData._dose1->getGeometricInfo(), appData._dose2, transform); } else if (appData._interpolatorName == "nn") { dose2Accessor = generateNNMappableAccessor(appData._dose1->getGeometricInfo(), appData._dose2, transform); } else if (appData._interpolatorName == "linear") { dose2Accessor = generateLinearMappableAccessor(appData._dose1->getGeometricInfo(), appData._dose2, transform); } else { rttbDefaultExceptionStaticMacro( << "Unkown interpolation type selected. Cannot map dose. Interpolation type: " << appData._interpolatorName); } } rttb::core::DoseAccessorInterface::Pointer outputAccessor; if (appData._operator == "+") { rttb::algorithms::arithmetic::doseOp::AddWeighted addOp(appData._weightDose1, appData._weightDose2); outputAccessor = boost::make_shared >(appData._dose1, dose2Accessor, addOp); } else if (appData._operator == "*") { outputAccessor = boost::make_shared > (appData._dose1, dose2Accessor, rttb::algorithms::arithmetic::doseOp::Multiply()); } else { rttbDefaultExceptionStaticMacro( << "Unkown operator selected. Cannot map dose. Operator: " << appData._interpolatorName); } return outputAccessor; } void rttb::apps::doseAcc::processData(rttb::apps::doseAcc::ApplicationData& appData) { rttb::core::DoseAccessorInterface::Pointer outputAccessor = assembleOutputAccessor( appData); std::cout << std::endl << "generate output image... "; io::itk::ITKImageAccessorConverter converter(outputAccessor); converter.setFailOnInvalidIDs(true); converter.process(); io::itk::ITKImageAccessorConverter::ITKImageType::Pointer itkImage = converter.getITKImage(); std::cout << "done." << std::endl; std::cout << std::endl << "write output image... "; io::itk::ImageWriter writer(appData._outputFileName, itkImage.GetPointer()); writer.writeFile(); std::cout << "done." << std::endl; }; diff --git a/apps/DoseAcc/DoseAccHelper.h b/apps/DoseAcc/DoseAccHelper.h index 8fb43be..9ecb548 100644 --- a/apps/DoseAcc/DoseAccHelper.h +++ b/apps/DoseAcc/DoseAccHelper.h @@ -1,49 +1,43 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_ACC_HELPER_H #define __DOSE_ACC_HELPER_H #include #include #include "rttbDoseAccessorInterface.h" #include "DoseAccApplicationData.h" namespace rttb { namespace apps { namespace doseAcc { ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); /**Contains the business logic for the accumulation of the doses and the storing of the result. Uses appData for the input data and the correct configuration.*/ void processData(ApplicationData& appData); } } } #endif diff --git a/apps/DoseMap/DoseMap.cpp b/apps/DoseMap/DoseMap.cpp index d46d82c..3cd9386 100644 --- a/apps/DoseMap/DoseMap.cpp +++ b/apps/DoseMap/DoseMap.cpp @@ -1,214 +1,208 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "DoseMapApplicationData.h" #include "DoseMapHelper.h" #include "DoseMapCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbException.h" #include "mapDummyRegistrationAlgorithm.h" #include "rttbDoseLoader.cpp" /** Main function of dose mapper. @retval 0 normal program execution @retval 2 not enough required input files. @retval 4 Error loading input dose file @retval 5 Error loading reference dose file @retval 6 Error loading registration @retval 9 Error while mapping or storing result. */ int main(int argc, const char** argv) { int result = 0; rttb::apps::doseMap::ApplicationData appData; boost::shared_ptr argParser; try { std::string appName = "DoseMap"; 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 2; } // 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; } try{ rttb::apps::doseMap::populateAppData(argParser, appData); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Input dose file: " << appData._inputDoseFileName << std::endl; std::cout << "Input dose file load style: " << appData._inputDoseLoadStyle.at(0) << std::endl; std::cout << "Output file: " << appData._outputFileName << std::endl; if (!(appData._regFileName.empty())) { std::cout << "Registration file: " << appData._regFileName << std::endl; } if (!(appData._refDoseFileName.empty())) { std::cout << "Reference dose file: " << appData._refDoseFileName << std::endl; std::cout << "Reference dose style: " << appData._refDoseLoadStyle.at(0) << std::endl; } std::cout << std::endl << "read dose file... "; try { appData._inputDose = rttb::io::utils::loadDose(appData._inputDoseFileName, appData._inputDoseLoadStyle); std::cout << "done." << std::endl; } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } if (!(appData._refDoseFileName.empty())) { try { appData._refDose = rttb::io::utils::loadDose(appData._refDoseFileName, appData._refDoseLoadStyle); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 5; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 5; } catch (...) { std::cerr << "Error!!! unknown error while reading reference image." << std::endl; return 5; } } else { appData._refDose = appData._inputDose; } if (!(appData._regFileName.empty())) { try { appData._spReg = rttb::apps::doseMap::loadRegistration(appData._regFileName); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 6; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 6; } catch (...) { std::cerr << "Error!!! unknown error while reading registration file." << std::endl; return 6; } } else { //generate dummy identity registration using DummyRegType = map::algorithm::DummyRegistrationAlgorithm<3>; DummyRegType::Pointer regAlg = DummyRegType::New(); appData._spReg = regAlg->getRegistration(); } try { rttb::apps::doseMap::processData(appData); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 9; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 9; } catch (...) { std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; return 9; } std::cout << std::endl; return result; } diff --git a/apps/DoseMap/DoseMapApplicationData.h b/apps/DoseMap/DoseMapApplicationData.h index 550b9bf..f7d426e 100644 --- a/apps/DoseMap/DoseMapApplicationData.h +++ b/apps/DoseMap/DoseMapApplicationData.h @@ -1,66 +1,65 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ #ifndef __DOSEMAP_APPLICATION_DATA_H #define __DOSEMAP_APPLICATION_DATA_H #include "mapRegistration.h" #include "rttbDoseAccessorInterface.h" - namespace rttb { namespace apps { namespace doseMap { class DoseMapCmdLineParser; /*! @class ApplicationData @brief Class for storing all relevant variables needed in DoseMap */ class ApplicationData { public: typedef map::core::Registration<3, 3> RegistrationType; /** Loaded Dose.*/ core::DoseAccessorInterface::Pointer _inputDose; std::string _inputDoseFileName; std::string _inputDoseLoadStyle; core::DoseAccessorInterface::Pointer _refDose; std::string _refDoseFileName; std::string _refDoseLoadStyle; RegistrationType::Pointer _spReg; std::string _regFileName; std::string _outputFileName; std::string _interpolatorName; 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/apps/DoseMap/DoseMapCmdLineParser.h b/apps/DoseMap/DoseMapCmdLineParser.h index d956900..677478c 100644 --- a/apps/DoseMap/DoseMapCmdLineParser.h +++ b/apps/DoseMap/DoseMapCmdLineParser.h @@ -1,63 +1,56 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #ifndef __DOSEMAP_CMD_LINE_PARSER #define __DOSEMAP_CMD_LINE_PARSER #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace doseMap { /*! @class DoseMapCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class DoseMapCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: DoseMapCmdLineParser(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_INPUT_DOSE_FILE_NAME = "inputDoseFileName"; const std::string OPTION_OUTPUT_FILE_NAME = "outputFileName"; const std::string OPTION_INTERPOLATOR = "interpolator"; const std::string OPTION_REG_FILE_NAME = "regFileName"; const std::string OPTION_REF_DOSE_FILE = "refDoseFile"; const std::string OPTION_REF_DOSE_LOAD_STYLE = "refDoseLoadStyle"; const std::string OPTION_INPUT_DOSE_LOAD_STYLE = "inputDoseLoadStyle"; }; } } } #endif \ No newline at end of file diff --git a/apps/DoseMap/DoseMapHelper.cpp b/apps/DoseMap/DoseMapHelper.cpp index 6d833d9..db54354 100644 --- a/apps/DoseMap/DoseMapHelper.cpp +++ b/apps/DoseMap/DoseMapHelper.cpp @@ -1,120 +1,113 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "DoseMapHelper.h" #include #include "mapRegistrationFileReader.h" #include "rttbITKImageAccessorConverter.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbMatchPointTransformation.h" #include "rttbLinearInterpolation.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbRosuMappableDoseAccessor.h" #include "rttbArithmetic.h" #include "rttbBinaryFunctorAccessor.h" #include "rttbExceptionMacros.h" #include "rttbImageWriter.h" rttb::apps::doseMap::ApplicationData::RegistrationType::Pointer rttb::apps::doseMap::loadRegistration(const std::string& fileName) { map::io::RegistrationFileReader::Pointer spRegReader = map::io::RegistrationFileReader::New(); map::io::RegistrationFileReader::LoadedRegistrationPointer spReg; std::cout << std::endl << "read registration file... "; spReg = spRegReader->read(fileName); std::cout << "done." << std::endl; ApplicationData::RegistrationType::Pointer resultPtr = dynamic_cast(spReg.GetPointer()); if (resultPtr.IsNull()) { mapDefaultExceptionStaticMacro( << "Loaded registration cannot be used. Only 3D 3D registrations are allowed."); } return resultPtr; }; /**Private helper function for processData(). Generates a suitable output accessor * (depending on the configuration in appData a suitable accessor pipeline is established) * which performs the accumulation of the doses and returns the output.to */ rttb::core::DoseAccessorInterface::Pointer assembleOutputAccessor(rttb::apps::doseMap::ApplicationData& appData) { rttb::core::DoseAccessorInterface::Pointer outputAccessor = appData._inputDose; auto transform = boost::make_shared(appData._spReg); if (appData._interpolatorName == "rosu") { outputAccessor = boost::make_shared(appData._refDose->getGeometricInfo(), appData._inputDose, transform); } else { rttb::interpolation::InterpolationBase::Pointer interpolate = boost::make_shared(); if (appData._interpolatorName == "nn") { interpolate = boost::make_shared(); } else if (appData._interpolatorName != "linear") { mapDefaultExceptionStaticMacro( << "Unkown interpolation type selected. Cannot map dose. Interpolation type: " << appData._interpolatorName); } outputAccessor = boost::make_shared(appData._refDose->getGeometricInfo(), appData._inputDose, transform, interpolate); } return outputAccessor; } void rttb::apps::doseMap::processData(rttb::apps::doseMap::ApplicationData& appData) { rttb::core::DoseAccessorInterface::Pointer outputAccessor = assembleOutputAccessor( appData); std::cout << std::endl << "generate output image... "; io::itk::ITKImageAccessorConverter converter(outputAccessor); converter.setFailOnInvalidIDs(true); converter.process(); io::itk::ITKImageAccessorConverter::ITKImageType::Pointer itkImage = converter.getITKImage(); std::cout << "done." << std::endl; std::cout << std::endl << "write output image... "; io::itk::ImageWriter writer(appData._outputFileName, itkImage.GetPointer()); writer.writeFile(); std::cout << "done." << std::endl; }; diff --git a/apps/DoseMap/DoseMapHelper.h b/apps/DoseMap/DoseMapHelper.h index 047e577..00ed90c 100644 --- a/apps/DoseMap/DoseMapHelper.h +++ b/apps/DoseMap/DoseMapHelper.h @@ -1,44 +1,38 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_MAP_HELPER_H #define __DOSE_MAP_HELPER_H #include "DoseMapApplicationData.h" namespace rttb { namespace apps { namespace doseMap { ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); /**Contains the business logic for the accumulation of the doses and the storing of the result. Uses appData for the input data and the correct configuration.*/ void processData(ApplicationData& appData); } } } #endif diff --git a/apps/DoseTool/DoseToolCmdLineParser.h b/apps/DoseTool/DoseToolCmdLineParser.h index 685c955..d720e18 100644 --- a/apps/DoseTool/DoseToolCmdLineParser.h +++ b/apps/DoseTool/DoseToolCmdLineParser.h @@ -1,66 +1,61 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSETOOL_CMD_LINE_PARSER #define __DOSETOOL_CMD_LINE_PARSER #include "CmdLineParserBase.h" + namespace rttb { namespace apps { namespace doseTool { /*! @class DoseToolCmdLineParser @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, const std::string& description, const std::string& contributor, const std::string& category); 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_DOSE_STATISTICS = "doseStatistics"; const std::string OPTION_DVH = "DVH"; 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"; const std::string OPTION_MULTIPLE_STRUCTS_MODE = "multipleStructsMode"; }; } } } #endif \ No newline at end of file diff --git a/apps/DoseTool/DoseToolHelper.h b/apps/DoseTool/DoseToolHelper.h index 54f2da1..02a2840 100644 --- a/apps/DoseTool/DoseToolHelper.h +++ b/apps/DoseTool/DoseToolHelper.h @@ -1,60 +1,53 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSETOOL_HELPER_H #define __DOSETOOL_HELPER_H - #include "rttbDoseAccessorInterface.h" #include "rttbStructureSetGeneratorInterface.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" namespace rttb { namespace apps { namespace doseTool { class ApplicationData; /*! @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 Generates a mask from the struct file by using the boostAccessor. In case of itk image, it directly loads the voxelized image. */ std::vector generateMasks( ApplicationData& appData); core::DoseIteratorInterface::Pointer generateMaskedDoseIterator( core::MaskAccessorInterface::Pointer maskAccessorPtr, core::DoseAccessorInterface::Pointer doseAccessorPtr); std::string assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName); } } } #endif diff --git a/apps/VoxelizerTool/VoxelizerTool.cpp b/apps/VoxelizerTool/VoxelizerTool.cpp index 9e70d48..789b713 100644 --- a/apps/VoxelizerTool/VoxelizerTool.cpp +++ b/apps/VoxelizerTool/VoxelizerTool.cpp @@ -1,149 +1,144 @@ // ----------------------------------------------------------------------- // 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: 1390 $ (last changed revision) -// @date $Date: 2016-07-13 09:57:44 +0200 (Mi, 13 Jul 2016) $ (last change date) -// @author $Author: strubel $ (last changed by) -*/ + #include #include "VoxelizerToolHelper.h" #include "VoxelizerToolCmdLineParser.h" #include "VoxelizerToolApplicationData.h" #include "rttbDoseLoader.cpp" #include "rttbStructLoader.cpp" int main(int argc, const char** argv) { rttb::apps::voxelizerTool::ApplicationData appData; const std::string appCategory = "RT-Toolbox App"; const std::string appName = "VoxelizerTool"; const std::string appDesc = "An App to voxelize RT structures in a reference image."; const std::string appContributor = "SIDT@DKFZ"; const std::string appVersion = RTTB_FULL_VERSION_STRING; boost::shared_ptr argParser; try { argParser = boost::make_shared(argc, argv, appName, appVersion, appDesc, appContributor, appCategory); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return 5; } // 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) || argParser->isSet(argParser->OPTION_XML)) { return 0; } rttb::apps::voxelizerTool::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Struct file: " << appData._structFile << std::endl; std::cout << "Reference Image: " << appData._referenceFile << std::endl; std::cout << "Output file: " << appData._outputFilename << std::endl; std::cout << "Struct regex: " << appData._regEx << std::endl; std::cout << "Add structures: " << appData._addStructures << std::endl; std::cout << "Multiple Struct: " << appData._multipleStructs << std::endl; std::cout << "Strict voxelization: " << !appData._noStrictVoxelization << std::endl << std::endl; std::cout << "reading reference and structure file..." << std::endl; try { appData._dose = rttb::io::utils::loadDose(appData._referenceFile, appData._referenceFileLoadStyle); } 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 input dose image." << std::endl; return 2; } try { appData._struct = rttb::io::utils::loadStruct(appData._structFile, appData._structFileLoadStyle, appData._regEx); } 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 input struct image." << std::endl; return 2; } std::cout << "done." << std::endl; try { rttb::apps::voxelizerTool::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error while doing voxelization!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (itk::ExceptionObject& err) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; return 3; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (...) { std::cerr << "Error!!! unknown error while doing voxelization." << std::endl; return 3; } return 0; } diff --git a/apps/VoxelizerTool/VoxelizerToolApplicationData.h b/apps/VoxelizerTool/VoxelizerToolApplicationData.h index db8e74f..2ea07f6 100644 --- a/apps/VoxelizerTool/VoxelizerToolApplicationData.h +++ b/apps/VoxelizerTool/VoxelizerToolApplicationData.h @@ -1,66 +1,65 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ - #ifndef __VoxelizerApplicationData_h #define __VoxelizerApplicationData_h #include "boost/shared_ptr.hpp" #include "rttbDoseAccessorInterface.h" #include "rttbStructureSetGeneratorInterface.h" #include #include namespace rttb { namespace apps { namespace voxelizerTool { class VoxelizerCmdLineParser; /*! @class ApplicationData @brief Class for storing all relevant variables needed in VoxelizerTool */ class ApplicationData { public: core::DoseAccessorInterface::Pointer _dose; core::StructureSet::Pointer _struct; std::string _structFile; std::string _referenceFile; std::string _outputFilename; std::string _regEx; std::string _referenceFileLoadStyle; std::string _structFileLoadStyle; bool _multipleStructs; bool _binaryVoxelization; bool _addStructures; bool _noStrictVoxelization; /*! @brief Resets the variables. */ void reset(); ApplicationData(); }; /*! @brief Reads the necessary arguments from the VoxelizerCmdLineParser and writes them in the respective variables of ApplicationData. */ void populateAppData(boost::shared_ptr argParser, ApplicationData& appData); } } } #endif diff --git a/apps/VoxelizerTool/VoxelizerToolCmdLineParser.h b/apps/VoxelizerTool/VoxelizerToolCmdLineParser.h index 5a54c71..9ec9e91 100644 --- a/apps/VoxelizerTool/VoxelizerToolCmdLineParser.h +++ b/apps/VoxelizerTool/VoxelizerToolCmdLineParser.h @@ -1,65 +1,59 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __VoxelizerCmdLineParser_h #define __VoxelizerCmdLineParser_h #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace voxelizerTool { /*! @class VoxelizerCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class VoxelizerCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: VoxelizerCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version, const std::string& description, const std::string& contributor, const std::string& category); void validateInput() const override; void printHelp() const override; // Option groups const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; // Parameters const std::string OPTION_STRUCT_FILE = "structFile"; const std::string OPTION_REFERENCE_FILE = "referenceFile"; const std::string OPTION_REFERENCE_FILE_LOAD_STYLE = "referenceFileLoadStyle"; const std::string OPTION_OUTPUT_FILE_NAME = "output"; const std::string OPTION_REGEX = "struct"; const std::string OPTION_MULTIPLE_STRUCTS = "multipleStructs"; const std::string OPTION_BINARY_VOXELIZATION = "binaryVoxelization"; const std::string OPTION_ADDSTRUCTURES = "addStructures"; const std::string OPTION_NO_STRICT_VOXELIZATION = "noStrictVoxelization"; }; } } } #endif \ No newline at end of file diff --git a/apps/VoxelizerTool/VoxelizerToolHelper.cpp b/apps/VoxelizerTool/VoxelizerToolHelper.cpp index d53f3a5..a946e7b 100644 --- a/apps/VoxelizerTool/VoxelizerToolHelper.cpp +++ b/apps/VoxelizerTool/VoxelizerToolHelper.cpp @@ -1,216 +1,211 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ + #include #include "rttbBoostMaskAccessor.h" #include "itkMacro.h" #include "VoxelizerToolHelper.h" #include "VoxelizerToolApplicationData.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbImageWriter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkAddImageFilter.h" #include #include #include "rttbUtils.h" #include "rttbDicomFileStructureSetGenerator.h" void rttb::apps::voxelizerTool::removeSpecialCharacters(std::string& label) { //Replace / to avoid problems with directories (struct "Magen/DD" --> Magen/DD.mhd), delete trailing . to avoid filenames with two trailing points (Niere re. --> Niere re..mhd) while (label.find("/") != std::string::npos) { label.replace(label.find("/"), 1, "_"); } if (*label.rbegin() == '.') { label.replace(label.size() - 1, 1, ""); } } rttb::core::MaskAccessorInterface::Pointer rttb::apps::voxelizerTool::createMask( rttb::core::DoseAccessorInterface::Pointer doseAccessorPtr, rttb::core::Structure::Pointer structurePtr, bool strict) { rttb::core::MaskAccessorInterface::Pointer maskAccessorPtr; if (doseAccessorPtr != nullptr && structurePtr != nullptr) { maskAccessorPtr = boost::make_shared (structurePtr, doseAccessorPtr->getGeometricInfo(), strict); maskAccessorPtr->updateMask(); } return maskAccessorPtr; } void rttb::apps::voxelizerTool::writeMaskToFile(std::vector maskVector, const std::string& outputFileName, bool voxelization) { if (!maskVector.empty()) { io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage; if (maskVector.size() > 1) { itkImage = addMultipleStructsToImage(maskVector); } else { io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskVector.at(0)); maskAccessorConverter.process(); itkImage = maskAccessorConverter.getITKImage(); } if (voxelization) { itkImage = applyThresholdFilter(itkImage); } io::itk::ImageWriter writer(outputFileName, itkImage); writer.writeFile(); } } rttb::io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer rttb::apps::voxelizerTool::addMultipleStructsToImage( std::vector maskVector) { std::vector listOfITKImages; for (const auto & i : maskVector) { io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(i); maskAccessorConverter.process(); listOfITKImages.push_back(maskAccessorConverter.getITKImage()); } itk::AddImageFilter , itk::Image>::Pointer addFilter = itk::AddImageFilter , itk::Image>::New(); io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer filterResult; for (int k = 1; k < listOfITKImages.size(); k++) { if (k == 1) { addFilter->SetInput1(listOfITKImages.at(0)); } else { addFilter->SetInput1(filterResult); } addFilter->SetInput2(listOfITKImages.at(k)); addFilter->Update(); filterResult = addFilter->GetOutput(); } return filterResult.GetPointer(); } rttb::io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer rttb::apps::voxelizerTool::applyThresholdFilter( io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage) { itk::BinaryThresholdImageFilter< itk::Image, itk::Image >::Pointer filter = itk::BinaryThresholdImageFilter< itk::Image, itk::Image >::New(); filter->SetInput(itkImage); filter->SetLowerThreshold(0.5); filter->SetUpperThreshold(1.0); filter->SetInsideValue(1.0); filter->Update(); return filter->GetOutput(); } void rttb::apps::voxelizerTool::processData(rttb::apps::voxelizerTool::ApplicationData& appData) { if (appData._struct->getNumberOfStructures()>0) { std::vector maskVector; if (appData._addStructures) { for (size_t i=0; igetNumberOfStructures(); i++ ) { std::cout << "creating mask #" << i << "..."; maskVector.push_back(createMask(appData._dose, appData._struct->getStructure(i), !appData._noStrictVoxelization)); std::cout << "done" << std::endl; } std::cout << "writing mask to file..."; writeMaskToFile(maskVector, appData._outputFilename, appData._binaryVoxelization); std::cout << "done" << std::endl; } else { //default behavior: read only first struct that matches the regex unsigned int maxIterationCount = 1; //only if specified: read all structs that matches the regex if (appData._multipleStructs) { maxIterationCount = appData._struct->getNumberOfStructures(); } for (size_t i = 0; igetStructure(i), !appData._noStrictVoxelization); std::cout << "done" << std::endl; std::string labelOfInterest = appData._struct->getStructure(i)->getLabel(); removeSpecialCharacters(labelOfInterest); std::string outputName = appData._outputFilename; if (appData._multipleStructs) { std::string fileName = rttb::core::getFilenameWithoutEnding( appData._outputFilename); std::string fileEnding = rttb::core::getFileEnding(appData._outputFilename); outputName = fileName + "_" + labelOfInterest + fileEnding; } std::vector currenMaskVector{ currentMask }; std::cout << "writing mask #" << i << " to file..."; writeMaskToFile(currenMaskVector, outputName, appData._binaryVoxelization); std::cout << "done" << std::endl; } } } else { std::cout << "No struct found" << std::endl; } } \ No newline at end of file diff --git a/apps/VoxelizerTool/VoxelizerToolHelper.h b/apps/VoxelizerTool/VoxelizerToolHelper.h index 14482aa..a8dae7e 100644 --- a/apps/VoxelizerTool/VoxelizerToolHelper.h +++ b/apps/VoxelizerTool/VoxelizerToolHelper.h @@ -1,67 +1,61 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include #include "rttbStructure.h" #include "rttbMaskAccessorInterface.h" #include "rttbITKImageMaskAccessor.h" #include "rttbDoseAccessorInterface.h" namespace rttb { namespace apps { namespace voxelizerTool { class ApplicationData; void processData(ApplicationData& appData); /**@brief Search the label with the position from index @return a label from the list as string */ void removeSpecialCharacters(std::string& label); /**@brief create a mask with _rtStructureSet and _doseAccessor object. @return a mask object */ core::MaskAccessorInterface::Pointer createMask( core::DoseAccessorInterface::Pointer doseAccessorPtr, rttb::core::Structure::Pointer structurePtr, bool strict); /**@brief write the mask into the outputfile @param Outputfilename */ void writeMaskToFile(std::vector maskVector, const std::string& outputFileName, bool voxelization); io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer addMultipleStructsToImage( std::vector maskVector); io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer applyThresholdFilter( io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer itkImage); } } } \ No newline at end of file diff --git a/cmake/moduleExports.h.in b/cmake/moduleExports.h.in index 26ba997..0e79d53 100644 --- a/cmake/moduleExports.h.in +++ b/cmake/moduleExports.h.in @@ -1,42 +1,36 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "RTToolboxConfigure.h" #ifndef @MODULE_NAME@_EXPORTS_H #define @MODULE_NAME@_EXPORTS_H #if defined(WIN32) && !defined(RTTB_STATIC) #ifdef @MODULE_PROVIDES@_EXPORTS #define @MODULE_EXPORT_DEFINE@ __declspec(dllexport) #else #define @MODULE_EXPORT_DEFINE@ __declspec(dllimport) #endif #else #define @MODULE_EXPORT_DEFINE@ #endif #ifndef _CMAKE_MODULENAME #ifdef @MODULE_PROVIDES@_EXPORTS #define _CMAKE_MODULENAME "@MODULE_NAME@" #endif #endif #endif diff --git a/code/algorithms/rttbArithmetic.cpp b/code/algorithms/rttbArithmetic.cpp index 52bdf2b..fa10e9a 100644 --- a/code/algorithms/rttbArithmetic.cpp +++ b/code/algorithms/rttbArithmetic.cpp @@ -1,106 +1,99 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbArithmetic.h" - namespace rttb { namespace algorithms { namespace arithmetic { void add(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result) { doseOp::Add addOP; arithmetic(dose1, dose2, result, addOP); } void add(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result) { maskOp::Add addOP; arithmetic(mask1, mask2, result, addOP); } void subtract(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result) { maskOp::Subtract subOP; arithmetic(mask1, mask2, result, subOP); } void multiply(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result) { doseMaskOp::Multiply multOP; arithmetic(dose, mask, result, multOP); } namespace doseOp { DoseTypeGy Add::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return dose1Val + dose2Val; } AddWeighted::AddWeighted(const DoseCalcType w1, const DoseCalcType w2): weight1(w1), weight2(w2) {}; DoseTypeGy AddWeighted::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return weight1 * dose1Val + weight2 * dose2Val; } rttb::DoseTypeGy Multiply::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return dose1Val * dose2Val; } } namespace doseMaskOp { DoseTypeGy Multiply::calc(const DoseTypeGy doseVal, const FractionType maskVal) const { return doseVal * maskVal; } } namespace maskOp { FractionType Add::calc(const FractionType mask1Val, const FractionType mask2Val) const { FractionType added = mask1Val + mask2Val; return (1 < added ? 1 : added); } FractionType Subtract::calc(const FractionType mask1Val, const FractionType mask2Val) const { FractionType sub = mask1Val - mask2Val; return (0 > sub ? 0 : sub); } } } } } \ No newline at end of file diff --git a/code/algorithms/rttbArithmetic.h b/code/algorithms/rttbArithmetic.h index d62e403..3049953 100644 --- a/code/algorithms/rttbArithmetic.h +++ b/code/algorithms/rttbArithmetic.h @@ -1,159 +1,153 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __ARITHMETIC_H #define __ARITHMETIC_H #include "rttbDoseAccessorInterface.h" #include "rttbMutableMaskAccessorInterface.h" #include "rttbMutableDoseAccessorInterface.h" #include "rttbMaskAccessorInterface.h" namespace rttb { namespace algorithms { namespace arithmetic { using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; using MutableDoseAccessorPointer = core::MutableDoseAccessorInterface::Pointer; using MutableMaskAccessorPointer = core::MutableMaskAccessorInterface::Pointer; using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; /*! Applies the given dose operation to the given doses and stores the result in result @pre pointers to accessors are !nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template void arithmetic(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result, TDoseOperation op); ///*! Applies the given dose operation to the mapped given doses (transformation given by MatchPoint) and stores the result in result // @pre pointers to accessors are ! nullptr. // @exception NullPointerException thrown if one of the input accessors is nullptr. // @exception TransformationOutsideImageException thrown if the transformation maps to a position outside the original image. // */ // template // void arithmetic (const DoseAccessorPointer dose1, const MappableDoseAccessorPointer dose2, // MutableDoseAccessorPointer result, TDoseOperation op); /*! Applies the given dose-mask operation to the given dose and mask and stores the result in result @pre pointers to accessors are ! nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template void arithmetic(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result, TDoseMaskOperation op); /*! Applies the given mask operation to the given masks and stores the result in result @pre pointers to accessors are !nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template void arithmetic(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result, TMaskOperation op); //convenience functions void add(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result); //void add(const DoseAccessorPointer dose1, const MappableDoseAccessorPointer dose2, // MutableDoseAccessorPointer result); void add(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result); void subtract(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result); void multiply(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result); /*all operation classes need to implement the function calc() that performs the entry wise operation The operations are sorted into name spaces according to useful application. If the input values are compatible the operations can also be applied to accessors they were not meant for. */ //Operations for binary-dose-operation template namespace doseOp { class Add { public: DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; class AddWeighted { private: DoseCalcType weight1, weight2; public: /* ! Constructor initializes weights applied to individual doses values on adding. */ AddWeighted(const DoseCalcType w1 = 1, const DoseCalcType w2 = 1); DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; class Multiply { public: DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; } //Operations for binary-dose-mask-operation template namespace doseMaskOp { class Multiply { public: DoseTypeGy calc(const DoseTypeGy doseVal, const FractionType maskVal) const; }; } //Operations for binary-mask-operation template //the result of these operations needs to be between 0 and 1 namespace maskOp { class Add { public: FractionType calc(const FractionType mask1Val, const FractionType mask2Val) const; }; class Subtract { public: FractionType calc(const FractionType mask1Val, const FractionType mask2Val) const; }; } }//end namespace arithmetic }//end namespace algorithms }//end namespace core #include "rttbArithmetic.tpp" #endif diff --git a/code/algorithms/rttbArithmetic.tpp b/code/algorithms/rttbArithmetic.tpp index 21de034..09eabec 100644 --- a/code/algorithms/rttbArithmetic.tpp +++ b/code/algorithms/rttbArithmetic.tpp @@ -1,129 +1,123 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #ifndef __ARITHMETIC_TPP #define __ARITHMETIC_TPP namespace rttb { namespace algorithms { namespace arithmetic { template void arithmetic(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result, TDoseOperation op) { //handle null pointers if (dose1 == nullptr || dose2 == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(dose1->getGeometricInfo().equalsAlmost(dose2->getGeometricInfo()) && dose1->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to doses with equal geometricInfo (same grid) GridSizeType numVoxels = dose1->getGridSize(); for (VoxelGridID id = 0; id < numVoxels; ++id) { DoseTypeGy opVal = op.calc(dose1->getValueAt(id), dose2->getValueAt(id)); result->setDoseAt(id, opVal); } } template void arithmetic(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result, TDoseMaskOperation op) { //handle null pointers if (dose == nullptr || mask == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(dose->getGeometricInfo().equalsAlmost(mask->getGeometricInfo()) && dose->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to accessors with equal geometricInfo (same grid) core::MaskVoxel mVoxel(0); GridSizeType numVoxels = dose->getGridSize(); for (VoxelGridID id = 0; id < numVoxels; ++id) { mask->getMaskAt(id, mVoxel); DoseTypeGy opVal = op.calc(dose->getValueAt(id), mVoxel.getRelevantVolumeFraction()); result->setDoseAt(id, opVal); } } template void arithmetic(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result, TMaskOperation op) { //handle null pointers if (mask1 == nullptr || mask2 == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(mask1->getGeometricInfo().equalsAlmost(mask2->getGeometricInfo()) && mask1->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to accessors with equal geometricInfo (same grid) core::MaskVoxel m1Voxel(0); //initialize results list with mask1 values result->setRelevantVoxelVector(mask1->getRelevantVoxelVector()); MaskVoxelListPointer voxelListMask2 = mask2->getRelevantVoxelVector(); auto it = voxelListMask2->begin(); while (it != voxelListMask2->end()) { mask1->getMaskAt(it->getVoxelGridID(), m1Voxel); FractionType opVal = op.calc(m1Voxel.getRelevantVolumeFraction(), it->getRelevantVolumeFraction()); result->setMaskAt(it->getVoxelGridID(), core::MaskVoxel(it->getVoxelGridID(), opVal)); ++it; } } } } } #endif \ No newline at end of file diff --git a/code/algorithms/rttbBinaryFunctorAccessor.h b/code/algorithms/rttbBinaryFunctorAccessor.h index ffa3e45..0b927a9 100644 --- a/code/algorithms/rttbBinaryFunctorAccessor.h +++ b/code/algorithms/rttbBinaryFunctorAccessor.h @@ -1,99 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __BINARY_FUNCTOR_ACCESSOR_H #define __BINARY_FUNCTOR_ACCESSOR_H #include "rttbAccessorInterface.h" #include "rttbBaseType.h" namespace rttb { namespace algorithms { /*! @class BinaryFunctorAccessor @brief Class that allows to access the results of a binary operation. @details this Accessor takes two accessors as operants (the operants must have the same geometry) and computes a resulting value by using a given operation functor. The resulting value will be returned from the accessor as its value upon request. @remark this can be seen as a lazy filter pattern, thus the accessor is filtering/operating on dose values upon request. */ template class BinaryFunctorAccessor: public core::AccessorInterface { protected: core::AccessorInterface::ConstPointer _spData1; core::AccessorInterface::ConstPointer _spData2; TDoseOperation _functor; public: /*! @brief Constructor. @param data1 pointer to the 1st data operand @param data2 pointer to the 2nd data operand @param functor Instance of the operation that should be used @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is nullptr or if geometricInfos don't match */ BinaryFunctorAccessor(core::AccessorInterface::ConstPointer data1, core::AccessorInterface::ConstPointer data2, const TDoseOperation& functor); /*! @brief Virtual destructor */ ~BinaryFunctorAccessor() override = default; /*! @pre: the geometricInfo of both doseAccessors are equal */ inline const core::GeometricInfo& getGeometricInfo() const override { return _spData1->getGeometricInfo(); }; /*! @pre: the geometricInfo of both doseAccessors are equal */ inline GridSizeType getGridSize() const override { return _spData1->getGeometricInfo().getNumberOfVoxels(); }; /*! @brief Returns the result dose computed by the functor. It uses the dose values of both operand doses specified via the passed ID. @return the dose value if inside, -1 else @pre .calc(dose1,dose2) has to be implemented */ GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief Returns the result dose computed by the functor. It uses the dose values of both operand doses specified via the passed index. @return the dose value if inside, -1 else @pre .calc(dose1,dose2) has to be implemented */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return IDType(); } }; } } #include "rttbBinaryFunctorAccessor.tpp" #endif diff --git a/code/algorithms/rttbBinaryFunctorAccessor.tpp b/code/algorithms/rttbBinaryFunctorAccessor.tpp index 7b2887d..c56e9ed 100644 --- a/code/algorithms/rttbBinaryFunctorAccessor.tpp +++ b/code/algorithms/rttbBinaryFunctorAccessor.tpp @@ -1,82 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbBinaryFunctorAccessor.h" #ifndef __BINARY_FUNCTOR_ACCESSOR_TPP #define __BINARY_FUNCTOR_ACCESSOR_TPP namespace rttb { namespace algorithms { template BinaryFunctorAccessor::BinaryFunctorAccessor(core::AccessorInterface::ConstPointer data1, core::AccessorInterface::ConstPointer data2, const TDoseOperation& functor) { if (data1 == nullptr || data2 == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } if (!(data1->getGeometricInfo() == data2->getGeometricInfo())) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } _spData1 = data1; _spData2 = data2; _functor = functor; } template GenericValueType BinaryFunctorAccessor::getValueAt( const VoxelGridID aID) const { if (getGeometricInfo().validID(aID)) { GenericValueType value = _functor.calc(_spData1->getValueAt(aID), _spData2->getValueAt(aID)); return value; } else { return -1; } } template DoseTypeGy BinaryFunctorAccessor::getValueAt( const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_spData1->getGeometricInfo().convert(aIndex, aVoxelGridID)) { return getValueAt(aVoxelGridID); } else { return -1; } } } } #endif \ No newline at end of file diff --git a/code/algorithms/rttbDoseStatistics.cpp b/code/algorithms/rttbDoseStatistics.cpp index 464a80f..a1147a0 100644 --- a/code/algorithms/rttbDoseStatistics.cpp +++ b/code/algorithms/rttbDoseStatistics.cpp @@ -1,293 +1,287 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDoseStatistics.h" #include "boost/make_shared.hpp" #include "rttbDataNotAvailableException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace algorithms { DoseStatistics::DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, DoseStatisticType stdDeviation, VoxelNumberType numVoxels, VolumeType volume, ResultListPointer maximumVoxelPositions /*= ResultListPointer()*/, ResultListPointer minimumVoxelPositions /*= ResultListPointer()*/, VolumeToDoseMeasureCollection Dx, DoseToVolumeMeasureCollection Vx, VolumeToDoseMeasureCollection MOHx, VolumeToDoseMeasureCollection MOCx, VolumeToDoseMeasureCollection MaxOHx, VolumeToDoseMeasureCollection MinOCx, DoseTypeGy referenceDose /*=-1*/): _minimum(minimum), _maximum(maximum), _mean(mean), _stdDeviation(stdDeviation), _numVoxels(numVoxels), _volume(volume), _Dx(::boost::make_shared(Dx)), _Vx(::boost::make_shared(Vx)), _MOHx(::boost::make_shared(MOHx)), _MOCx(::boost::make_shared(MOCx)), _MaxOHx(::boost::make_shared(MaxOHx)), _MinOCx(::boost::make_shared(MinOCx)) { if (maximumVoxelPositions == nullptr) { _maximumVoxelPositions = boost::make_shared > > (std::vector >()); } else { _maximumVoxelPositions = maximumVoxelPositions; } if (minimumVoxelPositions == nullptr) { _minimumVoxelPositions = boost::make_shared > > (std::vector >()); } else { _minimumVoxelPositions = minimumVoxelPositions; } if (referenceDose <= 0) { _referenceDose = _maximum; } else { _referenceDose = referenceDose; } } DoseStatistics::~DoseStatistics() = default; void DoseStatistics::setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions) { _minimumVoxelPositions = minimumVoxelPositions; } void DoseStatistics::setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions) { _maximumVoxelPositions = maximumVoxelPositions; } void DoseStatistics::setDx(VolumeToDoseMeasureCollection::Pointer DxValues) { _Dx = DxValues; } void DoseStatistics::setVx(DoseToVolumeMeasureCollection::Pointer VxValues) { _Vx = VxValues; } void DoseStatistics::setMOHx(VolumeToDoseMeasureCollection::Pointer MOHxValues) { _MOHx = MOHxValues; } void DoseStatistics::setMOCx(VolumeToDoseMeasureCollection::Pointer MOCxValues) { _MOCx = MOCxValues; } void DoseStatistics::setMaxOHx(VolumeToDoseMeasureCollection::Pointer MaxOHValues) { _MaxOHx = MaxOHValues; } void DoseStatistics::setMinOCx(VolumeToDoseMeasureCollection::Pointer MinOCValues) { _MinOCx = MinOCValues; } void DoseStatistics::setReferenceDose(DoseTypeGy referenceDose) { if (referenceDose <= 0) { _referenceDose = _maximum; } else { _referenceDose = referenceDose; } } VoxelNumberType DoseStatistics::getNumberOfVoxels() const { return _numVoxels; } VolumeType DoseStatistics::getVolume() const { return _volume; } DoseTypeGy DoseStatistics::getReferenceDose() const { return _referenceDose; } DoseStatisticType DoseStatistics::getMaximum() const { return _maximum; } DoseStatisticType DoseStatistics::getMinimum() const { return _minimum; } DoseStatisticType DoseStatistics::getMean() const { return _mean; } DoseStatisticType DoseStatistics::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DoseStatistics::getVariance() const { return _stdDeviation * _stdDeviation; } double DoseStatistics::getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const { if (aMap.find(key) != std::end(aMap)) { return aMap.find(key)->second; } else { //value not in map. We have to find the nearest value if (aMap.empty()) { throw core::DataNotAvailableException("No Vx values are defined"); } else { if (findNearestValueInstead) { auto iterator = findNearestKeyInMap(aMap, key); storedKey = iterator->first; return iterator->second; } else { throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } } } std::map::const_iterator DoseStatistics::findNearestKeyInMap( const std::map& aMap, double key) const { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(aMap); while (iterator != std::end(aMap)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(aMap)) { --iterator; return iterator; } else { return std::begin(aMap); } } } --iterator; return iterator; } DoseStatistics::ResultListPointer DoseStatistics::getMaximumVoxelPositions() const { return _maximumVoxelPositions; } DoseStatistics::ResultListPointer DoseStatistics::getMinimumVoxelPositions() const { return _minimumVoxelPositions; } DoseToVolumeMeasureCollection DoseStatistics::getVx() const { return *_Vx; } VolumeToDoseMeasureCollection DoseStatistics::getDx() const { return *_Dx; } VolumeToDoseMeasureCollection DoseStatistics::getMOHx() const { return *_MOHx; } VolumeToDoseMeasureCollection DoseStatistics::getMOCx() const { return *_MOCx; } VolumeToDoseMeasureCollection DoseStatistics::getMaxOHx() const { return *_MaxOHx; } VolumeToDoseMeasureCollection DoseStatistics::getMinOCx() const { return *_MinOCx; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatistics.h b/code/algorithms/rttbDoseStatistics.h index 6bd70bb..2480321 100644 --- a/code/algorithms/rttbDoseStatistics.h +++ b/code/algorithms/rttbDoseStatistics.h @@ -1,178 +1,172 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DOSE_STATISTICS_H #define __DOSE_STATISTICS_H #include #include #include #include #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" #include "rttbVolumeToDoseMeasureCollection.h" #include "rttbDoseToVolumeMeasureCollection.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseStatistics @brief This is a data class storing different statistical values from a rt dose distribution @sa DoseStatisticsCalculator */ class RTTBAlgorithms_EXPORT DoseStatistics { public: rttbClassMacroNoParent(DoseStatistics); typedef boost::shared_ptr > > ResultListPointer; private: double getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const; std::map::const_iterator findNearestKeyInMap(const std::map& aMap, double key) const; DoseStatisticType _minimum; DoseStatisticType _maximum; DoseStatisticType _mean; DoseStatisticType _stdDeviation; VoxelNumberType _numVoxels; VolumeType _volume; ResultListPointer _minimumVoxelPositions; ResultListPointer _maximumVoxelPositions; VolumeToDoseMeasureCollection::Pointer _Dx; DoseToVolumeMeasureCollection::Pointer _Vx; VolumeToDoseMeasureCollection::Pointer _MOHx; VolumeToDoseMeasureCollection::Pointer _MOCx; VolumeToDoseMeasureCollection::Pointer _MaxOHx; VolumeToDoseMeasureCollection::Pointer _MinOCx; DoseTypeGy _referenceDose; //for Vx computation public: /*! @brief Standard Constructor */ //DoseStatistics(); /*! @brief Constructor @details the dose statistic values are set. Complex values maximumVoxelLocation, maximumVoxelLocation, Dx, Vx, MOHx, MOCx, MaxOHx and MinOCx are optional */ DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, DoseStatisticType stdDeviation, VoxelNumberType numVoxels, VolumeType volume, ResultListPointer minimumVoxelPositions = nullptr, ResultListPointer maximumVoxelPositions = nullptr, VolumeToDoseMeasureCollection Dx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::Dx), DoseToVolumeMeasureCollection Vx = DoseToVolumeMeasureCollection(DoseToVolumeMeasureCollection::Vx), VolumeToDoseMeasureCollection MOHx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MOHx), VolumeToDoseMeasureCollection MOCx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MOCx), VolumeToDoseMeasureCollection MaxOHx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MaxOHx), VolumeToDoseMeasureCollection MinOCx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MinOCx), DoseTypeGy referenceDose = -1); ~DoseStatistics(); void setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions); void setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions); void setDx(VolumeToDoseMeasureCollection::Pointer DxValues); void setVx(DoseToVolumeMeasureCollection::Pointer VxValues); void setMOHx(VolumeToDoseMeasureCollection::Pointer MOHxValues); void setMOCx(VolumeToDoseMeasureCollection::Pointer MOCxValues); void setMaxOHx(VolumeToDoseMeasureCollection::Pointer MaxOHxValues); void setMinOCx(VolumeToDoseMeasureCollection::Pointer MinOCxValues); void setReferenceDose(DoseTypeGy referenceDose); /*! @brief Get number of voxels in doseIterator, with sub-voxel accuracy. */ VoxelNumberType getNumberOfVoxels() const; /*! @brief Get the volume of the voxels in doseIterator (in cm3), with sub-voxel accuracy */ VolumeType getVolume() const; /*! @brief Get the reference dose for Vx computation */ DoseTypeGy getReferenceDose() const; /*! @brief Get the maximum of the current dose distribution. @return Return the maximum dose in Gy */ DoseStatisticType getMaximum() const; /*! @brief Get a vector of the the maximum dose VoxelGridIDs together with their dose value in Gy @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMaximumVoxelPositions() const; /*! @brief Get the minimum of the current dose distribution. @return Return the minimum dose in Gy */ DoseStatisticType getMinimum() const; /*! @brief Get a vector of the the minimum dose VoxelGridIDs together with their dose value in Gy @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMinimumVoxelPositions() const; /*! @brief Get the mean of the current dose distribution. @return Return the mean dose in Gy */ DoseStatisticType getMean() const; /*! @brief Get the standard deviation of the current dose distribution. @return Return the standard deviation in Gy */ DoseStatisticType getStdDeviation() const; /*! @brief Get the variance of of the current dose distribution. @return Return the variance in Gy */ DoseStatisticType getVariance() const; VolumeToDoseMeasureCollection getDx() const; DoseToVolumeMeasureCollection getVx() const; VolumeToDoseMeasureCollection getMOHx() const; VolumeToDoseMeasureCollection getMOCx() const; VolumeToDoseMeasureCollection getMaxOHx() const; VolumeToDoseMeasureCollection getMinOCx() const; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseStatisticsCalculator.cpp b/code/algorithms/rttbDoseStatisticsCalculator.cpp index f46b77c..6969acb 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.cpp +++ b/code/algorithms/rttbDoseStatisticsCalculator.cpp @@ -1,419 +1,413 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDoseStatisticsCalculator.h" #include #include #include #include #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include namespace rttb { namespace algorithms { DoseStatisticsCalculator::DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator) { if (aDoseIterator == nullptr) { throw core::NullPointerException("DoseIterator must not be nullptr"); } else { _doseIterator = aDoseIterator; } _simpleDoseStatisticsCalculated = false; _complexDoseStatisticsCalculated = false; _multiThreading = false; _mutex = ::boost::make_shared<::boost::shared_mutex>(); } DoseStatisticsCalculator::~DoseStatisticsCalculator() = default; DoseStatisticsCalculator::DoseIteratorPointer DoseStatisticsCalculator::getDoseIterator() const { return _doseIterator; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( bool computeComplexMeasures, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } //"simple" dose statistics are mandatory calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); if (computeComplexMeasures) { //more complex dose statistics are optional with default maximum dose and default relative x values calculateComplexDoseStatistics(_statistics->getMaximum(), std::vector(), std::vector()); } return _statistics; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } if (referenceDose <= 0) { throw rttb::core::InvalidParameterException("Reference dose must be > 0 !"); } //simple dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); //more complex dose statistics with given reference dose and default x values calculateComplexDoseStatistics(referenceDose, std::vector(), std::vector()); return _statistics; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } //"simple" dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); if (referenceDose <= 0) { //more complex dose statistics with default maximum dose and relative x values calculateComplexDoseStatistics(_statistics->getMaximum(), precomputeDoseValues, precomputeVolumeValues); } else { //more complex dose statistics with given reference dose and relative x values calculateComplexDoseStatistics(referenceDose, precomputeDoseValues, precomputeVolumeValues); } return _statistics; } void DoseStatisticsCalculator::calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { _doseVector.clear(); _voxelProportionVector.clear(); std::multimap doseValueVSIndexMap; std::vector voxelProportionVectorTemp; DoseStatisticType maximumDose = 0; DoseStatisticType minimumDose = std::numeric_limits::max(); DoseStatisticType meanDose; DoseStatisticType stdDeviationDose; DoseTypeGy sum = 0; VolumeType numVoxels = 0.0; DoseTypeGy squareSum = 0; VolumeType volume = 0; _doseIterator->reset(); int i = 0; DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid()) { doseValue = _doseIterator->getCurrentDoseValue(); if (i == 0) { minimumDose = doseValue; volume = _doseIterator->getCurrentVoxelVolume(); } rttb::FractionType voxelProportion = _doseIterator->getCurrentRelevantVolumeFraction(); sum += doseValue * voxelProportion; numVoxels += voxelProportion; squareSum += doseValue * doseValue * voxelProportion; if (doseValue > maximumDose) { maximumDose = doseValue; } else if (doseValue < minimumDose) { minimumDose = doseValue; } voxelProportionVectorTemp.push_back(voxelProportion); doseValueVSIndexMap.insert(std::pair(doseValue, i)); i++; _doseIterator->next(); } if (numVoxels != 0) { meanDose = sum / numVoxels; //standard deviation is defined only for n>=2 if (numVoxels >= 2) { //uncorrected variance is calculated DoseStatisticType varianceDose = (squareSum / numVoxels - meanDose * meanDose); if (varianceDose < errorConstant) { stdDeviationDose = 0; } else { stdDeviationDose = pow(varianceDose, 0.5); } } else { stdDeviationDose = 0; } } //sort dose values and corresponding volume fractions in member variables for (auto & it : doseValueVSIndexMap) { _doseVector.push_back((float)it.first); _voxelProportionVector.push_back(voxelProportionVectorTemp.at(it.second)); } volume *= numVoxels; _statistics = boost::make_shared(minimumDose, maximumDose, meanDose, stdDeviationDose, numVoxels, volume); _simpleDoseStatisticsCalculated = true; ResultListPointer minimumVoxelPositions = computeMinimumPositions(maxNumberMinimaPositions); ResultListPointer maximumVoxelPositions = computeMaximumPositions(maxNumberMaximaPositions); _statistics->setMinimumVoxelPositions(minimumVoxelPositions); _statistics->setMaximumVoxelPositions(maximumVoxelPositions); } void DoseStatisticsCalculator::calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues) { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call calculateComplexDoseStatistics()"); } std::vector precomputeDoseValuesNonConst = precomputeDoseValues; std::vector precomputeVolumeValuesNonConst = precomputeVolumeValues; //set default values if (precomputeDoseValues.empty()) { std::vector defaultPrecomputeDoseValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( 0.95)(0.98); precomputeDoseValuesNonConst = defaultPrecomputeDoseValues; } if (precomputeVolumeValues.empty()) { std::vector defaultPrecomputeVolumeValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( 0.95)(0.98); precomputeVolumeValuesNonConst = defaultPrecomputeVolumeValues; } _Vx = ::boost::make_shared(precomputeDoseValuesNonConst, referenceDose, _doseIterator); _Vx->compute(); _Dx = ::boost::make_shared(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume(), _statistics->getMinimum()); _Dx->compute(); _MOHx = ::boost::make_shared(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MOHx->compute(); _MOCx = ::boost::make_shared(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MOCx->compute(); _MaxOHx = ::boost::make_shared(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MaxOHx->compute(); _MinOCx = ::boost::make_shared(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume(), _statistics->getMinimum(), _statistics->getMaximum()); _MinOCx->compute(); _statistics->setVx(_Vx->getMeasureCollection()); _statistics->setDx(_Dx->getMeasureCollection()); _statistics->setMOHx(_MOHx->getMeasureCollection()); _statistics->setMOCx(_MOCx->getMeasureCollection()); _statistics->setMaxOHx(_MaxOHx->getMeasureCollection()); _statistics->setMinOCx(_MinOCx->getMeasureCollection()); _statistics->setReferenceDose(referenceDose); _complexDoseStatisticsCalculated = true; } void DoseStatisticsCalculator::addPrecomputeValues(const std::vector& values) { if (!_complexDoseStatisticsCalculated) { throw core::InvalidDoseException("Complex DoseStatistics have to be computed in order to call addPrecomputeDoseValues()"); } _Vx->addPrecomputeDoseValues(values); _Dx->addPrecomputeVolumeValues(values); _MOHx->addPrecomputeVolumeValues(values); _MOCx->addPrecomputeVolumeValues(values); _MaxOHx->addPrecomputeVolumeValues(values); _MinOCx->addPrecomputeVolumeValues(values); } void DoseStatisticsCalculator::recalculateDoseStatistics() { if (!_complexDoseStatisticsCalculated) { throw core::InvalidDoseException("Complex DoseStatistics have to be computed in order to call recalculateDoseStatistics()"); } _Vx->compute(); _Dx->compute(); _MOHx->compute(); _MOCx->compute(); _MaxOHx->compute(); _MinOCx->compute(); } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMaximumPositions( unsigned int maxNumberMaxima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMaximumPositions()"); } ResultListPointer maxVoxelVector = boost::make_shared > >(); unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMaxima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMaximum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair voxel(doseValue, currentID); maxVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return maxVoxelVector; } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMinimumPositions( unsigned int maxNumberMinima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMinimumPositions()"); } ResultListPointer minVoxelVector = boost::make_shared > >(); /*! @todo: Architecture Annotation: Finding the positions for the minimum only once reduces computation time, but will require sensible use by the programmers. To be save the output vector minVoxelVector will be always cleared here to garantee that no false values are presented. This change may be revoced to increase computation speed later on (only compute if(minVoxelVector->size()==0)). */ unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMinima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMinimum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair voxel(doseValue, currentID); minVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return minVoxelVector; } void DoseStatisticsCalculator::setMultiThreading(const bool choice) { _multiThreading = choice; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatisticsCalculator.h b/code/algorithms/rttbDoseStatisticsCalculator.h index 431850a..3f075be 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.h +++ b/code/algorithms/rttbDoseStatisticsCalculator.h @@ -1,207 +1,201 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DOSE_STATISTICS_CALCULATOR_H #define __DOSE_STATISTICS_CALCULATOR_H #include #include #include #include "rttbDoseIteratorInterface.h" #include "rttbDoseStatistics.h" #include "RTTBAlgorithmsExports.h" #include "rttbDxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbVxDoseToVolumeMeasureCollectionCalculator.h" #include "rttbMOHxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMOCxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseStatisticsCalculator @brief Class for calculating different statistical values from a RT dose distribution @details These values range from standard statistical values such as minimum, maximum and mean to more complex dose specific measures such as Vx (volume irradiated with a dose >=x), Dx (minimal dose delivered to x% of the VOI) or MOHx (mean in the hottest volume). For a complete list, see calculateDoseStatistics(). @note the complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set in calculateDoseStatistics() */ class RTTBAlgorithms_EXPORT DoseStatisticsCalculator { public: using DoseIteratorPointer = core::DoseIteratorInterface::Pointer; using ResultListPointer = DoseStatistics::ResultListPointer; using DoseStatisticsPointer = DoseStatistics::Pointer; private: DoseIteratorPointer _doseIterator; /*! @brief Contains relevant dose values sorted in descending order. */ std::vector _doseVector; /*! @brief Contains the corresponding voxel proportions to the values in doseVector. */ std::vector _voxelProportionVector; /*! @brief The doseStatistics are stored here. */ DoseStatisticsPointer _statistics; bool _simpleDoseStatisticsCalculated; bool _complexDoseStatisticsCalculated; bool _multiThreading; ::boost::shared_ptr _mutex; VxDoseToVolumeMeasureCollectionCalculator::Pointer _Vx; DxVolumeToDoseMeasureCollectionCalculator::Pointer _Dx; MOHxVolumeToDoseMeasureCollectionCalculator::Pointer _MOHx; MOCxVolumeToDoseMeasureCollectionCalculator::Pointer _MOCx; MaxOHxVolumeToDoseMeasureCollectionCalculator::Pointer _MaxOHx; MinOCxVolumeToDoseMeasureCollectionCalculator::Pointer _MinOCx; /*! @brief Calculates the positions where the dose has its maximum @param maxNumberMaximaPositions the maximal amount of computed positions @pre maximumDose must be defined in _statistics with the correct value */ ResultListPointer computeMaximumPositions(unsigned int maxNumberMaximaPositions) const; /*! @brief Calculates the positions where the dose has its minimum @param maxNumberMinimaPositions the maximal amount of computed positions (they are read sequentially using the iterator until maxNumberMinimaPositions have been read, other positions are not considered) @pre minimumDose must be defined in _statistics with the correct value */ ResultListPointer computeMinimumPositions(unsigned int maxNumberMinimaPositions) const; /*! @brief Calculates simple dose statistics (min, mean, max, stdDev, minDosePositions, maxDosePositions) @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed */ void calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions); /*! @brief Calculates complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) @warning computations can take quite long (>1 min) for large structures as many statistics are precomputed */ void calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues); public: ~DoseStatisticsCalculator(); /*! @brief Constructor @param aDoseIterator the dose to be analyzed */ DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator); DoseIteratorPointer getDoseIterator() const; /*! @brief Compute simple or complex dose statistics with default relative x values and the maximum dose as default reference dose (for Vx computation) @details The following statistics are calculated always (i.e. also if computeComplexMeasures=false):
  • minimum dose
  • mean dose
  • maximum dose
  • standard deviation dose
  • voxel positions of minimum dose
  • voxel positions of maximum dose
Additionally, these statistics are computed if computeComplexMeasures=true:
  • Dx (the minimal dose delivered to a volume >= x)
  • Vx (the volume irradiated with a dose >= x)
  • MOHx (mean dose of the hottest x volume)
  • MOCx (mean dose of the coldest x volume)
  • MaxOHx (Maximum outside of the hottest x volume)
  • MinOCx (Minimum outside of the coldest x volume)
Default x values for Vx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to maxDose. Default x values for Dx, MOHx, MOCx, MaxOHx and MinOCx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to volume. @param computeComplexMeasures should complex statistics be calculated? If it is true, the complex dose statistics will be calculated with default relative x values and the maximum dose as reference dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning If computeComplexMeasures==true, computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(bool computeComplexMeasures = false, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given reference dose and default relative x values @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @exception InvalidParameterException thrown if referenceDose <= 0 @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given relative x values and reference dose @param precomputeDoseValues the relative dose values for Vx precomputation, e.g. 0.02, 0.05, 0.95... @param precomputeVolumeValues the relative volume values for Dx, MOHx, MOCx, MaxOHx and MinOCx precomputation, e.g. 0.02, 0.05, 0.95... @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose. Default value is the maximum dose. @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set by in precomputeDoseValues and precomputeVolumeValues. Only these values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose = -1, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Adds additonal precompute values for all complex Dose Statistics @exception InvalidDoseException if complexDoseStatistics are not already calculated */ void addPrecomputeValues(const std::vector& values); /*! @brief Recalculates the DoseMeasures for all complex Dose Statistics @exception InvalidDoseException if complexDoseStatistics are not already calculated */ void recalculateDoseStatistics(); void setMultiThreading(bool choice); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp b/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp index f4e3546..bc97a13 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp +++ b/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp @@ -1,91 +1,85 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseToVolumeMeasureCollection.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { DoseToVolumeMeasureCollection::DoseToVolumeMeasureCollection(complexStatistics name, DoseTypeGy referenceDose) : _name(name), _referenceDose(referenceDose), _values(std::map()) {} void DoseToVolumeMeasureCollection::setReferenceDose(DoseTypeGy referenceDose) { this->_referenceDose = referenceDose; } void DoseToVolumeMeasureCollection::insertValue(DoseTypeGy dose, VolumeType volume) { this->_values.insert(std::pair(dose, volume)); } VolumeType DoseToVolumeMeasureCollection::getValue(DoseTypeGy xVolumeAbsolute) const { VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } VolumeType DoseToVolumeMeasureCollection::getValue(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy & nearestXDose) const { return getSpecificValue(_values, xDoseAbsolute, findNearestValue, nearestXDose); } VolumeType DoseToVolumeMeasureCollection::getValueRelative(DoseTypeGy xDoseRelative) const { if (_referenceDose != -1 && xDoseRelative >= 0 && xDoseRelative <= 1) { DoseTypeGy xDoseAbsolute = xDoseRelative * _referenceDose; DoseTypeGy dummy; return getSpecificValue(_values, xDoseAbsolute, false, dummy); } else { throw rttb::core::InvalidParameterException("Reference dose must be > 0 and 0 <= relative Dose <= 1"); } } VolumeType DoseToVolumeMeasureCollection::getValueRelative(DoseTypeGy xDoseRelative, bool findNearestValue, DoseTypeGy & nearestXDose) const { if (_referenceDose != -1 && xDoseRelative >= 0 && xDoseRelative <= 1) { DoseTypeGy xDoseAbsolute = xDoseRelative * _referenceDose; return getSpecificValue(_values, xDoseAbsolute, findNearestValue, nearestXDose); } else { throw rttb::core::InvalidParameterException("Reference dose must be > 0 and 0 <= relative Dose <= 1"); } } DoseToVolumeMeasureCollection::DoseToVolumeFunctionType DoseToVolumeMeasureCollection::getAllValues() const { return this->_values; } bool operator==(const DoseToVolumeMeasureCollection& volumeToDoseMesureCollection, const DoseToVolumeMeasureCollection& otherVolumeToDoseMesureCollection) { if (volumeToDoseMesureCollection.getName() == otherVolumeToDoseMesureCollection.getName() && volumeToDoseMesureCollection.getAllValues() == otherVolumeToDoseMesureCollection.getAllValues()) { return true; } return false; } } } diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollection.h b/code/algorithms/rttbDoseToVolumeMeasureCollection.h index 83af22b..c335296 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollection.h +++ b/code/algorithms/rttbDoseToVolumeMeasureCollection.h @@ -1,82 +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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_TO_VOLUME_MEASURE_COLLECTION_H #define __DOSE_TO_VOLUME_MEASURE_COLLECTION_H #include "rttbMeasureCollection.h" #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseToVolumeMeasureCollection @brief This class handels the access to the DoseToVolumeMeasureCollection elements for a specific complex statistic @note _referenceDose has to be set to use getValueRelative() otherwise an exception is thrown */ class RTTBAlgorithms_EXPORT DoseToVolumeMeasureCollection : public MeasureCollection { public: rttbClassMacro(DoseToVolumeMeasureCollection, MeasureCollection) typedef std::map DoseToVolumeFunctionType; private: complexStatistics _name; DoseTypeGy _referenceDose; DoseToVolumeFunctionType _values; public: DoseToVolumeMeasureCollection(complexStatistics name, DoseTypeGy referenceDose = -1); /*! @brief This has to be set >=0 to use getValueRelative() */ void setReferenceDose(DoseTypeGy referenceDose); void insertValue(DoseTypeGy dose, VolumeType volume); /*! @brief Gets the volume irradiated with a dose >= x, depending on the complexStatistics name. @return Return absolute volume in absolute cm^3. @exception InvalidDoseException if the vector values is empty or _referenceDose is -1 @exception NoDataException if the requested Dose is not in the vector */ VolumeType getValue(DoseTypeGy xVolumeAbsolute) const; VolumeType getValue(DoseTypeGy xVolumeAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const; VolumeType getValueRelative(DoseTypeGy xDoseRelative) const; VolumeType getValueRelative(DoseTypeGy xDoseRelative, bool findNearestValue, DoseTypeGy& nearestXDose) const; DoseToVolumeFunctionType getAllValues() const; friend bool operator==(const DoseToVolumeMeasureCollection& volumeToDoseMesureCollection, const DoseToVolumeMeasureCollection& otherVolumeToDoseMesureCollection); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp index 9709cbf..419c861 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp @@ -1,92 +1,86 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseToVolumeMeasureCollectionCalculator.h" #include #include "rttbInvalidParameterException.h" #include "rttbUtils.h" #include //#include namespace rttb { namespace algorithms { DoseToVolumeMeasureCollectionCalculator::DoseToVolumeMeasureCollectionCalculator(const std::vector& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, DoseToVolumeMeasureCollection::complexStatistics name, bool multiThreading) : _doseIterator(doseIterator), _referenceDose(referenceDose), _measureCollection(::boost::make_shared(name)), _multiThreading(multiThreading) { addPrecomputeDoseValues(precomputeDoseValues); } void DoseToVolumeMeasureCollectionCalculator::compute() { std::vector threads; for (double _precomputeDoseValue : _precomputeDoseValues) { double xAbsolute = _precomputeDoseValue * _referenceDose; if (!rttb::core::isKey(_measureCollection->getAllValues(), xAbsolute)) { if (_multiThreading) { throw rttb::core::InvalidParameterException("MultiThreading is not implemented yet."); //threads.push_back(boost::thread(&DoseToVolumeMeasureCollectionCalculator::insertIntoMeasureCollection, this , xAbsolute, computeSpecificValue(xAbsolute))); } else { insertIntoMeasureCollection(xAbsolute, this->computeSpecificValue(xAbsolute)); } } } for (auto & thread : threads) { thread.join(); } } void DoseToVolumeMeasureCollectionCalculator::addPrecomputeDoseValues(const std::vector& values) { for (double value : values) { if (value > 1 || value < 0) { throw rttb::core::InvalidParameterException("Values must be between 1 and 0!"); } if (!rttb::core::isKey(_precomputeDoseValues, value)) { _precomputeDoseValues.push_back(value); } } } DoseToVolumeMeasureCollection::Pointer DoseToVolumeMeasureCollectionCalculator::getMeasureCollection() { return _measureCollection; } void DoseToVolumeMeasureCollectionCalculator::insertIntoMeasureCollection(DoseTypeGy xAbsolute, VolumeType resultVolume) { _measureCollection->insertValue(xAbsolute, resultVolume); } } } diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h index b07d0e3..dedfd9f 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h +++ b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h @@ -1,99 +1,93 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_TO_VOLUME_MEASURE_COLLECTION_CALCULATOR_H #define __DOSE_TO_VOLUME_MEASURE_COLLECTION_CALCULATOR_H #include #include #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" #include "rttbDoseToVolumeMeasureCollection.h" #include "rttbDoseIteratorInterface.h" #include #include "rttbDoseStatistics.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseToVolumeMeasureCollectionCalculator @brief Class for calculating DoseToVolume measures @details This class is used as a basis for DoseToVolumeMeasureCollectionCalculators. It implements the compute() method that is the same for every inheriting subclass, it accesses computeSpecificValue, which has to be implemented for each different complex statistic. */ class RTTBAlgorithms_EXPORT DoseToVolumeMeasureCollectionCalculator { public: rttbClassMacroNoParent(DoseToVolumeMeasureCollectionCalculator) typedef std::map VolumeToDoseFunctionType; protected: core::DoseIteratorInterface::Pointer _doseIterator; private: std::vector _precomputeDoseValues; DoseTypeGy _referenceDose; DoseToVolumeMeasureCollection::Pointer _measureCollection; bool _multiThreading; public: /*! @brief Computes not already computed values for the measureCollection. Algorithm for the specific complex Statistic has to be implemented in the corresponding subclass. */ void compute(); /*! @brief Adds additional values to the _precomputeDoseValues vector. @exception InvalidParameterException If values vector contains values that are not between 0 and 1 */ void addPrecomputeDoseValues(const std::vector& values); DoseToVolumeMeasureCollection::Pointer getMeasureCollection(); protected: DoseToVolumeMeasureCollectionCalculator(const std::vector& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, DoseToVolumeMeasureCollection::complexStatistics name, bool multiThreading); void insertIntoMeasureCollection(DoseTypeGy xAbsolute, VolumeType resultVolume); /*! @brief Computes the specific VolumeType depending on the complext statistic @note has to be overwritten */ virtual VolumeType computeSpecificValue(double xAbsolute) const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp index d91a6b8..be8e0e9 100644 --- a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,61 +1,55 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { DxVolumeToDoseMeasureCollectionCalculator::DxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::Dx, multiThreading), _minimum(minimum) {} DoseTypeGy DxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; bool voxelOverflow = false; for (auto i = _doseVector.size() - 1; i != static_cast(-1); i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { voxelOverflow = true; resultDose = _doseVector.at(i); break; } } if (!voxelOverflow) { resultDose = _minimum; } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h index aac332d..a6e1509 100644 --- a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h @@ -1,56 +1,50 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __DX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include namespace rttb { namespace algorithms { /*! @class DxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating Dx VolumeToDose measures */ class RTTBAlgorithms_EXPORT DxVolumeToDoseMeasureCollectionCalculator: public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(DxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; public: DxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp index 7b0330d..6cf1a3c 100644 --- a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,63 +1,57 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMOCxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MOCxVolumeToDoseMeasureCollectionCalculator::MOCxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MOCx, multiThreading) {} DoseTypeGy MOCxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; auto it = _doseVector.begin(); auto itD = _voxelProportionVector.begin(); for (; it != _doseVector.end(); ++it, ++itD) { double voxelProportion = *itD; countVoxels += voxelProportion; sum += (*it) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return static_cast(sum / noOfVoxel); } } } } \ No newline at end of file diff --git a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h index 0e0251a..36614a9 100644 --- a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h @@ -1,52 +1,46 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include namespace rttb { namespace algorithms { /*! @class MOCxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MOCx VolumeToDose measures */ class RTTBAlgorithms_EXPORT MOCxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MOCxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) MOCxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp index fe4c776..713a5b9 100644 --- a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,63 +1,57 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMOHxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MOHxVolumeToDoseMeasureCollectionCalculator::MOHxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MOHx, multiThreading) {} DoseTypeGy MOHxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; for (auto i = _doseVector.size() - 1; i!=static_cast(-1); i--) { double voxelProportion = _voxelProportionVector.at(i); countVoxels += voxelProportion; sum += _doseVector.at(i) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return static_cast(sum / noOfVoxel); } } } } \ No newline at end of file diff --git a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h index 291af78..f7b2f06 100644 --- a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MOHX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MOHX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include namespace rttb { namespace algorithms { /*! @class MOHxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MOHx VolumeToDose measures */ class RTTBAlgorithms_EXPORT MOHxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MOHxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; public: MOHxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp index edcc8c0..47e63ed 100644 --- a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,57 +1,51 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MaxOHxVolumeToDoseMeasureCollectionCalculator::MaxOHxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MaxOHx, multiThreading) {} DoseTypeGy MaxOHxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; for (auto i = _doseVector.size() - 1; i!=static_cast(-1); i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { if (i > 0) { resultDose = _doseVector.at(i - 1); } break; } } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h index e4fcd7b..7767a07 100644 --- a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h @@ -1,50 +1,44 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MAXOHX_VOLUME_TO_DOSE_MEASURE_CALCULATOR_COLLECTION_H #define __MAXOHX_VOLUME_TO_DOSE_MEASURE_CALCULATOR_COLLECTION_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { /*! @class MaxOHxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MaxOH VolumeToDose measures */ class RTTBAlgorithms_EXPORT MaxOHxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MaxOHxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) MaxOHxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMeasureCollection.cpp b/code/algorithms/rttbMeasureCollection.cpp index 7f441ec..39209e8 100644 --- a/code/algorithms/rttbMeasureCollection.cpp +++ b/code/algorithms/rttbMeasureCollection.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMeasureCollection.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { MeasureCollection::complexStatistics MeasureCollection::getName() const { return this->_name; } double MeasureCollection::getSpecificValue(const std::map& values, double key, bool findNearestValueInstead, double& storedKey) const { if (values.find(key) != std::end(values)) { return values.find(key)->second; } else { //value not in map. We have to find the nearest value if (values.empty()) { throw core::DataNotAvailableException("No Vx values are defined"); } else { if (findNearestValueInstead) { auto iterator = findNearestKeyInMap(values, key); storedKey = iterator->first; return iterator->second; } else { throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } } } std::map::const_iterator MeasureCollection::findNearestKeyInMap( const std::map& values, double key) const { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(values); while (iterator != std::end(values)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(values)) { --iterator; return iterator; } else { return std::begin(values); } } } --iterator; return iterator; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMeasureCollection.h b/code/algorithms/rttbMeasureCollection.h index fd8de9e..2487e97 100644 --- a/code/algorithms/rttbMeasureCollection.h +++ b/code/algorithms/rttbMeasureCollection.h @@ -1,60 +1,54 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MEASURE_COLLECTION_H #define __MEASURE_COLLECTION_H #include #include #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" namespace rttb { namespace algorithms { /*! @class MeasureCollection @brief This class handels the access to the MeasureCollection elements and defines which names can be used for them */ class RTTBAlgorithms_EXPORT MeasureCollection { public: rttbClassMacroNoParent(MeasureCollection) enum complexStatistics { Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx }; protected: complexStatistics _name; public: complexStatistics getName() const; protected: double getSpecificValue(const std::map& values, double key, bool findNearestValueInstead, double& storedKey) const; std::map::const_iterator findNearestKeyInMap(const std::map& values, double key) const; }; } } #endif diff --git a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp index cefd42b..0b743ce 100644 --- a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,75 +1,69 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MinOCxVolumeToDoseMeasureCollectionCalculator::MinOCxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, const DoseStatisticType maximum, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MinOCx, multiThreading), _minimum(minimum), _maximum(maximum) {} DoseTypeGy MinOCxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; auto it = _doseVector.begin(); auto itD = _voxelProportionVector.begin(); for (; itD != _voxelProportionVector.end(); ++itD, ++it) { countVoxels += *itD; if (countVoxels >= noOfVoxel) { break; } } if (it != _doseVector.end()) { ++it; if (it != _doseVector.end()) { resultDose = *it; } else { resultDose = (DoseTypeGy)_maximum; } } else { resultDose = (DoseTypeGy)_minimum; } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h index a33b34e..756f618 100644 --- a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MINOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MINOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { /*! @class MinOCxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MinOC VolumeToDose measures */ class RTTBAlgorithms_EXPORT MinOCxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MinOCxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; DoseStatisticType _maximum; public: MinOCxVolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, const DoseStatisticType maximum, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp b/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp index 759cb1a..7847d64 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp +++ b/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp @@ -1,98 +1,91 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "rttbVolumeToDoseMeasureCollection.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { VolumeToDoseMeasureCollection::VolumeToDoseMeasureCollection(complexStatistics name, VolumeType volume) : _name(name), _volume(volume), _values(std::map()) {} void VolumeToDoseMeasureCollection::setVolume(VolumeType volume) { this->_volume = volume; } void VolumeToDoseMeasureCollection::insertValue(VolumeType volume, DoseTypeGy dose) { this->_values.insert(std::pair(volume, dose)); } DoseTypeGy VolumeToDoseMeasureCollection::getValue(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } DoseTypeGy VolumeToDoseMeasureCollection::getValue(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType & nearestXVolume) const { return getSpecificValue(_values, xVolumeAbsolute, findNearestValue, nearestXVolume); } DoseTypeGy VolumeToDoseMeasureCollection::getValueRelative(VolumeType xVolumeRelative) const { if (_volume == -1) { throw rttb::core::DataNotAvailableException("Volume is not set"); } if (xVolumeRelative >= 0 && xVolumeRelative <= 1) { DoseTypeGy xVolumeAbsolute = xVolumeRelative * _volume; VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } else { throw rttb::core::InvalidParameterException("Relative Volume must be >= 0 and <=1"); } } DoseTypeGy VolumeToDoseMeasureCollection::getValueRelative(VolumeType xVolumeRelative, bool findNearestValue, VolumeType & nearestXVolume) const { if (_volume == -1) { throw rttb::core::DataNotAvailableException("Volume is not set"); } if (xVolumeRelative >= 0 && xVolumeRelative <= 1) { DoseTypeGy xVolumeAbsolute = xVolumeRelative * _volume; return getSpecificValue(_values, xVolumeAbsolute, findNearestValue, nearestXVolume); } else { throw rttb::core::InvalidParameterException("Relative Volume must be >= 0 and <=1"); } } VolumeToDoseMeasureCollection::VolumeToDoseFunctionType VolumeToDoseMeasureCollection::getAllValues() const { return this->_values; } bool operator==(const VolumeToDoseMeasureCollection& volumeToDoseMesureCollection,const VolumeToDoseMeasureCollection& otherVolumeToDoseMesureCollection) { if (volumeToDoseMesureCollection.getName() == otherVolumeToDoseMesureCollection.getName() && volumeToDoseMesureCollection.getAllValues() == otherVolumeToDoseMesureCollection.getAllValues()) { return true; } return false; } } } diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollection.h b/code/algorithms/rttbVolumeToDoseMeasureCollection.h index 0f0b39a..c9e4f71 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollection.h +++ b/code/algorithms/rttbVolumeToDoseMeasureCollection.h @@ -1,82 +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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __VOLUME_TO_DOSE_MEASURE_COLLECTION_H #define __VOLUME_TO_DOSE_MEASURE_COLLECTION_H #include "rttbMeasureCollection.h" #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class VolumeToDoseMeasureCollection @brief This class handels the access to the VolumeToDoseMeasureCollection elements for a specific complex statistic @note _volume has to be set to use getValueRelative() otherwise an exception is thrown */ class RTTBAlgorithms_EXPORT VolumeToDoseMeasureCollection : public MeasureCollection { public: rttbClassMacro(VolumeToDoseMeasureCollection, MeasureCollection) typedef std::map VolumeToDoseFunctionType; private: complexStatistics _name; VolumeType _volume; VolumeToDoseFunctionType _values; public: VolumeToDoseMeasureCollection(complexStatistics name, VolumeType volume = -1); /*! @brief This has to be set >=0 to use getValueRelative() */ void setVolume(VolumeType volume); void insertValue(VolumeType volume, DoseTypeGy dose); /*! @brief Gets the x of the current volume, depending on the complexStatistics name. @return Return dose value in Gy. @exception InvalidDoseException if the vector values is empty @exception DataNotAvailableException if _volume is not set */ DoseTypeGy getValue(VolumeType xVolumeAbsolute) const; DoseTypeGy getValue(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXDose) const; DoseTypeGy getValueRelative(VolumeType xDoseRelative) const; DoseTypeGy getValueRelative(VolumeType xDoseRelative, bool findNearestValue, VolumeType& nearestXDose) const; VolumeToDoseFunctionType getAllValues() const; friend bool operator==(const VolumeToDoseMeasureCollection& volumeToDoseMesureCollection, const VolumeToDoseMeasureCollection& otherVolumeToDoseMesureCollection); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp index 3a84ac2..abc876b 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,90 +1,84 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include #include "rttbInvalidParameterException.h" #include "rttbUtils.h" #include //#include namespace rttb { namespace algorithms { VolumeToDoseMeasureCollectionCalculator::VolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, VolumeToDoseMeasureCollection::complexStatistics name, bool multiThreading) : _doseVector(doseVector), _currentVoxelVolume(currentVoxelVolume), _voxelProportionVector(voxelProportionVector), _volume(volume), _measureCollection(::boost::make_shared(name)), _multiThreading(multiThreading) { addPrecomputeVolumeValues(precomputeVolumeValues); } void VolumeToDoseMeasureCollectionCalculator::compute() { std::vector threads; for (double _precomputeVolumeValue : _precomputeVolumeValues) { double xAbsolute = _precomputeVolumeValue * _volume; if (!rttb::core::isKey(_measureCollection->getAllValues(), xAbsolute)) { if (_multiThreading) { throw rttb::core::InvalidParameterException("MultiThreading is not implemented yet."); //threads.push_back(boost::thread(&VolumeToDoseMeasureCollectionCalculator::insertIntoMeasureCollection, this, xAbsolute, computeSpecificValue(xAbsolute))); } else { insertIntoMeasureCollection(xAbsolute, this->computeSpecificValue(xAbsolute)); } } } for (auto & thread : threads) { thread.join(); } } void VolumeToDoseMeasureCollectionCalculator::addPrecomputeVolumeValues(const std::vector& values) { for (double value : values) { if (value > 1 || value < 0) { throw rttb::core::InvalidParameterException("Values must be between 1 and 0!"); } if (!rttb::core::isKey(_precomputeVolumeValues, value)) { _precomputeVolumeValues.push_back(value); } } } VolumeToDoseMeasureCollection::Pointer VolumeToDoseMeasureCollectionCalculator::getMeasureCollection() { return _measureCollection; } void VolumeToDoseMeasureCollectionCalculator::insertIntoMeasureCollection(VolumeType xAbsolute, DoseTypeGy resultDose) { _measureCollection->insertValue(xAbsolute, resultDose); } } } diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h index d9bf743..3838437 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h @@ -1,92 +1,86 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollection.h" #include #include "rttbDoseStatistics.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class VolumeToDoseMeasureCollectionCalculator @brief Class for calculating VolumeToDose measures @details This class is used as a basis for VolumeToDoseMeasureCollectionCalculator. It implements the compute() method that is the same for every inheriting subclass, it accesses computeSpecificValue, which has to be implemented for each different complex statistic. */ class RTTBAlgorithms_EXPORT VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacroNoParent(VolumeToDoseMeasureCollectionCalculator) typedef std::map VolumeToDoseFunctionType; protected: std::vector _doseVector; DoseVoxelVolumeType _currentVoxelVolume; std::vector _voxelProportionVector; private: std::vector _precomputeVolumeValues; VolumeType _volume; VolumeToDoseMeasureCollection::Pointer _measureCollection; bool _multiThreading; public: /*! @brief Computes not already computed values for the measureCollection. Algorithm for the specific complex Statistic has to be implemented in the corresponding subclass. */ void compute(); /*! @brief Adds additional values to the _precomputeVolumeValues vector. @exception InvalidParameterException If values vector contains values that are not between 0 and 1 */ void addPrecomputeVolumeValues(const std::vector& values); VolumeToDoseMeasureCollection::Pointer getMeasureCollection(); protected: VolumeToDoseMeasureCollectionCalculator(const std::vector& precomputeVolumeValues, const VolumeType volume, const std::vector& doseVector, const std::vector& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, VolumeToDoseMeasureCollection::complexStatistics name, bool multiThreading); void insertIntoMeasureCollection(VolumeType xAbsolute, DoseTypeGy resultDose); /*! @brief Computes the specific DoseTypeGy depending on the complext statistic @note has to be overwritten */ virtual DoseTypeGy computeSpecificValue(double xAbsolute) const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp index 2325fe1..1fe63cd 100644 --- a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbVxDoseToVolumeMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { VxDoseToVolumeMeasureCollectionCalculator::VxDoseToVolumeMeasureCollectionCalculator(const std::vector& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, bool multiThreading) : DoseToVolumeMeasureCollectionCalculator(precomputeDoseValues, referenceDose, doseIterator, DoseToVolumeMeasureCollection::Vx, multiThreading) {} VolumeType VxDoseToVolumeMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { rttb::FractionType count = 0; _doseIterator->reset(); DoseTypeGy currentDose = 0; while (_doseIterator->isPositionValid()) { currentDose = _doseIterator->getCurrentDoseValue(); if (currentDose >= xAbsolute) { count += _doseIterator->getCurrentRelevantVolumeFraction(); } _doseIterator->next(); } return count * this->_doseIterator->getCurrentVoxelVolume(); } } } \ No newline at end of file diff --git a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h index 5a7ea85..6b7c97a 100644 --- a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h +++ b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h @@ -1,52 +1,46 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DV_DOSE_TO_VOLUME_MEASURE_CALCULATOR_H #define __DV_DOSE_TO_VOLUME_MEASURE_CALCULATOR_H #include "rttbDoseToVolumeMeasureCollectionCalculator.h" #include namespace rttb { namespace algorithms { /*! @class VxDoseToVolumeMeasureCollectionCalculator @brief Class for calculating Vx DoseToVolume measures */ class RTTBAlgorithms_EXPORT VxDoseToVolumeMeasureCollectionCalculator : public DoseToVolumeMeasureCollectionCalculator { public: rttbClassMacro(VxDoseToVolumeMeasureCollectionCalculator, DoseToVolumeMeasureCollectionCalculator) VxDoseToVolumeMeasureCollectionCalculator(const std::vector& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, bool multiThreading = false); protected: VolumeType computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/core/rttbAccessorInterface.h b/code/core/rttbAccessorInterface.h index f09a5f7..08979c5 100644 --- a/code/core/rttbAccessorInterface.h +++ b/code/core/rttbAccessorInterface.h @@ -1,105 +1,100 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ACCESSOR_INTERFACE_H #define __ACCESSOR_INTERFACE_H #include #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbIndexConversionInterface.h" #include "rttbCommon.h" #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class AccessorInterface @brief Interface for any sort of Accessor */ class RTTBCore_EXPORT AccessorInterface : public IndexConversionInterface { public: rttbClassMacro(AccessorInterface, IndexConversionInterface); private: AccessorInterface(const AccessorInterface&) = delete; //not implemented on purpose -> non-copyable AccessorInterface& operator=(const AccessorInterface&) = delete;//not implemented on purpose -> non-copyable public: AccessorInterface() = default; ~AccessorInterface() override = default; /*! @brief test if given ID is inside current dose grid */ bool validID(const VoxelGridID aID) const { return this->getGeometricInfo().validID(aID); }; /*! @brief test if given index is inside current dose grid */ bool validIndex(const VoxelGridIndex3D& aIndex) const { return this->getGeometricInfo().validIndex(aIndex); }; virtual const core::GeometricInfo& getGeometricInfo() const = 0; virtual GridSizeType getGridSize() const { return this->getGeometricInfo().getNumberOfVoxels(); }; virtual GenericValueType getValueAt(const VoxelGridID aID) const = 0; virtual GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const = 0; /*! @brief is true if dose is on a homogeneous grid @remarks Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change. */ virtual bool isGridHomogeneous() const { return true; } virtual const IDType getUID() const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbAccessorWithGeoInfoBase.cpp b/code/core/rttbAccessorWithGeoInfoBase.cpp index 8f5b140..1a13661 100644 --- a/code/core/rttbAccessorWithGeoInfoBase.cpp +++ b/code/core/rttbAccessorWithGeoInfoBase.cpp @@ -1,45 +1,38 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include "rttbAccessorWithGeoInfoBase.h" namespace rttb { namespace core { const core::GeometricInfo& AccessorWithGeoInfoBase:: getGeometricInfo() const { return _geoInfo; } AccessorWithGeoInfoBase::~AccessorWithGeoInfoBase() = default; AccessorWithGeoInfoBase::AccessorWithGeoInfoBase() = default; } } diff --git a/code/core/rttbAccessorWithGeoInfoBase.h b/code/core/rttbAccessorWithGeoInfoBase.h index 044908b..d4d8fb0 100644 --- a/code/core/rttbAccessorWithGeoInfoBase.h +++ b/code/core/rttbAccessorWithGeoInfoBase.h @@ -1,62 +1,57 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ACCESSOR_WITH_GEO_INFO_BASE_H #define __ACCESSOR_WITH_GEO_INFO_BASE_H #include "rttbAccessorInterface.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class AccessorWithGeoInfoBase @brief Base class for all accessor implementations that have there own geometric info. */ class RTTBCore_EXPORT AccessorWithGeoInfoBase : public core::AccessorInterface { protected: virtual void assembleGeometricInfo()=0; core::GeometricInfo _geoInfo; public: ~AccessorWithGeoInfoBase() override; AccessorWithGeoInfoBase(); const core::GeometricInfo& getGeometricInfo() const override; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbBaseType.h b/code/core/rttbBaseType.h index e726eb5..d6d53d8 100644 --- a/code/core/rttbBaseType.h +++ b/code/core/rttbBaseType.h @@ -1,619 +1,613 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __BASE_TYPE_NEW_H #define __BASE_TYPE_NEW_H #include #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { const double errorConstant = 1e-5; const double reducedErrorConstant = 0.0001; using UnsignedIndex1D = unsigned short; /*! @class UnsignedIndex3D @brief 3D index. */ class UnsignedIndex3D: public boost::numeric::ublas::vector { public: UnsignedIndex3D() : boost::numeric::ublas::vector(3,0) {} UnsignedIndex3D(const UnsignedIndex1D value) : boost::numeric::ublas::vector(3, value) {} UnsignedIndex3D(const UnsignedIndex1D xValue, const UnsignedIndex1D yValue, const UnsignedIndex1D zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } const UnsignedIndex1D x() const { return (*this)(0); } const UnsignedIndex1D y() const { return (*this)(1); } const UnsignedIndex1D z() const { return (*this)(2); } friend bool operator==(const UnsignedIndex3D& gi1, const UnsignedIndex3D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const UnsignedIndex3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; using UnsignedIndexList = std::list; using FileNameString = std::string; using ContourGeometricTypeString = std::string; using WorldCoordinate = double; /*! @class WorldCoordinate3D @brief 3D coordinate in real world coordinates like in DICOM to define ImagePositionPatient. */ class WorldCoordinate3D: public boost::numeric::ublas::vector { public: WorldCoordinate3D() : boost::numeric::ublas::vector(3,0) {} WorldCoordinate3D(const WorldCoordinate value) : boost::numeric::ublas::vector(3, value) {} WorldCoordinate3D(const WorldCoordinate xValue, const WorldCoordinate yValue, const WorldCoordinate zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } WorldCoordinate3D(const WorldCoordinate3D& w): boost::numeric::ublas::vector(3) { (*this)(0) = w.x(); (*this)(1) = w.y(); (*this)(2) = w.z(); } const WorldCoordinate x() const { return (*this)(0); } const WorldCoordinate y() const { return (*this)(1); } const WorldCoordinate z() const { return (*this)(2); } //vector cross product (not included in boost.ublas) WorldCoordinate3D cross(WorldCoordinate3D aVector) const { WorldCoordinate3D result; WorldCoordinate x = (*this)(0); WorldCoordinate y = (*this)(1); WorldCoordinate z = (*this)(2); result(0) = y * aVector(2) - z * aVector(1); result(1) = z * aVector(0) - x * aVector(2); result(2) = x * aVector(1) - y * aVector(0); return result; } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } WorldCoordinate3D& operator=(const WorldCoordinate3D& wc) { (*this)(0) = wc.x(); (*this)(1) = wc.y(); (*this)(2) = wc.z(); return (*this); } WorldCoordinate3D& operator=(const boost::numeric::ublas::vector wc) { (*this)(0) = wc(0); (*this)(1) = wc(1); (*this)(2) = wc(2); return (*this); } WorldCoordinate3D operator-(const boost::numeric::ublas::vector wc) { return WorldCoordinate3D((*this)(0) - wc(0), (*this)(1) - wc(1), (*this)(2) - wc(2)); } WorldCoordinate3D operator+(const boost::numeric::ublas::vector wc) { return WorldCoordinate3D((*this)(0) + wc(0), (*this)(1) + wc(1), (*this)(2) + wc(2)); } friend bool operator==(const WorldCoordinate3D& wc1, const WorldCoordinate3D& wc2) { if (wc1.size() != wc2.size()) { return false; } for (size_t i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } bool equalsAlmost(const WorldCoordinate3D& another, double errorConstantWC = 1e-5) const { if (size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstantWC; } friend std::ostream& operator<<(std::ostream& s, const WorldCoordinate3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /* ! @brief continuous index */ using DoubleVoxelGridIndex3D = rttb::WorldCoordinate3D; using ImageSize = rttb::UnsignedIndex3D; using GridVolumeType = double; /*! @class SpacingVectorType3D @brief 3D spacing vector. @pre values of this vector may not be negative. */ class SpacingVectorType3D: public boost::numeric::ublas::vector { public: SpacingVectorType3D() : boost::numeric::ublas::vector(3,0) {} SpacingVectorType3D(const GridVolumeType value) : boost::numeric::ublas::vector(3, value) { if (value < 0) { throw std::invalid_argument("received negative value"); } } SpacingVectorType3D(const GridVolumeType xValue, const GridVolumeType yValue, const GridVolumeType zValue) : boost::numeric::ublas::vector(3) { if (xValue < 0 || yValue < 0 || zValue < 0) { throw std::invalid_argument("received negative value"); } (*this)(0) = xValue; (*this)(1) = yValue; (*this)(2) = zValue; } SpacingVectorType3D(const SpacingVectorType3D& w) : SpacingVectorType3D(w.x(), w.y(), w.z()) { } const GridVolumeType x() const { return (*this)(0); } const GridVolumeType y() const { return (*this)(1); } const GridVolumeType z() const { return (*this)(2); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } SpacingVectorType3D& operator=(const SpacingVectorType3D& wc) { (*this)(0) = wc.x(); (*this)(1) = wc.y(); (*this)(2) = wc.z(); return (*this); } SpacingVectorType3D& operator=(const WorldCoordinate3D& wc) { (*this)(0) = GridVolumeType(wc.x()); (*this)(1) = GridVolumeType(wc.y()); (*this)(2) = GridVolumeType(wc.z()); return (*this); } SpacingVectorType3D& operator=(const boost::numeric::ublas::vector wc) { (*this)(0) = wc(0); (*this)(1) = wc(1); (*this)(2) = wc(2); return (*this); } friend bool operator==(const SpacingVectorType3D& wc1, const SpacingVectorType3D& wc2) { if (wc1.size() != wc2.size()) { return false; } for (size_t i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } bool equalsAlmost(const SpacingVectorType3D& another, double errorConstantSV = 1e-5) const { if ((*this).size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstantSV; } friend std::ostream& operator<<(std::ostream& s, const SpacingVectorType3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /*! @class OrientationMatrix @brief Used to store image orientation information */ class OrientationMatrix : public boost::numeric::ublas::matrix { public: /*! The default constructor generates a 3x3 unit matrix */ OrientationMatrix() : boost::numeric::ublas::matrix(3, 3, 0) { for (std::size_t m = 0; m < (*this).size1(); m++) { (*this)(m, m) = 1; } } OrientationMatrix(const WorldCoordinate value) : boost::numeric::ublas::matrix(3, 3, value) {} bool equalsAlmost(const OrientationMatrix& anOrientationMatrix, double errorConstantOM=1e-5) const { if (anOrientationMatrix.size1() == (*this).size1()) { if (anOrientationMatrix.size2() == (*this).size2()) { for (std::size_t m = 0; m < anOrientationMatrix.size1(); m++) { for (std::size_t n = 0; n < anOrientationMatrix.size2(); n++) { if ((std::abs((*this)(m, n) - anOrientationMatrix(m, n)) > errorConstantOM)) { return false; } } }// end element comparison } else { return false; } } else { return false; } return true; } friend bool operator==(const OrientationMatrix& om1, const OrientationMatrix& om2) { return om1.equalsAlmost(om2, 0.0); } friend std::ostream& operator<<(std::ostream& s, const OrientationMatrix& anOrientationMatrix) { s << "[ "; for (std::size_t m = 0; m < anOrientationMatrix.size1(); m++) { s << "[ "; for (std::size_t n = 0; n < anOrientationMatrix.size2(); n++) { if (n == 0) { s << anOrientationMatrix(m, n); } else { s << ", " << anOrientationMatrix(m, n); } } s << " ]"; } s << " ]"; return s; } }; /*! base for 2D and 3D VoxelIndex; Therefore required beside VoxelGridID */ using GridIndexType = unsigned int; /*! @class VoxelGridIndex3D @brief 3D voxel grid index in a discret geometry (matrix/image). @details analogous to DICOM where ImagePositionPatient gives the position of the center of the first coordinate (0/0/0) */ class VoxelGridIndex3D: public boost::numeric::ublas::vector { public: VoxelGridIndex3D() : boost::numeric::ublas::vector(3,0) {} VoxelGridIndex3D(const GridIndexType value) : boost::numeric::ublas::vector(3, value) {} VoxelGridIndex3D(const GridIndexType xValue, const GridIndexType yValue, const GridIndexType zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } const GridIndexType x() const { return (*this)(0); } const GridIndexType y() const { return (*this)(1); } const GridIndexType z() const { return (*this)(2); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } VoxelGridIndex3D& operator=(const UnsignedIndex3D& ui) { (*this)(0) = ui(0); (*this)(1) = ui(1); (*this)(2) = ui(2); return (*this); } friend bool operator==(const VoxelGridIndex3D& gi1, const VoxelGridIndex3D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const VoxelGridIndex3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /*! @class VoxelGridIndex3D @brief 2D voxel grid index. */ class VoxelGridIndex2D: public boost::numeric::ublas::vector { public: VoxelGridIndex2D() : boost::numeric::ublas::vector(2,0) {} VoxelGridIndex2D(const GridIndexType value) : boost::numeric::ublas::vector(2, value) {} VoxelGridIndex2D(const GridIndexType xValue, const GridIndexType yValue) : boost::numeric::ublas::vector(2, xValue) { (*this)(1) = yValue; } const GridIndexType x() const { return (*this)(0); } const GridIndexType y() const { return (*this)(1); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()); return s; } friend bool operator==(const VoxelGridIndex2D& gi1, const VoxelGridIndex2D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const VoxelGridIndex2D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << " ]"; return s; } }; using GridSizeType = long; using VoxelGridID = int; //starts from 0 and is continuously counting all positions on the grid using VoxelGridDimensionType = unsigned int; typedef double FractionType, DVHVoxelNumber; typedef double DoseCalcType, DoseTypeGy, GenericValueType, DoseVoxelVolumeType, VolumeType, GridVolumeType, PercentType, VoxelNumberType, BEDType, LQEDType; using IDType = std::string; using StructureLabel = std::string; struct DVHRole { enum Type { TargetVolume = 1, HealthyTissue = 2, WholeVolume = 4, UserDefined = 128 } Type; }; struct DVHType { enum Type { Differential = 1, Cumulative = 2 } Type; }; using FileNameType = std::string; using PolygonType = std::vector; using PolygonSequenceType = std::vector; using IndexValueType = double; using DoseStatisticType = double; using DICOMRTFileNameString = std::string; using Uint16 = unsigned short; typedef std::string XMLString, StatisticsString; }//end: namespace rttb #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDVH.cpp b/code/core/rttbDVH.cpp index 9ef8eb9..880fe12 100644 --- a/code/core/rttbDVH.cpp +++ b/code/core/rttbDVH.cpp @@ -1,394 +1,388 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbDVH.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" #include "rttbUtils.h" namespace rttb { namespace core { DVH::~DVH() = default; DVH::DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, const IDType& aStructureID, const IDType& aDoseID): DVH(aDataDifferential, aDeltaD, aDeltaV, aStructureID, aDoseID, "") { } DVH::DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, const IDType& aStructureID, const IDType& aDoseID, const IDType& aVoxelizationID): _deltaD(aDeltaD), _deltaV(aDeltaV), _structureID(aStructureID), _doseID(aDoseID), _voxelizationID(aVoxelizationID) { _dataDifferential.clear(); _dataDifferential = aDataDifferential; this->init(); } DVH::DVH(const DVH& copy) : DVH(copy._dataDifferential, copy._deltaD, copy._deltaV, copy._structureID, copy._doseID, copy._voxelizationID) { _label = copy._label; } DVH& DVH::operator=(const DVH& copy) { if (this != ©) { _deltaD = copy._deltaD; _deltaV = copy._deltaV; _structureID = copy._structureID; _doseID = copy._doseID; _voxelizationID = copy._voxelizationID; _label = copy._label; _dataDifferential.clear(); _dataDifferential = copy._dataDifferential; } this->init(); return *this; } bool operator==(const DVH& aDVH, const DVH& otherDVH) { bool result; //larger error constant because especially numberOfVoxels differ quite a bit after serialization const double errorConstantDVH = 1e-4; result = valueIsClose(aDVH.getDeltaD(), otherDVH.getDeltaD(), errorConstantDVH); result = result && valueIsClose(aDVH.getDeltaV(), otherDVH.getDeltaV(), errorConstantDVH); result = result && (aDVH.getDoseID() == otherDVH.getDoseID()); result = result && (aDVH.getStructureID() == otherDVH.getStructureID()); result = result && (aDVH.getVoxelizationID() == otherDVH.getVoxelizationID()); result = result && valueIsClose(aDVH.getNumberOfVoxels(),otherDVH.getNumberOfVoxels(), errorConstantDVH); result = result && valueIsClose(aDVH.getMaximum(), otherDVH.getMaximum(), errorConstantDVH); result = result && valueIsClose(aDVH.getMinimum(), otherDVH.getMinimum(), errorConstantDVH); result = result && valueIsClose(aDVH.getMean(), otherDVH.getMean(), errorConstantDVH); result = result && (aDVH.getDataDifferential().size() == otherDVH.getDataDifferential().size()); if (!result) { return result; } for (size_t i = 0; i < aDVH.getDataDifferential().size(); i++) { result = result && valueIsClose(aDVH.getDataDifferential().at(i), otherDVH.getDataDifferential().at(i), errorConstantDVH); } return result; } std::ostream& operator<<(std::ostream& s, const DVH& aDVH) { s << "[ " << aDVH.getStructureID() << ", " << aDVH.getDoseID() << ", " << aDVH.getVoxelizationID() << "\n " << "Number of Voxels: " << aDVH.getNumberOfVoxels() << " " << "Minimum/Maximum/Mean/Standard deviation: " << aDVH.getMinimum() << ", " << aDVH.getMaximum() << ", " << aDVH.getMean() << ", " << aDVH.getStdDeviation() << " ]"; return s; } std::deque DVH::getDataDifferential() const { return _dataDifferential; } std::deque DVH::getDataCumulative() const { return _dataCumulative; } DoseVoxelVolumeType DVH::getDeltaV() const { return _deltaV; } DoseTypeGy DVH::getDeltaD() const { return _deltaD; } IDType DVH::getDoseID() const { return this->_doseID; } IDType DVH::getStructureID() const { return this->_structureID; } IDType DVH::getVoxelizationID() const { return this->_voxelizationID; } void DVH::setDoseID(IDType aDoseID) { _doseID = aDoseID; } void DVH::setStructureID(IDType aStrID) { _structureID = aStrID; } DoseStatisticType DVH::getMaximum() const { return _maximum; } DoseStatisticType DVH::getMinimum() const { return _minimum; } DoseStatisticType DVH::getMean() const { return _mean; } DVHVoxelNumber DVH::getNumberOfVoxels() const { return _numberOfVoxels; } DoseStatisticType DVH::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DVH::getVariance() const { return _variance; } void DVH::init() { if (_deltaD == 0 || _deltaV == 0) { throw InvalidParameterException("DVH init error: neither _deltaD nor _deltaV must be zero!"); } if (this->_dataDifferential.empty()) { throw InvalidParameterException("DVH init error: data differential is empty!"); } double sum = 0; double squareSum = 0; _numberOfVoxels = 0; _maximum = 0; _minimum = 0; _dataCumulative.clear(); DataDifferentialType::iterator it; int i = 0; for (it = _dataDifferential.begin(); it != _dataDifferential.end(); ++it) { _numberOfVoxels += (*it); if ((*it) > 0) { _maximum = (i + 0.5) * this->_deltaD; } if ((_minimum == 0.0f) && ((*it) > 0)) { _minimum = (i + 0.5) * this->_deltaD; } sum += (*it) * (i + 0.5) * this->_deltaD; squareSum += (*it) * pow((i + 0.5) * this->_deltaD, 2); i++; } _mean = sum / _numberOfVoxels; _variance = (squareSum / _numberOfVoxels - _mean * _mean); _stdDeviation = pow(_variance, 0.5); this->calcCumulativeDVH(); } void DVH::calcCumulativeDVH() { _dataCumulative.clear(); DoseCalcType cumulativeDVHi = 0; for (auto valueItr = _dataDifferential.rbegin(); valueItr != _dataDifferential.rend(); ++valueItr) { cumulativeDVHi += *valueItr; _dataCumulative.push_front(cumulativeDVHi); } } DoseStatisticType DVH::getMedian() const { double median_voxel = 0; int median_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (median_voxel < (_numberOfVoxels - median_voxel)) { median_voxel += _dataDifferential[i]; median_i = i; } } double median = (median_i + 0.5) * this->_deltaD; return median; } DoseStatisticType DVH::getModal() const { double modal_voxel = 0; int modal_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (modal_voxel < _dataDifferential[i]) { modal_voxel = _dataDifferential[i]; modal_i = i; } } double modal = (modal_i + 0.5) * this->_deltaD; return modal; } VolumeType DVH::getVx(DoseTypeGy xDoseAbsolute) const { auto i = static_cast(xDoseAbsolute / _deltaD); if (i < _dataCumulative.size()) { VolumeType vx = (_dataCumulative.at(i)); vx = (vx * this->_deltaV); return vx; } else { return 0; } } DoseTypeGy DVH::getDx(VolumeType xVolumeAbsolute) const { GridIndexType i = 0; for (; i < _dataCumulative.size(); i++) { double volumeAbsoluteI = _dataCumulative[i] * this->_deltaV; if (xVolumeAbsolute > volumeAbsoluteI) { break; } } if (i <= _dataCumulative.size() && i > 0) { DoseTypeGy dx = (i - 1) * this->_deltaD; return dx; } else { return 0; } } VolumeType DVH::getAbsoluteVolume(int relativePercent) const { return (relativePercent * getNumberOfVoxels() * getDeltaV() / 100.0); } std::deque DVH::convertAbsoluteToRelative(bool isCumulative) const { DataDifferentialType relativeData, absoluteData; if (isCumulative) { absoluteData = getDataCumulative(); } else { absoluteData = getDataDifferential(); } for (std::deque::iterator it = absoluteData.begin(); it != absoluteData.end(); ++it) { relativeData.push_back((*it) / getNumberOfVoxels()); } return relativeData; } void DVH::setLabel(StructureLabel aLabel) { _label = aLabel; } StructureLabel DVH::getLabel() const { return _label; } std::map DVH::getNormalizedDVH(DVHType dvhType) const { std::map normalizedDVH; DataDifferentialType data; if (dvhType.Type == DVHType::Cumulative) { data = getDataCumulative(); } else { data = getDataDifferential(); } if (data.empty()) { throw InvalidParameterException("DVH data is empty. Can't retrieve normalized DVH"); } for (size_t i = 0; i < data.size(); i++) { normalizedDVH.insert(std::pair(i * getDeltaD(), data[i] * getDeltaV())); } return normalizedDVH; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVH.h b/code/core/rttbDVH.h index a86c416..59e75f3 100644 --- a/code/core/rttbDVH.h +++ b/code/core/rttbDVH.h @@ -1,218 +1,213 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_H #define __DVH_H #include #include #include #include "boost/shared_ptr.hpp" #include "rttbBaseType.h" #include "rttbCommon.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DVH @brief This is a class representing a dose volume histogram (DVH) */ class RTTBCore_EXPORT DVH { public: using DataDifferentialType = std::deque; rttbClassMacroNoParent(DVH); private: /*! @brief Differential dvh data index is the dose bin, value is the voxel number (sub voxel accuracy) of the dose bin */ DataDifferentialType _dataDifferential; /*! @brief Absolute dose value of a dose-bin in Gy */ DoseTypeGy _deltaD; /*! @brief Volume of a voxel in cm3 */ DoseVoxelVolumeType _deltaV; IDType _structureID; IDType _doseID; IDType _voxelizationID; StructureLabel _label; DoseStatisticType _maximum; DoseStatisticType _minimum; DoseStatisticType _mean; DoseStatisticType _modal; DVHVoxelNumber _numberOfVoxels; DoseStatisticType _median; DoseStatisticType _stdDeviation; DoseStatisticType _variance; DataDifferentialType _dataCumulative; /*! @brief DVH initialization The DVH is initialized and all statistical values are calculated. @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ void init(); /*! @brief Calculate the cumulative data of dvh */ void calcCumulativeDVH(); public: ~DVH(); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, const IDType& aStructureID, const IDType& aDoseID); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, const IDType& aStructureID, const IDType& aDoseID, const IDType& aVoxelizationID); DVH(const DVH& copy); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH& operator=(const DVH& copy); /*! equality operator DVHs are considered equal if the following are equal (let alone double inconsistencies): - structureID - doseID - voxelizationID - number of voxels - Histogram entries. */ bool friend operator==(const DVH& aDVH, const DVH& otherDVH); friend std::ostream& operator<<(std::ostream& s, const DVH& aDVH); void setLabel(StructureLabel aLabel); StructureLabel getLabel() const; /*! @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @return Return differential data of the dvh (relative or absolute depending on the input parameter). */ DataDifferentialType getDataDifferential() const; /*! @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @return Return cumulative data of the dvh */ DataDifferentialType getDataCumulative() const; DoseVoxelVolumeType getDeltaV() const; DoseTypeGy getDeltaD() const; IDType getStructureID() const; IDType getDoseID() const; IDType getVoxelizationID() const; void setDoseID(IDType aDoseID); void setStructureID(IDType aStrID); /*! @brief Calculate number of the voxels (with sub voxel accuracy) @return Return -1 if not initialized */ DVHVoxelNumber getNumberOfVoxels() const; /*! @brief Get the maximum dose in Gy from dvh @return Return the maximum dose in Gy (i+0.5)*deltaD, i-the maximal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMaximum() const; /*! @brief Get the minimum dose in Gy from dvh @return Return the minimum dose (i+0.5)*deltaD, i-the minimal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMinimum() const; DoseStatisticType getMean() const; DoseStatisticType getMedian() const; DoseStatisticType getModal() const; DoseStatisticType getStdDeviation() const; DoseStatisticType getVariance() const; /*! @brief Get Vx the volume irradiated to >= x @return Return absolute Volume in absolute cm3 Return -1 if not initialized */ VolumeType getVx(DoseTypeGy xDoseAbsolute) const; /*! @brief Get Dx the minimal dose delivered to x @return Return absolute dose value in Gy Return -1 if not initialized */ DoseTypeGy getDx(VolumeType xVolumeAbsolute) const; /*! @brief Calculate the absolute volume in cm3 @param relativePercent 0~100, the percent of the whole volume */ VolumeType getAbsoluteVolume(int relativePercent) const; /*! @brief Convert absolute values relative to the total number of voxels */ DataDifferentialType convertAbsoluteToRelative(bool isCumulative = true) const; /* @brief Multiplies each values with its Delta value. Values depend on DVHType. @param The DVHType that is being used DVHType::Cumulative or DVHType::Differential */ std::map getNormalizedDVH(DVHType dvhType = { DVHType::Cumulative }) const; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDVHCalculator.cpp b/code/core/rttbDVHCalculator.cpp index cbf9049..8c5e2ba 100644 --- a/code/core/rttbDVHCalculator.cpp +++ b/code/core/rttbDVHCalculator.cpp @@ -1,131 +1,124 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "rttbDVHCalculator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace core { DVHCalculator::DVHCalculator(DoseIteratorPointer aDoseIterator, const IDType& aStructureID, const IDType& aDoseID, DoseTypeGy aDeltaD, const int aNumberOfBins) { if (aDoseIterator == nullptr) { throw NullPointerException("aDoseIterator must not be nullptr! "); } _doseIteratorPtr = aDoseIterator; _structureID = aStructureID; _doseID = aDoseID; if (aNumberOfBins <= 0 || aDeltaD < 0) { throw InvalidParameterException("aNumberOfBins/aDeltaD must be >0! "); } _numberOfBins = aNumberOfBins; _deltaD = aDeltaD; if (_deltaD == 0) { aDoseIterator->reset(); DoseTypeGy max = 0; while (aDoseIterator->isPositionValid()) { DoseTypeGy currentVal = 0; currentVal = aDoseIterator->getCurrentDoseValue(); if (currentVal > max) { max = currentVal; } aDoseIterator->next(); } _deltaD = (max * 1.5 / _numberOfBins); if (_deltaD == 0) { _deltaD = 0.1; } } } DVHCalculator::~DVHCalculator() = default; DVH::Pointer DVHCalculator::generateDVH() { std::deque dataDifferential(_numberOfBins, 0); // calculate DVH _doseIteratorPtr->reset(); while (_doseIteratorPtr->isPositionValid()) { DoseTypeGy currentVal = 0; FractionType voxelProportion = _doseIteratorPtr->getCurrentRelevantVolumeFraction(); currentVal = _doseIteratorPtr->getCurrentDoseValue(); auto dose_bin = static_cast(currentVal / _deltaD); if (dose_bin < _numberOfBins) { dataDifferential[dose_bin] += voxelProportion; } else { throw InvalidParameterException("_numberOfBins is too small: dose bin out of bounds! "); } _doseIteratorPtr->next(); } if (boost::dynamic_pointer_cast(_doseIteratorPtr)) { _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), _structureID, _doseID, _doseIteratorPtr->getVoxelizationID()); } else { _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), _structureID, _doseID); } return _dvh; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVHCalculator.h b/code/core/rttbDVHCalculator.h index 0139735..55973b1 100644 --- a/code/core/rttbDVHCalculator.h +++ b/code/core/rttbDVHCalculator.h @@ -1,82 +1,77 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_CALCULATOR_H #define __DVH_CALCULATOR_H #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskedDoseIteratorInterface.h" #include "rttbDVHGeneratorInterface.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DVHCalculator @brief Calculates a DVH for a given DoseIterator. */ class RTTBCore_EXPORT DVHCalculator : public DVHGeneratorInterface { public: using DoseIteratorPointer = core::DoseIteratorInterface::Pointer; using MaskedDoseIteratorPointer = core::MaskedDoseIteratorInterface::Pointer; DoseIteratorPointer _doseIteratorPtr; IDType _structureID; IDType _doseID; DoseTypeGy _deltaD; int _numberOfBins; /*! @brief Constructor. @param aDeltaD the absolute dose value in Gy for dose_bin [i,i+1). Optional, if aDeltaD==0, it will be calculated using aDeltaD=max(aDoseIterator)*1.5/aNumberOfBins @exception InvalidParameterException throw if _numberOfBins<=0 or _deltaD<0 */ DVHCalculator(DoseIteratorPointer aDoseIterator, const IDType& aStructureID, const IDType& aDoseID, const DoseTypeGy aDeltaD = 0, const int aNumberOfBins = 201); ~DVHCalculator(); /*! @brief Generate DVH @return Return new shared pointer of DVH. @exception InvalidParameterException throw if _numberOfBins invalid: _numberOfBins must be > max(aDoseIterator)/aDeltaD! */ DVH::Pointer generateDVH() override; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDVHGeneratorInterface.h b/code/core/rttbDVHGeneratorInterface.h index 99a79a7..3c01907 100644 --- a/code/core/rttbDVHGeneratorInterface.h +++ b/code/core/rttbDVHGeneratorInterface.h @@ -1,57 +1,52 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_GENERATOR_INTERFACE_H #define __DVH_GENERATOR_INTERFACE_H #include #include "rttbDVH.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DVHGeneratorInterface @brief Interface for all DVH generating classes */ class DVHGeneratorInterface { protected: core::DVH::Pointer _dvh; public: /*! @brief Generate DVH @return Return new shared pointer of DVH. */ virtual core::DVH::Pointer generateDVH() = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDVHSet.cpp b/code/core/rttbDVHSet.cpp index 9d7fc57..6dc83bd 100644 --- a/code/core/rttbDVHSet.cpp +++ b/code/core/rttbDVHSet.cpp @@ -1,223 +1,217 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDVHSet.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { DVHSet::DVHSet(IDType aStructureSetID, IDType aDoseID) : _structureSetID(aStructureSetID), _doseID(aDoseID) {} DVHSet::DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, IDType aStructureSetID, IDType aDoseID) { _dvhHTSet = aDVHHTSet; _dvhTVSet = aDVHTVSet; this->_structureSetID = aStructureSetID; this->_doseID = aDoseID; } DVHSet::DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, IDType aStructureSetID, IDType aDoseID) { _dvhHTSet = aDVHHTSet; _dvhTVSet = aDVHTVSet; _dvhWVSet = aDVHWVSet; this->_structureSetID = aStructureSetID; this->_doseID = aDoseID; } std::size_t DVHSet::size() const { return _dvhHTSet.size() + _dvhTVSet.size() + _dvhWVSet.size(); } void DVHSet::setStrSetID(IDType aStrSetID) { _structureSetID = aStrSetID; } void DVHSet::setDoseID(IDType aDoseID) { _doseID = aDoseID; } IDType DVHSet::getStrSetID() const { return _structureSetID; } IDType DVHSet::getDoseID() const { return _doseID; } DVH* DVHSet::getDVH(IDType structureID) { auto itTV = _dvhTVSet.begin(); for (; itTV != _dvhTVSet.end(); ++itTV) { if ((*(itTV)).getStructureID() == structureID) { return &(*itTV); } } auto itHT = _dvhHTSet.begin(); for (; itHT != _dvhHTSet.end(); ++itHT) { if ((*(itHT)).getStructureID() == structureID) { return &(*itHT); } } auto itWV = _dvhWVSet.begin(); for (; itWV != _dvhWVSet.end(); ++itWV) { if ((*(itWV)).getStructureID() == structureID) { return &(*itWV); } } std::cout << "No DVH with the structure id: " << structureID << " was found!" << std::endl; return nullptr; } void DVHSet::insert(DVH& aDvh, DVHRole aDVHRole) { if (aDVHRole.Type == DVHRole::TargetVolume) { _dvhTVSet.push_back(aDvh); } else if (aDVHRole.Type == DVHRole::HealthyTissue) { _dvhHTSet.push_back(aDvh); } else if (aDVHRole.Type == DVHRole::WholeVolume) { _dvhWVSet.push_back(aDvh); } else { throw core::InvalidParameterException("aDVHType must be TV or HT or WV!"); } } VolumeType DVHSet::getWholeVolume(DoseTypeGy aDoseAbsolute) const { VolumeType volume = this->getHealthyTissueVolume(aDoseAbsolute) + this->getTargetVolume( aDoseAbsolute); return volume; } VolumeType DVHSet::getHealthyTissueVolume(DoseTypeGy aDoseAbsolute) const { auto itHT = _dvhHTSet.begin(); VolumeType volume = 0; while (itHT != _dvhHTSet.end()) { VolumeType testVol = 0; DVH dvh = *(itHT); testVol = dvh.getVx(aDoseAbsolute); if (testVol >= 0) { volume += testVol; } ++itHT; } return volume; } VolumeType DVHSet::getTargetVolume(DoseTypeGy aDoseAbsolute) const { auto itTV = _dvhTVSet.begin(); VolumeType volume = 0; while (itTV != _dvhTVSet.end()) { VolumeType testVol = 0; DVH dvh = *(itTV); testVol = dvh.getVx(aDoseAbsolute); if (testVol >= 0) { volume += testVol; } ++itTV; } return volume; } bool operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet) { if (aDVHSet.getStrSetID() != otherDVHSet.getStrSetID()) { return false; } if (aDVHSet.getDoseID() != otherDVHSet.getDoseID()) { return false; } if (aDVHSet.size() != otherDVHSet.size()) { return false; } return true; } std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet) { s << "[ " << aDVHSet.getStrSetID() << ", " << aDVHSet.getDoseID() << " ]"; return s; } std::ostream& operator<<(std::ostream& s, const DVHSet::DVHSetType& aDVHSet) { s << "[ "; for (const auto & i : aDVHSet) { s << i; } s << " ]"; return s; } } } diff --git a/code/core/rttbDVHSet.h b/code/core/rttbDVHSet.h index 2c8f10a..62b4e1f 100644 --- a/code/core/rttbDVHSet.h +++ b/code/core/rttbDVHSet.h @@ -1,152 +1,146 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DVH_SET_H #define __DVH_SET_H #include #include #include #include "rttbCommon.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DVHSet @brief This is a class representing a RT DVHSet including Target Volume and Organ at Risk. @details A DVHSet consists of three subsets: one for the target volume (_dvhTVSet), one for healthy tissue (_dvhHTSet), and one for the whole volume (_dvhWVSet). */ class RTTBCore_EXPORT DVHSet { public: rttbClassMacroNoParent(DVHSet) using DVHSetType = std::vector; using IndexType = DVHSetType::size_type; private: IDType _structureSetID; IDType _doseID; DVHSetType _dvhTVSet; DVHSetType _dvhHTSet; DVHSetType _dvhWVSet; public: DVHSet(IDType aStructureSetID = "", IDType aDoseID = ""); DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, IDType aStructureSetID = "", IDType aDoseID = ""); DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, IDType aStructureSetID = "", IDType aDoseID = ""); /*! @brief Get the size of the DVHSet, that is the sum of the numbers of DVHs in all sub-sets. */ std::size_t size() const; void setStrSetID(IDType aStrSetID); void setDoseID(IDType aDoseID); IDType getStrSetID() const; IDType getDoseID() const; /*! @brief Get the DVH according to the structure ID @return Return nullptr if not found */ DVH* getDVH(IDType aStructureID); /*! @brief Insert a DVH object. @brief param aDVHType "TV" for target volume or "HT" for healthy tissue or "WV" for whole volume @exception InvalidParameterException Thrown if no valid DVHRole was given. */ void insert(DVH& aDvh, DVHRole aDVHRole); /*! @brief Get DVH subset for target volume */ const DVHSetType& getTargetVolumeSet() const { return _dvhTVSet; }; /*! @brief Get DVH subset for healthy tissue */ const DVHSetType& getHealthyTissueSet() const { return _dvhHTSet; }; /*! @brief Get DVH subset for whole volume */ const DVHSetType& getWholeVolumeSet() const { return _dvhWVSet; }; /*! @brief Get the whole volume irradiated to >= aDoseAbsolute */ VolumeType getWholeVolume(DoseTypeGy aDoseAbsolute) const; /*! @brief Get the healthy tissue volume irradiated to >= aDoseAbsolute @return Return -1 if DVH of _dvhHTSet init() failed */ VolumeType getHealthyTissueVolume(DoseTypeGy aDoseAbsolute) const; /*! @brief Get the target volume irradiated to >= aDoseAbsolute @return Return -1 if DVH of _dvhTVSet init() failed */ VolumeType getTargetVolume(DoseTypeGy aDoseAbsolute) const; /*! DVHSets are considered equal if they have the same structureSet, dose and voxelization ID and the number of DVHs are equal. */ bool friend operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet); friend std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet); friend std::ostream& operator<<(std::ostream& s, const DVHSetType& aDVHSet); }; bool operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet); std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet); std::ostream& operator<<(std::ostream& s, const DVHSet::DVHSetType& aDVHSet); } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDataNotAvailableException.h b/code/core/rttbDataNotAvailableException.h index 2de51df..ebe6bf4 100644 --- a/code/core/rttbDataNotAvailableException.h +++ b/code/core/rttbDataNotAvailableException.h @@ -1,49 +1,42 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DATA_NOT_AVAILABLE_EXCEPTION_H #define __DATA_NOT_AVAILABLE_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" - namespace rttb { namespace core { /*! @class DataNotAvailableException @brief This exception will be thrown if the requested data is not available. */ class RTTBCore_EXPORT DataNotAvailableException : public Exception { public: DataNotAvailableException(const std::string& aWhat) : Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbDoseAccessorGeneratorBase.h b/code/core/rttbDoseAccessorGeneratorBase.h index 5808cc2..ece92d7 100644 --- a/code/core/rttbDoseAccessorGeneratorBase.h +++ b/code/core/rttbDoseAccessorGeneratorBase.h @@ -1,53 +1,48 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_GENERATOR_BASE_H #define __DOSE_ACCESSOR_GENERATOR_BASE_H #include #include "rttbDoseAccessorGeneratorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DoseAccessorGeneratorBase @brief Abstract class for all Dose Accessor generating classes */ class DoseAccessorGeneratorBase: public DoseAccessorGeneratorInterface { protected: /*! @brief Dose accessor which should be generated */ DoseAccessorPointer _doseAccessor; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDoseAccessorGeneratorInterface.h b/code/core/rttbDoseAccessorGeneratorInterface.h index f58740b..b9c50f4 100644 --- a/code/core/rttbDoseAccessorGeneratorInterface.h +++ b/code/core/rttbDoseAccessorGeneratorInterface.h @@ -1,70 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_GENERATOR_INTERFACE_H #define __DOSE_ACCESSOR_GENERATOR_INTERFACE_H #include "rttbDoseAccessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class DoseAccessorGeneratorInterface @brief Interface for all Dose Accessor generating classes */ class DoseAccessorGeneratorInterface { public: using DoseAccessorPointer = core::AccessorInterface::Pointer; private: DoseAccessorGeneratorInterface(const DoseAccessorGeneratorInterface&) = delete; //not implemented on purpose -> non-copyable DoseAccessorGeneratorInterface& operator=(const DoseAccessorGeneratorInterface&) = delete;//not implemented on purpose -> non-copyable protected: DoseAccessorGeneratorInterface() = default; virtual ~DoseAccessorGeneratorInterface() = default; public: /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. */ virtual DoseAccessorPointer generateDoseAccessor() = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDoseAccessorInterface.h b/code/core/rttbDoseAccessorInterface.h index 311f693..12669df 100644 --- a/code/core/rttbDoseAccessorInterface.h +++ b/code/core/rttbDoseAccessorInterface.h @@ -1,43 +1,38 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_INTERFACE_NEW_H #define __DOSE_ACCESSOR_INTERFACE_NEW_H #include "rttbAccessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { using DoseAccessorInterface = rttb::core::AccessorInterface; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbDoseIteratorInterface.cpp b/code/core/rttbDoseIteratorInterface.cpp index 9ebe9f9..b0c3cf9 100644 --- a/code/core/rttbDoseIteratorInterface.cpp +++ b/code/core/rttbDoseIteratorInterface.cpp @@ -1,41 +1,35 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" namespace rttb { namespace core { DoseIteratorInterface::DoseIteratorInterface(DoseAccessorPointer aDoseAccessor) { if (aDoseAccessor == nullptr) { throw NullPointerException(" dose accessor pointer must not be nullptr!"); } _spDoseAccessor = aDoseAccessor; } }//end: namespace core }//end: namespace rttb diff --git a/code/core/rttbDoseIteratorInterface.h b/code/core/rttbDoseIteratorInterface.h index f4d5bae..4fe6915 100644 --- a/code/core/rttbDoseIteratorInterface.h +++ b/code/core/rttbDoseIteratorInterface.h @@ -1,105 +1,100 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ITERATOR_INTERFACE_NEW_H #define __DOSE_ITERATOR_INTERFACE_NEW_H #include "rttbBaseType.h" #include "rttbCommon.h" #include "rttbDoseAccessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { class GeometricInfo; /*! @class DoseIteratorInterface @brief This class represents the dose iterator interface. */ class DoseIteratorInterface { public: rttbClassMacroNoParent(DoseIteratorInterface); using DoseAccessorPointer = DoseAccessorInterface::Pointer; private: DoseIteratorInterface(const DoseIteratorInterface&) = delete; //not implemented on purpose -> non-copyable DoseIteratorInterface& operator=(const DoseIteratorInterface&) = delete;//not implemented on purpose -> non-copyable DoseIteratorInterface() = default; protected: /*! @brief DoseAccessor to get access to actual dose data */ DoseAccessorPointer _spDoseAccessor; public: /*! @brief Constructor with a DoseIterator this should be the default for all implementations. */ DoseIteratorInterface(DoseAccessorPointer aDoseAccessor); virtual ~DoseIteratorInterface() = default; /*! @brief Set the iterator to the start of the dose. */ virtual bool reset() = 0; /*! @brief Move to next position. If this position is valid is not necessarily tested. */ virtual void next() = 0; virtual bool isPositionValid() const = 0; /*! @brief Return volume of one voxel (in cm3)*/ //previously getDeltaV() virtual DoseVoxelVolumeType getCurrentVoxelVolume() const = 0; virtual DoseTypeGy getCurrentDoseValue() const = 0; /*! @return If this is a masked dose iterator, return the voxel proportion inside a given structure, value 0~1; Otherwise, 1 */ virtual FractionType getCurrentRelevantVolumeFraction() const = 0; virtual VoxelGridID getCurrentVoxelGridID() const = 0; virtual IDType getVoxelizationID() const { return ""; }; IDType getDoseUID() const { return _spDoseAccessor->getUID(); }; }; //end class }//end: namespace core }//end: namespace rttb #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbException.h b/code/core/rttbException.h index e9728b2..bf6b25b 100644 --- a/code/core/rttbException.h +++ b/code/core/rttbException.h @@ -1,50 +1,44 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __RTTBEXCEPTION_H #define __RTTBEXCEPTION_H #include #include #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class Exception @brief Exception interface used by all RTToolbox exceptions. */ class RTTBCore_EXPORT Exception : public std::runtime_error { public: Exception(const std::string& aWhat) : runtime_error(aWhat) {}; }; } } #endif diff --git a/code/core/rttbExceptionMacros.h b/code/core/rttbExceptionMacros.h index cc28faf..a45ae35 100644 --- a/code/core/rttbExceptionMacros.h +++ b/code/core/rttbExceptionMacros.h @@ -1,101 +1,95 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "rttbException.h" /*!@def rttbDefaultExceptionMacro * This macro is used to throw a basic ExceptionObject within an object method. * It will generate the exception message and throw the exception.\n * Use rttbDefaultExceptionStaticMacro() for other objects that do not compli with the api or for * static functions.\n * Use rttbExceptionMacro() if you want to specifiy a arbitrary exception class that should be thrown. * Example usage looks like: * rttbDefaultExceptionMacro(<< "this is an exception" << this->SomeVariable); * @ingroup Exception */ #define rttbDefaultExceptionMacro(x) \ { \ std::ostringstream message; \ message << "Exception: " \ << "(" << this << "): " x; \ ::rttb::core::Exception e_(message.str().c_str()); \ throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } /*!@def rttbExceptionMacro * This macro is used to throw the passed exception class within an object method. * The macro presumes that the object owns a method this->GetNameOfClass().\n * The macro will set file name, line number and function signiture to the exception * and log the exception as error in the logbook before throwing it.\n * Use rttbExceptionStaticMacro() for other objects that do not compli with the api or for * static functions.\n * @sa mapGenericExceptionMacro * * Example usage looks like: * rttbExceptionMacro(AnExceptionClass, << "this is an exception" << this->SomeVariable); * @ingroup Exception */ #define rttbExceptionMacro( EType, x) \ { \ std::ostringstream message; \ message << "Exception: "\ << "(" << this << "): " x; \ EType e_(message.str().c_str()); \ throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } /*!@def rttbDefaultExceptionStaticMacro * This macro is used to throw a basic ExceptionObject within a static method. * It will generate the exception message and throw the exception.\n * Use rttbExceptionStaticMacro() if you want to specifiy a arbitrary exception class that should be thrown. * Example usage looks like: * rttbDefaultExceptionMacro(<< "this is an exception" << SomeVariable); * @ingroup Exception */ #define rttbDefaultExceptionStaticMacro(x) \ { \ std::ostringstream message; \ message << "Exception: " x; \ ::rttb::core::Exception e_(message.str().c_str()); \ throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } /*!@def rttbExceptionStaticMacro * This macro is used to throw the passed exception class within a static method. * The macro will set file name, line number and function signiture to the exception * and log the exception as error in the logbook before throwing it.\n * Use mapGenericExceptionMacro() for other objects that do not compli with the api or for * static functions.\n * @sa mapGenericExceptionMacro * * Example usage looks like: * rttbExceptionMacro(AnExceptionClass, << "this is an exception" << this->SomeVariable); * @ingroup Exception */ #define rttbExceptionStaticMacro( EType, x) \ { \ std::ostringstream message; \ message << "Exception: " x; \ EType e_(message.str().c_str()); \ throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } diff --git a/code/core/rttbGenericDoseIterator.cpp b/code/core/rttbGenericDoseIterator.cpp index f883d48..8e318f6 100644 --- a/code/core/rttbGenericDoseIterator.cpp +++ b/code/core/rttbGenericDoseIterator.cpp @@ -1,93 +1,87 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbGenericDoseIterator.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { GenericDoseIterator::GenericDoseIterator(DoseAccessorPointer aDoseAccessor) : DoseIteratorInterface( aDoseAccessor) { _currentDoseVoxelGridID = 0; _currentVoxelVolume = 0; } bool GenericDoseIterator::reset() { _currentDoseVoxelGridID = 0; if (_spDoseAccessor->isGridHomogeneous()) { SpacingVectorType3D voxelSizeVec = (_spDoseAccessor->getGeometricInfo()).getSpacing(); _currentVoxelVolume = voxelSizeVec(0) * voxelSizeVec(1) * voxelSizeVec(2) / 1000; } else { _currentVoxelVolume = 0; throw InvalidParameterException("Inhomogeneous grids are currently not supported!"); } return true; } void GenericDoseIterator::next() { if (_spDoseAccessor->getGeometricInfo().getNumberOfVoxels() > _currentDoseVoxelGridID) { ++_currentDoseVoxelGridID; } } bool GenericDoseIterator::isPositionValid() const { return _spDoseAccessor->getGeometricInfo().validID(_currentDoseVoxelGridID); } DoseVoxelVolumeType GenericDoseIterator::getCurrentVoxelVolume() const { if (_spDoseAccessor->isGridHomogeneous()) { return _currentVoxelVolume; } else { throw InvalidParameterException("Inhomogeneous grids are currently not supported!"); } } DoseTypeGy GenericDoseIterator::getCurrentDoseValue() const { if (isPositionValid()) { return _spDoseAccessor->getValueAt(_currentDoseVoxelGridID); } else { return 0; } } }//end: namespace core }//end: namespace rttb \ No newline at end of file diff --git a/code/core/rttbGenericDoseIterator.h b/code/core/rttbGenericDoseIterator.h index 799b351..4c5a53d 100644 --- a/code/core/rttbGenericDoseIterator.h +++ b/code/core/rttbGenericDoseIterator.h @@ -1,111 +1,106 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __GENERIC_DOSE_ITERATOR_INTERFACE_NEW_H #define __GENERIC_DOSE_ITERATOR_INTERFACE_NEW_H #include #include #include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class GenericDoseIterator @brief Standard implementation of the dose iterator interface. */ class RTTBCore_EXPORT GenericDoseIterator : public DoseIteratorInterface { public: using DoseAccessorPointer = DoseAccessorInterface::Pointer; using DoseIteratorPointer = DoseIteratorInterface::Pointer; private: VoxelGridID _currentDoseVoxelGridID; DoseVoxelVolumeType _currentVoxelVolume; GenericDoseIterator(const GenericDoseIterator&) = delete; //not implemented on purpose -> non-copyable GenericDoseIterator& operator=(const GenericDoseIterator&) = delete;//not implemented on purpose -> non-copyable public: /*! @brief Constructor @param aDoseAccessor contains the corresponding dose data */ GenericDoseIterator(DoseAccessorPointer aDoseAccessor); /*! @brief Set the itterator to the start of the Dose. @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because these grids are currently not supported. */ bool reset() override; /*! @brief Test if next voxel position is still on the data grid, if so move to next position. */ void next() override; /*! @brief Determine if the current voxel position is valid. */ bool isPositionValid() const override; /*! @brief Return volume of one voxel (in cm3) @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because these grids are currently not supported. */ DoseVoxelVolumeType getCurrentVoxelVolume() const override; DoseTypeGy getCurrentDoseValue() const override; /*! @brief For DoseIterators this function returns 1, always, because no mask is applied. */ inline FractionType getCurrentRelevantVolumeFraction() const override { return 1; }; inline VoxelGridID getCurrentVoxelGridID() const override { return _currentDoseVoxelGridID; }; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbGenericMaskedDoseIterator.cpp b/code/core/rttbGenericMaskedDoseIterator.cpp index cc7c34e..2424d06 100644 --- a/code/core/rttbGenericMaskedDoseIterator.cpp +++ b/code/core/rttbGenericMaskedDoseIterator.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbGenericMaskedDoseIterator.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { bool GenericMaskedDoseIterator::reset() { _maskVoxelVec = _spMask->getRelevantVoxelVector(); _currentMaskPos = _maskVoxelVec->begin(); core::GeometricInfo geoInfo = _spDoseAccessor->getGeometricInfo(); _currentVoxelVolume = geoInfo.getSpacing()(0) * geoInfo.getSpacing()(1) * geoInfo.getSpacing()( 2) / 1000; return true; } void GenericMaskedDoseIterator::next() { ++_currentMaskPos; } DoseVoxelVolumeType GenericMaskedDoseIterator::getCurrentVoxelVolume() const { if (_spDoseAccessor->isGridHomogeneous()) { return _currentVoxelVolume; } else { throw InvalidParameterException("Inhomogeneous grids are currently not supported! "); } } FractionType GenericMaskedDoseIterator::getCurrentRelevantVolumeFraction() const { if (!(_currentMaskPos == _maskVoxelVec->end())) { assert(_spMask->getGeometricInfo().validID(_currentMaskPos->getVoxelGridID())); return _currentMaskPos->getRelevantVolumeFraction(); } return 0; } bool GenericMaskedDoseIterator::isPositionValid() const { if (_currentMaskPos == _maskVoxelVec->end()) { return false; } return _spDoseAccessor->getGeometricInfo().validID(_currentMaskPos->getVoxelGridID()) && _spMask->getGeometricInfo().validID(_currentMaskPos->getVoxelGridID()); } VoxelGridID GenericMaskedDoseIterator::getCurrentVoxelGridID() const { return _currentMaskPos->getVoxelGridID(); } DoseTypeGy GenericMaskedDoseIterator::getCurrentMaskedDoseValue() const { assert(isPositionValid()); return getCurrentDoseValue() * getCurrentRelevantVolumeFraction(); } DoseTypeGy GenericMaskedDoseIterator::getCurrentDoseValue() const { assert(_spDoseAccessor->getGeometricInfo().validID(_currentMaskPos->getVoxelGridID())); return _spDoseAccessor->getValueAt(_currentMaskPos->getVoxelGridID()); } }//end namespace core }//end namespace rttb \ No newline at end of file diff --git a/code/core/rttbGenericMaskedDoseIterator.h b/code/core/rttbGenericMaskedDoseIterator.h index 9c97528..2af24e0 100644 --- a/code/core/rttbGenericMaskedDoseIterator.h +++ b/code/core/rttbGenericMaskedDoseIterator.h @@ -1,114 +1,109 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __GENERIC_MASKED_DOSE_ITERATOR_NEW_H #define __GENERIC_MASKED_DOSE_ITERATOR_NEW_H #include #include "rttbBaseType.h" #include "rttbMaskedDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class GenericMaskedDoseIterator @brief This is a templated class representing a generic masked dose iterator for a VoxelizationPolicy. @see testing/GenericMaskedDoseIteratorTest.cpp for more information. */ class RTTBCore_EXPORT GenericMaskedDoseIterator : public MaskedDoseIteratorInterface { public: using MaskVoxelListPointer = MaskAccessorInterface::MaskVoxelListPointer; using MaskVoxelList = MaskAccessorInterface::MaskVoxelList; using MaskAccessorPointer = MaskedDoseIteratorInterface::MaskAccessorPointer; using DoseAccessorPointer = MaskedDoseIteratorInterface::DoseAccessorPointer; private: using MaskVoxelListIterator = MaskVoxelList::const_iterator; /*! The current index position of the vector _maskVoxelVec*/ MaskVoxelListIterator _currentMaskPos; /*! vector of MaskVoxel, as defined in the voxelization*/ MaskVoxelListPointer _maskVoxelVec; /*! the volume in cm^3 of the current dose voxel*/ DoseVoxelVolumeType _currentVoxelVolume; public: GenericMaskedDoseIterator(MaskAccessorPointer aSpMask, DoseAccessorPointer aDoseAccessor) : MaskedDoseIteratorInterface(aSpMask, aDoseAccessor) {}; /*! @brief Set the position on the first index. Use also as initialization. */ bool reset() override; /*! move to next mask position. The validity of the position is not checked here. */ void next() override; /*! @brief Volume of one voxel (in cm3) @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because these grids are currently not supported. */ DoseVoxelVolumeType getCurrentVoxelVolume() const override; FractionType getCurrentRelevantVolumeFraction() const override; inline MaskVoxelListPointer getMaskVoxelVec() const { return _maskVoxelVec; }; /*! Check first if the position inside the maskedVoxelVector is valid. If so, check if the gridID at the current position in the MaskedVoxelVector is valid in the dose and mask grid. */ bool isPositionValid() const override; /*! @brief get current VoxelGridID (on dose voxel grid)*/ VoxelGridID getCurrentVoxelGridID() const override; /*! @return current dose value multiplied by current volume fraction*/ DoseTypeGy getCurrentMaskedDoseValue() const override; /*! @return current dose value without masking*/ DoseTypeGy getCurrentDoseValue() const override; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbGeometricInfo.cpp b/code/core/rttbGeometricInfo.cpp index e402699..5d78d25 100644 --- a/code/core/rttbGeometricInfo.cpp +++ b/code/core/rttbGeometricInfo.cpp @@ -1,310 +1,304 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbGeometricInfo.h" #include #include #include namespace rttb { namespace core { void GeometricInfo::setSpacing(const SpacingVectorType3D& aSpacingVector) { _spacing = aSpacingVector; } const SpacingVectorType3D& GeometricInfo::getSpacing() const { return _spacing; } void GeometricInfo::setImagePositionPatient(const WorldCoordinate3D& aImagePositionPatient) { _imagePositionPatient = aImagePositionPatient; } const WorldCoordinate3D& GeometricInfo::getImagePositionPatient() const { return _imagePositionPatient; } void GeometricInfo::setOrientationMatrix(const OrientationMatrix& anOrientationMatrix) { _orientationMatrix = anOrientationMatrix; computeInvertOrientation(); } bool GeometricInfo::computeInvertOrientation() { using pmatrix = boost::numeric::ublas::permutation_matrix; boost::numeric::ublas::matrix A(_orientationMatrix); // create a permutation matrix for the LU-factorization pmatrix pm(A.size1()); size_t res = boost::numeric::ublas::lu_factorize(A, pm); if (res != 0) { return false; } _invertedOrientationMatrix.assign(boost::numeric::ublas::identity_matrix (A.size1())); // backsubstitute to get the inverse boost::numeric::ublas::lu_substitute(A, pm, _invertedOrientationMatrix); return true; } void GeometricInfo::setImageSize(const ImageSize& aSize) { setNumColumns(aSize(0)); setNumRows(aSize(1)); setNumSlices(aSize(2)); } const ImageSize GeometricInfo::getImageSize() const { return ImageSize(static_cast(getNumColumns()), static_cast(getNumRows()), static_cast(getNumSlices())); } void GeometricInfo::setNumColumns(const VoxelGridDimensionType aValue) { _numberOfColumns = aValue; } const VoxelGridDimensionType GeometricInfo::getNumColumns() const { return _numberOfColumns; } void GeometricInfo::setNumRows(const VoxelGridDimensionType aValue) { _numberOfRows = aValue; } const VoxelGridDimensionType GeometricInfo::getNumRows() const { return _numberOfRows; } void GeometricInfo::setNumSlices(const VoxelGridDimensionType aValue) { _numberOfFrames = aValue; } const VoxelGridDimensionType GeometricInfo::getNumSlices() const { return _numberOfFrames; } bool operator==(const GeometricInfo& gInfo, const GeometricInfo& gInfo1) { return (gInfo.getImagePositionPatient() == gInfo1.getImagePositionPatient() && gInfo.getOrientationMatrix() == gInfo1.getOrientationMatrix() && gInfo.getSpacing() == gInfo1.getSpacing() && gInfo.getNumColumns() == gInfo1.getNumColumns() && gInfo.getNumRows() == gInfo1.getNumRows() && gInfo.getNumSlices() == gInfo1.getNumSlices()); } bool GeometricInfo::equalsAlmost(const GeometricInfo& another, double errorConstantGI /*= 1e-5*/) const { return (getImagePositionPatient().equalsAlmost(another.getImagePositionPatient(), errorConstantGI) && getOrientationMatrix().equalsAlmost(another.getOrientationMatrix(), errorConstantGI) && getSpacing().equalsAlmost(another.getSpacing(), errorConstantGI) && getNumColumns() == another.getNumColumns() && getNumRows() == another.getNumRows() && getNumSlices() == another.getNumSlices()); } bool GeometricInfo::worldCoordinateToGeometryCoordinate(const WorldCoordinate3D& aWorldCoordinate, DoubleVoxelGridIndex3D& aIndex) const { WorldCoordinate3D distanceToIP; distanceToIP = aWorldCoordinate - _imagePositionPatient; boost::numeric::ublas::vector result = boost::numeric::ublas::prod( _invertedOrientationMatrix, distanceToIP); boost::numeric::ublas::vector resultS = boost::numeric::ublas::element_div(result, _spacing); aIndex = DoubleVoxelGridIndex3D(resultS(0), resultS(1), resultS(2)); //if we convert DoubleVoxelGridIndex3D (double) to VoxelGridIndex3D (unsigned int), we can't find out if it's negative. //So we have to check before. if (aIndex(0) < -0.5 || aIndex(1) < -0.5 || aIndex(2) < -0.5){ return false; } else { //check if it is inside VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), GridIndexType(aIndex(1) + 0.5), GridIndexType(aIndex(2) + 0.5)); return isInside(indexInt); } } bool GeometricInfo::worldCoordinateToIndex(const WorldCoordinate3D& aWorldCoordinate, VoxelGridIndex3D& aIndex) const { DoubleVoxelGridIndex3D doubleIndex; bool inside = worldCoordinateToGeometryCoordinate(aWorldCoordinate, doubleIndex); aIndex = VoxelGridIndex3D(GridIndexType(doubleIndex(0)+0.5), GridIndexType(doubleIndex(1)+0.5), GridIndexType(doubleIndex(2)+0.5)); return inside; } bool GeometricInfo::geometryCoordinateToWorldCoordinate(const DoubleVoxelGridIndex3D& aIndex, WorldCoordinate3D& aWorldCoordinate) const { boost::numeric::ublas::vector resultS = boost::numeric::ublas::element_prod( aIndex, _spacing); boost::numeric::ublas::vector result = boost::numeric::ublas::prod( _orientationMatrix, resultS); aWorldCoordinate = result + _imagePositionPatient; //if we convert DoubleVoxelGridIndex3D (double) to VoxelGridIndex3D (unsigned int), we can't find out if it's negative. //So we have to check before. if (aIndex(0) < -0.5 || aIndex(1) < -0.5 || aIndex(2) < -0.5){ return false; } else { VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), GridIndexType(aIndex(1) + 0.5), GridIndexType(aIndex(2) + 0.5)); return isInside(indexInt); } } bool GeometricInfo::indexToWorldCoordinate(const VoxelGridIndex3D& aIndex, WorldCoordinate3D& aWorldCoordinate) const { DoubleVoxelGridIndex3D indexDouble = DoubleVoxelGridIndex3D(aIndex(0), aIndex(1), aIndex(2)); return geometryCoordinateToWorldCoordinate(indexDouble, aWorldCoordinate); } bool GeometricInfo::isInside(const VoxelGridIndex3D& aIndex) const { return (aIndex(0) >= 0 && aIndex(1) >= 0 && aIndex(2) >= 0 && aIndex(0) < static_cast(_numberOfColumns) && aIndex(1) < static_cast(_numberOfRows) && aIndex(2) < static_cast(_numberOfFrames)); } bool GeometricInfo::isInside(const WorldCoordinate3D& aWorldCoordinate) const { VoxelGridIndex3D currentIndex; return (worldCoordinateToIndex(aWorldCoordinate, currentIndex)); } const GridSizeType GeometricInfo::getNumberOfVoxels() const { auto nVoxels = static_cast(_numberOfRows * _numberOfColumns * _numberOfFrames); return nVoxels; } bool GeometricInfo::convert(const VoxelGridID& gridID, VoxelGridIndex3D& gridIndex) const { if (validID(gridID)) { gridIndex(0) = gridID % getNumColumns(); VoxelGridID tempID = (gridID - gridIndex.x()) / getNumColumns(); gridIndex(1) = tempID % getNumRows(); gridIndex(2) = (tempID - gridIndex.y()) / getNumRows(); return true; } return false; } bool GeometricInfo::convert(const VoxelGridIndex3D& gridIndex, VoxelGridID& gridID) const { if ((gridIndex.x() >= static_cast(getNumColumns())) || (gridIndex.y() >= static_cast(getNumRows())) || (gridIndex.z() >= static_cast(getNumSlices()))) { return false; } else { gridID = gridIndex.z() * getNumColumns() * getNumRows() + gridIndex.y() * getNumColumns() + gridIndex.x(); return validID(gridID); } } bool GeometricInfo::validID(const VoxelGridID aID) const { return (aID >= 0 && aID < getNumberOfVoxels()); } bool GeometricInfo::validIndex(const VoxelGridIndex3D& aIndex) const { VoxelGridID aID; if (!convert(aIndex, aID)) { return false; } else { return validID(aID); } } std::ostream& operator<<(std::ostream& s, const GeometricInfo& anGeometricInfo) { s << "[ " << anGeometricInfo.getImagePositionPatient() << "; " << anGeometricInfo.getOrientationMatrix() << "; " << anGeometricInfo.getSpacing() << "; " << "; " << anGeometricInfo.getNumColumns() << "; " << anGeometricInfo.getNumRows() << "; " << anGeometricInfo.getNumSlices() << " ]"; return s; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbGeometricInfo.h b/code/core/rttbGeometricInfo.h index 983c8e9..d4ea7e0 100644 --- a/code/core/rttbGeometricInfo.h +++ b/code/core/rttbGeometricInfo.h @@ -1,193 +1,187 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __GEOMETRIC_INFO_NEW_H #define __GEOMETRIC_INFO_NEW_H #include #include #include "rttbBaseType.h" #include #include "rttbCommon.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @brief GeometricInfo objects contain all the information required for transformations between voxel grid coordinates and world coordinates. Corresponding converter functions are also available. @note ITK Pixel Indexing used (http://www.itk.org/Doxygen45/html/classitk_1_1Image.html): The Index type reverses the order so that with Index[0] = col, Index[1] = row, Index[2] = slice. */ class RTTBCore_EXPORT GeometricInfo { public: rttbClassMacroNoParent(GeometricInfo) private: WorldCoordinate3D _imagePositionPatient{ 0 }; OrientationMatrix _orientationMatrix{ 0 }; OrientationMatrix _invertedOrientationMatrix{ 0 }; SpacingVectorType3D _spacing{ 0 }; VoxelGridDimensionType _numberOfColumns{0}; VoxelGridDimensionType _numberOfRows{0}; VoxelGridDimensionType _numberOfFrames{0}; /* @brief Matrix inversion routine. Uses lu_factorize and lu_substitute in uBLAS to invert a matrix http://savingyoutime.wordpress.com/2009/09/21/c-matrix-inversion-boostublas/ */ bool computeInvertOrientation(); public: /*! @brief Constructor, initializes orientation matrix, spacing vector and patient position with zeros. */ GeometricInfo() = default; void setSpacing(const SpacingVectorType3D& aSpacingVector); const SpacingVectorType3D& getSpacing() const; void setImagePositionPatient(const WorldCoordinate3D& aImagePositionPatient); const WorldCoordinate3D& getImagePositionPatient() const; void setOrientationMatrix(const OrientationMatrix& anOrientationMatrix); const OrientationMatrix getOrientationMatrix() const { return _orientationMatrix; }; void setImageSize(const ImageSize& aSize); const ImageSize getImageSize() const; void setNumColumns(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumColumns() const; void setNumRows(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumRows() const; void setNumSlices(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumSlices() const; /*! @brief determines equality of two GeometricInfo objects. */ friend bool RTTBCore_EXPORT operator == (const GeometricInfo& gInfo, const GeometricInfo& gInfo1); bool equalsAlmost(const GeometricInfo& another, double errorConstantGI = 1e-5) const; /*! @brief converts world coordinates to voxel grid index. @details the voxels world coordinates are defined by spacing, orientation and imagePositionPatient. (-0.5/-0.5/-0.5) --> (0/0/0) and (0.4999/0.4999/0.4999) --> (0/0/0) define the outer coordinates of a voxel with spacing=1, orientation= x y z (identity matrix) and imagePositionPatient=(0/0/0). @sa WorldCoordinate3D VoxelGridIndex3D @note The conversion of values is done even if the target index is not inside the given voxel grid. @returns false if aWorldCoordinate is outside the voxel grid, true otherwise. */ bool worldCoordinateToIndex(const WorldCoordinate3D& aWorldCoordinate, VoxelGridIndex3D& aIndex) const; /*! @brief converts world coordinates to double geometry coordinate. @details This is needed because of a double precision voxel coordinate system for voxelization. The world coordinate of the image position patient is the center of the first voxel (0.0/0.0/0.0). (-0.5/-0.5/-0.5) --> (-0.5/-0.5/-0.5) and (0.4999/0.4999/0.4999) --> (0.4999/0.4999/0.4999) with spacing=1, orientation= x y z (identity matrix) and imagePositionPatient=(0/0/0). @sa WorldCoordinate3D, DoubleVoxelGridIndex3D @note The conversion of values is done even if the target index is not inside the given voxel grid. @returns false if aWorldCoordinate is outside the voxel grid, true otherwise. */ bool worldCoordinateToGeometryCoordinate(const WorldCoordinate3D& aWorldCoordinate, DoubleVoxelGridIndex3D& aIndex) const; /*! @brief converts double geometry coordinate to world coordinates. @details This is needed because of a double precision voxel coordinate system for voxelization. The world coordinate of the image position patient is the center of the first voxel (0.0/0.0/0.0). (-0.5/-0.5/-0.5) --> (-0.5/-0.5/-0.5) and (5.5/3.2/1.0) --> (5.5/3.2/1.0) with spacing=1, orientation= x y z (identity matrix) and imagePositionPatient=(0/0/0). @sa DoubleVoxelGridIndex3D, WorldCoordinate3D @note The conversion of values is done even if the target index is not inside the given voxel grid. @returns false if aWorldCoordinate is outside the voxel grid, true otherwise. */ bool geometryCoordinateToWorldCoordinate(const DoubleVoxelGridIndex3D& aIndex, WorldCoordinate3D& aWorldCoordinate) const; /*! @brief convert voxel grid index to world coordinates @details The world coordinate of the image position patient (center of the first voxel) is the center of the first voxel (0.0/0.0/0.0) (0/0/0) --> (0.0/0.0/0.0) and (1/1/2) --> (1.0/1.0/2.0) with spacing=1, orientation= x y z (identity matrix) and imagePositionPatient=(0/0/0). Thus, the center of the voxel is taken and converted. @sa VoxelGridIndex3D, WorldCoordinate3D @note The conversion of values is done even if the target index is not inside the given voxel grid. @returns false if aWorldCoordinate is outside the voxel grid, true otherwise. */ bool indexToWorldCoordinate(const VoxelGridIndex3D& aIndex, WorldCoordinate3D& aWorldCoordinate) const; /*! @brief check if a given voxel grid index is inside the given voxel grid.*/ bool isInside(const VoxelGridIndex3D& aIndex) const; /*! @brief check if a given world coordinate is inside the given voxel grid.*/ bool isInside(const WorldCoordinate3D& aWorldCoordinate) const; const GridSizeType getNumberOfVoxels() const; bool convert(const VoxelGridID& gridID, VoxelGridIndex3D& gridIndex) const; bool convert(const VoxelGridIndex3D& gridIndex, VoxelGridID& gridID) const; /*! @brief test if given ID is inside current dose grid */ bool validID(const VoxelGridID aID) const; /*! @brief test if given index is inside current dose grid */ bool validIndex(const VoxelGridIndex3D& aIndex) const; /*!@ brief generates string stream representation of the GeometricInfo object. */ friend std::ostream& operator << (std::ostream& s, const GeometricInfo& anGeometricInfo); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbIndexConversionInterface.h b/code/core/rttbIndexConversionInterface.h index 5982e5f..36c7bc6 100644 --- a/code/core/rttbIndexConversionInterface.h +++ b/code/core/rttbIndexConversionInterface.h @@ -1,60 +1,55 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __INDEX_CONVERSION_INTERFACE_NEW_H #define __INDEX_CONVERSION_INTERFACE_NEW_H #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif #include namespace rttb { namespace core { /*! @class IndexConversionInterface @brief This class represents the conversion of 3D grid indices to 1D grid IDs. */ class IndexConversionInterface { public: rttbClassMacroNoParent(IndexConversionInterface); private: IndexConversionInterface(const IndexConversionInterface&) = delete; //not implemented on purpose -> non-copyable IndexConversionInterface& operator=(const IndexConversionInterface&) = delete;//not implemented on purpose -> non-copyable public: IndexConversionInterface() = default; virtual ~IndexConversionInterface() = default; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbIndexOutOfBoundsException.h b/code/core/rttbIndexOutOfBoundsException.h index 33dcdf3..c645f2f 100644 --- a/code/core/rttbIndexOutOfBoundsException.h +++ b/code/core/rttbIndexOutOfBoundsException.h @@ -1,47 +1,41 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __INDEX_OUT_OF_BOUNDS_EXCEPTION_H #define __INDEX_OUT_OF_BOUNDS_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class IndexOutOfBoundsException @brief This exception will be thrown if any index out of bound. */ class RTTBCore_EXPORT IndexOutOfBoundsException : public Exception { public: IndexOutOfBoundsException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbInvalidDoseException.h b/code/core/rttbInvalidDoseException.h index 84a9e4a..c815749 100644 --- a/code/core/rttbInvalidDoseException.h +++ b/code/core/rttbInvalidDoseException.h @@ -1,48 +1,42 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __INVALID_DOSE_EXCEPTION_H #define __INVALID_DOSE_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class InvalidDoseException @brief This exception will be thrown if dose is invalid. */ class RTTBCore_EXPORT InvalidDoseException : public Exception { public: InvalidDoseException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbInvalidParameterException.h b/code/core/rttbInvalidParameterException.h index e3b2aad..1d4d903 100644 --- a/code/core/rttbInvalidParameterException.h +++ b/code/core/rttbInvalidParameterException.h @@ -1,47 +1,41 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __INVALID_PARAMETER_EXCEPTION_H #define __INVALID_PARAMETER_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class InvalidParameterException @brief This exception will be thrown if any parameter is invalid. */ class RTTBCore_EXPORT InvalidParameterException : public Exception { public: InvalidParameterException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbMappingOutsideOfImageException.h b/code/core/rttbMappingOutsideOfImageException.h index e5d0b8a..7f97af1 100644 --- a/code/core/rttbMappingOutsideOfImageException.h +++ b/code/core/rttbMappingOutsideOfImageException.h @@ -1,49 +1,42 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __MAPPING_OUTSIDE_OF_IMAGE_EXCEPTION_H #define __MAPPING_OUTSIDE_OF_IMAGE_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" - namespace rttb { namespace core { /*! @class MappingOutsideOfImageException @brief This exception will be thrown if a transformation leads to an invalid position outside of the image. */ class RTTBCore_EXPORT MappingOutsideOfImageException : public Exception { public: MappingOutsideOfImageException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbMaskAccessorGeneratorBase.h b/code/core/rttbMaskAccessorGeneratorBase.h index 87dbadd..250618d 100644 --- a/code/core/rttbMaskAccessorGeneratorBase.h +++ b/code/core/rttbMaskAccessorGeneratorBase.h @@ -1,62 +1,57 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MASK_ACCESSOR_GENERATOR_BASE_H #define __MASK_ACCESSOR_GENERATOR_BASE_H #include "rttbMaskAccessorGeneratorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MaskAccessorGeneratorBase @brief Abstract class for all DoseAccessor generating classes */ class MaskAccessorGeneratorBase: public MaskAccessorGeneratorInterface { public: using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; private: protected: /*! @brief Mask accessor which should be generated */ MaskAccessorPointer _maskAccessor; public: }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskAccessorGeneratorInterface.h b/code/core/rttbMaskAccessorGeneratorInterface.h index f750cce..7612996 100644 --- a/code/core/rttbMaskAccessorGeneratorInterface.h +++ b/code/core/rttbMaskAccessorGeneratorInterface.h @@ -1,70 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MASK_ACCESSOR_GENERATOR_INTERFACE_H #define __MASK_ACCESSOR_GENERATOR_INTERFACE_H #include "rttbMaskAccessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MaskAccessorGeneratorInterface @brief Interface for all MaskAccessor generating classes */ class MaskAccessorGeneratorInterface { public: using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; private: MaskAccessorGeneratorInterface(const MaskAccessorGeneratorInterface&) = delete; //not implemented on purpose -> non-copyable MaskAccessorGeneratorInterface& operator=(const MaskAccessorGeneratorInterface&) = delete;//not implemented on purpose -> non-copyable protected: MaskAccessorGeneratorInterface() = default; virtual ~MaskAccessorGeneratorInterface() = default; public: /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. */ virtual MaskAccessorPointer generateMaskAccessor() = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskAccessorInterface.h b/code/core/rttbMaskAccessorInterface.h index 44072d0..0b532d6 100644 --- a/code/core/rttbMaskAccessorInterface.h +++ b/code/core/rttbMaskAccessorInterface.h @@ -1,111 +1,106 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MASK_ACCESSOR_INTERFACE_NEW_H #define __MASK_ACCESSOR_INTERFACE_NEW_H #include "rttbCommon.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" #include "rttbIndexConversionInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { class GeometricInfo; /*! @class MaskAccessorInterface @brief This class triggers the voxelization and gives acess to the masked voxels. */ class MaskAccessorInterface: public IndexConversionInterface { public: rttbClassMacro(MaskAccessorInterface, IndexConversionInterface); using MaskVoxelList = std::vector; using MaskVoxelListPointer = boost::shared_ptr; private: MaskAccessorInterface(const MaskAccessorInterface&) = delete; //not implemented on purpose -> non-copyable MaskAccessorInterface& operator=(const MaskAccessorInterface&) = delete;//not implemented on purpose -> non-copyable public: MaskAccessorInterface() = default; ~MaskAccessorInterface() override = default; /*! @brief Start generation of mask @post mask is valid and acessible */ virtual void updateMask() = 0; virtual const GeometricInfo& getGeometricInfo() const = 0; /*! @brief Get vector containing all relevant voxels that are inside the given structure. */ virtual MaskVoxelListPointer getRelevantVoxelVector() = 0; /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure @pre updateMask should have been called (at least once, to ensure a valid mask). */ virtual MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold) = 0; /*! @brief Get masked voxel value corresponding to a given VoxelGridID. @post after a valid call voxel contains the mask information corresponding to aID. If aID is not valid, voxel values are undefined. @return Indicates if a MaskVoxel for the given ID exists and therefore if parameter voxel containes valid values. @pre updateMask should have been called (at least once, to ensure a valid mask). */ virtual bool getMaskAt(const VoxelGridID aID, MaskVoxel& voxel) const = 0; /*! @brief Get masked voxel value corresponding to a given VoxelGridIndex. @post after a valid call voxel contains the mask information corresponding to gridIndex. If gridIndex is not valid, voxel values are undefined. @return Indicates if a MaskVoxel for the given index exists and therefore if parameter voxel containes valid values. @pre updateMask should have been called (at least once, to ensure a valid mask). */ virtual bool getMaskAt(const VoxelGridIndex3D& gridIndex, MaskVoxel& voxel) const = 0; /* @brief Is true if dose is on a homogeneous grid. @note Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change. */ virtual bool isGridHomogeneous() const { return true; } virtual IDType getMaskUID() const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskAccessorProcessorBase.h b/code/core/rttbMaskAccessorProcessorBase.h index 05d9010..2b2044f 100644 --- a/code/core/rttbMaskAccessorProcessorBase.h +++ b/code/core/rttbMaskAccessorProcessorBase.h @@ -1,68 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MASK_ACCESSOR_PROCESSOR_BASE_H #define __MASK_ACCESSOR_PROCESSOR_BASE_H #include "rttbMaskAccessorProcessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MaskAccessorProcessorBase @brief Abstract class for all MaskAccessor converter classes */ class MaskAccessorProcessorBase: public MaskAccessorProcessorInterface { public: using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; void setMaskAccessor(MaskAccessorPointer accessor) override { _maskAccessor = accessor; }; private: MaskAccessorProcessorBase(const MaskAccessorProcessorBase&) = delete; //not implemented on purpose -> non-copyable MaskAccessorProcessorBase& operator=(const MaskAccessorProcessorBase&) = delete;//not implemented on purpose -> non-copyable protected: MaskAccessorProcessorBase() = default; ~MaskAccessorProcessorBase() override = default; /*! @brief Mask accessor which should be generated */ MaskAccessorPointer _maskAccessor; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskAccessorProcessorInterface.h b/code/core/rttbMaskAccessorProcessorInterface.h index c3064e1..3ea5fec 100644 --- a/code/core/rttbMaskAccessorProcessorInterface.h +++ b/code/core/rttbMaskAccessorProcessorInterface.h @@ -1,74 +1,69 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MASK_ACCESSOR_PROCESSOR_INTERFACE_H #define __MASK_ACCESSOR_PROCESSOR_INTERFACE_H #include "rttbMaskAccessorInterface.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MaskAccessorProcessorInterface @brief Interface for all MaskAccessor converter classes */ class MaskAccessorProcessorInterface { public: using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; private: MaskAccessorProcessorInterface(const MaskAccessorProcessorInterface&) = delete; //not implemented on purpose -> non-copyable MaskAccessorProcessorInterface& operator=(const MaskAccessorProcessorInterface&) = delete;//not implemented on purpose -> non-copyable protected: MaskAccessorProcessorInterface() = default; virtual ~MaskAccessorProcessorInterface() = default; public: /*! @brief Sets the MaskAccessor that should be processed @pre passed accessor must point to a valid instance. */ virtual void setMaskAccessor(MaskAccessorPointer accessor) = 0; /*! @brief Process the passed MaskAccessor @return if the processing was successful. */ virtual bool process() = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskVoxel.cpp b/code/core/rttbMaskVoxel.cpp index f230eb1..6e7f1dd 100644 --- a/code/core/rttbMaskVoxel.cpp +++ b/code/core/rttbMaskVoxel.cpp @@ -1,96 +1,90 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbMaskVoxel.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { MaskVoxel::MaskVoxel(const rttb::VoxelGridID& aVoxelGridID) { if (aVoxelGridID < 0) { std::cout << aVoxelGridID << std::endl; throw InvalidParameterException("VoxelGridID is not valid!"); } else { _voxelGridID = aVoxelGridID; _volumeFraction = 1; } } MaskVoxel::MaskVoxel(const rttb::VoxelGridID& aVoxelGridID, FractionType aVolumeFraction) { if (aVoxelGridID < 0) { std::cout << aVoxelGridID << std::endl; throw InvalidParameterException("VoxelGridID is not valid!"); } else if (aVolumeFraction < 0 || aVolumeFraction > 1) { std::cout << aVolumeFraction << std::endl; throw InvalidParameterException("Volume fraction needs to be between 0 and 1!"); } else { _voxelGridID = aVoxelGridID; _volumeFraction = aVolumeFraction; } } bool MaskVoxel::operator==(const MaskVoxel& voxel) const { return ((_voxelGridID == voxel.getVoxelGridID()) && (_volumeFraction == voxel.getRelevantVolumeFraction())); } bool MaskVoxel::operator<(const MaskVoxel& maskVoxel) const { return (_voxelGridID < maskVoxel.getVoxelGridID()); } const VoxelGridID& MaskVoxel::getVoxelGridID() const { return _voxelGridID; } void MaskVoxel::setRelevantVolumeFraction(FractionType aVolumeFraction) { if (aVolumeFraction < 0 || aVolumeFraction > 1) { std::cout << aVolumeFraction << std::endl; throw InvalidParameterException("Volume fraction needs to be between 0 and 1!"); } _volumeFraction = aVolumeFraction; } FractionType MaskVoxel::getRelevantVolumeFraction() const { return _volumeFraction; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbMaskVoxel.h b/code/core/rttbMaskVoxel.h index 8f07e9d..1f7891d 100644 --- a/code/core/rttbMaskVoxel.h +++ b/code/core/rttbMaskVoxel.h @@ -1,92 +1,86 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __MASK_VOXEL_NEW_H #define __MASK_VOXEL_NEW_H #include "rttbBaseType.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MaskVoxel * @brief AMaskVoxel stores the VoxelGridID of the corresponding dose voxel and the corresponding volume fraction as defined by the given mask. */ class RTTBCore_EXPORT MaskVoxel { private: /*! @brief A 1D voxel grid index on dose grid */ VoxelGridID _voxelGridID; /*! @brief The relevant volume fraction that is masked by the given structure: 0~1 */ FractionType _volumeFraction; public: /*! @brief Constructor @pre aVoxelGridID needs to point to a valid grid position. */ MaskVoxel(const VoxelGridID& aVoxelGridID); /*! @brief Constructor @pre aVoxelGridID needs to point to a valid grid position. */ MaskVoxel(const VoxelGridID& aVoxelGridID, FractionType aVolumeFraction); /*! @brief Operator == @return Return true if the id and volumeFraction are equal to these of the maskVoxel */ bool operator==(const MaskVoxel& maskVoxel) const; /*! @brief Operator < @return Return true if the id < the id of the maskVoxel */ bool operator<(const MaskVoxel& maskVoxel) const; const VoxelGridID& getVoxelGridID() const; void setRelevantVolumeFraction(const FractionType aVolumeFraction); FractionType getRelevantVolumeFraction() const; friend std::ostream& operator<<(std::ostream& s, const MaskVoxel& maskVoxel) { s << "( " << maskVoxel.getVoxelGridID() << ": " << maskVoxel.getRelevantVolumeFraction() << " )"; return s; }; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMaskedDoseIteratorInterface.cpp b/code/core/rttbMaskedDoseIteratorInterface.cpp index f7659e2..cc89049 100644 --- a/code/core/rttbMaskedDoseIteratorInterface.cpp +++ b/code/core/rttbMaskedDoseIteratorInterface.cpp @@ -1,49 +1,43 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbMaskedDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "rttbNullPointerException.h" #include "rttbException.h" namespace rttb { namespace core { MaskedDoseIteratorInterface::MaskedDoseIteratorInterface(MaskAccessorPointer aMaskAccessor, DoseAccessorPointer aDoseAccessor): DoseIteratorInterface(aDoseAccessor) { if (aMaskAccessor == nullptr) { throw NullPointerException(" mask pointer must not be nullptr!"); } else { _spMask = aMaskAccessor; } if (!(_spMask->getGeometricInfo() == _spDoseAccessor->getGeometricInfo())) { throw Exception("Mask and Dose need to be defined on the same grid"); } } } } \ No newline at end of file diff --git a/code/core/rttbMaskedDoseIteratorInterface.h b/code/core/rttbMaskedDoseIteratorInterface.h index be8c87e..aeccc3a 100644 --- a/code/core/rttbMaskedDoseIteratorInterface.h +++ b/code/core/rttbMaskedDoseIteratorInterface.h @@ -1,86 +1,80 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __MASKED_DOSE_ITERATOR_INTERFACE_NEW_H #define __MASKED_DOSE_ITERATOR_INTERFACE_NEW_H #include #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { class MaskAccessorInterface; /*! @class MaskedDoseIteratorInterface @brief Give access to masked dose data. */ class RTTBCore_EXPORT MaskedDoseIteratorInterface : public DoseIteratorInterface { public: rttbClassMacro(MaskedDoseIteratorInterface, DoseIteratorInterface); using MaskAccessorPointer = MaskAccessorInterface::Pointer; using DoseAccessorPointer = DoseAccessorInterface::Pointer; using DoseIteratorPointer = DoseIteratorInterface::Pointer; private: MaskedDoseIteratorInterface(const MaskedDoseIteratorInterface&) = delete; MaskedDoseIteratorInterface& operator=(const MaskedDoseIteratorInterface&) = delete; protected: /*! @brief Mask that is to be applied to currently loaded dose*/ MaskAccessorPointer _spMask; public: /* Constructor @pre core::GeometricInfo represents the same geometric space for both mask and dose, i.e. both live on the same data grid. Both accessors need to be valid. */ MaskedDoseIteratorInterface(MaskAccessorPointer aMaskAccessor, DoseAccessorPointer aDoseAccessor); ~MaskedDoseIteratorInterface() override = default; inline MaskAccessorPointer getMaskAccessor() const { return _spMask; }; /* Return doseValue*voxelFraction for the current position */ virtual DoseTypeGy getCurrentMaskedDoseValue() const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMutableDoseAccessorInterface.h b/code/core/rttbMutableDoseAccessorInterface.h index 91bd539..c491e90 100644 --- a/code/core/rttbMutableDoseAccessorInterface.h +++ b/code/core/rttbMutableDoseAccessorInterface.h @@ -1,59 +1,54 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MUTABLE_DOSE_ACCESSOR_INTERFACE_NEW_H #define __MUTABLE_DOSE_ACCESSOR_INTERFACE_NEW_H #include "rttbDoseAccessorInterface.h" #include "rttbBaseType.h" #include "rttbCommon.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class MutableDoseAccessorInterface @brief Extends the DoseAccessorInterface to provide writing access to the data. */ class MutableDoseAccessorInterface: public DoseAccessorInterface { public: rttbClassMacro(MutableDoseAccessorInterface, DoseAccessorInterface) virtual void setDoseAt(const VoxelGridID aID, DoseTypeGy value) = 0; virtual void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbMutableMaskAccessorInterface.h b/code/core/rttbMutableMaskAccessorInterface.h index 1054e6d..6601102 100644 --- a/code/core/rttbMutableMaskAccessorInterface.h +++ b/code/core/rttbMutableMaskAccessorInterface.h @@ -1,65 +1,60 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MUTABLE_MASK_ACCESSOR_INTERFACE_H #define __MUTABLE_MASK_ACCESSOR_INTERFACE_H #include "rttbCommon.h" #include "rttbMaskAccessorInterface.h" #include "rttbBaseType.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { class MaskVoxel; /*! @class MutableMaskAccessorInterface @brief Extends the MaskAccessorInterface to provide writing access to the data. @details This interface is created for external manipulation of generated masks. For example to store the results of arithmetic operations on other masks. */ class MutableMaskAccessorInterface: public MaskAccessorInterface { public: rttbClassMacro(MutableMaskAccessorInterface, MaskAccessorInterface) using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; virtual void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer) = 0; virtual void setMaskAt(VoxelGridID aID, const MaskVoxel& voxel) = 0; virtual void setMaskAt(const VoxelGridIndex3D& gridIndex, const MaskVoxel& voxel) = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbNullPointerException.h b/code/core/rttbNullPointerException.h index 3de5e2f..dc2d2dd 100644 --- a/code/core/rttbNullPointerException.h +++ b/code/core/rttbNullPointerException.h @@ -1,47 +1,40 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __NULL_POINTER_EXCEPTION_H #define __NULL_POINTER_EXCEPTION_H #include #include "rttbException.h" #include "RTTBCoreExports.h" - namespace rttb { namespace core { /*! @class NullPointerException @brief This exception will be thrown if any pointer is nullptr. */ class RTTBCore_EXPORT NullPointerException : public Exception { public: NullPointerException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbPaddingException.h b/code/core/rttbPaddingException.h index 0d76de0..c7618d8 100644 --- a/code/core/rttbPaddingException.h +++ b/code/core/rttbPaddingException.h @@ -1,47 +1,40 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __PADDING_EXCEPTION_H #define __PADDING_EXCEPTION_H #include #include "rttbException.h" - namespace rttb { namespace core { /*! @class PaddingException @brief This exception will be thrown if it can't be guaranteed that a transformation covers only a part of the target space. */ class PaddingException: public Exception { public: PaddingException(const std::string& aWhat): Exception(aWhat) {} }; } } #endif diff --git a/code/core/rttbStrVectorStructureSetGenerator.cpp b/code/core/rttbStrVectorStructureSetGenerator.cpp index 5a2b7f4..e0651f7 100644 --- a/code/core/rttbStrVectorStructureSetGenerator.cpp +++ b/code/core/rttbStrVectorStructureSetGenerator.cpp @@ -1,67 +1,61 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbStrVectorStructureSetGenerator.h" #include #include "boost/make_shared.hpp" namespace rttb { namespace core { StrVectorStructureSetGenerator::StrVectorStructureSetGenerator(std::vector& aStructureVector, IDType aPatientUID) { _patientUID = aPatientUID; _strVector = aStructureVector; } StrVectorStructureSetGenerator::StructureSetPointer StrVectorStructureSetGenerator::generateStructureSet() { std::vector _filteredStructs = _strVector; if (this->getStructureLabelFilterActive()) { _filteredStructs.clear(); std::regex e(this->getFilterRegEx()); std::vector::iterator it; for(it= _strVector.begin();it!=_strVector.end();++it) { if (std::regex_match((*it)->getLabel(), e)) { _filteredStructs.push_back((*it)); } } } return boost::make_shared(_filteredStructs, _patientUID); } } }//end namespace rttb diff --git a/code/core/rttbStrVectorStructureSetGenerator.h b/code/core/rttbStrVectorStructureSetGenerator.h index ae52196..a3e6097 100644 --- a/code/core/rttbStrVectorStructureSetGenerator.h +++ b/code/core/rttbStrVectorStructureSetGenerator.h @@ -1,83 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #ifndef __STR_VECTOR_STRUCTURE_SET_GENERATOR_H #define __STR_VECTOR_STRUCTURE_SET_GENERATOR_H #include #include #include "rttbStructureSetGeneratorInterface.h" #include "rttbStructureSet.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class StrVectorStructureSetGenerator @brief Generate a structure set with a vector of Structures. */ class RTTBCore_EXPORT StrVectorStructureSetGenerator : public core::StructureSetGeneratorInterface { public: using StructTypePointer = core::Structure::Pointer; using StructureSetPointer = StructureSet::Pointer; protected: IDType _patientUID; std::vector _strVector; StrVectorStructureSetGenerator() = default; public: /*! @brief Constructor @param aStructureVector the vector of structure shared pointer @param aPatientUID the patient UID. */ StrVectorStructureSetGenerator(std::vector& aStructureVector, IDType aPatientUID = ""); /*! @brief Generate StructureSet @return Return shared pointer of StructureSet. */ StructureSetPointer generateStructureSet() override; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbStructure.cpp b/code/core/rttbStructure.cpp index 8872ca2..22dfe89 100644 --- a/code/core/rttbStructure.cpp +++ b/code/core/rttbStructure.cpp @@ -1,145 +1,139 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include #include #include "rttbStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { /*! Compares two polygons in the same plane. Helper function for sorting of polygons. */ bool comparePolygon(PolygonType A, PolygonType B) { PolygonType::iterator it; for (it = A.begin(); it != A.end(); ++it) { if ((*it)(2) != A.at(0)(2)) { throw std::range_error("Error: A must in the same _z plane!"); } } PolygonType::iterator it2; for (it2 = B.begin(); it2 != B.end(); ++it2) { if ((*it2)(2) != B.at(0)(2)) { throw std::range_error("Error: B must in the same _z plane!"); } } if (A.size() == 0 || B.size() == 0) { throw std::range_error("Error: A and B must not be empty!"); } return (A.at(0)(2) < B.at(0)(2)); } Structure::Structure() : _structureVector(0), _label("") { if (_strUID.empty()) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _strUID = ss.str(); } } Structure::Structure(PolygonSequenceType strVector) : Structure() { _structureVector = strVector; sort(_structureVector.begin(), _structureVector.end(), comparePolygon); } Structure::Structure(const Structure& copy) : _structureVector(copy.getStructureVector()), _strUID(copy.getUID()), _label(copy.getLabel()) { } Structure::~Structure() = default; const PolygonSequenceType& Structure::getStructureVector() const { return _structureVector; } int Structure::getNumberOfEndpoints() const { int count = 0; PolygonSequenceType::const_iterator itVV; for (itVV = _structureVector.begin(); itVV != _structureVector.end(); ++itVV) { count += (int)(*itVV).size(); } return count; } IDType Structure::getUID() const { return _strUID; } void Structure::setUID(const IDType& aUID) { _strUID = aUID; } void Structure::setLabel(const StructureLabel& aLabel) { _label = aLabel; } StructureLabel Structure::getLabel() const { return _label; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbStructure.h b/code/core/rttbStructure.h index 09887cc..4746c98 100644 --- a/code/core/rttbStructure.h +++ b/code/core/rttbStructure.h @@ -1,114 +1,107 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #ifndef __STRUCTURE_H #define __STRUCTURE_H #include #include #include "rttbBaseType.h" #include "rttbCommon.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class Structure @brief This is a class representing a RT Structure */ class RTTBCore_EXPORT Structure { public: rttbClassMacroNoParent(Structure); private: /*! @brief WorldCoordinate3D in mm */ PolygonSequenceType _structureVector; /*! @brief Contour Geometric Type using DICOM-RT definition (3006,0042). * POINT: indicates that the contour is a single point, defining a specific location of significance. * OPEN_PLANAR: indicates that the last vertex shall not be connected to the first point, and that all points * in Contour Data (3006,0050) shall be coplanar. * OPEN_NONPLANAR: indicates that the last vertex shall not be connected to the first point, and that the points * in Contour Data(3006,0050) may be non-coplanar. * CLOSED_PLANAR: indicates that the last point shall be connected to the first point, where the first point is * not repeated in the Contour Data. All points in Contour Data (3006,0050) shall be coplanar. */ std::vector _contourGeometricTypeVector; /*! @brief Structure UID*/ IDType _strUID; /*! @brief Structure Label*/ StructureLabel _label; public: /*! @brief Structure Standard Constructor uid will be randomly generated using boost::uuid library at first. To change the uid using setUID(). */ Structure(); /*! @brief Structure Constructor uid will be randomly generated using boost::uuid library at first. To change the uid using setUID(). */ Structure(PolygonSequenceType strVector); Structure(const Structure& copy); ~Structure(); const PolygonSequenceType& getStructureVector() const; /*! @brief Get the number of end points (points that define the polygon) of all contours of the structure. */ int getNumberOfEndpoints() const; IDType getUID() const; void setUID(const IDType& aUID); void setLabel(const StructureLabel& aLabel); StructureLabel getLabel() const; }; }//end namespace core }//end namespace rttb #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbStructureSet.cpp b/code/core/rttbStructureSet.cpp index 81624be..10366cd 100644 --- a/code/core/rttbStructureSet.cpp +++ b/code/core/rttbStructureSet.cpp @@ -1,84 +1,78 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include #include "rttbStructureSet.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { StructureSet::StructureSet(const std::vector& aStructureVector, IDType aPatientUID, IDType aUID) { _structureSetVector = aStructureVector; _patientUID = aPatientUID; _UID = aUID; if (_UID == "") { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _UID = ss.str(); } } Structure::Pointer StructureSet::getStructure(size_t aStructureNo) const { auto size = this->getNumberOfStructures(); if (aStructureNo >= size) { std::stringstream sstr; sstr << "aStructureNo must be between 0 and " << size; throw InvalidParameterException(sstr.str()); } return _structureSetVector.at(aStructureNo); } StructureSet::NumberOfStructuresType StructureSet::getNumberOfStructures() const { return _structureSetVector.size(); } IDType StructureSet::getUID() const { return _UID; } IDType StructureSet::getPatientUID() const { return _patientUID; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbStructureSet.h b/code/core/rttbStructureSet.h index d43cae0..ff03a22 100644 --- a/code/core/rttbStructureSet.h +++ b/code/core/rttbStructureSet.h @@ -1,93 +1,87 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __STRUCTURE_SET_H #define __STRUCTURE_SET_H #include #include "rttbBaseType.h" #include "rttbCommon.h" #include "rttbStructure.h" #include "RTTBCoreExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class StructureSet @brief This is an class representing a structure set, which can be used to generate masks. */ class RTTBCore_EXPORT StructureSet { public: rttbClassMacroNoParent(StructureSet); using NumberOfStructuresType = size_t; protected: std::vector _structureSetVector; IDType _UID; IDType _patientUID; public: virtual ~StructureSet() = default; /*! @brief Constructor @param aPatientUID the patient UID. @param aUID the structure set UID. If it is empty, it will be calculated in the constructor */ StructureSet(const std::vector& aStructureVector, IDType aPatientUID = "", IDType aUID = ""); /*! @brief Get the Structure with the index aStructureNo @return Return Structure pointer. @exception InvalidParameterException Thrown if structureNo not between 0 and number of structures of structureSet. */ Structure::Pointer getStructure(size_t aStructureNo) const; /*! @brief Get the number of structures @return Return the number of structures. */ NumberOfStructuresType getNumberOfStructures() const; virtual IDType getUID() const; virtual IDType getPatientUID() const; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/core/rttbStructureSetGeneratorInterface.h b/code/core/rttbStructureSetGeneratorInterface.h index 0c018a3..57ef737 100644 --- a/code/core/rttbStructureSetGeneratorInterface.h +++ b/code/core/rttbStructureSetGeneratorInterface.h @@ -1,94 +1,89 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __STRUCTURE_SET_GENERATOR_INTERFACE_H #define __STRUCTURE_SET_GENERATOR_INTERFACE_H #include #include "rttbStructureSet.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace core { /*! @class StructureSetGeneratorInterface @brief Interface for all structure set generating classes */ class StructureSetGeneratorInterface { public: rttbClassMacroNoParent(StructureSetGeneratorInterface); private: StructureSetGeneratorInterface(const StructureSetGeneratorInterface&) = delete; //not implemented on purpose -> non-copyable StructureSetGeneratorInterface& operator=(const StructureSetGeneratorInterface&) = delete;//not implemented on purpose -> non-copyable protected: StructureSetGeneratorInterface() = default; virtual ~StructureSetGeneratorInterface() = default; private: bool _activeFilter{false}; std::string _filterRegEx; public: void setStructureLabelFilterActive(bool active) { _activeFilter = active; }; bool getStructureLabelFilterActive() const { return _activeFilter; }; void setFilterRegEx(const std::string& filter) { _filterRegEx = filter; }; std::string getFilterRegEx() const { return _filterRegEx; }; /*! @brief Generate StructureSet @return Return shared pointer of StructureSet. */ virtual StructureSet::Pointer generateStructureSet() = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/indices/rttbConformalIndex.cpp b/code/indices/rttbConformalIndex.cpp index d373653..a474ef2 100644 --- a/code/indices/rttbConformalIndex.cpp +++ b/code/indices/rttbConformalIndex.cpp @@ -1,126 +1,120 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbConformalIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace indices { ConformalIndex::ConformalIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference) : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool ConformalIndex::calcIndex() { VolumeType TV = _dvhSet->getTargetVolume(0); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (TV != 0 && Vref != 0) { _value = (_dvhSet->getTargetVolume(_doseReference) / TV) * (_dvhSet->getTargetVolume(_doseReference) / Vref); std::vector dvhHTSet = this->_dvhSet->getHealthyTissueSet(); std::vector::iterator it; for (it = dvhHTSet.begin(); it != dvhHTSet.end(); ++it) { core::DVH dvh = *(it); VolumeType HT = dvh.getVx(0); if (HT != 0) { _value *= (1 - dvh.getVx(this->_doseReference) / HT); } } } else if (TV == 0) { throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); } else { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } return true; } IndexValueType ConformalIndex::getValueAt(core::DVHSet::IndexType tvIndex) { std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (tvIndex >= dvhTVSet.size()) { rttbExceptionMacro(core::InvalidParameterException, << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } else { core::DVH dvh = dvhTVSet.at(tvIndex); VolumeType TV = dvh.getVx(0); if (TV == 0) { throw core::InvalidParameterException("DVH invalid: Volume of tvIndex should not be 0!"); } else if (Vref == 0) { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } double value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th target volume value = value * dvh.getVx(_doseReference) / Vref; //conformation number std::vector dvhHTSet = this->_dvhSet->getHealthyTissueSet(); std::vector::iterator it; for (it = dvhHTSet.begin(); it != dvhHTSet.end(); ++it) { dvh = *(it); VolumeType HT = dvh.getVx(0); if (HT != 0) { value *= (1 - dvh.getVx(this->_doseReference) / HT); } } return value; } } }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbConformalIndex.h b/code/indices/rttbConformalIndex.h index 0a2ec27..9b04300 100644 --- a/code/indices/rttbConformalIndex.h +++ b/code/indices/rttbConformalIndex.h @@ -1,70 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __CONFORMAL_INDEX_H #define __CONFORMAL_INDEX_H - #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class ConformalIndex @brief This class representing a ConformalIndex Object. @details Conformal Index \f$(COIN)= Conformation Number(CN)* (1-Vref,0/Vnt,0)*(1-Vref,1/Vnt,1)... i\f$, i: i-th critiacal organ Conformation Number \f$(CN)= \frac{TVref}{TV} * \frac{TVref}{Vref}\f$ @ingroup indices */ class RTTBIndices_EXPORT ConformalIndex : public DvhBasedDoseIndex { protected: /*! @brief Calculate conformal index @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid */ bool calcIndex() override; public: /*! @brief Constructor */ ConformalIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference); /*! @brief Dose index calculation for tvIndex-th treated volume @param tvIndex index in the DVH in the current set of tv-DVHs @return Return index value @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) override; }; } } #endif diff --git a/code/indices/rttbConformationNumber.cpp b/code/indices/rttbConformationNumber.cpp index 5cc6e40..d034a23 100644 --- a/code/indices/rttbConformationNumber.cpp +++ b/code/indices/rttbConformationNumber.cpp @@ -1,97 +1,91 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbConformationNumber.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace indices { ConformationNumber::ConformationNumber(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference) : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool ConformationNumber::calcIndex() { VolumeType TV = _dvhSet->getTargetVolume(0); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (TV != 0 && Vref != 0) { _value = (_dvhSet->getTargetVolume(_doseReference) / TV) * (_dvhSet->getTargetVolume(_doseReference) / Vref); } else if (TV == 0) { throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); } else { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } return true; } IndexValueType ConformationNumber::getValueAt(core::DVHSet::IndexType tvIndex) { std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (tvIndex >= dvhTVSet.size()) { rttbExceptionMacro(core::InvalidParameterException, << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } else { core::DVH dvh = dvhTVSet.at(tvIndex); VolumeType TV = dvh.getVx(0); if (TV == 0) { throw core::InvalidParameterException("DVH invalid: Volume of tvIndex should not be 0!"); } else if (Vref == 0) { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } IndexValueType value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th target volume value = value * dvh.getVx(_doseReference) / Vref; return value; } } }//end namespace indices }//end namespace rttb \ No newline at end of file diff --git a/code/indices/rttbConformationNumber.h b/code/indices/rttbConformationNumber.h index ad6b10e..e9d9fdf 100644 --- a/code/indices/rttbConformationNumber.h +++ b/code/indices/rttbConformationNumber.h @@ -1,70 +1,64 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __CONFORMATION_NUMBER_H #define __CONFORMATION_NUMBER_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class ConformationNumber @brief This class representing a ConformationNumber Object. @details Conformation Number \f$(CN)= (TVref/TV) * (TVref/Vref)\f$ @ingroup indices */ class RTTBIndices_EXPORT ConformationNumber : public DvhBasedDoseIndex { protected: /*! @brief Calculate conformation number @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid */ bool calcIndex() override; public: /*! @brief Constructor */ ConformationNumber(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference); /*! @brief Dose index calculation for tvIndex-th treated volume @param tvIndex index in the DVH in the current set of tv-DVHs @return Return index value @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) override; }; } } #endif diff --git a/code/indices/rttbConformityIndex.cpp b/code/indices/rttbConformityIndex.cpp index 4fd6bf3..5353a18 100644 --- a/code/indices/rttbConformityIndex.cpp +++ b/code/indices/rttbConformityIndex.cpp @@ -1,96 +1,90 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbConformityIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace indices { ConformityIndex::ConformityIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference) : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool ConformityIndex::calcIndex() { VolumeType TV = _dvhSet->getTargetVolume(0); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (TV != 0 && Vref != 0) { _value = (_dvhSet->getTargetVolume(this->_doseReference) / TV) * (1 - _dvhSet->getHealthyTissueVolume(_doseReference) / Vref); } else if (TV == 0) { throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); } else { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } return true; } IndexValueType ConformityIndex::getValueAt(core::DVHSet::IndexType tvIndex) { std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); if (tvIndex >= dvhTVSet.size()) { rttbExceptionMacro(core::InvalidParameterException, << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } else { core::DVH dvh = dvhTVSet.at(tvIndex); VolumeType TV = dvh.getVx(0); if (TV == 0) { throw core::InvalidParameterException("DVH invalid: Volume of tvIndex should not be 0!"); } else if (Vref == 0) { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } double value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th treated volume value = value * (1 - _dvhSet->getHealthyTissueVolume(_doseReference) / Vref); return value; } } }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbConformityIndex.h b/code/indices/rttbConformityIndex.h index 3de3557..83ab5d2 100644 --- a/code/indices/rttbConformityIndex.h +++ b/code/indices/rttbConformityIndex.h @@ -1,69 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __CONFORMITY_INDEX_H #define __CONFORMITY_INDEX_H - #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class ConformityIndex @brief This class representing a ConformityIndex Object. @details: Conformity Index (CI): \f$CI(D)=IFtv(D)*(1-IFht(D))\f$, D:reference dose, IFtv(D): the irradiation factor of the PTV, defined as the fraction of the PTV receiving a dose higher than D IFht(D): the irradiation factor of healthy tissue, defined as the radio of the volume of tissue outside the PTV receiving a dose greater than D to the volume of isodose D @ingroup indices */ class RTTBIndices_EXPORT ConformityIndex : public DvhBasedDoseIndex { protected: /*! @brief Calculate Conformity index @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid */ bool calcIndex() override; public: /*! @brief Constructor */ ConformityIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference); /*! @brief Dose index calculation for tvIndex-th treated volume @param tvIndex index in the DVH in the current set of tv-DVHs @return Return index value @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) override; }; } } #endif diff --git a/code/indices/rttbCoverageIndex.cpp b/code/indices/rttbCoverageIndex.cpp index 6b5606d..93bec42 100644 --- a/code/indices/rttbCoverageIndex.cpp +++ b/code/indices/rttbCoverageIndex.cpp @@ -1,79 +1,73 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbCoverageIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace indices { CoverageIndex::CoverageIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference) : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool CoverageIndex::calcIndex() { VolumeType TV = _dvhSet->getTargetVolume(0); if (TV != 0) { _value = _dvhSet->getTargetVolume(this->_doseReference) / TV; } else { throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); } return true; } IndexValueType CoverageIndex::getValueAt(core::DVHSet::IndexType tvIndex) { std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); if (tvIndex >= dvhTVSet.size()) { rttbExceptionMacro(core::InvalidParameterException, << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } core::DVH dvh = dvhTVSet.at(tvIndex); VolumeType TV = dvh.getVx(0); if (TV == 0) { throw core::InvalidParameterException("DVH invalid: Volume of tvIndex should not be 0!"); } IndexValueType value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th treated volume return value; } }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbCoverageIndex.h b/code/indices/rttbCoverageIndex.h index 7040b39..fc00958 100644 --- a/code/indices/rttbCoverageIndex.h +++ b/code/indices/rttbCoverageIndex.h @@ -1,67 +1,62 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __COVERAGE_INDEX_H #define __COVERAGE_INDEX_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "rttbDVHSet.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class CoverageIndex @brief This class representing a CoverageIndex Object. @details Coverage Index fraction of the target volume receiving a dose >= the reference dose @ingroup indices */ class RTTBIndices_EXPORT CoverageIndex : public DvhBasedDoseIndex { protected: /*! @brief Calculate conformation number @exception InvalidParameterException Thrown if dvhSet invalid */ bool calcIndex() override; public: /*! @brief Constructor */ CoverageIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference); /*! @brief Dose index calculation for tvIndex-th treated volume * @param tvIndex: index in the vector of DVH TV * @return Return index value @exception InvalidParameterException Thrown if tvIndex invalid */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) override; }; } } #endif diff --git a/code/indices/rttbDoseIndex.cpp b/code/indices/rttbDoseIndex.cpp index 3b512cd..309e8da 100644 --- a/code/indices/rttbDoseIndex.cpp +++ b/code/indices/rttbDoseIndex.cpp @@ -1,81 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDoseIndex.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace indices { DoseIndex::DoseIndex(DoseTypeGy aDoseReference) : _doseReference(aDoseReference), _initSuccess(false) {} DoseIndex::~DoseIndex()= default; bool DoseIndex::init() { if (!(this->checkInputs())) { throw core::InvalidParameterException("Check inputs failed: invalid parameters! "); } if (this->calcIndex()) { _initSuccess = true; } else { throw core::InvalidParameterException("Index calculation failed! "); } return _initSuccess; } void DoseIndex::setDoseReference(DoseTypeGy aDoseReference) { _doseReference = aDoseReference; _initSuccess = false; init(); } DoseTypeGy DoseIndex::getDoseReference() const { return _doseReference; } IndexValueType DoseIndex::getValue() const { if (_initSuccess) { return _value; } else { throw core::Exception("DoseIndex init error: init() must be called first!"); } } } } diff --git a/code/indices/rttbDoseIndex.h b/code/indices/rttbDoseIndex.h index 6d5aa40..61b4ea6 100644 --- a/code/indices/rttbDoseIndex.h +++ b/code/indices/rttbDoseIndex.h @@ -1,89 +1,83 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_INDEX_H #define __DOSE_INDEX_H - #include "rttbBaseType.h" #include "rttbDVHSet.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class DoseIndex @brief This is the interface for dose/plan comparison indices. @ingroup indices */ class RTTBIndices_EXPORT DoseIndex { protected: IndexValueType _value; DoseTypeGy _doseReference; /*! @brief If init() successful*/ bool _initSuccess; /*! @brief Initialize the calculation. It should be called in constructor or if any parameter of the calcualtion is changed. @return Return true if successfully @exception InvalidParameterException thrown if any input is invalid or index calculation failed */ bool init(); /*! @brief Dose index calculation */ virtual bool calcIndex() = 0; /*! @brief Check all inputs for the index calculation*/ virtual bool checkInputs() = 0; public: /*! @brief Constructor with the referece dose*/ DoseIndex(DoseTypeGy aDoseReference); virtual ~DoseIndex(); /*! @brief Set the reference dose */ void setDoseReference(DoseTypeGy aDoseReference); /*! @brief Get the reference dose */ DoseTypeGy getDoseReference() const; /*! @brief Get the value of dose/plan comparison index @return Return the value of this index @exception Exception Thrown if the class was not initialized previously. */ IndexValueType getValue() const; /*! @brief Get the value of dose/plan comparison index for a treated volume with the index in the DVH treated volume set @param tvIndex index in the DVH in the current set of DVH subset for target volume: use DVHSet.getTargetVolumeSet() */ virtual IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) = 0; }; } } #endif diff --git a/code/indices/rttbDvhBasedDoseIndex.cpp b/code/indices/rttbDvhBasedDoseIndex.cpp index b89537b..e3919c8 100644 --- a/code/indices/rttbDvhBasedDoseIndex.cpp +++ b/code/indices/rttbDvhBasedDoseIndex.cpp @@ -1,50 +1,43 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDvhBasedDoseIndex.h" - namespace rttb { namespace indices { DvhBasedDoseIndex::DvhBasedDoseIndex(core::DVHSet::Pointer aDVHSet, DoseTypeGy aDoseReference) : DoseIndex(aDoseReference), _dvhSet(aDVHSet) { } bool DvhBasedDoseIndex::checkInputs() { if (!_dvhSet) { return false; } else { return true; } } } } diff --git a/code/indices/rttbDvhBasedDoseIndex.h b/code/indices/rttbDvhBasedDoseIndex.h index b1f9458..2929e17 100644 --- a/code/indices/rttbDvhBasedDoseIndex.h +++ b/code/indices/rttbDvhBasedDoseIndex.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_BASED_DOSE_INDEX_H #define __DVH_BASED_DOSE_INDEX_H - #include "rttbBaseType.h" #include "rttbDVHSet.h" #include "rttbDoseIndex.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class DvhBasedDoseIndex @brief This is the interface for dose/plan comparison indices calculated by DVh set of the dose. */ class RTTBIndices_EXPORT DvhBasedDoseIndex : public DoseIndex { protected: core::DVHSet::Pointer _dvhSet; /*! @brief Check inputs*/ bool checkInputs() override; public: /*! @brief Constructor*/ DvhBasedDoseIndex(core::DVHSet::Pointer aDVHSet, DoseTypeGy aDoseReference); }; } } #endif diff --git a/code/indices/rttbHomogeneityIndex.cpp b/code/indices/rttbHomogeneityIndex.cpp index 7897871..408e6c6 100644 --- a/code/indices/rttbHomogeneityIndex.cpp +++ b/code/indices/rttbHomogeneityIndex.cpp @@ -1,103 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "rttbHomogeneityIndex.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace indices { HomogeneityIndex::HomogeneityIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference) : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool HomogeneityIndex::calcIndex() { double max = 0; double min = std::numeric_limits::max(); std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); std::vector::iterator it; for (it = dvhTVSet.begin(); it != dvhTVSet.end(); ++it) { core::DVH dvh = *(it); if (it == dvhTVSet.begin()) { min = dvh.getMinimum(); } if (dvh.getMaximum() > max) { max = dvh.getMaximum(); } if (dvh.getMinimum() < min) { min = dvh.getMinimum(); } } if (this->getDoseReference() != 0) { _value = (max - min) / this->getDoseReference(); } else { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } return true; } IndexValueType HomogeneityIndex::getValueAt(core::DVHSet::IndexType tvIndex) { std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); if (tvIndex >= dvhTVSet.size()) { rttbExceptionMacro(core::InvalidParameterException, << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } core::DVH dvh = dvhTVSet.at(tvIndex); if (this->getDoseReference() <= 0) { rttbExceptionMacro(core::InvalidParameterException, << "Reference dose " << this->getDoseReference() << " invalid: Volume of reference dose should not be 0!"); } return (dvh.getMaximum() - dvh.getMinimum()) / this->getDoseReference(); } }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbHomogeneityIndex.h b/code/indices/rttbHomogeneityIndex.h index 568326a..ba0d74b 100644 --- a/code/indices/rttbHomogeneityIndex.h +++ b/code/indices/rttbHomogeneityIndex.h @@ -1,65 +1,60 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __HOMOGENEITY_INDEX_H #define __HOMOGENEITY_INDEX_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "RTTBIndicesExports.h" namespace rttb { namespace indices { /*! @class HomogeneityIndex @brief This class representing a HomogeneityIndex Object. @details Homogeneity Index \f$(HI) = \frac{D_{max}(PTV)-D_{min}(PTV)}{D_{ref}}\f$ @ingroup indices */ class RTTBIndices_EXPORT HomogeneityIndex : public DvhBasedDoseIndex { protected: /*! @brief Calculate Conformity index @exception InvalidParameterException Thrown if aDoseReference invalid */ bool calcIndex() override; public: /*! @brief Constructor */ HomogeneityIndex(core::DVHSet::Pointer dvhSet, DoseTypeGy aDoseReference); /*! @brief Dose index calculation for tvIndex-th treated volume @param tvIndex index in the DVH in the current set of tv-DVHs @return Return index value @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) override; }; } } #endif diff --git a/code/interpolation/ITKTransformation/rttbITKTransformation.cpp b/code/interpolation/ITKTransformation/rttbITKTransformation.cpp index a5e442e..8d55f58 100644 --- a/code/interpolation/ITKTransformation/rttbITKTransformation.cpp +++ b/code/interpolation/ITKTransformation/rttbITKTransformation.cpp @@ -1,91 +1,85 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbITKTransformation.h" #include "rttbNullPointerException.h" namespace rttb { namespace interpolation { ITKTransformation::ITKTransformation(const Transform3D3DType* aTransformation): _pTransformation(aTransformation) { //handle null pointer if (aTransformation == nullptr) { throw core::NullPointerException("Pointer to registration is nullptr."); } } void ITKTransformation::convert(const WorldCoordinate3D& aWorldCoordinate, InputPointType& aInputPoint) const { assert(aWorldCoordinate.size() == 3); assert(aInputPoint.Length == 3); for (unsigned int i = 0; i < aInputPoint.Length; ++i) { aInputPoint[i] = aWorldCoordinate[i]; } } void ITKTransformation::convert(const OutputPointType& aOutputPoint, WorldCoordinate3D& aWorldCoordinate) const { assert(aWorldCoordinate.size() == 3); assert(aOutputPoint.Length == 3); for (unsigned int i = 0; i < aOutputPoint.Length; ++i) { aWorldCoordinate[i] = aOutputPoint[i]; } } bool ITKTransformation::transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const { InputPointType aTargetPoint; OutputPointType aMovingPoint; convert(worldCoordinateTarget, aTargetPoint); aMovingPoint = _pTransformation->TransformPoint(aTargetPoint); convert(aMovingPoint, worldCoordinateMoving); //TransformPoint has no return value... return true; } bool ITKTransformation::transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const { OutputPointType aTargetPoint; InputPointType aMovingPoint; convert(worldCoordinateMoving, aMovingPoint); aTargetPoint = _pTransformation->TransformPoint(aMovingPoint); convert(aTargetPoint, worldCoordinateTarget); //TransformPoint has no return value... return true; } } } diff --git a/code/interpolation/ITKTransformation/rttbITKTransformation.h b/code/interpolation/ITKTransformation/rttbITKTransformation.h index 830fda5..3f907d3 100644 --- a/code/interpolation/ITKTransformation/rttbITKTransformation.h +++ b/code/interpolation/ITKTransformation/rttbITKTransformation.h @@ -1,81 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_MAPPABLE_DOSE_ACCESSOR_H #define __ITK_MAPPABLE_DOSE_ACCESSOR_H #include #include "itkTransform.h" #include "rttbTransformationInterface.h" #include "RTTBInterpolationITKTransformationExports.h" namespace rttb { namespace interpolation { /*! @class ITKTransformation @brief This class can deal with dose information that has to be transformed into another geometry than the original dose image (transformation specified by ITK transformation object). */ class RTTBInterpolationITKTransformation_EXPORT ITKTransformation : public TransformationInterface { public: static const unsigned int InputDimension3D = 3; static const unsigned int OutputDimension3D = 3; using TransformScalarType = double; typedef itk::Transform Transform3D3DType; using InputPointType = Transform3D3DType::InputPointType; using OutputPointType = Transform3D3DType::OutputPointType; private: //! Has to be a Pointer type because of inheritance issues with itkSmartPointer (that doesn't recognize the inheritance) const Transform3D3DType* _pTransformation; protected: void convert(const WorldCoordinate3D& aWorldCoordinate, InputPointType& aInputPoint) const; void convert(const OutputPointType& aOutputPoint, WorldCoordinate3D& aWorldCoordinate) const; public: /*! @brief Constructor. @param aTransformation transformation in ITK format. @sa MappableDoseAccessorBase @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is nullptr @exception core::PaddingException if the transformation is undefined and if _acceptPadding==false */ ITKTransformation(const Transform3D3DType* aTransformation); ~ITKTransformation() override = default; /*! @brief performs a transformation targetImage --> movingImage */ bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const override; /*! @brief performs a transformation movingImage --> targetImage */ bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const override; }; } } #endif diff --git a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp index 09f5f65..6f72a3f 100644 --- a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp +++ b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp @@ -1,88 +1,82 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbMatchPointTransformation.h" #include "rttbNullPointerException.h" namespace rttb { namespace interpolation { MatchPointTransformation::MatchPointTransformation( const Registration3D3DType* aRegistration): _pRegistration(aRegistration) { //handle null pointers if (aRegistration == nullptr) { throw core::NullPointerException("Pointer to registration is nullptr."); } } void MatchPointTransformation::convert(const WorldCoordinate3D& aWorldCoordinate, TargetPointType& aTargetPoint) const { assert(aWorldCoordinate.size() == 3); assert(aTargetPoint.Length == 3); for (unsigned int i = 0; i < aTargetPoint.Length; ++i) { aTargetPoint[i] = aWorldCoordinate[i]; } } void MatchPointTransformation::convert(const MovingPointType& aMovingPoint, WorldCoordinate3D& aWorldCoordinate) const { assert(aWorldCoordinate.size() == 3); assert(aMovingPoint.Length == 3); for (unsigned int i = 0; i < aMovingPoint.Length; ++i) { aWorldCoordinate[i] = aMovingPoint[i]; } } bool MatchPointTransformation::transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const { TargetPointType aTargetPoint; MovingPointType aMovingPoint; convert(worldCoordinateTarget, aTargetPoint); bool ok = _pRegistration->mapPointInverse(aTargetPoint, aMovingPoint); convert(aMovingPoint, worldCoordinateMoving); return ok; } bool MatchPointTransformation::transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const { TargetPointType aTargetPoint; MovingPointType aMovingPoint; convert(worldCoordinateMoving, aMovingPoint); bool ok = _pRegistration->mapPoint(aMovingPoint, aTargetPoint); convert(aTargetPoint, worldCoordinateTarget); return ok; } } } diff --git a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h index 07a480f..b255571 100644 --- a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h +++ b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h @@ -1,80 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MATCHPOINT_TRANSFORMATION_H #define __MATCHPOINT_TRANSFORMATION_H #include "mapRegistration.h" #include "rttbTransformationInterface.h" #include "RTTBInterpolationMatchPointTransformationExports.h" namespace rttb { namespace interpolation { /*! @class MatchPointTransformation @brief This class can deal with dose information that has to be transformed into another geometry than the original dose image (transformation specified by MatchPoint registration object). @ingroup interpolation */ class RTTBInterpolationMatchPointTransformation_EXPORT MatchPointTransformation : public TransformationInterface { public: static const unsigned int TargetDimension3D = 3; static const unsigned int MovingDimension3D = 3; typedef map::core::Registration Registration3D3DType; typedef map::core::Registration::MovingPointType MovingPointType; typedef map::core::Registration::TargetPointType TargetPointType; /*! @brief Constructor. @param aRegistration registration given in MatchPoint format (note the use of pointer since itkSmartPointer does not support inheritance) @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is nullptr @exception core::PaddingException if the transformation is undefined and if _acceptPadding==false */ MatchPointTransformation(const Registration3D3DType* aRegistration); ~MatchPointTransformation() override = default; /*! @brief performs a transformation targetImage --> movingImage */ bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const override; /*! @brief performs a transformation movingImage --> targetImage */ bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const override; protected: void convert(const WorldCoordinate3D& aWorldCoordinate, TargetPointType& aTargetPoint) const; void convert(const MovingPointType& aMovingPoint, WorldCoordinate3D& aWorldCoordinate) const; private: //! Has to be a Pointer type because of inheritance issues with itkSmartPointer (that doesn't recognize the inheritance) const Registration3D3DType* _pRegistration; }; } } #endif diff --git a/code/interpolation/rttbInterpolationBase.cpp b/code/interpolation/rttbInterpolationBase.cpp index 0fd1863..282bb3f 100644 --- a/code/interpolation/rttbInterpolationBase.cpp +++ b/code/interpolation/rttbInterpolationBase.cpp @@ -1,197 +1,191 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbInterpolationBase.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "rttbMappingOutsideOfImageException.h" namespace rttb { namespace interpolation { void InterpolationBase::setAccessorPointer(core::AccessorInterface::ConstPointer originalData) { if (originalData != nullptr) { _spOriginalData = originalData; } else { throw core::NullPointerException("originalDose is nullptr!"); } }; void InterpolationBase::getNeighborhoodVoxelValues( const WorldCoordinate3D& aWorldCoordinate, unsigned int neighborhood, std::array& target, boost::shared_ptr values) const { if (_spOriginalData == nullptr) { throw core::NullPointerException("originalDose is nullptr!"); } //Determine target (abs(desired worldCoordinate- corner pixel world coordinate/pixel spacing) and values of corner pixels (from originalDose) VoxelGridIndex3D aIndex; if (_spOriginalData->getGeometricInfo().worldCoordinateToIndex(aWorldCoordinate, aIndex)) { //determine just the nearest voxel to the world coordinate if (neighborhood == 0) { values[0] = _spOriginalData->getValueAt(aIndex); } //determine the 8 voxels around the world coordinate else if (neighborhood == 8) { std::list cornerPoints; WorldCoordinate3D theNextVoxel; _spOriginalData->getGeometricInfo().indexToWorldCoordinate(aIndex, theNextVoxel); SpacingVectorType3D pixelSpacing = (_spOriginalData->getGeometricInfo()).getSpacing(); VoxelGridIndex3D leftTopFrontCoordinate; //find the voxel with the smallest coordinate values in each dimension. This defines the standard cube for (unsigned int i = 0; i < 3; i++) { if (aWorldCoordinate[i] < theNextVoxel[i]) { if (aIndex[i] > 0) { leftTopFrontCoordinate[i] = aIndex[i] - 1; target[i] = (aWorldCoordinate[i] - (theNextVoxel[i] - pixelSpacing[i])) / pixelSpacing[i]; } //@todo: see T22315 else { leftTopFrontCoordinate[i] = aIndex[i]; target[i] = (aWorldCoordinate[i] - (theNextVoxel[i] - pixelSpacing[i])) / pixelSpacing[i]; } } else { leftTopFrontCoordinate[i] = aIndex[i]; target[i] = (aWorldCoordinate[i] - theNextVoxel[i]) / pixelSpacing[i]; } } for (unsigned int zIncr = 0; zIncr < 2; zIncr++) { for (unsigned int yIncr = 0; yIncr < 2; yIncr++) { for (unsigned int xIncr = 0; xIncr < 2; xIncr++) { cornerPoints.emplace_back(leftTopFrontCoordinate[0] + xIncr, leftTopFrontCoordinate[1] + yIncr, leftTopFrontCoordinate[2] + zIncr); } } } //target range has to be always [0,1] for (unsigned int i = 0; i < 3; i++) { assert(target[i] >= 0.0 && target[i] <= 1.0); } unsigned int count = 0; //now just get the values of all (dose) voxels and store them in values for (auto cornerPointsIterator = cornerPoints.begin(); cornerPointsIterator != cornerPoints.end(); ++cornerPointsIterator, ++count) { if (_spOriginalData->getGeometricInfo().isInside(*cornerPointsIterator)) { values[count] = _spOriginalData->getValueAt(*cornerPointsIterator); } else { //outside value! boundary treatment values[count] = getNearestInsideVoxelValue(*cornerPointsIterator); } assert(values[count] != -1); } } else { throw core::InvalidParameterException("neighborhoods other than 0 and 8 not yet supported in Interpolation"); } } else { throw core::MappingOutsideOfImageException("Error in conversion from world coordinates to index"); } } DoseTypeGy InterpolationBase::getNearestInsideVoxelValue(const VoxelGridIndex3D& currentVoxelIndex) const { VoxelGridIndex3D voxelChangedXYZ[] = {currentVoxelIndex, currentVoxelIndex, currentVoxelIndex, currentVoxelIndex, currentVoxelIndex, currentVoxelIndex, currentVoxelIndex}; unsigned int runningIndex; //x,y,z for (runningIndex = 0; runningIndex < 3; ++runningIndex) { voxelChangedXYZ[runningIndex][runningIndex] -= 1; } //xy voxelChangedXYZ[runningIndex][0] -= 1; voxelChangedXYZ[runningIndex][1] -= 1; ++runningIndex; //xz voxelChangedXYZ[runningIndex][0] -= 1; voxelChangedXYZ[runningIndex][2] -= 1; ++runningIndex; //yz voxelChangedXYZ[runningIndex][1] -= 1; voxelChangedXYZ[runningIndex][2] -= 1; ++runningIndex; //xyz voxelChangedXYZ[runningIndex][0] -= 1; voxelChangedXYZ[runningIndex][1] -= 1; voxelChangedXYZ[runningIndex][2] -= 1; ++runningIndex; unsigned int replacementVoxelIndex = 0; while (replacementVoxelIndex < runningIndex) { if (_spOriginalData->getGeometricInfo().validIndex(voxelChangedXYZ[replacementVoxelIndex])) { return _spOriginalData->getValueAt(voxelChangedXYZ[replacementVoxelIndex]); } ++replacementVoxelIndex; } return -1; } }//end namespace core }//end namespace rttb diff --git a/code/interpolation/rttbInterpolationBase.h b/code/interpolation/rttbInterpolationBase.h index b007b8f..990f775 100644 --- a/code/interpolation/rttbInterpolationBase.h +++ b/code/interpolation/rttbInterpolationBase.h @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __INTERPOLATION_BASE_H #define __INTERPOLATION_BASE_H #include #include #include #include "rttbAccessorInterface.h" #include "RTTBInterpolationExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace interpolation { /*! @class InterpolationBase @brief Base class for interpolation. @ingroup interpolation */ class RTTBInterpolation_EXPORT InterpolationBase { public: rttbClassMacroNoParent(InterpolationBase) /*! @brief Constructor */ InterpolationBase() = default; /*! @brief Virtual destructor of base class */ virtual ~InterpolationBase() = default; /*! @brief Sets the AccessorPointer @pre originalData initialized @exception core::NullPointerException if originalData==nullptr */ void setAccessorPointer(core::AccessorInterface::ConstPointer originalData); /*! @brief Returns the interpolated value for the given world coordinate */ virtual DoseTypeGy getValue(const WorldCoordinate3D& aWorldCoordinate) const = 0; protected: rttb::core::AccessorInterface::ConstPointer _spOriginalData; /*! @brief determines voxels in a certain neighborhood of a physical based coordinate and converts in a standard cube with corner points [0 0 0], [1 0 0], [0 1 0], [1 1 0], [0 0 1], [1 0 1], [0 1 1], [1 1 1]. @param aWorldCoordinate the coordinate where to start @param neighborhood voxel around coordinate (currently only 0 and 8 implemented) @param target coordinates inside the standard cube with values [0 1] in each dimension. @param values dose values at all corner points of the standard cube. Is of type boost:shared_ptr[neighborhood] @pre target and values have to be correctly initialized (e.g. std::array target = {0.0, 0.0, 0.0}; boost::shared_ptr values(new DoseTypeGy[8]()); where 8 is neighborhood) @exception core::InvalidParameterException if neighborhood =! 0 && !=8 @exception core::MappingOutsideOfImageException if initial mapping of aWorldCoordinate is outside image @exception core::NullPointerException if dose is nullptr */ void getNeighborhoodVoxelValues(const WorldCoordinate3D& aWorldCoordinate, unsigned int neighborhood, std::array& target, boost::shared_ptr values) const; /*! @brief returns the nearest inside voxel value @pre the voxelGridIndex is outside the image and voxelGridIndex>image.size() for all dimensions. Also voxelGridIndex[]>=0 for all dimensions @note used for virtually expanding the image by one voxel as edge handling */ DoseTypeGy getNearestInsideVoxelValue(const VoxelGridIndex3D& currentVoxelIndex) const; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/interpolation/rttbLinearInterpolation.cpp b/code/interpolation/rttbLinearInterpolation.cpp index c2bb553..f399052 100644 --- a/code/interpolation/rttbLinearInterpolation.cpp +++ b/code/interpolation/rttbLinearInterpolation.cpp @@ -1,59 +1,53 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbLinearInterpolation.h" #include namespace rttb { namespace interpolation { DoseTypeGy LinearInterpolation::trilinear(std::array target, boost::shared_ptr values) const { //4 linear interpolation in x direction DoseTypeGy c_00 = values[0] * (1.0 - target[0]) + values[1] * target[0]; DoseTypeGy c_10 = values[2] * (1.0 - target[0]) + values[3] * target[0]; DoseTypeGy c_01 = values[4] * (1.0 - target[0]) + values[5] * target[0]; DoseTypeGy c_11 = values[6] * (1.0 - target[0]) + values[7] * target[0]; //combine result in y direction DoseTypeGy c_0 = c_00 * (1.0 - target[1]) + c_10 * target[1]; DoseTypeGy c_1 = c_01 * (1.0 - target[1]) + c_11 * target[1]; //finally incorporate z direction return (c_0 * (1.0 - target[2]) + c_1 * target[2]); } DoseTypeGy LinearInterpolation::getValue(const WorldCoordinate3D& aWorldCoordinate) const { //proper initialization of target and values std::array target = {0.0, 0.0, 0.0}; auto values = boost::make_shared(8); getNeighborhoodVoxelValues(aWorldCoordinate, 8, target, values); return trilinear(target, values); } } } diff --git a/code/interpolation/rttbLinearInterpolation.h b/code/interpolation/rttbLinearInterpolation.h index 5fdd399..f9c7865 100644 --- a/code/interpolation/rttbLinearInterpolation.h +++ b/code/interpolation/rttbLinearInterpolation.h @@ -1,62 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __LINEAR_INTERPOLATION_H #define __LINEAR_INTERPOLATION_H #include #include "rttbInterpolationBase.h" #include "RTTBInterpolationExports.h" namespace rttb { namespace interpolation { /*! @class LinearInterpolation @brief Linear interpolation. @ingroup interpolation */ class RTTBInterpolation_EXPORT LinearInterpolation : public InterpolationBase { public: /*! @brief Constructor */ LinearInterpolation() = default; /*! @brief Returns the interpolated value */ DoseTypeGy getValue(const WorldCoordinate3D& aWorldCoordinate) const override; private: /*! @brief Trilinar interpolation @sa InterpolationBase for details about target and values @note Source: http://en.wikipedia.org/wiki/Trilinear_interpolation */ DoseTypeGy trilinear(std::array target, boost::shared_ptr values) const; }; } } #endif diff --git a/code/interpolation/rttbMappableDoseAccessorInterface.h b/code/interpolation/rttbMappableDoseAccessorInterface.h index b691c8e..f62ba1b 100644 --- a/code/interpolation/rttbMappableDoseAccessorInterface.h +++ b/code/interpolation/rttbMappableDoseAccessorInterface.h @@ -1,100 +1,95 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __MAPPABLE_DOSE_ACCESSOR_BASE_H #define __MAPPABLE_DOSE_ACCESSOR_BASE_H #include #include "rttbDoseAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "rttbTransformationInterface.h" #include "rttbNullPointerException.h" namespace rttb { namespace interpolation { /*! @class MappableDoseAccessorInterface @brief Interface for dealing with dose information that has to be transformed into another geometry than the original dose image @details implementation of strategy is done by derived class (e.g. SimpleMappableDoseAccessor or RosuMappableDoseAccessor. Transformation is defined in TransformationInterface @ingroup interpolation */ class MappableDoseAccessorInterface: public core::DoseAccessorInterface { public: rttbClassMacro(MappableDoseAccessorInterface,core::DoseAccessorInterface) protected: core::DoseAccessorInterface::ConstPointer _spOriginalDoseDataMovingImage; TransformationInterface::Pointer _spTransformation; core::GeometricInfo _geoInfoTargetImage; bool _acceptPadding; DoseTypeGy _defaultOutsideValue; public: /*! @brief Constructor. @param geoInfoTargetImage target image geometry @param doseMovingImage dose of moving image @param aTransformation the transformation @param acceptPadding is mapping outside the image allowed @param defaultOutsideValue the default outside voxel value if accepptPadding=true @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is nullptr */ MappableDoseAccessorInterface(const core::GeometricInfo& geoInfoTargetImage, core::DoseAccessorInterface::ConstPointer doseMovingImage, const TransformationInterface::Pointer aTransformation, bool acceptPadding = true, DoseTypeGy defaultOutsideValue = 0.0): _spOriginalDoseDataMovingImage(doseMovingImage), _spTransformation(aTransformation), _geoInfoTargetImage(geoInfoTargetImage), _acceptPadding(acceptPadding), _defaultOutsideValue(defaultOutsideValue) { //handle null pointers if (doseMovingImage == nullptr || aTransformation == nullptr) { throw core::NullPointerException("Pointers to input accessors/transformation cannot be nullptr."); } } /*! @brief Virtual destructor of base class */ ~MappableDoseAccessorInterface() override = default; inline const core::GeometricInfo& getGeometricInfo() const override { return _geoInfoTargetImage; }; inline GridSizeType getGridSize() const override { return _geoInfoTargetImage.getNumberOfVoxels(); }; const IDType getUID() const override { return _spOriginalDoseDataMovingImage->getUID(); }; }; } } #endif diff --git a/code/interpolation/rttbNearestNeighborInterpolation.cpp b/code/interpolation/rttbNearestNeighborInterpolation.cpp index bc34750..6493de5 100644 --- a/code/interpolation/rttbNearestNeighborInterpolation.cpp +++ b/code/interpolation/rttbNearestNeighborInterpolation.cpp @@ -1,41 +1,35 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbNearestNeighborInterpolation.h" #include #include namespace rttb { namespace interpolation { DoseTypeGy NearestNeighborInterpolation::getValue(const WorldCoordinate3D& aWorldCoordinate) const { //proper initialization of target and values (although target is irrelevant in nearest neighbor case) std::array target = {{0.0, 0.0, 0.0}}; auto values = boost::make_shared(8); getNeighborhoodVoxelValues(aWorldCoordinate, 0, target, values); return values[0]; } } } diff --git a/code/interpolation/rttbNearestNeighborInterpolation.h b/code/interpolation/rttbNearestNeighborInterpolation.h index eb4ee74..168b8f7 100644 --- a/code/interpolation/rttbNearestNeighborInterpolation.h +++ b/code/interpolation/rttbNearestNeighborInterpolation.h @@ -1,53 +1,47 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __NEAREST_NEIGHBOR_INTERPOLATION_H #define __NEAREST_NEIGHBOR_INTERPOLATION_H #include "rttbInterpolationBase.h" #include "RTTBInterpolationExports.h" namespace rttb { namespace interpolation { /*! @class NearestNeighborInterpolation @brief Nearest Neighbor interpolation @ingroup interpolation */ class RTTBInterpolation_EXPORT NearestNeighborInterpolation : public InterpolationBase { public: /*! @brief Constructor */ NearestNeighborInterpolation() = default; /*! @brief Returns the interpolated value (the nearest voxel value given by _spOriginalData->getGeometricInfo().worldCoordinateToIndex()) */ DoseTypeGy getValue(const WorldCoordinate3D& aWorldCoordinate) const override; }; } } #endif diff --git a/code/interpolation/rttbRosuMappableDoseAccessor.h b/code/interpolation/rttbRosuMappableDoseAccessor.h index aaecd0d..a7ea314 100644 --- a/code/interpolation/rttbRosuMappableDoseAccessor.h +++ b/code/interpolation/rttbRosuMappableDoseAccessor.h @@ -1,80 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ROSU_MAPPABLE_DOSE_ACCESSOR_H #define __ROSU_MAPPABLE_DOSE_ACCESSOR_H #include #include "rttbBaseType.h" #include "rttbInterpolationBase.h" #include "rttbMappableDoseAccessorInterface.h" namespace rttb { namespace interpolation { class TransformationInterface; /*! @class RosuMappableDoseAccessor @brief Class for dose mapping based on interpolation described in the Rosu2005 paper @details implementation of the following paper: Rosu, M., Chetty, I. J., Balter, J. M., Kessler, M. L., McShan, D. L., & Ten Haken, R. K. (2005). Dose reconstruction in deforming lung anatomy: Dose grid size effects and clinical implications. Medical Physics, 32(8), 2487. @ingroup interpolation */ class RosuMappableDoseAccessor: public MappableDoseAccessorInterface { private: InterpolationBase::Pointer _spInterpolation; public: /*! @brief Constructor. Just hands values over to base class constructor. @note no interpolation as parameter since linear interpolation is fixed. @sa MappableDoseAccessorBase */ RosuMappableDoseAccessor(const core::GeometricInfo& geoInfoTargetImage, core::DoseAccessorInterface::ConstPointer doseMovingImage, const TransformationInterface::Pointer aTransformation, bool acceptPadding = true, DoseTypeGy defaultOutsideValue = 0.0); /*! @brief Virtual destructor. */ ~RosuMappableDoseAccessor() override = default; GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief Returns the dose for a given voxel grid index. The computation of the octant around the voxel is done and the interpolation is performed. @details Boundary treatment: if more than 6 subvoxels are outside: return _defaultOutsideValue. Otherwise: ignore the outside values. @return the dose or if (isOutside==true && _acceptPadding==true) then _defaultValue @exception core::MappingOutsideOfImageException if the point is mapped outside and if _acceptPadding==false, possibly returning _defaultValue) */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; private: /*! @brief returns the octant coordinates around a coordinate. @details i.e. coordinate is the center of a virtual voxel. Then, each side is divided into equal parts. The centers of the new subvoxels are then returned. @return a vector of the octant coordinates. */ std::vector getOctants(const WorldCoordinate3D& aCoordinate) const; }; } } #endif diff --git a/code/interpolation/rttbSimpleMappableDoseAccessor.h b/code/interpolation/rttbSimpleMappableDoseAccessor.h index 35f3b89..d152af2 100644 --- a/code/interpolation/rttbSimpleMappableDoseAccessor.h +++ b/code/interpolation/rttbSimpleMappableDoseAccessor.h @@ -1,76 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __SIMPLE_MAPPABLE_DOSE_ACCESSOR_H #define __SIMPLE_MAPPABLE_DOSE_ACCESSOR_H #include #include #include "rttbInterpolationBase.h" #include "rttbLinearInterpolation.h" #include "rttbTransformationInterface.h" #include "rttbMappableDoseAccessorInterface.h" #include "RTTBInterpolationExports.h" namespace rttb { namespace interpolation { /*! @class SimpleMappableDoseAccessor @brief Class for dose mapping based on simple trilinear interpolation @ingroup interpolation */ class RTTBInterpolation_EXPORT SimpleMappableDoseAccessor : public MappableDoseAccessorInterface { private: InterpolationBase::Pointer _spInterpolation; public: /*! @brief Constructor. Just hands values over to base class constructor. @param aInterpolation the used interpolation. @sa MappableDoseAccessorBase */ SimpleMappableDoseAccessor(const core::GeometricInfo& geoInfoTargetImage, core::DoseAccessorInterface::ConstPointer doseMovingImage, const TransformationInterface::Pointer aTransformation, const InterpolationBase::Pointer aInterpolation = ::boost::make_shared(), bool acceptPadding = true, DoseTypeGy defaultOutsideValue = 0.0); /*! @brief Virtual destructor of class */ ~SimpleMappableDoseAccessor() override = default; /*! @brief Returns the dose for a given voxel grid id. Plain trilinear interpolation is performed. @sa getDoseAt(const VoxelGridIndex3D& aIndex) */ GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief Returns the dose for a given voxel grid index. Plain trilinear interpolation is performed. @return the dose or if (isOutside==true && _acceptPadding==true) then _defaultValue @exception core::MappingOutsideOfImageException if the point is mapped outside and if _acceptPadding==false, possibly returning _defaultValue) */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; }; } } #endif diff --git a/code/interpolation/rttbTransformationInterface.h b/code/interpolation/rttbTransformationInterface.h index 407e52e..90e4d17 100644 --- a/code/interpolation/rttbTransformationInterface.h +++ b/code/interpolation/rttbTransformationInterface.h @@ -1,81 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __TRANSFORMATION_INTERFACE_H #define __TRANSFORMATION_INTERFACE_H #include #include "rttbBaseType.h" #include "RTTBInterpolationExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace interpolation { /*! @class TransformationInterface @brief Base class for transformation (in World coordinates). @ingroup interpolation */ class RTTBInterpolation_EXPORT TransformationInterface { public: rttbClassMacroNoParent(TransformationInterface) protected: /*! @brief Constructor */ TransformationInterface() = default; /*! @brief Virtual destructor of interface class */ virtual ~TransformationInterface() = default; public: /*! @brief performs a transformation targetImage --> movingImage */ virtual bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const = 0; /*! @brief performs a transformation movingImage --> targetImage */ virtual bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const = 0; private: TransformationInterface(const TransformationInterface&) = delete;//not implemented on purpose -> non-copyable TransformationInterface& operator=(const TransformationInterface&) = delete;//not implemented on purpose -> non-copyable }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/io/dicom/rttbDVHDicomFileReader.cpp b/code/io/dicom/rttbDVHDicomFileReader.cpp index 481a53f..fe0a5f1 100644 --- a/code/io/dicom/rttbDVHDicomFileReader.cpp +++ b/code/io/dicom/rttbDVHDicomFileReader.cpp @@ -1,51 +1,45 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDVHDicomFileReader.h" #include "rttbException.h" namespace rttb { namespace io { namespace dicom { DVHDicomFileReader::DVHDicomFileReader(FileNameString aFileName) { this->setFileName(aFileName); this->createDVH(); } void DVHDicomFileReader::setFileName(FileNameString aFileName) { _fileName = aFileName; } void DVHDicomFileReader::createDVH() { assert(false); throw rttb::core::Exception("DICOM DVH reader currently not implemented."); }; } } } diff --git a/code/io/dicom/rttbDVHDicomFileReader.h b/code/io/dicom/rttbDVHDicomFileReader.h index 5b004d9..15fb9e8 100644 --- a/code/io/dicom/rttbDVHDicomFileReader.h +++ b/code/io/dicom/rttbDVHDicomFileReader.h @@ -1,58 +1,53 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_DICOM_FILE_READER_H #define __DVH_DICOM_FILE_READER_H #include "rttbBaseType.h" #include "rttbDVHGeneratorInterface.h" namespace rttb { namespace io { namespace dicom { /*! @class DVHDicomFileReader @brief Read DVH data from a dicom file and create corresponding DVH object. */ class DVHDicomFileReader: public core::DVHGeneratorInterface { private: FileNameString _fileName; void createDVH(); public: /*! @brief DVHDicomFileReader Constructor @param aFileName the dicom dvh file name */ DVHDicomFileReader(FileNameString aFileName); /*! @brief Set the dicom dvh file name (triggers data import) @param aFileName the dicom dvh file name */ void setFileName(FileNameString aFileName); }; } } } #endif diff --git a/code/io/dicom/rttbDcmrtException.h b/code/io/dicom/rttbDcmrtException.h index 1707420..ecda6e8 100644 --- a/code/io/dicom/rttbDcmrtException.h +++ b/code/io/dicom/rttbDcmrtException.h @@ -1,49 +1,43 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DCMRT_EXCEPTION_H #define __DCMRT_EXCEPTION_H #include #include "rttbException.h" namespace rttb { namespace io { namespace dicom { /*! @class DcmrtException @brief This class represents a DcmrtException. Any dcmrt error will throw this exception. */ class DcmrtException: public core::Exception { public: DcmrtException(const std::string& aWhat): Exception(aWhat) {} }; } } } #endif diff --git a/code/io/dicom/rttbDicomDoseAccessor.cpp b/code/io/dicom/rttbDicomDoseAccessor.cpp index 8616ded..a018e77 100644 --- a/code/io/dicom/rttbDicomDoseAccessor.cpp +++ b/code/io/dicom/rttbDicomDoseAccessor.cpp @@ -1,293 +1,285 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "drtdose.h" #include #include #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" - - namespace rttb { namespace io { namespace dicom { DicomDoseAccessor::~DicomDoseAccessor() = default; DicomDoseAccessor::DicomDoseAccessor(DRTDoseIODPtr aDRTDoseIODP, DcmItemPtr aDcmDataset) { _dose = aDRTDoseIODP; _dataSet = aDcmDataset; OFString uid; _dose->getSeriesInstanceUID(uid); _doseUID = uid.c_str(); this->begin(); } bool DicomDoseAccessor::begin() { assembleGeometricInfo(); doseData.clear(); OFString doseGridScalingStr; this->_dose->getDoseGridScaling(doseGridScalingStr); try { _doseGridScaling = boost::lexical_cast(doseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } OFCondition status; unsigned long count; const Uint16* pixelData; status = _dataSet->findAndGetUint16Array(DcmTagKey(0x7fe0, 0x0010), pixelData, &count); if (status.good()) { for (unsigned int i = 0; i < static_cast(this->_geoInfo.getNumberOfVoxels()); i++) { this->doseData.push_back(pixelData[i]); } return true; } else { throw io::dicom::DcmrtException("Read Pixel Data (7FE0,0010) failed!"); } } void DicomDoseAccessor::assembleGeometricInfo() { Uint16 temp = 0; this->_dose->getColumns(temp); _geoInfo.setNumColumns(temp); temp = 0; this->_dose->getRows(temp); _geoInfo.setNumRows(temp); if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } OFString numberOfFramesStr; OFString imageOrientationRowX, imageOrientationRowY, imageOrientationRowZ; OFString imageOrientationColumnX, imageOrientationColumnY, imageOrientationColumnZ; WorldCoordinate3D imageOrientationRow; WorldCoordinate3D imageOrientationColumn; try { this->_dose->getNumberOfFrames(numberOfFramesStr); _geoInfo.setNumSlices(boost::lexical_cast(numberOfFramesStr.c_str())); _dose->getImageOrientationPatient(imageOrientationRowX, 0); _dose->getImageOrientationPatient(imageOrientationRowY, 1); _dose->getImageOrientationPatient(imageOrientationRowZ, 2); _dose->getImageOrientationPatient(imageOrientationColumnX, 3); _dose->getImageOrientationPatient(imageOrientationColumnY, 4); _dose->getImageOrientationPatient(imageOrientationColumnZ, 5); imageOrientationRow(0) = boost::lexical_cast(imageOrientationRowX.c_str()); imageOrientationRow(1) = boost::lexical_cast(imageOrientationRowY.c_str()); imageOrientationRow(2) = boost::lexical_cast(imageOrientationRowZ.c_str()); imageOrientationColumn(0) = boost::lexical_cast(imageOrientationColumnX.c_str()); imageOrientationColumn(1) = boost::lexical_cast(imageOrientationColumnY.c_str()); imageOrientationColumn(2) = boost::lexical_cast(imageOrientationColumnZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("boost::lexical_cast failed! Empty dicom dose!") ; } /*Get orientation*/ OrientationMatrix orientation; orientation(0, 0) = imageOrientationRow.x(); orientation(1, 0) = imageOrientationRow.y(); orientation(2, 0) = imageOrientationRow.z(); orientation(0, 1) = imageOrientationColumn.x(); orientation(1, 1) = imageOrientationColumn.y(); orientation(2, 1) = imageOrientationColumn.z(); WorldCoordinate3D perpendicular = imageOrientationRow.cross(imageOrientationColumn); orientation(0, 2) = perpendicular.x(); orientation(1, 2) = perpendicular.y(); orientation(2, 2) = perpendicular.z(); _geoInfo.setOrientationMatrix(orientation); OFString imagePositionX, imagePositionY, imagePositionZ; _dose->getImagePositionPatient(imagePositionX, 0); _dose->getImagePositionPatient(imagePositionY, 1); _dose->getImagePositionPatient(imagePositionZ, 2); WorldCoordinate3D imagePositionPatient; try { imagePositionPatient(0) = boost::lexical_cast(imagePositionX.c_str()); imagePositionPatient(1) = boost::lexical_cast(imagePositionY.c_str()); imagePositionPatient(2) = boost::lexical_cast(imagePositionZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read image position X/Y/Z!") ; } _geoInfo.setImagePositionPatient(imagePositionPatient); /*Get spacing*/ SpacingVectorType3D spacingVector; OFString pixelSpacingRowStr, pixelSpacingColumnStr, sliceThicknessStr; _dose->getPixelSpacing(pixelSpacingRowStr, 0); _dose->getPixelSpacing(pixelSpacingColumnStr, 1); try { spacingVector(1) = boost::lexical_cast(pixelSpacingRowStr.c_str()); spacingVector(0) = boost::lexical_cast(pixelSpacingColumnStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read Pixel Spacing Row/Column!") ; } _geoInfo.setSpacing(spacingVector); if (_geoInfo.getSpacing()(0) == 0 || _geoInfo.getSpacing()(1) == 0) { throw core::InvalidDoseException("Pixel spacing is 0!"); } _dose->getSliceThickness(sliceThicknessStr); try { spacingVector(2) = boost::lexical_cast(sliceThicknessStr.c_str()); } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ; } if (spacingVector(2) == 0) { OFVector gridFrameOffsetVector; _dose->getGridFrameOffsetVector(gridFrameOffsetVector); if (gridFrameOffsetVector.size() >= 2) { spacingVector(2) = gridFrameOffsetVector.at(1) - gridFrameOffsetVector.at( 0); //read slice thickness from GridFrameOffsetVector (3004,000c) } if (spacingVector(2) == 0) { OFCondition status; DcmItem doseitem; OFString pixelSpacingBetweenSlices; status = _dose->write(doseitem); if (status.good()) { status = doseitem.findAndGetOFString(DcmTagKey(0x0018, 0x0088), pixelSpacingBetweenSlices); try { spacingVector(2) = boost::lexical_cast (pixelSpacingBetweenSlices.c_str());//read slice thickness from PixelSpacingBetweenSlices (0018,0088) } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ; } } //if no useful tags to compute slicing -> set slice thickness to spacingVector(0) if (spacingVector(2) == 0) { std::cerr << "sliceThickness == 0! It wird be replaced with pixelSpacingRow=" << _geoInfo.getSpacing()(0) << "!" << std::endl; spacingVector(2) = spacingVector(0); } } } _geoInfo.setSpacing(spacingVector); } GenericValueType DicomDoseAccessor::getValueAt(const VoxelGridID aID) const { return doseData.at(aID) * _doseGridScaling; } GenericValueType DicomDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getValueAt(aVoxelGridID); } else { return -1; } } } } } diff --git a/code/io/dicom/rttbDicomDoseAccessor.h b/code/io/dicom/rttbDicomDoseAccessor.h index 2358d28..5e54f62 100644 --- a/code/io/dicom/rttbDicomDoseAccessor.h +++ b/code/io/dicom/rttbDicomDoseAccessor.h @@ -1,99 +1,93 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_DOSE_ACCESSOR_H #define __DICOM_DOSE_ACCESSOR_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include #include #include #include "rttbAccessorWithGeoInfoBase.h" #include "rttbBaseType.h" - namespace rttb { namespace io { namespace dicom { /*! @class DicomDoseAccessor @brief This class gives access to dose information from DRTDoseIOD and DcmItem */ class DicomDoseAccessor: public core::AccessorWithGeoInfoBase { public: using DRTDoseIODPtr = boost::shared_ptr; using DcmItemPtr = boost::shared_ptr; private: DRTDoseIODPtr _dose; DcmItemPtr _dataSet; /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector doseData; double _doseGridScaling; IDType _doseUID; DicomDoseAccessor() = delete; protected: /*! @brief Initialize dose data @exception InvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. */ bool begin(); /*! @brief get all required data from dicom information contained in _dose @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. */ void assembleGeometricInfo() override; public: ~DicomDoseAccessor() override; /*! @brief Constructor. Initialisation with a boost::shared_ptr of DRTDoseIOD and of DcmItem to get the pixel data @exception DcmrtException Throw if dcmrt error */ DicomDoseAccessor(DRTDoseIODPtr aDRTDoseIODP, DcmItemPtr aDcmDataset); GenericValueType getValueAt(const VoxelGridID aID) const override; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return _doseUID; }; }; } } } #endif diff --git a/code/io/dicom/rttbDicomFileDoseAccessorGenerator.h b/code/io/dicom/rttbDicomFileDoseAccessorGenerator.h index 0526098..4846b62 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorGenerator.h +++ b/code/io/dicom/rttbDicomFileDoseAccessorGenerator.h @@ -1,77 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_FILE_DOSE_ACCESSOR_GENERATOR_H #define __DICOM_FILE_DOSE_ACCESSOR_GENERATOR_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbDoseAccessorGeneratorBase.h" #include "rttbBaseType.h" - namespace rttb { namespace io { namespace dicom { /*! @class DicomFileDoseAccessorGenerator @brief Load dose data from dicom file and generate DicomDoseAccessor. */ class DicomFileDoseAccessorGenerator: public core::DoseAccessorGeneratorBase { public: using DRTDoseIODPtr = boost::shared_ptr; using DcmItemPtr = boost::shared_ptr; private: FileNameType _dicomDoseFileName; DicomFileDoseAccessorGenerator() = delete; protected: public: ~DicomFileDoseAccessorGenerator() override; /*! @brief Constructor. Initialization with a DICOM-RT dose file or a directory name @param aDICOMRTDoseFileName a DICOM-RT dose file name or a directory name @exception InvalidParameterException thrown if the file does not exist or the directory has no dicom dose file @exception DcmrtException thrown if load and read file failed */ DicomFileDoseAccessorGenerator(FileNameType aDICOMRTDoseFileName); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. @exception InvalidDoseException Thrown if the loaded dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error */ DoseAccessorPointer generateDoseAccessor() override ; }; } } } #endif diff --git a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp index 55e3b0a..9543f80 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp +++ b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp @@ -1,257 +1,250 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include #include #include #include #include "rttbDicomFileDoseAccessorWriter.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseStatisticsCalculator.h" namespace rttb { namespace io { namespace dicom { DicomFileDoseAccessorWriter::DicomFileDoseAccessorWriter() { _doseIOD = boost::make_shared(); _dataset = _fileformat.getDataset(); } void DicomFileDoseAccessorWriter::setFileName(DICOMRTFileNameString aFileName) { _fileName = aFileName; } bool DicomFileDoseAccessorWriter::process() { OFCondition status; /* Prepare dcmtk */ DcmItem* dcm_item = nullptr; //get geometric info rttb::core::GeometricInfo geometricInfo = _doseAccessor->getGeometricInfo(); /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ OFString CreationUID(_doseAccessor->getUID().c_str()); _dataset->putAndInsertString(DCM_ImageType, R"(DERIVED\SECONDARY\REFORMATTED)"); _dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, "");//Creation Date _dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, "");//Creation Time _dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, CreationUID); _dataset->putAndInsertString(DCM_SOPClassUID, UID_RTDoseStorage); _dataset->putAndInsertString(DCM_SOPInstanceUID, _doseAccessor->getUID().c_str()); _dataset->putAndInsertOFStringArray(DCM_StudyDate, ""); _dataset->putAndInsertOFStringArray(DCM_StudyTime, ""); _dataset->putAndInsertOFStringArray(DCM_AccessionNumber, ""); _dataset->putAndInsertOFStringArray(DCM_Modality, "RTDOSE"); _dataset->putAndInsertString(DCM_Manufacturer, "RTToolbox"); _dataset->putAndInsertString(DCM_InstitutionName, ""); _dataset->putAndInsertString(DCM_ReferringPhysicianName, ""); _dataset->putAndInsertString(DCM_StationName, ""); _dataset->putAndInsertString(DCM_ManufacturerModelName, "RTToolbox"); /* (0008,1140) DCM_ReferencedImageSequence -- MIM likes this */ dcm_item = nullptr; _dataset->findOrCreateSequenceItem( DCM_ReferencedImageSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_CTImageStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); _dataset->putAndInsertString(DCM_PatientName, ""); _dataset->putAndInsertString(DCM_PatientID, ""); _dataset->putAndInsertString(DCM_PatientBirthDate, ""); _dataset->putAndInsertString(DCM_PatientSex, "O"); _dataset->putAndInsertString(DCM_SliceThickness, boost::lexical_cast(geometricInfo.getSpacing()(2)).c_str()); _dataset->putAndInsertString(DCM_SoftwareVersions, ""); _dataset->putAndInsertString(DCM_StudyInstanceUID, ""); _dataset->putAndInsertString(DCM_SeriesInstanceUID, ""); _dataset->putAndInsertString(DCM_StudyID, "10001"); _dataset->putAndInsertString(DCM_SeriesNumber, ""); _dataset->putAndInsertString(DCM_InstanceNumber, "1"); /* GCS FIX: PatientOrientation */ std::ostringstream sstr; sstr << geometricInfo.getImagePositionPatient().x() << R"(\)" << geometricInfo.getImagePositionPatient().y() << R"(\)" << geometricInfo.getImagePositionPatient().z(); _dataset->putAndInsertString(DCM_PatientOrientation, "L/P"); _dataset->putAndInsertString(DCM_ImagePositionPatient, sstr.str().c_str()); auto orientationMatrix = geometricInfo.getOrientationMatrix(); sstr.str(""); sstr << orientationMatrix(0,0) << R"(\)" << orientationMatrix(1,0) << R"(\)" << orientationMatrix(2,0) << R"(\)" << orientationMatrix(0,1) << R"(\)" << orientationMatrix(1,1) << R"(\)" << orientationMatrix(2,1); _dataset->putAndInsertString(DCM_ImageOrientationPatient, sstr.str().c_str()); _dataset->putAndInsertString(DCM_FrameOfReferenceUID, ""); _dataset->putAndInsertString(DCM_SamplesPerPixel, "1"); _dataset->putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2"); sstr.str(""); sstr << geometricInfo.getNumSlices(); _dataset->putAndInsertString(DCM_NumberOfFrames, sstr.str().c_str()); /* GCS FIX: Add FrameIncrementPointer */ _dataset->putAndInsertString(DCM_FrameIncrementPointer, "(3004,000c)"); _dataset->putAndInsertUint16(DCM_Rows, static_cast(geometricInfo.getNumRows())); _dataset->putAndInsertUint16(DCM_Columns, static_cast(geometricInfo.getNumColumns())); sstr.str(""); sstr << geometricInfo.getSpacing()(1) << R"(\)" << geometricInfo.getSpacing()(0); _dataset->putAndInsertString(DCM_PixelSpacing, sstr.str().c_str()); _dataset->putAndInsertString(DCM_BitsAllocated, "32"); _dataset->putAndInsertString(DCM_BitsStored, "32"); _dataset->putAndInsertString(DCM_HighBit, "31"); _dataset->putAndInsertString(DCM_DoseUnits, "GY"); _dataset->putAndInsertString(DCM_DoseSummationType, "PLAN"); sstr.str("0"); for (unsigned int i = 1; i < geometricInfo.getNumSlices(); i++) { sstr << R"(\)" << i* geometricInfo.getSpacing()(2); } _dataset->putAndInsertString(DCM_GridFrameOffsetVector, sstr.str().c_str()); /* 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. */ /* Find the maximum value in the image */ boost::shared_ptr spTestDoseIterator = boost::make_shared(_doseAccessor); rttb::core::GenericDoseIterator::DoseIteratorPointer spDoseIterator(spTestDoseIterator); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); auto doseStatistics = myDoseStatsCalculator.calculateDoseStatistics(); double maxDose = doseStatistics->getMaximum(); /* Find scale factor */ double dose_scale; dose_scale = maxDose / PixelDataMaxValue; /* Scale the image and add scale factor to _dataset */ sstr.str(""); sstr << dose_scale; _dataset->putAndInsertString(DCM_DoseGridScaling, sstr.str().c_str()); /* (300c,0002) ReferencedRTPlanSequence -- for future expansion */ dcm_item = nullptr; _dataset->findOrCreateSequenceItem( DCM_ReferencedRTPlanSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_RTPlanStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); /* (300c,0060) DCM_ReferencedStructureSetSequence -- MIM likes this */ dcm_item = nullptr; _dataset->findOrCreateSequenceItem( DCM_ReferencedStructureSetSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_RTStructureSetStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); /* Convert image bytes to integer, then add to _dataset */ Uint16* pixelData; auto pixelCount = static_cast(geometricInfo.getNumRows() * geometricInfo.getNumColumns() * geometricInfo.getNumSlices()); pixelData = new Uint16[pixelCount]; for (unsigned int i = 0; i < pixelCount; ++i) { double doseValue = _doseAccessor->getValueAt(i); double pixelValue = doseValue / dose_scale; if (pixelValue > PixelDataMaxValue) { pixelValue = PixelDataMaxValue; } pixelData[i] = boost::numeric_cast(pixelValue); } status = _dataset->putAndInsertUint16Array(DCM_PixelData, pixelData, pixelCount); if (!status.good()) { throw core::InvalidDoseException("Error: put and insert pixel data failed!"); } //Write dose to file status = _fileformat.saveFile(_fileName.c_str(), EXS_LittleEndianExplicit); if (status.bad()) { std::cerr << "Error: cannot write DICOM RTDOSE!" << std::endl; } return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDicomFileDoseAccessorWriter.h b/code/io/dicom/rttbDicomFileDoseAccessorWriter.h index 8f58ac4..db43ac5 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorWriter.h +++ b/code/io/dicom/rttbDicomFileDoseAccessorWriter.h @@ -1,82 +1,77 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_FILE_DOSE_ACCESSOR_WRITER_H #define __DICOM_FILE_DOSE_ACCESSOR_WRITER_H #include "../itk/rttbDoseAccessorProcessorBase.h" #include "../itk/rttbDoseAccessorConversionSettingInterface.h" #include "rttbDicomDoseAccessor.h" //pixel data max value UINT16_MAX #define PixelDataMaxValue 0xffff namespace rttb { namespace io { namespace dicom { /*! @class DicomFileDoseAccessorWriter @brief Class converts/dumps the processed accessor into an dicom file @remark DoseAccessorConversionInterface defines how the converter should react on non valid dose values. */ class DicomFileDoseAccessorWriter: public core::DoseAccessorProcessorBase, public core::DoseAccessorConversionSettingInterface { public: using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; using DRTDoseIODPointer = DicomDoseAccessor::DRTDoseIODPtr; /*! @brief Standard Constructor. */ DicomFileDoseAccessorWriter(); ~DicomFileDoseAccessorWriter() override = default; /*! Set a file name to write the dose @param aFileName a file name to write the dose */ void setFileName(DICOMRTFileNameString aFileName); /*! @brief Convert the accessor into dicom dataset and write dicom dataset to a file @exception InvalidDoseException thrown if put and insert pixel data into dicom dataset failed */ bool process() override; private: DicomFileDoseAccessorWriter(const DicomFileDoseAccessorWriter&) = delete; //not implemented on purpose -> non-copyable DicomFileDoseAccessorWriter& operator=(const DicomFileDoseAccessorWriter&) = delete;//not implemented on purpose -> non-copyable DRTDoseIODPointer _doseIOD; DICOMRTFileNameString _fileName; DcmFileFormat _fileformat; DcmDataset* _dataset; }; } } } #endif diff --git a/code/io/dicom/rttbDicomFileReaderHelper.h b/code/io/dicom/rttbDicomFileReaderHelper.h index 63e067a..739d4ca 100644 --- a/code/io/dicom/rttbDicomFileReaderHelper.h +++ b/code/io/dicom/rttbDicomFileReaderHelper.h @@ -1,75 +1,74 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ #ifndef __DICOM_FILE_READER_HELPER_H #define __DICOM_FILE_READER_HELPER_H #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbBaseType.h" #include "boost/shared_ptr.hpp" - namespace rttb { namespace io { namespace dicom { struct Modality { enum Type { RTDOSE = 1, RTSTRUCT = 2, RTPLAN = 3, UserDefined = 128 } Type; }; using DRTDoseIODPtr = boost::shared_ptr; using DcmDataSetPtr = boost::shared_ptr; /*! Return the vector of all files with the same UID in the given directory, the UID is defined by the first file with the modality. @exception InvalidParameterException thrown if the file/directory does not exist or the modality is invalid @exception DcmrtException thrown if load/read file failed */ std::vector getFileNamesWithSameUID(FileNameType aDirName, Modality aModality); /*! Return the vector of all files with the same UID in the directory of the given file @exception InvalidParameterException thrown if the file does not exist @exception DcmrtException thrown if load/read file failed */ std::vector getFileNames(FileNameType aFileName); /*! Return modality DcmTagKey(0x0008, 0x0060) @exception DcmrtException thrown if reading modality failed*/ OFString getModality(DcmDataSetPtr aDcmDataSet); /*! Return uid DcmTagKey(0x0020, 0x000e) @exception DcmrtException thrown if reading uid failed*/ OFString getUID(DcmDataSetPtr aDcmDataSet); }; } } #endif diff --git a/code/io/dicom/rttbDicomFileStructureSetGenerator.h b/code/io/dicom/rttbDicomFileStructureSetGenerator.h index 8da25cf..659495e 100644 --- a/code/io/dicom/rttbDicomFileStructureSetGenerator.h +++ b/code/io/dicom/rttbDicomFileStructureSetGenerator.h @@ -1,95 +1,89 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ /* Changes in Architecture: The DICOM specific classes will be removed and transfered to the corresponding IO classes. This class should only provide general structure functionality. */ #ifndef __DICOM_FILE_STRUCTURE_SET_GENERATOR_H #define __DICOM_FILE_STRUCTURE_SET_GENERATOR_H #include #include #include "drtstrct.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace io { namespace dicom { /*! @class DicomFileStructureSetGenerator @brief Generate a structure set from a corresponding dicomRT file. */ class DicomFileStructureSetGenerator: public core::StrVectorStructureSetGenerator { public: using StructTypePointer = core::Structure::Pointer; using StructureSetPointer = core::StructureSet::Pointer; using DRTStrSetIODPtr = boost::shared_ptr; private: IDType _UID; DICOMRTFileNameString _fileName; DicomFileStructureSetGenerator() = default; public: /*! @brief Constructor @param aDICOMRTStrSetFileName a DICOM-RT Structure set file name or a directory name @exception InvalidParameterException thrown if the file does not exist or the directory has no dicom structure file @exception DcmrtException thrown if load and read file failed */ DicomFileStructureSetGenerator(DICOMRTFileNameString aDICOMRTStrSetFileName); /*! @brief Destructor */ ~DicomFileStructureSetGenerator() override; /*! @brief generate structure set @return return shared pointer of StructureSet @exception DcmrtException Thrown if loadFile and read failed @exception InvalidParameterException throw if the imported header tags are not numerical. */ StructureSetPointer generateStructureSet() override; }; } } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp index c86b317..700514c 100644 --- a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp +++ b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp @@ -1,71 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace io { namespace dicom { DicomIODDoseAccessorGenerator::~DicomIODDoseAccessorGenerator() = default; DicomIODDoseAccessorGenerator::DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP) { _doseIODPtr = aDRTDoseIODP; } core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomIODDoseAccessorGenerator::generateDoseAccessor() { DcmItem doseitem; OFCondition status; status = _doseIODPtr->write(doseitem);//write DoseIOD to DcmItem to get pixel data if (status.good()) { DcmItemPtr dataSetPtr = boost::make_shared(doseitem); _doseAccessor = boost::make_shared(_doseIODPtr, dataSetPtr); return _doseAccessor; } else { throw io::dicom::DcmrtException("Write DICOM RT Dose to DcmItem failed!"); } } } } } diff --git a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.h b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.h index 409a615..e2eaf11 100644 --- a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.h +++ b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.h @@ -1,75 +1,69 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_IOD_DOSE_ACCESSOR_GENERATOR_H #define __DICOM_IOD_DOSE_ACCESSOR_GENERATOR_H #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbDoseAccessorGeneratorBase.h" - namespace rttb { namespace io { namespace dicom { /*! @class DicomIODDoseAccessorGenerator @brief Generate DicomDoseAccessor with a DRTDoseIOD. */ class DicomIODDoseAccessorGenerator: public core::DoseAccessorGeneratorBase { public: using DRTDoseIODPtr = boost::shared_ptr; using DcmItemPtr = boost::shared_ptr; protected: private: DRTDoseIODPtr _doseIODPtr; DicomIODDoseAccessorGenerator() = delete; public: ~DicomIODDoseAccessorGenerator() override; /*! @brief Constructor. Initialization with a boost shared pointer of DRTDoseIOD */ DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. @exception InvalidDoseException Thrown if aDRTDoseIODP is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error */ DoseAccessorPointer generateDoseAccessor() override ; }; } } } #endif diff --git a/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp b/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp index 11b89f4..70ff824 100644 --- a/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp +++ b/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp @@ -1,208 +1,201 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include #include #include #include "rttbStructure.h" #include "rttbDicomIODStructureSetGenerator.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace io { namespace dicom { DicomIODStructureSetGenerator::DicomIODStructureSetGenerator(DRTStrSetIODPtr aDRTStructureSetIOD) { _drtStrSetIOD = aDRTStructureSetIOD; } void DicomIODStructureSetGenerator::readStrSet() { OFString uid; _drtStrSetIOD->getSeriesInstanceUID(uid); _UID = uid.c_str(); OFString uid2; _drtStrSetIOD->getPatientID(uid2); _patientUID = uid2.c_str(); DRTStructureSetROISequence* rois = &_drtStrSetIOD->getStructureSetROISequence(); //generate map of relevant ROIs std::map filteredROIs; std::regex e(this->getFilterRegEx()); for (unsigned long i = 0; i < rois->getNumberOfItems(); i++) { DRTStructureSetROISequence::Item* roisItem = &rois->getItem(i); OFString roiNumber; roisItem->getROINumber(roiNumber); OFString ofRoiName; roisItem->getROIName(ofRoiName); std::string roiName(ofRoiName.c_str()); - //replace wrongly 'á' character by ' ' in ROI name + //replace wrongly 'á' character by ' ' in ROI name correctSpacesInROIName(roiName); if (!this->getStructureLabelFilterActive() || std::regex_match(roiName, e)) { filteredROIs.emplace(roiNumber, roiName); } } /*A structure is a DRTROIContourSequence::Item. Each Item defines a roi. Each ROI contains a sequence of one or more contours, where a contour is either a single point (for a point ROI) or more than one point (representing an open or closed polygon). */ DRTROIContourSequence* rcs; rcs = &_drtStrSetIOD->getROIContourSequence(); DRTROIContourSequence::Item* rcsItem; long numberOfStructures = rcs->getNumberOfItems(); bool isEmpty = rcs->isEmpty(); if (numberOfStructures == 0 || isEmpty) { throw core::InvalidParameterException("Empty Structure Set!") ; } int structureNo = 0; for (rcs->gotoFirstItem(); (rcs->getCurrentItem(rcsItem)).good(); rcs->gotoNextItem()) { OFString refROINumber; rcsItem->getReferencedROINumber(refROINumber); //check if ROI number is in the filtered ROIS if (filteredROIs.find(refROINumber) != filteredROIs.end()) { DRTContourSequence* cs; cs = &rcsItem->getContourSequence(); unsigned long no2 = cs->getNumberOfItems(); PolygonSequenceType structureVector; for (unsigned long j = 0; j < no2; j++) { /*DRTContourSequence::Item represents a contour (either a single point (for a point ROI) or more than one point (representing an open or closed polygon))*/ DRTContourSequence::Item* csItem; csItem = &cs->getItem(j); OFString contourData; OFString numberOfContourPoints; csItem->getNumberOfContourPoints(numberOfContourPoints); unsigned int numberOfContourPointsInt; std::stringstream is(numberOfContourPoints.c_str()); is >> numberOfContourPointsInt; OFString countourNumber; csItem->getContourNumber(countourNumber); PolygonType contourVector; char* pEnd; for (unsigned int k = 0; k < numberOfContourPointsInt; k++) { WorldCoordinate3D point; for (unsigned int i = 0; i < 3; i++) { csItem->getContourData(contourData, k * 3 + i); WorldCoordinate value = strtod(contourData.c_str(), &pEnd); if (*pEnd != '\0') { throw core::InvalidParameterException("Contour data not readable!") ; } if (i == 0) { point(0) = value; } else if (i == 1) { point(1) = value; } else { point(2) = value; } } contourVector.push_back(point); } structureVector.push_back(contourVector); } boost::shared_ptr spStruct = boost::make_shared(structureVector); StructTypePointer str(spStruct); str->setLabel(filteredROIs[refROINumber]); std::cout << filteredROIs[refROINumber].c_str() << " read" << std::endl; std::stringstream sstr; sstr << structureNo; str->setUID(sstr.str()); _strVector.push_back(str); } ++structureNo; } } DicomIODStructureSetGenerator::~DicomIODStructureSetGenerator() = default; DicomIODStructureSetGenerator::StructureSetPointer DicomIODStructureSetGenerator::generateStructureSet() { this->readStrSet(); return boost::make_shared(_strVector, _patientUID, _UID); } void DicomIODStructureSetGenerator::correctSpacesInROIName(std::string& roiName) { for (auto& character : roiName) { if (character == -96) { character = ' '; } } } }//end namespace dicom }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDicomIODStructureSetGenerator.h b/code/io/dicom/rttbDicomIODStructureSetGenerator.h index 2be016c..f37ae17 100644 --- a/code/io/dicom/rttbDicomIODStructureSetGenerator.h +++ b/code/io/dicom/rttbDicomIODStructureSetGenerator.h @@ -1,91 +1,84 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ /* Changes in Architecture: The DICOM specific classes will be removed and transfered to the corresponding IO classes. This class should only provide general structure functionality. */ #ifndef __DICOM_IOD_STRUCTURE_SET_GENERATOR_H #define __DICOM_IOD_STRUCTURE_SET_GENERATOR_H #include #include "drtstrct.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" - namespace rttb { namespace io { namespace dicom { /*! @class DicomIODStructureSetGenerator @brief Generate a structure set from a DRTStructureSetIOD pointer. */ class DicomIODStructureSetGenerator: public core::StrVectorStructureSetGenerator { public: using StructTypePointer = core::Structure::Pointer; using StructureSetPointer = core::StructureSet::Pointer; using DRTStrSetIODPtr = boost::shared_ptr; private: DRTStrSetIODPtr _drtStrSetIOD; IDType _UID; /*! Import Structure data from file. @exception InvalidParameterException Thrown if the imported header tags are not numerical. */ void readStrSet(); - /*! Replaces the character 'á' ((int)-96) to ' ' ((int)32) in a string. + /*! Replaces the character 'á' ((int)-96) to ' ' ((int)32) in a string. */ void correctSpacesInROIName(std::string& roiName); public: /*! @brief Structure Constructor Get the vector of structures from DRTStructureSetIOD object @exception NullPointerException Thrown if structureSet is nullptr */ DicomIODStructureSetGenerator(DRTStrSetIODPtr aDRTStructureSetIOD); /*! @brief Destructor */ ~DicomIODStructureSetGenerator() override; /*! @brief generate structure set @return return shared pointer of StructureSet @exception InvalidParameterException throw if the imported header tags are not numerical. */ StructureSetPointer generateStructureSet() override; }; } } } #endif diff --git a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp index 0df602e..733cc4f 100644 --- a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp +++ b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp @@ -1,326 +1,319 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDicomHelaxDoseAccessor.h" #include "boost/lexical_cast.hpp" #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/numeric/ublas/matrix.hpp" #include - #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace helax { DicomHelaxDoseAccessor::~DicomHelaxDoseAccessor() = default; DicomHelaxDoseAccessor::DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector) { for (const auto & i : aDICOMRTDoseVector) { _doseVector.push_back(i); } this->begin(); } bool DicomHelaxDoseAccessor::begin() { if (_doseVector.size() == 0) { throw core::InvalidParameterException(" The size of aDICOMRTDoseVector is 0!"); } assembleGeometricInfo(); _doseData.clear(); OFString doseGridScalingStr; _doseVector.at(0)->getDoseGridScaling( doseGridScalingStr);//get the first dose grid scaling as _doseGridScaling try { _doseGridScaling = boost::lexical_cast(doseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } for (auto dose : _doseVector) { OFString currentDoseGridScalingStr; dose->getDoseGridScaling(currentDoseGridScalingStr); double currentDoseGridScaling; try { currentDoseGridScaling = boost::lexical_cast(currentDoseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } OFCondition status; DcmFileFormat fileformat; DcmItem doseitem; status = dose->write(doseitem); if (status.good()) { unsigned long count; const Uint16* pixelData; status = doseitem.findAndGetUint16Array(DcmTagKey(0x7fe0, 0x0010), pixelData, &count); if (status.good()) { for (unsigned int j = 0; j < static_cast(_geoInfo.getNumColumns()*_geoInfo.getNumRows()); j++) { auto data = static_cast(pixelData[j] * currentDoseGridScaling / _doseGridScaling); this->_doseData.push_back(data); //recalculate dose data } } else { throw dicom::DcmrtException("Read Pixel Data (7FE0,0010) failed!"); } } else { throw dicom::DcmrtException("Read DICOM-RT Dose file failed!"); } } return true; } void DicomHelaxDoseAccessor::assembleGeometricInfo() { DRTDoseIODPtr dose = _doseVector.at(0); Uint16 temp = 0; dose->getColumns(temp); _geoInfo.setNumColumns(temp); temp = 0; dose->getRows(temp); _geoInfo.setNumRows(temp); OFString numberOfFramesStr; dose->getNumberOfFrames(numberOfFramesStr); if (!numberOfFramesStr.empty()) { _geoInfo.setNumSlices(boost::lexical_cast(numberOfFramesStr.c_str())); } else { _geoInfo.setNumSlices((VoxelGridDimensionType)_doseVector.size()); } if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } OFString imageOrientationRowX; dose->getImageOrientationPatient(imageOrientationRowX, 0); OFString imageOrientationRowY; dose->getImageOrientationPatient(imageOrientationRowY, 1); OFString imageOrientationRowZ; dose->getImageOrientationPatient(imageOrientationRowZ, 2); OFString imageOrientationColumnX; dose->getImageOrientationPatient(imageOrientationColumnX, 3); OFString imageOrientationColumnY; dose->getImageOrientationPatient(imageOrientationColumnY, 4); OFString imageOrientationColumnZ; dose->getImageOrientationPatient(imageOrientationColumnZ, 5); WorldCoordinate3D imageOrientationRow; WorldCoordinate3D imageOrientationColumn; try { imageOrientationRow(0) = boost::lexical_cast(imageOrientationRowX.c_str()); imageOrientationRow(1) = boost::lexical_cast(imageOrientationRowY.c_str()); imageOrientationRow(2) = boost::lexical_cast(imageOrientationRowZ.c_str()); imageOrientationColumn(0) = boost::lexical_cast(imageOrientationColumnX.c_str()); imageOrientationColumn(1) = boost::lexical_cast(imageOrientationColumnY.c_str()); imageOrientationColumn(2) = boost::lexical_cast(imageOrientationColumnZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("boost::lexical_cast WorldCoordinate failed! Can not read image orientation X/Y/Z!") ; } OrientationMatrix orientation; orientation(0, 0) = imageOrientationRow.x(); orientation(1, 0) = imageOrientationRow.y(); orientation(2, 0) = imageOrientationRow.z(); orientation(0, 1) = imageOrientationColumn.x(); orientation(1, 1) = imageOrientationColumn.y(); orientation(2, 1) = imageOrientationColumn.z(); WorldCoordinate3D perpendicular = imageOrientationRow.cross(imageOrientationColumn); orientation(0, 2) = perpendicular.x(); orientation(1, 2) = perpendicular.y(); orientation(2, 2) = perpendicular.z(); _geoInfo.setOrientationMatrix(orientation); OFString imagePositionX; dose->getImagePositionPatient(imagePositionX, 0); OFString imagePositionY; dose->getImagePositionPatient(imagePositionY, 1); OFString imagePositionZ; dose->getImagePositionPatient(imagePositionZ, 2); WorldCoordinate3D imagePositionPatient; try { imagePositionPatient(0) = boost::lexical_cast(imagePositionX.c_str()); imagePositionPatient(1) = boost::lexical_cast(imagePositionY.c_str()); imagePositionPatient(2) = boost::lexical_cast(imagePositionZ.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("boost::lexical_cast ImagePosition failed! Can not read image position X/Y/Z!") ; } _geoInfo.setImagePositionPatient(imagePositionPatient); SpacingVectorType3D spacingVector; OFString pixelSpacingRowStr; dose->getPixelSpacing(pixelSpacingRowStr, 0); OFString pixelSpacingColumnStr; dose->getPixelSpacing(pixelSpacingColumnStr, 1); try { spacingVector(1) = boost::lexical_cast(pixelSpacingRowStr.c_str()); spacingVector(0) = boost::lexical_cast(pixelSpacingColumnStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read Pixel Spacing Row/Column!") ; } _geoInfo.setSpacing(spacingVector); if (_geoInfo.getSpacing()(0) == 0 || _geoInfo.getSpacing()(1) == 0) { throw core::InvalidDoseException("Pixel spacing not readable or = 0!"); } OFString sliceThicknessStr; dose->getSliceThickness(sliceThicknessStr); try { spacingVector(2) = boost::lexical_cast(sliceThicknessStr.c_str()); } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ;//if no information about slice thickness, set to 0 and calculate it using z coordinate difference between 1. and 2. dose } if (spacingVector(2) == 0) { if (_doseVector.size() > 1) { DRTDoseIODPtr dose2 = _doseVector.at(1);//get the 2. dose OFString imagePositionZ2; dose2->getImagePositionPatient(imagePositionZ2, 2); try { spacingVector(2) = boost::lexical_cast(imagePositionZ2.c_str()) - imagePositionPatient( 2); //caculate slicethickness } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read image position Z of the 2. dose!"); } } else { std::cerr << "sliceThickness == 0! It will be replaced with pixelSpacingRow=" << _geoInfo.getSpacing()(0) << "!" << std::endl; spacingVector(2) = spacingVector(0); } } _geoInfo.setSpacing(spacingVector); } GenericValueType DicomHelaxDoseAccessor::getValueAt(const VoxelGridID aID) const { return _doseData.at(aID) * _doseGridScaling; } GenericValueType DicomHelaxDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getValueAt(aVoxelGridID); } else { return -1; } } } } } diff --git a/code/io/helax/rttbDicomHelaxDoseAccessor.h b/code/io/helax/rttbDicomHelaxDoseAccessor.h index ba0d8a0..0d5929d 100644 --- a/code/io/helax/rttbDicomHelaxDoseAccessor.h +++ b/code/io/helax/rttbDicomHelaxDoseAccessor.h @@ -1,101 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_HELAX_DOSE_ACCESSOR_H #define __DICOM_HELAX_DOSE_ACCESSOR_H #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbBaseType.h" #include "rttbAccessorWithGeoInfoBase.h" - - namespace rttb { namespace io { namespace helax { /*! @class DicomHelaxDoseAccessor @brief Load dose data from a directory containing dicom dose files, each file describes the helax dose in one slice. */ class DicomHelaxDoseAccessor: public core::AccessorWithGeoInfoBase { public: using DRTDoseIODPtr = boost::shared_ptr; private: /*! vector of DRTDoseIOD shared pointers, each DRTDoseIOD pointer presents the dose in one slice*/ std::vector _doseVector; /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector _doseData; double _doseGridScaling; IDType _doseUID; DicomHelaxDoseAccessor() = delete; protected: /*! @brief Initialize dose data @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. */ bool begin(); /*! @brief get all required data from dicom information contained in _dose @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. */ void assembleGeometricInfo() override; public: ~DicomHelaxDoseAccessor() override; /*! @brief Constructor. Initialisation with a vector of DRTDoseIOD pointers @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error */ DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector); GenericValueType getValueAt(const VoxelGridID aID) const override; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return _doseUID; }; }; } } } #endif diff --git a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp index 408767f..2c15a74 100644 --- a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp @@ -1,94 +1,88 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" #include "rttbDicomFileReaderHelper.h" namespace rttb { namespace io { namespace helax { DicomHelaxFileDoseAccessorGenerator::~DicomHelaxFileDoseAccessorGenerator() = default; DicomHelaxFileDoseAccessorGenerator::DicomHelaxFileDoseAccessorGenerator( FileNameType aDICOMRTDoseDirName) { _doseDirName = aDICOMRTDoseDirName; } core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomHelaxFileDoseAccessorGenerator::generateDoseAccessor() { rttb::io::dicom::Modality doseModality = {rttb::io::dicom::Modality::RTDOSE}; std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(_doseDirName, doseModality); OFCondition status; DcmFileFormat fileformat; std::vector doseVector; for (auto & i : fileVector) { DRTDoseIODPtr dose = boost::make_shared(); status = fileformat.loadFile(i.c_str()); if (!status.good()) { throw core::InvalidDoseException("Error: load dose fileformat.loadFile failed!"); } status = dose->read(*fileformat.getDataset()); if (!status.good()) { throw core::InvalidDoseException("Error: read DRTDoseIOD failed!"); } doseVector.push_back(dose); } _doseAccessor = boost::make_shared(doseVector); return _doseAccessor; } } } } diff --git a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.h b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.h index e3e9552..6a6a50c 100644 --- a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.h +++ b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.h @@ -1,79 +1,73 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_HELAX_FILE_DOSE_ACCESSOR_GENERATOR_H #define __DICOM_HELAX_FILE_DOSE_ACCESSOR_GENERATOR_H #include #include #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbDoseAccessorGeneratorBase.h" #include "rttbBaseType.h" - namespace rttb { namespace io { namespace helax { /*! @class DicomHelaxFileDoseAccessorGenerator @brief Load dose data from dicom helax files and generate DoseAccessor */ class DicomHelaxFileDoseAccessorGenerator: public core::DoseAccessorGeneratorBase { public: using DRTDoseIODPtr = boost::shared_ptr; protected: private: FileNameType _doseDirName; DicomHelaxFileDoseAccessorGenerator() = delete; public: ~DicomHelaxFileDoseAccessorGenerator() override; /*! @brief Constructor. Initialisation with a directory name */ DicomHelaxFileDoseAccessorGenerator(FileNameType aDICOMRTDoseDirName); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. @exception InvalidParameterException Thrown if aDICOMRTDoseDirName is not found @exception InvalidDoseException Thrown if any loaded dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error */ DoseAccessorPointer generateDoseAccessor() override ; }; } } } #endif diff --git a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp index 801211e..820a131 100644 --- a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp @@ -1,56 +1,50 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "rttbDicomHelaxIODVecDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" namespace rttb { namespace io { namespace helax { DicomHelaxIODVecDoseAccessorGenerator::~DicomHelaxIODVecDoseAccessorGenerator() = default; DicomHelaxIODVecDoseAccessorGenerator::DicomHelaxIODVecDoseAccessorGenerator( std::vector& aDICOMRTDoseVector) { _dosePtrVector = aDICOMRTDoseVector; } core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomHelaxIODVecDoseAccessorGenerator::generateDoseAccessor() { _doseAccessor = boost::make_shared(_dosePtrVector); return _doseAccessor; } } } } diff --git a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.h b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.h index 2ed0def..86716f8 100644 --- a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.h +++ b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.h @@ -1,74 +1,68 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DICOM_HELAX_IOD_VEC_DOSE_ACCESSOR_GENERATOR_H #define __DICOM_HELAX_IOD_VEC_DOSE_ACCESSOR_GENERATOR_H #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbDoseAccessorGeneratorBase.h" - namespace rttb { namespace io { namespace helax { /*! @class DicomHelaxIODVecDoseAccessorGenerator @brief Generate DoseAccessor with a vector of DRTDoseIOD. */ class DicomHelaxIODVecDoseAccessorGenerator: public core::DoseAccessorGeneratorBase { public: using DRTDoseIODPtr = boost::shared_ptr; protected: private: std::vector _dosePtrVector; DicomHelaxIODVecDoseAccessorGenerator() = delete; public: ~DicomHelaxIODVecDoseAccessorGenerator() override; /*! @brief Constructor. Initialisation with a vector of DRTDoseIOD pointers */ DicomHelaxIODVecDoseAccessorGenerator(std::vector& aDICOMRTDoseVector); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 @exception DcmrtException Throw if dcmrt error */ DoseAccessorPointer generateDoseAccessor() override ; }; } } } #endif diff --git a/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp index ceca521..ee10c34 100644 --- a/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp @@ -1,58 +1,52 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace io { namespace dicom { DicomIODDoseAccessorGenerator::~DicomIODDoseAccessorGenerator() {} DicomIODDoseAccessorGenerator::DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP) { _doseIODPtr = aDRTDoseIODP; } core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomIODDoseAccessorGenerator::generateDoseAccessor() { _doseAccessor = boost::make_shared(_doseIODPtr); return _doseAccessor; } } } } diff --git a/code/io/itk/itkDoseAccessorImageFilter.cpp b/code/io/itk/itkDoseAccessorImageFilter.cpp index e5c9331..2be3390 100644 --- a/code/io/itk/itkDoseAccessorImageFilter.cpp +++ b/code/io/itk/itkDoseAccessorImageFilter.cpp @@ -1,84 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include "itkDoseAccessorImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkProgressReporter.h" - namespace itk { /** * Constructor */ DoseAccessorImageFilter ::DoseAccessorImageFilter() { this->SetNumberOfRequiredInputs(1); } void DoseAccessorImageFilter ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) { ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); using ImageRegionConstIteratorType = ImageRegionConstIteratorWithIndex; using OutputImageRegionIteratorType = ImageRegionIterator; InputImagePointer inputPtr = dynamic_cast< InputImageType* >(ProcessObject::GetInput(0)); ImageRegionConstIteratorType inputItr; if (inputPtr) { inputItr = ImageRegionConstIteratorType(inputPtr, outputRegionForThread); } OutputImagePointer outputPtr = dynamic_cast< OutputImageType* >(ProcessObject::GetOutput(0)); OutputImageRegionIteratorType outputItr; if (outputPtr) { outputItr = OutputImageRegionIteratorType(outputPtr, outputRegionForThread); } if (inputPtr && outputPtr) { while (!(outputItr.IsAtEnd())) { ImageRegionConstIteratorType::IndexType index = inputItr.GetIndex(); rttb::VoxelGridIndex3D doseIndex(index[0], index[1], index[2]); outputItr.Set(m_Accessor->getValueAt(doseIndex)); ++outputItr; ++inputItr; progress.CompletedPixel(); } } } } // end namespace itk diff --git a/code/io/itk/itkDoseAccessorImageFilter.h b/code/io/itk/itkDoseAccessorImageFilter.h index f41e9a9..9d072f6 100644 --- a/code/io/itk/itkDoseAccessorImageFilter.h +++ b/code/io/itk/itkDoseAccessorImageFilter.h @@ -1,118 +1,112 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __itkDoseAccessorImageFilter_h #define __itkDoseAccessorImageFilter_h #include "itkImageToImageFilter.h" #include "rttbDoseAccessorInterface.h" #include "rttbITKImageAccessor.h" namespace itk { /** \class DoseAccessorImageFilter * \brief Perform a generic pixel-wise operation on the input image by setting its pixel values according to the dose accessor output. * * \ingroup IntensityImageFilters MultiThreaded * \ingroup ITKImageIntensity */ typedef rttb::io::itk::ITKImageAccessor::ITKImageType RTTBDoseImageType; class ITK_EXPORT DoseAccessorImageFilter: public ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > { public: /** Standard class typedefs. */ typedef DoseAccessorImageFilter Self; typedef ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(DoseAccessorImageFilter, ImageToImageFilter); /** Some typedefs. */ typedef RTTBDoseImageType InputImageType; typedef InputImageType::Pointer InputImagePointer; typedef InputImageType::RegionType InputImageRegionType; typedef InputImageType::PixelType InputImagePixelType; typedef RTTBDoseImageType OutputImageType; typedef OutputImageType::Pointer OutputImagePointer; typedef OutputImageType::RegionType OutputImageRegionType; typedef OutputImageType::PixelType OutputImagePixelType; typedef rttb::core::DoseAccessorInterface DoseAccessorType; typedef rttb::core::DoseAccessorInterface::Pointer DoseAccessorPointer; /** Get the accessor pointer. */ DoseAccessorPointer GetAccessor() { return m_Accessor; } /** Set the accessor pointer. */ void SetAccessor(DoseAccessorPointer accessor) { if (m_Accessor != accessor) { m_Accessor = accessor; this->Modified(); } } /** ImageDimension constants */ itkStaticConstMacro( InputImageDimension, unsigned int, InputImageType::ImageDimension); itkStaticConstMacro( OutputImageDimension, unsigned int, OutputImageType::ImageDimension); protected: DoseAccessorImageFilter(); ~DoseAccessorImageFilter() override {} /** DoseAccessorImageFilter can be implemented as a multi threaded 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 OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) override; private: DoseAccessorImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented DoseAccessorPointer m_Accessor; }; } // end namespace itk #endif diff --git a/code/io/itk/itkMaskAccessorImageSource.cpp b/code/io/itk/itkMaskAccessorImageSource.cpp index b781774..2a523f9 100644 --- a/code/io/itk/itkMaskAccessorImageSource.cpp +++ b/code/io/itk/itkMaskAccessorImageSource.cpp @@ -1,108 +1,101 @@ // ----------------------------------------------------------------------- // 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: 1233 $ (last changed revision) -// @date $Date: 2016-01-20 15:47:47 +0100 (Mi, 20 Jan 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "itkMaskAccessorImageSource.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkProgressReporter.h" #include "itkExceptionObject.h" #include "rttbGeometricInfo.h" namespace itk { /** * Constructor */ MaskAccessorImageSource ::MaskAccessorImageSource() = default; void MaskAccessorImageSource ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) { ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); using OutputImageRegionIteratorType = ImageRegionIterator; OutputImagePointer outputPtr = dynamic_cast< OutputImageType* >(ProcessObject::GetOutput(0)); OutputImageRegionIteratorType outputItr; if (outputPtr) { outputItr = OutputImageRegionIteratorType(outputPtr, outputRegionForThread); for (; !(outputItr.IsAtEnd()); ++outputItr) { OutputImageType::IndexType index = outputItr.GetIndex(); rttb::VoxelGridIndex3D maskIndex(index[0], index[1], index[2]); rttb::VoxelGridID id = 0; if (m_Accessor->getGeometricInfo().convert(maskIndex, id)) { auto finding = m_idMap.find(id); if (finding != m_idMap.end()) { // Set the current pixel outputItr.Set(m_MaskedVoxels->at(finding->second).getRelevantVolumeFraction()); } } else { if (m_FailsOnInvalidIDs) { itkExceptionMacro(<<"invalid Mask index. Index:"<(ProcessObject::GetOutput(0)); outputPtr->FillBuffer(0.0); //The id map approach and working with relevant voxel vector is a workarround till task T22067 is solved and and can be used again. m_MaskedVoxels = m_Accessor->getRelevantVoxelVector(); m_idMap.clear(); for (rttb::core::MaskAccessorInterface::MaskVoxelList::size_type pos = 0; pos < m_MaskedVoxels->size(); ++pos) { m_idMap.insert(std::make_pair((*m_MaskedVoxels)[pos].getVoxelGridID(), pos)); } } } // end namespace itk diff --git a/code/io/itk/itkMaskAccessorImageSource.h b/code/io/itk/itkMaskAccessorImageSource.h index 543d992..c16a034 100644 --- a/code/io/itk/itkMaskAccessorImageSource.h +++ b/code/io/itk/itkMaskAccessorImageSource.h @@ -1,111 +1,105 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __itkMaskAccessorImageSource_h #define __itkMaskAccessorImageSource_h #include "itkGenerateImageSource.h" #include "rttbMaskAccessorInterface.h" #include "rttbITKImageMaskAccessor.h" namespace itk { /** \class MaskAccessorImageSource * \brief Converts a given mask accessor into an itk image. * */ typedef rttb::io::itk::ITKImageMaskAccessor::ITKMaskImageType RTTBMaskImageType; class ITK_EXPORT MaskAccessorImageSource: public GenerateImageSource< RTTBMaskImageType> { public: /** Standard class typedefs. */ typedef MaskAccessorImageSource Self; typedef GenerateImageSource< RTTBMaskImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(MaskAccessorImageSource, ImageToImageFilter); /** Some typedefs. */ typedef RTTBMaskImageType OutputImageType; typedef OutputImageType::Pointer OutputImagePointer; typedef OutputImageType::RegionType OutputImageRegionType; typedef OutputImageType::PixelType OutputImagePixelType; typedef rttb::core::MaskAccessorInterface AccessorType; typedef rttb::core::MaskAccessorInterface::Pointer AccessorPointer; /** Get the accessor pointer. */ itkGetConstMacro(Accessor, AccessorPointer); /** Set the accessor pointer. */ void SetAccessor(AccessorPointer accessor) { if (m_Accessor != accessor) { m_Accessor = accessor; this->Modified(); } } itkSetMacro(FailsOnInvalidIDs, bool); itkGetConstMacro(FailsOnInvalidIDs, bool); itkSetMacro(InvalidMaskValue, OutputImageType::ValueType); itkGetConstMacro(InvalidMaskValue, OutputImageType::ValueType); /** ImageDimension constants */ itkStaticConstMacro( OutputImageDimension, unsigned int, OutputImageType::ImageDimension); protected: MaskAccessorImageSource(); ~MaskAccessorImageSource() override {} void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, ThreadIdType threadId) override; void BeforeThreadedGenerateData() override; private: MaskAccessorImageSource(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented typedef std::map VoxelMapType; VoxelMapType m_idMap; rttb::core::MaskAccessorInterface::MaskVoxelListPointer m_MaskedVoxels; AccessorPointer m_Accessor; bool m_FailsOnInvalidIDs{true}; OutputImageType::ValueType m_InvalidMaskValue{0}; }; } // end namespace itk #endif diff --git a/code/io/itk/rttbDoseAccessorConversionSettingInterface.h b/code/io/itk/rttbDoseAccessorConversionSettingInterface.h index 5548fdc..5cdd88d 100644 --- a/code/io/itk/rttbDoseAccessorConversionSettingInterface.h +++ b/code/io/itk/rttbDoseAccessorConversionSettingInterface.h @@ -1,77 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_CONVERSION_SETTING_INTERFACE_H #define __DOSE_ACCESSOR_CONVERSION_SETTING_INTERFACE_H namespace rttb { namespace core { /*! @class DoseAccessorConversionSettingInterface @brief Interface for specifying settings for dose accessor converters (e.g. how to handle invalid dose voxels) */ class DoseAccessorConversionSettingInterface { public: /* Defines if the conversion process should fail (with an exception) if an invalid id/voxel occurs.*/ void setFailOnInvalidIDs(bool failOnInvalid) { _failedOnInvalidID = failOnInvalid; } /* Indicates how the conversion should handle invalid ids/voxels.\n * true: fails with an exception * false: uses the specified "invalid dose value".*/ bool failsOnInvalidIDs() const { return _failedOnInvalidID; } /* Sets the value that should be used for invalid ids/voxels.*/ void setInvalidDoseValue(DoseTypeGy value) { _invalidDoseValue = value; } /* Returns the value that is used for invalid ids/voxels.*/ DoseTypeGy getInvalidDoseValue() const { return _invalidDoseValue; } DoseAccessorConversionSettingInterface() = default; virtual ~DoseAccessorConversionSettingInterface() = default; private: DoseAccessorConversionSettingInterface(const DoseAccessorConversionSettingInterface&) = delete; //not implemented on purpose -> non-copyable DoseAccessorConversionSettingInterface& operator=(const DoseAccessorConversionSettingInterface&) = delete;//not implemented on purpose -> non-copyable protected: bool _failedOnInvalidID{false}; DoseTypeGy _invalidDoseValue{-1.0}; }; } } #endif diff --git a/code/io/itk/rttbDoseAccessorProcessorBase.h b/code/io/itk/rttbDoseAccessorProcessorBase.h index 7283f31..893c827 100644 --- a/code/io/itk/rttbDoseAccessorProcessorBase.h +++ b/code/io/itk/rttbDoseAccessorProcessorBase.h @@ -1,61 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_PROCESSOR_BASE_H #define __DOSE_ACCESSOR_PROCESSOR_BASE_H #include #include "rttbDoseAccessorProcessorInterface.h" namespace rttb { namespace core { /*! @class DoseAccessorProcessorBase @brief Abstract class for all DoseAccessor generating classes */ class DoseAccessorProcessorBase: public DoseAccessorProcessorInterface { public: using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; void setDoseAccessor(DoseAccessorPointer accessor) override { _doseAccessor = accessor; }; private: DoseAccessorProcessorBase(const DoseAccessorProcessorBase&) = delete; //not implemented on purpose -> non-copyable DoseAccessorProcessorBase& operator=(const DoseAccessorProcessorBase&) = delete;//not implemented on purpose -> non-copyable protected: DoseAccessorProcessorBase() = default; ~DoseAccessorProcessorBase() override = default; /*! @brief Dose accessor which should be generated */ DoseAccessorPointer _doseAccessor; }; } } #endif diff --git a/code/io/itk/rttbDoseAccessorProcessorInterface.h b/code/io/itk/rttbDoseAccessorProcessorInterface.h index 52abd1f..ead9576 100644 --- a/code/io/itk/rttbDoseAccessorProcessorInterface.h +++ b/code/io/itk/rttbDoseAccessorProcessorInterface.h @@ -1,65 +1,60 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_ACCESSOR_PROCESSOR_INTERFACE_H #define __DOSE_ACCESSOR_PROCESSOR_INTERFACE_H #include "rttbDoseAccessorInterface.h" namespace rttb { namespace core { /*! @class DoseAccessorProcessorInterface @brief Interface for all DoseAccessor generating classes */ class DoseAccessorProcessorInterface { public: using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; private: DoseAccessorProcessorInterface(const DoseAccessorProcessorInterface&) = delete; //not implemented on purpose -> non-copyable DoseAccessorProcessorInterface& operator=(const DoseAccessorProcessorInterface&) = delete;//not implemented on purpose -> non-copyable protected: DoseAccessorProcessorInterface() = default; virtual ~DoseAccessorProcessorInterface() = default; public: /*! @brief Sets the DoseAccessor that should be processed @pre passed accessor must point to a valid instance. */ virtual void setDoseAccessor(DoseAccessorPointer accessor) = 0; /*! @brief Process the passed DoseAccessor @return if the processing was successful. */ virtual bool process() = 0; }; } } #endif diff --git a/code/io/itk/rttbFileDispatch.cpp b/code/io/itk/rttbFileDispatch.cpp index b06e21b..e82e298 100644 --- a/code/io/itk/rttbFileDispatch.cpp +++ b/code/io/itk/rttbFileDispatch.cpp @@ -1,127 +1,120 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/Core/source/mapFileDispatch.cpp $ -*/ #include "rttbFileDispatch.h" #include "itksys/SystemTools.hxx" namespace rttb { namespace core { FileNameString FileDispatch:: getName(const FileNameString& sFilePath) { FileNameString result = itksys::SystemTools::GetFilenameWithoutLastExtension(sFilePath); return result; }; FileNameString FileDispatch:: getExtension(const FileNameString& sFilePath) { FileNameString result = itksys::SystemTools::GetFilenameLastExtension(sFilePath); return result; }; FileNameString FileDispatch:: getFullName(const FileNameString& sFilePath) { FileNameString result = itksys::SystemTools::GetFilenameName(sFilePath); return result; }; FileNameString FileDispatch:: getPath(const FileNameString& sFilePath) { FileNameString result = itksys::SystemTools::GetFilenamePath(sFilePath); return ensureCorrectOSPathSeparator(result); }; FileNameString FileDispatch:: getName() { return getName(_fileName); }; FileNameString FileDispatch:: getExtension() { return getExtension(_fileName); }; FileNameString FileDispatch:: getFullName() { return getFullName(_fileName); }; FileNameString FileDispatch:: getPath() { return getPath(_fileName); }; FileDispatch:: FileDispatch(const FileNameString& filePath) { _fileName = filePath; }; /** Convertes all path seperators in the seperators used in the current OS.*/ FileNameString FileDispatch:: ensureCorrectOSPathSeparator(const FileNameString& path) { FileNameString ret = path; #ifdef _WIN32 const FileNameString curSep = "\\"; const char wrongSep = '/'; #else const FileNameString curSep = "/"; const char wrongSep = '\\'; #endif FileNameString::size_type pos = ret.find_first_of(wrongSep); while (pos != FileNameString::npos) { ret.replace(pos, 1, curSep); pos = ret.find_first_of(wrongSep); } return ret; } } } \ No newline at end of file diff --git a/code/io/itk/rttbFileDispatch.h b/code/io/itk/rttbFileDispatch.h index 58d66d5..71128da 100644 --- a/code/io/itk/rttbFileDispatch.h +++ b/code/io/itk/rttbFileDispatch.h @@ -1,70 +1,62 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/Core/include/mapFileDispatch.h $ -*/ - #ifndef __RTTB_FILE_DISPATCH_H #define __RTTB_FILE_DISPATCH_H #include #include "rttbBaseType.h" namespace rttb { namespace core { /*! @class FileDispatch @brief Convenience functions for working with files and path @note code copied from MatchPoint, see documentation (http://sourceforge.net/projects/matchpoint/) */ class FileDispatch { public: /** Returns the name of the file (without extension).*/ static FileNameString getName(const FileNameString& sFilePath); /** Returns the extansion of the file (dot included).*/ static FileNameString getExtension(const FileNameString& sFilePath); /** Returns name of the file plus extension.*/ static FileNameString getFullName(const FileNameString& sFilePath); /** Returns the directory the file is located in (without trailing slash). * @remark this function always removes the last element of the path. Thus * if you pass a path without a file, it will return the parent directory.*/ static FileNameString getPath(const FileNameString& sFilePath); /** Convertes all path seperators in the seperators used in the current OS.*/ static FileNameString ensureCorrectOSPathSeparator(const FileNameString& path); FileNameString getName(); FileNameString getExtension(); FileNameString getFullName(); FileNameString getPath(); FileDispatch(const FileNameString& filePath); private: FileNameString _fileName; }; }//end namespace core }//end namespace rttb #endif diff --git a/code/io/itk/rttbGenericImageReader.cpp b/code/io/itk/rttbGenericImageReader.cpp index 0fb76ab..9d3d872 100644 --- a/code/io/itk/rttbGenericImageReader.cpp +++ b/code/io/itk/rttbGenericImageReader.cpp @@ -1,301 +1,294 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/source/mapGenericImageReader.cpp $ -*/ #include "rttbGenericImageReader.h" namespace rttb { namespace io { namespace itk { void GenericImageReader::load() { _spImage = nullptr; FileNameString probeFileName = this->_fileName; if (this->_seriesReadStyle == ImageSeriesReadStyle::Numeric) { using NamesType = ::itk::NumericSeriesFileNames; NamesType::Pointer names = NamesType::New(); names->SetStartIndex(1); names->SetEndIndex(1); names->SetSeriesFormat(this->_fileName.c_str()); probeFileName = names->GetFileNames()[0]; } ::itk::ImageIOBase::Pointer imageIO = ::itk::ImageIOFactory::CreateImageIO(probeFileName.c_str(), ::itk::ImageIOFactory::ReadMode); if (!imageIO) { throw ::itk::ExceptionObject("No ImageIO found for given file. Please check if the file exists and has a supported format. File:" + probeFileName); } // Now that we found the appropriate ImageIO class, ask it to // read the meta data from the image file. imageIO->SetFileName(probeFileName.c_str()); imageIO->ReadImageInformation(); this->_loadedComponentType = imageIO->GetComponentType(); this->_loadedPixelType = imageIO->GetPixelType(); if (this->_loadedPixelType == ::itk::ImageIOBase::RGB && imageIO->GetNumberOfComponents() == 1) { //if only one channel per pixel handle as scalar as long as RGB etc. is not supported this->_loadedPixelType = ::itk::ImageIOBase::SCALAR; } this->_loadedComponentTypeStr = imageIO->GetComponentTypeAsString(this->_loadedComponentType); this->_loadedPixelTypeStr = imageIO->GetPixelTypeAsString(this->_loadedPixelType); this->_loadedDimensions = imageIO->GetNumberOfDimensions(); if (this->_seriesReadStyle == ImageSeriesReadStyle::Numeric && this->_loadedDimensions == 2) { this->_loadedDimensions = 3; //it is a stack of 2D images -> 3D } if (this->_loadedDimensions < 2 || this->_loadedDimensions > 3) { throw ::itk::ExceptionObject("The file uses a number of dimensions that is not supported in this application. Only dim<=3 supported "); } switch (_loadedPixelType) { case ::itk::ImageIOBase::SCALAR: { if (this->_loadedDimensions == 2) { loadScalar<2>(); } else { loadScalar<3>(); } break; } default: { throw ::itk::ExceptionObject("The file uses a pixel type that is not supported in this application. Only SCALAR pixel type supported "); } } _upToDate = true; }; template void GenericImageReader:: loadScalar() { // Use the pixel type to instantiate the appropriate reader switch (this->_loadedComponentType) { case ::itk::ImageIOBase::UCHAR: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::CHAR: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::USHORT: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::SHORT: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::UINT: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::INT: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::ULONG: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::LONG: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::FLOAT: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } case ::itk::ImageIOBase::DOUBLE: { this->_spImage = readImage(_fileName, _seriesReadStyle, false, 0, 0, _upperSeriesLimit, &_dictionaryArray); break; } default: { throw ::itk::ExceptionObject("The file uses a pixel component type that is not supported in this application. ComponentType: " + this->_loadedComponentTypeStr); } } }; const FileNameString& GenericImageReader:: getFileName() const { return _fileName; }; void GenericImageReader:: setFileName(const FileNameString& fileName) { if (fileName != _fileName) { _upToDate = false; _fileName = fileName; } } const unsigned int GenericImageReader:: getUpperSeriesLimit() const { return _upperSeriesLimit; }; void GenericImageReader:: setUpperSeriesLimit(const unsigned int upperLimit) { if (upperLimit != _upperSeriesLimit) { _upToDate = false; _upperSeriesLimit = upperLimit; }; }; const ImageSeriesReadStyle::Type GenericImageReader:: getSeriesReadStyle() const { return _seriesReadStyle; }; void GenericImageReader:: setSeriesReadStyle(ImageSeriesReadStyle::Type readStyle) { if (readStyle != _seriesReadStyle) { _upToDate = false; _seriesReadStyle = readStyle; }; }; GenericImageReader::GenericOutputImageType* GenericImageReader:: GetOutput(unsigned int& loadedDimensions, LoadedPixelType& loadedPixelType, LoadedComponentType& loadedComponentType) { if (!_upToDate) { load(); loadedPixelType = _loadedPixelType; loadedComponentType = _loadedComponentType; loadedDimensions = _loadedDimensions; }; return _spImage; }; GenericImageReader:: GenericImageReader() : _fileName() { }; GenericImageReader:: ~GenericImageReader() = default; const GenericImageReader::MetaDataDictionaryArrayType& GenericImageReader:: getMetaDictionaryArray() { return _dictionaryArray; }; }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbGenericImageReader.h b/code/io/itk/rttbGenericImageReader.h index 037a154..cfead1f 100644 --- a/code/io/itk/rttbGenericImageReader.h +++ b/code/io/itk/rttbGenericImageReader.h @@ -1,163 +1,156 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/include/mapGenericImageReader.h $ -*/ #ifndef __RTTB_GENERIC_IMAGE_READER_H #define __RTTB_GENERIC_IMAGE_READER_H #include "rttbImageReader.h" namespace rttb { namespace io { namespace itk { /** @class ImageReader * @brief Helper class manages the generic loading (unspecified dimension and pixel type) of 2D/3D images ... * * GenericImageReader uses the ImageReader class and dispatches the dimension and pixel type information from the specified image file. * GenericImageReader supports 2D and 3D images and the following pixel types: * - (unsigned) char * - (unsigned) short * - (unsigned) int * - (unsigned) long * - float * - double * . * Due to the fact that it builds upon the itk io infrastructure, all formats supported by ITK * can be read. * For further information regarding the usage see documentation of ImageReader. * @sa ImageReader * @note code copied from MatchPoint, see documentation (http://sourceforge.net/projects/matchpoint/) */ class GenericImageReader : public ::itk::Object { public: using Self = rttb::io::itk::GenericImageReader; using Superclass = ::itk::Object; using Pointer = ::itk::SmartPointer; using ConstPointer = ::itk::SmartPointer; itkTypeMacro(GenericImageReader, ::itk::Object); itkNewMacro(Self); using GenericOutputImageType = ::itk::DataObject; using LoadedPixelType = ::itk::ImageIOBase::IOPixelType; using LoadedComponentType = ::itk::ImageIOBase::IOComponentType; using MetaDataDictionaryArrayType = std::vector< ::itk::MetaDataDictionary>; private: /** Loaded Image.*/ GenericOutputImageType::Pointer _spImage; /** The file name of the image. */ FileNameString _fileName; /** The upper limit for the searching of series files in the path.*/ unsigned int _upperSeriesLimit{255}; /** Indicates if the image data is up to date or should be read again.*/ bool _upToDate{false}; /** Defines if the specified image file is part of a series and the * whole series should be read into one image. Only relevant for 3D images.*/ ImageSeriesReadStyle::Type _seriesReadStyle{ImageSeriesReadStyle::Default}; unsigned int _loadedDimensions; LoadedPixelType _loadedPixelType; LoadedComponentType _loadedComponentType; std::string _loadedComponentTypeStr; std::string _loadedPixelTypeStr; MetaDataDictionaryArrayType _dictionaryArray; /** Loads the image. First identifies pixel type and dimension and then deligates according * to the pixel type. * @exception map::core::ExceptionObject If no ImageIO is found. * @exception map::core::ExceptionObject If dimension of the image is not supported. Only 2D/3D is supported. * @exception map::core::ExceptionObject If pixel type is not supported. Currently only scalar pixels are supported. */ void load(); /** Loads an scalar image. * @exception map::core::ExceptionObject If pixel component type is not supported. */ template void loadScalar(); //template //void loadRGB(); public: /** Function to access the member variable _FileName. _FileName represents the filename of the * headerfile. The path must be included, the file extension may left away. * @return File name of the header file.*/ const FileNameString& getFileName() const; /** Function to access the member variable _FileName. _FileName represents the filename of the * headerfile. The path must be included, the file extension may left away. * @param [in] sFileName The file name of the header file.*/ void setFileName(const FileNameString& sFileName); /** Function to access the member variable _upperSeriesLimit. _upperSeriesLimit represents * the upper limit for the series file search. * @return The upper limit of the series search.*/ const unsigned int getUpperSeriesLimit() const; /** Function to access the member variable _upperSeriesLimit. _upperSeriesLimit represents * the upper limit for the series file search. Changing the series limit out dates the ImageReader. * @remark It is only relevant if series style is set to "Numeric". * @param [in] upperLimit The upper limit of the header file.*/ void setUpperSeriesLimit(const unsigned int upperLimit); /** Function to access the member variable _seriesReadStyle (see member description for more information).*/ const ImageSeriesReadStyle::Type getSeriesReadStyle() const; /** Function to access the member variable _seriesReadStyle (see member description for more information). * Changing the style out dates the ImageReader.*/ void setSeriesReadStyle(ImageSeriesReadStyle::Type readStyle); /** Function loads the image if needed and returns the data. * @return Pointer to loaded image. * @exception map::core::ExceptionObject If no ImageIO is found. * @exception map::core::ExceptionObject If dimension of the image is not supported. Only 2D/3D is supported. * @exception map::core::ExceptionObject If pixel type is not supported. Currently only scalar pixels are supported. * @exception map::core::ExceptionObject If pixel component type is not supported. */ GenericOutputImageType* GetOutput(unsigned int& loadedDimensions, LoadedPixelType& loadedPixelType, LoadedComponentType& loadedComponentType); /** Function returns the reference to the meta data dictionary(ies) of the latest file(s) loaded by this class. * Array may be empty if no MetaDictionary exists.*/ const MetaDataDictionaryArrayType& getMetaDictionaryArray(); protected: GenericImageReader(); ~GenericImageReader() override; }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/itk/rttbITKException.h b/code/io/itk/rttbITKException.h index 0cfb43b..13e66da 100644 --- a/code/io/itk/rttbITKException.h +++ b/code/io/itk/rttbITKException.h @@ -1,49 +1,43 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __ITK_EXCEPTION_H #define __ITK_EXCEPTION_H #include #include "rttbException.h" namespace rttb { namespace io { namespace itk { /*! @class ITKException @brief This class represents a ITKException. Any itk error will throw this exception. */ class ITKException: public core::Exception { public: ITKException(const std::string& aWhat): Exception(aWhat) {} }; } } } #endif diff --git a/code/io/itk/rttbITKIOHelper.cpp b/code/io/itk/rttbITKIOHelper.cpp index f9f56b6..be8ee1d 100644 --- a/code/io/itk/rttbITKIOHelper.cpp +++ b/code/io/itk/rttbITKIOHelper.cpp @@ -1,167 +1,165 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ - #include "rttbITKIOHelper.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace io { namespace itk { ITKImageType::Pointer readITKDoubleImage(FileNameType aITKImageFile, bool isDicom) { ITKImageType::Pointer itkDoubleImage; GenericImageReader::Pointer spReader = GenericImageReader::New(); if (isDicom) { spReader->setSeriesReadStyle(ImageSeriesReadStyle::Type::Dicom); } spReader->setFileName(aITKImageFile); GenericImageReader::GenericOutputImageType::Pointer itkGenericImage; ITKImageType::ConstPointer itkDoubleImageConst; try { unsigned int loadedDimensions; GenericImageReader::LoadedPixelType loadedPixelType; GenericImageReader::LoadedComponentType loadedComponentType; itkGenericImage = spReader->GetOutput(loadedDimensions, loadedPixelType, loadedComponentType); if (loadedDimensions != 3) { throw core::InvalidParameterException("image dimensions != 3. Only dim = 3 supported."); } if (loadedPixelType != ::itk::ImageIOBase::SCALAR) { throw core::InvalidParameterException("image component type != SCALAR. Only SCALAR supported."); } if (loadedComponentType == ::itk::ImageIOBase::DOUBLE) { itkDoubleImage = dynamic_cast(itkGenericImage.GetPointer()); } else { itkDoubleImage = handleGenericImage(itkGenericImage, loadedComponentType); } if (itkDoubleImage.IsNull()) { throw core::InvalidDoseException("Error!!! unable to load input image. File is not existing or has an unsupported format."); } } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; throw rttb::core::InvalidDoseException(e.GetDescription()); } return itkDoubleImage; } ITKImageType::Pointer handleGenericImage( GenericImageReader::GenericOutputImageType* itkGenericImage, ::itk::ImageIOBase::IOComponentType& loadedComponentType) { ITKImageType::Pointer itkDoubleImage; switch (loadedComponentType) { case ::itk::ImageIOBase::UCHAR: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::CHAR: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::USHORT: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::SHORT: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::UINT: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::INT: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::ULONG: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::LONG: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::FLOAT: { itkDoubleImage = doCasting(itkGenericImage); break; } case ::itk::ImageIOBase::DOUBLE: { itkDoubleImage = doCasting(itkGenericImage); break; } default: { throw core::InvalidParameterException("image type unknown"); } } return itkDoubleImage; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKIOHelper.h b/code/io/itk/rttbITKIOHelper.h index eb5598b..7757582 100644 --- a/code/io/itk/rttbITKIOHelper.h +++ b/code/io/itk/rttbITKIOHelper.h @@ -1,60 +1,58 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ #ifndef __ITK_IO_HELPER_H #define __ITK_IO_HELPER_H #include "rttbBaseType.h" #include "rttbGenericImageReader.h" #include "itkImage.h" - - namespace rttb { namespace io { namespace itk { typedef ::itk::Image ITKImageType; /*! @brief Read a itk image file into itkImage */ ITKImageType::Pointer readITKDoubleImage(FileNameType aITKImageFile, bool isDicom = false); /*! @brief Converts a generic image to itkImage @param itkGenericImage the image read by GenericImageReader @param loadedComponentType the component type (used for casting later on) @exception InvalidParameterException if component type is not supported @sa GenericImageReader */ ITKImageType::Pointer handleGenericImage(GenericImageReader::GenericOutputImageType* itkGenericImage, ::itk::ImageIOBase::IOComponentType& loadedComponentType); /*! @brief Casts into itkImage */ template ITKImageType::Pointer doCasting( GenericImageReader::GenericOutputImageType* genericImage); }//end namespace itk }//end namespace io }//end namespace rttb #include "rttbITKIOHelper.tpp" #endif diff --git a/code/io/itk/rttbITKIOHelper.tpp b/code/io/itk/rttbITKIOHelper.tpp index d80a09d..aba6330 100644 --- a/code/io/itk/rttbITKIOHelper.tpp +++ b/code/io/itk/rttbITKIOHelper.tpp @@ -1,65 +1,58 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/include/mapImageReader.tpp $ -*/ #ifndef __RTTB_ITK_IO_HELPER_TPP #define __RTTB_ITK_IO_HELPER_TPP #include "rttbITKImageAccessor.h" #include "itkCastImageFilter.h" namespace rttb { namespace io { namespace itk { template ITKImageType::Pointer doCasting( GenericImageReader::GenericOutputImageType* genericImage) { ITKImageType::Pointer itkDoubleImage; typedef ::itk::Image InputImageType; using OutputImageType = ITKImageType; typename InputImageType::Pointer pCastedInput = dynamic_cast(genericImage); typedef ::itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(pCastedInput); try { //important to update the filter! castFilter->Update(); itkDoubleImage = castFilter->GetOutput(); } catch (::itk::ExceptionObject& e) { std::cerr << "ITK Error!!!" << std::endl; std::cerr << e << std::endl; } return itkDoubleImage; } } } } #endif diff --git a/code/io/itk/rttbITKImageAccessor.cpp b/code/io/itk/rttbITKImageAccessor.cpp index 73f74cc..9ce23cd 100644 --- a/code/io/itk/rttbITKImageAccessor.cpp +++ b/code/io/itk/rttbITKImageAccessor.cpp @@ -1,114 +1,108 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "rttbITKImageAccessor.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace io { namespace itk { ITKImageAccessor::~ITKImageAccessor() = default; ITKImageAccessor::ITKImageAccessor(ITKImageType::ConstPointer image) { _data = image; if (_data.IsNull()) { throw core::InvalidDoseException("Dose image = 0!") ; } assembleGeometricInfo(); } GenericValueType ITKImageAccessor::getValueAt(const VoxelGridID aID) const { VoxelGridIndex3D aVoxelGridIndex; if (_geoInfo.convert(aID, aVoxelGridIndex)) { return getValueAt(aVoxelGridIndex); } else { return -1; } } GenericValueType ITKImageAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { if (_geoInfo.validIndex(aIndex)) { const ITKImageType::IndexType pixelIndex = {{aIndex[0], aIndex[1], aIndex[2]}}; return _data->GetPixel(pixelIndex); } else { return -1; } } void ITKImageAccessor::assembleGeometricInfo() { _geoInfo.setSpacing(SpacingVectorType3D(_data->GetSpacing()[0], _data->GetSpacing()[1], _data->GetSpacing()[2])); if (_geoInfo.getSpacing()[0] == 0 || _geoInfo.getSpacing()[1] == 0 || _geoInfo.getSpacing()[2] == 0) { throw core::InvalidDoseException("Pixel spacing = 0!"); } _geoInfo.setImagePositionPatient(WorldCoordinate3D(_data->GetOrigin()[0], _data->GetOrigin()[1], _data->GetOrigin()[2])); OrientationMatrix OM(0); for (unsigned int col = 0; col < 3; ++col) { for (unsigned int row = 0; row < 3; ++row) { OM(col, row) = _data->GetDirection()(col, row); } } _geoInfo.setOrientationMatrix(OM); _geoInfo.setNumColumns(_data->GetLargestPossibleRegion().GetSize()[0]); _geoInfo.setNumRows(_data->GetLargestPossibleRegion().GetSize()[1]); _geoInfo.setNumSlices(_data->GetLargestPossibleRegion().GetSize()[2]); if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } } } } } diff --git a/code/io/itk/rttbITKImageAccessor.h b/code/io/itk/rttbITKImageAccessor.h index a02a26d..655a759 100644 --- a/code/io/itk/rttbITKImageAccessor.h +++ b/code/io/itk/rttbITKImageAccessor.h @@ -1,89 +1,84 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_ACCESSOR_H #define __ITK_IMAGE_ACCESSOR_H #include "rttbAccessorWithGeoInfoBase.h" #include "rttbBaseType.h" #include "itkImage.h" #include "RTTBITKIOExports.h" namespace rttb { namespace io { namespace itk { /*! @class ITKImageAccessor @brief This class gives access to information stored in an itk image @details There is no value scaling, i.e., it is assumed that the values in the itkImage are absolute. */ class RTTBITKIO_EXPORT ITKImageAccessor : public core::AccessorWithGeoInfoBase { public: typedef ::itk::Image ITKImageType; private: /** @brief The dose as itkImage */ ITKImageType::ConstPointer _data; IDType _UID; /*! @brief constructor @exception InvalidDoseException if _dose is nullptr */ ITKImageAccessor() = delete; /*! @brief get all required data from the itk image contained in _dose @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. */ void assembleGeometricInfo() override; public: ~ITKImageAccessor() override; /*! @brief Constructor. Initialization with a itk image @pre image must be a valid instance (and !nullptr) @note the doseImage pixels are assumed absolute */ ITKImageAccessor(ITKImageType::ConstPointer image); /*! @brief returns the dose for an id */ GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief returns the dose for an index */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return _UID; }; }; } } } #endif diff --git a/code/io/itk/rttbITKImageAccessorConverter.cpp b/code/io/itk/rttbITKImageAccessorConverter.cpp index cf1caae..64aead4 100644 --- a/code/io/itk/rttbITKImageAccessorConverter.cpp +++ b/code/io/itk/rttbITKImageAccessorConverter.cpp @@ -1,111 +1,105 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbITKImageAccessorConverter.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "itkDoseAccessorImageFilter.h" namespace rttb { namespace io { namespace itk { ITKImageAccessorConverter::ITKImageAccessorConverter(DoseAccessorPointer accessor) { setDoseAccessor(accessor); } bool ITKImageAccessorConverter::process() { //Transfer GeometricInfo to ITK Properties core::GeometricInfo geoInfo = _doseAccessor->getGeometricInfo(); ITKImageType::RegionType region; ITKImageType::IndexType start; for (unsigned int i = 0; i < 3; ++i) { start[i] = 0; } ITKImageType::SizeType size; size[0] = geoInfo.getNumColumns(); size[1] = geoInfo.getNumRows(); size[2] = geoInfo.getNumSlices(); ITKImageType::SpacingType spacing; for (unsigned int i = 0; i < 3; ++i) { spacing[i] = geoInfo.getSpacing()[i]; } ITKImageType::PointType origin; for (unsigned int i = 0; i < 3; ++i) { origin[i] = geoInfo.getImagePositionPatient()[i]; } ITKImageType::DirectionType direction; OrientationMatrix OM = geoInfo.getOrientationMatrix(); for (unsigned int col = 0; col < 3; ++col) { for (unsigned int row = 0; row < 3; ++row) { direction(col, row) = OM(col, row); } } //Create image, assign properties region.SetSize(size); region.SetIndex(start); _itkImage = ITKImageType::New(); _itkImage->SetRegions(region); _itkImage->SetSpacing(spacing); _itkImage->SetDirection(direction); _itkImage->SetOrigin(origin); _itkImage->Allocate(); ::itk::DoseAccessorImageFilter::Pointer accessorFilter = ::itk::DoseAccessorImageFilter::New(); accessorFilter->SetInput(_itkImage); accessorFilter->SetAccessor(_doseAccessor); accessorFilter->Update(); _itkImage = accessorFilter->GetOutput(); return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageAccessorConverter.h b/code/io/itk/rttbITKImageAccessorConverter.h index 2ff380c..a4be81a 100644 --- a/code/io/itk/rttbITKImageAccessorConverter.h +++ b/code/io/itk/rttbITKImageAccessorConverter.h @@ -1,69 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_ACCESSOR_CONVERTER_H #define __ITK_IMAGE_ACCESSOR_CONVERTER_H #include "rttbDoseAccessorProcessorBase.h" #include "rttbDoseAccessorConversionSettingInterface.h" #include "itkImage.h" #include "RTTBITKIOExports.h" + namespace rttb { namespace io { namespace itk { /*! @class ITKImageAccessorConverter @brief Class converts/dumps the processed accessor into an itk image @remark DoseAccessorConversionInterface defines how the converter should react on non valid dose values. */ class RTTBITKIO_EXPORT ITKImageAccessorConverter : public core::DoseAccessorProcessorBase, public core::DoseAccessorConversionSettingInterface { public: typedef ::itk::Image ITKImageType; using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; bool process() override; ITKImageType::Pointer getITKImage() { return _itkImage; } ITKImageAccessorConverter(DoseAccessorPointer accessor); ~ITKImageAccessorConverter() override = default; private: ITKImageAccessorConverter(const ITKImageAccessorConverter&) = delete; //not implemented on purpose -> non-copyable ITKImageAccessorConverter& operator=(const ITKImageAccessorConverter&) = delete;//not implemented on purpose -> non-copyable ITKImageType::Pointer _itkImage; }; } } } #endif diff --git a/code/io/itk/rttbITKImageAccessorGenerator.cpp b/code/io/itk/rttbITKImageAccessorGenerator.cpp index f47270e..3012752 100644 --- a/code/io/itk/rttbITKImageAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageAccessorGenerator.cpp @@ -1,60 +1,53 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "rttbITKImageAccessor.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" - namespace rttb { namespace io { namespace itk { ITKImageAccessorGenerator::ITKImageAccessorGenerator(const ITKImageType* aDoseImage) { if (aDoseImage == nullptr) { throw core::InvalidDoseException("doseImage is nullptr"); } _dosePtr = aDoseImage; } core::DoseAccessorGeneratorBase::DoseAccessorPointer ITKImageAccessorGenerator::generateDoseAccessor() { _doseAccessor = boost::make_shared(_dosePtr); return _doseAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageAccessorGenerator.h b/code/io/itk/rttbITKImageAccessorGenerator.h index 82a527d..e972f20 100644 --- a/code/io/itk/rttbITKImageAccessorGenerator.h +++ b/code/io/itk/rttbITKImageAccessorGenerator.h @@ -1,71 +1,66 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_ACCESSOR_GENERATOR_H #include "rttbDoseAccessorGeneratorBase.h" #include "itkImage.h" #include "RTTBITKIOExports.h" namespace rttb { namespace io { namespace itk { /*! @class ITKImageAccessorGenerator @brief Generate ITKImageAccessor wrapping an itk image as object (not as file). @note it implies that the information is stored in absolute values. */ class RTTBITKIO_EXPORT ITKImageAccessorGenerator : public core::DoseAccessorGeneratorBase { public: typedef ::itk::Image ITKImageType; using DoseAccessorPointer = DoseAccessorGeneratorBase::DoseAccessorPointer; private: /** @brief The dose as itkImage */ ITKImageType::ConstPointer _dosePtr; ITKImageAccessorGenerator() = delete; public: ~ITKImageAccessorGenerator() override = default; /*! @pre aDoseImage must point to a valid instance. @exception InvalidDoseException Thrown if aDoseImage is invalid. */ ITKImageAccessorGenerator(const ITKImageType* aDoseImage); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. */ DoseAccessorPointer generateDoseAccessor() override ; }; } } } #endif diff --git a/code/io/itk/rttbITKImageFileAccessorGenerator.cpp b/code/io/itk/rttbITKImageFileAccessorGenerator.cpp index 0e11d04..03f4395 100644 --- a/code/io/itk/rttbITKImageFileAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageFileAccessorGenerator.cpp @@ -1,49 +1,48 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ #include #include #include "rttbITKImageFileAccessorGenerator.h" #include "rttbITKImageAccessorConverter.h" #include "rttbITKIOHelper.h" - namespace rttb { namespace io { namespace itk { ITKImageFileAccessorGenerator::~ITKImageFileAccessorGenerator() = default; ITKImageFileAccessorGenerator::ITKImageFileAccessorGenerator(const FileNameType& fileName, const bool& useDicom) { _fileName = fileName; _useDicom = useDicom; } rttb::core::DoseAccessorGeneratorBase::DoseAccessorPointer ITKImageFileAccessorGenerator::generateDoseAccessor() { _itkDoubleImage = readITKDoubleImage(_fileName, _useDicom); _doseAccessor = boost::make_shared(_itkDoubleImage.GetPointer()); return _doseAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageFileAccessorGenerator.h b/code/io/itk/rttbITKImageFileAccessorGenerator.h index 3425aa9..e290ac0 100644 --- a/code/io/itk/rttbITKImageFileAccessorGenerator.h +++ b/code/io/itk/rttbITKImageFileAccessorGenerator.h @@ -1,73 +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. // //------------------------------------------------------------------------ #ifndef __ITK_IMAGE_FILE_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_FILE_ACCESSOR_GENERATOR_H #include "rttbDoseAccessorGeneratorBase.h" #include "rttbBaseType.h" #include "itkImage.h" - namespace rttb { namespace io { namespace itk { /*! @class ITKImageFileAccessorGenerator @brief Load image data using the itk loading methods and wraps the resulting itk image in a ITKImageAccessor. * this can be used if dose distributions are stored in formats like meta image, nrrd... * @note it implies that the dose information is stored in absolute Gy values. */ class ITKImageFileAccessorGenerator: public core::DoseAccessorGeneratorBase { public: typedef ::itk::Image ITKImageType; using DoseAccessorPointer = DoseAccessorGeneratorBase::DoseAccessorPointer; private: FileNameType _fileName; /** @brief The dose as itkImage */ ITKImageType::Pointer _itkDoubleImage; bool _useDicom; ITKImageFileAccessorGenerator() = delete; public: ~ITKImageFileAccessorGenerator() override; ITKImageFileAccessorGenerator(const FileNameType& fileName, const bool& useDicom = false); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. @exception InvalidDoseException Thrown if file could not be read @exception InvalidParameterException Thrown if file has imageDimension !=3 or image component type != SCALAR @details is always converted into a itkImage by using a CastImageFilter @sa doCasting, handleGenericImage */ DoseAccessorPointer generateDoseAccessor() override; }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp index 6c19ee0..b1dfd6f 100644 --- a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp @@ -1,57 +1,50 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "../itk/rttbITKIOHelper.h" - namespace rttb { namespace io { namespace itk { ITKImageFileMaskAccessorGenerator::~ITKImageFileMaskAccessorGenerator() = default; ITKImageFileMaskAccessorGenerator::ITKImageFileMaskAccessorGenerator(const FileNameType& fileName) { _itkMaskFileName = fileName; } rttb::core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageFileMaskAccessorGenerator::generateMaskAccessor() { _itkDoubleImage = rttb::io::itk::readITKDoubleImage(_itkMaskFileName); _maskAccessor = boost::make_shared(_itkDoubleImage.GetPointer()); return _maskAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h index aa09e6e..2593c53 100644 --- a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h +++ b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h @@ -1,73 +1,67 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_MASK_FILE_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_MASK_FILE_ACCESSOR_GENERATOR_H #include "rttbMaskAccessorGeneratorBase.h" #include "rttbBaseType.h" #include "rttbITKImageMaskAccessor.h" - namespace rttb { namespace io { namespace itk { /*! @class ITKImageFileMaskAccessorGenerator @brief Load 3D Mask data using the itk loading methods and wraps the resulting itk image in a ITKImageMaskAccessor. * this is normally used if Mask distributions are stored in formats like meta image, nrrd... */ class ITKImageFileMaskAccessorGenerator: public core::MaskAccessorGeneratorBase { public: using MaskAccessorPointer = MaskAccessorGeneratorBase::MaskAccessorPointer; private: FileNameType _itkMaskFileName; /** @brief The mask as itkImage */ ITKImageMaskAccessor::ITKMaskImageType::Pointer _itkDoubleImage; ITKImageFileMaskAccessorGenerator() = delete; public: ~ITKImageFileMaskAccessorGenerator() override; ITKImageFileMaskAccessorGenerator(const FileNameType& fileName); /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. @exception InvalidDoseException Thrown if file could not be read @exception InvalidParameterException Thrown if file has imageDimension !=3 or image component type != SCALAR @details is always converted into a itkImage by using a CastImageFilter @sa doCasting, handleGenericImage */ MaskAccessorPointer generateMaskAccessor() override; }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/itk/rttbITKImageMaskAccessor.cpp b/code/io/itk/rttbITKImageMaskAccessor.cpp index e9f7551..830af89 100644 --- a/code/io/itk/rttbITKImageMaskAccessor.cpp +++ b/code/io/itk/rttbITKImageMaskAccessor.cpp @@ -1,176 +1,170 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbITKImageMaskAccessor.h" #include "rttbGeometricInfo.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace io { namespace itk { ITKImageMaskAccessor::ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage) : _mask(aMaskImage) { if (_mask.IsNull()) { throw core::InvalidDoseException("Mask image = 0!") ; } assembleGeometricInfo(); } ITKImageMaskAccessor::~ITKImageMaskAccessor() = default; bool ITKImageMaskAccessor::assembleGeometricInfo() { _geoInfo = boost::make_shared(); _geoInfo->setSpacing(SpacingVectorType3D(_mask->GetSpacing()[0], _mask->GetSpacing()[1], _mask->GetSpacing()[2])); if (_geoInfo->getSpacing()[0] == 0 || _geoInfo->getSpacing()[1] == 0 || _geoInfo->getSpacing()[2] == 0) { throw core::InvalidDoseException("Pixel spacing = 0!"); } _geoInfo->setImagePositionPatient(WorldCoordinate3D(_mask->GetOrigin()[0], _mask->GetOrigin()[1], _mask->GetOrigin()[2])); OrientationMatrix OM(0); for (unsigned int col = 0; col < 3; ++col) { for (unsigned int row = 0; row < 3; ++row) { OM(col, row) = _mask->GetDirection()(col, row); } } _geoInfo->setOrientationMatrix(OM); _geoInfo->setNumColumns(_mask->GetLargestPossibleRegion().GetSize()[0]); _geoInfo->setNumRows(_mask->GetLargestPossibleRegion().GetSize()[1]); _geoInfo->setNumSlices(_mask->GetLargestPossibleRegion().GetSize()[2]); if (_geoInfo->getNumColumns() == 0 || _geoInfo->getNumRows() == 0 || _geoInfo->getNumSlices() == 0) { throw core::InvalidDoseException("Empty mask!") ; } return true; } void ITKImageMaskAccessor::updateMask() { return; } ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector() { updateMask(); _relevantVoxelVector = getRelevantVoxelVector(0); return _relevantVoxelVector; } ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector( float lowerThreshold) { auto filteredVoxelVectorPointer = boost::make_shared(); updateMask(); unsigned int size = _geoInfo->getNumColumns() * _geoInfo->getNumRows() * _geoInfo->getNumSlices(); filteredVoxelVectorPointer->reserve(size); for (unsigned int gridIndex = 0 ; gridIndex < size; gridIndex++) { core::MaskVoxel currentVoxel = core::MaskVoxel(gridIndex); if (getMaskAt(gridIndex, currentVoxel)) { if (currentVoxel.getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(currentVoxel); } } } return filteredVoxelVectorPointer; } bool ITKImageMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { VoxelGridIndex3D aVoxelGridIndex; if (_geoInfo->convert(aID, aVoxelGridIndex)) { return getMaskAt(aVoxelGridIndex, voxel); } else { return false; } } bool ITKImageMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { voxel.setRelevantVolumeFraction(0); if (_geoInfo->validIndex(aIndex)) { const ITKMaskImageType::IndexType pixelIndex = {{aIndex[0], aIndex[1], aIndex[2]}}; double value = _mask->GetPixel(pixelIndex); VoxelGridID gridId; _geoInfo->convert(aIndex, gridId); if (value >= 0 && value <= 1) { voxel.setRelevantVolumeFraction(value); return true; } else { std::cerr << "The pixel value of the mask should be >=0 and <=1!" << std::endl; return false; } } else { return false; } } const core::GeometricInfo& ITKImageMaskAccessor::getGeometricInfo() const { return *_geoInfo; }; } } } diff --git a/code/io/itk/rttbITKImageMaskAccessor.h b/code/io/itk/rttbITKImageMaskAccessor.h index 19ed4ee..2dca57c 100644 --- a/code/io/itk/rttbITKImageMaskAccessor.h +++ b/code/io/itk/rttbITKImageMaskAccessor.h @@ -1,120 +1,115 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_MASK_ACCESSOR_H #define __ITK_IMAGE_MASK_ACCESSOR_H #include "rttbMaskAccessorInterface.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "itkImage.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace io { namespace itk { /*! @class ITKImageMaskAccessor @brief This class gives access to mask information stored in an itk image */ class ITKImageMaskAccessor: public core::MaskAccessorInterface { public: typedef ::itk::Image ITKMaskImageType; using ITKImageBaseType = ::itk::ImageBase<3>; using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; private: /** @brief The mask as itkImage */ ITKMaskImageType::ConstPointer _mask; IDType _maskUID; core::GeometricInfo::Pointer _geoInfo; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _relevantVoxelVector; /*! @brief get all required data from the itk image contained in _Mask @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. */ bool assembleGeometricInfo(); public: ~ITKImageMaskAccessor() override; ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage); /*! @brief voxelization of the given structures according to the original RTToolbox algorithm*/ void updateMask() override; /*! @brief get vector conatining al relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector() override; /*! @brief get vector conatining al relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold) override; /*!@brief determine how a given voxel on the dose grid is masked * @param aID ID of the voxel in grid. * @param voxel Reference to the voxel. * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. * The relevant volume fraction will be set to zero. * @return Indicates of the voxel exists and therefore if parameter voxel contains valid values.*/ bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const override; bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const override; /*! @brief give access to GeometricInfo*/ const core::GeometricInfo& getGeometricInfo() const override; /* @ brief is true if Mask is on a homogeneous grid */ // Inhomogeneous grids are not supported at the moment, but if they will // be supported in the future the interface does not need to change. bool isGridHomogeneous() const override { return true; }; IDType getMaskUID() const override { return _maskUID; }; }; } } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/io/itk/rttbITKImageMaskAccessorConverter.cpp b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp index 44c2873..7982d28 100644 --- a/code/io/itk/rttbITKImageMaskAccessorConverter.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp @@ -1,92 +1,85 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include #include "rttbITKImageMaskAccessorConverter.h" #include "rttbGeometricInfo.h" #include "itkMaskAccessorImageSource.h" namespace rttb { namespace io { namespace itk { ITKImageMaskAccessorConverter::ITKImageMaskAccessorConverter(MaskAccessorPointer accessor) { setMaskAccessor(accessor); } bool ITKImageMaskAccessorConverter::process() { //Transfer GeometricInfo to ITK Properties core::GeometricInfo geoInfo = _maskAccessor->getGeometricInfo(); ITKImageMaskAccessor::ITKMaskImageType::IndexType start = {{0, 0, 0}}; ITKImageMaskAccessor::ITKMaskImageType::SizeType size = {{geoInfo.getNumColumns(), geoInfo.getNumRows(), geoInfo.getNumSlices()}}; ITKImageMaskAccessor::ITKMaskImageType::SpacingType spacing; for (unsigned int i = 0; i < 3; ++i) { spacing[i] = geoInfo.getSpacing()[i]; } ITKImageMaskAccessor::ITKMaskImageType::PointType origin; for (unsigned int i = 0; i < 3; ++i) { origin[i] = geoInfo.getImagePositionPatient()[i]; } ITKImageMaskAccessor::ITKMaskImageType::DirectionType direction; OrientationMatrix OM = geoInfo.getOrientationMatrix(); for (unsigned int col = 0; col < 3; ++col) { for (unsigned int row = 0; row < 3; ++row) { direction(col, row) = OM(col, row); } } ::itk::MaskAccessorImageSource::Pointer imagesource = ::itk::MaskAccessorImageSource::New(); imagesource->SetSize(size); imagesource->SetSpacing(spacing); imagesource->SetDirection(direction); imagesource->SetOrigin(origin); imagesource->SetAccessor(_maskAccessor); imagesource->SetFailsOnInvalidIDs(failsOnInvalidIDs()); imagesource->SetInvalidMaskValue(_invalidDoseValue); imagesource->Update(); _itkImage = imagesource->GetOutput(); return true; } }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageMaskAccessorConverter.h b/code/io/itk/rttbITKImageMaskAccessorConverter.h index 9bde713..fba46e6 100644 --- a/code/io/itk/rttbITKImageMaskAccessorConverter.h +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.h @@ -1,70 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #define __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorProcessorBase.h" #include "../itk/rttbDoseAccessorConversionSettingInterface.h" #include "RTTBITKIOExports.h" namespace rttb { namespace io { namespace itk { /*! @class ITKImageMaskAccessorConverter @brief Class converts/dumps the processed accessor into an itk image @remark MaskAccessorConversionInterface defines how the converter should react on non valid Mask values. */ class RTTBITKIO_EXPORT ITKImageMaskAccessorConverter : public core::MaskAccessorProcessorBase, public rttb::core::DoseAccessorConversionSettingInterface { public: using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; bool process() override; const ITKImageMaskAccessor::ITKMaskImageType::Pointer getITKImage() { return _itkImage; } ITKImageMaskAccessorConverter(MaskAccessorPointer accessor); ~ITKImageMaskAccessorConverter() override = default; private: ITKImageMaskAccessorConverter(const ITKImageMaskAccessorConverter&) = delete; //not implemented on purpose -> non-copyable ITKImageMaskAccessorConverter& operator=(const ITKImageMaskAccessorConverter&) = delete;//not implemented on purpose -> non-copyable ITKImageMaskAccessor::ITKMaskImageType::Pointer _itkImage; }; } } } #endif diff --git a/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp index b649b5d..102605d 100644 --- a/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp @@ -1,59 +1,51 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include #include #include "rttbITKImageMaskAccessorGenerator.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" - namespace rttb { namespace io { namespace itk { ITKImageMaskAccessorGenerator::ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage) { if (aMaskImage == nullptr) { throw core::InvalidDoseException("MaskImage is nullptr"); } _maskPtr = aMaskImage; } core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageMaskAccessorGenerator::generateMaskAccessor() { _maskAccessor = boost::make_shared(_maskPtr); return _maskAccessor; } }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageMaskAccessorGenerator.h b/code/io/itk/rttbITKImageMaskAccessorGenerator.h index 1a82579..f93dddd 100644 --- a/code/io/itk/rttbITKImageMaskAccessorGenerator.h +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.h @@ -1,68 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorGeneratorBase.h" #include "RTTBITKIOExports.h" namespace rttb { namespace io { namespace itk { /*! @class ITKImageMaskAccessorGenerator @brief Generate ITKImageMaskAccessor wrapping an itk image as object (not as file). */ class RTTBITKIO_EXPORT ITKImageMaskAccessorGenerator : public core::MaskAccessorGeneratorBase { public: using MaskAccessorPointer = MaskAccessorGeneratorBase::MaskAccessorPointer; private: /** @brief The Mask as itkImage */ ITKImageMaskAccessor::ITKMaskImageType::ConstPointer _maskPtr; ITKImageMaskAccessorGenerator() = delete; public: ~ITKImageMaskAccessorGenerator() override = default; /*! @pre aMaskImage must point to a valid instance. @exception InvalidDoseException Thrown if aMaskImage is invalid. */ ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage); /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. */ MaskAccessorPointer generateMaskAccessor() override ; }; } } } #endif diff --git a/code/io/itk/rttbImageReader.h b/code/io/itk/rttbImageReader.h index df3db02..ca9153c 100644 --- a/code/io/itk/rttbImageReader.h +++ b/code/io/itk/rttbImageReader.h @@ -1,224 +1,216 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/include/mapImageReader.h $ -*/ - #ifndef __RTTB_IMAGE_READER_H #define __RTTB_IMAGE_READER_H #include "itkImage.h" #include "itkImageSource.h" namespace rttb { namespace io { namespace itk { struct ImageSeriesReadStyle { enum Type { Default = 0, //* - Depending on the file extension (DICOM images (*.dcm, *.ima): Dicom; others: None; No image file: Dicom) None = 1, //* - No series reading, only the specified file Dicom = 2, //* - Use series reader and DCMTKSeriesFileNames Numeric = 3, //* - Use series reader and NumericSeriesFileNames GDCM = 4 //* - Use series reader and GDCMSeriesFileNames }; }; /** @class ImageReader * @brief Helper class manages the loading of 2D/3D images based on itk but with some convenience features ... * * ImageReader is used to load 2D or 3D images in an itk like style, but also offers * some convenience features and the specialties of different formats into account.\n * 2D images will be loaded directly by the IO classes of itk, so in this case the * ImageReader is only a layer of abstraction.\n * 3D images will be handled different, depending on the type of files and the chosen * series read style:\n * - Default: Depending on the file extension (DICOM images (*.dcm, *.ima): Dicom; others: None; No image file: Dicom * - None: directly by the itk io (no series reading) * - Dicom: uses itk series reader, currently a list of files will be generated that is similar to GDCM (old ::itk::DICOMKSeriesFileNames is not supported any more by itk > 4.3.x.) * - GDCM: uses itk series reader, the list of files will be generated * by the ::itk::GDCMSeriesFileNames in the specified path ordered by * imagePositionPatient. * - Numeric: Will be considered as series of images. The list of files will be * created by ::itk::NumericSeriesFileNames, so in this case the given * file name is already masked by %d for the increasing index within * the file name. * . * @note code copied from MatchPoint, see documentation (http://sourceforge.net/projects/matchpoint/) */ template class ImageReader { public: typedef ::itk::Image InputImageType; typedef ::itk::Image OutputImageType; using RescaleValueType = TInputPixel; using MetaDataDictionaryArrayType = std::vector< ::itk::MetaDataDictionary>; using String = std::string; using OStringStream = std::ostringstream; using IStringStream = std::istringstream; virtual const char* GetNameOfClass() const { return "ImageReader"; } private: /** Loaded Image.*/ typename OutputImageType::Pointer _spImage; /** The file name of the image. */ String _fileName; /** The upper limit for the searching of series files in the path.*/ unsigned int _upperSeriesLimit; /** Indicates if the image data is up to date or should be read again.*/ bool _upToDate; /** Indicates if the output image intensity should be rescaled.*/ bool _rescaleImage; /** Indicates the minimum of the output.*/ RescaleValueType _rescaleMin; /** Indicates the maximum of the output.*/ RescaleValueType _rescaleMax; /** Defines if the specified image file is part of a series and the * whole series should be read into one image. Only relevant for 3D images.*/ typename ImageSeriesReadStyle::Type _seriesReadStyle; MetaDataDictionaryArrayType _dictionaryArray; void load2D(); typename ::itk::ImageSource::Pointer prepareNumericSource() const; typename ::itk::ImageSource::Pointer prepareDICOMSource() const; typename ::itk::ImageSource::Pointer prepareNormalSource() const; typename ::itk::ImageSource::Pointer prepareGDCMSource() const; void load3D(); using ITKMetaDataDictionaryArray = std::vector< ::itk::MetaDataDictionary *>; void copyMetaDictionaryArray(const ITKMetaDataDictionaryArray* fromArray, MetaDataDictionaryArrayType& toArray); public: /** Function to access the member variable _FileName. _FileName represents the filename of the * headerfile. The path must be included, the file extension may left away. * @return File name of the header file.*/ const String& getFileName() const; /** Function to access the member variable _FileName. _FileName represents the filename of the * headerfile. The path must be included, the file extension may left away. * @param [in] sFileName The file name of the header file.*/ void setFileName(const String& sFileName); /** Function to access the member variable _rescaleMin. _rescaleMin represents * the minimum of the intensity rescale filter. * @return The minimum of the intensity rescale filter.*/ const RescaleValueType& getRescaleMinimum() const; /** Function to access the member variable _rescaleMin. _rescaleMin represents * the minimum of the intensity rescale filter. Changing the rescale minimum out dates the ImageReader. * @param [in] rescaleMin The minimum of the intensity rescale filter.*/ void setRescaleMinimum(const RescaleValueType& rescaleMin); /** Function to access the member variable _rescaleMin. _rescaleMax represents * the minimum of the intensity rescale filter. * @return The minimum of the intensity rescale filter.*/ const RescaleValueType& getRescaleMaximum() const; /** Function to access the member variable _rescaleMin. _rescaleMax represents * the minimum of the intensity rescale filter. Changing the rescale maximum out dates the ImageReader. * @param [in] rescaleMax The minimum of the intensity rescale filter.*/ void setRescaleMaximum(const RescaleValueType& rescaleMax); /** Function to access the member variable _rescaleImage. _rescaleImage indicates if a * loaded image should be rescaled regarding its intensities. * @return If the ImageReader converts images to iso-voxel.*/ const bool getRescaleImage() const; /** Function to access the member variable _rescaleImage. _rescaleImage indicates if a * loaded image should be rescaled regarding its intensities. Changing the rescale option out dates the ImageReader. * @param [in] rescaleImage Specifies if image should be converted to isovoxel.*/ void setRescaleImage(const bool rescaleImage); /** Function to access the member variable _upperSeriesLimit. _upperSeriesLimit represents * the upper limit for the series file search. * @return The upper limit of the series search.*/ const unsigned int getUpperSeriesLimit() const; /** Function to access the member variable _upperSeriesLimit. _upperSeriesLimit represents * the upper limit for the series file search. Changing the series limit out dates the ImageReader. * @remark It is only relevant if series style is set to "Numeric". * @param [in] upperLimit The upper limit of the header file.*/ void setUpperSeriesLimit(const unsigned int upperLimit); /** Function to access the member variable _seriesReadStyle (see member description for more information).*/ const typename ImageSeriesReadStyle::Type getSeriesReadStyle() const; /** Function to access the member variable _seriesReadStyle (see member description for more information). * Changing the style out dates the ImageReader.*/ void setSeriesReadStyle(typename ImageSeriesReadStyle::Type readStyle); /** Function loads the image if needed and returns the data. * @return Pointer to loaded image.*/ OutputImageType* GetOutput(); /** Function returns the reference to the meta data dictionary(ies) of the latest file(s) loaded by this class. * Array may be empty if no MetaDictionary exists.*/ const MetaDataDictionaryArrayType& getMetaDictionaryArray(); ImageReader(); virtual ~ImageReader(); }; /** * @brief Helper function for the use of ImageReader in on statement ... * * for specific informations please see the documentation of ImageReader. * @param pLoadedDictArray Pass a pointer to valid array to receive the meta dictionaries * loaded with the image. If the pointer is null, no dictionaries will be transfered. The array * will be reseted before the loaded dictionaries will be added. * @sa ImageReader * @ingroup Utils */ template typename ImageReader::OutputImageType::Pointer readImage(const std::string& fileName, ImageSeriesReadStyle::Type readStyle = ImageSeriesReadStyle::Default, bool rescaleImage = false, typename ImageReader::RescaleValueType rescaleMin = 0, typename ImageReader::RescaleValueType rescaleMax = 255, unsigned int upperNumericSeriesLimit = 100, typename ImageReader::MetaDataDictionaryArrayType* pLoadedDictArray = NULL); }//end namespace itk }//end namespace io }//end namespace rttb #include "rttbImageReader.tpp" #endif diff --git a/code/io/itk/rttbImageReader.tpp b/code/io/itk/rttbImageReader.tpp index 2611246..7a1f9ee 100644 --- a/code/io/itk/rttbImageReader.tpp +++ b/code/io/itk/rttbImageReader.tpp @@ -1,532 +1,524 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -// Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/include/mapImageReader.tpp $ -*/ #ifndef __RTTB_IMAGE_READER_TPP #define __RTTB_IMAGE_READER_TPP #include "rttbImageReader.h" #include "rttbFileDispatch.h" #include "RTToolboxConfigure.h" #ifdef RTTB_DISABLE_ITK_IO_FACTORY_AUTO_REGISTER #undef ITK_IO_FACTORY_REGISTER_MANAGER #endif #include "itkImageFileReader.h" #include "itkImageSeriesReader.h" #include "itkImageSeriesWriter.h" #include "itkNumericSeriesFileNames.h" #include "itkGDCMSeriesFileNames.h" #include "itkRescaleIntensityImageFilter.h" #include "itkCastImageFilter.h" #include "itkFixedArray.h" #include "itksys/SystemTools.hxx" #include #include - namespace rttb { namespace io { namespace itk { template void ImageReader:: load2D() { using ImageReaderType = ::itk::ImageFileReader< InputImageType >; typedef ::itk::RescaleIntensityImageFilter< InputImageType, InputImageType > RescaleFilterType; typedef ::itk::CastImageFilter< InputImageType, OutputImageType > CastFilterType; typename CastFilterType::Pointer imageCaster = CastFilterType::New(); typename ImageReaderType::Pointer imageReader = ImageReaderType::New(); typename RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); rescaleFilter->SetOutputMinimum(static_cast(_rescaleMin)); rescaleFilter->SetOutputMaximum(static_cast(_rescaleMax)); imageReader->SetFileName(_fileName.c_str()); rescaleFilter->SetInput(imageReader->GetOutput()); if (_rescaleImage) { imageCaster->SetInput(rescaleFilter->GetOutput()); } else { imageCaster->SetInput(imageReader->GetOutput()); } _spImage = imageCaster->GetOutput(); imageCaster->Update(); _dictionaryArray.clear(); _dictionaryArray.push_back(imageReader->GetImageIO()->GetMetaDataDictionary()); _upToDate = true; }; template const typename ImageReader::MetaDataDictionaryArrayType& ImageReader:: getMetaDictionaryArray() { return _dictionaryArray; }; template void ImageReader:: copyMetaDictionaryArray(const ITKMetaDataDictionaryArray* fromArray, MetaDataDictionaryArrayType& toArray) { toArray.clear(); auto itr = fromArray->begin(); auto end = fromArray->end(); while (itr != end) { toArray.push_back(*(*itr)); ++itr; } }; template typename ::itk::ImageSource::InputImageType>::Pointer ImageReader:: prepareNumericSource() const { //mumeric series image reader using SeriesReaderType = ::itk::ImageSeriesReader; using NamesType = ::itk::NumericSeriesFileNames; typename SeriesReaderType::Pointer seriesReader = SeriesReaderType::New(); NamesType::Pointer names = NamesType::New(); names->SetStartIndex(1); names->SetEndIndex(_upperSeriesLimit); names->SetSeriesFormat(_fileName.c_str()); seriesReader->SetFileNames(names->GetFileNames()); if (seriesReader->GetFileNames().size() == 0) { throw ::itk::ExceptionObject("Image reader is not correctly configured. Preparing a series reading of a numeric source no(!) files were found."); } typename ::itk::ImageSource::InputImageType>::Pointer genericReader = seriesReader.GetPointer(); return genericReader; }; template typename ::itk::ImageSource::InputImageType>::Pointer ImageReader:: prepareDICOMSource() const { //ITK > v4.3.x removed old DICOMSeriesFileNames. Thus currently only support GDCM as source by default return prepareGDCMSource(); }; template typename ::itk::ImageSource::InputImageType>::Pointer ImageReader:: prepareGDCMSource() const { core::FileDispatch dispatch(_fileName); FileNameString dir = dispatch.getPath(); FileNameString strippedFileName = dispatch.getFullName(); using NamesGeneratorType = ::itk::GDCMSeriesFileNames; NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New(); nameGenerator->SetInputDirectory(dir); nameGenerator->SetUseSeriesDetails(true); ::itk::FilenamesContainer fileNames; if (strippedFileName.empty()) { std::cerr << "No file name specified. Use first DICOM series found in directory." << std::endl; fileNames = nameGenerator->GetInputFileNames(); } else { ::itk::SerieUIDContainer seriesUIDs = nameGenerator->GetSeriesUIDs(); std::cerr << "Checking found DICOM series." << std::endl; //check the found series for the filename to pick the right series correlated to the passed filename while (seriesUIDs.size() > 0) { fileNames = nameGenerator->GetFileNames(seriesUIDs.back()); std::cerr << "Checking series: " << seriesUIDs.back() << " (file count: " << fileNames.size() << ")" << std::endl; seriesUIDs.pop_back(); for (::itk::SerieUIDContainer::const_iterator pos = fileNames.begin(); pos != fileNames.end(); ++pos) { if (pos->find(strippedFileName) != FileNameString::npos) { //this series containes the passed filename -> //we have the right block of files -> we are done. std::cerr << "Found right series!" << std::endl; seriesUIDs.clear(); break; } } } } using SeriesReaderType = ::itk::ImageSeriesReader; typename SeriesReaderType::Pointer seriesReader = SeriesReaderType::New(); seriesReader->SetFileNames(fileNames); if (seriesReader->GetFileNames().size() == 0) { throw ::itk::ExceptionObject("Image reader is not correctly configured. Preparing a series reading of a DICOM source no(!) dicom files were found. search location: " + _fileName); } typename ::itk::ImageSource::InputImageType>::Pointer genericReader = seriesReader.GetPointer(); return genericReader; }; template typename ::itk::ImageSource::InputImageType>::Pointer ImageReader:: prepareNormalSource() const { //Normal image reader (no series read style) using ImageReaderType = ::itk::ImageFileReader< InputImageType >; typename ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(_fileName.c_str()); typename ::itk::ImageSource::InputImageType>::Pointer genericReader = imageReader.GetPointer(); return genericReader; }; template void ImageReader:: load3D() { core::FileDispatch dispatch(_fileName); FileNameString sTemp = dispatch.getExtension(); //Convert to lowercase for (char & spos : sTemp) { spos = std::tolower(spos, std::locale("")); } typedef ::itk::RescaleIntensityImageFilter< InputImageType, InputImageType > RescaleFilterType; typedef ::itk::CastImageFilter< InputImageType, OutputImageType > CastFilterType; typename CastFilterType::Pointer imageCaster = CastFilterType::New(); typename RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); typename ::itk::ImageSource::Pointer spReader; rescaleFilter->SetOutputMinimum(static_cast(_rescaleMin)); rescaleFilter->SetOutputMaximum(static_cast(_rescaleMax)); if (_seriesReadStyle == ImageSeriesReadStyle::Numeric) { spReader = prepareNumericSource(); } else if (_seriesReadStyle == ImageSeriesReadStyle::Dicom) { spReader = prepareDICOMSource(); } else if (_seriesReadStyle == ImageSeriesReadStyle::GDCM) { spReader = prepareGDCMSource(); } else if (_seriesReadStyle == ImageSeriesReadStyle::Default) { bool isDir = itksys::SystemTools::FileIsDirectory(_fileName.c_str()); if (isDir || sTemp == ".dcm" || sTemp == ".ima") { spReader = prepareDICOMSource(); } else { spReader = prepareNormalSource(); } } else { //style is none spReader = prepareNormalSource(); } if (_rescaleImage) { rescaleFilter->SetInput(spReader->GetOutput()); imageCaster->SetInput(rescaleFilter->GetOutput()); } else { imageCaster->SetInput(spReader->GetOutput()); } imageCaster->Update(); _spImage = imageCaster->GetOutput(); using ImageReaderType = ::itk::ImageFileReader< InputImageType >; using ImageSeriesReaderType = ::itk::ImageSeriesReader; auto* pFileReader = dynamic_cast(spReader.GetPointer()); auto* pSeriesReader = dynamic_cast(spReader.GetPointer()); if (pFileReader) { _dictionaryArray.clear(); _dictionaryArray.push_back(pFileReader->GetImageIO()->GetMetaDataDictionary()); } else if (pSeriesReader) { copyMetaDictionaryArray(pSeriesReader->GetMetaDataDictionaryArray(), _dictionaryArray); } else { throw ::itk::ExceptionObject("Image reader is not valid. Internal reader seams not to be itk::ImageFileReader or itk::ImageSeriesReader."); } _upToDate = true; }; template const FileNameString& ImageReader:: getFileName() const { return _fileName; }; template void ImageReader:: setFileName(const FileNameString& fileName) { if (fileName != _fileName) { _upToDate = false; _fileName = fileName; } } template const typename ImageReader::RescaleValueType& ImageReader:: getRescaleMinimum() const { return _rescaleMin; }; template void ImageReader:: setRescaleMinimum(const RescaleValueType& dRescaleMin) { if (dRescaleMin != _rescaleMin) { _upToDate = false; _rescaleMin = dRescaleMin; }; }; template const typename ImageReader::RescaleValueType& ImageReader:: getRescaleMaximum() const { return _rescaleMax; }; template void ImageReader:: setRescaleMaximum(const RescaleValueType& dRescaleMax) { if (dRescaleMax != _rescaleMax) { _upToDate = false; _rescaleMax = dRescaleMax; }; }; template const bool ImageReader:: getRescaleImage() const { return _rescaleImage; }; template void ImageReader:: setRescaleImage(const bool rescaleImage) { if (rescaleImage != _rescaleImage) { _upToDate = false; _rescaleImage = rescaleImage; }; }; template const unsigned int ImageReader:: getUpperSeriesLimit() const { return _upperSeriesLimit; }; template void ImageReader:: setUpperSeriesLimit(const unsigned int upperLimit) { if (upperLimit != _upperSeriesLimit) { _upToDate = false; _upperSeriesLimit = upperLimit; }; }; template const ImageSeriesReadStyle::Type ImageReader:: getSeriesReadStyle() const { return _seriesReadStyle; }; template void ImageReader:: setSeriesReadStyle(ImageSeriesReadStyle::Type readStyle) { if (readStyle != _seriesReadStyle) { _upToDate = false; _seriesReadStyle = readStyle; }; }; template typename ImageReader::OutputImageType* ImageReader:: GetOutput() { if (!_upToDate) { switch (OutputImageType::GetImageDimension()) { case 2: load2D(); break; case 3: load3D(); break; default: throw ::itk::ExceptionObject("Image reader only accepts 2 or 3 dimensional images."); }; }; return _spImage; }; template ImageReader:: ImageReader() { _fileName = ""; _upperSeriesLimit = 255; _upToDate = false; _rescaleImage = false; _rescaleMax = 255; _rescaleMin = 0; _seriesReadStyle = ImageSeriesReadStyle::Default; }; template ImageReader:: ~ImageReader() = default; template typename ImageReader::OutputImageType::Pointer readImage( const FileNameString& fileName, ImageSeriesReadStyle::Type readStyle, bool rescaleImage, typename ImageReader::RescaleValueType rescaleMin, typename ImageReader::RescaleValueType rescaleMax, unsigned int upperNumericSeriesLimit, typename ImageReader::MetaDataDictionaryArrayType* pLoadedDictArray) { ImageReader reader; reader.setFileName(fileName); reader.setSeriesReadStyle(readStyle); reader.setRescaleImage(rescaleImage); reader.setRescaleMaximum(rescaleMax); reader.setRescaleMinimum(rescaleMin); reader.setUpperSeriesLimit(upperNumericSeriesLimit); typename ImageReader::OutputImageType::Pointer spResult = reader.GetOutput(); if (pLoadedDictArray) { *pLoadedDictArray = reader.getMetaDictionaryArray(); }; return spResult; }; } } } #endif diff --git a/code/io/itk/rttbImageWriter.cpp b/code/io/itk/rttbImageWriter.cpp index 8ea3b66..0130969 100644 --- a/code/io/itk/rttbImageWriter.cpp +++ b/code/io/itk/rttbImageWriter.cpp @@ -1,61 +1,55 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbImageWriter.h" #include "rttbITKException.h" namespace rttb { namespace io { namespace itk { ImageWriter::ImageWriter(const FileNameString& aFileName, ITKImageTypeConstPointer aITKImage) : _fileName(aFileName), _itkImage(aITKImage) { } bool ImageWriter::writeFile() { WriterType::Pointer writer = WriterType::New(); writer->SetFileName(_fileName); writer->SetUseCompression(true); writer->SetInput(_itkImage); try { writer->Update(); } catch (::itk::ExceptionObject& excp) { std::cerr << "Error: ITK Exception caught " << excp << std::endl; throw rttb::io::itk::ITKException("ITK Exception in writing image: writer->Update()!"); return false; } return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbImageWriter.h b/code/io/itk/rttbImageWriter.h index 70778fa..d3505ca 100644 --- a/code/io/itk/rttbImageWriter.h +++ b/code/io/itk/rttbImageWriter.h @@ -1,76 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __RTTB_IMAGE_WRITER_H #define __RTTB_IMAGE_WRITER_H #include "RTToolboxConfigure.h" #ifdef RTTB_DISABLE_ITK_IO_FACTORY_AUTO_REGISTER #undef ITK_IO_FACTORY_REGISTER_MANAGER #endif #include "itkImage.h" #include "itkImageFileWriter.h" #include "rttbBaseType.h" #include "RTTBITKIOExports.h" namespace rttb { namespace io { namespace itk { /** @class ImageWriter * @brief Helper class writing 3D images to file ... * */ class RTTBITKIO_EXPORT ImageWriter { typedef ::itk::Image ITKMaskImageType; using ITKImageTypeConstPointer = ITKMaskImageType::ConstPointer; using WriterType = ::itk::ImageFileWriter; private: FileNameString _fileName; ITKImageTypeConstPointer _itkImage; public: ImageWriter(const FileNameString& aFileName, ITKImageTypeConstPointer aITKImage); /*! @brief Write itk image to file @return Return true if successful. @exception InvalidParameterException thrown if itk exception by writing the image */ bool writeFile(); }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/models/rttbModelXMLWriter.cpp b/code/io/models/rttbModelXMLWriter.cpp index 81a2bb0..b187d7c 100644 --- a/code/io/models/rttbModelXMLWriter.cpp +++ b/code/io/models/rttbModelXMLWriter.cpp @@ -1,148 +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: 1328 $ (last changed revision) -// @date $Date: 2016-04-22 09:50:01 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbModelXMLWriter.h" #include /*boost includes*/ #include #include #include #include "rttbInvalidParameterException.h" #include "rttbDVHXMLFileWriter.h" #include "rttbDoseStatisticsXMLWriter.h" namespace rttb { namespace io { namespace models { ModelXMLWriter::ModelXMLWriter(const std::string& filename, rttb::models::BioModel::Pointer model, bool printDVH) : _filename(filename), _model(model), _printDVH(printDVH) { } void ModelXMLWriter::setFilename(FileNameString filename) { _filename = filename; } FileNameString ModelXMLWriter::getFilename() const { return _filename; } void ModelXMLWriter::setModel(rttb::models::BioModel::Pointer model) { _model = model; } rttb::models::BioModel::Pointer ModelXMLWriter::getModel() const { return _model; } void ModelXMLWriter::setPrintDVH(bool printDVH) { _printDVH = printDVH; } bool ModelXMLWriter::getPrintDVH() const { return _printDVH; } void ModelXMLWriter::writeModel() { std::setprecision(2); boost::property_tree::ptree pt; std::string xmlattrNameTag = ".name"; std::string modelTag = "BioModel"; std::string propertyTag = "property"; std::string configTag = "config"; std::string resultsTag = "results"; std::string valueTag = "value"; auto dvh = _model->getDVH(); boost::property_tree::ptree propertynode; boost::property_tree::ptree confignode; confignode.put("BioModelType", _model->getModelType()); confignode.put("StructureID", dvh->getStructureID()); confignode.put("DoseID", dvh->getDoseID()); if (_printDVH) { FileNameString filename = "dvhfor" + _model->getModelType() + ".xml"; DVHType typeDiff = { DVHType::Differential }; io::other::DVHXMLFileWriter dvhWriter(filename, typeDiff); dvhWriter.writeDVH(dvh); confignode.put("DVHReference", filename); } pt.add_child(modelTag + "." + configTag, confignode); propertynode.put("", _model->getValue()); propertynode.put(xmlattrNameTag, valueTag); pt.add_child(modelTag + "." + resultsTag + "." + propertyTag, propertynode); std::map parameterMap = _model->getParameterMap(); for (std::map::const_iterator it = parameterMap.begin(); it != parameterMap.end(); ++it) { double value = it->second; if (value - static_cast(std::round(value)) < errorConstant) { propertynode.put("", static_cast(value)); } else { propertynode.put("", static_cast(value)); } propertynode.put(xmlattrNameTag, it->first); pt.add_child(modelTag + "." + resultsTag + "." + propertyTag, propertynode); } try { boost::property_tree::xml_parser::xml_writer_settings settings = boost::property_tree::xml_writer_make_settings('\t', 1); boost::property_tree::xml_parser::write_xml(_filename, pt, std::locale(), settings); } catch (const boost::property_tree::xml_parser_error& e) { std::cout << e.what(); throw core::InvalidParameterException("Write xml failed: xml_parser_error!"); } } } } } diff --git a/code/io/models/rttbModelXMLWriter.h b/code/io/models/rttbModelXMLWriter.h index f21417c..7a1e779 100644 --- a/code/io/models/rttbModelXMLWriter.h +++ b/code/io/models/rttbModelXMLWriter.h @@ -1,66 +1,57 @@ // ----------------------------------------------------------------------- // 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: 1250 $ (last changed revision) -// @date $Date: 2016-02-18 15:25:55 +0100 (Do, 18 Feb 2016) $ (last change date) -// @author $Author: zhangl $ (last changed by) -*/ + #ifndef __MODELS_XML_WRITER_H #define __MODELS_XML_WRITER_H - - #include "rttbBioModel.h" - - namespace rttb { namespace io { namespace models { /*! @class ModelXMLWriter @brief Writes a model (TCP, NTCP, ...) to an xml file */ class ModelXMLWriter { private: std::string _filename; rttb::models::BioModel::Pointer _model; bool _printDVH; public: ModelXMLWriter(const std::string& filename, rttb::models::BioModel::Pointer model, bool printDVH = true); void setFilename(std::string filename); std::string getFilename() const; void setModel(rttb::models::BioModel::Pointer model); rttb::models::BioModel::Pointer getModel() const; void setPrintDVH(bool printDVH); bool getPrintDVH() const; void writeModel(); }; } } } #endif diff --git a/code/io/other/rttbDVHXMLFileReader.cpp b/code/io/other/rttbDVHXMLFileReader.cpp index 506a671..6616a50 100644 --- a/code/io/other/rttbDVHXMLFileReader.cpp +++ b/code/io/other/rttbDVHXMLFileReader.cpp @@ -1,154 +1,148 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include #include #include "rttbDVHXMLFileReader.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace other { DVHXMLFileReader::DVHXMLFileReader(FileNameString aFileName) { _fileName = aFileName; _resetFile = true; } DVHXMLFileReader::~DVHXMLFileReader() = default; void DVHXMLFileReader::resetFileName(FileNameString aFileName) { _fileName = aFileName; _resetFile = true; } void DVHXMLFileReader::createDVH() { boost::property_tree::ptree pt; // Load the XML file into the property tree. If reading fails // (cannot open file, parse error), an exception is thrown. try { read_xml(_fileName, pt); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw rttb::core::InvalidParameterException("DVH file name invalid: could not open the xml file!"); } std::string dvhType; std::deque dataDifferential, dataCumulative; DoseTypeGy deltaD = 0; DoseVoxelVolumeType deltaV = 0; IDType strID; IDType doseID; bool normalized; dvhType = pt.get("dvh.type"); deltaD = pt.get("dvh.deltaD"); deltaV = pt.get("dvh.deltaV"); strID = pt.get("dvh.structureID"); doseID = pt.get("dvh.doseID"); boost::optional dvhNormalized = pt.get_optional("dvh.normalized"); if (dvhNormalized) { normalized = dvhNormalized.get(); } else { normalized = false; } if (dvhType != "DIFFERENTIAL" && dvhType != "CUMULATIVE") { throw core::InvalidParameterException("DVH Type invalid! Only: DIFFERENTIAL/CUMULATIVE!"); } BOOST_FOREACH(boost::property_tree::ptree::value_type & v, pt.get_child("dvh.data")) { if (dvhType == "DIFFERENTIAL") { dataDifferential.push_back(boost::lexical_cast(v.second.data()) / (normalized ? deltaV : 1)); } else if (dvhType == "CUMULATIVE") { dataCumulative.push_back(boost::lexical_cast(v.second.data()) / (normalized ? deltaV : 1)); } } unsigned int numberOfBins = static_cast(std::max(dataDifferential.size(), dataCumulative.size())); if (dvhType == "CUMULATIVE") //dataDifferential should be calculated { DoseCalcType differentialDVHi = 0; std::deque::iterator it; for (it = dataCumulative.begin(); it != dataCumulative.end(); ++it) { if (dataDifferential.size() == numberOfBins - 1) { differentialDVHi = *it; } else { differentialDVHi = *it - *(it + 1); } dataDifferential.push_back(differentialDVHi); } } _dvh = boost::make_shared(dataDifferential, deltaD, deltaV, strID, doseID); _resetFile = false; } core::DVH::Pointer DVHXMLFileReader::generateDVH() { if (_resetFile) { this->createDVH(); } return _dvh; } }//end namespace other }//end namespace io }//end namespace rttb diff --git a/code/io/other/rttbDVHXMLFileReader.h b/code/io/other/rttbDVHXMLFileReader.h index 6a7cf52..5b1cd6f 100644 --- a/code/io/other/rttbDVHXMLFileReader.h +++ b/code/io/other/rttbDVHXMLFileReader.h @@ -1,69 +1,64 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_XML_FILE_READER_H #define __DVH_XML_FILE_READER_H #include "rttbBaseType.h" #include "rttbDVHGeneratorInterface.h" namespace rttb { namespace io { namespace other { /*! @class DVHXMLFileReader @brief Reads DVH data from xml files. */ class DVHXMLFileReader: public core::DVHGeneratorInterface { private: FileNameString _fileName; bool _resetFile; /*! @brief Create new DVH object using the info from dvh txt file @exception InvalidParameterException Thrown if _fileName invalid */ void createDVH(); public: /*! @brief Constructor. */ DVHXMLFileReader(FileNameString aFileName); ~DVHXMLFileReader(); /*! @brief Change file name. */ void resetFileName(FileNameString aFileName); /*! @brief Generate DVH, createDVH() will be called @return Return new shared pointer of DVH. @exception InvalidParameterException Thrown if _fileName invalid */ core::DVH::Pointer generateDVH() override; }; } } } #endif diff --git a/code/io/other/rttbDVHXMLFileWriter.cpp b/code/io/other/rttbDVHXMLFileWriter.cpp index 1114ec3..edede47 100644 --- a/code/io/other/rttbDVHXMLFileWriter.cpp +++ b/code/io/other/rttbDVHXMLFileWriter.cpp @@ -1,146 +1,139 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include "rttbDVHXMLFileWriter.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbException.h" #include #include namespace rttb { namespace io { namespace other { DVHXMLFileWriter::DVHXMLFileWriter(FileNameString aFileName, DVHType aDVHType) { this->setFileName(aFileName); this->setDVHType(aDVHType); } void DVHXMLFileWriter::setDVHType(DVHType aDVHType) { _dvhType = aDVHType; } FileNameString DVHXMLFileWriter::getFileName() const { return _fileName; } void DVHXMLFileWriter::setFileName(FileNameString aFileName) { _fileName = aFileName; } DVHType DVHXMLFileWriter::getDVHType() const { return _dvhType; } void DVHXMLFileWriter::writeDVH(core::DVH::Pointer aDvh, bool normalized) { if (aDvh == nullptr) { throw core::NullPointerException("aDvh must not be nullptr! "); } using boost::property_tree::ptree; ptree pt; DataDifferentialType data; std::map normalizedData; if (_dvhType.Type == DVHType::Differential) { pt.put("dvh.type", "DIFFERENTIAL"); if (normalized) { normalizedData = aDvh->getNormalizedDVH({ DVHType::Cumulative }); } else { data = aDvh->getDataDifferential(); } } else if (_dvhType.Type == DVHType::Cumulative) { pt.put("dvh.type", "CUMULATIVE"); if (normalized) { normalizedData = aDvh->getNormalizedDVH(); } else { data = aDvh->getDataCumulative(); } } else { throw core::InvalidParameterException("DVH Type not acceptable: Only: DIFFERENTIAL/CUMULATIVE!"); } pt.put("dvh.deltaD", aDvh->getDeltaD()); pt.put("dvh.deltaV", aDvh->getDeltaV()); pt.put("dvh.structureID", aDvh->getStructureID()); pt.put("dvh.doseID", aDvh->getDoseID()); pt.put("dvh.normalized", normalized); if (normalized) { for (auto elem : normalizedData) { boost::property_tree::ptree node; node.put("", elem.second); node.put(".doseGy", elem.first); pt.add_child("dvh.data.volumeInCcm", node); } } else { for (size_t i = 0; i < data.size(); i++) { boost::property_tree::ptree node; node.put("", data[i]); node.put(".dosebin", i); pt.add_child("dvh.data.volume", node); } } try { boost::property_tree::xml_parser::xml_writer_settings settings = boost::property_tree::xml_writer_make_settings ('\t', 1); boost::property_tree::xml_parser::write_xml(_fileName, pt, std::locale(), settings); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw core::InvalidParameterException("Write xml failed: xml_parser_error!"); } } } } } diff --git a/code/io/other/rttbDVHXMLFileWriter.h b/code/io/other/rttbDVHXMLFileWriter.h index 4e8a8f0..5157b99 100644 --- a/code/io/other/rttbDVHXMLFileWriter.h +++ b/code/io/other/rttbDVHXMLFileWriter.h @@ -1,84 +1,79 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_XML_FILE_WRITER_H #define __DVH_XML_FILE_WRITER_H #include "rttbDVH.h" #include "../rttbDVHWriterInterface.h" #include "rttbBaseType.h" #include "RTTBOtherIOExports.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace io { namespace other { /*! @class DVHXMLFileWriter @brief Writes DVHs to xml files. */ class RTTBOtherIO_EXPORT DVHXMLFileWriter : public DVHWriterInterface { public: using DataDifferentialType = core::DVH::DataDifferentialType; private: FileNameString _fileName; DVHType _dvhType; public: /*! @brief Constructor @param aFileName a xml file name to write @param aDVHType: DIFFERENTIAL or CUMULATIVE. */ DVHXMLFileWriter(FileNameString aFileName, DVHType aDVHType); void setFileName(FileNameString aFileName); FileNameString getFileName() const; void setDVHType(DVHType aDVHType); DVHType getDVHType() const; /*! @brief Write aDvh to xml file with the name: _fileName @exception NullPointerException Thrown if _aDvh is nullptr @exception InvalidParameterException Thrown if _fileName invalid: could not open; or if _dvhType invalid: only DIFFERENTIAL or CUMULATIVE is accepted! @exception Exception thrown if dvh init error */ void writeDVH(core::DVH::Pointer aDvh, bool normalized = false) override; }; } } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/io/other/rttbDoseStatisticsXMLReader.cpp b/code/io/other/rttbDoseStatisticsXMLReader.cpp index 63d35ed..b4530f5 100644 --- a/code/io/other/rttbDoseStatisticsXMLReader.cpp +++ b/code/io/other/rttbDoseStatisticsXMLReader.cpp @@ -1,220 +1,214 @@ // ----------------------------------------------------------------------- // 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: 1328 $ (last changed revision) -// @date $Date: 2016-04-22 09:50:01 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include #include #include #include #include #include "rttbDoseStatisticsXMLReader.h" #include "rttbInvalidParameterException.h" #include "rttbVolumeToDoseMeasureCollection.h" namespace rttb { namespace io { namespace other { DoseStatisticsXMLReader::DoseStatisticsXMLReader(const std::string& filename) : _filename(filename), _newFile(true) { } DoseStatisticsXMLReader::~DoseStatisticsXMLReader() = default; void DoseStatisticsXMLReader::setFilename(const std::string& filename) { _filename = filename; _newFile = true; } algorithms::DoseStatistics::Pointer DoseStatisticsXMLReader::generateDoseStatistic() { if (_newFile) { this->createDoseStatistic(); } return _doseStatistic; } void DoseStatisticsXMLReader::createDoseStatistic() { boost::property_tree::ptree pt; // Load the XML file into the property tree. If reading fails // (cannot open file, parse error), an exception is thrown. try { read_xml(_filename, pt); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw rttb::core::InvalidParameterException("DoseStatistics file name invalid: could not open the xml file!"); } // data to fill the parameter for the DoseStatistics std::string name; std::string datum; unsigned int x; std::pair voxelid; std::vector < std::pair> vec; //initialize all parameters for the DoseStatistics double minimum=-1; double maximum=-1; double numVoxels=-1; double volume=-1; double referenceDose = -1; double mean=-1; double stdDeviation=-1; boost::shared_ptr > > minimumVoxelPositions = nullptr; boost::shared_ptr > > maximumVoxelPositions = nullptr; rttb::algorithms::VolumeToDoseMeasureCollection Dx(rttb::algorithms::VolumeToDoseMeasureCollection::Dx); rttb::algorithms::DoseToVolumeMeasureCollection Vx(rttb::algorithms::DoseToVolumeMeasureCollection::Vx); rttb::algorithms::VolumeToDoseMeasureCollection MOHx(rttb::algorithms::VolumeToDoseMeasureCollection::MOHx); rttb::algorithms::VolumeToDoseMeasureCollection MOCx(rttb::algorithms::VolumeToDoseMeasureCollection::MOCx); rttb::algorithms::VolumeToDoseMeasureCollection MaxOHx(rttb::algorithms::VolumeToDoseMeasureCollection::MaxOHx); rttb::algorithms::VolumeToDoseMeasureCollection MinOCx(rttb::algorithms::VolumeToDoseMeasureCollection::MinOCx); BOOST_FOREACH(boost::property_tree::ptree::value_type & data, pt.get_child("statistics.results")) { datum = data.second.data(); BOOST_FOREACH(boost::property_tree::ptree::value_type & middle, data.second) { BOOST_FOREACH(boost::property_tree::ptree::value_type & innernode, middle.second) { std::string mia = innernode.first; if (innernode.first == "name") { name = innernode.second.data(); } else if (innernode.first == "voxelGridID") { boost::replace_all(datum, "\r\n", ""); boost::replace_all(datum, "\n", ""); boost::trim(datum); voxelid.first = boost::lexical_cast(datum); voxelid.second = boost::lexical_cast(innernode.second.data()); vec.push_back(voxelid); } else if (innernode.first == "x") { x = boost::lexical_cast(innernode.second.data()); } } } // fill with the extracted data if (name == "numberOfVoxels") { numVoxels = boost::lexical_cast(datum); } else if (name == "volume") { volume = boost::lexical_cast(datum); Dx.setVolume(volume); MOHx.setVolume(volume); MOCx.setVolume(volume); MaxOHx.setVolume(volume); } else if (name == "referenceDose") { referenceDose = boost::lexical_cast(datum); Vx.setReferenceDose(referenceDose); } else if (name == "mean") { mean = boost::lexical_cast(datum); } else if (name == "standardDeviation") { stdDeviation = boost::lexical_cast(datum); } else if (name == "minimum") { minimum = boost::lexical_cast(datum); if (!vec.empty()) { minimumVoxelPositions = boost::make_shared>>(vec); vec.clear(); } } else if (name == "maximum") { maximum = boost::lexical_cast(datum); if (!vec.empty()) { maximumVoxelPositions = boost::make_shared>>(vec); vec.clear(); } } else if (name == "Dx") { Dx.insertValue(static_cast(x)*volume / 100, boost::lexical_cast(datum)); } else if (name == "Vx") { Vx.insertValue(static_cast(x)*referenceDose / 100, boost::lexical_cast(datum)); } else if (name == "MOHx") { MOHx.insertValue(static_cast(x)*volume / 100, boost::lexical_cast(datum)); } else if (name == "MOCx") { MOCx.insertValue(static_cast(x)*volume / 100, boost::lexical_cast(datum)); } else if (name == "MaxOHx") { MaxOHx.insertValue(static_cast(x)*volume / 100, boost::lexical_cast(datum)); } else if (name == "MinOCx") { MinOCx.insertValue(static_cast(x)*volume / 100, boost::lexical_cast(datum)); } } // make DoseStatistcs _doseStatistic = boost::make_shared( minimum, maximum, mean, stdDeviation, numVoxels, volume, minimumVoxelPositions, maximumVoxelPositions , Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx, referenceDose); } }//end namespace other }//end namespace io }//end namespace rttb diff --git a/code/io/other/rttbDoseStatisticsXMLReader.h b/code/io/other/rttbDoseStatisticsXMLReader.h index d214111..79aff6f 100644 --- a/code/io/other/rttbDoseStatisticsXMLReader.h +++ b/code/io/other/rttbDoseStatisticsXMLReader.h @@ -1,63 +1,58 @@ // ----------------------------------------------------------------------- // 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: 1250 $ (last changed revision) -// @date $Date: 2016-02-18 15:25:55 +0100 (Do, 18 Feb 2016) $ (last change date) -// @author $Author: zhangl $ (last changed by) -*/ + #ifndef __DOSE_STATISTICS_XML_READER_H #define __DOSE_STATISTICS_XML_READER_H #include "rttbDoseStatistics.h" namespace rttb { namespace io { namespace other { /*! @class DoseStatisticsXMLReader @brief Reads a dose statistics XML into a DoseStatistics object */ class DoseStatisticsXMLReader{ public: DoseStatisticsXMLReader(const std::string& filename); ~DoseStatisticsXMLReader(); void setFilename(const std::string& filename); /*! @brief Generate a Model, createModel() will be called @return Return new shared pointer of a Model. @exception InvalidParameterException Thrown if _filename invalid */ algorithms::DoseStatistics::Pointer generateDoseStatistic(); private: std::string _filename; bool _newFile; algorithms::DoseStatistics::Pointer _doseStatistic; /*! @brief Create new Model object using the info from model xml file @exception InvalidParameterException Thrown if _filename invalid */ void createDoseStatistic(); }; } } } #endif diff --git a/code/io/rttbDVHWriterInterface.h b/code/io/rttbDVHWriterInterface.h index 86b06a0..890a265 100644 --- a/code/io/rttbDVHWriterInterface.h +++ b/code/io/rttbDVHWriterInterface.h @@ -1,47 +1,41 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DVH_WRITER_INTERFACE_H #define __DVH_WRITER_INTERFACE_H - #include "rttbDVH.h" #include "RTTBOtherIOExports.h" namespace rttb { namespace io { /*! @class DVHWriterInterface @brief Interface for classes that write DVH data to files. */ class RTTBOtherIO_EXPORT DVHWriterInterface { /*! @brief Write aDvh */ public: virtual void writeDVH(core::DVH::Pointer aDvh, bool normalized = false) = 0; }; } } #endif diff --git a/code/masks/rttbBoostMask.cpp b/code/masks/rttbBoostMask.cpp index 05eeba3..63c13ae 100644 --- a/code/masks/rttbBoostMask.cpp +++ b/code/masks/rttbBoostMask.cpp @@ -1,565 +1,558 @@ -// ----------------------------------------------------------------------- -// 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - -#include - -#include -#include -#include -#include - -#include "rttbBoostMask.h" -#include "rttbNullPointerException.h" -#include "rttbInvalidParameterException.h" -#include "rttbBoostMaskGenerateMaskVoxelListThread.h" -#include "rttbBoostMaskVoxelizationThread.h" - - -namespace rttb -{ - namespace masks - { - namespace boost - { - - - BoostMask::BoostMask(core::GeometricInfo::Pointer aDoseGeoInfo, - core::Structure::Pointer aStructure, bool strict, unsigned int numberOfThreads) - : _geometricInfo(aDoseGeoInfo), _structure(aStructure), - _strict(strict), _numberOfThreads(numberOfThreads), _voxelizationThickness(0.0), - _voxelInStructure(::boost::make_shared()) - { - - _isUpToDate = false; - - if (_geometricInfo == nullptr) - { - throw rttb::core::NullPointerException("Error: Geometric info is nullptr!"); - } - else if (_structure == nullptr) - { - throw rttb::core::NullPointerException("Error: Structure is nullptr!"); - } - - if (_numberOfThreads == 0) - { - _numberOfThreads = ::boost::thread::hardware_concurrency(); - if (_numberOfThreads == 0) - { - throw rttb::core::InvalidParameterException("Error: detection of the number of hardware threads is not possible. Please specify number of threads for voxelization explicitly as parameter in BoostMask."); - } - } - - } - - BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector() - { - if (!_isUpToDate) - { - calcMask(); - } - - return _voxelInStructure; - } - - void BoostMask::calcMask() - { - preprocessing(); - voxelization(); - generateMaskVoxelList(); - _isUpToDate = true; - } - - void BoostMask::preprocessing() - { - rttb::PolygonSequenceType polygonSequence = _structure->getStructureVector(); - - //Convert world coordinate polygons to the polygons with geometry coordinate - rttb::PolygonSequenceType geometryCoordinatePolygonVector; - rttb::PolygonSequenceType::iterator it; - rttb::DoubleVoxelGridIndex3D globalMaxGridIndex(std::numeric_limits::min(), - std::numeric_limits::min(), std::numeric_limits::min()); - rttb::DoubleVoxelGridIndex3D globalMinGridIndex(_geometricInfo->getNumColumns(), - _geometricInfo->getNumRows(), 0); - - for (it = polygonSequence.begin(); it != polygonSequence.end(); ++it) - { - PolygonType rttbPolygon = *it; - PolygonType geometryCoordinatePolygon; - - //1. convert polygon to geometry coordinate polygons - //2. calculate global min/max - //3. check if polygon is planar - if (!preprocessingPolygon(rttbPolygon, geometryCoordinatePolygon, globalMinGridIndex, - globalMaxGridIndex, errorConstant)) - { - throw rttb::core::Exception("TiltedMaskPlaneException"); - } - - geometryCoordinatePolygonVector.push_back(geometryCoordinatePolygon); - } - - rttb::VoxelGridIndex3D minIndex = VoxelGridIndex3D(GridIndexType(globalMinGridIndex(0) ), - GridIndexType(globalMinGridIndex(1) ), GridIndexType(globalMinGridIndex(2) )); - rttb::VoxelGridIndex3D maxIndex = VoxelGridIndex3D(GridIndexType(globalMaxGridIndex(0) ), - GridIndexType(globalMaxGridIndex(1) ), GridIndexType(globalMaxGridIndex(2) )); - - _globalBoundingBox.push_back(minIndex); - _globalBoundingBox.push_back(maxIndex); - - //convert rttb polygon sequence to a map of z index and a vector of boost ring 2d (without holes) - _ringMap = convertRTTBPolygonSequenceToBoostRingMap(geometryCoordinatePolygonVector); - - } - - void BoostMask::voxelization() - { - - if (_globalBoundingBox.size() < 2) - { - throw rttb::core::InvalidParameterException("Bounding box calculation failed! "); - } - - BoostRingMap::iterator itMap; - - size_t mapSizeInAThread = _ringMap.size() / _numberOfThreads; - unsigned int count = 0; - unsigned int countThread = 0; - BoostPolygonMap polygonMap; - std::vector polygonMapVector; - - //check donut and convert to a map of z index and a vector of boost polygon 2d (with or without holes) - for (itMap = _ringMap.begin(); itMap != _ringMap.end(); ++itMap) - { - //the vector of all boost 2d polygons with the same z grid index(donut polygon is accepted). - BoostPolygonVector polygonVector = checkDonutAndConvert((*itMap).second); - - if (count == mapSizeInAThread && countThread < (_numberOfThreads - 1)) - { - polygonMapVector.push_back(polygonMap); - polygonMap.clear(); - count = 0; - countThread++; - } - - polygonMap.insert(std::pair((*itMap).first, - polygonVector)); - count++; - - } - - _voxelizationMap = ::boost::make_shared >(); - - polygonMapVector.push_back(polygonMap); //insert the last one - - //generate voxelization map, multi-threading - ::boost::thread_group threads; - auto aMutex = ::boost::make_shared<::boost::shared_mutex>(); - - for (const auto & i : polygonMapVector) - { - BoostMaskVoxelizationThread t(i, _globalBoundingBox, - _voxelizationMap, aMutex, _strict); - threads.create_thread(t); - } - - threads.join_all(); - } - - void BoostMask::generateMaskVoxelList() - { - if (_globalBoundingBox.size() < 2) - { - throw rttb::core::InvalidParameterException("Bounding box calculation failed! "); - } - - //check homogeneous of the voxelization plane (the contours plane) - if (!calcVoxelizationThickness(_voxelizationThickness)) - { - throw rttb::core::InvalidParameterException("Error: The contour plane should be homogeneous!"); - } - - - - ::boost::thread_group threads; - auto aMutex = ::boost::make_shared<::boost::shared_mutex>(); - - unsigned int sliceNumberInAThread = _geometricInfo->getNumSlices() / _numberOfThreads; - - //generate mask voxel list, multi-threading - for (unsigned int i = 0; i < _numberOfThreads; ++i) - { - unsigned int beginSlice = i * sliceNumberInAThread; - unsigned int endSlice; - - if (i < _numberOfThreads - 1) - { - endSlice = (i + 1) * sliceNumberInAThread; - } - else - { - endSlice = _geometricInfo->getNumSlices(); - } - - - BoostMaskGenerateMaskVoxelListThread t(_globalBoundingBox, _geometricInfo, _voxelizationMap, - _voxelizationThickness, beginSlice, endSlice, - _voxelInStructure, _strict, aMutex); - - threads.create_thread(t); - - } - - threads.join_all(); - - } - - bool BoostMask::preprocessingPolygon(const rttb::PolygonType& aRTTBPolygon, - rttb::PolygonType& geometryCoordinatePolygon, rttb::DoubleVoxelGridIndex3D& minimum, - rttb::DoubleVoxelGridIndex3D& maximum, double aErrorConstant) const - { - - double minZ = _geometricInfo->getNumSlices(); - double maxZ = 0.0; - - for (auto worldCoordinatePoint : aRTTBPolygon) - { - //convert to geometry coordinate polygon - rttb::DoubleVoxelGridIndex3D geometryCoordinatePoint; - _geometricInfo->worldCoordinateToGeometryCoordinate(worldCoordinatePoint, geometryCoordinatePoint); - - geometryCoordinatePolygon.push_back(geometryCoordinatePoint); - - //calculate the current global min/max - //min and max for x - if (geometryCoordinatePoint(0) < minimum(0)) - { - minimum(0) = geometryCoordinatePoint(0); - } - - if (geometryCoordinatePoint(0) > maximum(0)) - { - maximum(0) = geometryCoordinatePoint(0); - } - - //min and max for y - if (geometryCoordinatePoint(1) < minimum(1)) - { - minimum(1) = geometryCoordinatePoint(1); - } - - if (geometryCoordinatePoint(1) > maximum(1)) - { - maximum(1) = geometryCoordinatePoint(1); - } - - //min and max for z - if (geometryCoordinatePoint(2) < minimum(2)) - { - minimum(2) = geometryCoordinatePoint(2); - } - - if (geometryCoordinatePoint(2) > maximum(2)) - { - maximum(2) = geometryCoordinatePoint(2); - } - - //check planar - if (geometryCoordinatePoint(2) < minZ) - { - minZ = geometryCoordinatePoint(2); - } - - if (geometryCoordinatePoint(2) > maxZ) - { - maxZ = geometryCoordinatePoint(2); - } - - } - - return (std::abs(maxZ - minZ) <= aErrorConstant); - } - - - BoostMask::BoostRing2D BoostMask::convertRTTBPolygonToBoostRing(const rttb::PolygonType& - aRTTBPolygon) const - { - BoostMask::BoostRing2D polygon2D; - BoostPoint2D firstPoint; - - for (unsigned int i = 0; i < aRTTBPolygon.size(); i++) - { - rttb::WorldCoordinate3D rttbPoint = aRTTBPolygon.at(i); - BoostPoint2D boostPoint(rttbPoint[0], rttbPoint[1]); - - if (i == 0) - { - firstPoint = boostPoint; - } - - ::boost::geometry::append(polygon2D, boostPoint); - } - - ::boost::geometry::append(polygon2D, firstPoint); - return polygon2D; - } - - BoostMask::BoostRingMap BoostMask::convertRTTBPolygonSequenceToBoostRingMap( - const rttb::PolygonSequenceType& aRTTBPolygonVector) const - { - rttb::PolygonSequenceType::const_iterator it; - BoostMask::BoostRingMap aRingMap; - - for (it = aRTTBPolygonVector.begin(); it != aRTTBPolygonVector.end(); ++it) - { - rttb::PolygonType rttbPolygon = *it; - double zIndex = rttbPolygon.at(0)[2];//get the first z index of the polygon - bool isFirstZ = true; - - if (!aRingMap.empty()) - { - auto findIt = findNearestKey(aRingMap, zIndex, errorConstant); - - //if the z index is found (same slice), add the polygon to vector - if (findIt != aRingMap.end()) - { - //BoostRingVector ringVector = ; - (*findIt).second.push_back(convertRTTBPolygonToBoostRing(rttbPolygon)); - isFirstZ = false; - } - } - - //if it is the first z index in the map, insert vector with the polygon - if (isFirstZ) - { - BoostRingVector ringVector; - ringVector.push_back(convertRTTBPolygonToBoostRing(rttbPolygon)); - aRingMap.insert(std::pair(zIndex, ringVector)); - } - - - } - - return aRingMap; - } - - BoostMask::BoostRingMap::iterator BoostMask::findNearestKey(BoostMask::BoostRingMap& - aBoostRingMap, double aIndex, double aErrorConstant) const - { - auto find = aBoostRingMap.find(aIndex); - - //if find a key equivalent to aIndex, found - if (find != aBoostRingMap.end()) - { - return find; - } - else - { - auto lowerBound = aBoostRingMap.lower_bound(aIndex); - - //if all keys go before aIndex, check the last key - if (lowerBound == aBoostRingMap.end()) - { - lowerBound = --aBoostRingMap.end(); - } - - //if the lower bound very close to aIndex, found - if (std::abs((*lowerBound).first - aIndex) <= aErrorConstant) - { - return lowerBound; - } - else - { - //if the lower bound is the beginning, not found - if (lowerBound == aBoostRingMap.begin()) - { - return aBoostRingMap.end(); - } - else - { - auto lowerBound1 = --lowerBound;//the key before the lower bound - - //if the key before the lower bound very close to a Index, found - if (std::abs((*lowerBound1).first - aIndex) <= aErrorConstant) - { - return lowerBound1; - } - //else, not found - else - { - return aBoostRingMap.end(); - } - } - } - - } - } - - BoostMask::BoostPolygonVector BoostMask::checkDonutAndConvert(const BoostMask::BoostRingVector& - aRingVector) const - { - //check donut - BoostMask::BoostRingVector::const_iterator it1; - BoostMask::BoostRingVector::const_iterator it2; - BoostMask::BoostPolygonVector boostPolygonVector; - std::vector donutIndexVector;//store the outer and inner ring index - BoostMask::BoostPolygonVector donutVector;//store new generated donut polygon - - //Get donut index and donut polygon - unsigned int index1 = 0; - - for (it1 = aRingVector.begin(); it1 != aRingVector.end(); ++it1, index1++) - { - bool it1IsDonut = false; - - //check if the ring is already determined as a donut - for (unsigned int i : donutIndexVector) - { - if (i == index1) - { - it1IsDonut = true; - break; - } - } - - //if not jet, check now - if (!it1IsDonut) - { - bool it2IsDonut = false; - unsigned int index2 = 0; - - for (it2 = aRingVector.begin(); it2 != aRingVector.end(); ++it2, index2++) - { - if (it2 != it1) - { - BoostMask::BoostPolygon2D polygon2D; - - if (::boost::geometry::within(*it1, *it2)) - { - ::boost::geometry::append(polygon2D, *it2);//append an outer ring to the polygon - ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring - ::boost::geometry::append(polygon2D, *it1, 0);//append a ring to the interior ring - it2IsDonut = true; - } - //if donut - else if (::boost::geometry::within(*it2, *it1)) - { - ::boost::geometry::append(polygon2D, *it1);//append an outer ring to the polygon - ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring - ::boost::geometry::append(polygon2D, *it2, 0);//append a ring to the interior ring - it2IsDonut = true; - } - - if (it2IsDonut) - { - donutIndexVector.push_back(index1); - donutIndexVector.push_back(index2); - donutVector.push_back(polygon2D);//store donut polygon - break;//Only store the first donut! - } - } - } - } - } - - //Store no donut polygon to boostPolygonVector - index1 = 0; - - for (it1 = aRingVector.begin(); it1 != aRingVector.end(); ++it1, index1++) - { - bool it1IsDonut = false; - - //check if the ring is the outer or inner of a donut - for (unsigned int i : donutIndexVector) - { - if (i == index1) - { - it1IsDonut = true; - break; - } - } - - if (!it1IsDonut) - { - BoostMask::BoostPolygon2D polygon2D; - ::boost::geometry::append(polygon2D, *it1); - boostPolygonVector.push_back(polygon2D);//insert the ring, which is not a part of donut - } - } - - //Append donut polygon to boostPolygonVector - BoostMask::BoostPolygonVector::iterator itDonut; - - for (itDonut = donutVector.begin(); itDonut != donutVector.end(); ++itDonut) - { - boostPolygonVector.push_back(*itDonut);//append donuts - } - - return boostPolygonVector; - } - - bool BoostMask::calcVoxelizationThickness(double& aThickness) const - { - - if (_voxelizationMap->size() <= 1) - { - aThickness = 1; - return true; - } - - double thickness = 0; - - auto it = _voxelizationMap->cbegin(); - auto it2 = ++_voxelizationMap->cbegin(); - for (; - it != _voxelizationMap->cend() && it2 != _voxelizationMap->cend(); ++it, ++it2) - { - if (thickness == 0) - { - thickness = it2->first - it->first; - } - else - { - double curThickness = it2->first - it->first; - //if not homogeneous (leave out double imprecisions), return false - if (std::abs(thickness-curThickness)>errorConstant) - { - //return false; - std::cout << "Two polygons are far from each other?" << std::endl; - } - } - - } - - if (thickness != 0) - { - aThickness = thickness; - } - else - { - aThickness = 1; - } - - return true; - } - } - } -} +// ----------------------------------------------------------------------- +// 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. +// +//------------------------------------------------------------------------ + +#include + +#include +#include +#include +#include + +#include "rttbBoostMask.h" +#include "rttbNullPointerException.h" +#include "rttbInvalidParameterException.h" +#include "rttbBoostMaskGenerateMaskVoxelListThread.h" +#include "rttbBoostMaskVoxelizationThread.h" + +namespace rttb +{ + namespace masks + { + namespace boost + { + + + BoostMask::BoostMask(core::GeometricInfo::Pointer aDoseGeoInfo, + core::Structure::Pointer aStructure, bool strict, unsigned int numberOfThreads) + : _geometricInfo(aDoseGeoInfo), _structure(aStructure), + _strict(strict), _numberOfThreads(numberOfThreads), _voxelizationThickness(0.0), + _voxelInStructure(::boost::make_shared()) + { + + _isUpToDate = false; + + if (_geometricInfo == nullptr) + { + throw rttb::core::NullPointerException("Error: Geometric info is nullptr!"); + } + else if (_structure == nullptr) + { + throw rttb::core::NullPointerException("Error: Structure is nullptr!"); + } + + if (_numberOfThreads == 0) + { + _numberOfThreads = ::boost::thread::hardware_concurrency(); + if (_numberOfThreads == 0) + { + throw rttb::core::InvalidParameterException("Error: detection of the number of hardware threads is not possible. Please specify number of threads for voxelization explicitly as parameter in BoostMask."); + } + } + + } + + BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector() + { + if (!_isUpToDate) + { + calcMask(); + } + + return _voxelInStructure; + } + + void BoostMask::calcMask() + { + preprocessing(); + voxelization(); + generateMaskVoxelList(); + _isUpToDate = true; + } + + void BoostMask::preprocessing() + { + rttb::PolygonSequenceType polygonSequence = _structure->getStructureVector(); + + //Convert world coordinate polygons to the polygons with geometry coordinate + rttb::PolygonSequenceType geometryCoordinatePolygonVector; + rttb::PolygonSequenceType::iterator it; + rttb::DoubleVoxelGridIndex3D globalMaxGridIndex(std::numeric_limits::min(), + std::numeric_limits::min(), std::numeric_limits::min()); + rttb::DoubleVoxelGridIndex3D globalMinGridIndex(_geometricInfo->getNumColumns(), + _geometricInfo->getNumRows(), 0); + + for (it = polygonSequence.begin(); it != polygonSequence.end(); ++it) + { + PolygonType rttbPolygon = *it; + PolygonType geometryCoordinatePolygon; + + //1. convert polygon to geometry coordinate polygons + //2. calculate global min/max + //3. check if polygon is planar + if (!preprocessingPolygon(rttbPolygon, geometryCoordinatePolygon, globalMinGridIndex, + globalMaxGridIndex, errorConstant)) + { + throw rttb::core::Exception("TiltedMaskPlaneException"); + } + + geometryCoordinatePolygonVector.push_back(geometryCoordinatePolygon); + } + + rttb::VoxelGridIndex3D minIndex = VoxelGridIndex3D(GridIndexType(globalMinGridIndex(0) ), + GridIndexType(globalMinGridIndex(1) ), GridIndexType(globalMinGridIndex(2) )); + rttb::VoxelGridIndex3D maxIndex = VoxelGridIndex3D(GridIndexType(globalMaxGridIndex(0) ), + GridIndexType(globalMaxGridIndex(1) ), GridIndexType(globalMaxGridIndex(2) )); + + _globalBoundingBox.push_back(minIndex); + _globalBoundingBox.push_back(maxIndex); + + //convert rttb polygon sequence to a map of z index and a vector of boost ring 2d (without holes) + _ringMap = convertRTTBPolygonSequenceToBoostRingMap(geometryCoordinatePolygonVector); + + } + + void BoostMask::voxelization() + { + + if (_globalBoundingBox.size() < 2) + { + throw rttb::core::InvalidParameterException("Bounding box calculation failed! "); + } + + BoostRingMap::iterator itMap; + + size_t mapSizeInAThread = _ringMap.size() / _numberOfThreads; + unsigned int count = 0; + unsigned int countThread = 0; + BoostPolygonMap polygonMap; + std::vector polygonMapVector; + + //check donut and convert to a map of z index and a vector of boost polygon 2d (with or without holes) + for (itMap = _ringMap.begin(); itMap != _ringMap.end(); ++itMap) + { + //the vector of all boost 2d polygons with the same z grid index(donut polygon is accepted). + BoostPolygonVector polygonVector = checkDonutAndConvert((*itMap).second); + + if (count == mapSizeInAThread && countThread < (_numberOfThreads - 1)) + { + polygonMapVector.push_back(polygonMap); + polygonMap.clear(); + count = 0; + countThread++; + } + + polygonMap.insert(std::pair((*itMap).first, + polygonVector)); + count++; + + } + + _voxelizationMap = ::boost::make_shared >(); + + polygonMapVector.push_back(polygonMap); //insert the last one + + //generate voxelization map, multi-threading + ::boost::thread_group threads; + auto aMutex = ::boost::make_shared<::boost::shared_mutex>(); + + for (const auto & i : polygonMapVector) + { + BoostMaskVoxelizationThread t(i, _globalBoundingBox, + _voxelizationMap, aMutex, _strict); + threads.create_thread(t); + } + + threads.join_all(); + } + + void BoostMask::generateMaskVoxelList() + { + if (_globalBoundingBox.size() < 2) + { + throw rttb::core::InvalidParameterException("Bounding box calculation failed! "); + } + + //check homogeneous of the voxelization plane (the contours plane) + if (!calcVoxelizationThickness(_voxelizationThickness)) + { + throw rttb::core::InvalidParameterException("Error: The contour plane should be homogeneous!"); + } + + + + ::boost::thread_group threads; + auto aMutex = ::boost::make_shared<::boost::shared_mutex>(); + + unsigned int sliceNumberInAThread = _geometricInfo->getNumSlices() / _numberOfThreads; + + //generate mask voxel list, multi-threading + for (unsigned int i = 0; i < _numberOfThreads; ++i) + { + unsigned int beginSlice = i * sliceNumberInAThread; + unsigned int endSlice; + + if (i < _numberOfThreads - 1) + { + endSlice = (i + 1) * sliceNumberInAThread; + } + else + { + endSlice = _geometricInfo->getNumSlices(); + } + + + BoostMaskGenerateMaskVoxelListThread t(_globalBoundingBox, _geometricInfo, _voxelizationMap, + _voxelizationThickness, beginSlice, endSlice, + _voxelInStructure, _strict, aMutex); + + threads.create_thread(t); + + } + + threads.join_all(); + + } + + bool BoostMask::preprocessingPolygon(const rttb::PolygonType& aRTTBPolygon, + rttb::PolygonType& geometryCoordinatePolygon, rttb::DoubleVoxelGridIndex3D& minimum, + rttb::DoubleVoxelGridIndex3D& maximum, double aErrorConstant) const + { + + double minZ = _geometricInfo->getNumSlices(); + double maxZ = 0.0; + + for (auto worldCoordinatePoint : aRTTBPolygon) + { + //convert to geometry coordinate polygon + rttb::DoubleVoxelGridIndex3D geometryCoordinatePoint; + _geometricInfo->worldCoordinateToGeometryCoordinate(worldCoordinatePoint, geometryCoordinatePoint); + + geometryCoordinatePolygon.push_back(geometryCoordinatePoint); + + //calculate the current global min/max + //min and max for x + if (geometryCoordinatePoint(0) < minimum(0)) + { + minimum(0) = geometryCoordinatePoint(0); + } + + if (geometryCoordinatePoint(0) > maximum(0)) + { + maximum(0) = geometryCoordinatePoint(0); + } + + //min and max for y + if (geometryCoordinatePoint(1) < minimum(1)) + { + minimum(1) = geometryCoordinatePoint(1); + } + + if (geometryCoordinatePoint(1) > maximum(1)) + { + maximum(1) = geometryCoordinatePoint(1); + } + + //min and max for z + if (geometryCoordinatePoint(2) < minimum(2)) + { + minimum(2) = geometryCoordinatePoint(2); + } + + if (geometryCoordinatePoint(2) > maximum(2)) + { + maximum(2) = geometryCoordinatePoint(2); + } + + //check planar + if (geometryCoordinatePoint(2) < minZ) + { + minZ = geometryCoordinatePoint(2); + } + + if (geometryCoordinatePoint(2) > maxZ) + { + maxZ = geometryCoordinatePoint(2); + } + + } + + return (std::abs(maxZ - minZ) <= aErrorConstant); + } + + + BoostMask::BoostRing2D BoostMask::convertRTTBPolygonToBoostRing(const rttb::PolygonType& + aRTTBPolygon) const + { + BoostMask::BoostRing2D polygon2D; + BoostPoint2D firstPoint; + + for (unsigned int i = 0; i < aRTTBPolygon.size(); i++) + { + rttb::WorldCoordinate3D rttbPoint = aRTTBPolygon.at(i); + BoostPoint2D boostPoint(rttbPoint[0], rttbPoint[1]); + + if (i == 0) + { + firstPoint = boostPoint; + } + + ::boost::geometry::append(polygon2D, boostPoint); + } + + ::boost::geometry::append(polygon2D, firstPoint); + return polygon2D; + } + + BoostMask::BoostRingMap BoostMask::convertRTTBPolygonSequenceToBoostRingMap( + const rttb::PolygonSequenceType& aRTTBPolygonVector) const + { + rttb::PolygonSequenceType::const_iterator it; + BoostMask::BoostRingMap aRingMap; + + for (it = aRTTBPolygonVector.begin(); it != aRTTBPolygonVector.end(); ++it) + { + rttb::PolygonType rttbPolygon = *it; + double zIndex = rttbPolygon.at(0)[2];//get the first z index of the polygon + bool isFirstZ = true; + + if (!aRingMap.empty()) + { + auto findIt = findNearestKey(aRingMap, zIndex, errorConstant); + + //if the z index is found (same slice), add the polygon to vector + if (findIt != aRingMap.end()) + { + //BoostRingVector ringVector = ; + (*findIt).second.push_back(convertRTTBPolygonToBoostRing(rttbPolygon)); + isFirstZ = false; + } + } + + //if it is the first z index in the map, insert vector with the polygon + if (isFirstZ) + { + BoostRingVector ringVector; + ringVector.push_back(convertRTTBPolygonToBoostRing(rttbPolygon)); + aRingMap.insert(std::pair(zIndex, ringVector)); + } + + + } + + return aRingMap; + } + + BoostMask::BoostRingMap::iterator BoostMask::findNearestKey(BoostMask::BoostRingMap& + aBoostRingMap, double aIndex, double aErrorConstant) const + { + auto find = aBoostRingMap.find(aIndex); + + //if find a key equivalent to aIndex, found + if (find != aBoostRingMap.end()) + { + return find; + } + else + { + auto lowerBound = aBoostRingMap.lower_bound(aIndex); + + //if all keys go before aIndex, check the last key + if (lowerBound == aBoostRingMap.end()) + { + lowerBound = --aBoostRingMap.end(); + } + + //if the lower bound very close to aIndex, found + if (std::abs((*lowerBound).first - aIndex) <= aErrorConstant) + { + return lowerBound; + } + else + { + //if the lower bound is the beginning, not found + if (lowerBound == aBoostRingMap.begin()) + { + return aBoostRingMap.end(); + } + else + { + auto lowerBound1 = --lowerBound;//the key before the lower bound + + //if the key before the lower bound very close to a Index, found + if (std::abs((*lowerBound1).first - aIndex) <= aErrorConstant) + { + return lowerBound1; + } + //else, not found + else + { + return aBoostRingMap.end(); + } + } + } + + } + } + + BoostMask::BoostPolygonVector BoostMask::checkDonutAndConvert(const BoostMask::BoostRingVector& + aRingVector) const + { + //check donut + BoostMask::BoostRingVector::const_iterator it1; + BoostMask::BoostRingVector::const_iterator it2; + BoostMask::BoostPolygonVector boostPolygonVector; + std::vector donutIndexVector;//store the outer and inner ring index + BoostMask::BoostPolygonVector donutVector;//store new generated donut polygon + + //Get donut index and donut polygon + unsigned int index1 = 0; + + for (it1 = aRingVector.begin(); it1 != aRingVector.end(); ++it1, index1++) + { + bool it1IsDonut = false; + + //check if the ring is already determined as a donut + for (unsigned int i : donutIndexVector) + { + if (i == index1) + { + it1IsDonut = true; + break; + } + } + + //if not jet, check now + if (!it1IsDonut) + { + bool it2IsDonut = false; + unsigned int index2 = 0; + + for (it2 = aRingVector.begin(); it2 != aRingVector.end(); ++it2, index2++) + { + if (it2 != it1) + { + BoostMask::BoostPolygon2D polygon2D; + + if (::boost::geometry::within(*it1, *it2)) + { + ::boost::geometry::append(polygon2D, *it2);//append an outer ring to the polygon + ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring + ::boost::geometry::append(polygon2D, *it1, 0);//append a ring to the interior ring + it2IsDonut = true; + } + //if donut + else if (::boost::geometry::within(*it2, *it1)) + { + ::boost::geometry::append(polygon2D, *it1);//append an outer ring to the polygon + ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring + ::boost::geometry::append(polygon2D, *it2, 0);//append a ring to the interior ring + it2IsDonut = true; + } + + if (it2IsDonut) + { + donutIndexVector.push_back(index1); + donutIndexVector.push_back(index2); + donutVector.push_back(polygon2D);//store donut polygon + break;//Only store the first donut! + } + } + } + } + } + + //Store no donut polygon to boostPolygonVector + index1 = 0; + + for (it1 = aRingVector.begin(); it1 != aRingVector.end(); ++it1, index1++) + { + bool it1IsDonut = false; + + //check if the ring is the outer or inner of a donut + for (unsigned int i : donutIndexVector) + { + if (i == index1) + { + it1IsDonut = true; + break; + } + } + + if (!it1IsDonut) + { + BoostMask::BoostPolygon2D polygon2D; + ::boost::geometry::append(polygon2D, *it1); + boostPolygonVector.push_back(polygon2D);//insert the ring, which is not a part of donut + } + } + + //Append donut polygon to boostPolygonVector + BoostMask::BoostPolygonVector::iterator itDonut; + + for (itDonut = donutVector.begin(); itDonut != donutVector.end(); ++itDonut) + { + boostPolygonVector.push_back(*itDonut);//append donuts + } + + return boostPolygonVector; + } + + bool BoostMask::calcVoxelizationThickness(double& aThickness) const + { + + if (_voxelizationMap->size() <= 1) + { + aThickness = 1; + return true; + } + + double thickness = 0; + + auto it = _voxelizationMap->cbegin(); + auto it2 = ++_voxelizationMap->cbegin(); + for (; + it != _voxelizationMap->cend() && it2 != _voxelizationMap->cend(); ++it, ++it2) + { + if (thickness == 0) + { + thickness = it2->first - it->first; + } + else + { + double curThickness = it2->first - it->first; + //if not homogeneous (leave out double imprecisions), return false + if (std::abs(thickness-curThickness)>errorConstant) + { + //return false; + std::cout << "Two polygons are far from each other?" << std::endl; + } + } + + } + + if (thickness != 0) + { + aThickness = thickness; + } + else + { + aThickness = 1; + } + + return true; + } + } + } +} diff --git a/code/masks/rttbBoostMask.h b/code/masks/rttbBoostMask.h index cf994bb..1db206a 100644 --- a/code/masks/rttbBoostMask.h +++ b/code/masks/rttbBoostMask.h @@ -1,202 +1,195 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #ifndef __BOOST_MASK_R_H #define __BOOST_MASK_R_H #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbGeometricInfo.h" #include "rttbMaskAccessorInterface.h" #include #include #include #include namespace rttb { namespace masks { namespace boost { /*! @class BoostMask * @brief Implementation of voxelization using boost::geometry. * @attention If "strict" is set to true, an exception will be thrown when the given structure has self intersection. * (A structure without self intersection means all contours of the structure have no self intersection, and * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored * and the mask will be calculated, however, it may cause errors in the mask results. */ class BoostMask { public: using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; /*! @brief Constructor * @exception rttb::core::NullPointerException thrown if aDoseGeoInfo or aStructure is nullptr * @param aDoseGeoInfo the GeometricInfo * @param aStructure the structure set * @param strict indicates whether to allow self intersection in the structure. If it is set to true, an exception will be thrown when the given structure has self intersection. * @param numberOfThreads number of threads used for voxelization. default value 0 means automatic detection, using the number of Hardware thread/cores * @exception InvalidParameterException thrown if strict is true and the structure has self intersections */ BoostMask(core::GeometricInfo::Pointer aDoseGeoInfo, core::Structure::Pointer aStructure, bool strict = true, unsigned int numberOfThreads = 0); /*! @brief Generate mask and return the voxels in the mask * @exception rttb::core::InvalidParameterException thrown if the structure has self intersections */ MaskVoxelListPointer getRelevantVoxelVector(); private: using BoostPoint2D = ::boost::geometry::model::d2::point_xy; using BoostPolygon2D = ::boost::geometry::model::polygon< ::boost::geometry::model::d2::point_xy >; using BoostRing2D = ::boost::geometry::model::ring< ::boost::geometry::model::d2::point_xy >; using BoostRingVector = std::vector;//polygon without holes using BoostPolygonVector = std::vector;//polygon with or without holes using VoxelIndexVector = std::vector; typedef std::map BoostPolygonMap;//map of the z index with the vector of boost 2d polygon typedef std::map BoostRingMap;//map of the z index with the vector of boost 2d ring typedef ::boost::multi_array BoostArray2D; using BoostArray2DPointer = ::boost::shared_ptr; typedef ::boost::shared_ptr > BoostArrayMapPointer; core::GeometricInfo::Pointer _geometricInfo; core::Structure::Pointer _structure; bool _strict; /*! @brief The number of threads */ unsigned int _numberOfThreads; //@brief The thickness of the voxelization plane (the contour plane), in double dose grid index //@details for example, the first contour has the double grid index 0.1, the second 0.3, the third 0.5, then the thickness is 0.2 double _voxelizationThickness; //@brief vector of the MaskVoxel inside the structure MaskVoxelListPointer _voxelInStructure; /*! @brief The map of z index and a vector of boost ring 2d (without holes) * @details Key: the double z grid index * Value: the vector of boost ring 2d (without holes) */ BoostRingMap _ringMap; /*! @brief The min and max index of the global bounding box. * @details The first index has the minimum for x/y/z of the global bounding box. * The second index has the maximum for x/y/z of the global bounding index. */ VoxelIndexVector _globalBoundingBox; /*! @brief The voxelization map * @details key: the converted double z grid index of a contour plane * value: the 2d mask, array[i][j] = the mask value of the position (i,j) in the global bounding box, * i: 0 - (_globalBoundingBoxSize0-1), j: 0 - (_globalBoundingBoxSize1-1) */ BoostArrayMapPointer _voxelizationMap; /*! @brief If the mask is up to date */ bool _isUpToDate; /*! @brief Voxelization and generate mask */ void calcMask(); /*! @brief The preprocessing step, wich consists of the following logic and Sub setps: * @details For all contours in a struct: * 1) Transfer the contour polygons into boost::geometry structures * 1a) Convert the contur points from world coordinates into geometry coordinates. * 1b) get min and max for x/y/z of a contour * 2) Tilt check: if difference of z_min and z_max is larger then a tolerance value -> there is a tilt. Throw rttb::TiltedMaskPlaneException. * 3) Get struct-bounding-box: get x_min_struct, y_min_struct, x_max_struct, y_max_struct to define the bounding box that containes all contours of a struct in x-y-dimensions. */ void preprocessing(); /*! @brief The voxelization step, which computes the voxelization planes (in x/y) for all contours of an struct. * @details For each contour (that is in the z-Range of the reference geometry) of the struct: * 1) Allocate result array (voxelization plane) based on the bounding box (see Preprocessing Step 3) * 2) Generate voxelization plane for the contour (based on the x-y-raster of the reference geometry). * 3) Add result Array (key is the z-Value of the contour) */ void voxelization(); /*! @brief mask voxel Generation step which transfers the voxelization planes into the (z-)geometry of the reference geometry. * @details It consists of following Sub steps : * For all "slices" in the reference geometry : * 1) generate weight vector for all voxelization planes for a given z - value of a slice * Iterate over the bounding box of a struct.For each voxel : * 2) Compute weighted sum of all voxelization planes(use weight vector, step 1) * 2a) If sum > 0 : Add mask voxel for the current x / y(inner Loop) and z value(outer Loop). * 3) return mask voxel list. */ void generateMaskVoxelList(); /*! @brief Convert the rttb polygon with world coordinate to the rttb polygon with double geometry coordinate, calculate the current min/max * and check if the polygon is planar * @param minimum the current global minimum * @param maximum the current global maximum * @return Return true if the polygon is planar, which means that the minimal and maximal z-coordinate of the polygon is not larger than a error constant */ bool preprocessingPolygon(const rttb::PolygonType& aRTTBPolygon, rttb::PolygonType& geometryCoordinatePolygon, rttb::DoubleVoxelGridIndex3D& minimum, rttb::DoubleVoxelGridIndex3D& maximum, double aErrorConstant) const; /*! @brief Convert a rttb 3d polygon to a 2d boost ring*/ BoostRing2D convertRTTBPolygonToBoostRing(const rttb::PolygonType& aRTTBPolygon) const; /*! @brief Convert a rttb 3d polygon to a map of z index with a vector of boost 2d ring, because of tilt check use the first z index of the polygon as the map key*/ BoostRingMap convertRTTBPolygonSequenceToBoostRingMap(const rttb::PolygonSequenceType& aRTTBPolygonVector) const; /*! @brief Find the key with error constant to aIndex * @pre aBoostRingMap should not be empty * @return Return aBoostRingMap.end() if the key is not found */ BoostMask::BoostRingMap::iterator findNearestKey(BoostMask::BoostRingMap& aBoostRingMap, double aIndex, double aErrorConstant) const; /*! @brief If 2 rings in the vector build a donut, convert the 2 rings to a donut polygon, other rings unchanged*/ BoostPolygonVector checkDonutAndConvert(const BoostRingVector& aRingVector) const; /*! @brief Calculate the voxelization thickness. Return false, if the voxelization plane is not homogeneous */ bool calcVoxelizationThickness(double& aThickness) const; }; } } } #endif diff --git a/code/masks/rttbBoostMaskAccessor.cpp b/code/masks/rttbBoostMaskAccessor.cpp index 0985637..231f1a7 100644 --- a/code/masks/rttbBoostMaskAccessor.cpp +++ b/code/masks/rttbBoostMaskAccessor.cpp @@ -1,161 +1,155 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbBoostMaskAccessor.h" #include "rttbBoostMask.h" #include #include #include #include namespace rttb { namespace masks { namespace boost { BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo, bool strict) : _spStructure(aStructurePointer), _geoInfo(aGeometricInfo), _strict(strict) { _spRelevantVoxelVector = MaskVoxelListPointer(); //generate new structure set uid ::boost::uuids::uuid id; ::boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "BoostMask_" + ss.str(); } BoostMaskAccessor::~BoostMaskAccessor() = default; void BoostMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; // already calculated } BoostMask mask(::boost::make_shared(_geoInfo), _spStructure, _strict); _spRelevantVoxelVector = mask.getRelevantVoxelVector(); } BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() { // if not already generated start voxelization here updateMask(); return _spRelevantVoxelVector; } BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector( float lowerThreshold) { auto filteredVoxelVectorPointer = ::boost::make_shared(); updateMask(); // filter relevant voxels auto it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } bool BoostMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { auto it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } } // returns false if mask was not calculated without triggering calculation (otherwise not const!) else { return false; } return false; } bool BoostMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const { return _geoInfo; }; } } } \ No newline at end of file diff --git a/code/masks/rttbBoostMaskAccessor.h b/code/masks/rttbBoostMaskAccessor.h index 83bf37c..5a02dd4 100644 --- a/code/masks/rttbBoostMaskAccessor.h +++ b/code/masks/rttbBoostMaskAccessor.h @@ -1,121 +1,116 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __BOOST_MASK_R_ACCESSOR__H #define __BOOST_MASK_R_ACCESSOR__H #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbMaskAccessorInterface.h" #include "rttbStructure.h" #include "RTTBBoostMaskExports.h" namespace rttb { namespace masks { namespace boost { /*! @class BoostMaskAccessor * @brief Using the voxelization based on boost::geometry and generate the mask accessor. * @attention If "strict" is set to true, an exception will be thrown when the given structure has self intersection. * (A structure without self intersection means all contours of the structure have no self intersection, and * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored * and the mask will be calculated, however, it may cause errors in the mask results. */ class RTTBBoostMask_EXPORT BoostMaskAccessor : public core::MaskAccessorInterface { public: using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; using StructTypePointer = core::Structure::Pointer; private: StructTypePointer _spStructure; core::GeometricInfo _geoInfo; bool _strict; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; IDType _maskUID; public: /*! @brief Constructor with a structure pointer and a geometric info pointer * @param aStructurePointer smart pointer of the structure * @param aGeometricInfo smart pointer of the geometricInfo of the dose * @param strict indicates whether to allow self intersection in the structure. If it is set to true, an exception will be thrown when the given structure has self intersection. * @exception InvalidParameterException thrown if strict is true and the structure has self intersections */ BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo, bool strict = true); /*! @brief destructor*/ ~BoostMaskAccessor() override; /*! @brief voxelization of the given structures using boost algorithms*/ void updateMask() override; /*! @brief get vector containing all relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector() override; /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold) override; /*!@brief determine how a given voxel on the dose grid is masked * @param aID ID of the voxel in grid. * @param voxel Reference to the voxel. * @post after a valid call voxel containes the information of the specified grid voxel. If aID is not valid, voxel values are undefined. * The relevant volume fraction will be set to zero. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const override; /*!@brief determine how a given voxel on the dose grid is masked * @param aIndex 3d index of the voxel in grid. * @param voxel Reference to the voxel. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const override; /*! @brief give access to GeometricInfo*/ const core::GeometricInfo& getGeometricInfo() const override; /* @ brief is true if dose is on a homogeneous grid * @remark Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change.*/ bool isGridHomogeneous() const override { return true; }; IDType getMaskUID() const override { return _maskUID; }; }; } } } #endif diff --git a/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.cpp b/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.cpp index db6db0b..8bff3c7 100644 --- a/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.cpp +++ b/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.cpp @@ -1,157 +1,150 @@ -// ----------------------------------------------------------------------- -// 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - -#include "rttbBoostMaskGenerateMaskVoxelListThread.h" - -#include "rttbInvalidParameterException.h" -#include - - -namespace rttb -{ - namespace masks - { - namespace boost - { - BoostMaskGenerateMaskVoxelListThread::BoostMaskGenerateMaskVoxelListThread( - const VoxelIndexVector& aGlobalBoundingBox, - core::GeometricInfo::Pointer aGeometricInfo, - BoostArrayMapPointer aVoxelizationMap, - double aVoxelizationThickness, - unsigned int aBeginSlice, - unsigned int aEndSlice, - MaskVoxelListPointer aMaskVoxelList, - bool strictVoxelization, - ::boost::shared_ptr<::boost::shared_mutex> aMutex) : - _globalBoundingBox(aGlobalBoundingBox), _geometricInfo(aGeometricInfo), - _voxelizationMap(aVoxelizationMap), _voxelizationThickness(aVoxelizationThickness), - _beginSlice(aBeginSlice), _endSlice(aEndSlice), - _resultMaskVoxelList(aMaskVoxelList), _strictVoxelization(strictVoxelization), _mutex(aMutex) - {} - - void BoostMaskGenerateMaskVoxelListThread::operator()() - { - rttb::VoxelGridIndex3D minIndex = _globalBoundingBox.at(0); - rttb::VoxelGridIndex3D maxIndex = _globalBoundingBox.at(1); - unsigned int globalBoundingBoxSize0 = maxIndex[0] - minIndex[0] + 1; - unsigned int globalBoundingBoxSize1 = maxIndex[1] - minIndex[1] + 1; - - std::vector maskVoxelsInThread; - - for (unsigned int indexZ = _beginSlice; indexZ < _endSlice; ++indexZ) - { - //calculate weight vector - std::map weightVectorForZ; - calcWeightVector(indexZ, weightVectorForZ); - - //For each x,y, calc sum of all voxelization plane, use weight vector - for (unsigned int x = 0; x < globalBoundingBoxSize0; ++x) - { - for (unsigned int y = 0; y < globalBoundingBoxSize1; ++y) - { - rttb::VoxelGridIndex3D currentIndex; - currentIndex[0] = x + minIndex[0]; - currentIndex[1] = y + minIndex[1]; - currentIndex[2] = indexZ; - rttb::VoxelGridID gridID; - _geometricInfo->convert(currentIndex, gridID); - double volumeFraction = 0; - - auto it = weightVectorForZ.cbegin(); - auto itMap = _voxelizationMap->cbegin(); - - for (; it != weightVectorForZ.cend() - && itMap != _voxelizationMap->cend(); ++it, ++itMap) - { - double weight = it->second; - if (weight > 0){ - BoostArray2DPointer voxelizationArray = itMap->second; - - //calc sum of all voxelization plane, use weight - volumeFraction += (*voxelizationArray)[x][y] * weight; - } - } - - if (volumeFraction > 1 && ((volumeFraction - 1) <= errorConstant || !_strictVoxelization)) - { - volumeFraction = 1; - } - else if (volumeFraction < 0 || (volumeFraction - 1) > errorConstant) - { - throw rttb::core::InvalidParameterException("Mask calculation failed! The volume fraction should >= 0 and <= 1!"); - } - - //insert mask voxel if volumeFraction > 0 - if (volumeFraction > 0) - { - core::MaskVoxel maskVoxelPtr = core::MaskVoxel(gridID, volumeFraction); - maskVoxelsInThread.push_back(maskVoxelPtr); - } - } - - } - } - - ::boost::unique_lock<::boost::shared_mutex> lock(*_mutex); - _resultMaskVoxelList->insert(_resultMaskVoxelList->end(), maskVoxelsInThread.begin(), maskVoxelsInThread.end()); - } - - void BoostMaskGenerateMaskVoxelListThread::calcWeightVector(const rttb::VoxelGridID& aIndexZ, - std::map& weightVector) const - { - double indexZMin = aIndexZ - 0.5; - double indexZMax = aIndexZ + 0.5; - - for (auto & it : *_voxelizationMap) - { - double voxelizationPlaneIndexMin = it.first - 0.5 * _voxelizationThickness; - double voxelizationPlaneIndexMax = it.first + 0.5 * _voxelizationThickness; - double weight = 0; - - if ((voxelizationPlaneIndexMin < indexZMin) && (voxelizationPlaneIndexMax > indexZMin)) - { - if (voxelizationPlaneIndexMax < indexZMax) - { - weight = voxelizationPlaneIndexMax - indexZMin; - } - else - { - weight = 1; - } - } - else if ((voxelizationPlaneIndexMin >= indexZMin) && (voxelizationPlaneIndexMin < indexZMax)) - { - if (voxelizationPlaneIndexMax < indexZMax) - { - weight = _voxelizationThickness; - } - else - { - weight = indexZMax - voxelizationPlaneIndexMin; - } - } - - weightVector.insert(std::pair(it.first, weight)); - } - } - } - } -} +// ----------------------------------------------------------------------- +// 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. +// +//------------------------------------------------------------------------ + +#include "rttbBoostMaskGenerateMaskVoxelListThread.h" + +#include "rttbInvalidParameterException.h" +#include + +namespace rttb +{ + namespace masks + { + namespace boost + { + BoostMaskGenerateMaskVoxelListThread::BoostMaskGenerateMaskVoxelListThread( + const VoxelIndexVector& aGlobalBoundingBox, + core::GeometricInfo::Pointer aGeometricInfo, + BoostArrayMapPointer aVoxelizationMap, + double aVoxelizationThickness, + unsigned int aBeginSlice, + unsigned int aEndSlice, + MaskVoxelListPointer aMaskVoxelList, + bool strictVoxelization, + ::boost::shared_ptr<::boost::shared_mutex> aMutex) : + _globalBoundingBox(aGlobalBoundingBox), _geometricInfo(aGeometricInfo), + _voxelizationMap(aVoxelizationMap), _voxelizationThickness(aVoxelizationThickness), + _beginSlice(aBeginSlice), _endSlice(aEndSlice), + _resultMaskVoxelList(aMaskVoxelList), _strictVoxelization(strictVoxelization), _mutex(aMutex) + {} + + void BoostMaskGenerateMaskVoxelListThread::operator()() + { + rttb::VoxelGridIndex3D minIndex = _globalBoundingBox.at(0); + rttb::VoxelGridIndex3D maxIndex = _globalBoundingBox.at(1); + unsigned int globalBoundingBoxSize0 = maxIndex[0] - minIndex[0] + 1; + unsigned int globalBoundingBoxSize1 = maxIndex[1] - minIndex[1] + 1; + + std::vector maskVoxelsInThread; + + for (unsigned int indexZ = _beginSlice; indexZ < _endSlice; ++indexZ) + { + //calculate weight vector + std::map weightVectorForZ; + calcWeightVector(indexZ, weightVectorForZ); + + //For each x,y, calc sum of all voxelization plane, use weight vector + for (unsigned int x = 0; x < globalBoundingBoxSize0; ++x) + { + for (unsigned int y = 0; y < globalBoundingBoxSize1; ++y) + { + rttb::VoxelGridIndex3D currentIndex; + currentIndex[0] = x + minIndex[0]; + currentIndex[1] = y + minIndex[1]; + currentIndex[2] = indexZ; + rttb::VoxelGridID gridID; + _geometricInfo->convert(currentIndex, gridID); + double volumeFraction = 0; + + auto it = weightVectorForZ.cbegin(); + auto itMap = _voxelizationMap->cbegin(); + + for (; it != weightVectorForZ.cend() + && itMap != _voxelizationMap->cend(); ++it, ++itMap) + { + double weight = it->second; + if (weight > 0){ + BoostArray2DPointer voxelizationArray = itMap->second; + + //calc sum of all voxelization plane, use weight + volumeFraction += (*voxelizationArray)[x][y] * weight; + } + } + + if (volumeFraction > 1 && ((volumeFraction - 1) <= errorConstant || !_strictVoxelization)) + { + volumeFraction = 1; + } + else if (volumeFraction < 0 || (volumeFraction - 1) > errorConstant) + { + throw rttb::core::InvalidParameterException("Mask calculation failed! The volume fraction should >= 0 and <= 1!"); + } + + //insert mask voxel if volumeFraction > 0 + if (volumeFraction > 0) + { + core::MaskVoxel maskVoxelPtr = core::MaskVoxel(gridID, volumeFraction); + maskVoxelsInThread.push_back(maskVoxelPtr); + } + } + + } + } + + ::boost::unique_lock<::boost::shared_mutex> lock(*_mutex); + _resultMaskVoxelList->insert(_resultMaskVoxelList->end(), maskVoxelsInThread.begin(), maskVoxelsInThread.end()); + } + + void BoostMaskGenerateMaskVoxelListThread::calcWeightVector(const rttb::VoxelGridID& aIndexZ, + std::map& weightVector) const + { + double indexZMin = aIndexZ - 0.5; + double indexZMax = aIndexZ + 0.5; + + for (auto & it : *_voxelizationMap) + { + double voxelizationPlaneIndexMin = it.first - 0.5 * _voxelizationThickness; + double voxelizationPlaneIndexMax = it.first + 0.5 * _voxelizationThickness; + double weight = 0; + + if ((voxelizationPlaneIndexMin < indexZMin) && (voxelizationPlaneIndexMax > indexZMin)) + { + if (voxelizationPlaneIndexMax < indexZMax) + { + weight = voxelizationPlaneIndexMax - indexZMin; + } + else + { + weight = 1; + } + } + else if ((voxelizationPlaneIndexMin >= indexZMin) && (voxelizationPlaneIndexMin < indexZMax)) + { + if (voxelizationPlaneIndexMax < indexZMax) + { + weight = _voxelizationThickness; + } + else + { + weight = indexZMax - voxelizationPlaneIndexMin; + } + } + + weightVector.insert(std::pair(it.first, weight)); + } + } + } + } +} diff --git a/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.h b/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.h index 7be9b2f..1f42945 100644 --- a/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.h +++ b/code/masks/rttbBoostMaskGenerateMaskVoxelListThread.h @@ -1,91 +1,84 @@ -// ----------------------------------------------------------------------- -// 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - - -#ifndef __BOOST_MASK_GENERATE_MASK_VOXEL_LIST_H -#define __BOOST_MASK_GENERATE_MASK_VOXEL_LIST_H - -#include "rttbBaseType.h" -#include "rttbGeometricInfo.h" -#include "rttbMaskAccessorInterface.h" - -#include -#include -#include - -namespace rttb -{ - namespace masks - { - namespace boost - { - /*! @class BoostMaskGenerateMaskVoxelListThread - * - */ - class BoostMaskGenerateMaskVoxelListThread - { - - public: - typedef ::boost::multi_array BoostArray2D; - using BoostArray2DPointer = ::boost::shared_ptr; - typedef ::boost::shared_ptr > BoostArrayMapPointer; - using VoxelIndexVector = std::vector; - using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; - - BoostMaskGenerateMaskVoxelListThread(const VoxelIndexVector& aGlobalBoundingBox, - core::GeometricInfo::Pointer aGeometricInfo, - BoostArrayMapPointer aVoxelizationMap, - double aVoxelizationThickness, - unsigned int aBeginSlice, - unsigned int aEndSlice, - MaskVoxelListPointer aMaskVoxelList, bool strictVoxelization, ::boost::shared_ptr<::boost::shared_mutex> aMutex); - void operator()(); - - private: - VoxelIndexVector _globalBoundingBox; - core::GeometricInfo::Pointer _geometricInfo; - BoostArrayMapPointer _voxelizationMap; - bool _strictVoxelization=true; - //(for example, the first contour has the double grid index 0.1, the second 0.3, the third 0.5, then the thickness is 0.2) - double _voxelizationThickness; - - unsigned int _beginSlice; - /*! @brief _endSlice is the first index not to be processed (like a end iterator) - */ - unsigned int _endSlice; - - MaskVoxelListPointer _resultMaskVoxelList; - ::boost::shared_ptr<::boost::shared_mutex> _mutex; - - /*! @brief For each dose grid index z, calculate the weight vector for each structure contour - */ - void calcWeightVector(const rttb::VoxelGridID& aIndexZ, - std::map& weightVector) const; - - }; - - } - - - } -} - +// ----------------------------------------------------------------------- +// 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. +// +//------------------------------------------------------------------------ + +#ifndef __BOOST_MASK_GENERATE_MASK_VOXEL_LIST_H +#define __BOOST_MASK_GENERATE_MASK_VOXEL_LIST_H + +#include "rttbBaseType.h" +#include "rttbGeometricInfo.h" +#include "rttbMaskAccessorInterface.h" + +#include +#include +#include + +namespace rttb +{ + namespace masks + { + namespace boost + { + /*! @class BoostMaskGenerateMaskVoxelListThread + * + */ + class BoostMaskGenerateMaskVoxelListThread + { + + public: + typedef ::boost::multi_array BoostArray2D; + using BoostArray2DPointer = ::boost::shared_ptr; + typedef ::boost::shared_ptr > BoostArrayMapPointer; + using VoxelIndexVector = std::vector; + using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; + + BoostMaskGenerateMaskVoxelListThread(const VoxelIndexVector& aGlobalBoundingBox, + core::GeometricInfo::Pointer aGeometricInfo, + BoostArrayMapPointer aVoxelizationMap, + double aVoxelizationThickness, + unsigned int aBeginSlice, + unsigned int aEndSlice, + MaskVoxelListPointer aMaskVoxelList, bool strictVoxelization, ::boost::shared_ptr<::boost::shared_mutex> aMutex); + void operator()(); + + private: + VoxelIndexVector _globalBoundingBox; + core::GeometricInfo::Pointer _geometricInfo; + BoostArrayMapPointer _voxelizationMap; + bool _strictVoxelization=true; + //(for example, the first contour has the double grid index 0.1, the second 0.3, the third 0.5, then the thickness is 0.2) + double _voxelizationThickness; + + unsigned int _beginSlice; + /*! @brief _endSlice is the first index not to be processed (like a end iterator) + */ + unsigned int _endSlice; + + MaskVoxelListPointer _resultMaskVoxelList; + ::boost::shared_ptr<::boost::shared_mutex> _mutex; + + /*! @brief For each dose grid index z, calculate the weight vector for each structure contour + */ + void calcWeightVector(const rttb::VoxelGridID& aIndexZ, + std::map& weightVector) const; + + }; + + } + + + } +} + #endif \ No newline at end of file diff --git a/code/masks/rttbBoostMaskVoxelizationThread.cpp b/code/masks/rttbBoostMaskVoxelizationThread.cpp index d184883..693898b 100644 --- a/code/masks/rttbBoostMaskVoxelizationThread.cpp +++ b/code/masks/rttbBoostMaskVoxelizationThread.cpp @@ -1,174 +1,168 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbBoostMaskVoxelizationThread.h" #include "rttbInvalidParameterException.h" #include #include #include namespace rttb { namespace masks { namespace boost { BoostMaskVoxelizationThread::BoostMaskVoxelizationThread(const BoostPolygonMap& APolygonMap, const VoxelIndexVector& aGlobalBoundingBox, BoostArrayMapPointer anArrayMap, ::boost::shared_ptr<::boost::shared_mutex> aMutex, bool strict) : _geometryCoordinateBoostPolygonMap(APolygonMap), _globalBoundingBox(aGlobalBoundingBox), _resultVoxelization(anArrayMap), _mutex(aMutex), _strict(strict) { } void BoostMaskVoxelizationThread::operator()() { rttb::VoxelGridIndex3D minIndex = _globalBoundingBox.at(0); rttb::VoxelGridIndex3D maxIndex = _globalBoundingBox.at(1); const unsigned int globalBoundingBoxSize0 = maxIndex[0] - minIndex[0] + 1; const unsigned int globalBoundingBoxSize1 = maxIndex[1] - minIndex[1] + 1; std::map > voxelizationMapInThread; for (auto & it : _geometryCoordinateBoostPolygonMap) { BoostArray2D maskArray(::boost::extents[globalBoundingBoxSize0][globalBoundingBoxSize1]); BoostPolygonVector boostPolygonVec = it.second; for (unsigned int x = 0; x < globalBoundingBoxSize0; ++x) { for (unsigned int y = 0; y < globalBoundingBoxSize1; ++y) { rttb::VoxelGridIndex3D currentIndex; currentIndex[0] = x + minIndex[0]; currentIndex[1] = y + minIndex[1]; currentIndex[2] = 0; //Get intersection polygons of the dose voxel and the structure BoostPolygonDeque polygons = getIntersections(currentIndex, boostPolygonVec); //Calc areas of all intersection polygons double volumeFraction = calcArea(polygons); volumeFraction = correctForErrorAndStrictness(volumeFraction, _strict); if (volumeFraction < 0 || volumeFraction > 1 ) { throw rttb::core::InvalidParameterException("Mask calculation failed! The volume fraction should >= 0 and <= 1!"); } maskArray[x][y] = volumeFraction; } } voxelizationMapInThread.insert(std::pair(it.first, ::boost::make_shared(maskArray))); } //insert gathered values into voxelization map ::boost::unique_lock<::boost::shared_mutex> lock(*_mutex); _resultVoxelization->insert(voxelizationMapInThread.begin(), voxelizationMapInThread.end()); } /*Get intersection polygons of the contour and a voxel polygon*/ BoostMaskVoxelizationThread::BoostPolygonDeque BoostMaskVoxelizationThread::getIntersections( const rttb::VoxelGridIndex3D& aVoxelIndex3D, const BoostPolygonVector& intersectionSlicePolygons) { BoostMaskVoxelizationThread::BoostPolygonDeque polygonDeque; BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); ::boost::geometry::correct(voxelPolygon); BoostPolygonVector::const_iterator it; for (it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it) { BoostPolygon2D contour = *it; ::boost::geometry::correct(contour); BoostPolygonDeque intersection; ::boost::geometry::intersection(voxelPolygon, contour, intersection); polygonDeque.insert(polygonDeque.end(), intersection.begin(), intersection.end()); } return polygonDeque; } BoostMaskVoxelizationThread::BoostRing2D BoostMaskVoxelizationThread::get2DContour( const rttb::VoxelGridIndex3D& aVoxelGrid3D) { BoostRing2D polygon; BoostPoint2D point1(aVoxelGrid3D[0] - 0.5, aVoxelGrid3D[1] - 0.5); ::boost::geometry::append(polygon, point1); BoostPoint2D point2(aVoxelGrid3D[0] + 0.5, aVoxelGrid3D[1] - 0.5); ::boost::geometry::append(polygon, point2); BoostPoint2D point3(aVoxelGrid3D[0] + 0.5, aVoxelGrid3D[1] + 0.5); ::boost::geometry::append(polygon, point3); BoostPoint2D point4(aVoxelGrid3D[0] - 0.5, aVoxelGrid3D[1] + 0.5); ::boost::geometry::append(polygon, point4); ::boost::geometry::append(polygon, point1); return polygon; } /*Calculate the intersection area*/ double BoostMaskVoxelizationThread::calcArea(const BoostPolygonDeque& aPolygonDeque) { double area = 0; BoostPolygonDeque::const_iterator it; for (it = aPolygonDeque.begin(); it != aPolygonDeque.end(); ++it) { area += ::boost::geometry::area(*it); } return area; } double BoostMaskVoxelizationThread::correctForErrorAndStrictness(double volumeFraction, bool strict) const { if (strict){ if (volumeFraction > 1 && (volumeFraction - 1) <= errorConstant) { volumeFraction = 1; } } else { if (volumeFraction > 1){ volumeFraction = 1; } else if (volumeFraction < 0){ volumeFraction = 0; } } return volumeFraction; } } } } diff --git a/code/masks/rttbBoostMaskVoxelizationThread.h b/code/masks/rttbBoostMaskVoxelizationThread.h index 3ffd14c..b31079f 100644 --- a/code/masks/rttbBoostMaskVoxelizationThread.h +++ b/code/masks/rttbBoostMaskVoxelizationThread.h @@ -1,109 +1,102 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #ifndef __BOOST_MASK_VOXELIZATION_THREAD_H #define __BOOST_MASK_VOXELIZATION_THREAD_H #include #include "rttbBaseType.h" #include #include #include #include #include namespace rttb { namespace masks { namespace boost { /*! @class BoostMaskGenerateMaskVoxelListThread * */ class BoostMaskVoxelizationThread { public: using BoostPolygon2D = ::boost::geometry::model::polygon< ::boost::geometry::model::d2::point_xy >; using BoostPolygonVector = std::vector;//polygon with or without holes typedef std::map BoostPolygonMap;//map of the z index with the vector of boost 2d polygon using VoxelIndexVector = std::vector; typedef ::boost::multi_array BoostArray2D; using BoostArray2DPointer = ::boost::shared_ptr; typedef ::boost::shared_ptr > BoostArrayMapPointer; /*! @brief Constructor * @param aMutex a mutex for thread-safe handling of the _resultVoxelization * @param strict true means that volumeFractions of <0 and >1 are NOT corrected. Otherwise, they are automatically corrected to 0 or 1, respectively. */ BoostMaskVoxelizationThread(const BoostPolygonMap& APolygonMap, const VoxelIndexVector& aGlobalBoundingBox, BoostArrayMapPointer anArrayMap, ::boost::shared_ptr<::boost::shared_mutex> aMutex, bool strict); void operator()(); private: using BoostPolygonDeque = std::deque; using BoostRing2D = ::boost::geometry::model::ring< ::boost::geometry::model::d2::point_xy >; using BoostPoint2D = ::boost::geometry::model::d2::point_xy; BoostPolygonMap _geometryCoordinateBoostPolygonMap; VoxelIndexVector _globalBoundingBox; BoostArrayMapPointer _resultVoxelization; ::boost::shared_ptr<::boost::shared_mutex> _mutex; bool _strict; /*! @brief Get intersection polygons of the contour and a voxel polygon * @param aVoxelIndex3D The 3d grid index of the voxel * @param intersectionSlicePolygons The polygons of the slice intersecting the voxel * @return Return all intersection polygons of the structure and the voxel */ static BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D, const BoostPolygonVector& intersectionSlicePolygons); /*! @brief Get the voxel 2d contour polygon in geometry coordinate*/ static BoostRing2D get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D); /*! @brief Calculate the area of all polygons * @param aPolygonDeque The deque of polygons * @return Return the area of all polygons */ static double calcArea(const BoostPolygonDeque& aPolygonDeque); /*! @brief Corrects the volumeFraction * @details the volume fraction is corrected in case of strict=true. Otherwise, it's only corrected for double imprecision * @return The corrected volumeFraction */ double correctForErrorAndStrictness(double volumeFraction, bool strict) const; }; } } } #endif \ No newline at end of file diff --git a/code/masks/rttbGenericMutableMaskAccessor.cpp b/code/masks/rttbGenericMutableMaskAccessor.cpp index 3e0fd97..16f2eac 100644 --- a/code/masks/rttbGenericMutableMaskAccessor.cpp +++ b/code/masks/rttbGenericMutableMaskAccessor.cpp @@ -1,179 +1,173 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbGenericMutableMaskAccessor.h" #include "rttbMaskVoxel.h" #include "rttbNullPointerException.h" #include #include #include #include namespace rttb { namespace masks { GenericMutableMaskAccessor::GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo) : _geoInfo(aGeometricInfo), _spRelevantVoxelVector(MaskVoxelListPointer()) { //generate new structure set uid boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "GenericMutableMask_" + ss.str(); } GenericMutableMaskAccessor::~GenericMutableMaskAccessor() = default; void GenericMutableMaskAccessor::updateMask() {} GenericMutableMaskAccessor::MaskVoxelListPointer GenericMutableMaskAccessor::getRelevantVoxelVector() { return _spRelevantVoxelVector; } GenericMutableMaskAccessor::MaskVoxelListPointer GenericMutableMaskAccessor::getRelevantVoxelVector( float lowerThreshold) { auto filteredVoxelVectorPointer = boost::make_shared(); // filter relevant voxels auto it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } bool GenericMutableMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { auto it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } //aID is not in mask voxel.setRelevantVolumeFraction(0); } return false; } bool GenericMutableMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } void GenericMutableMaskAccessor::setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel) { //check if ID is valid if (!_geoInfo.validID(aID)) { return; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { auto it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { (*it) = voxel; return; } ++it; } //not sID is not found in existing voxels _spRelevantVoxelVector->push_back(voxel); } } void GenericMutableMaskAccessor::setMaskAt(const VoxelGridIndex3D& aIndex, const core::MaskVoxel& voxel) { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { setMaskAt(aVoxelGridID, voxel); } } void GenericMutableMaskAccessor::setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer) { _spRelevantVoxelVector = MaskVoxelListPointer(aVoxelListPointer); } } } \ No newline at end of file diff --git a/code/masks/rttbGenericMutableMaskAccessor.h b/code/masks/rttbGenericMutableMaskAccessor.h index ed5e2cf..f85cb7d 100644 --- a/code/masks/rttbGenericMutableMaskAccessor.h +++ b/code/masks/rttbGenericMutableMaskAccessor.h @@ -1,107 +1,102 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __GENERIC_MUTABLE_MASK_ACCESSOR_H #define __GENERIC_MUTABLE_MASK_ACCESSOR_H #include "rttbMutableMaskAccessorInterface.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" namespace rttb { namespace masks { /*! @class GenericMutableMaskAccessor @brief Default implementation of MutableMaskAccessorInterface. @see MutableMaskAccessorInterface */ class GenericMutableMaskAccessor: public core::MutableMaskAccessorInterface { public: using MaskVoxelList = core::MutableMaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MutableMaskAccessorInterface::MaskVoxelListPointer; private: core::GeometricInfo _geoInfo; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; IDType _maskUID; GenericMutableMaskAccessor(const GenericMutableMaskAccessor&) = delete; //not implemented on purpose -> non-copyable GenericMutableMaskAccessor& operator=(const GenericMutableMaskAccessor&) = delete;//not implemented on purpose -> non-copyable public: ~GenericMutableMaskAccessor() override; GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo); /*! @brief initialize mask structure if _spRelevantVoxelVector was not previously initialized*/ void updateMask() override; /*! @brief get vector containing all relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector() override; /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold) override; /*!@brief determine how a given voxel on the dose grid is masked * @param aID ID of the voxel in grid. * @param voxel Reference to the voxel. * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. * The relevant volume fraction will be set to zero. * @return Indicates if the voxel exists and therefore if parameter voxel contains valid values.*/ bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const override; bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const override; /* @ brief is true if dose is on a homogeneous grid */ // Inhomogeneous grids are not supported at the moment, but if they will // be supported in the future the interface does not need to change. bool isGridHomogeneous() const override { return true; }; /*! @brief give access to GeometricInfo*/ inline const core::GeometricInfo& getGeometricInfo() const override { return _geoInfo; }; IDType getMaskUID() const override { return _maskUID; }; void setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel) override; void setMaskAt(const VoxelGridIndex3D& gridIndex, const core::MaskVoxel& voxel) override; void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer) override; }; } } #endif \ No newline at end of file diff --git a/code/models/rttbBaseTypeModels.h b/code/models/rttbBaseTypeModels.h index 07285cd..d5d6370 100644 --- a/code/models/rttbBaseTypeModels.h +++ b/code/models/rttbBaseTypeModels.h @@ -1,52 +1,46 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __BASE_TYPE_MODEL_H #define __BASE_TYPE_MODEL_H #include #include "rttbBaseType.h" namespace rttb { namespace models { using BioModelParamType = double; using BioModelValueType = double; const double infinity = 1e30; struct TcpParams { double alphaMean; double alphaVariance; double rho; std::vector volumeVector; std::vector bedVector; }; } } #endif \ No newline at end of file diff --git a/code/models/rttbBioModel.cpp b/code/models/rttbBioModel.cpp index 4a4b9f7..3417517 100644 --- a/code/models/rttbBioModel.cpp +++ b/code/models/rttbBioModel.cpp @@ -1,62 +1,55 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #define _USE_MATH_DEFINES #include #include #include "rttbBioModel.h" - namespace rttb { namespace models { bool BioModel::init(const double doseFactor) { if (_dvh != nullptr) { _value = this->calcModel(doseFactor); return true; } return false; } void BioModel::setDVH(const DVHPointer aDVH) { _dvh = aDVH; } const BioModel::DVHPointer BioModel::getDVH() const { return _dvh; } const BioModelValueType BioModel::getValue() const { return _value; } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbBioModel.h b/code/models/rttbBioModel.h index 3d0d091..6fef77d 100644 --- a/code/models/rttbBioModel.h +++ b/code/models/rttbBioModel.h @@ -1,110 +1,104 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __BIO_MODEL_H #define __BIO_MODEL_H #include "rttbDVH.h" #include "rttbBaseTypeModels.h" #include #include "RTTBModelsExports.h" #include namespace rttb { namespace models { /*! @class BioModel @brief This is the interface class for biological models */ class RTTBModels_EXPORT BioModel { public: rttbClassMacroNoParent(BioModel) using ParamVectorType = std::vector; using DVHPointer = core::DVH::Pointer; protected: DVHPointer _dvh; BioModelValueType _value{0}; /*! @brief Calculate the model value @param doseFactor scaling factor for the dose. The model calculation will use the dvh with each di=old di*doseFactor. */ virtual BioModelValueType calcModel(const double doseFactor = 1) = 0; /* Map of all parameters */ std::map parameterMap; std::string _name; public: BioModel() = default; BioModel(DVHPointer aDvh): _dvh(aDvh), _value(0) {}; virtual ~BioModel()= default; /*! @brief Start the calculation. If any parameter changed, init() should be called again and return =true before getValue() is called! @return Return true if successful */ bool init(const double doseFactor = 1); /*! @param aDVH must be a DVH calculated by a cumulative dose distribution, not a fraction DVH! */ void setDVH(const DVHPointer aDVH); const DVHPointer getDVH() const; /*! @brief Set parameter vector, where index of vector is the parameter ID. */ virtual void setParameterVector(const ParamVectorType& aParameterVector) = 0; virtual void setParameterByID(const int aParamId, const BioModelParamType aValue) = 0; /*! @brief Get parameter by ID. @return Return -1 if ID is not found. */ virtual const int getParameterID(const std::string& aParamName) const = 0; virtual std::map getParameterMap() const = 0; virtual void fillParameterMap() = 0 ; virtual std::string getModelType() const = 0; /*! @brief Get the value of biological model @pre init() must be called and =true! */ const BioModelValueType getValue() const; }; }//end namespace models }//end namespace rttb #endif diff --git a/code/models/rttbBioModelCurve.cpp b/code/models/rttbBioModelCurve.cpp index a4565d2..24ca50c 100644 --- a/code/models/rttbBioModelCurve.cpp +++ b/code/models/rttbBioModelCurve.cpp @@ -1,93 +1,87 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "rttbBioModel.h" #include "rttbNTCPLKBModel.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" namespace rttb { namespace models { CurveDataType getCurveDoseVSBioModel(BioModel& aModel, double normalisationDose, int aBin, double minDose, double maxDose) { CurveDataType _curveData; double minFactor = 0, maxFactor = 0; minFactor = minDose / normalisationDose; maxFactor = maxDose / normalisationDose; double lastValue = 0; for (int i = 0; i < aBin; i++) { double factor = minFactor + i * (maxFactor - minFactor) / (aBin - 1); if (lastValue < 1) { aModel.init(factor); BioModelValueType value = aModel.getValue(); lastValue = value; _curveData.insert(CurvePointType(factor * normalisationDose, value)); } else { _curveData.insert(CurvePointType(factor * normalisationDose, 1)); } } return _curveData; } CurveDataType getCurveEUDVSBioModel(NTCPLKBModel& aModel, DoseCalcType maxFactor, DoseCalcType minFactor, int aBin) { CurveDataType _curveData; BioModel::DVHPointer _dvh = aModel.getDVH(); for (int i = 0; i < aBin; i++) { DoseCalcType factor = minFactor + i * (maxFactor - minFactor) / (aBin - 1); core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), _dvh->getDeltaD() * factor, _dvh->getDeltaV(), "temporary", "temporary"); auto spDVH = boost::make_shared(variantDVH); double eud = getEUD(spDVH, aModel.getA()); aModel.init(factor); BioModelValueType value = aModel.getValue(); _curveData.insert(CurvePointType(eud, value)); } return _curveData; } } } \ No newline at end of file diff --git a/code/models/rttbBioModelCurve.h b/code/models/rttbBioModelCurve.h index 8bd6f5a..7e4e44d 100644 --- a/code/models/rttbBioModelCurve.h +++ b/code/models/rttbBioModelCurve.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __MODEL_CURVE_H #define __MODEL_CURVE_H namespace rttb { namespace models { class BioModel; class NTCPLKBModel; //map of dose value and model value typedef std::map CurveDataType; //pair of dose value and model value typedef std::pair CurvePointType; /*! @brief Get the curve TCP/NTCP Value vs normalisationDose, normalisationDose variant between minDose and maxDose. @param aBin the size of the map @param minDose min value for x axis @param maxDose max value for x axis @param normalisationDose prescribed dose of the current _dvh or mean/maximum. */ CurveDataType getCurveDoseVSBioModel(BioModel& aModel, double normalisationDose, int aBin = 201, double minDose = 0.1, double maxDose = 150); /*! @brief Get the curve NTCP Value vs EUD, dvh variant between minFactor*deltaD and maxFactor*deltaD. @param aBin the size of the map @param minFactor min factor for dvh deltaD @param maxFactor max factor for dvh deltaD */ CurveDataType getCurveEUDVSBioModel(NTCPLKBModel& aModel, DoseCalcType maxFactor = 10, DoseCalcType minFactor = 0.1, int aBin = 201); } } #endif \ No newline at end of file diff --git a/code/models/rttbBioModelScatterPlots.cpp b/code/models/rttbBioModelScatterPlots.cpp index b33a133..67565ef 100644 --- a/code/models/rttbBioModelScatterPlots.cpp +++ b/code/models/rttbBioModelScatterPlots.cpp @@ -1,220 +1,214 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "rttbBioModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace models { /* Initiate Random Number generator with current time */ boost::random::mt19937 rng(static_cast(time(nullptr))); /* Generate random number between 0 and 1 */ boost::random::uniform_01 uniDist(rng); ScatterPlotType getScatterPlotVary1Parameter(BioModel& aModel, int aParamId, BioModelParamType aMean, BioModelParamType aVariance, DoseTypeGy aNormalisationDose, int numberOfPoints, DoseTypeGy aMinDose, DoseTypeGy aMaxDose) { ScatterPlotType scatterPlotData; if (aVariance == 0) { //set to small positive value to avoid negative infinity! aVariance = 1e-30; } if (aMaxDose <= aMinDose) { throw core::InvalidParameterException("Parameter invalid: aMaxDose must be > aMinDose!"); } if (aNormalisationDose <= 0) { throw core::InvalidParameterException("Parameter invalid: aNormalisationDose must be > 0!"); } /* Choose Normal Distribution */ boost::random::normal_distribution gaussian_dist(0, aVariance); /* Create a Gaussian Random Number generator * by binding with previously defined * normal distribution object */ boost::random::variate_generator > generator( rng, gaussian_dist); int i = 0; while (i < numberOfPoints) { double paramValue, probability; double randomValue = generator(); paramValue = randomValue + aMean; probability = normal_pdf(randomValue, aVariance); if (probability > 1) { probability = 1; } //randomly select a dose between aMinDose and aMaxDose double dose = uniDist() * (aMaxDose - aMinDose) + aMinDose; if (probability > 0) { try { aModel.setParameterByID(aParamId, paramValue); aModel.init(dose / aNormalisationDose); double value = aModel.getValue(); std::pair modelProbPair = std::make_pair(value, probability); scatterPlotData.insert(std::pair >(dose, modelProbPair)); i++; } catch (core::InvalidParameterException& /*e*/) { //repeat evaluation to guarantee the correct number of scatter values continue; } } } return scatterPlotData; } double normal_pdf(double aValue, double aVariance) { static const double inv_sqrt_2pi = 0.3989422804014327; double a = (aValue) / aVariance; return inv_sqrt_2pi / aVariance * std::exp(-0.5f * a * a); } ScatterPlotType getScatterPlotVaryParameters(BioModel& aModel, std::vector aParamIdVec, BioModel::ParamVectorType aMeanVec, BioModel::ParamVectorType aVarianceVec, DoseTypeGy aNormalisationDose, int numberOfPoints, DoseTypeGy aMinDose, DoseTypeGy aMaxDose) { ScatterPlotType scatterPlotData; if (aMaxDose <= aMinDose) { throw core::InvalidParameterException("Parameter invalid: aMaxDose must be > aMinDose!"); } if (aNormalisationDose <= 0) { throw core::InvalidParameterException("Parameter invalid: aNormalisationDose must be > 0!"); } //all input vectors need to have the same size if (((aVarianceVec.size() != aMeanVec.size()) || (aVarianceVec.size() != aParamIdVec.size()))) { throw core::InvalidParameterException("Parameter vectors have different sizes!"); } for (double & v : aVarianceVec) { //set to small positive value to avoid negative infinity! if (v == 0) { v = 1e-30; } } double paramValue; // vary all parameters for each scattered point int i = 0; while (i < numberOfPoints) { double probability = 1; for (GridIndexType j = 0; j < aParamIdVec.size(); j++) { /* Choose Normal Distribution */ boost::random::normal_distribution gaussian_dist(0, aVarianceVec.at(j)); /* Create a Gaussian Random Number generator * by binding with previously defined * normal distribution object */ boost::random::variate_generator > generator( rng, gaussian_dist); double randomValue = generator(); paramValue = randomValue + aMeanVec.at(j); if (aVarianceVec.at(j) != 0) { /* calculate combined probability */ probability = probability * normal_pdf(randomValue, aVarianceVec.at(j)); } else { throw core::InvalidParameterException("Parameter invalid: Variance should not be 0!"); } aModel.setParameterByID(aParamIdVec.at(j), paramValue); } //randomly select a dose between aMinDose and aMaxDose double dose = uniDist() * (aMaxDose - aMinDose) + aMinDose; if (probability > 0) { try { aModel.init(dose / aNormalisationDose); double value = aModel.getValue(); std::pair modelProbPair = std::make_pair(value, probability); scatterPlotData.insert(std::pair >(dose, modelProbPair)); i++; } catch (core::InvalidParameterException& /*e*/) { //repeat evaluation to guarantee the correct number of scatter values continue; } } } return scatterPlotData; } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbBioModelScatterPlots.h b/code/models/rttbBioModelScatterPlots.h index ea3d31b..9268b63 100644 --- a/code/models/rttbBioModelScatterPlots.h +++ b/code/models/rttbBioModelScatterPlots.h @@ -1,96 +1,90 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __MODEL_SCATTER_H #define __MODEL_SCATTER_H #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { class BioModel; // maps dose to a pair of model value and probability typedef std::multimap > ScatterPlotType; using ParamVectorType = std::vector; /*! @brief Get the points (TCP/NTCP Value, probability of the value) if 1 parameter vary from a normal- distribution with mean=aMean, variance=aVariance. @param aModel biological model for which the scatter plot will be generated @param aParamId ID of the parameter to be varied to generate the scatter plot @param aMean mean value for the distribution of the varied parameter @param aVariance variance of the varied parameter. The variance may not be exactly zero. If so, it is set to 1e-30 to avoid numerical instability. @param aNormalisationDose prescribed dose of the current _dvh @param numberOfPoints the size of the map, number of points to be calculated @param aMinDose dose will be randomly selected from [aMinDose] (uniform distribution). They will define the minvalue for x axis @param aMaxDose dose will be randomly selected from [aMaxDose] (uniform distribution). They will define the max value for x axis @return Map of scattered values. If all parameters are valid, this map contains numberOfPoints valid scatter values. If aMaxDose<=aMinDose, the scatter plot cannot be generated. The map will therefore be empty. @warning This method is slow, do not use with too many points. Because the scatter plot map must contain numberOfPoints the scatter plot generation may run more often (producing invalid values). In tests the generation process runs on average approximately 20% more often. @exception InvalidParameterException Thrown if aNormalisationDose<=0 or aMinDose<=aMaxiDose */ ScatterPlotType getScatterPlotVary1Parameter(BioModel& aModel, int aParamId, BioModelParamType aMean, BioModelParamType aVariance, DoseTypeGy aNormalisationDose, int numberOfPoints = 100, DoseTypeGy aMinDose = 0, DoseTypeGy aMaxDose = 150); /*! @brief Get the points (TCP/NTCP Value, probability of the value) if >=1 parameter vary from a normal- distribution with mean of parameter aParamIdVec.at(i)=aMeanVec.at(i), variance of parameter aParamIdVec.at(i)= aVarianceVec.at(i). @param aModel biological model for which the scatter plot will be generated @param aParamIdVec a vector containing the IDs of the parameters to be varied to generate the scatter plot @param aMeanVec a vector of mean values for the distribution of individually the varied parameters @param aVarianceVec a vector of variance values of the individually varied parameter. The variance may not be exactly zero for any parameter. If so, it is set to 1e-30 to avoid numerical instability. @param aNormalisationDose prescribed dose of the current _dvh @param numberOfPoints the size of the map, number of points to be calculated @param aMinDose dose will be randomly selected from [aMinDose] (uniform distribution). They will define the min value for x axis @param aMaxDose dose will be randomly selected from [aMaxDose] (uniform distribution). They will define the max value for x axis @throw InvalidParameterException is thrown if the parameter vectors do not have the same size. @return Map of scattered values. If all parameters are valid, this map contains numberOfPoints valid scatter values. If aMaxDose<=aMinDose, the scatter plot cannot be generated. The map will therefore be empty. @warning This method is very slow do not use with too many points. Because the scatter plot map must contain numberOfPoints the scatter plot generation may run more often (producing invalid values). In tests the generation process runs on average approximately 20% more often. @exception InvalidParameterException Thrown if aNormalisationDose<=0 or aMinDose<=aMaxiDose */ ScatterPlotType getScatterPlotVaryParameters(BioModel& aModel, std::vector aParamIdVec, ParamVectorType aMeanVec, ParamVectorType aVarianceVec, DoseTypeGy aNormalisationDose, int numberOfPoints = 50, DoseTypeGy aMinDose = 0, DoseTypeGy aMaxDose = 150); /*! Compute normal probability density function for zero mean at aValue with aVariance. */ double normal_pdf(double aValue, double aVariance); } } #endif \ No newline at end of file diff --git a/code/models/rttbDoseBasedModels.cpp b/code/models/rttbDoseBasedModels.cpp index b473c4a..ad62861 100644 --- a/code/models/rttbDoseBasedModels.cpp +++ b/code/models/rttbDoseBasedModels.cpp @@ -1,41 +1,36 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include "rttbDoseBasedModels.h" #include "rttbInvalidParameterException.h" #include namespace rttb { namespace models { rttb::models::BioModelValueType calcLQ(DoseTypeGy dose, DoseCalcType alpha, DoseCalcType beta, unsigned int nFractions) { if (dose < 0 || alpha < 0 || beta < 0) { throw core::InvalidParameterException("Parameter invalid: dose, alpha, beta must be >=0!"); } return exp(-((alpha * dose) + (beta * dose * dose / DoseCalcType(nFractions)))); } } } \ No newline at end of file diff --git a/code/models/rttbDoseBasedModels.h b/code/models/rttbDoseBasedModels.h index fa9a7d6..0101de3 100644 --- a/code/models/rttbDoseBasedModels.h +++ b/code/models/rttbDoseBasedModels.h @@ -1,43 +1,37 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ -#include "rttbBaseTypeModels.h" +#include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @brief Calculate biological LinearQuadratic Model of a dose @details \f$LQ = exp(-\frac{alpha*d+beta*d^2}{nFractions})\f$ @param dose @param alpha @param beta @param nFractions the number of fractions @pre dose>=0 @pre alpha>=0 @pre beta>=0 @return The LQ value @exception rttb::core::InvalidParameterException Thrown if parameters were not set correctly. */ BioModelValueType calcLQ(DoseTypeGy dose, DoseCalcType alpha, DoseCalcType beta, unsigned int nFractions=1); } } \ No newline at end of file diff --git a/code/models/rttbDvhBasedModels.cpp b/code/models/rttbDvhBasedModels.cpp index f72f97b..0eb56c2 100644 --- a/code/models/rttbDvhBasedModels.cpp +++ b/code/models/rttbDvhBasedModels.cpp @@ -1,177 +1,172 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace models { DoseStatisticType getEUD(core::DVH::ConstPointer dvh, const DoseCalcType aA) { if (aA == 0) { throw core::InvalidParameterException("Parameter invalid: aA should not be zero!"); } DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } double eud = 0; DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); for (GridIndexType i = 0; i < dataDifferential.size(); i++) { double doseGyi = (i + 0.5) * deltaD; double relativeVolumei = dataDifferential[i] / numberOfVoxels; eud += pow((double)doseGyi, (double)aA) * relativeVolumei; } eud = pow((double)eud, (double)(1 / aA)); return eud; } BEDDVHType calcBEDDVH(core::DVH::ConstPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume) { std::map dataBED; std::map dataBEDRelative; DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } if (alpha_beta <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha_beta must be >0!"); } if (numberOfFractions <= 0) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); std::deque::iterator it; int i = 0; for (it = dataDifferential.begin(); it != dataDifferential.end(); ++it) { DoseTypeGy doseGyi = ((i + 0.5) * deltaD); DoseTypeGy bedi = 0; bedi = (doseGyi * (1 + doseGyi / (numberOfFractions * alpha_beta))); if (!relativeVolume) { dataBED.insert(std::pair(bedi, (*it))); } else { dataBEDRelative.insert(std::pair(bedi, (*it) / numberOfVoxels)); } i++; } if (!relativeVolume) { return dataBED; } else { return dataBEDRelative; } } LQEDDVHType calcLQED2DVH(core::DVH::ConstPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume) { std::map dataLQED2; std::map dataLQED2Relative; DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } if (alpha_beta <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha_beta must be >0!"); } if (numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); std::deque::iterator it; int i = 0; for (it = dataDifferential.begin(); it != dataDifferential.end(); ++it) { DoseTypeGy doseGyi = ((i + 0.5) * deltaD); DoseTypeGy lqed2i = 0; lqed2i = (doseGyi * ((alpha_beta + doseGyi / numberOfFractions) / (alpha_beta + 2))); if (!relativeVolume) { dataLQED2.insert(std::pair(lqed2i, *it)); } else { dataLQED2Relative.insert(std::pair(lqed2i, (*it) / numberOfVoxels)); } i++; } if (!relativeVolume) { return dataLQED2; } else { return dataLQED2Relative; } } } } \ No newline at end of file diff --git a/code/models/rttbDvhBasedModels.h b/code/models/rttbDvhBasedModels.h index 875f927..7d5334e 100644 --- a/code/models/rttbDvhBasedModels.h +++ b/code/models/rttbDvhBasedModels.h @@ -1,50 +1,65 @@ +// ----------------------------------------------------------------------- +// 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. +// +//------------------------------------------------------------------------ + #include #include "rttbDVH.h" #include "rttbBaseType.h" namespace rttb { namespace models { using DataDifferentialType = core::DVH::DataDifferentialType; typedef std::map BEDDVHType; typedef std::map LQEDDVHType; /*! @brief Get Equivalent Uniform Dose (EUD) @pre dvh data differential is not empty, @pre aA is not zero, @return Return calculated EUD value, @exception InvalidParameterException Thrown if parameters were not set correctly. */ DoseStatisticType getEUD(core::DVH::ConstPointer dvh, const DoseCalcType aA); /*! @brief Calculate Biological Effective/Equivalent Dose (BED) of dvh @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 @return Return map: keys are BEDi in Gy, values are the volume of the dose bin @exception InvalidParameterException Thrown if parameters were not set correctly. */ BEDDVHType calcBEDDVH(core::DVH::ConstPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume = false); /*! @brief Calculate Linear-quadratic equivalent dose for 2-Gy (LQED2) of dvh @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 @return Return map: keys are LQED2 in Gy, values are the volume of the dose bin; return empty map if not initialized @exception InvalidParameterException Thrown if parameters were not set correctly. */ LQEDDVHType calcLQED2DVH(core::DVH::ConstPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume = false); } } \ No newline at end of file diff --git a/code/models/rttbIntegration.cpp b/code/models/rttbIntegration.cpp index 2ec03c5..115467c 100644 --- a/code/models/rttbIntegration.cpp +++ b/code/models/rttbIntegration.cpp @@ -1,192 +1,186 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include #include #include "rttbIntegration.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace models { double tcpModelFunctor::calculate(double x) const { if (x == 0) { x = 1e-30; } return tcpFunction(a + (1 - x) / x, params) / (x * x); } double LkbModelFunctor::calculate(double x) const { if (x == 0) { x = 1e-30; } return lkbFunction(b - (1 - x) / x) / (x * x); } double tcpFunction(double x, const TcpParams& tcp_params) { double alphaVariance = tcp_params.alphaVariance; if (alphaVariance == 0) { alphaVariance = 1e-30; } double f = exp(-pow((x - tcp_params.alphaMean) / alphaVariance, 2) / 2); for (size_t i = 0; i < tcp_params.volumeVector.size(); ++i) { double tmp, tmp1, tmp2, tmp3; tmp1 = exp(-x * tcp_params.bedVector.at(i)); tmp2 = -(tcp_params.rho) * tcp_params.volumeVector.at(i); tmp3 = tmp2 * tmp1; tmp = exp(tmp3); if (tmp != 1) { f = f * tmp; } } return f; } double integrateTCP(double a, const TcpParams& params) { double aNew = 1e-30; double bNew = 1.0; tcpModelFunctor BMFunction; BMFunction.params = params; BMFunction.a = a; return iterativeIntegration(BMFunction, aNew, bNew); } double lkbFunction(double x) { double tmp = -pow(x, 2) / 2; double step = exp(tmp); return step; } double integrateLKB(double b) { double aNew = 1e-30; double bNew = 1.0; LkbModelFunctor BMFunction; BMFunction.b = b; return iterativeIntegration(BMFunction, aNew, bNew); } //returns the nth stage of refinement of the extended trapezoidal rule template integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, int stepNum) { static integrationType result; if (stepNum == 1) { result = 0.5 * (b - a) * (BMfunction.calculate(a) + BMfunction.calculate(b)); } else { integrationType x, tnm, sum, del; int it, j; for (it = 1, j = 1; j < stepNum - 1; j++) { it <<= 1; } tnm = it; del = (b - a) / tnm; x = a + 0.5 * del; for (sum = 0.0, j = 0; j < it; j++, x += del) { sum += BMfunction.calculate(x); } result = 0.5 * (result + (b - a) * sum / tnm); } return result; } template integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, integrationType b) { integrationType ost = 0.0; integrationType os = 0.0; unsigned int maxSteps = 50; double eps = 1e-6; unsigned int i = 1; for (; i <= maxSteps; ++i) { integrationType st = trapzd(BMfunction, a, b, i); integrationType s = (4.0 * st - ost) / 3.0; if (i > 5) { if (fabs(s - os) < eps * fabs(os) || (s == 0.0 && os == 0.0)) { return s; } } os = s; ost = st; } //too many iterations, this should never be reachable! throw rttb::core::InvalidParameterException("Integral calculation failed: too many iterations! "); } } } diff --git a/code/models/rttbIntegration.h b/code/models/rttbIntegration.h index 5878aa0..23b7ece 100644 --- a/code/models/rttbIntegration.h +++ b/code/models/rttbIntegration.h @@ -1,119 +1,114 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __INTEGRATION_H #define __INTEGRATION_H #include "rttbBaseTypeModels.h" namespace rttb { namespace models { using integrationType = double; /*! @class LkbModelFunctor @brief A FunctorType: calculate the transformed LKB-Model @details LBK Model is calculated using the transformation \f$x = b - \frac{1-t}{t}\f$. \f$\int_{-\infty}^{b} dx\f$, \f$f(x) = \int_0^1 dt \frac{f(b - \frac{(1-t)}{t})}{t^2}\f$ */ class LkbModelFunctor { public: /*!b: upper bound of the lkb integration*/ double b; /*! calculate the transformed LKB-Model using the transformation \f$x = b - \frac{1-t}{t}.\f$ */ double calculate(double x) const; }; /*! @class tcpModelFunctor @brief A FunctorType: calculate the transformed TCP-LQ-Model @details LBK Model is calculated using the transformation \f$x = a + \frac{1-t}{t}\f$. \f$\int_{a}^{+\infty} dx f(x) =\int_0^1 dt \frac{f(a + \frac{(1-t)}{t}}{t^2}\f$ */ class tcpModelFunctor { public: //TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector TcpParams params; /*! a: lower bound of the tcp integration*/ double a; /*! calculate the transformed TCP-LQ-Model using the transformation \f$x = a + \frac{1-t}{t}\f$. */ double calculate(double x) const; }; /*! @brief Function to be integrated for TCP LQ model. @param x: variable of the TCP LQ model @param tcp_params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector @return Return the function value */ double tcpFunction(double x, const TcpParams& tcp_params); /*! @brief Compute integration step for \f$f(x) = exp(-\frac{t^2}{2})\f$. @param x: variable of the lkb function @return Return the function value */ double lkbFunction(double x); /*! @brief Calculate LKB Integration over \f$(-\infty,b)\f$. The integral is mapped onto the semi-open interval \f$(0,1]\f$ using the transformation \f$x = b - \frac{1-t}{t}\f$ @param b: upper bound of the lkb integration */ double integrateLKB(double b); /*! @brief Calculate TCP integration over \f$(a, \infty)\f$. The integral is mapped onto the semi-open interval \f$(0,1]\f$ using the transformation \f$x = a + \frac{1-t}{t}\f$ @param a: lower bound of the tcp integration @param params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector */ double integrateTCP(double a, const TcpParams& params); /* @brief This function returns the nth stage of refinement of the extended trapezoidal rule. @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor @param a: lower bound of the integral @param b: upper bound of the integral @param stepNum: the nth stage @param result: the current result */ template integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, int stepNum); /*! @brief Iterative integration routine @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor @param a: lower bound of the integral @param b: upper bound of the integral @exception throw InvalidParameterException if integral calculation failed. */ template integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, integrationType b); } } #endif \ No newline at end of file diff --git a/code/models/rttbLQModelAccessor.cpp b/code/models/rttbLQModelAccessor.cpp index edc564d..850e246 100644 --- a/code/models/rttbLQModelAccessor.cpp +++ b/code/models/rttbLQModelAccessor.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbLQModelAccessor.h" #include "rttbDoseBasedModels.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbMappingOutsideOfImageException.h" namespace rttb { namespace models { LQModelAccessor::~LQModelAccessor() = default; LQModelAccessor::LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta, unsigned int nFractions, double doseScaling) : _dose(dose), _alpha(alpha), _beta(beta), _nFractions(nFractions), _alphaMap(nullptr), _betaMap(nullptr), _doseScaling(doseScaling), _withAlphaBetaMaps(false) { if (_dose == nullptr) { throw core::InvalidDoseException("Dose is nullptr"); } if (_doseScaling < 0) { throw core::InvalidParameterException("Dose Scaling must be >0"); } assembleGeometricInfo(); } LQModelAccessor::LQModelAccessor(DoseAccessorPointer dose, DoseAccessorPointer alphaMap, DoseAccessorPointer betaMap, unsigned int nFractions, double doseScaling) :_dose(dose), _alpha(-1.), _beta(-1.), _nFractions(nFractions), _alphaMap(betaMap), _betaMap(alphaMap), _doseScaling(doseScaling), _withAlphaBetaMaps(true) { if (_dose == nullptr || _alphaMap == nullptr || _betaMap == nullptr) { throw core::InvalidDoseException("Dose or alphaMap or betaMap is nullptr"); } if (_doseScaling < 0) { throw core::InvalidParameterException("Dose Scaling must be >0"); } assembleGeometricInfo(); } GenericValueType LQModelAccessor::getValueAt(const VoxelGridID aID) const { VoxelGridIndex3D aVoxelGridIndex3D; if (_geoInfo.convert(aID, aVoxelGridIndex3D)) { return getValueAt(aVoxelGridIndex3D); } else { throw core::MappingOutsideOfImageException("Error in conversion from index to world coordinates"); } } GenericValueType LQModelAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { if (_withAlphaBetaMaps){ return calcLQ(_dose->getValueAt(aIndex) * _doseScaling, _alphaMap->getValueAt(aIndex), _betaMap->getValueAt(aIndex), _nFractions); } else { return calcLQ(_dose->getValueAt(aIndex) * _doseScaling, _alpha, _beta, _nFractions); } } void LQModelAccessor::assembleGeometricInfo() { _geoInfo = _dose->getGeometricInfo(); } } } diff --git a/code/models/rttbLQModelAccessor.h b/code/models/rttbLQModelAccessor.h index 3c6ab46..c97ba08 100644 --- a/code/models/rttbLQModelAccessor.h +++ b/code/models/rttbLQModelAccessor.h @@ -1,92 +1,87 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __LQ_MODEL_ACCESSOR_H #define __LQ_MODEL_ACCESSOR_H #include "rttbAccessorWithGeoInfoBase.h" #include "rttbDoseAccessorInterface.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @class LQModelAccessor @brief This class gives access to the LQ Model information in an image */ class LQModelAccessor: public core::AccessorWithGeoInfoBase { public: using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; private: DoseAccessorPointer _dose; BioModelParamType _alpha; BioModelParamType _beta; unsigned int _nFractions; DoseAccessorPointer _alphaMap; DoseAccessorPointer _betaMap; double _doseScaling; bool _withAlphaBetaMaps; IDType _bioModelUID; LQModelAccessor() = delete; /*! @brief get all required data from the dose geometric info */ void assembleGeometricInfo() override; public: ~LQModelAccessor() override; /*! @brief Constructor. @pre dose must be a valid instance (and != nullptr) @exception InvalidDoseException if _dose is nullptr */ LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta, unsigned int nFractions=1, double doseScaling = 1.0); /*! @brief Constructor. @pre dose must be a valid instance (and != nullptr) @exception InvalidDoseException if dose is nullptr, if alphaMap is nullptr or if betaMap is nullptr */ LQModelAccessor(DoseAccessorPointer dose, DoseAccessorPointer alphaMap, DoseAccessorPointer betaMap, unsigned int nFractions = 1, double doseScaling = 1.0); /*! @brief returns the LQ Model value for an id */ GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief returns the LQ Model value for an index */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return _bioModelUID; }; }; } } #endif diff --git a/code/models/rttbNTCPLKBModel.cpp b/code/models/rttbNTCPLKBModel.cpp index 34fd4ad..b7cc495 100644 --- a/code/models/rttbNTCPLKBModel.cpp +++ b/code/models/rttbNTCPLKBModel.cpp @@ -1,181 +1,175 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #define _USE_MATH_DEFINES #include #include #include #include #include #include "rttbIntegration.h" #include "rttbNTCPLKBModel.h" #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" - namespace rttb { namespace models { NTCPLKBModel::NTCPLKBModel() : NTCPModel(){ _name = "NTCPLKBModel"; fillParameterMap(); } NTCPLKBModel::NTCPLKBModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aM, BioModelParamType aA): NTCPModel(aDvh, aD50), _m(aM), _a(aA) { _name = "NTCPLKBModel"; fillParameterMap(); } void NTCPLKBModel::setA(const BioModelParamType aA) { _a = aA; } const BioModelParamType NTCPLKBModel::getA() { return _a; } void NTCPLKBModel::setM(const BioModelParamType aM) { _m = aM; } const BioModelParamType NTCPLKBModel::getM() { return _m; } void NTCPLKBModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 3! "); } else { _d50 = aParameterVector.at(0); _m = aParameterVector.at(1); _a = aParameterVector.at(2); } } void NTCPLKBModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _d50 = aValue; } else if (aParamId == 1) { _m = aValue; } else if (aParamId == 2) { _a = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(for d50) or 1(for m) or 2(for a)! "); } } const int NTCPLKBModel::getParameterID(const std::string& aParamName) const { if (aParamName == "d50") { return 0; } else if (aParamName == "m") { return 1; } else if (aParamName == "a") { return 2; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be d50 or m or a!"); } } std::map NTCPLKBModel::getParameterMap() const{ return parameterMap; } void NTCPLKBModel::fillParameterMap(){ parameterMap["d50"] = getD50(); parameterMap["m"] = getM(); parameterMap["a"] = getA(); } std::string NTCPLKBModel::getModelType() const{ return _name; } BioModelValueType NTCPLKBModel::calcModel(const double doseFactor) { if (_a == 0) { throw core::InvalidParameterException("_a must not be zero"); } if (_m == 0) { throw core::InvalidParameterException("_m must not be zero"); } core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), _dvh->getDeltaV(), "temporary", "temporary"); auto spDVH = boost::make_shared(variantDVH); double eud = getEUD(spDVH, this->_a); //_m must not be zero double t = (eud - this->_d50) / (this->_m * this->_d50); double value = 1 / pow(2 * M_PI, 0.5); double result = integrateLKB(t); if (result != -100) { value *= result; return value; } else { return false; } } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbNTCPLKBModel.h b/code/models/rttbNTCPLKBModel.h index 23c6c71..56b8690 100644 --- a/code/models/rttbNTCPLKBModel.h +++ b/code/models/rttbNTCPLKBModel.h @@ -1,104 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __NTCP_LKB_MODEL_H #define __NTCP_LKB_MODEL_H #include #include "rttbNTCPModel.h" #include "rttbBaseTypeModels.h" - - namespace rttb { namespace models { /*! @class NTCPLKBModel @brief This class represents a NTCP(Normal Tissue Complication Probability) LKB model (Lyman 1985, Kutcher and Burman 1989) @see NTCPModel */ class NTCPLKBModel: public NTCPModel { public: using ParamVectorType = NTCPModel::ParamVectorType; private: /*! The steepness of the dose-response curve. Must not be zero on model evaluation. */ BioModelParamType _m{0}; /*! Tumor or normal tissue-specific parameter that describes the dose-volume effect, e.g. -10 for prostate (Wu 2002). Must not be zero on model evaluation, because EUD calculation will fail. */ BioModelParamType _a{0}; protected: /*! @brief Calculate the model value * @param doseFactor: scaling factor for the dose. The model calculation will use the dvh with each di=old di*doseFactor. * @throw if either _a or _m is zero for the model calculation */ BioModelValueType calcModel(const double doseFactor = 1) override; public: NTCPLKBModel(); NTCPLKBModel(core::DVH::Pointer aDvh, BioModelParamType aD50, BioModelParamType aM, BioModelParamType aA); void setM(const BioModelParamType aM); const BioModelParamType getM(); void setA(const BioModelParamType aA); const BioModelParamType getA(); /*! @brief Set parameter with ID. "d50":0,"m":1,"a":2 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2. */ void setParameterByID(const int aParamId, const BioModelParamType aValue) override; /*! @brief Set parameter vector, where index of vector is the parameter ID. "d50":0,"m":1,"a":2 @exception InvalidParameterException Thrown if aParamterVector.size()!=3. */ void setParameterVector(const ParamVectorType& aParameterVector) override; /*! @brief Get parameter ID. "d50":0,"m":1,"a":2 @return 0 for "d50", 1 for "m", 2 for "a" @exception InvalidParameterException Thrown if aParamName is not d50 or m or a. */ const int getParameterID(const std::string& aParamName) const override; std::map getParameterMap() const override; void fillParameterMap() override; std::string getModelType() const override; }; } } #endif diff --git a/code/models/rttbNTCPModel.h b/code/models/rttbNTCPModel.h index 6e509d8..8648bfa 100644 --- a/code/models/rttbNTCPModel.h +++ b/code/models/rttbNTCPModel.h @@ -1,66 +1,57 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __NTCP_MODEL_H #define __NTCP_MODEL_H - #include "rttbBioModel.h" #include "rttbBaseTypeModels.h" - - namespace rttb { namespace models { /*! @class NTCPModel @brief This is the interface class for NTCP(Normal Tissue Complication Probability) models */ class NTCPModel: public BioModel { public: using ParamVectorType = BioModel::ParamVectorType; protected: BioModelParamType _d50{0}; public: NTCPModel(): BioModel() {} NTCPModel(const BioModelParamType aD50): BioModel(), _d50(aD50) {} NTCPModel(core::DVH::Pointer aDvh, const BioModelParamType aD50): BioModel(aDvh), _d50(aD50) {} const BioModelParamType getD50() { return _d50; } void setD50(const BioModelParamType aD50) { _d50 = aD50; } }; }//end namespace models }//end namespace rttb #endif diff --git a/code/models/rttbNTCPRSModel.cpp b/code/models/rttbNTCPRSModel.cpp index 372ed39..e2b549e 100644 --- a/code/models/rttbNTCPRSModel.cpp +++ b/code/models/rttbNTCPRSModel.cpp @@ -1,173 +1,168 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #define _USE_MATH_DEFINES #include #include #include "rttbNTCPRSModel.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace models { NTCPRSModel::NTCPRSModel() : NTCPModel() { _name = "NTCPRSModel"; fillParameterMap(); } NTCPRSModel::NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, BioModelParamType aS): NTCPModel(aDvh, aD50), _gamma(aGamma), _s(aS) { _name = "NTCPRSModel"; fillParameterMap(); } void NTCPRSModel::setGamma(const BioModelParamType aGamma) { _gamma = aGamma; } const BioModelParamType NTCPRSModel::getGamma() { return _gamma; } void NTCPRSModel::setS(const BioModelParamType aS) { _s = aS; } const BioModelParamType NTCPRSModel::getS() { return _s; } void NTCPRSModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 3! "); } else { _d50 = aParameterVector.at(0); _gamma = aParameterVector.at(1); _s = aParameterVector.at(2); } } void NTCPRSModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _d50 = aValue; } else if (aParamId == 1) { _gamma = aValue; } else if (aParamId == 2) { _s = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(for d50) or 1(for gamma) or 2(for s)! "); } } const int NTCPRSModel::getParameterID(const std::string& aParamName) const { if (aParamName == "d50") { return 0; } else if (aParamName == "gamma") { return 1; } else if (aParamName == "s") { return 2; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be d50 or gamma or s!"); } } std::map NTCPRSModel::getParameterMap() const{ return parameterMap; } void NTCPRSModel::fillParameterMap() { parameterMap["d50"] = getD50(); parameterMap["gamma"] = getGamma(); parameterMap["s"] = getS(); } std::string NTCPRSModel::getModelType() const{ return _name; } const double NTCPRSModel::poissonModel(const double dose) { //_d50 must not be zero return pow(2, -exp(M_E * this->_gamma * (1 - dose / this->_d50))); } BioModelValueType NTCPRSModel::calcModel(double doseFactor) { if (_d50 == 0) { throw core::InvalidParameterException("d50 must not be zero"); } if (_s == 0) { throw core::InvalidParameterException("s must not be zero"); } std::deque dataDifferential = this->_dvh->getDataDifferential(); double ntcp = 1; for (GridIndexType i = 0; i < dataDifferential.size(); i++) { double pd = pow(this->poissonModel(i * this->_dvh->getDeltaD() * doseFactor), this->_s); double vi = dataDifferential[i] / this->_dvh->getNumberOfVoxels(); ntcp *= pow((1 - pd), vi); } //_s must not be zero return (BioModelValueType)(pow((1 - ntcp), 1 / this->_s)); } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbNTCPRSModel.h b/code/models/rttbNTCPRSModel.h index 9aba15b..387871b 100644 --- a/code/models/rttbNTCPRSModel.h +++ b/code/models/rttbNTCPRSModel.h @@ -1,111 +1,104 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __NTCP_RS_MODEL_H #define __NTCP_RS_MODEL_H #include #include "rttbNTCPModel.h" #include "rttbBaseTypeModels.h" - namespace rttb { namespace models { /*! @class NTCPRSModel @brief This class represents a NTCP(Normal Tissue Complication Probability) relative seriality model (Kaellman 1992) @see NTCPModel */ class NTCPRSModel: public NTCPModel { public: using ParamVectorType = NTCPModel::ParamVectorType; using DVHPointer = NTCPModel::DVHPointer; private: /*! _gamma The normalised dose-response gradient, values between 1.7 and 2.0 are typical for human tumours. (Kaellman 1992) */ BioModelParamType _gamma{0}; /*! _s The relative seriality factor, e.g. s=3.4 for the esophagus (highly serial structure) and s=0.0061 for the lung(highly parallel structure). Must not be zero on model evaluation. */ BioModelParamType _s{0}; const double poissonModel(const double dose); protected: /*! @brief Calculate the model value @param doseFactor scaling factor for the dose. The model calculation will use the dvh with each di=old di*doseFactor. @throw if either _s or _d50 is zero for the model calculation. */ BioModelValueType calcModel(const double doseFactor = 1) override; public: NTCPRSModel(); /*!@brief Constructor initializing all member variables with given parameters. */ NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, BioModelParamType aS); void setGamma(const BioModelParamType aGamma); const BioModelParamType getGamma(); void setS(const BioModelParamType aS); const BioModelParamType getS(); /*! @brief Set parameter with ID. "d50":0,"gamma":1,"s":2 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2. */ void setParameterByID(const int aParamId, const BioModelParamType aValue) override; /*! @brief Set parameter vector, where index of vector is the parameter Id. "d50":0,"gamma":1,"s":2 @exception InvalidParameterException Thrown if aParamterVector.size()!=3. */ void setParameterVector(const ParamVectorType& aParameterVector) override; /*! @brief Get parameter ID. "d50":0,"gamma":1,"s":2 @return 0 for "d50", 1 for "gamma", 2 for "s" @exception InvalidParameterException Thrown if aParamName is not d50 or gamma or s. */ const int getParameterID(const std::string& aParamName) const override; std::map getParameterMap() const override; void fillParameterMap() override; std::string getModelType() const override; }; } } #endif diff --git a/code/models/rttbTCPLQModel.cpp b/code/models/rttbTCPLQModel.cpp index ac82e94..9651baa 100644 --- a/code/models/rttbTCPLQModel.cpp +++ b/code/models/rttbTCPLQModel.cpp @@ -1,311 +1,304 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #define _USE_MATH_DEFINES #include #include #include #include #include #include "rttbTCPLQModel.h" #include "rttbDvhBasedModels.h" #include "rttbIntegration.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" - namespace rttb { namespace models { TCPLQModel::TCPLQModel(): TCPModel() { _name = "TCPLQModel"; fillParameterMap(); } TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, int aNumberOfFractions): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(0), _alpha_beta(aAlphaMean / aBeta), _rho(aRho) { _name = "TCPLQModel"; fillParameterMap(); } TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(aAlphaVariance), _alpha_beta(aAlpha_Beta), _rho(aRho) { fillParameterMap(); _name = "TCPLQModel"; } void TCPLQModel::setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance) { _alphaMean = aAlphaMean; _alphaVariance = aAlphaVariance; _alpha_beta = aAlpha_Beta; _rho = aRho; //reset _value, because parameters have changed. _value = 0; } void TCPLQModel::setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance) { _alphaVariance = aAlphaVariance; _alphaMean = aAlphaMean; } void TCPLQModel::setAlphaBeta(const BioModelParamType aAlpha_Beta) { _alpha_beta = aAlpha_Beta; } void TCPLQModel::setRho(const BioModelParamType aRho) { _rho = aRho; } const BioModelParamType TCPLQModel::getAlphaBeta() { return _alpha_beta; } const BioModelParamType TCPLQModel::getAlphaMean() { return _alphaMean; } const BioModelParamType TCPLQModel::getAlphaVariance() { return _alphaVariance; } const BioModelParamType TCPLQModel::getRho() { return _rho; } long double TCPLQModel::calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj) { return exp(-aRho * vj * exp(-aAlphaMean * bedj)); } long double TCPLQModel::calcTCP(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV) { std::map::iterator it; long double tcp = 1; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { long double tcpi = this->calcTCPi(aRho, aAlphaMean, (*it).second * aDeltaV, (*it).first); tcp = tcp * tcpi; } return tcp; } long double TCPLQModel::calcTCPAlphaNormalDistribution( std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance, double aDeltaV) { std::map::iterator it; std::vector volumeV2; std::vector bedV2; int i = 0; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { volumeV2.push_back((*it).second * aDeltaV); bedV2.push_back((*it).first); i++; } struct TcpParams params = {aAlphaMean, aAlphaVariance, aRho, volumeV2, bedV2}; double result = integrateTCP(0, params); if (result == -100) { std::cerr << "Integration error!\n"; return -1; } else { long double tcp = 1 / (pow(2 * M_PI, 0.5) * _alphaVariance) * result; return tcp; } } BioModelValueType TCPLQModel::calcModel(const double doseFactor) { core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), _dvh->getDeltaV(), "temporary", "temporary"); auto spDVH = boost::make_shared(variantDVH); BioModelValueType value = 0; if (_alphaVariance == 0) { if (_alphaMean <= 0 || _alpha_beta <= 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha, alpha/beta, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); value = (BioModelValueType)this->calcTCP(dataBED, _rho, _alphaMean, variantDVH.getDeltaV()); return value; } //if alpha normal distribution else { if (this->_alpha_beta <= 0 || this->_alphaMean <= 0 || this->_alphaVariance < 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha/beta, alphaMean, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); value = (BioModelValueType)(this->calcTCPAlphaNormalDistribution(dataBED, _rho, _alphaMean, _alphaVariance, variantDVH.getDeltaV())); return value; } } void TCPLQModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 4) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 4! "); } else { _alphaMean = aParameterVector.at(0); _alphaVariance = aParameterVector.at(1); _alpha_beta = aParameterVector.at(2); _rho = aParameterVector.at(3); } } void TCPLQModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _alphaMean = aValue; } else if (aParamId == 1) { _alphaVariance = aValue; } else if (aParamId == 2) { _alpha_beta = aValue; } else if (aParamId == 3) { _rho = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(alphaMean) or 1(alphaVariance) or 2(alpha_beta) or 3(rho)! "); } } const int TCPLQModel::getParameterID(const std::string& aParamName) const { if (aParamName == "alphaMean") { return 0; } else if (aParamName == "alphaVariance") { return 1; } else if (aParamName == "alpha_beta") { return 2; } else if (aParamName == "rho") { return 3; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be alphaMean or alphaVariance or alpha_beta or rho!"); } } std::map TCPLQModel::getParameterMap() const{ return parameterMap; } void TCPLQModel::fillParameterMap(){ parameterMap["numberOfFraction"] = getNumberOfFractions(); parameterMap["alphaMean"] = getAlphaMean(); parameterMap["alphaVariance"] = getAlphaVariance(); parameterMap["alpha_beta"] = getAlphaBeta(); parameterMap["rho"] = getRho(); } std::string TCPLQModel::getModelType() const{ return _name; } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbTCPLQModel.h b/code/models/rttbTCPLQModel.h index 3a96812..9b7eba2 100644 --- a/code/models/rttbTCPLQModel.h +++ b/code/models/rttbTCPLQModel.h @@ -1,169 +1,163 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __TCP_LQ_MODEL_H #define __TCP_LQ_MODEL_H #include #include #include "rttbTCPModel.h" #include "rttbBaseTypeModels.h" - namespace rttb { namespace models { /*! @class TCPLQModel @brief This class represents a TCP(Tumor Control Probability) LQ model (Nahum and Sanchez-Nieto 2001, Hall and Giaccia 2006) @see TCPModel */ class TCPLQModel: public TCPModel { public: using ParamVectorType = TCPModel::ParamVectorType; using DVHPointer = core::DVH::Pointer; private: /*! @brief Calculate intermediate tcp using alpha constant. This is a helper function for calcTCP() @see calcTCP */ long double calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj); /*! @brief Calculate tcp using alpha constant. */ long double calcTCP(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV); /*! @brief Calculate tcp using a normal distribution for alpha. */ long double calcTCPAlphaNormalDistribution(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance, double aDeltaV); protected: BioModelParamType _alphaMean{0}; BioModelParamType _alphaVariance{0}; BioModelParamType _alpha_beta{0}; /*! Roh is the initial clonogenic cell density */ BioModelParamType _rho{0}; /*! @brief Calculate the model value @param doseFactor scaling factor for prescribed dose. The model calculation will use the dvh with each di=old di*doseFactor. @pre _alphaMean >0 @pre _alphaVariance >= 0 @pre _alpha_beta > 0 @pre _rho > 0 @pre _numberOfFractions > 1 @exception InvalidParameterException Thrown if parameters were not set correctly. */ BioModelValueType calcModel(const double doseFactor = 1) override; public: TCPLQModel(); /*! @brief Constructor initializes member variables with given parameters. @pre aAlphaMean >0 @pre aBeta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, int aNumberOfFractions); /*! @brief Constructor for alpha distribution initializes member variables with given parameters. @pre aAlphaMean >0 @pre aAlphaVariance >0 @pre aAlpha_Beta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance); const BioModelParamType getRho(); void setRho(const BioModelParamType aRho); const BioModelParamType getAlphaMean(); const BioModelParamType getAlphaVariance(); /*! @brief The distribution of the parameter alpha, which is characteristic for a population of cells, is described by the its mean and variance. If alpha is constant the variance is 0. @param aAlphaVariance The variance of alpha can be given, the default value is 0 resulting in constant alpha. */ void setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance = 0); const BioModelParamType getAlphaBeta(); void setAlphaBeta(const BioModelParamType aAlpha_Beta); /*! @brief Set parameters for the TCP model. _value will be reset to 0. @param aAlpha_Beta alpha/beta constant . @param aAlphaMean mean of alpha distribution. @param aAlphaVariance variance of alpha distribution. */ void setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance = 0); /*! @brief Set parameter with ID. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2 or 3. */ void setParameterByID(const int aParamId, const BioModelParamType aValue) override; /*! @brief Set parameter vector, where index of vector is the parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamterVector.size()!=4. */ void setParameterVector(const ParamVectorType& aParameterVector) override; /*! @brief Get parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @return 0 for "alphaMean", 1 for "alphaVariance", 2 for "alpha_beta", 3 for "rho" @exception InvalidParameterException Thrown if aParamName is not alphaMean or alphaVariance or alpha_beta or rho. */ const int getParameterID(const std::string& aParamName) const override; std::map getParameterMap() const override; void fillParameterMap() override; std::string getModelType() const override; }; }//end algorithms }//end rttb #endif diff --git a/code/models/rttbTCPModel.cpp b/code/models/rttbTCPModel.cpp index 6eb54d3..ba528ac 100644 --- a/code/models/rttbTCPModel.cpp +++ b/code/models/rttbTCPModel.cpp @@ -1,42 +1,36 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbTCPModel.h" namespace rttb { namespace models { void TCPModel::setNumberOfFractions(const int aNumberOfFractions) { _numberOfFractions = aNumberOfFractions; } const int TCPModel::getNumberOfFractions() { return _numberOfFractions; } } } diff --git a/code/models/rttbTCPModel.h b/code/models/rttbTCPModel.h index b82577d..652903e 100644 --- a/code/models/rttbTCPModel.h +++ b/code/models/rttbTCPModel.h @@ -1,62 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __TCP_MODEL_H #define __TCP_MODEL_H - #include "rttbBioModel.h" namespace rttb { namespace models { /*! @class TCPModel @brief This is the interface class for TCP(Tumor Control Probability) models */ class TCPModel: public BioModel { public: using ParamVectorType = BioModel::ParamVectorType; protected: int _numberOfFractions{0}; public: TCPModel(): BioModel() {}; TCPModel(int aNum): BioModel(), _numberOfFractions(aNum) {}; TCPModel(core::DVH::Pointer aDvh, int aNum): BioModel(aDvh), _numberOfFractions(aNum) {}; void setNumberOfFractions(const int aNumberOfFractions); const int getNumberOfFractions(); }; }//end namespace models }//end namespace rttb #endif diff --git a/testing/algorithms/ArithmeticTest.cpp b/testing/algorithms/ArithmeticTest.cpp index 763f6d2..bad153d 100644 --- a/testing/algorithms/ArithmeticTest.cpp +++ b/testing/algorithms/ArithmeticTest.cpp @@ -1,358 +1,352 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "../core/DummyDoseAccessor.h" #include "../core/DummyMaskAccessor.h" #include "../core/DummyMutableDoseAccessor.h" #include "rttbDoseAccessorInterface.h" #include "rttbMutableDoseAccessorInterface.h" #include "rttbMutableMaskAccessorInterface.h" #include "rttbArithmetic.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbGenericMutableMaskAccessor.h" #include "rttbMaskAccessorInterface.h" namespace rttb { namespace testing { typedef core::DoseAccessorInterface::Pointer DoseAccessorPointer; typedef core::MutableDoseAccessorInterface::Pointer MutableDoseAccessorPointer; typedef DummyMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef DummyMaskAccessor::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::Pointer MaskAccessorPointer; typedef core::MutableMaskAccessorInterface::Pointer MutableMaskAccessorPointer; /*! @brief ArithmeticTest - tests arithmetic combinations of accessors 1) test dose-dose operations 2) test dose-mask operations 3) test mask-mask operations 4) test convenience functions */ int ArithmeticTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; // initialize accessors for arithmetic //DOSE: //Null pointers DoseAccessorPointer spDoseNull; MutableDoseAccessorPointer spMutableDoseNull; //dose with random values between 0 and 100 boost::shared_ptr spTestDoseAccessor1 = boost::make_shared(); DoseAccessorPointer spDoseAccessor1(spTestDoseAccessor1); //generate a 2nd dose with fixed values core::GeometricInfo geoInfo = spDoseAccessor1->getGeometricInfo(); DoseTypeGy valFix = 101; // to ensure values are larger than 100 on adding std::vector dose2Vals(geoInfo.getNumberOfVoxels(), valFix); boost::shared_ptr spTestDoseAccessor2 = boost::make_shared (dose2Vals, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); //generate result acessor std::vector doseResultVals(geoInfo.getNumberOfVoxels(), -1); boost::shared_ptr spTestMutableDoseAccessor = boost::make_shared(doseResultVals, geoInfo); MutableDoseAccessorPointer spMutableDoseAccessor(spTestMutableDoseAccessor); // different geometricInfo core::GeometricInfo geoInfo2 = geoInfo; geoInfo2.setNumColumns(5); geoInfo2.setNumRows(5); geoInfo2.setNumSlices(5); std::vector dose3Vals(geoInfo2.getNumberOfVoxels(), valFix); boost::shared_ptr spTestDoseAccessor3 = boost::make_shared (dose3Vals, geoInfo2); DoseAccessorPointer spDoseAccessorDiffGeoInfo(spTestDoseAccessor3); boost::shared_ptr spTestMutableDoseAccessor2 = boost::make_shared(dose3Vals, geoInfo2); MutableDoseAccessorPointer spMutableDoseAccessorDiffGeoInfo(spTestMutableDoseAccessor2); //MASK: //null pointer MaskAccessorPointer spMaskAccessorNull; MutableMaskAccessorPointer spMutableMaskAccessorNull; MaskVoxelList voxelList; FractionType aVolumeFraction = 1; VoxelGridID aVoxelGridID = 10; //generate a dummy mask while (aVoxelGridID < geoInfo.getNumberOfVoxels() && aVoxelGridID <= 30) { voxelList.push_back(core::MaskVoxel(aVoxelGridID, aVolumeFraction)); ++aVoxelGridID; } MaskVoxelListPointer voxelListPtr = boost::make_shared(voxelList); boost::shared_ptr dummyMask1 = boost::make_shared(geoInfo, voxelListPtr); MaskAccessorPointer spMaskAccessor1(dummyMask1); MaskVoxelList voxelList2; aVoxelGridID = 20; //generate a 2nd dummy mask that partly overlaps with the 1st one while (aVoxelGridID < geoInfo.getNumberOfVoxels() && aVoxelGridID <= 40) { voxelList2.push_back(core::MaskVoxel(aVoxelGridID, aVolumeFraction)); ++aVoxelGridID; } MaskVoxelListPointer voxelListPtr2 = boost::make_shared(voxelList2); boost::shared_ptr dummyMask2 = boost::make_shared(geoInfo, voxelListPtr2); MaskAccessorPointer spMaskAccessor2(dummyMask2); // result accessor boost::shared_ptr mMask1 = boost::make_shared(geoInfo); MutableMaskAccessorPointer spMutableMask(mMask1); // different geometricInfo boost::shared_ptr spDummyMaskDiffGeoInfo = boost::make_shared (geoInfo2, voxelListPtr2); MaskAccessorPointer spMaskAccessorDiffGeoInfo(spDummyMaskDiffGeoInfo); boost::shared_ptr mMask2 = boost::make_shared(geoInfo2); MutableMaskAccessorPointer spMutableMaskDiffGeoInfo(mMask2); // 1) test dose-dose operations //ADD algorithms::arithmetic::doseOp::Add addOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, addOP)); VoxelGridID id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseNull, spMutableDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseNull, spDoseAccessor2, spMutableDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseNull, addOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessorDiffGeoInfo, spMutableDoseAccessor, addOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessorDiffGeoInfo, spDoseAccessor2, spMutableDoseAccessor, addOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessorDiffGeoInfo, addOP), core::InvalidParameterException); //ADD_WEIGHTED algorithms::arithmetic::doseOp::AddWeighted addWOP(1, 2); CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, addWOP)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + 2 * valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + 2 * valFix, spMutableDoseAccessor->getValueAt(id)); //MULTIPLY algorithms::arithmetic::doseOp::Multiply multiplyOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, multiplyOP)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) * valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) * valFix, spMutableDoseAccessor->getValueAt(id)); // 2) test dose-mask operations //MULTIPLY algorithms::arithmetic::doseMaskOp::Multiply multOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessor, multOP)); core::MaskVoxel mVoxel(0); id = 5; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); spMaskAccessor1->getMaskAt(id, mVoxel); CHECK_EQUAL(spMutableDoseAccessor->getValueAt(id), mVoxel.getRelevantVolumeFraction()); id = 15; CHECK_EQUAL(valFix, spMutableDoseAccessor->getValueAt(id)); id = 35; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spMaskAccessorNull, spMutableDoseAccessor, multOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseNull, spDoseAccessor2, spMutableDoseAccessor, multOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseNull, multOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessorDiffGeoInfo, spMutableDoseAccessor, multOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessorDiffGeoInfo, spMaskAccessor1, spMutableDoseAccessor, multOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessorDiffGeoInfo, multOP), core::InvalidParameterException); // 3) test mask-mask operations //ADD algorithms::arithmetic::maskOp::Add maskAddOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor2, spMutableMask, maskAddOP)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessorNull, spMutableMask, maskAddOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessorNull, spMaskAccessor2, spMutableMask, maskAddOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor1, spMutableMaskAccessorNull, maskAddOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessorDiffGeoInfo, spMutableMask, maskAddOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessorDiffGeoInfo, spMaskAccessor2, spMutableMask, maskAddOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor1, spMutableMaskDiffGeoInfo, maskAddOP), core::InvalidParameterException); //SUBTRACT algorithms::arithmetic::maskOp::Subtract maskSubOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor2, spMutableMask, maskSubOP)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); // 4) test convenience functions // tests are similar to explicit calls CHECK_NO_THROW(algorithms::arithmetic::add(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); CHECK_NO_THROW(algorithms::arithmetic::add(spMaskAccessor1, spMaskAccessor2, spMutableMask)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); CHECK_NO_THROW(algorithms::arithmetic::subtract(spMaskAccessor1, spMaskAccessor2, spMutableMask)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); CHECK_NO_THROW(algorithms::arithmetic::multiply(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessor)); id = 5; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); spMaskAccessor1->getMaskAt(id, mVoxel); CHECK_EQUAL(spMutableDoseAccessor->getValueAt(id), mVoxel.getRelevantVolumeFraction()); id = 15; CHECK_EQUAL(valFix, spMutableDoseAccessor->getValueAt(id)); id = 35; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); RETURN_AND_REPORT_TEST_SUCCESS; } } } \ No newline at end of file diff --git a/testing/algorithms/BinaryFunctorAccessorTest.cpp b/testing/algorithms/BinaryFunctorAccessorTest.cpp index 8aea246..301933f 100644 --- a/testing/algorithms/BinaryFunctorAccessorTest.cpp +++ b/testing/algorithms/BinaryFunctorAccessorTest.cpp @@ -1,131 +1,125 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDoseAccessorInterface.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbArithmetic.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbBinaryFunctorAccessor.h" namespace rttb { namespace testing { typedef core::DoseAccessorInterface::Pointer DoseAccessorPointer; typedef algorithms::BinaryFunctorAccessor BinaryFunctorAccessorAddType; typedef algorithms::BinaryFunctorAccessor BinaryFunctorAccessorAddWeightedType; /*! @brief BinaryFunctorAccessorTest - tests functors of two accessors 1) test constructor 2) test getDoseAt */ int BinaryFunctorAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } if (argc > 2) { RTDOSE2_FILENAME = argv[2]; } DoseAccessorPointer spDoseAccessorNull; DoseAccessorPointer spDoseAccessor = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME.c_str()).generateDoseAccessor(); DoseAccessorPointer spDoseAccessor2 = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE2_FILENAME.c_str()).generateDoseAccessor(); algorithms::arithmetic::doseOp::Add addOP; algorithms::arithmetic::doseOp::AddWeighted addWeightedOP(1.0, 10.0); algorithms::arithmetic::doseOp::AddWeighted addWeightedTwoOP(2.0, 2.0); //1) Check constructor CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessorNull, spDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessorNull, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessorNull, spDoseAccessorNull, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessor2, addOP), core::InvalidParameterException); CHECK_NO_THROW(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessor, addOP)); CHECK_NO_THROW(BinaryFunctorAccessorAddWeightedType(spDoseAccessor, spDoseAccessor, addWeightedOP)); auto spBinaryFunctorDoseAccessorAdd = boost::make_shared(spDoseAccessor, spDoseAccessor, addOP); auto spBinaryFunctorDoseAccessorAddWeighted = boost::make_shared(spDoseAccessor, spDoseAccessor, addWeightedOP); auto spBinaryFunctorDoseAccessorAddWeightedTwo = boost::make_shared(spDoseAccessor, spDoseAccessor, addWeightedTwoOP); //2) Test getDoseAt() int lastIndex = spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumberOfVoxels() - 1; VoxelGridID aId[3] = { 5, 6067, lastIndex }; VoxelGridIndex3D aIndex[3] = {VoxelGridIndex3D(5, 0, 0), VoxelGridIndex3D(37, 0, 2), VoxelGridIndex3D(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumColumns() - 1, spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumRows() - 1, spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumSlices() - 1)}; for (int i = 0; i < 3; ++i) { CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i]), 4.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aId[i]), 22.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIndex[i]), spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i])); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIndex[i]), spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aId[i])); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i]) * 2.0, spBinaryFunctorDoseAccessorAddWeightedTwo->getValueAt(aId[i])); } VoxelGridID aIdInvalid(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumberOfVoxels()); VoxelGridIndex3D aIndexInvalid(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumColumns(), spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumRows(), spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumSlices()); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIdInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIndexInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIdInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIndexInvalid), -1.0); RETURN_AND_REPORT_TEST_SUCCESS; } } } \ No newline at end of file diff --git a/testing/algorithms/DoseStatisticsCalculatorTest.cpp b/testing/algorithms/DoseStatisticsCalculatorTest.cpp index cfb6c49..682a124 100644 --- a/testing/algorithms/DoseStatisticsCalculatorTest.cpp +++ b/testing/algorithms/DoseStatisticsCalculatorTest.cpp @@ -1,391 +1,385 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "../io/other/CompareDoseStatistic.h" #include "../../code/io/other/rttbDoseStatisticsXMLReader.h" #include "../core/DummyDoseAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::Pointer DoseIteratorPointer; typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; typedef rttb::algorithms::DoseStatistics::Pointer DoseStatisticsPointer; /*! @brief DoseStatisticsCalculatorTest - test the API of DoseStatisticsCalculator 1) test constructors 2) test setDoseIterator 3) test calculateDoseSatistics 4) get statistical values */ int DoseStatisticsCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string referenceXMLFilename; std::string doseFilename, structFilename; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); DoseIteratorPointer spDoseIteratorNull; if (argc > 3) { referenceXMLFilename = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; } //1) test constructors // the values cannot be accessed from outside, therefore correct default values are not tested CHECK_THROW_EXPLICIT(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator( spDoseIteratorNull), core::NullPointerException); CHECK_NO_THROW(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator)); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); //2) test setDoseIterator //3) test calculateDoseStatistics DoseStatisticsPointer theStatistics; //simple dose statistics CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics()); CHECK_EQUAL(theStatistics->getMinimumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getMaximumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getDx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMaxOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOCx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMinOCx().getAllValues().empty(), true); //check default values for computeComplexMeasures=true DoseStatisticsPointer theStatisticsDefault; myDoseStatsCalculator.setMultiThreading(true); CHECK_NO_THROW(theStatisticsDefault = myDoseStatsCalculator.calculateDoseStatistics(true)); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.02 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.05 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.1 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.9 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.95 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.98 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.02 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.05 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.1 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.9 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.95 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.98 * theStatisticsDefault->getVolume())); //check manually set reference dose and the default x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.1 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.1 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.1 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOHx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOCx().getValue(0.98 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //check manually set x values std::vector precomputeDoseValues, precomputeVolumeValues, additionalValues, faultyValues; precomputeDoseValues.push_back(0.01); precomputeDoseValues.push_back(0.02); precomputeDoseValues.push_back(0.05); precomputeVolumeValues.push_back(0.9); precomputeVolumeValues.push_back(0.95); precomputeVolumeValues.push_back(0.99); additionalValues.push_back(0.03); additionalValues.push_back(0.04); faultyValues.push_back(2); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, faultyValues), core::InvalidParameterException); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(faultyValues, precomputeVolumeValues), core::InvalidParameterException); CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues)); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.99 * theStatistics->getVolume())); CHECK_THROW_EXPLICIT(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(myDoseStatsCalculator.addPrecomputeValues(faultyValues), core::InvalidParameterException); CHECK_NO_THROW(myDoseStatsCalculator.addPrecomputeValues(additionalValues)); CHECK_NO_THROW(myDoseStatsCalculator.recalculateDoseStatistics()); CHECK_NO_THROW(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.95 * theStatistics->getVolume())); //check manually set reference dose and x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues, 100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //MOHx, MOCx, MaxOHx and MinOCx are computed analogous to Dx, they will not be checked. //4) get statistical values CHECK_EQUAL(theStatistics->getNumberOfVoxels(), doseVals->size()); //compute simple statistical values (min, mean, max, stddev) for comparison DoseStatisticType maximum = 0; DoseStatisticType minimum = 1000000; DoseStatisticType mean = 0; DoseStatisticType variance = 0; std::vector::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } if (minimum > *doseIt) { minimum = *doseIt; } mean += *doseIt; ++doseIt; } mean /= doseVals->size(); doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { variance += pow(*doseIt - mean, 2); ++doseIt; } variance /= doseVals->size(); DoseStatisticType stdDev = pow(variance, 0.5); //we have some precision problems here... double errorConstantLarger = 1e-2; CHECK_EQUAL(theStatistics->getMaximum(), maximum); CHECK_EQUAL(theStatistics->getMinimum(), minimum); CHECK_CLOSE(theStatistics->getMean(), mean, errorConstantLarger); CHECK_CLOSE(theStatistics->getStdDeviation(), stdDev, errorConstantLarger); CHECK_CLOSE(theStatistics->getVariance(), variance, errorConstantLarger); //check for complex doseStatistics (maximumPositions, minimumPositions, Vx, Dx, MOHx, MOCx, MAXOHx, MinOCx) unsigned int nMax = 0, nMin = 0; doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (*doseIt == theStatistics->getMaximum()) { nMax++; } if (*doseIt == theStatistics->getMinimum()) { nMin++; } ++doseIt; } //only 100 positions are stored if (nMax > 100) { nMax = 100; } if (nMin > 100) { nMin = 100; } auto maximaPositions = theStatistics->getMaximumVoxelPositions(); auto minimaPositions = theStatistics->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->size(), nMax); CHECK_EQUAL(minimaPositions->size(), nMin); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics->getMinimum()); } //generate specific example dose maximum = 9.5; minimum = 2.5; mean = 6; int sizeTemplate = 500; std::vector aDoseVector; for (int i = 0; i < sizeTemplate; i++) { aDoseVector.push_back(maximum); aDoseVector.push_back(minimum); } core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); geoInfo.setNumRows(20); geoInfo.setNumColumns(10); geoInfo.setNumSlices(5); boost::shared_ptr spTestDoseAccessor2 = boost::make_shared(aDoseVector, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); boost::shared_ptr spTestDoseIterator2 = boost::make_shared(spDoseAccessor2); DoseIteratorPointer spDoseIterator2(spTestDoseIterator2); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator2(spDoseIterator2); DoseStatisticsPointer theStatistics3 = myDoseStatsCalculator2.calculateDoseStatistics(); CHECK_EQUAL(theStatistics3->getMaximum(), maximum); CHECK_EQUAL(theStatistics3->getMinimum(), minimum); CHECK_EQUAL(theStatistics3->getMean(), mean); maximaPositions = theStatistics3->getMaximumVoxelPositions(); minimaPositions = theStatistics3->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->empty(), false); CHECK_EQUAL(minimaPositions->empty(), false); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics3->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics3->getMinimum()); } // compare with actual XML io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(doseFilename.c_str()); core::DoseAccessorInterface::Pointer doseAccessorPointer(doseAccessorGenerator.generateDoseAccessor()); rttb::io::dicom::DicomFileStructureSetGenerator structAccessorGenerator(structFilename.c_str()); structAccessorGenerator.setStructureLabelFilterActive(true); structAccessorGenerator.setFilterRegEx("Heart"); core::StructureSet::Pointer structureSetGeneratorPointer = structAccessorGenerator.generateStructureSet(); CHECK_EQUAL(structureSetGeneratorPointer->getNumberOfStructures(), 1); core::MaskAccessorInterface::Pointer maskAccessorPointer = boost::make_shared (structureSetGeneratorPointer->getStructure(0), doseAccessorPointer->getGeometricInfo(), true); maskAccessorPointer->updateMask(); boost::shared_ptr maskedDoseIterator = boost::make_shared(maskAccessorPointer, doseAccessorPointer); rttb::core::DoseIteratorInterface::Pointer doseIteratorPointer(maskedDoseIterator); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(doseIteratorPointer); DoseStatisticsPointer doseStatisticsActual = doseStatisticsCalculator.calculateDoseStatistics(14.0); io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsExpected = readerDefaultExpected.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsExpected, doseStatisticsActual)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/algorithms/DoseStatisticsTest.cpp b/testing/algorithms/DoseStatisticsTest.cpp index ef5e610..15a8059 100644 --- a/testing/algorithms/DoseStatisticsTest.cpp +++ b/testing/algorithms/DoseStatisticsTest.cpp @@ -1,251 +1,245 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDoseStatistics.h" #include "rttbDataNotAvailableException.h" #include "rttbVolumeToDoseMeasureCollection.h" namespace rttb { namespace testing { typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; /*! @brief DoseStatisticsTest - test the API of DoseStatistics 1) test constructors 2) test setters 3) test getters of complex statistics (with stored key and without stored key) */ int DoseStatisticsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; DoseStatisticType minimum = 1.0; DoseStatisticType mean = 5.5; DoseStatisticType maximum = 108.2; DoseStatisticType stdDeviation = 10.1; unsigned int numVoxels = 100000; VolumeType volume = numVoxels * (0.5 * 0.5 * 0.5); std::vector > minVoxels; std::vector > maxVoxels; minVoxels.push_back(std::make_pair(1.0, 11)); minVoxels.push_back(std::make_pair(1.0, 22)); minVoxels.push_back(std::make_pair(1.0, 33)); minVoxels.push_back(std::make_pair(1.0, 44)); maxVoxels.push_back(std::make_pair(108.2, 5)); maxVoxels.push_back(std::make_pair(108.2, 6)); maxVoxels.push_back(std::make_pair(108.2, 7)); maxVoxels.push_back(std::make_pair(108.2, 8)); ResultListPointer resultsMinVoxels = boost::make_shared > >(minVoxels); ResultListPointer resultsMaxVoxels = boost::make_shared > >(maxVoxels); algorithms::DoseToVolumeMeasureCollection Vx(algorithms::DoseToVolumeMeasureCollection::Vx, maximum); Vx.insertValue(1.1, 1000); Vx.insertValue(106.9, 99000); algorithms::VolumeToDoseMeasureCollection Dx(algorithms::VolumeToDoseMeasureCollection::Dx, volume); Dx.insertValue(1000, 1.1); Dx.insertValue(99000, 106.9); algorithms::VolumeToDoseMeasureCollection MOHx(algorithms::VolumeToDoseMeasureCollection::MOHx, volume); MOHx.insertValue(1000, 5); MOHx.insertValue(99000, 105.5); algorithms::VolumeToDoseMeasureCollection MOCx(algorithms::VolumeToDoseMeasureCollection::MOCx, volume); MOCx.insertValue(1000, 10); MOCx.insertValue(99000, 99); algorithms::VolumeToDoseMeasureCollection MaxOHx(algorithms::VolumeToDoseMeasureCollection::MaxOHx, volume); MaxOHx.insertValue(1000, 40); MaxOHx.insertValue(99000, 98.3); algorithms::VolumeToDoseMeasureCollection MinOCx(algorithms::VolumeToDoseMeasureCollection::MinOCx, volume); MinOCx.insertValue(1000, 25.5); MinOCx.insertValue(99000, 102.7); //1) test constructors CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, volume)); rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, volume); CHECK_EQUAL(aDoseStatistic.getMinimum(), minimum); CHECK_EQUAL(aDoseStatistic.getMaximum(), maximum); CHECK_EQUAL(aDoseStatistic.getMean(), mean); CHECK_EQUAL(aDoseStatistic.getStdDeviation(), stdDeviation); CHECK_EQUAL(aDoseStatistic.getVariance(), stdDeviation * stdDeviation); CHECK_EQUAL(aDoseStatistic.getNumberOfVoxels(), numVoxels); CHECK_EQUAL(aDoseStatistic.getVolume(), volume); //check default values for unset complex values CHECK_EQUAL(aDoseStatistic.getMaximumVoxelPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getMinimumVoxelPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getDx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getVx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMOHx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMOCx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMaxOHx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMinOCx().getAllValues().empty(), true); CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx)); rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx); CHECK_EQUAL(aDoseStatisticComplex.getMaximumVoxelPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatisticComplex.getMinimumVoxelPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatisticComplex.getDx() == Dx, true); CHECK_EQUAL(aDoseStatisticComplex.getVx() == Vx, true); CHECK_EQUAL(aDoseStatisticComplex.getMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatisticComplex.getMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getMinOCx() == MinOCx, true); //2) test setters (only complex statistics have setters) CHECK_NO_THROW(aDoseStatistic.setMaximumVoxelPositions(resultsMaxVoxels)); CHECK_NO_THROW(aDoseStatistic.setMinimumVoxelPositions(resultsMinVoxels)); CHECK_NO_THROW(aDoseStatistic.setDx(::boost::make_shared(Dx))); CHECK_NO_THROW(aDoseStatistic.setVx(::boost::make_shared(Vx))); CHECK_NO_THROW(aDoseStatistic.setMOHx(::boost::make_shared(MOHx))); CHECK_NO_THROW(aDoseStatistic.setMOCx(::boost::make_shared(MOCx))); CHECK_NO_THROW(aDoseStatistic.setMaxOHx(::boost::make_shared(MaxOHx))); CHECK_NO_THROW(aDoseStatistic.setMinOCx(::boost::make_shared(MinOCx))); CHECK_EQUAL(aDoseStatistic.getMaximumVoxelPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatistic.getMinimumVoxelPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatistic.getDx() == Dx, true); CHECK_EQUAL(aDoseStatistic.getVx() == Vx, true); CHECK_EQUAL(aDoseStatistic.getMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatistic.getMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatistic.getMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatistic.getMinOCx() == MinOCx, true); //3) test getters of complex statistics(with stored key and without stored key) //getAll*() already tested in (2) Vx = algorithms::DoseToVolumeMeasureCollection(algorithms::DoseToVolumeMeasureCollection::Vx, maximum); Vx.insertValue(1.1, 1000); Vx.insertValue(5.0, 2300); Vx.insertValue(90, 90500); Vx.insertValue(107, 99000); Dx = algorithms::VolumeToDoseMeasureCollection(algorithms::VolumeToDoseMeasureCollection::Dx, volume); Dx.insertValue(1000, 1.1); Dx.insertValue(2000, 2.0); Dx.insertValue(5000, 10.8); Dx.insertValue(90000, 89.5); Dx.insertValue(98000, 104.4); Dx.insertValue(99000, 106.9); rttb::algorithms::DoseStatistics aDoseStatisticNewValues(minimum, maximum, mean, stdDeviation, numVoxels, volume); aDoseStatisticNewValues.setDx(::boost::make_shared(Dx)); aDoseStatisticNewValues.setVx(::boost::make_shared(Vx)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(1.1)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(90)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(1000)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(98000)); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(1.1), Vx.getAllValues().find(1.1)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(90), Vx.getAllValues().find(90)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(1000), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(98000), Dx.getAllValues().find(98000)->second); //test if key-value combination NOT in map CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getDx().getValue(1001), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getVx().getValue(10), core::DataNotAvailableException); double closestDxKey, closestVxKey; CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(900, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(99001, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(10, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(900, true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(99001, true, closestDxKey), Dx.getAllValues().find(99000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(10, true, closestVxKey), Vx.getAllValues().find(5.0)->second); CHECK_EQUAL(closestDxKey, 99000); CHECK_EQUAL(closestVxKey, 5); // relatives only between 0 and 1 CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValueRelative(1.1 / aDoseStatistic.getReferenceDose())); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(1000 / aDoseStatistic.getVolume())); CHECK_THROW(aDoseStatisticNewValues.getVx().getValueRelative(-0.3)); CHECK_THROW(aDoseStatisticNewValues.getVx().getValueRelative(1.1)); CHECK_THROW(aDoseStatisticNewValues.getDx().getValueRelative(0.5)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(900 / aDoseStatistic.getVolume(), true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(0.5, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValueRelative(10 / aDoseStatistic.getReferenceDose(), true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValueRelative(900 / aDoseStatistic.getVolume(), true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValueRelative(10 / aDoseStatistic.getReferenceDose(), true, closestVxKey), Vx.getAllValues().find(5.0)->second); CHECK_EQUAL(closestVxKey, 5); //equal distance to two values. First value is returned. CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(1500, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(98.5, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(1500, true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(98.5, true, closestVxKey), Vx.getAllValues().find(90.0)->second); CHECK_EQUAL(closestDxKey, 1000); CHECK_EQUAL(closestVxKey, 90.0); double dummy; CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValue(25), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValue(9999), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValue(25, true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValue(9999, true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValueRelative(25 / aDoseStatistic.getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValueRelative(9999 / aDoseStatistic.getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValueRelative(25 / aDoseStatistic.getVolume(), true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValueRelative(9999 / aDoseStatistic.getVolume(), true, dummy), core::DataNotAvailableException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/algorithms/rttbAlgorithmsTests.cpp b/testing/algorithms/rttbAlgorithmsTests.cpp index e73def6..f5ce005 100644 --- a/testing/algorithms/rttbAlgorithmsTests.cpp +++ b/testing/algorithms/rttbAlgorithmsTests.cpp @@ -1,66 +1,60 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbAlgorithmsTests 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 { void registerTests() { LIT_REGISTER_TEST(DoseStatisticsTest); LIT_REGISTER_TEST(DoseStatisticsCalculatorTest); LIT_REGISTER_TEST(ArithmeticTest); LIT_REGISTER_TEST(BinaryFunctorAccessorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/apps/BioModelCalc/BioModelCalcInvalidParametersTest.cpp b/testing/apps/BioModelCalc/BioModelCalcInvalidParametersTest.cpp index ed5f185..0d1cb9c 100644 --- a/testing/apps/BioModelCalc/BioModelCalcInvalidParametersTest.cpp +++ b/testing/apps/BioModelCalc/BioModelCalcInvalidParametersTest.cpp @@ -1,98 +1,92 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (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 BioModelCalcInvalidParametersTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string bioModelCalcExecutable; if (argc > 1) { bioModelCalcExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string bioModelCalcExeWithPath = callingPath.parent_path().string() + "/" + bioModelCalcExecutable; //call with too few parameters std::string toofewParametersCommand = bioModelCalcExeWithPath; toofewParametersCommand += " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = bioModelCalcExeWithPath; toofewParametersCommand += " test test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = bioModelCalcExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -o test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); //call with invalid model std::string minimalCLI = bioModelCalcExeWithPath + " test test -p 1.0 1.0 "; std::string invalidModelOption = minimalCLI; invalidModelOption += "-m wrongModel"; std::cout << "Command line call: " + invalidModelOption << std::endl; CHECK_EQUAL(system(invalidModelOption.c_str()) != 0, true); //call with only one parameter std::string toofewModelParameterOption = bioModelCalcExeWithPath + " test test -p 1.0"; std::cout << "Command line call: " + toofewModelParameterOption << std::endl; CHECK_EQUAL(system(toofewModelParameterOption.c_str()) != 0, true); toofewModelParameterOption = bioModelCalcExeWithPath + " test test -a parameterMapsTest"; std::cout << "Command line call: " + toofewModelParameterOption << std::endl; CHECK_EQUAL(system(toofewModelParameterOption.c_str()) != 0, true); //call with invalid dose load option std::string invalidDoseLoadOption = minimalCLI; invalidDoseLoadOption += "-t invalidLoadStyleOption"; std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidDoseLoadOption.c_str()) != 0, true); //call with negative dose scaling std::string negativeDoseScalingCommand = minimalCLI; negativeDoseScalingCommand += "-e -1.0"; std::cout << "Command line call: " + negativeDoseScalingCommand << std::endl; CHECK_EQUAL(system(negativeDoseScalingCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/BioModelCalc/BioModelCalcParameterMapsTest.cpp b/testing/apps/BioModelCalc/BioModelCalcParameterMapsTest.cpp index 177f570..c683480 100644 --- a/testing/apps/BioModelCalc/BioModelCalcParameterMapsTest.cpp +++ b/testing/apps/BioModelCalc/BioModelCalcParameterMapsTest.cpp @@ -1,102 +1,96 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "litImageTester.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" #include "itkImage.h" #include "rttbITKIOHelper.h" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int BioModelCalcParameterMapsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string bioModelCalcExecutable; std::string doseFilename; std::string doseFilenameLoadStyle; std::string modelName; std::string modelParameterMaps; std::string modelParameterMapsLoadStyle; std::string referenceFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 7) { bioModelCalcExecutable = argv[1]; doseFilename = argv[2]; doseFilenameLoadStyle = argv[3]; modelName = argv[4]; modelParameterMaps = argv[5]; modelParameterMapsLoadStyle = argv[6]; referenceFilename = argv[7]; } std::string bioModelCalcExeWithPath = callingPath.parent_path().string() + "/" + bioModelCalcExecutable; std::string defaultOutputFilename = "bioModelParameterMapOutput.nrrd"; std::string baseCommand = bioModelCalcExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -t " + doseFilenameLoadStyle; baseCommand += " -o " + defaultOutputFilename; baseCommand += " -m " + modelName; baseCommand += " -a " + modelParameterMaps; baseCommand += " -u " + modelParameterMapsLoadStyle; std::string defaultDoseStatisticsCommand = baseCommand; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); // Check result against reference typedef ::itk::Image TestImageType; TestImageType::Pointer referenceImage = io::itk::readITKDoubleImage(referenceFilename); TestImageType::Pointer outputImage = io::itk::readITKDoubleImage(defaultOutputFilename); lit::ImageTester tester; tester.setExpectedImage(referenceImage); tester.setActualImage(outputImage); tester.setCheckThreshold(0.0); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/BioModelCalc/BioModelCalcSimpleTest.cpp b/testing/apps/BioModelCalc/BioModelCalcSimpleTest.cpp index 2651225..a21bbda 100644 --- a/testing/apps/BioModelCalc/BioModelCalcSimpleTest.cpp +++ b/testing/apps/BioModelCalc/BioModelCalcSimpleTest.cpp @@ -1,130 +1,124 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "litImageTester.h" #include "boost/filesystem.hpp" #include "itkImage.h" #include "rttbITKIOHelper.h" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int BioModelCalcSimpleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string bioModelCalcExecutable; std::string doseFilename; std::string doseFilenameLoadStyle; std::string modelName; std::string modelArguments; std::string referenceFilename; std::string referenceWithNFractionsFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 7) { bioModelCalcExecutable = argv[1]; doseFilename = argv[2]; doseFilenameLoadStyle = argv[3]; modelName = argv[4]; modelArguments = argv[5]; referenceFilename = argv[6]; referenceWithNFractionsFilename = argv[7]; } std::string bioModelCalcExeWithPath = callingPath.parent_path().string() + "/" + bioModelCalcExecutable; std::string defaultOutputFilename = "bioModelOutput.nrrd"; std::string baseCommand = bioModelCalcExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -t " + doseFilenameLoadStyle; baseCommand += " -o " + defaultOutputFilename; baseCommand += " -m " + modelName; baseCommand += " -p " + modelArguments; std::string defaultDoseStatisticsCommand = baseCommand; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); std::string defaultOutputWithNFractionsFilename = "bioModelWithNFractionsOutput.nrrd"; std::string baseCommandWithNFractions = bioModelCalcExeWithPath; baseCommandWithNFractions += " -d \"" + doseFilename + "\""; baseCommandWithNFractions += " -t " + doseFilenameLoadStyle; baseCommandWithNFractions += " -o " + defaultOutputWithNFractionsFilename; baseCommandWithNFractions += " -m " + modelName; baseCommandWithNFractions += " -p " + modelArguments; baseCommandWithNFractions += " -f 2"; std::cout << "Command line call: " + baseCommandWithNFractions << std::endl; CHECK_EQUAL(system(baseCommandWithNFractions.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); // Check result against reference typedef ::itk::Image TestImageType; TestImageType::Pointer referenceImage = io::itk::readITKDoubleImage(referenceFilename); TestImageType::Pointer outputImage = io::itk::readITKDoubleImage(defaultOutputFilename); lit::ImageTester tester; tester.setExpectedImage(referenceImage); tester.setActualImage(outputImage); tester.setCheckThreshold(0.0); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputWithNFractionsFilename), true); // Check result against reference TestImageType::Pointer referenceImageNFractions = io::itk::readITKDoubleImage(referenceWithNFractionsFilename); TestImageType::Pointer outputImageNFractions = io::itk::readITKDoubleImage(defaultOutputWithNFractionsFilename); lit::ImageTester testerWithNFractions; testerWithNFractions.setExpectedImage(referenceImageNFractions); testerWithNFractions.setActualImage(outputImageNFractions); testerWithNFractions.setCheckThreshold(0.0); CHECK_TESTER(testerWithNFractions); CHECK_EQUAL(std::remove(defaultOutputWithNFractionsFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/BioModelCalc/BioModelCalcTests.cpp b/testing/apps/BioModelCalc/BioModelCalcTests.cpp index b98b1b3..80c298d 100644 --- a/testing/apps/BioModelCalc/BioModelCalcTests.cpp +++ b/testing/apps/BioModelCalc/BioModelCalcTests.cpp @@ -1,71 +1,65 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { const char* _callingAppPath = nullptr; void registerTests() { LIT_REGISTER_TEST(BioModelCalcInvalidParametersTest); LIT_REGISTER_TEST(BioModelCalcSimpleTest); LIT_REGISTER_TEST(BioModelCalcParameterMapsTest); } } //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/apps/DoseAcc/DoseAccInvalidParametersTest.cpp b/testing/apps/DoseAcc/DoseAccInvalidParametersTest.cpp index b6bd47f..d67f07f 100644 --- a/testing/apps/DoseAcc/DoseAccInvalidParametersTest.cpp +++ b/testing/apps/DoseAcc/DoseAccInvalidParametersTest.cpp @@ -1,103 +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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (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 DoseAccInvalidParametersTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseAccExecutable; if (argc > 1) { doseAccExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string doseAccExeWithPath = callingPath.parent_path().string() + "/" + doseAccExecutable; //call with too few parameters std::string toofewParametersCommand = doseAccExeWithPath; toofewParametersCommand += " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseAccExeWithPath; toofewParametersCommand += " test test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseAccExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -e test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); std::string minimalCLI = doseAccExeWithPath + " test test test "; //call with invalid interpolator std::string invalidInterpolatorOption = minimalCLI; invalidInterpolatorOption += "-i wrongInterpolator"; std::cout << "Command line call: " + invalidInterpolatorOption << std::endl; CHECK_EQUAL(system(invalidInterpolatorOption.c_str()) != 0, true); //call with invalid operator std::string invalidOperatorOption = minimalCLI; invalidOperatorOption += "-p -"; std::cout << "Command line call: " + invalidOperatorOption << std::endl; CHECK_EQUAL(system(invalidOperatorOption.c_str()) != 0, true); //call with operator* and weight std::string invalidOperatorMultWithWeightOption = minimalCLI; invalidOperatorMultWithWeightOption += "-p * --weight1 2.0"; std::cout << "Command line call: " + invalidOperatorMultWithWeightOption << std::endl; CHECK_EQUAL(system(invalidOperatorMultWithWeightOption.c_str()) != 0, true); //call with invalid dose1 load option std::string invalidDose1LoadOption = minimalCLI; invalidDose1LoadOption += "-t invalidLoadStyleOption"; std::cout << "Command line call: " + invalidDose1LoadOption << std::endl; CHECK_EQUAL(system(invalidDose1LoadOption.c_str()) != 0, true); //call with invalid dose2 load option std::string invalidDose2LoadOption = minimalCLI; invalidDose2LoadOption += "-u invalidLoadStyleOption"; std::cout << "Command line call: " + invalidDose2LoadOption << std::endl; CHECK_EQUAL(system(invalidDose2LoadOption.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseAcc/DoseAccNeutralWeightTest.cpp b/testing/apps/DoseAcc/DoseAccNeutralWeightTest.cpp index 6774bf0..b08592d 100644 --- a/testing/apps/DoseAcc/DoseAccNeutralWeightTest.cpp +++ b/testing/apps/DoseAcc/DoseAccNeutralWeightTest.cpp @@ -1,108 +1,102 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "litImageTester.h" #include "boost/filesystem.hpp" #include "itkImage.h" #include "rttbITKIOHelper.h" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseAccNeutralWeightTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseAccExecutable; std::string doseFilename; std::string referenceFilename; std::string reference2Filename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 4) { doseAccExecutable = argv[1]; doseFilename = argv[2]; referenceFilename = argv[3]; reference2Filename = argv[4]; } std::string doseAccExeWithPath = callingPath.parent_path().string() + "/" + doseAccExecutable; const std::string defaultOutputAddFilename = "doseAccAddOutput.nrrd"; const std::string defaultOutputMultFilename = "doseAccMultOutput.nrrd"; std::string baseCommand = doseAccExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -e \"" + doseFilename + "\""; std::string defaultDoseAccAddCommand = baseCommand + " -o " + defaultOutputAddFilename + " --weight1 0.0"; std::cout << "Command line call: " + defaultDoseAccAddCommand << std::endl; CHECK_EQUAL(system(defaultDoseAccAddCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputAddFilename), true); std::string defaultDoseAccMultCommand = baseCommand + " -o " + defaultOutputMultFilename + " --operator \"*\""; std::cout << "Command line call: " + defaultDoseAccMultCommand << std::endl; CHECK_EQUAL(system(defaultDoseAccMultCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputMultFilename), true); // Check result against reference typedef ::itk::Image TestImageType; TestImageType::Pointer referenceAddImage = io::itk::readITKDoubleImage(referenceFilename); TestImageType::Pointer outputAddImage = io::itk::readITKDoubleImage(defaultOutputAddFilename); lit::ImageTester tester; tester.setExpectedImage(referenceAddImage); tester.setActualImage(outputAddImage); tester.setCheckThreshold(1e-5); CHECK_TESTER(tester); TestImageType::Pointer referenceMultImage = io::itk::readITKDoubleImage(reference2Filename); TestImageType::Pointer outputMultImage = io::itk::readITKDoubleImage(defaultOutputMultFilename); tester.setExpectedImage(referenceMultImage); tester.setActualImage(outputMultImage); tester.setCheckThreshold(1e-5); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputAddFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultOutputMultFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseAcc/DoseAccSimpleTest.cpp b/testing/apps/DoseAcc/DoseAccSimpleTest.cpp index 8107f00..6fb8af3 100644 --- a/testing/apps/DoseAcc/DoseAccSimpleTest.cpp +++ b/testing/apps/DoseAcc/DoseAccSimpleTest.cpp @@ -1,92 +1,86 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "litImageTester.h" #include "boost/filesystem.hpp" #include "itkImage.h" #include "rttbITKIOHelper.h" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseAccSimpleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseAccExecutable; std::string dose1Filename; std::string dose2Filename; std::string referenceFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 4) { doseAccExecutable = argv[1]; dose1Filename = argv[2]; dose2Filename = argv[3]; referenceFilename = argv[4]; } std::string doseAccExeWithPath = callingPath.parent_path().string() + "/" + doseAccExecutable; std::string defaultOutputFilename = "doseAccOutput.nrrd"; std::string baseCommand = doseAccExeWithPath; baseCommand += " -d \"" + dose1Filename + "\""; baseCommand += " -e \"" + dose2Filename + "\""; baseCommand += " -o " + defaultOutputFilename; std::string defaultDoseAccCommand = baseCommand + " --weight1 2.0"; std::cout << "Command line call: " + defaultDoseAccCommand << std::endl; CHECK_EQUAL(system(defaultDoseAccCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); // Check result against reference typedef ::itk::Image TestImageType; TestImageType::Pointer referenceImage = io::itk::readITKDoubleImage(referenceFilename); TestImageType::Pointer outputImage = io::itk::readITKDoubleImage(defaultOutputFilename); lit::ImageTester tester; tester.setExpectedImage(referenceImage); tester.setActualImage(outputImage); tester.setCheckThreshold(0.0); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseAcc/DoseAccTests.cpp b/testing/apps/DoseAcc/DoseAccTests.cpp index 51d1b8b..8b6e2cc 100644 --- a/testing/apps/DoseAcc/DoseAccTests.cpp +++ b/testing/apps/DoseAcc/DoseAccTests.cpp @@ -1,71 +1,65 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { const char* _callingAppPath = nullptr; void registerTests() { LIT_REGISTER_TEST(DoseAccInvalidParametersTest); LIT_REGISTER_TEST(DoseAccSimpleTest); LIT_REGISTER_TEST(DoseAccNeutralWeightTest); } } //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/apps/DoseMap/DoseMapInvalidParametersTest.cpp b/testing/apps/DoseMap/DoseMapInvalidParametersTest.cpp index 960224d..06758ca 100644 --- a/testing/apps/DoseMap/DoseMapInvalidParametersTest.cpp +++ b/testing/apps/DoseMap/DoseMapInvalidParametersTest.cpp @@ -1,74 +1,68 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseMap is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseMapInvalidParametersTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseMapExecutable; if (argc > 1) { doseMapExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string doseMapExeWithPath = callingPath.parent_path().string() + "/" + doseMapExecutable; //call with too few parameters std::string toofewParametersCommand = doseMapExeWithPath + " -d test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseMapExeWithPath + " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); //call with invalid dose load option std::string minimalCLI = doseMapExeWithPath + " test test "; std::string invalidDoseLoadOption = minimalCLI + "-l wrongOption"; std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidDoseLoadOption.c_str()) != 0, true); //call with invalid interpolator std::string invalidInterpolatorOption = minimalCLI + "-i wrongOption"; std::cout << "Command line call: " + invalidInterpolatorOption << std::endl; CHECK_EQUAL(system(invalidInterpolatorOption.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseMap/DoseMapSimpleTest.cpp b/testing/apps/DoseMap/DoseMapSimpleTest.cpp index 90d7fb2..abe0044 100644 --- a/testing/apps/DoseMap/DoseMapSimpleTest.cpp +++ b/testing/apps/DoseMap/DoseMapSimpleTest.cpp @@ -1,109 +1,102 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "boost/filesystem.hpp" #include "rttbITKImageAccessorConverter.h" - namespace rttb { namespace testing { //path to the current running directory. DoseMap is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseMapSimpleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseMapExecutable; std::string regFilename; std::string inputFilename; std::string refDoseLoadStyle; std::string inputDoseLoadStyle; std::string referenceFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 5 ) { doseMapExecutable = argv[1]; inputFilename = argv[2]; inputDoseLoadStyle = argv[3]; regFilename = argv[4]; referenceFilename = argv[5]; } std::string defaultOutputFilename = "output.nrrd"; std::string doseMapExeWithPath = callingPath.parent_path().string() + "/" + doseMapExecutable; std::string baseCommand = doseMapExeWithPath + " \"" + inputFilename + "\" " + defaultOutputFilename; std::string defaultDoseMapCommand = baseCommand+" -l "+ inputDoseLoadStyle; std::cout << "Command line call: " + defaultDoseMapCommand << std::endl; CHECK_EQUAL(system(defaultDoseMapCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); auto expectedImage = lit::TestImageIO::readImage( referenceFilename); auto actualImage = lit::TestImageIO::readImage( defaultOutputFilename); ::lit::ImageTester tester; tester.setExpectedImage(expectedImage); tester.setActualImage(actualImage); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); std::string defaultDoseMapCommandWithRegistration = defaultDoseMapCommand+ " -r \"" + regFilename + "\""; std::cout << "Command line call: " + defaultDoseMapCommandWithRegistration << std::endl; CHECK_EQUAL(system(defaultDoseMapCommandWithRegistration.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); actualImage = lit::TestImageIO::readImage( defaultOutputFilename); tester.setActualImage(actualImage); CHECK_TESTER(tester); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseMap/DoseMapTests.cpp b/testing/apps/DoseMap/DoseMapTests.cpp index 6606858..18e505b 100644 --- a/testing/apps/DoseMap/DoseMapTests.cpp +++ b/testing/apps/DoseMap/DoseMapTests.cpp @@ -1,70 +1,64 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { const char* _callingAppPath = NULL; void registerTests() { LIT_REGISTER_TEST(DoseMapInvalidParametersTest); LIT_REGISTER_TEST(DoseMapSimpleTest); } } //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/apps/DoseTool/DoseToolDVHTest.cpp b/testing/apps/DoseTool/DoseToolDVHTest.cpp index d2a1ac8..b4f72ce 100644 --- a/testing/apps/DoseTool/DoseToolDVHTest.cpp +++ b/testing/apps/DoseTool/DoseToolDVHTest.cpp @@ -1,96 +1,90 @@ // ----------------------------------------------------------------------- // 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: 1233 $ (last changed revision) -// @date $Date: 2016-01-20 15:47:47 +0100 (Mi, 20 Jan 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "../../io/other/CompareDVH.h" #include "rttbDVHXMLFileReader.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 DoseToolDVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 5) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "dicomDVHOutput2.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -s \"" + structFilename + "\""; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } std::string defaultDVHCommand = baseCommand + " -z " + defaultOutputFilename; std::cout << "Command line call: " + defaultDVHCommand << std::endl; CHECK_EQUAL(system(defaultDVHCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); io::other::DVHXMLFileReader xmlDVHDefaultReaderActual(defaultOutputFilename); DVHPointer defaultDVHActual = xmlDVHDefaultReaderActual.generateDVH(); io::other::DVHXMLFileReader xmlDVHDefaultReaderExpected(referenceXMLFilename); DVHPointer defaultDVHExpected = xmlDVHDefaultReaderExpected.generateDVH(); CHECK(checkEqualDVH(defaultDVHActual, defaultDVHExpected)); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseTool/DoseToolDicomDoseTest.cpp b/testing/apps/DoseTool/DoseToolDicomDoseTest.cpp index 1ec561d..12a7f45 100644 --- a/testing/apps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/apps/DoseTool/DoseToolDicomDoseTest.cpp @@ -1,137 +1,131 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseStatisticsXMLReader.h" #include "rttbDVHXMLFileReader.h" #include "../../io/other/CompareDoseStatistic.h" #include "../../io/other/CompareDVH.h" #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 DoseToolDicomDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; std::string referenceDVHXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 7) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; referenceDVHXMLFilename = argv[6]; referenceXMLComplexFilename = argv[7]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "dicomDoseOutput.xml"; std::string defaultDVHOutputFilename = "dicomDoseDVHOutput.xml"; std::string complexOutputFilename = "dicomDoseOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -s \"" + structFilename + "\""; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); std::string defaultDoseStatisticsAndDVHCommand = defaultDoseStatisticsCommand + " -z " + defaultDVHOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsAndDVHCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsAndDVHCommand.c_str()), 0); std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 14 Gy complexDoseStatisticsCommand += " -f -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_EQUAL(boost::filesystem::exists(defaultDVHOutputFilename), true); //check if file has dose statistics that are same than these in than reference file io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsDefaultExpected = readerDefaultExpected.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerDefaultActual(defaultOutputFilename); auto doseStatisticsDefaultActual = readerDefaultActual.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsDefaultExpected, doseStatisticsDefaultActual)); io::other::DoseStatisticsXMLReader readerComplexExpected(complexOutputFilename); auto doseStatisticsComplexExpected = readerComplexExpected.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerComplexActual(referenceXMLComplexFilename); auto doseStatisticsComplexActual = readerComplexActual.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsComplexExpected, doseStatisticsComplexActual)); //check DVH files io::other::DVHXMLFileReader xmlDVHDefaultReaderActual(defaultDVHOutputFilename); core::DVH::Pointer defaultDVHActual = xmlDVHDefaultReaderActual.generateDVH(); io::other::DVHXMLFileReader xmlDVHDefaultReaderExpected(referenceDVHXMLFilename); core::DVH::Pointer defaultDVHExpected = xmlDVHDefaultReaderExpected.generateDVH(); CHECK(checkEqualDVH(defaultDVHActual, defaultDVHExpected)); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultDVHOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseTool/DoseToolITKDoseTest.cpp b/testing/apps/DoseTool/DoseToolITKDoseTest.cpp index cd2ec21..77c7dd8 100644 --- a/testing/apps/DoseTool/DoseToolITKDoseTest.cpp +++ b/testing/apps/DoseTool/DoseToolITKDoseTest.cpp @@ -1,115 +1,109 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbDoseStatisticsXMLReader.h" #include "../../io/other/CompareDoseStatistic.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 DoseToolITKDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; std::string defaultOutputFilename; std::string complexOutputFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 8) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; referenceXMLComplexFilename = argv[6]; defaultOutputFilename = argv[7]; complexOutputFilename = argv[8]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -s \"" + structFilename + "\""; baseCommand += " -t itk "; if (structName != "") { baseCommand += " -n " + structName; } if (boost::filesystem::extension(structFilename).compare(".nrrd") == 0) { baseCommand += " -u itk"; } std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 14 Gy complexDoseStatisticsCommand += " -f -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 has dose statistics that are same than these in than reference file io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsDefaultExpected = readerDefaultExpected.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerDefaultActual(defaultOutputFilename); auto doseStatisticsDefaultActual = readerDefaultActual.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsDefaultExpected, doseStatisticsDefaultActual)); io::other::DoseStatisticsXMLReader readerComplexExpected(referenceXMLComplexFilename); auto doseStatisticsComplexExpected = readerComplexExpected.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerComplexActual(complexOutputFilename); auto doseStatisticsComplexActual = readerComplexActual.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsComplexExpected, doseStatisticsComplexActual)); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseTool/DoseToolInvalidParametersTest.cpp b/testing/apps/DoseTool/DoseToolInvalidParametersTest.cpp index 22d1dba..b28d7c6 100644 --- a/testing/apps/DoseTool/DoseToolInvalidParametersTest.cpp +++ b/testing/apps/DoseTool/DoseToolInvalidParametersTest.cpp @@ -1,98 +1,92 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (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; std::string doseToolExecutable; if (argc > 1) { doseToolExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; //call with too few parameters std::string toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -s test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -s test"; toofewParametersCommand += " -n test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " test"; toofewParametersCommand += " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -s test"; toofewParametersCommand += " -n test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); //call with invalid dose load option std::string minimalCLI = doseToolExeWithPath + " test test test "; std::string invalidDoseLoadOption = minimalCLI; invalidDoseLoadOption += "-t wrongOption"; std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidDoseLoadOption.c_str()) != 0, true); //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()) != 0, true); //call with complex dose statistics, but without prescribed dose std::string complexDoseWithoutPrescribedDoseCommand = minimalCLI; complexDoseWithoutPrescribedDoseCommand += "-f"; std::cout << "Command line call: " + complexDoseWithoutPrescribedDoseCommand << std::endl; CHECK_EQUAL(system(complexDoseWithoutPrescribedDoseCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseTool/DoseToolRegexTest.cpp b/testing/apps/DoseTool/DoseToolRegexTest.cpp index 7f3487f..6981dc0 100644 --- a/testing/apps/DoseTool/DoseToolRegexTest.cpp +++ b/testing/apps/DoseTool/DoseToolRegexTest.cpp @@ -1,119 +1,113 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseStatisticsXMLReader.h" #include "../../io/other/CompareDoseStatistic.h" #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 DoseToolRegexTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string doseLoadStyle; std::string structFilename; std::string structLoadStyle; std::string structName; std::string referenceXMLFilename; std::string referenceXMLFilename2; boost::filesystem::path callingPath(_callingAppPath); if (argc > 8) { doseToolExecutable = argv[1]; doseFilename = argv[2]; doseLoadStyle = argv[3]; structFilename = argv[4]; structLoadStyle = argv[5]; structName = argv[6]; referenceXMLFilename = argv[7]; referenceXMLFilename2 = argv[8]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "regexOutput.xml"; std::string defaultExpectedOutputFilename = "regexOutput_Nodes.xml"; std::string defaultExpectedOutputFilename2 = "regexOutput_Heart.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d \"" + doseFilename + "\""; baseCommand += " -t " + doseLoadStyle; baseCommand += " -s \"" + structFilename + "\""; baseCommand += " -u " + structLoadStyle; baseCommand += " -n \"" + structName + "\""; baseCommand += " -y " + defaultOutputFilename; std::cout << "Command line call: " + baseCommand << std::endl; CHECK_EQUAL(system(baseCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename), false); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename2), false); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); std::string defaultDoseStatisticsCommand = baseCommand + " -m"; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); //check if two file were written CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename2), true); //check if file has dose statistics that are same than these in than reference file io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsDefaultExpected = readerDefaultExpected.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerDefaultActual(defaultExpectedOutputFilename); auto doseStatisticsDefaultActual = readerDefaultActual.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsDefaultExpected, doseStatisticsDefaultActual)); io::other::DoseStatisticsXMLReader readerDefaultExpected2(referenceXMLFilename2); auto doseStatisticsDefaultExpected2 = readerDefaultExpected2.generateDoseStatistic(); io::other::DoseStatisticsXMLReader readerDefaultActual2(defaultExpectedOutputFilename2); auto doseStatisticsDefaultActual2 = readerDefaultActual2.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsDefaultExpected2, doseStatisticsDefaultActual2)); //delete file again CHECK_EQUAL(std::remove(defaultExpectedOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultExpectedOutputFilename2.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/apps/DoseTool/DoseToolTests.cpp b/testing/apps/DoseTool/DoseToolTests.cpp index 123c347..c3dc74a 100644 --- a/testing/apps/DoseTool/DoseToolTests.cpp +++ b/testing/apps/DoseTool/DoseToolTests.cpp @@ -1,73 +1,67 @@ // ----------------------------------------------------------------------- // 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: 1374 $ (last changed revision) -// @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) -// @author $Author: hentsch $ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { const char* _callingAppPath = nullptr; void registerTests() { LIT_REGISTER_TEST(DoseToolInvalidParametersTest); LIT_REGISTER_TEST(DoseToolDicomDoseTest); LIT_REGISTER_TEST(DoseToolITKDoseTest); LIT_REGISTER_TEST(DoseToolRegexTest); LIT_REGISTER_TEST(DoseToolDVHTest); } } //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/apps/VoxelizerTool/VoxelizerToolDifferentCommandsTest.cpp b/testing/apps/VoxelizerTool/VoxelizerToolDifferentCommandsTest.cpp index 527fe02..c7f3cc3 100644 --- a/testing/apps/VoxelizerTool/VoxelizerToolDifferentCommandsTest.cpp +++ b/testing/apps/VoxelizerTool/VoxelizerToolDifferentCommandsTest.cpp @@ -1,136 +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: 1333 $ (last changed revision) -// @date $Date: 2016-04-22 11:12:14 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include #include #include "itkImage.h" #include "itkImageFileReader.h" #include /*! @brief VoxelizerToolTest3. Test the output, multipleStructs and the booleanVoxelization parameter. */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolDifferentCommandsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef itk::Image< double, 3 > ImageType; typedef itk::ImageFileReader ReaderType; std::string voxelizerToolExe; std::string tempDirectory; std::string structFile; std::string referenceFile; if (argc > 4) { voxelizerToolExe = argv[1]; tempDirectory = argv[2]; structFile = argv[3]; referenceFile = argv[4]; } std::vector commands; commands.push_back("\"Niere.*\" -m -o Test.hdr"); commands.push_back("\"Rueckenmark\" -o Boolean.hdr -z"); std::vector filenames; filenames.push_back("Test_Niere li"); filenames.push_back("Test_Niere re"); filenames.push_back("Boolean"); std::vector > voxelsToTestInside; std::vector > voxelsToTestOutside; voxelsToTestInside.push_back(std::make_pair(ImageType::IndexType{ 48, 31, 18 }, 1.0)); //Niere li inside voxelsToTestOutside.push_back(std::make_pair(ImageType::IndexType{ 19, 31, 18 }, 0.0)); //Niere li outside voxelsToTestInside.push_back(std::make_pair(ImageType::IndexType{ 19, 31, 18 }, 1.0)); //Niere re inside voxelsToTestOutside.push_back(std::make_pair(ImageType::IndexType{ 48, 31, 18 }, 0.0)); //Niere re outside voxelsToTestInside.push_back(std::make_pair(ImageType::IndexType{ 35, 32, 30 }, 1.0)); //Rueckenmark inside voxelsToTestOutside.push_back(std::make_pair(ImageType::IndexType{ 35, 30, 23 }, 0.0)); //Rueckenmark outside boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -s \"" + structFile + "\""; baseCommand += " -r \"" + referenceFile + "\""; baseCommand += " -e "; for (size_t i = 0; i < commands.size(); i++) { std::string command = baseCommand + commands.at(i); int returnValue = system(command.c_str()); std::cout << "Command line call: " + command << std::endl; CHECK_EQUAL(returnValue, 0); } for (size_t i = 0; i < filenames.size(); i++) { const std::string HDRfileName = tempDirectory + "/" + filenames.at(i) + ".hdr"; boost::filesystem::path HDRFile(HDRfileName); const std::string IMGfileName = tempDirectory + "/" + filenames.at(i) + ".img"; boost::filesystem::path IMGFile(IMGfileName); CHECK_EQUAL(boost::filesystem::exists(HDRFile), true); CHECK_EQUAL(boost::filesystem::exists(IMGFile), true); //check voxel values if (boost::filesystem::exists(HDRFile)) { ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(HDRfileName); reader->Update(); ReaderType::OutputImageType::ConstPointer image = reader->GetOutput(); ImageType::PixelType voxelValueInside = image->GetPixel(voxelsToTestInside.at(i).first); ImageType::PixelType expectedVoxelValueInside = voxelsToTestInside.at(i).second; CHECK_EQUAL(voxelValueInside, expectedVoxelValueInside); ImageType::PixelType voxelValueOutside = image->GetPixel(voxelsToTestOutside.at(i).first); ImageType::PixelType expectedVoxelValueOutside = voxelsToTestOutside.at(i).second; CHECK_EQUAL(voxelValueOutside, expectedVoxelValueOutside); } if (boost::filesystem::exists(IMGFile)) { boost::filesystem::remove(IMGFile); } if (boost::filesystem::exists(HDRFile)) { boost::filesystem::remove(HDRFile); } } RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/apps/VoxelizerTool/VoxelizerToolIncorrectCommandsTest.cpp b/testing/apps/VoxelizerTool/VoxelizerToolIncorrectCommandsTest.cpp index 398b55d..7b112d1 100644 --- a/testing/apps/VoxelizerTool/VoxelizerToolIncorrectCommandsTest.cpp +++ b/testing/apps/VoxelizerTool/VoxelizerToolIncorrectCommandsTest.cpp @@ -1,120 +1,114 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include "litCheckMacros.h" #include /*! @brief VoxelizerToolTest4. Test incorrect commands with a wrong structfile, referencefile and a wrong struct. if the command return one, the program could not run to the end. return zero the command is correct */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolIncorrectCommandsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string voxelizerToolExe; std::string structFile; std::string invalidStructFile; std::string invalidReferenceFile; std::string referenceFile; std::string structureName; std::string invalidStructureName; if (argc > 7) { voxelizerToolExe = argv[1]; structFile = argv[2]; invalidStructFile = argv[3]; referenceFile = argv[4]; invalidReferenceFile = argv[5]; structureName = argv[6]; invalidStructureName = argv[7]; } boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::string tooFewArgumentsCommand = voxelizerToolExeWithPath; tooFewArgumentsCommand += " -s " + invalidStructFile; tooFewArgumentsCommand += " -r " + referenceFile; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); tooFewArgumentsCommand = voxelizerToolExeWithPath; tooFewArgumentsCommand += " -s " + invalidStructFile; tooFewArgumentsCommand += " -e " + structureName; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); tooFewArgumentsCommand = voxelizerToolExeWithPath; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); std::string noOutputEndingCommand = voxelizerToolExeWithPath; noOutputEndingCommand += " -s " + invalidStructFile; noOutputEndingCommand += " -r " + referenceFile; noOutputEndingCommand += " -e " + structureName; noOutputEndingCommand += " -o bla"; std::cout << "Command line call: " + noOutputEndingCommand << std::endl; CHECK_EQUAL(system(noOutputEndingCommand.c_str()) != 0, true); std::string structCommand = voxelizerToolExeWithPath; structCommand += " -s " + invalidStructFile; structCommand += " -r " + referenceFile; structCommand += " -e " + structureName; std::cout << "Command line call: " + structCommand << std::endl; CHECK_EQUAL(system(structCommand.c_str()) != 0, true); std::string referenceCommand = voxelizerToolExeWithPath; referenceCommand += " -s " + structFile; referenceCommand += " -r " + invalidReferenceFile; referenceCommand += " -e " + structureName; std::cout << "Command line call: " + referenceCommand << std::endl; CHECK_EQUAL(system(referenceCommand.c_str()) != 0, true); std::string structureNameCommand = voxelizerToolExeWithPath; structureNameCommand += " -s " + structFile; structureNameCommand += " -r " + referenceFile; structureNameCommand += +" -e " + invalidStructureName; std::cout << "Command line call: " + structureNameCommand << std::endl; CHECK_EQUAL(system(structureNameCommand.c_str()), 0); std::string referenceLoadingStyleCommand = voxelizerToolExeWithPath; referenceLoadingStyleCommand += " -s " + structFile; referenceLoadingStyleCommand += " -r " + referenceFile; referenceLoadingStyleCommand += +" -e " + invalidStructureName; referenceLoadingStyleCommand += +" -y nonsense"; std::cout << "Command line call: " + referenceLoadingStyleCommand << std::endl; CHECK_EQUAL(system(referenceLoadingStyleCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/apps/VoxelizerTool/VoxelizerToolVoxelValueTest.cpp b/testing/apps/VoxelizerTool/VoxelizerToolVoxelValueTest.cpp index 380bc25..6a2a124 100644 --- a/testing/apps/VoxelizerTool/VoxelizerToolVoxelValueTest.cpp +++ b/testing/apps/VoxelizerTool/VoxelizerToolVoxelValueTest.cpp @@ -1,133 +1,127 @@ // ----------------------------------------------------------------------- // 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: 1333 $ (last changed revision) -// @date $Date: 2016-04-22 11:12:14 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "litCheckMacros.h" #include #include "itkImage.h" #include "itkImageFileReader.h" #include #include /*! @brief VoxelizerToolTest5. Search the coordinate at the Image and return the Voxel(Pixel) value. */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolVoxelValue(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef itk::Image< double, 3 > ImageType; typedef itk::ImageFileReader ReaderType; std::string voxelizerToolExe; std::string tempDirectory; std::string structFile; std::string referenceFile; std::string structName; if (argc > 5) { voxelizerToolExe = argv[1]; tempDirectory = argv[2]; structFile = argv[3]; referenceFile = argv[4]; structName = argv[5]; } boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::string command = voxelizerToolExeWithPath; command += " -s \"" + structFile + "\""; command += " -r \"" + referenceFile + "\""; command += " -e " + structName; command += " -o testOutputVoxelValue.hdr"; int returnValue = system(command.c_str()); CHECK_EQUAL(returnValue, 0); //image values taken in Mevislab //Index inside ImageType::IndexType voxelInside1 = {{20, 30, 30}}; ImageType::IndexType voxelInside2 = {{30, 10, 40}}; //Outside index ImageType::IndexType voxelOutside1 = {{40, 30, 30}}; ImageType::IndexType voxelOutside2 = {{10, 40, 30}}; //Border index ImageType::IndexType voxelBorder1 = {{12, 23, 27}}; ImageType::IndexType voxelBorder2 = {{34, 21, 31}}; std::vector voxelIndices = boost::assign::list_of(voxelInside1)(voxelInside2)( voxelOutside1)( voxelOutside2)(voxelBorder1)(voxelBorder2); std::vector expectedVoxelValues = boost::assign::list_of(1.0)(1.0)(0.0)(0.0)( 0.265865)(0.819613); std::string filenameHDRWithVoxelization = tempDirectory + "/testOutputVoxelValue.hdr"; std::string filenameIMGWithVoxelization = tempDirectory + "/testOutputVoxelValue.img"; CHECK(boost::filesystem::exists(filenameHDRWithVoxelization)); CHECK(boost::filesystem::exists(filenameIMGWithVoxelization)); if (boost::filesystem::exists(filenameHDRWithVoxelization)) { ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filenameHDRWithVoxelization); reader->Update(); ReaderType::OutputImageType::ConstPointer image = reader->GetOutput(); for (size_t i = 0; i < voxelIndices.size(); i++) { ImageType::PixelType voxelValue = image->GetPixel(voxelIndices.at(i)); ImageType::PixelType expectedVoxelValue = expectedVoxelValues.at(i); if (expectedVoxelValue == 0.0 || expectedVoxelValue == 1.0) { CHECK_EQUAL(voxelValue, expectedVoxelValue); } else { CHECK_CLOSE(voxelValue, expectedVoxelValue, 1e-4); } } boost::filesystem::remove(filenameHDRWithVoxelization); if (boost::filesystem::exists(filenameIMGWithVoxelization)) { boost::filesystem::remove(filenameIMGWithVoxelization); } } RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/core/BaseTypeTest.cpp b/testing/core/BaseTypeTest.cpp index 911b582..d51e2c7 100644 --- a/testing/core/BaseTypeTest.cpp +++ b/testing/core/BaseTypeTest.cpp @@ -1,277 +1,271 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @brief BaseTypeTests - tests the API for the classes in baseType 1) UnsignedIndex3D 2) WorldCoordinate3D 3) SpacingVectorType3D 4) OrientationMatrix 5) VoxelGridIndex3D 6) VoxelGridIndex2D */ int BaseTypeTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) UnsignedIndex3D CHECK_NO_THROW(UnsignedIndex3D ui); UnsignedIndex3D emptyUnsignedIndex3D; CHECK_EQUAL(emptyUnsignedIndex3D.x(), 0); CHECK_EQUAL(emptyUnsignedIndex3D.y(), 0); CHECK_EQUAL(emptyUnsignedIndex3D.z(), 0); CHECK_NO_THROW(UnsignedIndex3D ui(5)); UnsignedIndex3D sameValueUnsignedIndex(5); CHECK_EQUAL(sameValueUnsignedIndex.x(), 5); CHECK_EQUAL(sameValueUnsignedIndex.y(), 5); CHECK_EQUAL(sameValueUnsignedIndex.z(), 5); CHECK_NO_THROW(UnsignedIndex3D ui(5, 8, 42)); UnsignedIndex3D differentValueUnsignedIndex(5, 8, 42); CHECK_EQUAL(differentValueUnsignedIndex.x(), 5); CHECK_EQUAL(differentValueUnsignedIndex.y(), 8); CHECK_EQUAL(differentValueUnsignedIndex.z(), 42); UnsignedIndex3D threeDimensionalUnsignedIndexSame(5, 8, 42); UnsignedIndex3D threeDimensionalUnsignedIndexDifferent(1, 2, 3); CHECK(differentValueUnsignedIndex == threeDimensionalUnsignedIndexSame); CHECK_EQUAL(differentValueUnsignedIndex == threeDimensionalUnsignedIndexDifferent, false); CHECK_EQUAL(differentValueUnsignedIndex == sameValueUnsignedIndex, false); CHECK_EQUAL(emptyUnsignedIndex3D == sameValueUnsignedIndex, false); //2) WorldCoordinate3D CHECK_NO_THROW(WorldCoordinate3D wc); WorldCoordinate3D emptyWC3D; CHECK_EQUAL(emptyWC3D.x(), 0); CHECK_EQUAL(emptyWC3D.y(), 0); CHECK_EQUAL(emptyWC3D.z(), 0); CHECK_NO_THROW(WorldCoordinate3D wc(6.5)); WorldCoordinate3D sameValueWC3D(6.5); CHECK_EQUAL(sameValueWC3D.x(), 6.5); CHECK_EQUAL(sameValueWC3D.y(), 6.5); CHECK_EQUAL(sameValueWC3D.z(), 6.5); CHECK_NO_THROW(WorldCoordinate3D(5.8, 0.1, -2.7)); WorldCoordinate3D differentValueWC3D(5.8, 0.1, -2.7); CHECK_EQUAL(differentValueWC3D.x(), 5.8); CHECK_EQUAL(differentValueWC3D.y(), 0.1); CHECK_EQUAL(differentValueWC3D.z(), -2.7); CHECK_EQUAL(differentValueWC3D.toString(), "5.800000 0.100000 -2.700000"); WorldCoordinate3D differentValueWC3Dsecond(1.5, -3.9, 0.7); WorldCoordinate3D resultWC3DCrossTrue(-10.46, -8.11, -22.77); CHECK_NO_THROW(differentValueWC3D.cross(differentValueWC3Dsecond)); auto resultWC3DCrossComputed = differentValueWC3D.cross(differentValueWC3Dsecond); CHECK_CLOSE(resultWC3DCrossComputed.x(), resultWC3DCrossTrue.x(), errorConstant); CHECK_CLOSE(resultWC3DCrossComputed.y(), resultWC3DCrossTrue.y(), errorConstant); CHECK_CLOSE(resultWC3DCrossComputed.z(), resultWC3DCrossTrue.z(), errorConstant); CHECK_NO_THROW(differentValueWC3Dsecond.cross(differentValueWC3D)); auto resultWC3DCrossComputedOrder = differentValueWC3Dsecond.cross(differentValueWC3D); CHECK_CLOSE(resultWC3DCrossComputed.x(), resultWC3DCrossComputedOrder.x()*-1, errorConstant); CHECK_CLOSE(resultWC3DCrossComputed.y(), resultWC3DCrossComputedOrder.y()*-1, errorConstant); CHECK_CLOSE(resultWC3DCrossComputed.z(), resultWC3DCrossComputedOrder.z()*-1, errorConstant); differentValueWC3D = differentValueWC3Dsecond; CHECK_EQUAL(differentValueWC3D.x(), 1.5); CHECK_EQUAL(differentValueWC3D.y(), -3.9); CHECK_EQUAL(differentValueWC3D.z(), 0.7); boost::numeric::ublas::vector wcUblas(3, 4.5); differentValueWC3D = wcUblas; CHECK_EQUAL(differentValueWC3D.x(), 4.5); CHECK_EQUAL(differentValueWC3D.y(), 4.5); CHECK_EQUAL(differentValueWC3D.z(), 4.5); WorldCoordinate3D WCresultMinus; CHECK_NO_THROW(WCresultMinus = differentValueWC3D- differentValueWC3Dsecond); CHECK_EQUAL(WCresultMinus.x(), differentValueWC3D.x()- differentValueWC3Dsecond.x()); CHECK_EQUAL(WCresultMinus.y(), differentValueWC3D.y() - differentValueWC3Dsecond.y()); CHECK_EQUAL(WCresultMinus.z(), differentValueWC3D.z() - differentValueWC3Dsecond.z()); WorldCoordinate3D WCresultPlus; CHECK_NO_THROW(WCresultPlus = differentValueWC3D + differentValueWC3Dsecond); CHECK_EQUAL(WCresultPlus.x(), differentValueWC3D.x() + differentValueWC3Dsecond.x()); CHECK_EQUAL(WCresultPlus.y(), differentValueWC3D.y() + differentValueWC3Dsecond.y()); CHECK_EQUAL(WCresultPlus.z(), differentValueWC3D.z() + differentValueWC3Dsecond.z()); WorldCoordinate3D sameAsWcUblas(4.5); CHECK_EQUAL(resultWC3DCrossTrue== differentValueWC3Dsecond, false); CHECK_EQUAL(differentValueWC3D == sameAsWcUblas, true); WorldCoordinate3D sameAsWcUblasAlmost(4.5+1e-6, 4.5-1e-6, 4.5+2e-7); CHECK_EQUAL(sameAsWcUblas.equalsAlmost(sameAsWcUblasAlmost), true); CHECK_EQUAL(sameAsWcUblas.equalsAlmost(resultWC3DCrossComputedOrder), false); //3) SpacingVectorType CHECK_NO_THROW(SpacingVectorType3D svt); SpacingVectorType3D emptySvt; CHECK_EQUAL(emptySvt.x(), 0); CHECK_EQUAL(emptySvt.y(), 0); CHECK_EQUAL(emptySvt.z(), 0); CHECK_NO_THROW(SpacingVectorType3D svt(1.5)); CHECK_THROW(SpacingVectorType3D svt(-1.5)); SpacingVectorType3D sameValueSvt(1.5); CHECK_EQUAL(sameValueSvt.x(), 1.5); CHECK_EQUAL(sameValueSvt.y(), 1.5); CHECK_EQUAL(sameValueSvt.z(), 1.5); CHECK_NO_THROW(SpacingVectorType3D svt(1.5, 1.5, 0.5)); CHECK_THROW(SpacingVectorType3D svt(1.5, -1.5, 0.5)); CHECK_THROW(SpacingVectorType3D svt(-1.5, -1.5, -0.5)); SpacingVectorType3D differentValuesSvt(1.5, 1.5, 0.5); CHECK_EQUAL(differentValuesSvt.x(), 1.5); CHECK_EQUAL(differentValuesSvt.y(), 1.5); CHECK_EQUAL(differentValuesSvt.z(), 0.5); SpacingVectorType3D differentValuesSvtChanged(0.5, 0.5, 1.5); CHECK_NO_THROW(SpacingVectorType3D svt(differentValuesSvtChanged)); SpacingVectorType3D svtNew(differentValuesSvtChanged); CHECK_EQUAL(svtNew.x(), 0.5); CHECK_EQUAL(svtNew.y(), 0.5); CHECK_EQUAL(svtNew.z(), 1.5); CHECK_NO_THROW(svtNew = differentValuesSvt); CHECK_EQUAL(svtNew.x(), 1.5); CHECK_EQUAL(svtNew.y(), 1.5); CHECK_EQUAL(svtNew.z(), 0.5); CHECK_NO_THROW(svtNew = differentValueWC3D); CHECK_EQUAL(svtNew.x(), 4.5); CHECK_EQUAL(svtNew.y(), 4.5); CHECK_EQUAL(svtNew.z(), 4.5); boost::numeric::ublas::vector ublasVector(3, 0.5); CHECK_NO_THROW(svtNew = ublasVector); CHECK_EQUAL(svtNew.x(), 0.5); CHECK_EQUAL(svtNew.y(), 0.5); CHECK_EQUAL(svtNew.z(), 0.5); SpacingVectorType3D sameAsUblasVector(0.5); CHECK_EQUAL(svtNew== differentValuesSvtChanged, false); CHECK_EQUAL(svtNew == sameAsUblasVector, true); SpacingVectorType3D almostSameAsUblasVector(0.5+1e-6, 0.5-1e-6,0.5+2e-7); CHECK(svtNew.equalsAlmost(almostSameAsUblasVector)); CHECK_EQUAL(differentValuesSvtChanged.toString(), "0.500000 0.500000 1.500000"); //4) OrientationMatrix CHECK_NO_THROW(OrientationMatrix om); OrientationMatrix om; CHECK_EQUAL(om(0, 0), 1.0); CHECK_EQUAL(om(1, 1), 1.0); CHECK_EQUAL(om(2, 2), 1.0); CHECK_EQUAL(om(0, 1), 0.0); CHECK_EQUAL(om(0, 2), 0.0); CHECK_EQUAL(om(1, 0), 0.0); CHECK_EQUAL(om(1, 2), 0.0); CHECK_EQUAL(om(2, 0), 0.0); CHECK_EQUAL(om(2, 1), 0.0); CHECK_NO_THROW(OrientationMatrix omValue(0.1)); OrientationMatrix omValue(0.1); for (unsigned int i = 0; i < 3; i++) { for (unsigned int j = 0; j < 3; j++) { CHECK_EQUAL(omValue(i, j), 0.1); } } OrientationMatrix omValueAlmost(0.1+1e-6); CHECK_EQUAL(omValue.equalsAlmost(omValueAlmost), true); CHECK_EQUAL(omValue.equalsAlmost(om), false); OrientationMatrix omSame; CHECK_EQUAL(om == omSame, true); CHECK_EQUAL(omValue == omValueAlmost, false); //5) VoxelGridIndex3D CHECK_NO_THROW(VoxelGridIndex3D vgi); VoxelGridIndex3D vgi; CHECK_EQUAL(vgi.x(), 0); CHECK_EQUAL(vgi.y(), 0); CHECK_EQUAL(vgi.z(), 0); CHECK_NO_THROW(VoxelGridIndex3D vgiValue(2)); VoxelGridIndex3D vgiValue(2); CHECK_EQUAL(vgiValue.x(), 2); CHECK_EQUAL(vgiValue.y(), 2); CHECK_EQUAL(vgiValue.z(), 2); CHECK_NO_THROW(VoxelGridIndex3D vgiValueDifferent(2,3,5)); VoxelGridIndex3D vgiValueDifferent(2,3,5); CHECK_EQUAL(vgiValueDifferent.x(), 2); CHECK_EQUAL(vgiValueDifferent.y(), 3); CHECK_EQUAL(vgiValueDifferent.z(), 5); CHECK_EQUAL(vgiValueDifferent.toString(), "2 3 5"); CHECK_NO_THROW(vgiValueDifferent = threeDimensionalUnsignedIndexSame); CHECK_EQUAL(vgiValueDifferent.x(), 5); CHECK_EQUAL(vgiValueDifferent.y(), 8); CHECK_EQUAL(vgiValueDifferent.z(), 42); VoxelGridIndex3D vgiValueDifferentSame(5, 8, 42); CHECK_EQUAL(vgi==vgiValue, false); CHECK_EQUAL(vgiValueDifferentSame == vgiValueDifferent, true); //6) VoxelGridIndex2D CHECK_NO_THROW(VoxelGridIndex2D vgi); VoxelGridIndex2D vgi2D; CHECK_EQUAL(vgi2D.x(), 0); CHECK_EQUAL(vgi2D.y(), 0); CHECK_NO_THROW(VoxelGridIndex2D vgi2DValue(2)); VoxelGridIndex2D vgi2DValue(2); CHECK_EQUAL(vgi2DValue.x(), 2); CHECK_EQUAL(vgi2DValue.y(), 2); CHECK_NO_THROW(VoxelGridIndex2D vgi2DValueDifferent(2, 3)); VoxelGridIndex2D vgi2DValueDifferent(2, 3); CHECK_EQUAL(vgi2DValueDifferent.x(), 2); CHECK_EQUAL(vgi2DValueDifferent.y(), 3); CHECK_EQUAL(vgi2DValueDifferent.toString(), "2 3"); VoxelGridIndex2D vgi2DValueDifferentSame(2, 3); CHECK_EQUAL(vgi2D == vgi2DValueDifferent, false); CHECK_EQUAL(vgi2DValueDifferent == vgi2DValueDifferentSame, true); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/core/CreateTestStructure.cpp b/testing/core/CreateTestStructure.cpp index 6c81a22..d310ac4 100644 --- a/testing/core/CreateTestStructure.cpp +++ b/testing/core/CreateTestStructure.cpp @@ -1,688 +1,681 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests - #include #include "CreateTestStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace testing { CreateTestStructure::~CreateTestStructure() {} CreateTestStructure::CreateTestStructure(const core::GeometricInfo& aGeoInfo) { _geoInfo = aGeoInfo; } PolygonType CreateTestStructure::createPolygonLeftUpper(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); polygon.push_back(p1); std::cout << "(" << p1.x() << "," << p1.y() << "," << p1.z() << ")" << "; "; } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonCenter(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); WorldCoordinate3D p; p(0) = p1.x() ; p(1) = p1.y() ; //This can be done directly for x/y coordinates, but not for z. Thus, we do it in this function. p(2) = p1.z() - _geoInfo.getSpacing().z() / 2; polygon.push_back(p); } return polygon; } PolygonType CreateTestStructure::createPolygonCenterOnPlaneCenter(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; DoubleVoxelGridIndex3D indexDouble = DoubleVoxelGridIndex3D((aVoxelVector.at(i)).x(), (aVoxelVector.at(i)).y(), sliceNumber); WorldCoordinate3D p1; _geoInfo.geometryCoordinateToWorldCoordinate(indexDouble, p1); polygon.push_back(p1); } return polygon; } PolygonType CreateTestStructure::createPolygonBetweenUpperLeftAndCenter( std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D p; p(0) = p1.x() + delta.x() / 4; p(1) = p1.y() + delta.y() / 4; p(2) = p1.z(); polygon.push_back(p); std::cout << "(" << p.x() << "," << p.y() << "," << p.z() << ")" << "; "; } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonBetweenLowerRightAndCenter( std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D p; p(0) = p1.x() + delta.x() * 0.75; p(1) = p1.y() + delta.y() * 0.75; p(2) = p1.z(); polygon.push_back(p); std::cout << "(" << p.x() << "," << p.y() << "," << p.z() << ")" << "; "; } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonLeftEdgeMiddle(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D p; p(0) = p1.x(); p(1) = p1.y() + delta.y() * 0.5; p(2) = p1.z(); polygon.push_back(p); std::cout << "(" << p.x() << "," << p.y() << "," << p.z() << ")" << "; "; } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonUpperCenter(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D p; p(0) = p1.x() + delta.x() * 0.5; p(1) = p1.y(); p(2) = p1.z(); polygon.push_back(p); std::cout << "(" << p.x() << "," << p.y() << "," << p.z() << ")" << "; "; } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonIntermediatePoints(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; for (size_t i = 0; i < aVoxelVector.size(); i++) { VoxelGridIndex3D voxelIndex; VoxelGridIndex3D voxelIndex2; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; if (i < (aVoxelVector.size() - 1)) { voxelIndex2(0) = (aVoxelVector.at(i + 1)).x(); voxelIndex2(1) = (aVoxelVector.at(i + 1)).y(); voxelIndex2(2) = sliceNumber; } else { voxelIndex2(0) = (aVoxelVector.at(0)).x(); voxelIndex2(1) = (aVoxelVector.at(0)).y(); voxelIndex2(2) = sliceNumber; } WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D p2; _geoInfo.indexToWorldCoordinate(voxelIndex2, p2); SpacingVectorType3D delta2 = _geoInfo.getSpacing(); WorldCoordinate3D wp1; wp1(0) = p1.x() + delta.x() * 0.75; wp1(1) = p1.y() + delta.y() * 0.75; wp1(2) = p1.z(); WorldCoordinate3D wp2; wp2(0) = p2.x() + delta.x() * 0.75; wp2(1) = p2.y() + delta.y() * 0.75; wp2(2) = p2.z(); polygon.push_back(wp1); double diffX = (wp2.x() - wp1.x()) / 1000.0; double diffY = (wp2.y() - wp1.y()) / 1000.0; WorldCoordinate3D wp_intermediate; wp_intermediate(0) = 0; wp_intermediate(1) = 0; for (int j = 0; j < 1000; j++) { wp_intermediate(0) = wp1.x() + j * diffX; wp_intermediate(1) = wp1.y() + j * diffY; polygon.push_back(wp_intermediate); } } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createPolygonCircle(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; if (aVoxelVector.size() > 0) { unsigned int i = 0; VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; wp1(0) = p1.x(); wp1(1) = p1.y(); wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; wp_intermediate(0) = 0; wp_intermediate(1) = 0; wp_intermediate(2) = p1.z(); double radius = 2 * delta.x(); double frac_radius = (radius * 0.001); double correct_y = (delta.x() / delta.y()); for (unsigned int j = 0; j <= 1000; j++) { double y_offset = sqrt((radius * radius) - ((frac_radius * j) * (frac_radius * j))); wp_intermediate(0) = wp1.x() + frac_radius * j; wp_intermediate(1) = wp1.y() - (y_offset * correct_y); polygon.push_back(wp_intermediate); } for (unsigned int j = 1000; j <= 1000; j--) { double y_offset = sqrt((radius * radius) - ((frac_radius * j) * (frac_radius * j))); wp_intermediate(0) = wp1.x() + frac_radius * j; wp_intermediate(1) = wp1.y() + (y_offset * correct_y); polygon.push_back(wp_intermediate); } for (unsigned int j = 0; j <= 1000; j++) { double y_offset = sqrt((radius * radius) - ((frac_radius * j) * (frac_radius * j))); wp_intermediate(0) = wp1.x() - frac_radius * j; wp_intermediate(1) = wp1.y() + y_offset * correct_y; polygon.push_back(wp_intermediate); } for (unsigned int j = 1000; j <= 1000; j--) { double y_offset = sqrt((radius * radius) - ((frac_radius * j) * (frac_radius * j))); wp_intermediate(0) = wp1.x() + frac_radius * j; wp_intermediate(1) = wp1.y() + (y_offset * correct_y); polygon.push_back(wp_intermediate); } } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createStructureSeveralSectionsInsideOneVoxelA( std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; if (aVoxelVector.size() > 0) { int i = 0; VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; wp1(0) = p1.x(); wp1(1) = p1.y(); wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; wp_intermediate(0) = 0; wp_intermediate(1) = 0; wp_intermediate(2) = p1.z(); wp_intermediate(0) = wp1.x() + (delta.x() * 0.25); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.25); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.75); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.75); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.25); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.25); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.5); wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.75); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.75); wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); polygon.push_back(wp_intermediate); } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createStructureSelfTouchingA(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; if (aVoxelVector.size() > 0) { int i = 0; VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; wp1(0) = p1.x(); wp1(1) = p1.y(); wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; wp_intermediate(0) = 0; wp_intermediate(1) = 0; wp_intermediate(2) = p1.z(); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y(); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); } std::cout << std::endl; return polygon; } PolygonType CreateTestStructure::createStructureSelfTouchingB(std::vector aVoxelVector, GridIndexType sliceNumber) { PolygonType polygon; if (aVoxelVector.size() > 0) { int i = 0; VoxelGridIndex3D voxelIndex; voxelIndex(0) = (aVoxelVector.at(i)).x(); voxelIndex(1) = (aVoxelVector.at(i)).y(); voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; _geoInfo.indexToWorldCoordinate(voxelIndex, p1); SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; wp1(0) = p1.x(); wp1(1) = p1.y(); wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; wp_intermediate(0) = 0; wp_intermediate(1) = 0; wp_intermediate(2) = p1.z(); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y(); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); polygon.push_back(wp_intermediate); wp_intermediate(0) = wp1.x(); wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); polygon.push_back(wp_intermediate); } std::cout << std::endl; return polygon; } }//testing }//rttb diff --git a/testing/core/CreateTestStructure.h b/testing/core/CreateTestStructure.h index 627c5cf..cb0631f 100644 --- a/testing/core/CreateTestStructure.h +++ b/testing/core/CreateTestStructure.h @@ -1,81 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbStructure.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" namespace rttb { namespace testing { /*!@class CreateTestStructure @brief Create dummy structures for testing. */ class CreateTestStructure { private: core::GeometricInfo _geoInfo; CreateTestStructure() {}; public: ~CreateTestStructure(); CreateTestStructure(const core::GeometricInfo& aGeoInfo); PolygonType createPolygonLeftUpper(std::vector aVoxelVector, GridIndexType sliceNumber); /*The z coordinate of the polygon is the upper side of the voxel on the slice*/ PolygonType createPolygonCenter(std::vector aVoxelVector, GridIndexType sliceNumber); /*The z coordinate of the polygon is the center of the voxel on the slice*/ PolygonType createPolygonCenterOnPlaneCenter(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonBetweenUpperLeftAndCenter(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonBetweenLowerRightAndCenter(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonIntermediatePoints(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonUpperCenter(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonLeftEdgeMiddle(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createPolygonCircle(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createStructureSeveralSectionsInsideOneVoxelA(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createStructureSelfTouchingA(std::vector aVoxelVector, GridIndexType sliceNumber); PolygonType createStructureSelfTouchingB(std::vector aVoxelVector, GridIndexType sliceNumber); }; }//testing }//rttb diff --git a/testing/core/DVHCalculatorTest.cpp b/testing/core/DVHCalculatorTest.cpp index eb782e3..53f1d7f 100644 --- a/testing/core/DVHCalculatorTest.cpp +++ b/testing/core/DVHCalculatorTest.cpp @@ -1,154 +1,148 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGeometricInfo.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "DummyDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; /*!@brief DVHTest - test the API of DVH 1) test constructors (values as expected?) */ int DVHCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //create null pointer to DoseIterator DoseIteratorPointer spDoseIteratorNull; const IDType structureID = "myStructure"; const IDType doseIDNull = "myDose"; //1) test constructors (values as expected?) CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIteratorNull, structureID, doseIDNull), core::NullPointerException); //create dummy DoseAccessor boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); //create corresponding DoseIterator boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); const IDType doseID = spDoseAccessor->getUID(); CHECK_NO_THROW(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID)); CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, -1), core::InvalidParameterException); int numBins = 21; DoseTypeGy binSize = 0; DoseStatisticType maximum = 0; std::vector::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } ++doseIt; } binSize = maximum * 1.5 / numBins; CHECK_NO_THROW(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, binSize, numBins)); CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, 0, 0), core::InvalidParameterException);//aNumberOfBins must be >=0 core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, binSize, 1); CHECK_THROW_EXPLICIT(myDVHCalc.generateDVH(), core::InvalidParameterException);//_numberOfBins must be > max(aDoseIterator)/aDeltaD! //generateDVH (only test basic functionality here and test it in RTTBDicomIOTests and RTTBITKIOTests) //create dummy DoseAccessor with values 0 to check if _deltaD is set to 0.1 std::vector zeros(1000, 0); core::GeometricInfo geoInfo; geoInfo.setNumColumns(10); geoInfo.setNumRows(10); geoInfo.setNumSlices(10); geoInfo.setSpacing({1.0, 1.0, 1.0}); boost::shared_ptr spTestDoseAccessorZeros = boost::make_shared(zeros, geoInfo); DoseAccessorPointer spDoseAccessorZeros(spTestDoseAccessorZeros); boost::shared_ptr spTestDoseIteratorZeros = boost::make_shared(spDoseAccessorZeros); DoseIteratorPointer spDoseIteratorZeros(spTestDoseIteratorZeros); CHECK_NO_THROW(core::DVHCalculator myDVHCalc2(spDoseIteratorZeros, structureID, doseID, 0, numBins)); core::DVHCalculator myDVHCalc2(spDoseIteratorZeros, structureID, doseID, 0, numBins); core::DVH::Pointer dvh; CHECK_NO_THROW(dvh = myDVHCalc2.generateDVH()); CHECK(dvh); CHECK_CLOSE(dvh->getDeltaD(), 0.1, errorConstant); //create dummy MaskAccessor boost::shared_ptr spTestMaskAccessor = boost::make_shared(spDoseAccessor->getGeometricInfo()); MaskAccessorPointer spMaskAccessor(spTestMaskAccessor); //create corresponding MaskedDoseIterator boost::shared_ptr spTestMaskedDoseIterator = boost::make_shared(spMaskAccessor, spDoseAccessor); MaskedDoseIteratorPointer spMaskedDoseIterator(spTestMaskedDoseIterator); CHECK_NO_THROW(core::DVHCalculator myDVHCalc3(spMaskedDoseIterator, structureID, doseID)); core::DVHCalculator myDVHCalc3(spMaskedDoseIterator, structureID, doseID); CHECK_NO_THROW(dvh = myDVHCalc3.generateDVH()); CHECK(dvh); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHSetTest.cpp b/testing/core/DVHSetTest.cpp index 1d23a7f..5c25455 100644 --- a/testing/core/DVHSetTest.cpp +++ b/testing/core/DVHSetTest.cpp @@ -1,207 +1,201 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "DummyDVHGenerator.h" namespace rttb { namespace testing { typedef core::DVHSet::DVHSetType DVHSetType; /*! @brief DVHTest - test the API of DVH 1) test constructors (values as expected?) 2) test size 3) test set/getIDs 4) test insert/retrieve individual DVHs 5) test getDVHSet 6) test getVolume */ int DVHSetTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const IDType structureSetID = "myStructureSet"; const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; DummyDVHGenerator dvhGenerator; DVHSetType tvSet; IDType structureID = structureIDPrefix + "_TV_"; for (int i = 0; i < 3; i++) { tvSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } DVHSetType htSet; structureID = structureIDPrefix + "_HT_"; for (int i = 0; i < 5; i++) { htSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } DVHSetType wvSet; structureID = structureIDPrefix + "_WV_"; for (int i = 0; i < 1; i++) { wvSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } //1) test constructors (values as expected?) CHECK_NO_THROW(core::DVHSet(structureSetID, doseID)); CHECK_NO_THROW(core::DVHSet(tvSet, htSet, structureSetID, doseID)); CHECK_NO_THROW(core::DVHSet(tvSet, htSet, wvSet, structureSetID, doseID)); //2) test size core::DVHSet myDvhSet1(structureSetID, doseID); CHECK_EQUAL(myDvhSet1.size(), 0); core::DVHSet myDvhSet2(tvSet, htSet, structureSetID, doseID); CHECK_EQUAL(myDvhSet2.size(), tvSet.size() + htSet.size()); core::DVHSet myDvhSet3(tvSet, htSet, wvSet, structureSetID, doseID); CHECK_EQUAL(myDvhSet3.size(), tvSet.size() + htSet.size() + wvSet.size()); //3) test set/getIDs const IDType newStructureSetID = "myNewStructureSet"; const IDType newDoseID = "myNewDose"; CHECK_EQUAL(myDvhSet1.getStrSetID(), structureSetID); CHECK_EQUAL(myDvhSet1.getDoseID(), doseID); CHECK_NO_THROW(myDvhSet1.setStrSetID(newStructureSetID)); CHECK_NO_THROW(myDvhSet1.setDoseID(newDoseID)); CHECK_EQUAL(myDvhSet1.getStrSetID(), newStructureSetID); CHECK_EQUAL(myDvhSet1.getDoseID(), newDoseID); CHECK_EQUAL(myDvhSet3.getStrSetID(), structureSetID); CHECK_EQUAL(myDvhSet3.getDoseID(), doseID); CHECK_NO_THROW(myDvhSet3.setStrSetID(newStructureSetID)); CHECK_NO_THROW(myDvhSet3.setDoseID(newDoseID)); CHECK_EQUAL(myDvhSet3.getStrSetID(), newStructureSetID); CHECK_EQUAL(myDvhSet3.getDoseID(), newDoseID); //4) test insert/retrieve individual DVHs DVHRole roleTV = {DVHRole::TargetVolume}; DVHRole roleUser = { DVHRole::UserDefined }; structureID = structureIDPrefix + "_TV_"; core::DVH tv = dvhGenerator.generateDVH(structureID + boost::lexical_cast (tvSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 0); CHECK_NO_THROW(myDvhSet1.insert(tv, roleTV)); CHECK_EQUAL(myDvhSet1.size(), 1); std::size_t currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(tv, roleTV)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); CHECK_THROW_EXPLICIT(myDvhSet2.insert(tv, roleUser), core::InvalidParameterException); DVHRole roleHT = {DVHRole::HealthyTissue}; structureID = structureIDPrefix + "_HT_"; core::DVH ht = dvhGenerator.generateDVH(structureID + boost::lexical_cast (htSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 1); CHECK_NO_THROW(myDvhSet1.insert(ht, roleHT)); CHECK_EQUAL(myDvhSet1.size(), 2); currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(ht, roleHT)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); DVHRole roleWV = {DVHRole::WholeVolume}; structureID = structureIDPrefix + "_wv_"; IDType testID = structureID + boost::lexical_cast(wvSet.size()); core::DVH wv = dvhGenerator.generateDVH(structureID + boost::lexical_cast (wvSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 2); CHECK_NO_THROW(myDvhSet1.insert(wv, roleWV)); CHECK_EQUAL(myDvhSet1.size(), 3); currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(wv, roleWV)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); //5) test getDVHSet core::DVH* dvhPtr = myDvhSet1.getDVH(testID); CHECK_EQUAL(*dvhPtr, wv); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_TV_0"); CHECK_EQUAL(*dvhPtr, tvSet.at(0)); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_TV_2"); CHECK_EQUAL(*dvhPtr, tvSet.at(2)); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_HT_2"); CHECK_EQUAL(*dvhPtr, htSet.at(2)); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_WV_0"); CHECK_EQUAL(*dvhPtr, wvSet.at(0)); dvhPtr = myDvhSet3.getDVH("wrongID"); CHECK(!dvhPtr); DVHSetType tvTest = myDvhSet3.getTargetVolumeSet(); CHECK_EQUAL(tvTest, tvSet); DVHSetType htTest = myDvhSet3.getHealthyTissueSet(); CHECK_EQUAL(htTest, htSet); DVHSetType wvTest = myDvhSet3.getWholeVolumeSet(); CHECK_EQUAL(wvTest, wvSet); //6) test getVolume DoseTypeGy aDoseAbsolute = 10; CHECK_EQUAL(0, myDvhSet3.getHealthyTissueVolume(aDoseAbsolute)); CHECK_EQUAL(0, myDvhSet3.getTargetVolume(aDoseAbsolute)); CHECK_EQUAL(0, myDvhSet3.getWholeVolume(aDoseAbsolute)); //7) Test equality core::DVHSet myDvhSet4(myDvhSet1.getStrSetID(), myDvhSet1.getDoseID()); myDvhSet4.insert(tv, roleTV); myDvhSet4.insert(ht, roleHT); myDvhSet4.insert(wv, roleWV); CHECK_EQUAL(myDvhSet1 == myDvhSet2, false); CHECK_EQUAL(myDvhSet1 == myDvhSet4, true); myDvhSet4.setDoseID("bla"); CHECK_EQUAL(myDvhSet1 == myDvhSet4, false); myDvhSet4.setDoseID(myDvhSet1.getDoseID()); myDvhSet4.insert(tv, roleTV); CHECK_EQUAL(myDvhSet1 == myDvhSet4, false); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHTest.cpp b/testing/core/DVHTest.cpp index 6c93b4b..fc34f66 100644 --- a/testing/core/DVHTest.cpp +++ b/testing/core/DVHTest.cpp @@ -1,242 +1,236 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "DummyDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief DVHTest - test the API of DVH 1) test constructors (values as expected?) 2) test assignement 3) test set/getLabel 4) test set/get 5) test equality */ int DVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType anEmptyDataDifferential; DataDifferentialType aDataDifferential; DataDifferentialType aDataDifferential2; DataDifferentialType aDataDifferentialRelative; DoseStatisticType maximum = 0; DoseStatisticType minimum = 0; double sum = 0; double squareSum = 0; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values [0,100) for (int i = 0; i < 100; i++) { value = DoseCalcType((double(rand()) / RAND_MAX) * 1000); numberOfVoxels += value; aDataDifferential.push_back(value); aDataDifferential2.push_back(value * 10); if (value > 0) { maximum = (i + 0.5) * binSize; if (minimum == 0) { minimum = (i + 0.5) * binSize; } } sum += value * (i + 0.5) * binSize; squareSum += value * pow((i + 0.5) * binSize, 2); } double medianVoxel = 0; double modalVoxel = 0; unsigned int count = 0; unsigned int medianCount = 0; unsigned int modalCount = 0; for (const auto& aValue : aDataDifferential) { std::cout << aValue << std::endl; if (medianVoxel < numberOfVoxels - medianVoxel) { medianVoxel += aValue; medianCount = count; } if (modalVoxel < aValue) { modalVoxel = aValue; modalCount = count; } count++; } DoseStatisticType median = (medianCount + 0.5)*binSize; DoseStatisticType modal = (modalCount + 0.5)*binSize; DoseStatisticType mean = sum / numberOfVoxels; DoseStatisticType variance = (squareSum / numberOfVoxels - mean * mean); DoseStatisticType stdDeviation = pow(variance, 0.5); std::deque::iterator it; for (it = aDataDifferential.begin(); it != aDataDifferential.end(); ++it) { aDataDifferentialRelative.push_back((*it) / numberOfVoxels); } IDType structureID = "myStructure"; IDType doseID = "myDose"; IDType voxelizationID = "myVoxelization"; //1) test default constructor (values as expected?) CHECK_THROW(core::DVH(anEmptyDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(anEmptyDataDifferential, binSize, voxelVolume, structureID, doseID)); CHECK_NO_THROW(core::DVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID)); CHECK_NO_THROW(core::DVH(aDataDifferential, binSize, voxelVolume, structureID, doseID)); CHECK_THROW(core::DVH(aDataDifferential, 0, voxelVolume, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(aDataDifferential, 0, voxelVolume, structureID, doseID)); CHECK_THROW(core::DVH(aDataDifferential, binSize, 0, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(aDataDifferential, binSize, 0, structureID, doseID)); //2) test assignment core::DVH myTestDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID); CHECK_NO_THROW(core::DVH myOtherDVH = myTestDVH); core::DVH myOtherDVH(myTestDVH); CHECK_NO_THROW(myOtherDVH = myTestDVH); //3) test set/getLabel core::DVH myDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); StructureLabel label = ""; CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); label = "myLabel"; CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); label = "myLabel2"; CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); //4) test set/get //IDs CHECK_EQUAL(myDVH.getStructureID(), structureID); CHECK_EQUAL(myDVH.getDoseID(), doseID); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); /*! is related to #2029*/ myDVH.setDoseID("somethingElse"); CHECK_EQUAL(myDVH.getDoseID(), "somethingElse"); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); CHECK_EQUAL(myDVH.getStructureID(), structureID); /*! is related to #2029*/ myDVH.setStructureID("somethingOther"); CHECK_EQUAL(myDVH.getDoseID(), "somethingElse"); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); CHECK_EQUAL(myDVH.getStructureID(), "somethingOther"); //dataDifferential CHECK(myDVH.getDataDifferential() == aDataDifferential); CHECK(myDVH.getDataDifferential() == aDataDifferential); CHECK(myDVH.convertAbsoluteToRelative(false) == aDataDifferentialRelative); CHECK_EQUAL(myDVH.getNumberOfVoxels(), numberOfVoxels); CHECK_EQUAL(myDVH.getDeltaV(), voxelVolume); CHECK_EQUAL(myDVH.getDeltaD(), binSize); CHECK_EQUAL(myDVH.getMaximum(), maximum); CHECK_EQUAL(myDVH.getMinimum(), minimum); CHECK_EQUAL(myDVH.getMean(), mean); CHECK_EQUAL(myDVH.getVariance(), variance); CHECK_EQUAL(myDVH.getStdDeviation(), stdDeviation); CHECK_EQUAL(myDVH.getMedian(), median); CHECK_EQUAL(myDVH.getModal(), modal); //We can't test for absolute values as the implementation of rand() differs depending on compiler and different DVHs are created CHECK_NO_THROW(myDVH.getVx(0)); CHECK_NO_THROW(myDVH.getVx(7)); CHECK_NO_THROW(myDVH.getDx(0)); CHECK_NO_THROW(myDVH.getDx(100000)); int percentage = 20; VolumeType absVol = VolumeType(percentage * numberOfVoxels * voxelVolume / 100.0); CHECK_EQUAL(myDVH.getAbsoluteVolume(percentage), absVol); //5) test equality structureID = myDVH.getStructureID(); doseID = myDVH.getDoseID(); voxelizationID = myDVH.getVoxelizationID(); core::DVH myDVH2(aDataDifferential2, binSize, voxelVolume, structureID, doseID); core::DVH myDVH3(aDataDifferential, binSize, voxelVolume, structureID+"_diff", doseID); core::DVH myDVH4(aDataDifferential, binSize, voxelVolume, structureID, doseID+"_diff"); core::DVH myDVH5(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID+"_diff"); CHECK(!(myDVH == myDVH2)); CHECK(!(myDVH == myDVH3)); CHECK(!(myDVH == myDVH4)); CHECK(!(myDVH == myDVH5)); CHECK_EQUAL(myDVH, myDVH); core::DVH aDVH(myOtherDVH); CHECK_EQUAL(aDVH, myOtherDVH); std::map normalizedDVHDiff = myDVH.getNormalizedDVH({ DVHType::Differential }); for (auto elem : normalizedDVHDiff) { CHECK_EQUAL(aDataDifferential.at(std::round(elem.first / binSize)), (elem.second / voxelVolume)); } std::map normalizedDVHCum = myDVH.getNormalizedDVH(); for (auto elem : normalizedDVHCum) { CHECK_EQUAL(myDVH.getDataCumulative().at(std::round(elem.first / binSize)), (elem.second / voxelVolume)); } CHECK_NO_THROW(myDVH.getDataCumulative()); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DummyDVHGenerator.cpp b/testing/core/DummyDVHGenerator.cpp index dfe118e..66e1487 100644 --- a/testing/core/DummyDVHGenerator.cpp +++ b/testing/core/DummyDVHGenerator.cpp @@ -1,109 +1,104 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "DummyDVHGenerator.h" + namespace rttb { namespace testing { DummyDVHGenerator::DummyDVHGenerator(): _binSize(DoseTypeGy(0.1)), _voxelVolume(8), _value(0) { /* initialize random seed: */ srand(static_cast(time(nullptr))); }; core::DVH DummyDVHGenerator::generateDVH(IDType structureID, IDType doseID) { core::DVH::DataDifferentialType aDataDifferential; for (int i = 0; i < 100; i++) { _value = DoseCalcType((double(rand()) / RAND_MAX) * 1000); //cut off values to avoid problems on comparisson with reimported values after //writing to file. _value = floor(_value * 1000000) / 1000000; aDataDifferential.push_back(_value); } return core::DVH(aDataDifferential, _binSize, _voxelVolume, structureID, doseID); } core::DVH DummyDVHGenerator::generateDVH(IDType structureID, IDType doseID, DoseCalcType value) { _value = value; core::DVH::DataDifferentialType aDataDifferential; for (int i = 0; i < 100; i++) { aDataDifferential.push_back(_value); } return core::DVH(aDataDifferential, _binSize, _voxelVolume, structureID, doseID); } core::DVH DummyDVHGenerator::generateDVH(IDType structureID, IDType doseID, DoseCalcType minValue, DoseCalcType maxValue) { _voxelVolume = 0.2 * 0.2 * 0.4; bool decrease = false; core::DVH::DataDifferentialType aDataDifferential; for (int i = 0; i <= 200; i++) { if ((i > 20) && (i < 180)) { if ((_value == 0) && (!decrease)) { _value = DoseCalcType((double(rand()) / RAND_MAX) * 10) + minValue; } else if (!decrease) { _value = _value + DoseCalcType((double(rand()) / RAND_MAX) * (maxValue / 10)); } if ((_value > maxValue) || (decrease)) { decrease = true; _value = _value - DoseCalcType((double(rand()) / RAND_MAX) * (maxValue / 3)); } if (_value < 0) { _value = 0; } } else { _value = 0; } aDataDifferential.push_back(_value); } return core::DVH(aDataDifferential, _binSize, _voxelVolume, structureID, doseID); } } } \ No newline at end of file diff --git a/testing/core/DummyDVHGenerator.h b/testing/core/DummyDVHGenerator.h index ebbfaf4..c65c51e 100644 --- a/testing/core/DummyDVHGenerator.h +++ b/testing/core/DummyDVHGenerator.h @@ -1,71 +1,65 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_DVH_GENERATOR_H #define __DUMMY_DVH_GENERATOR_H #include #include "rttbDVH.h" #include "rttbBaseType.h" - namespace rttb { namespace testing { /*! @class DummyDVHGenerator @brief generate DVHs for testing based on a randomly generated dose data vector. */ class DummyDVHGenerator { private: DoseTypeGy _binSize; DoseVoxelVolumeType _voxelVolume; DoseCalcType _value; public: ~DummyDVHGenerator() {}; DummyDVHGenerator(); /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. The values of the 100 bins are randomly generated [0,1000]. */ core::DVH generateDVH(IDType structureID, IDType doseID); /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. The values of the 100 bins all contain the given value. */ core::DVH generateDVH(IDType structureID, IDType doseID, DoseCalcType value); /*! generate a dummy DVH with bin size = 0.1, voxel volume = 0.016 and 200 entries. The values of the 200 bins are random values inside the interval defined by minValue and maxValue. */ core::DVH generateDVH(IDType structureID, IDType doseID, DoseCalcType minValue, DoseCalcType maxValue); }; } } #endif diff --git a/testing/core/DummyDoseAccessor.cpp b/testing/core/DummyDoseAccessor.cpp index 5d42d3b..d88c09c 100644 --- a/testing/core/DummyDoseAccessor.cpp +++ b/testing/core/DummyDoseAccessor.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "DummyDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace testing { DummyDoseAccessor::~DummyDoseAccessor() {} DummyDoseAccessor::DummyDoseAccessor() { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyDoseAccessor_" + ss.str(); assembleGeometricInfo(); for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) { doseData.push_back((double(rand()) / RAND_MAX) * 1000); } } DummyDoseAccessor::DummyDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyDoseAccessor_" + ss.str(); doseData = aDoseVector; _geoInfo = geoInfo; } void DummyDoseAccessor::assembleGeometricInfo() { SpacingVectorType3D aVector(2.5); _geoInfo.setSpacing(aVector); WorldCoordinate3D anOtherVector(-25, -2, 35); _geoInfo.setImagePositionPatient(anOtherVector); _geoInfo.setNumRows(11); _geoInfo.setNumColumns(10); _geoInfo.setNumSlices(10); OrientationMatrix unit = OrientationMatrix(); _geoInfo.setOrientationMatrix(unit); } GenericValueType DummyDoseAccessor::getValueAt(const VoxelGridID aID) const { if (!_geoInfo.validID(aID)) { throw core::IndexOutOfBoundsException("Not a valid Position!"); } return doseData.at(aID); } GenericValueType DummyDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID gridID = 0; _geoInfo.convert(aIndex, gridID); return getValueAt(gridID); } }//end namespace testing }//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyDoseAccessor.h b/testing/core/DummyDoseAccessor.h index 067e76f..d31a21e 100644 --- a/testing/core/DummyDoseAccessor.h +++ b/testing/core/DummyDoseAccessor.h @@ -1,84 +1,78 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_DOSE_ACCESSOR_H #define __DUMMY_DOSE_ACCESSOR_H #include #include #include "rttbAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" - namespace rttb { namespace testing { /*! @class DummyDoseAccessor @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. The default grid size is [11,10,5] */ class DummyDoseAccessor: public core::AccessorWithGeoInfoBase { private: /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector doseData; IDType _doseUID; public: ~DummyDoseAccessor(); /*! @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. The default grid size is [11,10,5] */ DummyDoseAccessor(); /*! @brief Constructor. Initialisation of dose with a given vector. */ DummyDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo); void assembleGeometricInfo() override; const std::vector* getDoseVector() const { return &doseData; }; GenericValueType getValueAt(const VoxelGridID aID) const; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const; const IDType getUID() const { return _doseUID; }; }; } } #endif diff --git a/testing/core/DummyInhomogeneousDoseAccessor.cpp b/testing/core/DummyInhomogeneousDoseAccessor.cpp index 83c28f9..0087e28 100644 --- a/testing/core/DummyInhomogeneousDoseAccessor.cpp +++ b/testing/core/DummyInhomogeneousDoseAccessor.cpp @@ -1,43 +1,37 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "DummyInhomogeneousDoseAccessor.h" namespace rttb { namespace testing { DummyInhomogeneousDoseAccessor::~DummyInhomogeneousDoseAccessor() {} DummyInhomogeneousDoseAccessor::DummyInhomogeneousDoseAccessor() : DummyDoseAccessor() { } bool DummyInhomogeneousDoseAccessor::isGridHomogeneous() const { return false; } }//end namespace testing }//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyInhomogeneousDoseAccessor.h b/testing/core/DummyInhomogeneousDoseAccessor.h index 91260e4..05a4938 100644 --- a/testing/core/DummyInhomogeneousDoseAccessor.h +++ b/testing/core/DummyInhomogeneousDoseAccessor.h @@ -1,50 +1,44 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_DOSE_INHOMOGENEOUS_ACCESSOR_H #define __DUMMY_DOSE_INHOMOGENEOUS_ACCESSOR_H #include "DummyDoseAccessor.h" - namespace rttb { namespace testing { /*! @class DummyInhomogeneousDoseAccessor @brief A dummy DoseAccessor for testing with inhomogeneous grid */ class DummyInhomogeneousDoseAccessor: public DummyDoseAccessor { public: ~DummyInhomogeneousDoseAccessor(); /*! @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. The default grid size is [11,10,5] */ DummyInhomogeneousDoseAccessor(); bool isGridHomogeneous() const override; }; } } #endif diff --git a/testing/core/DummyMaskAccessor.cpp b/testing/core/DummyMaskAccessor.cpp index 46eba43..f6401e7 100644 --- a/testing/core/DummyMaskAccessor.cpp +++ b/testing/core/DummyMaskAccessor.cpp @@ -1,162 +1,156 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include #include "DummyMaskAccessor.h" #include "rttbNullPointerException.h" namespace rttb { namespace testing { DummyMaskAccessor::DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo) { _spRelevantVoxelVector = MaskVoxelListPointer(); _geoInfo = aGeometricInfo; boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "DummyMask_" + ss.str(); } DummyMaskAccessor::DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo, MaskVoxelListPointer voxelListPtr) { _spRelevantVoxelVector = voxelListPtr; _geoInfo = aGeometricInfo; boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "DummyMask_" + ss.str(); } void DummyMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; } for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) { if ((double(rand()) / RAND_MAX) > 0.5) { core::MaskVoxel newMaskVoxel(i); newMaskVoxel.setRelevantVolumeFraction((double(rand()) / RAND_MAX)); newRelevantVoxelVector.push_back(newMaskVoxel); } } _spRelevantVoxelVector = boost::make_shared(newRelevantVoxelVector); return; } DummyMaskAccessor::MaskVoxelListPointer DummyMaskAccessor::getRelevantVoxelVector() { updateMask(); return _spRelevantVoxelVector; } DummyMaskAccessor::MaskVoxelListPointer DummyMaskAccessor::getRelevantVoxelVector( float lowerThreshold) { auto filteredVoxelVectorPointer = boost::make_shared(); updateMask(); DummyMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } return filteredVoxelVectorPointer; } bool DummyMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { voxel.setRelevantVolumeFraction(0); if (!_geoInfo.validID(aID)) { return false; } if (_spRelevantVoxelVector) { DummyMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } } else { return false; } return false; } bool DummyMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } } } \ No newline at end of file diff --git a/testing/core/DummyMaskAccessor.h b/testing/core/DummyMaskAccessor.h index 4255eab..d2c0466 100644 --- a/testing/core/DummyMaskAccessor.h +++ b/testing/core/DummyMaskAccessor.h @@ -1,81 +1,75 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_MASK_ACCESSOR_H #define __DUMMY_MASK_ACCESSOR_H #include #include "rttbMaskAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" - namespace rttb { namespace testing { /*! @class DumyMaskAccessor @brief Create a dummy MaskAccessor for testing. */ class DummyMaskAccessor: public core::MaskAccessorInterface { public: typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; private: /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; core::GeometricInfo _geoInfo; IDType _maskUID; public: DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo); DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo, MaskVoxelListPointer voxelListPtr); ~DummyMaskAccessor() {}; void updateMask(); const core::GeometricInfo& getGeometricInfo() const { return _geoInfo; }; MaskVoxelListPointer getRelevantVoxelVector(); MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; bool getMaskAt(const VoxelGridIndex3D& gridIndex, core::MaskVoxel& voxel) const; IDType getMaskUID() const { return _maskUID; }; }; } } #endif diff --git a/testing/core/DummyMutableDoseAccessor.cpp b/testing/core/DummyMutableDoseAccessor.cpp index 12de4c3..ed82584 100644 --- a/testing/core/DummyMutableDoseAccessor.cpp +++ b/testing/core/DummyMutableDoseAccessor.cpp @@ -1,120 +1,114 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include #include "DummyMutableDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace testing { DummyMutableDoseAccessor::~DummyMutableDoseAccessor() {} DummyMutableDoseAccessor::DummyMutableDoseAccessor() { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyMutableDoseAccessor_" + ss.str(); SpacingVectorType3D aVector(2.5); _geoInfo.setSpacing(aVector); WorldCoordinate3D anOtherVector(-25, -2, 35); _geoInfo.setImagePositionPatient(anOtherVector); _geoInfo.setNumRows(11); _geoInfo.setNumColumns(10); _geoInfo.setNumSlices(5); OrientationMatrix unit = OrientationMatrix(); _geoInfo.setOrientationMatrix(unit); for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) { doseData.push_back((double(rand()) / RAND_MAX) * 1000); } } DummyMutableDoseAccessor::DummyMutableDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyMutableDoseAccessor_" + ss.str(); doseData = aDoseVector; _geoInfo = geoInfo; } const core::GeometricInfo& DummyMutableDoseAccessor:: getGeometricInfo() const { return _geoInfo; } GenericValueType DummyMutableDoseAccessor::getValueAt(const VoxelGridID aID) const { if (!_geoInfo.validID(aID)) { throw core::IndexOutOfBoundsException("Not a valid Position!"); } return doseData.at(aID); } GenericValueType DummyMutableDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID gridID = 0; _geoInfo.convert(aIndex, gridID); return getValueAt(gridID); } void DummyMutableDoseAccessor::setDoseAt(const VoxelGridID aID, DoseTypeGy value) { if (!_geoInfo.validID(aID)) { throw core::IndexOutOfBoundsException("Not a valid Position!"); } doseData.at(aID) = value; } void DummyMutableDoseAccessor::setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) { VoxelGridID gridID = 0; _geoInfo.convert(aIndex, gridID); setDoseAt(gridID, value); } }//end namespace testing }//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyMutableDoseAccessor.h b/testing/core/DummyMutableDoseAccessor.h index 5dbdae9..f7ceca3 100644 --- a/testing/core/DummyMutableDoseAccessor.h +++ b/testing/core/DummyMutableDoseAccessor.h @@ -1,88 +1,82 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_MUTABLE_DOSE_ACCESSOR_H #define __DUMMY_MUTABLE_DOSE_ACCESSOR_H #include #include "rttbMutableDoseAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" - namespace rttb { namespace testing { /*! @class DummyMutableDoseAccessor @brief A dummy MutableDoseAccessor for testing filled with random dose values between 0 and 100. The default grid size is [11,10,5] */ class DummyMutableDoseAccessor: public core::MutableDoseAccessorInterface { private: /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector doseData; IDType _doseUID; core::GeometricInfo _geoInfo; public: ~DummyMutableDoseAccessor(); /*! @brief A dummy DummyMutableDoseAccessor for testing filled with random dose values between 0 and 100. The default grid size is [11,10,5] */ DummyMutableDoseAccessor(); /*! @brief Constructor. Initialisation of dose with a given vector. */ DummyMutableDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo); const std::vector* getDoseVector() const { return &doseData; }; virtual const core::GeometricInfo& getGeometricInfo() const; GenericValueType getValueAt(const VoxelGridID aID) const; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const; void setDoseAt(const VoxelGridID aID, DoseTypeGy value); void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value); const IDType getUID() const { return _doseUID; }; }; } } #endif diff --git a/testing/core/DummyStructure.cpp b/testing/core/DummyStructure.cpp index 4a496a9..3345ff0 100644 --- a/testing/core/DummyStructure.cpp +++ b/testing/core/DummyStructure.cpp @@ -1,748 +1,742 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "DummyStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace testing { DummyStructure::~DummyStructure() {} DummyStructure::DummyStructure(const core::GeometricInfo& aGeoInfo) { _geoInfo = aGeoInfo; } core::Structure DummyStructure::CreateRectangularStructureCentered(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 1); VoxelGridIndex2D another_i2(5, 1); VoxelGridIndex2D another_i3(5, 5); VoxelGridIndex2D another_i4(2, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure_rectangular_centered = core::Structure(another_polySeq); return test_structure_rectangular_centered; } core::Structure DummyStructure::CreateRectangularStructureCenteredContourPlaneThicknessNotEqualDosePlaneThickness(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 1); VoxelGridIndex2D another_i2(5, 1); VoxelGridIndex2D another_i3(5, 5); VoxelGridIndex2D another_i4(2, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector, zPlane); PolygonType another_polygon2 = another_cts.createPolygonCenterOnPlaneCenter(another_voxelVector, zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); another_polySeq.push_back(another_polygon2); core::Structure test_structure_rectangular_centered = core::Structure(another_polySeq); return test_structure_rectangular_centered; } core::Structure DummyStructure::CreateRectangularStructureCentered(GridIndexType fromZPlane, GridIndexType toZPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 1); VoxelGridIndex2D another_i2(5, 1); VoxelGridIndex2D another_i3(5, 5); VoxelGridIndex2D another_i4(2, 5); PolygonSequenceType another_polySeq; for (unsigned int i = fromZPlane; i <= toZPlane; ++i){ another_voxelVector.clear(); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector, i); another_polySeq.push_back(another_polygon1); } core::Structure test_structure_rectangular_centered = core::Structure(another_polySeq); return test_structure_rectangular_centered; } core::Structure DummyStructure::CreateRectangularStructureCentered(GridIndexType fromZPlane, GridIndexType toZPlane, GridIndexType fromZPlane2, GridIndexType toZPlane2) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 1); VoxelGridIndex2D another_i2(5, 1); VoxelGridIndex2D another_i3(5, 5); VoxelGridIndex2D another_i4(2, 5); PolygonSequenceType another_polySeq; for (unsigned int i = fromZPlane; i <= toZPlane; ++i){ another_voxelVector.clear(); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector, i); another_polySeq.push_back(another_polygon1); } for (unsigned int i = fromZPlane2; i <= toZPlane2; ++i){ another_voxelVector.clear(); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector, i); another_polySeq.push_back(another_polygon1); } core::Structure test_structure_rectangular_centered = core::Structure(another_polySeq); return test_structure_rectangular_centered; } core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacement( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonBetweenUpperLeftAndCenter( another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight() { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonSequenceType another_polySeq; core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(5, 7); VoxelGridIndex2D another_i3(8, 4); VoxelGridIndex2D another_i4(5, 1); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonBetweenLowerRightAndCenter( another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClockIntermediatePoints( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(5, 7); VoxelGridIndex2D another_i3(8, 4); VoxelGridIndex2D another_i4(5, 1); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonIntermediatePoints(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureSeveralSeperateSectionsInsideOneVoxel( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); another_voxelVector.push_back(another_i1); PolygonType another_polygon1 = another_cts.createStructureSeveralSectionsInsideOneVoxelA( another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureSelfTouchingA(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); another_voxelVector.push_back(another_i1); PolygonType another_polygon1 = another_cts.createStructureSelfTouchingA(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureIntersectingTwoPolygonsInDifferentSlices( GridIndexType zPlane1, GridIndexType zPlane2) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); CreateTestStructure one_more_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(8, 6); VoxelGridIndex2D another_i4(2, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane1); std::vector one_more_voxelVector; VoxelGridIndex2D one_more_i1(3, 5); VoxelGridIndex2D one_more_i2(9, 5); VoxelGridIndex2D one_more_i3(9, 7); VoxelGridIndex2D one_more_i4(3, 7); one_more_voxelVector.push_back(one_more_i1); one_more_voxelVector.push_back(one_more_i2); one_more_voxelVector.push_back(one_more_i3); one_more_voxelVector.push_back(one_more_i4); PolygonType another_polygon2 = one_more_cts.createPolygonCenter(one_more_voxelVector , zPlane2); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); another_polySeq.push_back(another_polygon2); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureIntersectingTwoPolygons(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); CreateTestStructure one_more_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(8, 6); VoxelGridIndex2D another_i4(2, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); std::vector one_more_voxelVector; VoxelGridIndex2D one_more_i1(3, 5); VoxelGridIndex2D one_more_i2(9, 5); VoxelGridIndex2D one_more_i3(9, 7); VoxelGridIndex2D one_more_i4(3, 7); one_more_voxelVector.push_back(one_more_i1); one_more_voxelVector.push_back(one_more_i2); one_more_voxelVector.push_back(one_more_i3); one_more_voxelVector.push_back(one_more_i4); PolygonType another_polygon2 = one_more_cts.createPolygonCenter(one_more_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); another_polySeq.push_back(another_polygon2); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureIntersecting(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(2, 6); VoxelGridIndex2D another_i4(8, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouches(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i2(2, 8); VoxelGridIndex2D another_i3(4, 8); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); PolygonType another_polygon1 = another_cts.createPolygonUpperCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedPointDoubeled( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i4(2, 4); VoxelGridIndex2D another_i2(4, 4); VoxelGridIndex2D another_i3(3, 8); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); PolygonType another_polygon1 = another_cts.createPolygonUpperCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 5); VoxelGridIndex2D another_i2(3, 5); VoxelGridIndex2D another_i3(7, 6); VoxelGridIndex2D another_i4(7, 6); VoxelGridIndex2D another_i5(7, 4); VoxelGridIndex2D another_i6(7, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(7, 5); VoxelGridIndex2D another_i2(7, 5); VoxelGridIndex2D another_i3(3, 6); VoxelGridIndex2D another_i4(3, 6); VoxelGridIndex2D another_i5(3, 4); VoxelGridIndex2D another_i6(3, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedQuaterPi( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i2(3, 4); VoxelGridIndex2D another_i3(3, 6); VoxelGridIndex2D another_i4(3, 6); VoxelGridIndex2D another_i5(7, 5); VoxelGridIndex2D another_i6(7, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureCircle(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(4, 4); another_voxelVector.push_back(another_i1); PolygonType another_polygon1 = another_cts.createPolygonCircle(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperRight( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i3(4, 5); VoxelGridIndex2D another_i5(5, 3); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i5); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerRight( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); VoxelGridIndex2D another_i2(2, 2); VoxelGridIndex2D another_i3(3, 1); VoxelGridIndex2D another_i4(3, 1); VoxelGridIndex2D another_i5(4, 3); VoxelGridIndex2D another_i6(4, 3); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerLeft( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 3); VoxelGridIndex2D another_i2(3, 3); VoxelGridIndex2D another_i3(4, 4); VoxelGridIndex2D another_i4(4, 4); VoxelGridIndex2D another_i5(2, 5); VoxelGridIndex2D another_i6(2, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperLeft( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 5); VoxelGridIndex2D another_i2(5, 5); VoxelGridIndex2D another_i3(4, 6); VoxelGridIndex2D another_i4(4, 6); VoxelGridIndex2D another_i5(3, 4); VoxelGridIndex2D another_i6(3, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } void DummyStructure::ShowTestStructure(core::Structure aStructure) { WorldCoordinate3D aPoint(0); PolygonSequenceType strVector = aStructure.getStructureVector(); for (size_t struct_index = 0 ; struct_index < strVector.size() ; struct_index++) { for (size_t point_index = 0 ; point_index < strVector.at(struct_index).size() ; point_index++) { aPoint = strVector.at(struct_index).at(point_index); std::cout << " aPoint.x " << aPoint.x() << std::endl; std::cout << " aPoint.y " << aPoint.y() << std::endl; std::cout << " aPoint.z " << aPoint.z() << std::endl; } } } core::Structure DummyStructure::CreateRectangularStructureUpperLeftRotated(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } }//testing }//rttb diff --git a/testing/core/DummyStructure.h b/testing/core/DummyStructure.h index dea6e31..052283f 100644 --- a/testing/core/DummyStructure.h +++ b/testing/core/DummyStructure.h @@ -1,112 +1,105 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests - #include "rttbStructure.h" #include "CreateTestStructure.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" namespace rttb { namespace testing { /*! @class DummyStructure @brief generate simple geometric testing structures. The maximal x coordinate used is 9 and the maximal y coordinate is 8. Make sure the geometricInfo corresponds to a sufficiently large data grid. @see CreateTestStructures */ class DummyStructure { private: core::GeometricInfo _geoInfo; public: ~DummyStructure(); DummyStructure(const core::GeometricInfo& aGeoInfo); const core::GeometricInfo& getGeometricInfo() { return _geoInfo; }; core::Structure CreateRectangularStructureCentered(GridIndexType zPlane); /* Generate rectangular structure for the z slice and another slice between z and z+1. So the structure has a smaller z spacing than the dose */ core::Structure CreateRectangularStructureCenteredContourPlaneThicknessNotEqualDosePlaneThickness(GridIndexType zPlane); /* Generate rectangular structure for the z slices from fromZPlane(included) to toZPlane(included) */ core::Structure CreateRectangularStructureCentered(GridIndexType fromZPlane, GridIndexType toZPlane); /* Generate rectangular structure for the z slices from fromZPlane(included) to toZPlane(included) and from fromZPlane2(included) to toZPlane2(included) */ core::Structure CreateRectangularStructureCentered(GridIndexType fromZPlane, GridIndexType toZPlane, GridIndexType fromZPlane2, GridIndexType toZPlane2); core::Structure CreateTestStructureCircle(GridIndexType zPlane); core::Structure CreateRectangularStructureUpperLeftRotated(GridIndexType zPlane); core::Structure CreateTestStructureSeveralSeperateSectionsInsideOneVoxel(GridIndexType zPlane); core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacement( GridIndexType zPlane); core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight(); core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock( GridIndexType zPlane); core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClockIntermediatePoints( GridIndexType zPlane); core::Structure CreateTestStructureSelfTouchingA(GridIndexType zPlane); core::Structure CreateTestStructureIntersecting(GridIndexType zPlane); core::Structure CreateTestStructureIntersectingTwoPolygons(GridIndexType zPlane); core::Structure CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(GridIndexType zPlane1, GridIndexType zPlane2); core::Structure CreateTestStructureInsideInsideTouches(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesRotatedQuaterPi(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi( GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi( GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesRotatedPointDoubeled(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesUpperLeft(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesLowerLeft(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesLowerRight(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesUpperRight(GridIndexType zPlane); void ShowTestStructure(core::Structure aStructure); }; }//testing }//rttb diff --git a/testing/core/GenericDoseIteratorTest.cpp b/testing/core/GenericDoseIteratorTest.cpp index 93d6657..7894dbc 100644 --- a/testing/core/GenericDoseIteratorTest.cpp +++ b/testing/core/GenericDoseIteratorTest.cpp @@ -1,112 +1,106 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "DummyDoseAccessor.h" #include "DummyInhomogeneousDoseAccessor.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; /*! @brief GenericDoseIteratorTest - test the API of GenericDoseIterator 1) test constructor (values as expected?) 2) test reset/next/get current values/isPositionValid 3) test DoseIteratorInterface functions */ int GenericDoseIteratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //create dummy DoseAccessor boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); boost::shared_ptr spTestDoseAccessorInhomo = boost::make_shared(); DoseAccessorPointer spDoseAccessorInhomo(spTestDoseAccessorInhomo); //1) test constructor (values as expected?) CHECK_NO_THROW(core::GenericDoseIterator genDoseIterator(spDoseAccessor)); core::GenericDoseIterator genDoseIterator(spDoseAccessor); const VoxelGridID defaultDoseVoxelGridID = 0; const DoseVoxelVolumeType defaultVoxelVolume = 0; CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK_EQUAL(defaultVoxelVolume, genDoseIterator.getCurrentVoxelVolume()); core::GenericDoseIterator genDoseIteratorInhomo(spDoseAccessorInhomo); //2) test reset/next genDoseIterator.reset(); const DoseVoxelVolumeType homogeneousVoxelVolume = genDoseIterator.getCurrentVoxelVolume(); CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK(!(defaultVoxelVolume == genDoseIterator.getCurrentVoxelVolume())); core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); SpacingVectorType3D spacing = geoInfo.getSpacing(); CHECK_EQUAL(spacing(0)*spacing(1)*spacing(2) / 1000, genDoseIterator.getCurrentVoxelVolume()); CHECK_THROW_EXPLICIT(genDoseIteratorInhomo.reset(), core::InvalidParameterException); //check if the correct voxels are accessed const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); genDoseIterator.reset(); VoxelGridID position = 0; while (genDoseIterator.isPositionValid()) { CHECK_EQUAL(genDoseIterator.getCurrentDoseValue(), doseVals->at(position)); CHECK_EQUAL(homogeneousVoxelVolume, genDoseIterator.getCurrentVoxelVolume()); CHECK_EQUAL(1, genDoseIterator.getCurrentRelevantVolumeFraction()); CHECK_EQUAL(position, genDoseIterator.getCurrentVoxelGridID()); genDoseIterator.next(); position++; } CHECK_EQUAL(spTestDoseAccessor->getGridSize(), spTestDoseAccessor->getGeometricInfo().getNumberOfVoxels()); //check isPositionValid() in invalid positions CHECK(!(genDoseIterator.isPositionValid())); //after end of dose CHECK_EQUAL(genDoseIterator.getCurrentDoseValue(), 0); genDoseIterator.reset(); CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK(genDoseIterator.isPositionValid());//before start of dose //3) test DoseIteratorInterface functions CHECK_EQUAL(genDoseIterator.getVoxelizationID(), ""); CHECK_EQUAL(genDoseIterator.getDoseUID(), spTestDoseAccessor->getUID()); CHECK_THROW_EXPLICIT(genDoseIteratorInhomo.getCurrentVoxelVolume(), core::InvalidParameterException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/GenericMaskedDoseIteratorTest.cpp b/testing/core/GenericMaskedDoseIteratorTest.cpp index 6547c0b..6ba9097 100644 --- a/testing/core/GenericMaskedDoseIteratorTest.cpp +++ b/testing/core/GenericMaskedDoseIteratorTest.cpp @@ -1,143 +1,137 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbException.h" #include "DummyDoseAccessor.h" #include "DummyInhomogeneousDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::GenericMaskedDoseIterator::DoseAccessorPointer DoseAccessorPointer; /*! @brief GenericMaskedDoseIteratorTest. 1) test constructor (values as expected?) 2) test reset/next/get current values/isPositionValid */ int GenericMaskedDoseIteratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); boost::shared_ptr spTestDoseAccessorInhomo = boost::make_shared(); DoseAccessorPointer spDoseAccessorInhomo(spTestDoseAccessorInhomo); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); core::GeometricInfo geoInfo; boost::shared_ptr spTestMaskAccessor = boost::make_shared (geoInfo); MaskAccessorPointer spMaskAccessor(spTestMaskAccessor); //1) test constructor (values as expected?) //not nullptr MaskAccessorPointer spNullMaskAccessor; DoseAccessorPointer spNullDoseAccessor; CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spNullMaskAccessor, spDoseAccessor), core::NullPointerException); CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spNullDoseAccessor), core::NullPointerException); //not same core::GeometricInfo CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor), core::Exception); //set correct GeometricInfo geoInfo = spDoseAccessor->getGeometricInfo(); boost::shared_ptr spTestMaskAccessor1 = boost::make_shared (geoInfo); MaskAccessorPointer spMaskAccessorTemp(spTestMaskAccessor1); spMaskAccessor.swap(spMaskAccessorTemp); CHECK_NO_THROW(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor)); CHECK_EQUAL(spMaskAccessor->isGridHomogeneous(), true); core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor); core::GenericMaskedDoseIterator genMaskedDoseIteratorInhomo(spMaskAccessor, spDoseAccessorInhomo); //2) test reset/next const DummyMaskAccessor::MaskVoxelListPointer maskedVoxelListPtr = spTestMaskAccessor1->getRelevantVoxelVector(); genMaskedDoseIterator.reset(); const DoseVoxelVolumeType homogeneousVoxelVolume = genMaskedDoseIterator.getCurrentVoxelVolume(); CHECK_EQUAL((maskedVoxelListPtr->begin())->getVoxelGridID(), genMaskedDoseIterator.getCurrentVoxelGridID()); geoInfo = spDoseAccessor->getGeometricInfo(); SpacingVectorType3D spacing = geoInfo.getSpacing(); CHECK_EQUAL(spacing(0)*spacing(1)*spacing(2) / 1000, genMaskedDoseIterator.getCurrentVoxelVolume()); CHECK_THROW_EXPLICIT(genMaskedDoseIteratorInhomo.getCurrentVoxelVolume(), core::InvalidParameterException); genMaskedDoseIterator.reset(); for (unsigned int i = 0; i < maskedVoxelListPtr->size(); i++) { CHECK_NO_THROW(genMaskedDoseIterator.next()); } CHECK_EQUAL(genMaskedDoseIterator.getCurrentRelevantVolumeFraction(), 0); //check if the correct voxels are accessed genMaskedDoseIterator.reset(); VoxelGridID defaultDoseVoxelGridID = genMaskedDoseIterator.getCurrentVoxelGridID(); DoseTypeGy controlValue = 0; VoxelGridID position = 0; while (genMaskedDoseIterator.isPositionValid()) { controlValue = doseVals->at((maskedVoxelListPtr->at(position)).getVoxelGridID()); CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentDoseValue()); controlValue = controlValue * (maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(); CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentMaskedDoseValue()); CHECK_EQUAL(homogeneousVoxelVolume, genMaskedDoseIterator.getCurrentVoxelVolume()); CHECK_EQUAL((maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(), genMaskedDoseIterator.getCurrentRelevantVolumeFraction()); CHECK_EQUAL((maskedVoxelListPtr->at(position)).getVoxelGridID(), genMaskedDoseIterator.getCurrentVoxelGridID()); CHECK(genMaskedDoseIterator.isPositionValid()); genMaskedDoseIterator.next(); position++; } //check isPositionValid() in invalid positions CHECK(!(genMaskedDoseIterator.isPositionValid())); //after end of dose genMaskedDoseIterator.reset(); CHECK_EQUAL(defaultDoseVoxelGridID, genMaskedDoseIterator.getCurrentVoxelGridID()); CHECK(genMaskedDoseIterator.isPositionValid());//at start of dose RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/core/GeometricInfoTest.cpp b/testing/core/GeometricInfoTest.cpp index 52ee032..2e2ec50 100644 --- a/testing/core/GeometricInfoTest.cpp +++ b/testing/core/GeometricInfoTest.cpp @@ -1,561 +1,555 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" namespace rttb { namespace testing { /*!@brief GeometricInfoTest - test the API of GeometricInfo @note ITK pixel indexing: Index[0] = col, Index[1] = row, Index[2] = slice. 1) test default constructor (values as expected?) 2) test set/getImagePositionPatient 4) test set/getSpacing 5) test set/getNumColumns/Rows/Slices 6) test get/setOrientationMatrix 8) test operators "==" 9) test equalsAlmost 10) test world to index coordinate conversion 11) test isInside and index to world coordinate conversion 12) test with simple Geometry: isInside, geometryCoordinateToWorldCoordinate(), worldCoordinateToGeometryCoordinate(), indexToWorldCoordinate() 13) test getNumberOfVoxels 14) Test convert, validID and validIndex */ int GeometricInfoTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test default constructor (values as expected?) CHECK_NO_THROW(core::GeometricInfo()); core::GeometricInfo geoInfo; SpacingVectorType3D testNullSV(0); WorldCoordinate3D testNullWC(0); OrientationMatrix testNullOM(0); CHECK_EQUAL(testNullSV, geoInfo.getSpacing()); CHECK_EQUAL(testNullWC, geoInfo.getImagePositionPatient()); CHECK_EQUAL(testNullOM, geoInfo.getOrientationMatrix()); //2) test set/getImagePositionPatient WorldCoordinate3D testIPP(1.2, 3.4, 5.6); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); geoInfo.setImagePositionPatient(testIPP); CHECK_EQUAL(testIPP, geoInfo.getImagePositionPatient()); //4) test set/getSpacing //negative spacing does not make sense! /*!@is related to #2028 Should SpacingTypeVector/GridVolumeType/OrientationMatrix be forced to be non-negative?*/ SpacingVectorType3D expectedSpacing(4.15, 2.35, 100); expectedSpacing(0) = 4.15; expectedSpacing(1) = 2.35; expectedSpacing(2) = 100; CHECK_NO_THROW(geoInfo.setSpacing(expectedSpacing)); geoInfo.setSpacing(expectedSpacing); CHECK_EQUAL(expectedSpacing, geoInfo.getSpacing()); //5) test set/getNumColumns/Rows/Slices const VoxelGridIndex3D expectedVoxelDims(10, 5, 3); //CHECK_THROW(geoInfo.setNumColumns(1.2)); -> implicit conversion will prevent exception CHECK_NO_THROW(geoInfo.setNumColumns(expectedVoxelDims(0))); geoInfo.setNumColumns(expectedVoxelDims(0)); CHECK_NO_THROW(geoInfo.setNumRows(expectedVoxelDims(1))); geoInfo.setNumRows(expectedVoxelDims(1)); //CHECK_THROW(geoInfo.setNumSlices(4.2)); -> implicit conversion will prevent exception CHECK_NO_THROW(geoInfo.setNumSlices(expectedVoxelDims(2))); geoInfo.setNumSlices(expectedVoxelDims(2)); ImageSize rttbSize = geoInfo.getImageSize(); CHECK_EQUAL(rttbSize(0), geoInfo.getNumColumns()); CHECK_EQUAL(rttbSize(1), geoInfo.getNumRows()); CHECK_EQUAL(rttbSize(2), geoInfo.getNumSlices()); rttbSize = ImageSize(11, 99, 6); core::GeometricInfo geoInfo3; geoInfo3.setImageSize(rttbSize); CHECK_EQUAL(rttbSize(0), geoInfo3.getNumColumns()); CHECK_EQUAL(rttbSize(1), geoInfo3.getNumRows()); CHECK_EQUAL(rttbSize(2), geoInfo3.getNumSlices()); //6) test get/setOrientationMatrix CHECK_EQUAL(testNullOM, geoInfo.getOrientationMatrix()); OrientationMatrix testOM(0); const WorldCoordinate3D testIORow(5.5, 4.7, 3.2); const WorldCoordinate3D testIOColumn(2.5, 1.8, 9.1); WorldCoordinate3D ortho = testIORow.cross(testIOColumn); testOM(0, 0) = testIORow(0); testOM(1, 0) = testIORow(1); testOM(2, 0) = testIORow(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); testOM(0, 1) = testIOColumn(0); testOM(1, 1) = testIOColumn(1); testOM(2, 1) = testIOColumn(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); testOM(0, 2) = ortho(0); testOM(1, 2) = ortho(1); testOM(2, 2) = ortho(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); //8) test operators "==" core::GeometricInfo geoInfo2; CHECK_EQUAL(geoInfo, geoInfo); CHECK(!(geoInfo == geoInfo2)); CHECK_EQUAL(geoInfo.getOrientationMatrix(), testOM); CHECK(!(geoInfo.getOrientationMatrix() == testNullOM)); //9) test equalsALmost OrientationMatrix testOM2 = testOM; SpacingVectorType3D testSPV2 = expectedSpacing; WorldCoordinate3D testIPP2 = testIPP; core::GeometricInfo testGI2, testGIEmpty; testGI2.setImagePositionPatient(testIPP2); testGI2.setOrientationMatrix(testOM2); testGI2.setSpacing(testSPV2); double smallValue = 0.000000001; testOM(0, 0) += smallValue; testSPV2(2) += smallValue; testIPP2(1) += smallValue; core::GeometricInfo testGI2similar; testGI2similar.setImagePositionPatient(testIPP2); testGI2similar.setOrientationMatrix(testOM2); testGI2similar.setSpacing(testSPV2); CHECK_EQUAL(testGI2.equalsAlmost(testGI2similar), true); CHECK_EQUAL(testGI2similar.equalsAlmost(testGI2), true); CHECK_EQUAL(testGI2.equalsAlmost(testGI2similar, smallValue * 0.001), false); CHECK_EQUAL(testGIEmpty.equalsAlmost(testGI2), false); CHECK_EQUAL(testGI2.equalsAlmost(testGIEmpty), false); //10) test world to index coordinate conversion //use unit matrix as orientation matrix CHECK_NO_THROW(geoInfo.setOrientationMatrix(OrientationMatrix())); //origin (inside) WorldCoordinate3D insideTestWC1 = geoInfo.getImagePositionPatient(); //inside const VoxelGridIndex3D expectedIndex(8, 3, 2); WorldCoordinate3D insideTestWC2(expectedIndex(0)*expectedSpacing(0) + testIPP(0), expectedIndex(1)*expectedSpacing(1) + testIPP(1), expectedIndex(2)*expectedSpacing(2) + testIPP(2)); //outside WorldCoordinate3D insideTestWC3(-33.12, 0, 14); // outside (dimension of grid) WorldCoordinate3D insideTestWC4(expectedVoxelDims(0)*expectedSpacing(0) + testIPP(0), expectedVoxelDims(1)*expectedSpacing(1) + testIPP(1), expectedVoxelDims(2)*expectedSpacing(2) + testIPP(2)); CHECK(geoInfo.isInside(insideTestWC1)); CHECK(geoInfo.isInside(insideTestWC2)); CHECK(!(geoInfo.isInside(insideTestWC3))); CHECK(!(geoInfo.isInside(insideTestWC4))); VoxelGridIndex3D testConvert(0); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC1, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(VoxelGridIndex3D(0), testConvert); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC2, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndex, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC3, testConvert))); //CHECK_EQUAL(VoxelGridIndex3D(0),testConvert); //if value is in a negative grid position it will be converted //to a very large unrelated number. CHECK(!(geoInfo.isInside(testConvert))); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC4, testConvert))); CHECK_EQUAL(expectedVoxelDims, testConvert); CHECK(!(geoInfo.isInside(testConvert))); //use a more complicated orientation matrix OrientationMatrix newOrientation(0); newOrientation(0, 0) = 0.5; newOrientation(1, 2) = -3; newOrientation(2, 1) = 1; CHECK_NO_THROW(geoInfo.setOrientationMatrix(newOrientation)); testIPP = WorldCoordinate3D(20, 100, -1000); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); CHECK_NO_THROW(geoInfo.setSpacing(SpacingVectorType3D(1))); //values for testing were generated with a dedicated MeVisLab routine insideTestWC1 = geoInfo.getImagePositionPatient(); //origin (inside) const VoxelGridIndex3D expectedIndexWC1(0, 0, 0); insideTestWC2 = WorldCoordinate3D(22.5, 97, -998); //inside const VoxelGridIndex3D expectedIndexWC2(5, 2, 1); insideTestWC3 = WorldCoordinate3D(26, 88, -996); //outside const VoxelGridIndex3D expectedIndexWC3(12, 4, 4); insideTestWC4 = WorldCoordinate3D(25, 91, -995); // outside: Grid dimension = [10,5,3] const VoxelGridIndex3D expectedIndexWC4(10, 5, 3); CHECK(geoInfo.isInside(insideTestWC1)); CHECK_EQUAL(geoInfo.isInside(insideTestWC1), geoInfo.isInside(expectedIndexWC1)); CHECK(geoInfo.isInside(insideTestWC2)); CHECK_EQUAL(geoInfo.isInside(insideTestWC2), geoInfo.isInside(expectedIndexWC2)); CHECK(!(geoInfo.isInside(insideTestWC3))); CHECK_EQUAL(geoInfo.isInside(insideTestWC3), geoInfo.isInside(expectedIndexWC3)); CHECK(!(geoInfo.isInside(insideTestWC4))); CHECK_EQUAL(geoInfo.isInside(insideTestWC4), geoInfo.isInside(expectedIndexWC4)); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC1, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndexWC1, testConvert); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC2, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndexWC2, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC3, testConvert))); CHECK(!(geoInfo.isInside(testConvert))); CHECK_EQUAL(expectedIndexWC3, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC4, testConvert))); CHECK(!(geoInfo.isInside(testConvert))); CHECK_EQUAL(expectedIndexWC4, testConvert); //11) test isInside and index to world coordinate conversion //use unit matrix as orientation matrix CHECK_NO_THROW(geoInfo.setOrientationMatrix(OrientationMatrix())); VoxelGridIndex3D insideTest1(0, 0, 0); //origin (inside) VoxelGridIndex3D insideTest2(2, 3, 1); //inside VoxelGridIndex3D insideTest3(0, 6, 14); //outside VoxelGridIndex3D insideTest4 = expectedVoxelDims; // outside CHECK(geoInfo.isInside(insideTest1)); CHECK(geoInfo.isInside(insideTest2)); CHECK(!(geoInfo.isInside(insideTest3))); CHECK(!(geoInfo.isInside(insideTest4))); WorldCoordinate3D testInside(0); CHECK(geoInfo.indexToWorldCoordinate(insideTest1, testInside)); CHECK(geoInfo.isInside(testInside)); //CHECK_EQUAL(geoInfo.getImagePositionPatient(),testInside); //half voxel shift prevents equality! CHECK(geoInfo.indexToWorldCoordinate(insideTest2, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest3, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest4, testInside))); CHECK(!(geoInfo.isInside(testInside))); WorldCoordinate3D testWorldCoordinate; DoubleVoxelGridIndex3D testDoubleIndex; DoubleVoxelGridIndex3D doubleIndex1 = DoubleVoxelGridIndex3D(0.1, 0, -0.3); const WorldCoordinate3D expectedDoubleIndex1(20.1, 100, -1000.3); DoubleVoxelGridIndex3D doubleIndex2 = DoubleVoxelGridIndex3D(11, 6, 15); //outside const WorldCoordinate3D expectedDoubleIndex2(31, 106, -985); DoubleVoxelGridIndex3D doubleIndex3 = DoubleVoxelGridIndex3D(10.1, 5.0, 3.0); // outside: Grid dimension = [10,5,3] const WorldCoordinate3D expectedDoubleIndex3(30.1, 105, -997); DoubleVoxelGridIndex3D doubleIndex4 = DoubleVoxelGridIndex3D(0.0, 0.0, 0.0); const WorldCoordinate3D expectedDoubleIndex4 = geoInfo.getImagePositionPatient(); //test double index to world coordinate geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex1, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, expectedDoubleIndex1); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex2, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, expectedDoubleIndex2); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex3, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, expectedDoubleIndex3); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex4, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, expectedDoubleIndex4); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex4, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndex4); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex3, testDoubleIndex); CHECK_CLOSE(testDoubleIndex(0), doubleIndex3(0), errorConstant); CHECK_CLOSE(testDoubleIndex(1), doubleIndex3(1), errorConstant); CHECK_CLOSE(testDoubleIndex(2), doubleIndex3(2), errorConstant); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex2, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndex2); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex1, testDoubleIndex); CHECK_CLOSE(testDoubleIndex(0), doubleIndex1(0), errorConstant); CHECK_CLOSE(testDoubleIndex(1), doubleIndex1(1), errorConstant); CHECK_CLOSE(testDoubleIndex(2), doubleIndex1(2), errorConstant); VoxelGridIndex3D testIntIndex; geoInfo.worldCoordinateToIndex(expectedDoubleIndex4, testIntIndex); CHECK_EQUAL(testIntIndex, insideTest1); geoInfo.worldCoordinateToIndex(expectedDoubleIndex1, testIntIndex); CHECK_EQUAL(testIntIndex, insideTest1); geoInfo.worldCoordinateToIndex(expectedDoubleIndex3, testIntIndex); CHECK_EQUAL(testIntIndex, expectedVoxelDims); //use a more complicated orientation matrix newOrientation = OrientationMatrix(0); newOrientation(0, 0) = 0.5; newOrientation(1, 2) = -3; newOrientation(2, 1) = 1; CHECK_NO_THROW(geoInfo.setOrientationMatrix(newOrientation)); testIPP = WorldCoordinate3D(20, 100, -1000); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); CHECK_NO_THROW(geoInfo.setSpacing(SpacingVectorType3D(1))); //values for testing were generated with a dedicated MeVisLab routine //no half voxel shift anymore because we changed indexToWorldCoordinate/worldCoordinateToIndex insideTest1 = VoxelGridIndex3D(0, 0, 0); //origin (inside) const WorldCoordinate3D expectedIndex1(20, 100, -1000); insideTest2 = VoxelGridIndex3D(6, 0, 2); //inside const WorldCoordinate3D expectedIndex2(23, 94, -1000); insideTest3 = VoxelGridIndex3D(11, 6, 15); //outside const WorldCoordinate3D expectedIndex3(25.5, 55, -994); insideTest4 = VoxelGridIndex3D(10, 5, 3); // outside: Grid dimension = [10,5,3] const WorldCoordinate3D expectedIndex4(25, 91, -995); CHECK(geoInfo.isInside(insideTest1)); CHECK_EQUAL(geoInfo.isInside(insideTest1), geoInfo.isInside(expectedIndex1)); CHECK(geoInfo.isInside(insideTest2)); CHECK_EQUAL(geoInfo.isInside(insideTest2), geoInfo.isInside(expectedIndex2)); CHECK(!(geoInfo.isInside(insideTest3))); CHECK_EQUAL(geoInfo.isInside(insideTest3), geoInfo.isInside(expectedIndex3)); CHECK(!(geoInfo.isInside(insideTest4))); CHECK_EQUAL(geoInfo.isInside(insideTest4), geoInfo.isInside(expectedIndex4)); CHECK(geoInfo.indexToWorldCoordinate(insideTest1, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK_EQUAL(expectedIndex1, testInside); CHECK(geoInfo.indexToWorldCoordinate(insideTest2, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK_EQUAL(expectedIndex2, testInside); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest3, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK_EQUAL(expectedIndex3, testInside); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest4, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK_EQUAL(expectedIndex4, testInside); //12) test with simple Geometry: isInside, geometryCoordinateToWorldCoordinate(), worldCoordinateToGeometryCoordinate(), indexToWorldCoordinate() core::GeometricInfo geoInfoSimple; ImageSize rttbSimpleSize = ImageSize(10, 10, 10); geoInfoSimple.setImageSize(rttbSimpleSize); SpacingVectorType3D spacingSimple(1, 1, 1); geoInfoSimple.setSpacing(spacingSimple); OrientationMatrix OMOnes; geoInfoSimple.setOrientationMatrix(OMOnes); const DoubleVoxelGridIndex3D doubleIndexPixelOutside1 = DoubleVoxelGridIndex3D(-0.501, 0.0, 0.0); const DoubleVoxelGridIndex3D doubleIndexPixelOutside2 = DoubleVoxelGridIndex3D(0.0, 9.501, 0.0); const DoubleVoxelGridIndex3D doubleIndexPixelZero1 = DoubleVoxelGridIndex3D(0.0, 0.0, 0.0); const DoubleVoxelGridIndex3D doubleIndexPixelZero2 = DoubleVoxelGridIndex3D(-0.5, -0.5, -0.5); const DoubleVoxelGridIndex3D doubleIndexPixelZero3 = DoubleVoxelGridIndex3D(0.499999, 0.499999, 0.499999); const DoubleVoxelGridIndex3D doubleIndexPixelOne1 = DoubleVoxelGridIndex3D(1.0, 0.0, 0.0); const DoubleVoxelGridIndex3D doubleIndexPixelOne2 = DoubleVoxelGridIndex3D(0.5, 0.499999, 0.499999); const DoubleVoxelGridIndex3D doubleIndexPixelOne3 = DoubleVoxelGridIndex3D(1.49, -0.5, -0.5); const DoubleVoxelGridIndex3D doubleIndexPixelLast1 = DoubleVoxelGridIndex3D(9.0, 9.0, 9.0); const DoubleVoxelGridIndex3D doubleIndexPixelLast2 = DoubleVoxelGridIndex3D(9.4999, 9.4999, 9.4999); const DoubleVoxelGridIndex3D doubleIndexPixelLast3 = DoubleVoxelGridIndex3D(8.501, 8.501, 8.501); const VoxelGridIndex3D indexPixelOutside = VoxelGridIndex3D(11, 0, 0); const VoxelGridIndex3D indexPixelZero = VoxelGridIndex3D(0, 0, 0); const VoxelGridIndex3D indexPixelOne = VoxelGridIndex3D(1, 0, 0); const VoxelGridIndex3D indexPixelLast = VoxelGridIndex3D(9, 9, 9); const WorldCoordinate3D worldCoordinateOutside1(doubleIndexPixelOutside1(0), doubleIndexPixelOutside1(1), doubleIndexPixelOutside1(2)); const WorldCoordinate3D worldCoordinateOutside2(doubleIndexPixelOutside2(0), doubleIndexPixelOutside2(1), doubleIndexPixelOutside2(2)); const WorldCoordinate3D worldCoordinatePixelZero1(doubleIndexPixelZero1(0), doubleIndexPixelZero1(1), doubleIndexPixelZero1(2)); const WorldCoordinate3D worldCoordinatePixelZero2(doubleIndexPixelZero2(0), doubleIndexPixelZero2(1), doubleIndexPixelZero2(2)); const WorldCoordinate3D worldCoordinatePixelZero3(doubleIndexPixelZero3(0), doubleIndexPixelZero3(1), doubleIndexPixelZero3(2)); const WorldCoordinate3D worldCoordinatePixelOne1(doubleIndexPixelOne1(0), doubleIndexPixelOne1(1), doubleIndexPixelOne1(2)); const WorldCoordinate3D worldCoordinatePixelOne2(doubleIndexPixelOne2(0), doubleIndexPixelOne2(1), doubleIndexPixelOne2(2)); const WorldCoordinate3D worldCoordinatePixelOne3(doubleIndexPixelOne3(0), doubleIndexPixelOne3(1), doubleIndexPixelOne3(2)); const WorldCoordinate3D worldCoordinatePixelLast1(doubleIndexPixelLast1(0), doubleIndexPixelLast1(1), doubleIndexPixelLast1(2)); const WorldCoordinate3D worldCoordinatePixelLast2(doubleIndexPixelLast2(0), doubleIndexPixelLast2(1), doubleIndexPixelLast2(2)); const WorldCoordinate3D worldCoordinatePixelLast3(doubleIndexPixelLast3(0), doubleIndexPixelLast3(1), doubleIndexPixelLast3(2)); bool isInside; isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelOutside1, testWorldCoordinate); CHECK(!isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelOutside2, testWorldCoordinate); CHECK(!isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelZero1, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelZero1); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelZero2, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelZero2); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelZero3, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelZero3); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelOne1, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelOne1); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelOne2, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelOne2); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelOne3, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelOne3); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelLast1, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelLast1); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelLast2, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelLast2); CHECK(isInside); isInside = geoInfoSimple.geometryCoordinateToWorldCoordinate(doubleIndexPixelLast3, testWorldCoordinate); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelLast3); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinateOutside1, testDoubleIndex); CHECK(!isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinateOutside2, testDoubleIndex); CHECK(!isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelZero1, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelZero1); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelZero2, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelZero2); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelZero3, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelZero3); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelOne1, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelOne1); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelOne2, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelOne2); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelOne3, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelOne3); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelLast1, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelLast1); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelLast2, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelLast2); CHECK(isInside); isInside = geoInfoSimple.worldCoordinateToGeometryCoordinate(worldCoordinatePixelLast3, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndexPixelLast3); CHECK(isInside); isInside = geoInfoSimple.indexToWorldCoordinate(indexPixelOutside, testWorldCoordinate); CHECK(!isInside); isInside = geoInfoSimple.indexToWorldCoordinate(indexPixelZero, testWorldCoordinate); CHECK(isInside); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelZero1); isInside = geoInfoSimple.indexToWorldCoordinate(indexPixelOne, testWorldCoordinate); CHECK(isInside); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelOne1); isInside = geoInfoSimple.indexToWorldCoordinate(indexPixelLast, testWorldCoordinate); CHECK(isInside); CHECK_EQUAL(testWorldCoordinate, worldCoordinatePixelLast1); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinateOutside1, testIntIndex); CHECK(!isInside); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinateOutside2, testIntIndex); CHECK(!isInside); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelZero1, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelZero); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelZero2, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelZero); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelZero3, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelZero); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelOne1, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelOne); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelOne2, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelOne); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelOne3, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelOne); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelLast1, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelLast); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelLast2, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelLast); isInside = geoInfoSimple.worldCoordinateToIndex(worldCoordinatePixelLast3, testIntIndex); CHECK(isInside); CHECK_EQUAL(testIntIndex, indexPixelLast); //13) test getNumberOfVoxels CHECK_EQUAL(expectedVoxelDims(0)*expectedVoxelDims(1)*expectedVoxelDims(2), geoInfo.getNumberOfVoxels()); //14) Test convert, validID and validIndex geoInfo.setNumColumns(50); geoInfo.setNumRows(30); geoInfo.setNumSlices(40); VoxelGridIndex3D startIndex(0, 0, 0); VoxelGridID startId(0); VoxelGridIndex3D endIndex(geoInfo.getNumColumns() - 1, geoInfo.getNumRows() - 1, geoInfo.getNumSlices() - 1); VoxelGridID endId((geoInfo.getNumColumns()*geoInfo.getNumRows()*geoInfo.getNumSlices()) - 1); VoxelGridIndex3D indexInvalid(geoInfo.getNumColumns(), geoInfo.getNumRows(), geoInfo.getNumSlices()); VoxelGridID idInvalid(geoInfo.getNumColumns()*geoInfo.getNumRows()*geoInfo.getNumSlices()); CHECK(geoInfo.validID(startId)); CHECK(geoInfo.validIndex(startIndex)); VoxelGridIndex3D aIndex; VoxelGridID aId; CHECK(geoInfo.convert(startIndex, aId)); CHECK(geoInfo.convert(startId, aIndex)); CHECK_EQUAL(aId, startId); CHECK_EQUAL(aIndex, startIndex); CHECK(geoInfo.validID(endId)); CHECK(geoInfo.validIndex(endIndex)); CHECK(geoInfo.convert(endIndex, aId)); CHECK(geoInfo.convert(endId, aIndex)); CHECK_EQUAL(aId, endId); CHECK_EQUAL(aIndex, endIndex); CHECK(!geoInfo.validID(idInvalid)); CHECK(!geoInfo.validIndex(indexInvalid)); CHECK(!geoInfo.convert(idInvalid, aIndex)); CHECK(!geoInfo.convert(indexInvalid, aId)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/MaskVoxelTest.cpp b/testing/core/MaskVoxelTest.cpp index f573f29..db593bd 100644 --- a/testing/core/MaskVoxelTest.cpp +++ b/testing/core/MaskVoxelTest.cpp @@ -1,101 +1,95 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*! @brief MaskVoxelTest - test the API of MaskVoxel 1) test constructors (values as expected?) 2) test set/getRelevantVolumeFraction 3) test operators "==" 4) test operator "<" */ int MaskVoxelTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test constructors (values as expected?) //MaskVoxel(const VoxelGridID& aVoxelGridID); VoxelGridID anID = 5; const FractionType defaultFraction = 1; CHECK_NO_THROW(core::MaskVoxel MaskVoxel(anID)); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID), core::InvalidParameterException); core::MaskVoxel aMaskVoxel2(anID); CHECK_EQUAL(anID, aMaskVoxel2.getVoxelGridID()); CHECK_EQUAL(defaultFraction, aMaskVoxel2.getRelevantVolumeFraction()); //MaskVoxel(const VoxelGridID& aVoxelGridID, FractionType aVolumeFraction) anID = 15; FractionType aFraction = 0.73; CHECK_NO_THROW(core::MaskVoxel MaskVoxel(anID, aFraction)); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(anID, -aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, -aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(anID, aFraction + 2), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, aFraction + 2), core::InvalidParameterException); core::MaskVoxel aMaskVoxel3(anID, aFraction); CHECK_EQUAL(anID, aMaskVoxel3.getVoxelGridID()); CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); //2) test set/getRelevantVolumeFraction aFraction = 0.42; anID = aMaskVoxel3.getVoxelGridID(); CHECK_NO_THROW(aMaskVoxel3.setRelevantVolumeFraction(aFraction)); CHECK_THROW_EXPLICIT(aMaskVoxel3.setRelevantVolumeFraction(-aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(aMaskVoxel3.setRelevantVolumeFraction(aFraction + 2), core::InvalidParameterException); aMaskVoxel3.setRelevantVolumeFraction(aFraction); CHECK_EQUAL(anID, aMaskVoxel3.getVoxelGridID()); CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); //3) test operators "==" CHECK(!(aMaskVoxel2 == aMaskVoxel3)); //not equal core::MaskVoxel aMaskVoxel4(aMaskVoxel3.getVoxelGridID()); CHECK(!(aMaskVoxel4 == aMaskVoxel3)); //equal ID, but unequal volume fraction -> not equal aMaskVoxel4.setRelevantVolumeFraction(aMaskVoxel3.getRelevantVolumeFraction()); CHECK_EQUAL(aMaskVoxel4, aMaskVoxel3); //equal aMaskVoxel2.setRelevantVolumeFraction(aMaskVoxel3.getRelevantVolumeFraction()); CHECK(!(aMaskVoxel2 == aMaskVoxel3)); //no equal ID -> not equal //4) test operator "<" core::MaskVoxel aMaskVoxel5(2); CHECK(aMaskVoxel2 < aMaskVoxel3); CHECK(!(aMaskVoxel3 < aMaskVoxel4)); CHECK(!(aMaskVoxel4 < aMaskVoxel5)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/StrVectorStructureSetGeneratorTest.cpp b/testing/core/StrVectorStructureSetGeneratorTest.cpp index 0eb0622..1b9c23b 100644 --- a/testing/core/StrVectorStructureSetGeneratorTest.cpp +++ b/testing/core/StrVectorStructureSetGeneratorTest.cpp @@ -1,95 +1,89 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" #include "DummyStructure.h" #include "DummyDoseAccessor.h" #include "rttbInvalidParameterException.h" #include "rttbStructure.h" namespace rttb { namespace testing { /*! @brief StrVectorStructureSetGeneratorTest - tests the API for Structure 1) empty structure vector 2) dummy structure 3) with regex */ int StrVectorStructureSetGeneratorTest(int argc, char* argv[]) { typedef core::Structure::Pointer StructTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //1) empty structure vector std::vector strVector; CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator1(strVector)); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); CHECK_EQUAL(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getNumberOfStructures(), 0); CHECK_THROW_EXPLICIT(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getStructure(0), core::InvalidParameterException); //2) dummy structure boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer rectStrPtr = boost::make_shared(rect); rectStrPtr->setLabel("test"); strVector.push_back(rectStrPtr); CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator2(strVector)); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); CHECK_EQUAL(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getNumberOfStructures(), 1); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()->getStructure( 0)); //3) with regex StructTypePointer rectStrPtr2 = boost::make_shared(rect); rectStrPtr2->setLabel("none"); strVector.push_back(rectStrPtr2); core::StrVectorStructureSetGenerator generator(strVector); generator.setStructureLabelFilterActive(true); generator.setFilterRegEx("test"); CHECK_NO_THROW(generator.generateStructureSet()); CHECK_EQUAL(generator.generateStructureSet()->getNumberOfStructures(), 1); CHECK_EQUAL(generator.generateStructureSet()->getStructure(0)->getLabel(), "test"); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/core/StructureSetTest.cpp b/testing/core/StructureSetTest.cpp index add189c..0a3932f 100644 --- a/testing/core/StructureSetTest.cpp +++ b/testing/core/StructureSetTest.cpp @@ -1,82 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "litCheckMacros.h" #include "DummyStructure.h" #include "DummyDoseAccessor.h" #include "rttbInvalidParameterException.h" #include "rttbStructure.h" #include "rttbStructureSet.h" namespace rttb { namespace testing { /*! @brief StructureSet - tests the API for StructureSet 1) constructor 2) getters */ int StructureSetTest(int argc, char* argv[]) { typedef core::Structure::Pointer StructTypePointer; PREPARE_DEFAULT_TEST_REPORTING; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer rectStrPtr = boost::make_shared(rect); rectStrPtr->setLabel("test"); StructTypePointer rectStrPtr2 = boost::make_shared(rect); rectStrPtr2->setLabel("test2"); const IDType patientUID("patientUID"); const IDType UID("UID"); //1) constructor CHECK_NO_THROW(core::StructureSet({ })); core::StructureSet structureSetDefault({ }); CHECK_NO_THROW(core::StructureSet({ rectStrPtr, rectStrPtr2 }, patientUID, UID)); core::StructureSet structureSet({rectStrPtr, rectStrPtr2}, patientUID, UID); //2) getters CHECK_EQUAL(structureSetDefault.getNumberOfStructures(), 0); CHECK_EQUAL(structureSet.getNumberOfStructures(), 2); CHECK_EQUAL(structureSet.getStructure(0)->getLabel(), "test"); CHECK_EQUAL(structureSet.getStructure(1)->getLabel(), "test2"); CHECK_THROW_EXPLICIT(structureSet.getStructure(2), core::InvalidParameterException); CHECK_EQUAL(structureSet.getUID(), UID); CHECK_EQUAL(structureSet.getPatientUID(), patientUID); CHECK_NO_THROW(structureSetDefault.getUID()); CHECK_NO_THROW(structureSetDefault.getPatientUID()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/core/StructureTest.cpp b/testing/core/StructureTest.cpp index c55fb5f..59827e1 100644 --- a/testing/core/StructureTest.cpp +++ b/testing/core/StructureTest.cpp @@ -1,138 +1,132 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbInvalidParameterException.h" #include "DummyStructure.h" #include "DummyDoseAccessor.h" namespace rttb { namespace testing { /*! @brief StructureTest - tests the API for Structure 1) constructors 2) get/setXX */ int StructureTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); //1) constructors CHECK_NO_THROW(core::Structure()); core::Structure emptyTestStruct; CHECK_EQUAL("", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.getUID()); GridIndexType zPlane = 4; core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); CHECK_NO_THROW(core::Structure(rect.getStructureVector())); core::Structure rect2 = core::Structure(rect.getStructureVector()); CHECK_EQUAL(rect.getLabel(), rect2.getLabel()); CHECK(rect.getUID() != rect2.getUID()); PolygonSequenceType rectVec = rect.getStructureVector(); PolygonSequenceType rect2Vec = rect2.getStructureVector(); CHECK_EQUAL(rectVec.size(), rect2Vec.size()); PolygonSequenceType::iterator it = rectVec.begin(); PolygonSequenceType::iterator it2 = rect2Vec.begin(); for (; it != rectVec.end(); ++it) { CHECK_EQUAL(it->size(), it2->size()); PolygonType::iterator pit = it->begin(); PolygonType::iterator pit2 = it2->begin(); for (; pit != it->end(); ++pit) { CHECK_EQUAL(*(pit), *(pit2)); ++pit2; } ++it2; } CHECK_NO_THROW(core::Structure rect3 = rect); core::Structure rect3 = rect; CHECK_EQUAL(rect.getLabel(), rect3.getLabel()); CHECK_EQUAL(rect.getUID(), rect3.getUID()); PolygonSequenceType rect3Vec = rect3.getStructureVector(); CHECK_EQUAL(rectVec.size(), rect3Vec.size()); it = rectVec.begin(); PolygonSequenceType::iterator it3 = rect3Vec.begin(); for (; it != rectVec.end(); ++it) { CHECK_EQUAL(it->size(), it3->size()); PolygonType::iterator pit = it->begin(); PolygonType::iterator pit3 = it3->begin(); for (; pit != it->end(); ++pit) { CHECK_EQUAL(*(pit), *(pit3)); ++pit3; } ++it3; } //2) get/setXX CHECK_EQUAL("", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.setLabel("NEW Label")); CHECK_EQUAL("NEW Label", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.getUID()); CHECK_NO_THROW(emptyTestStruct.setUID("1.2.345.67.8.9")); CHECK_EQUAL("1.2.345.67.8.9", emptyTestStruct.getUID()); CHECK((emptyTestStruct.getStructureVector()).empty()); CHECK_EQUAL(0, emptyTestStruct.getNumberOfEndpoints()); CHECK_EQUAL(4, rect.getNumberOfEndpoints()); CHECK_EQUAL(rect.getNumberOfEndpoints(), rect2.getNumberOfEndpoints()); core::Structure circ = myStructGenerator.CreateTestStructureCircle(zPlane); CHECK_EQUAL(4004, circ.getNumberOfEndpoints()); core::Structure multiPoly = myStructGenerator.CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(zPlane, zPlane + 1); CHECK_EQUAL(8, multiPoly.getNumberOfEndpoints()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/core/rttbCoreTests.cpp b/testing/core/rttbCoreTests.cpp index fb9dd3b..04df057 100644 --- a/testing/core/rttbCoreTests.cpp +++ b/testing/core/rttbCoreTests.cpp @@ -1,73 +1,67 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(GeometricInfoTest); LIT_REGISTER_TEST(MaskVoxelTest); LIT_REGISTER_TEST(GenericDoseIteratorTest); LIT_REGISTER_TEST(GenericMaskedDoseIteratorTest); LIT_REGISTER_TEST(DVHCalculatorTest); LIT_REGISTER_TEST(DVHTest); LIT_REGISTER_TEST(DVHSetTest); LIT_REGISTER_TEST(GeometricInfoTest); LIT_REGISTER_TEST(MaskVoxelTest); LIT_REGISTER_TEST(GenericDoseIteratorTest); LIT_REGISTER_TEST(StructureTest); LIT_REGISTER_TEST(StrVectorStructureSetGeneratorTest); LIT_REGISTER_TEST(StructureSetTest); LIT_REGISTER_TEST(BaseTypeTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/examples/RTBioModelExampleTest.cpp b/testing/examples/RTBioModelExampleTest.cpp index fab0183..9a99dc7 100644 --- a/testing/examples/RTBioModelExampleTest.cpp +++ b/testing/examples/RTBioModelExampleTest.cpp @@ -1,415 +1,409 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" #include "rttbDoseIteratorInterface.h" #include "rttbDVHXMLFileReader.h" namespace rttb { namespace testing { /*! @brief RTBioModelTest. TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTBioModelExampleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef rttb::models::CurveDataType CurveDataType; typedef std::multimap > ScatterPlotType; typedef core::DVH::Pointer DVHPointer; //increased accuracy requires double values in the calculation (rttbBaseType.h) double toleranceEUD = 1e-5; double tolerance = 1e-7; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name //...........5: Virtuos MPM_LR_ah dvh lung file name //...........6: Virtuos MPM_LR_ah dvh target file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; std::string DVH_FILENAME_TV_TEST; std::string DVH_Virtuos_Target; std::string DVH_Virtuos_Lung; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } if (argc > 5) { DVH_FILENAME_TV_TEST = argv[5]; } if (argc > 6) { DVH_Virtuos_Lung = argv[6]; } if (argc > 7) { DVH_Virtuos_Target = argv[7]; } //DVH PTV rttb::io::other::DVHXMLFileReader dvhReader = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_PTV); DVHPointer dvhPtr = dvhReader.generateDVH(); CHECK_CLOSE(6.04759613161786830000e+001, models::getEUD(dvhPtr, 10), toleranceEUD); rttb::io::other::DVHXMLFileReader dvhReader_test_tv = rttb::io::other::DVHXMLFileReader( DVH_FILENAME_TV_TEST); DVHPointer dvh_test_tv = dvhReader_test_tv.generateDVH(); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 2; DoseTypeGy normalizationDose = 68; rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_NO_THROW(tcplq.init()); if (tcplq.init()) { CHECK_CLOSE(1.00497232941856940000e-127, tcplq.getValue(), tolerance); } CurveDataType curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CurveDataType::iterator it; for (it = curve.begin(); it != curve.end(); ++it) { if ((*it).first < 72) { CHECK_EQUAL(0, (*it).second); } else if ((*it).first > 150) { CHECK((*it).second > 0.9); } } models::BioModelParamType alphaBeta = 10; tcplq.setParameters(alpha, alphaBeta, roh, 0.08); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_CLOSE(1.84e-005, tcplq.getValue(), tolerance); } normalizationDose = 40; curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); alpha = 1; alphaBeta = 14.5; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_CLOSE(0.954885, tcplq.getValue(), toleranceEUD); } alpha = 0.9; alphaBeta = 1; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_EQUAL(1, tcplq.getValue()); } //TCP LQ Test alpha = 0.3; beta = 0.03; roh = 10000000; numFractions = 20; rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, numFractions); CHECK_EQUAL(alpha, tcplq_test.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq_test.getAlphaBeta()); CHECK_EQUAL(roh, tcplq_test.getRho()); CHECK_NO_THROW(tcplq_test.init()); if (tcplq_test.init()) { CHECK_CLOSE(9.79050278878883180000e-001, tcplq_test.getValue(), tolerance); } normalizationDose = 60; curve = models::getCurveDoseVSBioModel(tcplq_test, normalizationDose); //DVH HT 1 rttb::io::other::DVHXMLFileReader dvhReader2 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT1); DVHPointer dvhPtr2 = dvhReader2.generateDVH(); CHECK_CLOSE(1.07920836034015810000e+001, models::getEUD(dvhPtr2, 10), toleranceEUD); //test RTNTCPLKBModel rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 55; CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr2); CHECK_EQUAL(dvhPtr2, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(lkb.init()); if (lkb.init()) { CHECK_CLOSE(2.53523522831366570000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr2); CHECK_EQUAL(dvhPtr2, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); CHECK_NO_THROW(rs.init()); if (rs.init()) { CHECK_CLOSE(3.70385888626145740000e-009, rs.getValue(), tolerance); } //DVH HT 2 rttb::io::other::DVHXMLFileReader dvhReader3 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT2); DVHPointer dvhPtr3 = dvhReader3.generateDVH(); CHECK_CLOSE(1.26287047025885110000e+001, models::getEUD(dvhPtr3, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr3); CHECK_EQUAL(dvhPtr3, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); if (lkb.init()) { CHECK_CLOSE(7.36294657754956700000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr3); CHECK_EQUAL(dvhPtr3, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); if (rs.init()) { CHECK_CLOSE(1.76778795490939440000e-007, rs.getValue(), tolerance); } //DVH HT 3 rttb::io::other::DVHXMLFileReader dvhReader4 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT3); DVHPointer dvhPtr4 = dvhReader4.generateDVH(); CHECK_CLOSE(2.18212982041056310000e+001, models::getEUD(dvhPtr4, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr4); CHECK_EQUAL(dvhPtr4, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); if (lkb.init()) { CHECK_CLOSE(8.15234192641929420000e-005, lkb.getValue(), tolerance); } //test RTNTCPRSModel rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr4); CHECK_EQUAL(dvhPtr4, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); if (rs.init()) { CHECK_CLOSE(2.02607985020919480000e-004, rs.getValue(), tolerance); } //test using Virtuos Pleuramesotheliom MPM_LR_ah //DVH PTV rttb::io::other::DVHXMLFileReader dR_Target = rttb::io::other::DVHXMLFileReader(DVH_Virtuos_Target); DVHPointer dvhPtrTarget = dR_Target.generateDVH(); rttb::io::other::DVHXMLFileReader dR_Lung = rttb::io::other::DVHXMLFileReader(DVH_Virtuos_Lung); DVHPointer dvhPtrLung = dR_Lung.generateDVH(); //test TCP LQ Model models::BioModelParamType alphaMean = 0.34; models::BioModelParamType alphaVarianz = 0.02; models::BioModelParamType alpha_beta = 28; models::BioModelParamType rho = 1200; int numFractionsVirtuos = 27; rttb::models::TCPLQModel tcplqVirtuos = rttb::models::TCPLQModel(dvhPtrTarget, rho, numFractionsVirtuos, alpha_beta, alphaMean, alphaVarianz); if (tcplqVirtuos.init()) { CHECK_CLOSE(0.8894, tcplqVirtuos.getValue(), 1e-4); } models::BioModelParamType d50Mean = 20; models::BioModelParamType m = 0.36; models::BioModelParamType a = 1.06; rttb::models::NTCPLKBModel lkbVirtuos = rttb::models::NTCPLKBModel(dvhPtrLung, d50Mean, m, a); if (lkbVirtuos.init()) { CHECK_CLOSE(0.0397, lkbVirtuos.getValue(), 1e-4); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/RTBioModelScatterPlotExampleTest.cpp b/testing/examples/RTBioModelScatterPlotExampleTest.cpp index b4d5664..9dd4896 100644 --- a/testing/examples/RTBioModelScatterPlotExampleTest.cpp +++ b/testing/examples/RTBioModelScatterPlotExampleTest.cpp @@ -1,479 +1,473 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" #include "../models/rttbScatterTester.h" #include "rttbInvalidParameterException.h" #include "rttbDVHXMLFileReader.h" namespace rttb { namespace testing { /*! @brief RTBioModelScatterPlotExampleTest. calculating Curves and Scatterplots for TCP and NTCP models. The values on curve and scatterplot need to be similar for similar dose values. The range of difference is given by the variance used to generate the scatter. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTBioModelScatterPlotExampleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef rttb::models::CurveDataType CurveDataType; typedef rttb::models::ScatterPlotType ScatterPlotType; typedef core::DVH::Pointer DVHPointer; //increased accuracy requires double values in the calculation (rttbBaseType.h) double toleranceEUD = 1e-5; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: TV dvh file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_TV_TEST; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_TV_TEST = argv[3]; } //DVH PTV rttb::io::other::DVHXMLFileReader dvhReader = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_PTV); DVHPointer dvhPtr = dvhReader.generateDVH(); rttb::io::other::DVHXMLFileReader dvhReader_test_tv = rttb::io::other::DVHXMLFileReader( DVH_FILENAME_TV_TEST); DVHPointer dvh_test_tv = dvhReader_test_tv.generateDVH(); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 2; DoseTypeGy normalizationDose = 68; rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_NO_THROW(tcplq.init()); CurveDataType curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100)); ScatterPlotType tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100); CHECK_EQUAL(100, tcpScatter.size()); ScatterTester scatterCompare(curve, tcpScatter); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 3, roh, 0, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); std::vector paramIdVec; models::BioModel::ParamVectorType meanVec; models::BioModel::ParamVectorType meanVecTest; meanVecTest.push_back(alpha); models::BioModel::ParamVectorType varianceVec; //"alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 paramIdVec.push_back(0); meanVec.push_back(tcplq.getAlphaMean()); varianceVec.push_back(0); //setting parameter 1 will change the resulting scatter plot dramatically - is it meant to? //this is unexpected since the value was taken from the original calculation //paramIdVec.push_back(1); meanVec.push_back(tcplq.getAlphaVariance()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(tcplq.getAlphaBeta()); varianceVec.push_back(0); paramIdVec.push_back(3); meanVec.push_back(tcplq.getRho()); varianceVec.push_back(0); CHECK_THROW_EXPLICIT(models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVecTest, varianceVec, normalizationDose, 50), core::InvalidParameterException); ScatterPlotType scatterVary = models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVec, varianceVec, normalizationDose, 50); CHECK_EQUAL(50, scatterVary.size()); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); models::BioModelParamType variance = 0.00015; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100); scatterCompare.setVariance(variance); scatterCompare.setCompareScatter(tcpScatter); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 3, roh, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq.getAlphaMean()); varianceVec.push_back(variance); //paramIdVec.push_back(1); meanVec.push_back(tcplq.getAlphaVariance()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(tcplq.getAlphaBeta()); varianceVec.push_back(variance); paramIdVec.push_back(3); meanVec.push_back(tcplq.getRho()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); models::BioModelParamType alphaBeta = 10; tcplq.setParameters(alpha, alphaBeta, roh, 0.08); tcplq.init(); normalizationDose = 40; curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); //do not allow larger deviations scatterCompare.setAllowExceptions(false); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); variance = 0.25; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setVariance(variance); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); /*TCP LQ Test*/ alpha = 0.3; beta = 0.03; roh = 10000000; numFractions = 20; rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, numFractions); CHECK_NO_THROW(tcplq_test.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(tcplq_test, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, 0, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 3, roh, 0, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq_test.getAlphaMean()); varianceVec.push_back(0); //paramIdVec.push_back(1); meanVec.push_back(tcplq_test.getAlphaVariance()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(tcplq_test.getAlphaBeta()); varianceVec.push_back(0); paramIdVec.push_back(3); meanVec.push_back(tcplq_test.getRho()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(tcplq_test, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.00025; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 3, roh, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); scatterCompare.setAllowExceptions(false); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq_test.getAlphaMean()); varianceVec.push_back(variance); //paramIdVec.push_back(1); meanVec.push_back(tcplq_test.getAlphaVariance()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(tcplq_test.getAlphaBeta()); varianceVec.push_back(variance); paramIdVec.push_back(3); meanVec.push_back(tcplq_test.getRho()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(tcplq_test, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); //DVH HT 1 rttb::io::other::DVHXMLFileReader dvhReader2 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT1); DVHPointer dvhPtr2 = dvhReader2.generateDVH(); CHECK_CLOSE(1.07920836034015810000e+001, models::getEUD(dvhPtr2, 10), toleranceEUD); //test RTNTCPLKBModel rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 55; lkb.setDVH(dvhPtr2); lkb.setA(aVal); lkb.setM(mVal); lkb.setD50(d50Val); CHECK_NO_THROW(lkb.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(lkb, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(lkb, 2, aVal, 0, normalizationDose, 100)); ScatterPlotType scatter = models::getScatterPlotVary1Parameter(lkb, 2, aVal, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); //"d50":0,"m":1,"a":2 //test also with other parameter scatter = models::getScatterPlotVary1Parameter(lkb, 0, d50Val, 0, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(lkb.getD50()); varianceVec.push_back(0); paramIdVec.push_back(1); meanVec.push_back(lkb.getM()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(lkb.getA()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(lkb, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.00025; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(lkb, 2, aVal, variance, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(lkb, 2, aVal, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter scatter = models::getScatterPlotVary1Parameter(lkb, 0, d50Val, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(lkb.getD50()); varianceVec.push_back(variance); paramIdVec.push_back(1); meanVec.push_back(lkb.getM()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(lkb.getA()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(lkb, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); //test RTNTCPRSModel rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; rs.setDVH(dvhPtr2); rs.setD50(d50Val); rs.setGamma(gammaVal); rs.setS(sVal); CHECK_NO_THROW(rs.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(rs, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(rs, 0, d50Val, 0, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(rs, 0, d50Val, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); //"d50":0,"gamma":1,"s":2 //test also with other parameter scatter = models::getScatterPlotVary1Parameter(rs, 1, gammaVal, 0, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(rs.getD50()); varianceVec.push_back(0); paramIdVec.push_back(1); meanVec.push_back(rs.getGamma()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(rs.getS()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(rs, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.0075; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(rs, 0, d50Val, variance, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(rs, 0, d50Val, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter scatter = models::getScatterPlotVary1Parameter(rs, 2, sVal, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(rs.getD50()); varianceVec.push_back(variance); paramIdVec.push_back(1); meanVec.push_back(rs.getGamma()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(rs.getS()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(rs, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/RTDVHTest.cpp b/testing/examples/RTDVHTest.cpp index d040b8e..8b7e18d 100644 --- a/testing/examples/RTDVHTest.cpp +++ b/testing/examples/RTDVHTest.cpp @@ -1,108 +1,101 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests - #include "litCheckMacros.h" #include "rttbDVH.h" #include "rttbBaseType.h" #include "rttbDvhBasedModels.h" #include "rttbDVHXMLFileReader.h" namespace rttb { namespace testing { /*! @brief RTDVHTest. Max, min, mean, modal, median, Vx, Dx, EUD, BED, LQED2 are tested. Test if calculation in new architecture returns similar results to the original implementation. Comparison of actual DVH values is performed in DVHCalculatorComparisonTest.cpp. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTDVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: dvh file name std::string RTDVH_FILENAME_PTV; if (argc > 1) { RTDVH_FILENAME_PTV = argv[1]; } /*test RT dvh*/ rttb::io::other::DVHXMLFileReader dvhReader = rttb::io::other::DVHXMLFileReader(RTDVH_FILENAME_PTV); const DoseCalcType expectedValue = 0.01305; //dvhReader core::DVH::Pointer dvh = dvhReader.generateDVH(); CHECK_CLOSE(expectedValue, models::getEUD(dvh, 10), errorConstant); std::cout << models::getEUD(dvh, 10) << std::endl; CHECK_NO_THROW(models::calcBEDDVH(dvh, 15, 15)); CHECK_NO_THROW(models::calcLQED2DVH(dvh, 15, 10)); CHECK_NO_THROW(dvh->getDataDifferential()); CHECK_EQUAL(1, dvh->convertAbsoluteToRelative().at(0)); CHECK_NO_THROW(models::calcBEDDVH(dvh, 15, 15, true)); CHECK_NO_THROW(models::calcLQED2DVH(dvh, 15, 10, true)); //test statistics (relative cumulative data) CHECK_CLOSE(expectedValue, dvh->getMaximum(), errorConstant); CHECK_CLOSE(expectedValue, dvh->getMinimum(), errorConstant); CHECK_CLOSE(expectedValue, dvh->getMean(), errorConstant); CHECK_CLOSE(expectedValue, dvh->getMedian(), errorConstant); CHECK_CLOSE(expectedValue, dvh->getModal(), errorConstant); CHECK_EQUAL(0, dvh->getVx(0.014)); CHECK_EQUAL(250, dvh->getVx(0.01)); CHECK_CLOSE(0.0131, dvh->getDx(100), errorConstant + errorConstant * 10); CHECK_CLOSE(0.013, dvh->getDx(249), errorConstant); CHECK_EQUAL(0, dvh->getDx(251)); //test statistics (absolute cumulative data) CHECK_EQUAL(2000, dvh->getDataCumulative().at(0)); CHECK_EQUAL(0, dvh->getVx(0.014)); CHECK_EQUAL(250, dvh->getVx(0.01)); CHECK_CLOSE(0.0131, dvh->getDx(100), errorConstant + errorConstant * 10); CHECK_CLOSE(0.013, dvh->getDx(249), errorConstant); CHECK_EQUAL(0, dvh->getDx(251)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/RTDoseIndexTest.cpp b/testing/examples/RTDoseIndexTest.cpp index 4680166..35899fc 100644 --- a/testing/examples/RTDoseIndexTest.cpp +++ b/testing/examples/RTDoseIndexTest.cpp @@ -1,209 +1,202 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "litCheckMacros.h" #include "rttbDoseIndex.h" #include "rttbDVHSet.h" #include "rttbBaseType.h" #include "rttbNullPointerException.h" #include "rttbConformalIndex.h" #include "rttbConformationNumber.h" #include "rttbConformityIndex.h" #include "rttbCoverageIndex.h" #include "rttbHomogeneityIndex.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" #include "rttbDVHXMLFileReader.h" #include #include #include - namespace rttb { namespace testing { /*! @brief DoseIndexTest. ConformationNumber ConformalIndex ConformityIndex CoverageIndex HomogeneityIndex are tested. test dvh: deltaV 0.125, deltaD 0.5 1. dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133 2. dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40 3. dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50 4. dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70 Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTDoseIndexTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } /*test dvh: deltaV 0.125, deltaD 0.5*/ /*dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133*/ rttb::io::other::DVHXMLFileReader dvhReader = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_PTV); rttb::core::DVH dvhPTV = *(dvhReader.generateDVH()); /*dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40*/ rttb::io::other::DVHXMLFileReader dvhReader1 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT1); core::DVH dvhNT1 = *(dvhReader1.generateDVH()); /*dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50*/ rttb::io::other::DVHXMLFileReader dvhReader2 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT2); core::DVH dvhNT2 = *(dvhReader2.generateDVH()); /*dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70*/ rttb::io::other::DVHXMLFileReader dvhReader3 = rttb::io::other::DVHXMLFileReader(DVH_FILENAME_NT3); core::DVH dvhNT3 = *(dvhReader3.generateDVH()); std::vector dvhTVSet; std::vector dvhHTSet; dvhTVSet.push_back(dvhPTV); dvhHTSet.push_back(dvhNT1); dvhHTSet.push_back(dvhNT2); dvhHTSet.push_back(dvhNT3); ::boost::shared_ptr dvhSetPtr = ::boost::make_shared(dvhTVSet, dvhHTSet, "testStrSet", dvhPTV.getDoseID()); /*test exception*/ ::boost::shared_ptr dvhSetNullPtr; CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::CoverageIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); /*test exception for invalid reference dose*/ CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetPtr, 0), core::InvalidParameterException); /*test index calculation*/ /*RTConformationNumber */ //PTV covered by reference dose 30 = the whole PTV =362.5; Volume of the referece 30=362.5+1.25 indices::ConformationNumber cn = indices::ConformationNumber(dvhSetPtr, 30); //check if values are close. Equality is only achieved with double precission. CHECK_CLOSE(362.5 / 363.75, cn.getValue(), errorConstant); //cn==1*TV0/V0=362.5/2466.25 cn.setDoseReference(0); CHECK_CLOSE(362.5 / 2466.25, cn.getValue(), errorConstant); cn.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, cn.getValue(), errorConstant); //ref dose: 65 -> TVref=Vref -> cn=TVref/TV=2300/2900 CHECK_EQUAL(cn.getValue(), cn.getValueAt(0)); CHECK_THROW_EXPLICIT(cn.getValueAt(1), core::InvalidParameterException); /*ConformalIndex */ //HT 1 covered by ref=HT2 covered by ref=0, HT3 covered by ref=1.25 indices::ConformalIndex coin = indices::ConformalIndex(dvhSetPtr, 30); CHECK_CLOSE((362.5 / 363.75) * (1 - 1.25 / 151.25), coin.getValue(), errorConstant); coin.setDoseReference(0); CHECK_EQUAL(0, coin.getValue()); coin.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coin.getValue(), errorConstant); //ref dose: 65 -> Vref=0 for all HT -> cn=cn*(1-0)=cn CHECK_EQUAL(coin.getValue(), coin.getValueAt(0)); CHECK_THROW_EXPLICIT(coin.getValueAt(1), core::InvalidParameterException); /*ConformityIndex */ indices::ConformityIndex ci = indices::ConformityIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 363.75, ci.getValue(), errorConstant); ci.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, ci.getValue(), errorConstant); //ref dose: 65->ci=2300/2900*1*1*1 CHECK_EQUAL(ci.getValue(), ci.getValueAt(0)); CHECK_THROW_EXPLICIT(ci.getValueAt(1), core::InvalidParameterException); /*CoverageIndex*/ indices::CoverageIndex coverageI = indices::CoverageIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 362.5, coverageI.getValue(), errorConstant); //ref dose: 30 -> coverage index=1 coverageI.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coverageI.getValue(), errorConstant); //ref dose: 65->coverage index=2300/2900 CHECK_EQUAL(coverageI.getValue(), coverageI.getValueAt(0)); CHECK_THROW_EXPLICIT(coverageI.getValueAt(1), core::InvalidParameterException); /*HomogeneityIndex TV max: 133*0.5=66.5, TV min: 127*0.5=63.5 -> hi=(66.5-63.5)/30*/ indices::HomogeneityIndex hi = indices::HomogeneityIndex(dvhSetPtr, 30); CHECK_CLOSE(3 / 30.0, hi.getValue(), errorConstant); hi.setDoseReference(65); CHECK_CLOSE(3 / 65.0, hi.getValue(), errorConstant); CHECK_EQUAL(hi.getValue(), hi.getValueAt(0)); CHECK_THROW_EXPLICIT(hi.getValueAt(1), core::InvalidParameterException); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTDoseStatisticsDicomTest.cpp b/testing/examples/RTDoseStatisticsDicomTest.cpp index c9bf63e..d7b58c6 100644 --- a/testing/examples/RTDoseStatisticsDicomTest.cpp +++ b/testing/examples/RTDoseStatisticsDicomTest.cpp @@ -1,118 +1,112 @@ // ----------------------------------------------------------------------- // 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: 1328 $ (last changed revision) -// @date $Date: 2016-04-22 09:50:01 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @brief RTDoseStatisticsTest. Max, min, mean, standard deviation, variance, Vx, Dx, MOHx, MOCx, MaxOHx, MinOCx are tested. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed!*/ int RTDoseStatisticsDicomTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } else { std::cout << "at least one arguments required for RTDoseStatisticsDicomTest" << std::endl; return -1; } double expectedVal = 5.64477e-005; double volume = 24120.; typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef algorithms::DoseStatisticsCalculator::ResultListPointer ResultListPointer; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create corresponding DoseIterator ::boost::shared_ptr spDoseIteratorTmp = ::boost::make_shared(doseAccessor1); DoseIteratorPointer spDoseIterator(spDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(spDoseIterator); std::vector precomputedDoseValues; precomputedDoseValues.push_back(0); precomputedDoseValues.push_back(0.5); precomputedDoseValues.push_back(1); std::vector precomputedVolumeValues; precomputedVolumeValues.push_back(20000 / volume); precomputedVolumeValues.push_back(1); auto doseStatistics = doseStatisticsCalculator.calculateDoseStatistics(precomputedDoseValues, precomputedVolumeValues); CHECK_CLOSE(doseStatistics->getMean(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getStdDeviation(), 0, errorConstant); CHECK_CLOSE(doseStatistics->getVariance(), 0, errorConstant); double dummy; DoseTypeGy vx = doseStatistics->getVx().getValue(expectedVal, true, dummy); CHECK_EQUAL(vx, doseStatistics->getVx().getValue(0)); CHECK_CLOSE(expectedVal, doseStatistics->getDx().getValue(vx), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMaximum(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getMinimum(), expectedVal, errorConstant); ResultListPointer minListPtr = doseStatistics->getMinimumVoxelPositions(); ResultListPointer maxListPtr = doseStatistics->getMaximumVoxelPositions(); CHECK_EQUAL(maxListPtr->size(), 10); CHECK_EQUAL(minListPtr->size(), 10); CHECK_CLOSE(doseStatistics->getDx().getValue(24120), doseStatistics->getMinimum(), 0.001); CHECK_CLOSE(doseStatistics->getMOHx().getValue(24120), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMOCx().getValue(20000), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMinOCx().getValue(20000), doseStatistics->getMean(), reducedErrorConstant); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/rttbTestExamples.cpp b/testing/examples/rttbTestExamples.cpp index ebaf066..5fb25de 100644 --- a/testing/examples/rttbTestExamples.cpp +++ b/testing/examples/rttbTestExamples.cpp @@ -1,68 +1,61 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(RTBioModelExampleTest); LIT_REGISTER_TEST(RTDVHTest); LIT_REGISTER_TEST(RTDoseIndexTest); LIT_REGISTER_TEST(RTDoseStatisticsDicomTest); LIT_REGISTER_TEST(RTBioModelScatterPlotExampleTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/interpolation/DummyTransformation.cpp b/testing/interpolation/DummyTransformation.cpp index 1951b0e..4c6b4b7 100644 --- a/testing/interpolation/DummyTransformation.cpp +++ b/testing/interpolation/DummyTransformation.cpp @@ -1,42 +1,36 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "DummyTransformation.h" namespace rttb { namespace testing { bool DummyTransformation::transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const { worldCoordinateMoving = worldCoordinateTarget; return true; } bool DummyTransformation::transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const { worldCoordinateTarget = worldCoordinateMoving; return true; } } } diff --git a/testing/interpolation/DummyTransformation.h b/testing/interpolation/DummyTransformation.h index 546a140..34f89ab 100644 --- a/testing/interpolation/DummyTransformation.h +++ b/testing/interpolation/DummyTransformation.h @@ -1,54 +1,49 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_TRANSFORMATION_H #define __DUMMY_TRANSFORMATION_H #include "rttbTransformationInterface.h" namespace rttb { namespace testing { /*! @class DummyTransformation @brief implements a dummy transformation (return the points as they were given) */ class DummyTransformation : public interpolation::TransformationInterface { public: /*! @brief Constructor */ DummyTransformation() {}; /*! @brief target equals to moving */ bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const; /*! @brief moving equals to target */ bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const; }; } } #endif \ No newline at end of file diff --git a/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp b/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp index 7cf2995..b4c184f 100644 --- a/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp +++ b/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp @@ -1,178 +1,172 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbTransformationInterface.h" #include "rttbITKTransformation.h" #include "rttbNullPointerException.h" #include "itkTranslationTransform.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::ITKTransformation ITKTransformation; typedef itk::TranslationTransform TranslationTransformType; /*! @brief SimpleMappableDoseAccessorWithITKTest - test the API of SimpleMappableDoseAccessor with ITK transformation 1) Test constructor 2) test getDoseAt() a) with Identity transform b) with translation transform */ int SimpleMappableDoseAccessorWithITKTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorWithITKTest are expected" << std::endl; return -1; } const double doseGridScaling = 2.822386e-005; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); auto interpolationNN = boost::make_shared(); auto interpolationLinear = boost::make_shared(); TranslationTransformType::Pointer transformITKIdentityTemporary = TranslationTransformType::New(); TranslationTransformType::OutputVectorType translationIdentity; translationIdentity[0] = 0.0; translationIdentity[1] = 0.0; translationIdentity[2] = 0.0; transformITKIdentityTemporary->Translate(translationIdentity); auto transformITKIdentity = boost::make_shared(transformITKIdentityTemporary); TranslationTransformType::Pointer transformITKTranslationTemporary = TranslationTransformType::New(); TranslationTransformType::OutputVectorType translation; translation[0] = 5.0; translation[1] = 5.0; translation[2] = 5.0; transformITKTranslationTemporary->Translate(translation); auto transformITKTranslation = boost::make_shared(transformITKTranslationTemporary); auto aSimpleMappableDoseAccessorITKIdentity = boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformITKIdentity, interpolationLinear); auto aSimpleMappableDoseAccessorITKTranslation = boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformITKTranslation, interpolationLinear); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformITKIdentity, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformITKTranslation, interpolationLinear)); CHECK_NO_THROW(ITKTransformation(transformITKTranslationTemporary.GetPointer())); CHECK_THROW_EXPLICIT(ITKTransformation(nullptr), core::NullPointerException); //2) test getDoseAt() // a) with Identity transform //test valid voxels std::vector voxelsAsIndexToTest; std::vector expectedValues; voxelsAsIndexToTest.push_back(VoxelGridIndex3D(5, 9, 8)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(22, 15, 10)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(30, 20, 7)); expectedValues.push_back(5.0 * doseGridScaling); expectedValues.push_back(22.0 * doseGridScaling); expectedValues.push_back(30.0 * doseGridScaling); //convert VoxelGridIndex3D to VoxelGridID for (size_t i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorITKIdentity->getValueAt(voxelsAsIndexToTest.at(i)), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorITKIdentity->getValueAt(voxelsAsIndexToTest.at(i)), aSimpleMappableDoseAccessorITKIdentity->getValueAt(currentId)); } //no tests with invalid IDs, this has been done already tested in SimpleMappableDoseAccessorTest //b) with translation transform //translation of one voxel in each direction expectedValues.clear(); expectedValues.push_back(6.0 * doseGridScaling); expectedValues.push_back(23.0 * doseGridScaling); expectedValues.push_back(31.0 * doseGridScaling); for (size_t i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorITKTranslation->getValueAt(voxelsAsIndexToTest.at(i)), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorITKTranslation->getValueAt(voxelsAsIndexToTest.at(i)), aSimpleMappableDoseAccessorITKTranslation->getValueAt(currentId)); } RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp b/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp index fbd711b..677ce61 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp @@ -1,239 +1,233 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbGeometricInfo.h" #include "rttbTransformationInterface.h" #include "rttbMatchPointTransformation.h" #include "rttbNullPointerException.h" #include "registrationTest.h" #include "simpleRegistrationWorkflow.h" namespace rttb { namespace testing { static const unsigned int TargetDimension3D = 3; static const unsigned int MovingDimension3D = 3; typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef map::core::RegistrationTest Registration3D3DTypeTest; typedef Registration3D3DTypeTest::Pointer Registration3D3DTypeTestPointer; typedef map::core::Registration Registration3D3DType; typedef Registration3D3DType::Pointer Registration3D3DPointer; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::MatchPointTransformation MatchPointTransformation; /*! @brief SimpleMappableDoseAccessorWithMatchPointTest - test the API of SimpleMappableDoseAccessor with MatchPoint transform 1) Test constructor 2) test getDoseAt() a) with Identity transform b) with translation transform [3) test with rigid registration optional (if filenames are given as argument)] */ int SimpleMappableDoseAccessorWithMatchPointTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; std::string RTDOSE_FILENAME_REALISTIC = ""; std::string CT_PLANNING = ""; std::string CT_FRACTION = ""; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorWithMatchPointTest are expected" << std::endl; return -1; } if (argc > 5) { RTDOSE_FILENAME_REALISTIC = argv[3]; CT_PLANNING = argv[4]; CT_FRACTION = argv[5]; } rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); DoseAccessorPointer doseAccessorNull; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); Registration3D3DTypeTestPointer registration = Registration3D3DTypeTest::New(); double translation[] = {0.0, 0.0, 0.0}; registration->_translation = translation; registration->_limitedTarget = false; auto interpolationNN = ::boost::make_shared(); auto interpolationLinear = ::boost::make_shared(); NearestNeighborInterpolation::Pointer interpolationNull; auto transformMP = ::boost::make_shared(registration.GetPointer()); auto aSimpleMappableDoseAccessorMPIdentityLinear = ::boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear); auto aSimpleMappableDoseAccessorMPIdentityNN = ::boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); CHECK_NO_THROW(MatchPointTransformation(registration.GetPointer())); CHECK_THROW_EXPLICIT(MatchPointTransformation(nullptr), core::NullPointerException); //2) test getDoseAt() // a) with Identity transform double vectorDoseAccessorStartEnd = 0.0; while (vectorDoseAccessorStartEnd <= 1.0) { VoxelGridID runningID = (VoxelGridID)(vectorDoseAccessorStartEnd * (double)aSimpleMappableDoseAccessorMPIdentityLinear->getGridSize()); CHECK_EQUAL(aSimpleMappableDoseAccessorMPIdentityLinear->getValueAt(runningID), doseAccessor2->getValueAt(runningID)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPIdentityNN->getValueAt(runningID), doseAccessor2->getValueAt(runningID)); vectorDoseAccessorStartEnd += 0.1; } // b) with translation transform //Second: Translation (5mm/5mm/5mm) --> in voxel: (1/1/1) as pixelspacing = 5 mm translation[0] = translation[1] = translation[2] = 5.0; registration->_translation = translation; auto aSimpleMappableDoseAccessorMPTranslationLinear = boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear); auto aSimpleMappableDoseAccessorMPTranslationNN = boost::make_shared(doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN); rttb::VoxelGridIndex3D aIndexBeforeTransformation(0, 0, 0); rttb::VoxelGridIndex3D aIndexAfterTransformation(1, 1, 1); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation), doseAccessor2->getValueAt(aIndexAfterTransformation)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation), doseAccessor2->getValueAt(aIndexAfterTransformation)); rttb::VoxelGridIndex3D aIndexBeforeTransformation2(20, 10, 10); rttb::VoxelGridIndex3D aIndexAfterTransformation2(21, 11, 11); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation2), doseAccessor2->getValueAt(aIndexAfterTransformation2)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation2), doseAccessor2->getValueAt(aIndexAfterTransformation2)); rttb::VoxelGridIndex3D aIndexBeforeTransformation3( aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumColumns() - 2, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumRows() - 2, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumSlices() - 2); rttb::VoxelGridIndex3D aIndexAfterTransformation3( aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumColumns() - 1, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumRows() - 1, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumSlices() - 1); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation3), doseAccessor2->getValueAt(aIndexAfterTransformation3)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation3), doseAccessor2->getValueAt(aIndexAfterTransformation3)); if (RTDOSE_FILENAME_REALISTIC != "" && CT_FRACTION != "" && CT_PLANNING != "") { //3) test with rigid registration //realistic background: registration from BP-CT to fraction CT, apply on planning dose that is based on BP-CT (proof of concept) //Target image: fraction CT, Moving image: planning CT simpleRegistrationWorkflow prepareRegistrationRealisticScenario(CT_FRACTION, CT_PLANNING, true); Registration3D3DPointer registrationRealisticScenario = prepareRegistrationRealisticScenario.getRegistration(); auto transformRealistic = boost::make_shared(registrationRealisticScenario); io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE_FILENAME_REALISTIC.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); core::GeometricInfo geoInfoRealistic; geoInfoRealistic.setNumColumns( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[0]); geoInfoRealistic.setNumRows( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[1]); geoInfoRealistic.setNumSlices( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[2]); //Dose is related to BP-CT, map dose to fraction CT geometry auto aSimpleMappableDoseAccessorRealisticScenarioLinear = boost::make_shared(geoInfoRealistic, doseAccessor3, transformRealistic, interpolationLinear); //combination of 0, size/2 and size to check as coordinates std::vector coordinatesToCheckX, coordinatesToCheckY, coordinatesToCheckZ; coordinatesToCheckX.push_back(0); coordinatesToCheckX.push_back(geoInfoRealistic.getNumColumns() / 2); coordinatesToCheckX.push_back(geoInfoRealistic.getNumColumns() - 1); coordinatesToCheckY.push_back(0); coordinatesToCheckY.push_back(geoInfoRealistic.getNumRows() / 2); coordinatesToCheckY.push_back(geoInfoRealistic.getNumRows() - 1); coordinatesToCheckZ.push_back(0); coordinatesToCheckZ.push_back(geoInfoRealistic.getNumSlices() / 2); coordinatesToCheckZ.push_back(geoInfoRealistic.getNumSlices() - 1); //Pixels are inside the fraction CT image and mapping should work (even if they map outside of doseAccessor3) for (size_t i = 0; i < coordinatesToCheckX.size(); ++i) { for (size_t j = 0; j < coordinatesToCheckY.size(); ++j) { for (size_t k = 0; k < coordinatesToCheckZ.size(); ++k) { CHECK_NO_THROW(aSimpleMappableDoseAccessorRealisticScenarioLinear->getValueAt(VoxelGridIndex3D( coordinatesToCheckX.at(i), coordinatesToCheckY.at(j), coordinatesToCheckZ.at(k)))); } } } } RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp index ba9af1b..1dfd4a5 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp @@ -1,86 +1,80 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "registrationHelper.h" #include "litTestImageIO.h" #include "litImageTester.h" #include int setImageFileNames(std::string targetImage, std::string movingImage, bool isDirectory, AppGlobals& globals) { globals.targetImageFileName = targetImage; globals.movingImageFileName = movingImage; globals.isDirectory = isDirectory; return EXIT_SUCCESS; } int loadData(AppGlobals& globals) { if (!globals.isDirectory) { globals.spTargetImage = lit::TestImageIO::InternalImageType>::readImage( globals.targetImageFileName); } else { globals.spTargetImage = map::io::readImage (globals.targetImageFileName, map::io::ImageSeriesReadStyle::Dicom); } if (globals.spTargetImage.IsNull()) { std::cerr << "Error. Cannot load target image: " << globals.targetImageFileName << std::endl; return EXIT_FAILURE; } if (!globals.isDirectory) { globals.spMovingImage = lit::TestImageIO::InternalImageType>::readImage( globals.movingImageFileName); } else { globals.spMovingImage = map::io::readImage (globals.movingImageFileName, map::io::ImageSeriesReadStyle::Dicom); } if (globals.spMovingImage.IsNull()) { std::cerr << "Error. Cannot load moving image: " << globals.movingImageFileName << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } AppGlobals::AppGlobals() { }; \ No newline at end of file diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h index ee79206..4124dde 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h @@ -1,56 +1,50 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #ifndef __REGISTRATION_HELPER_H #define __REGISTRATION_HELPER_H #include "mapContinuousElements.h" #include "mapDiscreteElements.h" #include "mapImageReader.h" typedef map::core::discrete::Elements<3>::InternalImageType ImageType; typedef map::core::continuous::Elements<3>::InternalPointSetType LandmarksType; struct AppGlobals { std::string targetImageFileName; std::string movingImageFileName; bool isDirectory; ImageType::Pointer spTargetImage; ImageType::Pointer spMovingImage; ImageType::Pointer spResultImage; AppGlobals(); }; int setImageFileNames(std::string targetImage, std::string movingImage, bool isDirectory, AppGlobals& globals); int loadData(AppGlobals& globals); #endif \ No newline at end of file diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h b/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h index ee23b74..7046991 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h @@ -1,84 +1,79 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __REGISTRATION_TEST_H #define __REGISTRATION_TEST_H #include "mapRegistration.h" namespace map { namespace core { /*! @class TestRegistration @brief Simple implementation of MatchPoint Registration class with direct access to mapping. */ template class RegistrationTest: public Registration { public: typedef RegistrationTest Self; typedef RegistrationBase Superclass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; typedef typename Registration::TargetPointType TargetPointType; typedef typename Registration::MovingPointType MovingPointType; itkTypeMacro(RegistrationTest, Registration); itkNewMacro(Self); bool _limitedTarget; double* _translation; RegistrationTest() {}; ~RegistrationTest() { }; virtual bool mapPointInverse(const TargetPointType& inPoint, MovingPointType& outPoint) const { for (unsigned int i = 0; i < VTargetDimensions; i++) { outPoint[i] = inPoint[i] + _translation[i]; } return true; }; virtual bool hasLimitedTargetRepresentation() const { return _limitedTarget; } private: RegistrationTest(const Self& source); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } } #endif diff --git a/testing/interpolation/InterpolationMatchPointTransformation/rttbInterpolationMatchPointTests.cpp b/testing/interpolation/InterpolationMatchPointTransformation/rttbInterpolationMatchPointTests.cpp index 473ee84..9a298bf 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/rttbInterpolationMatchPointTests.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/rttbInterpolationMatchPointTests.cpp @@ -1,63 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbAlgorithmsTests 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 { void registerTests() { LIT_REGISTER_TEST(SimpleMappableDoseAccessorWithMatchPointTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp index 8fca7ce..fb4b417 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp @@ -1,110 +1,104 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #undef MAP_SEAL_ALGORITHMS #include "simpleRegistrationWorkflow.h" #include "registrationHelper.h" simpleRegistrationWorkflow::simpleRegistrationWorkflow(std::string targetFilename, std::string movingFilename, bool isDirectory) : _targetFilename(targetFilename), _movingFilename(movingFilename) { setImageFileNames(_targetFilename, _movingFilename, isDirectory, globals); loadData(globals); _spAlgorithmEuler = nullptr; } vnl_vector simpleRegistrationWorkflow::getRegistrationParameters( Registration3D3DPointer reg) { typedef map::core::PreCachedRegistrationKernel<3, 3> PreCachedRegistrationKernel3D3D; const PreCachedRegistrationKernel3D3D* pModelBasedDirectKernel3D3D = dynamic_cast(&(reg->getDirectMapping())); if (pModelBasedDirectKernel3D3D) { PreCachedRegistrationKernel3D3D::TransformType::ParametersType params = pModelBasedDirectKernel3D3D->getTransformModel()->GetParameters(); return params; } else { return vnl_vector(); } } void simpleRegistrationWorkflow::initializeAndPerformRegistration() { _spAlgorithmEuler = AlgorithmTypeEuler::New(); _spAlgorithmEuler->setProperty("PreinitTransform", map::core::MetaProperty::New(true)); _spAlgorithmEuler->setMovingImage(globals.spMovingImage); _spAlgorithmEuler->setTargetImage(globals.spTargetImage); AlgorithmTypeEuler::RegistrationType::Pointer spRegistration; try { spRegistration = _spAlgorithmEuler->getRegistration(); } catch (const map::core::ExceptionObject& e) { std::cerr << "caught an MatchPoint exception:\n"; e.Print(std::cerr); std::cerr << "\n"; } catch (const itk::ExceptionObject& e) { std::cerr << "caught an ITK exception:\n"; std::cerr << e.GetFile() << ":" << e.GetLine() << ":\n" << e.GetDescription() << "\n"; } catch (const std::exception& e) { std::cerr << "caught an exception:\n"; std::cerr << e.what() << "\n"; } catch (...) { std::cerr << "caught an unknown exception!!!\n"; } } map::core::Registration<3, 3>::Pointer simpleRegistrationWorkflow::getRegistration() { if (_spAlgorithmEuler.IsNull()) { initializeAndPerformRegistration(); } return _spAlgorithmEuler->getRegistration(); }; const itk::Image* simpleRegistrationWorkflow::getTargetImage() { if (_spAlgorithmEuler.IsNull()) { initializeAndPerformRegistration(); } return _spAlgorithmEuler->getTargetImage(); }; diff --git a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h index 75baffa..9a12227 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h @@ -1,63 +1,58 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __SIMPLE_REGISTRATION_WORKFLOW_H #define __SIMPLE_REGISTRATION_WORKFLOW_H #include #include "registrationHelper.h" #include "mapImageMappingTask.h" #include "mapITKEuler3DMattesMIRegistrationAlgorithmTemplate.h" #include "mapExceptionObject.h" /*! @class simpleRegistrationWorkflow @brief implements a concrete registration algorithm of MatchPoint */ class simpleRegistrationWorkflow { public: typedef map::core::Registration<3, 3> Registration3D3DType; typedef Registration3D3DType::Pointer Registration3D3DPointer; typedef map::algorithm::boxed::ITKEuler3DMattesMIRegistrationAlgorithm AlgorithmTypeEuler; private: std::string _targetFilename; std::string _movingFilename; std::string _targetDirectory; std::string _movingDirectory; AppGlobals globals; AlgorithmTypeEuler::Pointer _spAlgorithmEuler; public: /*! @brief Constructor */ simpleRegistrationWorkflow(std::string targetFilename, std::string movingFilename, bool isDirectory = false); map::core::Registration<3, 3>::Pointer getRegistration(); const itk::Image* getTargetImage(); vnl_vector getRegistrationParameters(Registration3D3DPointer reg); protected: void initializeAndPerformRegistration(); }; #endif \ No newline at end of file diff --git a/testing/interpolation/RosuMappableDoseAccessorTest.cpp b/testing/interpolation/RosuMappableDoseAccessorTest.cpp index eaaa6b2..6dac371 100644 --- a/testing/interpolation/RosuMappableDoseAccessorTest.cpp +++ b/testing/interpolation/RosuMappableDoseAccessorTest.cpp @@ -1,150 +1,144 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "litCheckMacros.h" #include #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbRosuMappableDoseAccessor.h" #include "DummyTransformation.h" #include "rttbNullPointerException.h" #include "rttbMappingOutsideOfImageException.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::RosuMappableDoseAccessor RosuMappableDoseAccessor; typedef rttb::interpolation::TransformationInterface TransformationInterface; /*! @brief RosuMappableDoseAccessorTest - test the API of RosuMappableDoseAccessor 1) Constructor 2) test getDoseAt() */ int RosuMappableDoseAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for RosuMappableDoseAccessorTest are expected" << std::endl; return -1; } const double doseGridScaling = 2.822386e-005; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); DoseAccessorPointer doseAccessorNull; auto transformDummy = boost::make_shared(); TransformationInterface::Pointer transformNull; auto aRosuMappableDoseAccessorDefault = boost::make_shared(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy); auto aRosuMappableDoseAccessorNoPadding = boost::make_shared(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, false); //1) Constructor CHECK_NO_THROW(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy)); CHECK_NO_THROW(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, false)); CHECK_NO_THROW(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, true, 5.0)); CHECK_THROW_EXPLICIT(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformDummy), core::NullPointerException); CHECK_THROW_EXPLICIT(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformNull), core::NullPointerException); CHECK_THROW_EXPLICIT(RosuMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformNull), core::NullPointerException); //2) test getDoseAt() std::vector voxelsAsIndexToTest; std::vector voxelsAsIdToTest; std::vector expectedValues; voxelsAsIndexToTest.push_back(VoxelGridIndex3D(5, 9, 8)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(22, 15, 10)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(30, 20, 7)); expectedValues.push_back(5.0 * doseGridScaling); expectedValues.push_back(22.0 * doseGridScaling); expectedValues.push_back(30.0 * doseGridScaling); //convert VoxelGridIndex3D to VoxelGridID for (unsigned int i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1->getGeometricInfo().convert(voxelsAsIndexToTest.at(i), currentId); voxelsAsIdToTest.push_back(currentId); } for (unsigned int i = 0; i < voxelsAsIndexToTest.size(); i++) { //test if the expected interpolation values are computed CHECK_CLOSE(aRosuMappableDoseAccessorDefault->getValueAt(voxelsAsIndexToTest.at(i)), expectedValues.at(i), errorConstant); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aRosuMappableDoseAccessorDefault->getValueAt(voxelsAsIndexToTest.at(i)), aRosuMappableDoseAccessorDefault->getValueAt(voxelsAsIdToTest.at(i))); } //test invalid voxels VoxelGridID invalidID(doseAccessor1->getGeometricInfo().getNumberOfVoxels() + 1); VoxelGridIndex3D invalidIndex(doseAccessor1->getGeometricInfo().getNumColumns() + 1, doseAccessor1->getGeometricInfo().getNumRows() + 1, doseAccessor1->getGeometricInfo().getNumSlices() + 1); CHECK_EQUAL(aRosuMappableDoseAccessorDefault->getValueAt(invalidID), 0.0); CHECK_EQUAL(aRosuMappableDoseAccessorDefault->getValueAt(invalidIndex), 0.0); CHECK_THROW_EXPLICIT(aRosuMappableDoseAccessorNoPadding->getValueAt(invalidID), core::MappingOutsideOfImageException); CHECK_THROW_EXPLICIT(aRosuMappableDoseAccessorNoPadding->getValueAt(invalidIndex), core::MappingOutsideOfImageException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/SimpleMappableDoseAccessorTest.cpp b/testing/interpolation/SimpleMappableDoseAccessorTest.cpp index 99a1b17..0506aba 100644 --- a/testing/interpolation/SimpleMappableDoseAccessorTest.cpp +++ b/testing/interpolation/SimpleMappableDoseAccessorTest.cpp @@ -1,168 +1,162 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "boost/make_shared.hpp" #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbTransformationInterface.h" #include "DummyTransformation.h" #include "rttbNullPointerException.h" #include "rttbMappingOutsideOfImageException.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; /*! @brief SimpleMappableDoseAccessorTest - test the API of SimpleMappableDoseAccessor 1) Test constructor 2) test getDoseAt() */ int SimpleMappableDoseAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorTest are expected" << std::endl; return -1; } const double doseGridScaling = 2.822386e-005; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); DoseAccessorPointer doseAccessorNull; TransformationInterface::Pointer transformDummy = boost::make_shared(); TransformationInterface::Pointer transformNull; auto interpolationNN = boost::make_shared(); auto interpolationLinear = boost::make_shared(); boost::shared_ptr interpolationNull; auto aSimpleMappableDoseAccessorDefault = boost::make_shared( doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy); auto aSimpleMappableDoseAccessorNoPadding = boost::make_shared( doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, false); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy)); CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, false)); CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, true, 5.0)); CHECK_NO_THROW(SimpleMappableDoseAccessor(doseAccessor1GeometricInfo, doseAccessor2, transformDummy, interpolationNN)); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformDummy, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformNull, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformNull, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor(doseAccessor1GeometricInfo, doseAccessor2, transformDummy, interpolationNull), core::NullPointerException); //2) test getGeometricInfo(), getGridSize(), getDoseUID() function CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getGeometricInfo(), doseAccessor1->getGeometricInfo()); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getGridSize(), doseAccessor1->getGeometricInfo().getNumberOfVoxels()); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getUID(), doseAccessor2->getUID()); //3) test getDoseAt() //test valid voxels std::vector voxelsAsIndexToTest; std::vector expectedValues; voxelsAsIndexToTest.push_back(VoxelGridIndex3D(5, 9, 8)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(22, 15, 10)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(30, 20, 7)); expectedValues.push_back(5.0 * doseGridScaling); expectedValues.push_back(22.0 * doseGridScaling); expectedValues.push_back(30.0 * doseGridScaling); for (unsigned int i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(currentId), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(currentId), aSimpleMappableDoseAccessorDefault->getValueAt(voxelsAsIndexToTest.at(i))); } //test invalid voxels VoxelGridID invalidID(doseAccessor1GeometricInfo.getNumberOfVoxels() + 1); VoxelGridIndex3D invalidIndex(doseAccessor1GeometricInfo.getNumColumns() + 1, doseAccessor1GeometricInfo.getNumRows() + 1, doseAccessor1GeometricInfo.getNumSlices() + 1); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(invalidID), 0.0); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(invalidIndex), 0.0); CHECK_THROW_EXPLICIT(aSimpleMappableDoseAccessorNoPadding->getValueAt(invalidID), core::MappingOutsideOfImageException); CHECK_THROW_EXPLICIT(aSimpleMappableDoseAccessorNoPadding->getValueAt(invalidIndex), core::MappingOutsideOfImageException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/rttbInterpolationTests.cpp b/testing/interpolation/rttbInterpolationTests.cpp index a4180bc..bd21cec 100644 --- a/testing/interpolation/rttbInterpolationTests.cpp +++ b/testing/interpolation/rttbInterpolationTests.cpp @@ -1,55 +1,54 @@ // ----------------------------------------------------------------------- // 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. // //------------------------------------------------------------------------ // this file defines the rttbAlgorithmsTests 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 { void registerTests() { LIT_REGISTER_TEST(SimpleMappableDoseAccessorTest); LIT_REGISTER_TEST(RosuMappableDoseAccessorTest); LIT_REGISTER_TEST(InterpolationTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/dicom/DicomDoseAccessorConverterTest.cpp b/testing/io/dicom/DicomDoseAccessorConverterTest.cpp index 56c43e0..685b816 100644 --- a/testing/io/dicom/DicomDoseAccessorConverterTest.cpp +++ b/testing/io/dicom/DicomDoseAccessorConverterTest.cpp @@ -1,130 +1,123 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorWriter.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace testing { /*!@brief DicomDoseAccessorGeneratorTest - test the generators for dicom data 1) test dicom file generator generateDoseAccessor() 2) test dicom IOD generator generateDoseAccessor() */ int DicomDoseAccessorConverterTest(int argc, char* argv[]) { typedef rttb::core::DoseAccessorInterface::Pointer DoseAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: the file name of the dose to read // 2: the file name of the dose to write std::string RTDOSE_FILENAME_R; std::string RTDOSE_FILENAME_W; if (argc > 2) { RTDOSE_FILENAME_R = argv[1]; RTDOSE_FILENAME_W = argv[2]; } double errorConstantDDA = 1e-3; DoseAccessorPointer doseAccessor_r = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME_R.c_str()).generateDoseAccessor(); CHECK_NO_THROW(io::dicom::DicomFileDoseAccessorWriter()); io::dicom::DicomFileDoseAccessorWriter doseConverter; CHECK_NO_THROW(doseConverter.setDoseAccessor(doseAccessor_r)); CHECK_NO_THROW(doseConverter.setFileName(RTDOSE_FILENAME_W)); CHECK_EQUAL(doseConverter.process(), true); DoseAccessorPointer doseAccessor_w = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME_W).generateDoseAccessor(); //Check geometricinfo CHECK(doseAccessor_r->getGeometricInfo().getImagePositionPatient().equalsAlmost( doseAccessor_w->getGeometricInfo().getImagePositionPatient(), errorConstantDDA)); CHECK(doseAccessor_r->getGeometricInfo().getOrientationMatrix().equalsAlmost( doseAccessor_w->getGeometricInfo().getOrientationMatrix(), errorConstantDDA)); CHECK(doseAccessor_r->getGeometricInfo().getSpacing().equalsAlmost( doseAccessor_w->getGeometricInfo().getSpacing(), errorConstantDDA)); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumColumns(), doseAccessor_w->getGeometricInfo().getNumColumns(), errorConstantDDA); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumRows(), doseAccessor_w->getGeometricInfo().getNumRows(), errorConstantDDA); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumSlices(), doseAccessor_w->getGeometricInfo().getNumSlices(), errorConstantDDA); //Check pixel data unsigned int size = doseAccessor_r->getGeometricInfo().getNumColumns() * doseAccessor_r->getGeometricInfo().getNumRows() * doseAccessor_r->getGeometricInfo().getNumSlices() ; for (unsigned int index = 0; index < 30; index++) { CHECK_CLOSE(doseAccessor_r->getValueAt(index), doseAccessor_w->getValueAt(index), errorConstantDDA); if (size / 2 - index >= 0 && size / 2 - index < size) { CHECK_CLOSE(doseAccessor_r->getValueAt(size / 2 - index), doseAccessor_w->getValueAt(size / 2 - index), errorConstantDDA); } CHECK_CLOSE(doseAccessor_r->getValueAt(size - index - 1), doseAccessor_w->getValueAt(size - index - 1), errorConstantDDA); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/DicomDoseAccessorGeneratorTest.cpp b/testing/io/dicom/DicomDoseAccessorGeneratorTest.cpp index 65c6cb6..a5d1106 100644 --- a/testing/io/dicom/DicomDoseAccessorGeneratorTest.cpp +++ b/testing/io/dicom/DicomDoseAccessorGeneratorTest.cpp @@ -1,115 +1,108 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace testing { /*!@brief DicomDoseAccessorGeneratorTest - test the generators for dicom data 1) test dicom file generator generateDoseAccessor() 2) test dicom IOD generator generateDoseAccessor() */ int DicomDoseAccessorGeneratorTest(int argc, char* argv[]) { typedef boost::shared_ptr DRTDoseIODPtr; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: dose1 file name // 2: dose2 file name // 3: dose3 file name std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } if (argc > 2) { RTDOSE2_FILENAME = argv[2]; } if (argc > 3) { RTDOSE3_FILENAME = argv[3]; } OFCondition status; DcmFileFormat fileformat; /* test DicomFileDoseAccessorGenerator generateDoseAccessor()*/ CHECK_THROW_EXPLICIT(io::dicom::DicomFileDoseAccessorGenerator("test.test").generateDoseAccessor(), core::InvalidParameterException); CHECK_NO_THROW(io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME.c_str()).generateDoseAccessor()); CHECK_NO_THROW(io::dicom::DicomFileDoseAccessorGenerator( RTDOSE2_FILENAME.c_str()).generateDoseAccessor()); CHECK_NO_THROW(io::dicom::DicomFileDoseAccessorGenerator( RTDOSE3_FILENAME.c_str()).generateDoseAccessor()); /* test DicomIODDoseAccessorGenerator generateDoseAccessor()*/ DRTDoseIODPtr dose = boost::make_shared(); CHECK_THROW_EXPLICIT(io::dicom::DicomIODDoseAccessorGenerator(dose).generateDoseAccessor(), io::dicom::DcmrtException); fileformat.loadFile(RTDOSE_FILENAME.c_str()); dose->read(*fileformat.getDataset()); CHECK_NO_THROW(io::dicom::DicomIODDoseAccessorGenerator(dose).generateDoseAccessor()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/DicomFileReaderHelperTest.cpp b/testing/io/dicom/DicomFileReaderHelperTest.cpp index 208edbc..6457efa 100644 --- a/testing/io/dicom/DicomFileReaderHelperTest.cpp +++ b/testing/io/dicom/DicomFileReaderHelperTest.cpp @@ -1,98 +1,91 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomFileReaderHelper.h" - namespace rttb { namespace testing { /*!@brief DicomDoseAccessorGeneratorTest - test the generators for dicom data 1) test getFileNamesWithSameUID() with a directory name 2) test getFileNames() with a RTDOSE file name and check equal with getFileNamesWithSameUID() 3) test getFileNames() with a RTSTRUCT file name */ int DicomFileReaderHelperTest(int argc, char* argv[]) { typedef boost::shared_ptr DRTDoseIODPtr; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: helax directory name // 2: dose file name // 3: structure file name std::string RT_DIRNAME; std::string RTDOSE_FILENAME; std::string RTStr_FILENAME; if (argc > 3) { RT_DIRNAME = argv[1]; RTDOSE_FILENAME = argv[2]; RTStr_FILENAME = argv[3]; } rttb::io::dicom::Modality doseModality = {rttb::io::dicom::Modality::RTDOSE}; rttb::io::dicom::Modality strModality = {rttb::io::dicom::Modality::RTSTRUCT}; //1) test getFileNamesWithSameUID() with a directory name std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(RT_DIRNAME, doseModality); CHECK_EQUAL(fileVector.size(), 52); //2) test getFileNames() with a RTDOSE file name and check equal with getFileNamesWithSameUID() std::vector fileVector2 = rttb::io::dicom::getFileNames(RTDOSE_FILENAME); for (size_t i = 0; i < fileVector.size(); i++) { CHECK_EQUAL(fileVector.at(i), fileVector2.at(i)); } //3) test getFileNames() with a RTSTRUCT file name fileVector2 = rttb::io::dicom::getFileNames(RTStr_FILENAME); CHECK_EQUAL(fileVector2.size(), 1); fileVector = rttb::io::dicom::getFileNamesWithSameUID(RT_DIRNAME, strModality); CHECK_EQUAL(fileVector.size(), 1); CHECK_EQUAL(fileVector.at(0), fileVector2.at(0)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/DicomIOTest.cpp b/testing/io/dicom/DicomIOTest.cpp index 6e303c5..3d7bb6c 100644 --- a/testing/io/dicom/DicomIOTest.cpp +++ b/testing/io/dicom/DicomIOTest.cpp @@ -1,241 +1,234 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" - namespace rttb { namespace testing { /*!@brief DicomIOTest - test the IO for dicom data 1) test dicom dose import if geometric info was set correctly 2) test dicom dose import accessing dose data and converting 3) check if dicom tags are correctly read 4) test structure import WARNING: The values for comparison need to be adjusted if the input files are changed! */ int DicomIOTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSet::Pointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name // 5: dose4 file name // 6: dose5 file name std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; std::string RTDOSE4_FILENAME; std::string RTDOSE5_FILENAME; if (argc > 1) { RTSTRUCT_FILENAME = argv[1]; } if (argc > 2) { RTDOSE_FILENAME = argv[2]; } if (argc > 3) { RTDOSE2_FILENAME = argv[3]; } if (argc > 4) { RTDOSE3_FILENAME = argv[4]; } if (argc > 5) { RTDOSE4_FILENAME = argv[5]; } if (argc > 6) { RTDOSE5_FILENAME = argv[6]; } OFCondition status; DcmFileFormat fileformat; /* read dicom-rt dose */ io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //1) test dicom dose import if geometric info was set correctly core::GeometricInfo geoInfo = doseAccessor1->getGeometricInfo(); CHECK_EQUAL(45, geoInfo.getNumRows()); CHECK_EQUAL(67, geoInfo.getNumColumns()); CHECK_EQUAL(64, geoInfo.getNumSlices()); CHECK_EQUAL(OrientationMatrix(), geoInfo.getOrientationMatrix()); SpacingVectorType3D pixelSpacing(5, 5, 5); CHECK_EQUAL(pixelSpacing, geoInfo.getSpacing()); WorldCoordinate3D imagePositionPatient(-170.556642, -273.431642, -674); CHECK_EQUAL(imagePositionPatient, geoInfo.getImagePositionPatient()); //test geometric info of an inhomogeneous dose grid io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator5(RTDOSE5_FILENAME.c_str()); DoseAccessorPointer doseAccessor5(doseAccessorGenerator5.generateDoseAccessor()); SpacingVectorType3D pixelSpacing5(2, 3, 2); CHECK_EQUAL(pixelSpacing5, doseAccessor5->getGeometricInfo().getSpacing()); const VoxelGridID start = 0; const VoxelGridIndex3D start3D(0); VoxelGridID end, inbetween; VoxelGridIndex3D end3D, inbetween3D; //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(2, doseAccessor1->getValueAt(start)); CHECK_EQUAL(2, doseAccessor1-> getValueAt(start3D)); CHECK_EQUAL(doseAccessor1->getValueAt(start), doseAccessor1-> getValueAt(start3D)); inbetween = int(std::floor(doseAccessor1->getGridSize() / 2.0)); doseAccessor1->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(2, doseAccessor1->getValueAt(inbetween)); CHECK_EQUAL(2, doseAccessor1-> getValueAt(inbetween3D)); CHECK_EQUAL(doseAccessor1->getValueAt(inbetween), doseAccessor1-> getValueAt(inbetween3D)); end = doseAccessor1->getGridSize() - 1; doseAccessor1->getGeometricInfo().convert(end, end3D); CHECK_EQUAL(2, doseAccessor1->getValueAt(end)); CHECK_EQUAL(2, doseAccessor1-> getValueAt(end3D)); CHECK_EQUAL(doseAccessor1->getValueAt(end), doseAccessor1-> getValueAt(end3D)); ::DRTDoseIOD rtdose2; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(50, doseAccessor2->getValueAt(start)); CHECK_EQUAL(50, doseAccessor2-> getValueAt(start3D)); CHECK_EQUAL(doseAccessor2->getValueAt(start), doseAccessor2-> getValueAt(start3D)); inbetween = int(std::floor(doseAccessor2->getGridSize() / 2.0)); doseAccessor2->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(50, doseAccessor2->getValueAt(inbetween)); CHECK_EQUAL(50, doseAccessor2-> getValueAt(inbetween3D)); CHECK_EQUAL(doseAccessor2->getValueAt(inbetween), doseAccessor2-> getValueAt(inbetween3D)); end = doseAccessor2->getGridSize() - 1; doseAccessor2->getGeometricInfo().convert(end, end3D); CHECK_EQUAL(50, doseAccessor2->getValueAt(end)); CHECK_EQUAL(50, doseAccessor2-> getValueAt(end3D)); CHECK_EQUAL(doseAccessor2->getValueAt(end), doseAccessor2-> getValueAt(end3D)); ::DRTDoseIOD rtdose3; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(0, doseAccessor3->getValueAt(start)); CHECK_EQUAL(0, doseAccessor3-> getValueAt(start3D)); CHECK_EQUAL(doseAccessor3->getValueAt(start), doseAccessor3-> getValueAt(start3D)); inbetween = int(std::floor(doseAccessor3->getGridSize() / 2.0)); doseAccessor3->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(0, doseAccessor3->getValueAt(inbetween)); CHECK_EQUAL(0, doseAccessor3-> getValueAt(inbetween3D)); CHECK_EQUAL(doseAccessor3->getValueAt(inbetween), doseAccessor3-> getValueAt(inbetween3D)); end = doseAccessor3->getGridSize() - 1; doseAccessor3->getGeometricInfo().convert(end, end3D); CHECK_CLOSE(1.46425, doseAccessor3->getValueAt(end), errorConstant); CHECK_CLOSE(1.46425, doseAccessor3-> getValueAt(end3D), errorConstant); CHECK_EQUAL(doseAccessor3->getValueAt(end), doseAccessor3-> getValueAt(end3D)); /* structure set */ StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); //4) test structure import CHECK_EQUAL(10, rtStructureSet->getNumberOfStructures()); CHECK_EQUAL("Aussenkontur", (rtStructureSet->getStructure(0))->getLabel()); CHECK_EQUAL("Rueckenmark", (rtStructureSet->getStructure(1))->getLabel()); CHECK_EQUAL("Niere re.", (rtStructureSet->getStructure(2))->getLabel()); CHECK_EQUAL("Niere li.", (rtStructureSet->getStructure(3))->getLabel()); CHECK_EQUAL("Magen/DD", (rtStructureSet->getStructure(4))->getLabel()); CHECK_EQUAL("Leber", (rtStructureSet->getStructure(5))->getLabel()); CHECK_EQUAL("Darm", (rtStructureSet->getStructure(6))->getLabel()); CHECK_EQUAL("Ref.Pkt.", (rtStructureSet->getStructure(7))->getLabel()); CHECK_EQUAL("PTV", (rtStructureSet->getStructure(8))->getLabel()); CHECK_EQUAL("Boost", (rtStructureSet->getStructure(9))->getLabel()); //4) Test other tags (GridFrameOffsetVector(3004,000c) and PixelSpacingBetweenSlices(0018, 0088)) to compute dose slicing io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator4(RTDOSE4_FILENAME.c_str()); DoseAccessorPointer doseAccessor4(doseAccessorGenerator4.generateDoseAccessor()); rttb::SpacingVectorType3D spacingVec = doseAccessor4->getGeometricInfo().getSpacing(); CHECK_EQUAL(2.5, spacingVec.x()); CHECK_EQUAL(2.5, spacingVec.y()); CHECK_EQUAL(3, spacingVec.z()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/DicomStructureSetGeneratorTest.cpp b/testing/io/dicom/DicomStructureSetGeneratorTest.cpp index 4aea224..c8d7296 100644 --- a/testing/io/dicom/DicomStructureSetGeneratorTest.cpp +++ b/testing/io/dicom/DicomStructureSetGeneratorTest.cpp @@ -1,104 +1,98 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbDicomIODStructureSetGenerator.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*!@brief DicomIOTest - test structure set generator for dicom data 1) test dicom file structure set generator 2) test dicom IOD structure set generator */ int DicomStructureSetGeneratorTest(int argc, char* argv[]) { typedef core::StructureSet::Pointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name std::string RTSTRUCT_FILENAME; if (argc > 1) { RTSTRUCT_FILENAME = argv[1]; } /* structure set */ //1) test dicom file structure set generator CHECK_NO_THROW(io::dicom::DicomFileStructureSetGenerator("")); CHECK_NO_THROW(io::dicom::DicomFileStructureSetGenerator("Test.test")); CHECK_THROW_EXPLICIT(io::dicom::DicomFileStructureSetGenerator("Test.test").generateStructureSet(), rttb::core::InvalidParameterException); CHECK_NO_THROW(io::dicom::DicomFileStructureSetGenerator(RTSTRUCT_FILENAME.c_str())); StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); //2) test dicom IOD structure set generator OFCondition status; DcmFileFormat fileformat; boost::shared_ptr drtStrSetIOD = boost::make_shared(); CHECK_NO_THROW(io::dicom::DicomIODStructureSetGenerator generator1(drtStrSetIOD)); CHECK_THROW_EXPLICIT(io::dicom::DicomIODStructureSetGenerator(drtStrSetIOD).generateStructureSet(), core::InvalidParameterException); fileformat.loadFile(RTSTRUCT_FILENAME.c_str()); drtStrSetIOD->read(*fileformat.getDataset()); CHECK_NO_THROW(io::dicom::DicomIODStructureSetGenerator generator2(drtStrSetIOD)); CHECK_NO_THROW(io::dicom::DicomIODStructureSetGenerator(drtStrSetIOD).generateStructureSet()); StructureSetPointer rtStructureSet2 = io::dicom::DicomIODStructureSetGenerator( drtStrSetIOD).generateStructureSet(); CHECK_EQUAL(rtStructureSet2->getNumberOfStructures(), rtStructureSet->getNumberOfStructures()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/rttbIOTests.cpp b/testing/io/dicom/rttbIOTests.cpp index 5f11f7b..5449c87 100644 --- a/testing/io/dicom/rttbIOTests.cpp +++ b/testing/io/dicom/rttbIOTests.cpp @@ -1,65 +1,59 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(DicomDoseAccessorConverterTest); LIT_REGISTER_TEST(DicomDoseAccessorGeneratorTest); LIT_REGISTER_TEST(DicomFileReaderHelperTest); LIT_REGISTER_TEST(DicomIOTest); LIT_REGISTER_TEST(DicomStructureSetGeneratorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/helax/DicomHelaxDoseAccessorGeneratorTest.cpp b/testing/io/helax/DicomHelaxDoseAccessorGeneratorTest.cpp index 13da8eb..0d400dd 100644 --- a/testing/io/helax/DicomHelaxDoseAccessorGeneratorTest.cpp +++ b/testing/io/helax/DicomHelaxDoseAccessorGeneratorTest.cpp @@ -1,136 +1,129 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbDicomHelaxIODVecDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace testing { /*!@brief DicomHelaxDoseAccessorGeneratorTest - test the IO for dicom helax data 1) test dicom helax file generator generateDoseAccessor() 2) test dicom helax IOD vector generator generateDoseAccessor() */ int DicomHelaxDoseAccessorGeneratorTest(int argc, char* argv[]) { typedef boost::shared_ptr DRTDoseIODPtr; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: dose directory name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name std::string RTDOSE_DIRNAME; std::string RTDOSE1_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; if (argc > 1) { RTDOSE_DIRNAME = argv[1]; } if (argc > 2) { RTDOSE1_FILENAME = argv[2]; } if (argc > 3) { RTDOSE2_FILENAME = argv[3]; } if (argc > 4) { RTDOSE3_FILENAME = argv[4]; } OFCondition status; DcmFileFormat fileformat; /* test dicom helax file generator generateDoseAccessor() */ CHECK_THROW_EXPLICIT( io::helax::DicomHelaxFileDoseAccessorGenerator("/testAsInvalidDirectoryName/").generateDoseAccessor(), core::InvalidParameterException); CHECK_NO_THROW(io::helax::DicomHelaxFileDoseAccessorGenerator( RTDOSE_DIRNAME.c_str()).generateDoseAccessor()); /* test dicom helax IOD vector generator generateDoseAccessor()*/ DRTDoseIODPtr dose1 = boost::make_shared(); DRTDoseIODPtr dose2 = boost::make_shared(); DRTDoseIODPtr dose3 = boost::make_shared(); std::vector doseVector; //test empty vector CHECK_THROW_EXPLICIT(io::helax::DicomHelaxIODVecDoseAccessorGenerator( doseVector).generateDoseAccessor(), core::InvalidParameterException); doseVector.push_back(dose1); doseVector.push_back(dose2); doseVector.push_back(dose3); //test vector with all empty dose IODs CHECK_THROW_EXPLICIT(io::helax::DicomHelaxIODVecDoseAccessorGenerator( doseVector).generateDoseAccessor(), core::InvalidDoseException); fileformat.loadFile(RTDOSE1_FILENAME.c_str()); dose1->read(*fileformat.getDataset()); fileformat.loadFile(RTDOSE2_FILENAME.c_str()); dose2->read(*fileformat.getDataset()); //test vector with one empty dose IOD CHECK_THROW_EXPLICIT(io::helax::DicomHelaxIODVecDoseAccessorGenerator( doseVector).generateDoseAccessor(), core::InvalidDoseException); fileformat.loadFile(RTDOSE3_FILENAME.c_str()); dose3->read(*fileformat.getDataset()); CHECK_NO_THROW(io::helax::DicomHelaxIODVecDoseAccessorGenerator(doseVector).generateDoseAccessor()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/helax/DicomHelaxIOTest.cpp b/testing/io/helax/DicomHelaxIOTest.cpp index e27dba4..70714e8 100644 --- a/testing/io/helax/DicomHelaxIOTest.cpp +++ b/testing/io/helax/DicomHelaxIOTest.cpp @@ -1,128 +1,121 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbDicomHelaxIODVecDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" #include "rttbDicomFileStructureSetGenerator.h" - namespace rttb { namespace testing { /*!@brief DicomHelaxIOTest - test the IO for dicom helax data 1) test dicom helax dose import if geometric info was set correctly 2) test dicom helax dose import accessing dose data and converting 3) test dicom helax structure import WARNING: The values for comparison need to be adjusted if the input files are changed! */ int DicomHelaxIOTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSet::Pointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: directory name std::string RT_DIRNAME; if (argc > 1) { RT_DIRNAME = argv[1]; } OFCondition status; DcmFileFormat fileformat; /* read dicom-rt dose */ io::helax::DicomHelaxFileDoseAccessorGenerator doseAccessorGenerator1(RT_DIRNAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //1) test dicom dose import if geometric info was set correctly core::GeometricInfo geoInfo = doseAccessor1->getGeometricInfo(); CHECK_EQUAL(64, geoInfo.getNumRows()); CHECK_EQUAL(54, geoInfo.getNumColumns()); CHECK_EQUAL(52, geoInfo.getNumSlices()); CHECK_EQUAL(OrientationMatrix(), geoInfo.getOrientationMatrix()); const VoxelGridID start = 0; const VoxelGridIndex3D start3D(0); VoxelGridID end, inbetween; VoxelGridIndex3D end3D, inbetween3D; //2) test dicom dose import accessing dose data and converting CHECK_EQUAL(doseAccessor1->getValueAt(start), doseAccessor1-> getValueAt(start3D)); inbetween = int(std::floor(doseAccessor1->getGridSize() / 2.0)); doseAccessor1->getGeometricInfo().convert(inbetween, inbetween3D); CHECK_EQUAL(doseAccessor1->getValueAt(inbetween), doseAccessor1-> getValueAt(inbetween3D)); end = doseAccessor1->getGridSize() - 1; doseAccessor1->getGeometricInfo().convert(end, end3D); CHECK_EQUAL(doseAccessor1->getValueAt(end), doseAccessor1-> getValueAt(end3D)); /* structure set */ StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RT_DIRNAME.c_str()).generateStructureSet(); //3) test structure import CHECK_EQUAL(8, rtStructureSet->getNumberOfStructures()); CHECK_EQUAL("Patient outline", (rtStructureSet->getStructure(0))->getLabel()); CHECK_EQUAL("boost", (rtStructureSet->getStructure(1))->getLabel()); CHECK_EQUAL("Chiasma", (rtStructureSet->getStructure(2))->getLabel()); CHECK_EQUAL("Sehnerv li.", (rtStructureSet->getStructure(3))->getLabel()); CHECK_EQUAL("Sehnerv re.", (rtStructureSet->getStructure(4))->getLabel()); CHECK_EQUAL("Auge li.", (rtStructureSet->getStructure(5))->getLabel()); CHECK_EQUAL("Auge re.", (rtStructureSet->getStructure(6))->getLabel()); CHECK_EQUAL("Hirnstamm", (rtStructureSet->getStructure(7))->getLabel()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/helax/rttbHelaxIOTests.cpp b/testing/io/helax/rttbHelaxIOTests.cpp index 80bbbf3..4390d18 100644 --- a/testing/io/helax/rttbHelaxIOTests.cpp +++ b/testing/io/helax/rttbHelaxIOTests.cpp @@ -1,62 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(DicomHelaxDoseAccessorGeneratorTest); LIT_REGISTER_TEST(DicomHelaxIOTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/itk/ITKBioModelAccessorConverterTest.cpp b/testing/io/itk/ITKBioModelAccessorConverterTest.cpp index 000ee32..39798cc 100644 --- a/testing/io/itk/ITKBioModelAccessorConverterTest.cpp +++ b/testing/io/itk/ITKBioModelAccessorConverterTest.cpp @@ -1,112 +1,105 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbAccessorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbLQModelAccessor.h" #include "rttbITKImageAccessor.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbITKImageAccessorConverter.h" #include "rttbDoseAccessorProcessorBase.h" #include "rttbDoseAccessorConversionSettingInterface.h" #include "rttbInvalidDoseException.h" - namespace rttb { namespace testing { /*!@brief ITKBioModelAccessorConverterTest - test the conversion rttb BioModel accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) */ int ITKBioModelAccessorConverterTest(int argc, char* argv[]) { typedef core::AccessorInterface::Pointer AccessorPointer; typedef core::DoseAccessorInterface::Pointer DoseAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } //1) Read dicomFile and test process() and getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor(doseAccessorGenerator.generateDoseAccessor()); AccessorPointer LQWithConstantDose = boost::make_shared(doseAccessor, 0.2, 0.02); io::itk::ITKImageAccessorConverter itkConverter(LQWithConstantDose); CHECK_NO_THROW(itkConverter.process()); CHECK_NO_THROW(itkConverter.getITKImage()); io::itk::ITKImageAccessor::ITKImageType::IndexType itkIndex; itkIndex[0] = itkIndex[1] = itkIndex[2] = 0; VoxelGridIndex3D rttbIndex(0, 0, 0); CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() / 2; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() / 2; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() / 2; CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() - 1; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() - 1; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() - 1; CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKDoseAccessorConverterTest.cpp b/testing/io/itk/ITKDoseAccessorConverterTest.cpp index 464ff41..f21ee7a 100644 --- a/testing/io/itk/ITKDoseAccessorConverterTest.cpp +++ b/testing/io/itk/ITKDoseAccessorConverterTest.cpp @@ -1,134 +1,127 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbITKImageAccessorConverter.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbDoseAccessorProcessorBase.h" #include "rttbDoseAccessorConversionSettingInterface.h" #include "rttbInvalidDoseException.h" - namespace rttb { namespace testing { /*!@brief ITKDoseAccessorConverterTest - test the conversion rttb dose accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) 2) test with mhd file (ITKImageFileDoseAccessorGenerator) */ int ITKDoseAccessorConverterTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: dose1 file name // 2: dose2 file name std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } if (argc > 2) { RTDOSE2_FILENAME = argv[2]; } //1) Read dicomFile and test getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor(doseAccessorGenerator.generateDoseAccessor()); io::itk::ITKImageAccessorConverter itkConverter(doseAccessor); CHECK_NO_THROW(itkConverter.process()); CHECK_NO_THROW(itkConverter.getITKImage()); io::itk::ITKImageAccessorConverter::ITKImageType::IndexType itkIndex; itkIndex[0] = itkIndex[1] = itkIndex[2] = 0; VoxelGridIndex3D rttbIndex(0, 0, 0); CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), doseAccessor->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() / 2; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() / 2; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() / 2; CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), doseAccessor->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() - 1; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() - 1; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() - 1; CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), doseAccessor->getValueAt(rttbIndex)); //2) Read mhdFile and test getITKImage() with Litmus TestImageIO io::itk::ITKImageFileAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); io::itk::ITKImageAccessorConverter itkConverter2(doseAccessor2); CHECK_NO_THROW(itkConverter2.process()); CHECK_NO_THROW(itkConverter2.getITKImage()); io::itk::ITKImageAccessorConverter::ITKImageType::Pointer expectedImage = lit::TestImageIO::readImage( RTDOSE2_FILENAME); ::lit::ImageTester tester; tester.setExpectedImage(expectedImage); tester.setActualImage(itkConverter2.getITKImage()); CHECK_TESTER(tester); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKDoseAccessorGeneratorTest.cpp b/testing/io/itk/ITKDoseAccessorGeneratorTest.cpp index a215841..d19514c 100644 --- a/testing/io/itk/ITKDoseAccessorGeneratorTest.cpp +++ b/testing/io/itk/ITKDoseAccessorGeneratorTest.cpp @@ -1,106 +1,100 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkExceptionObject.h" #include "rttbBaseType.h" #include "rttbITKImageAccessorConverter.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*!@brief ITKDoseAccessorGeneratorTest - test the generators for dicom data 1) test itk file generator generateDoseAccessor() 2) test itk generator generateDoseAccessor() */ int ITKDoseAccessorGeneratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: mhd/raw file name with short image type // 2: mhd/raw file name with double image type std::string ITKSHORTFILE_FILENAME, ITKDOUBLEFILE_FILENAME, ITK2DVECTORFILE_FILENAME, ITK2DFILE_FILENAME; if (argc > 4) { ITKSHORTFILE_FILENAME = argv[1]; ITKDOUBLEFILE_FILENAME = argv[2]; ITK2DVECTORFILE_FILENAME = argv[3]; ITK2DFILE_FILENAME = argv[4]; } /* test ITKFileDoseAccessorGenerator generateDoseAccessor()*/ CHECK_THROW_EXPLICIT(io::itk::ITKImageFileAccessorGenerator("test.test").generateDoseAccessor(), core::InvalidDoseException); CHECK_NO_THROW(io::itk::ITKImageFileAccessorGenerator( ITKSHORTFILE_FILENAME.c_str()).generateDoseAccessor()); CHECK_NO_THROW(io::itk::ITKImageFileAccessorGenerator( ITKDOUBLEFILE_FILENAME.c_str()).generateDoseAccessor()); CHECK_THROW_EXPLICIT(io::itk::ITKImageFileAccessorGenerator( ITK2DFILE_FILENAME.c_str()).generateDoseAccessor(), core::InvalidParameterException); CHECK_THROW(io::itk::ITKImageFileAccessorGenerator( ITK2DVECTORFILE_FILENAME.c_str()).generateDoseAccessor()); /* test ITKDoseAccessorGenerator generateDoseAccessor()*/ typedef itk::Image< DoseTypeGy, 3 > DoseImageType; typedef itk::ImageFileReader ReaderType; DoseImageType::Pointer invalidDose = DoseImageType::New(); ReaderType::Pointer reader = ReaderType::New(); CHECK_THROW_EXPLICIT(io::itk::ITKImageAccessorGenerator( invalidDose.GetPointer()).generateDoseAccessor(), core::InvalidDoseException); reader->SetFileName(ITKSHORTFILE_FILENAME); //important to update the reader (won't work without) reader->Update(); CHECK_NO_THROW(io::itk::ITKImageAccessorGenerator(reader->GetOutput()).generateDoseAccessor()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKIOTest.cpp b/testing/io/itk/ITKIOTest.cpp index caae969..3d179f1 100644 --- a/testing/io/itk/ITKIOTest.cpp +++ b/testing/io/itk/ITKIOTest.cpp @@ -1,217 +1,210 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbDoseIteratorInterface.h" #include "rttbITKImageAccessorConverter.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbITKImageAccessor.h" #include "rttbITKImageMaskAccessor.h" #include "rttbInvalidDoseException.h" #include "itkImageFileReader.h" - namespace rttb { namespace testing { /*!@brief ITKIOTest - test the IO for ITK data 1) test ITK dose import if geometric info was set correctly 2) test ITKImageFileDoseAccessorGenerator accessing dose data and converting (*.mhd file) 3) test ITKImageDoseAccessorGenerator accessing dose data and converting (*.mhd file) WARNING: The values for comparison need to be adjusted if the input files are changed! */ int ITKIOTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::MaskAccessorInterface::Pointer MaskAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: mhd file name // 2: mask file name std::string RTDOSE_FILENAME, VOXELIZEDMASK_FILENAME; if (argc > 2) { RTDOSE_FILENAME = argv[1]; VOXELIZEDMASK_FILENAME = argv[2]; } /* read dose in *.mhd file */ io::itk::ITKImageFileAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //1) test ITK dose import if geometric info was set correctly core::GeometricInfo geoInfo = doseAccessor1->getGeometricInfo(); CHECK_EQUAL(25, geoInfo.getNumRows()); CHECK_EQUAL(25, geoInfo.getNumColumns()); CHECK_EQUAL(15, geoInfo.getNumSlices()); //orientation matrix equals identity matrix CHECK_EQUAL(OrientationMatrix(), geoInfo.getOrientationMatrix()); const VoxelGridID start = 0; const VoxelGridIndex3D start3D(0); VoxelGridID end, inbetween, inbetween2, outside; VoxelGridIndex3D end3D, inbetween3D, inbetween23D, outside3D; //2) test ITK dose import accessing dose data and converting (*.mhd file) CHECK(doseAccessor1->getGeometricInfo().validID(start)); CHECK(doseAccessor1->getGeometricInfo().validIndex(start3D)); CHECK(!(doseAccessor1->getGeometricInfo().validID(doseAccessor1->getGridSize()))); CHECK(!(doseAccessor1->getGeometricInfo().validIndex(VoxelGridIndex3D( doseAccessor1->getGridSize())))); CHECK_EQUAL(0, doseAccessor1->getValueAt(start)); CHECK_EQUAL(doseAccessor1->getValueAt(start), doseAccessor1-> getValueAt(start3D)); CHECK_NO_THROW(doseAccessor1->getUID()); inbetween = 4039; doseAccessor1->getGeometricInfo().convert(inbetween, inbetween3D); CHECK(doseAccessor1->getGeometricInfo().validID(inbetween)); CHECK(doseAccessor1->getGeometricInfo().validIndex(inbetween3D)); CHECK_EQUAL(162.0, doseAccessor1->getValueAt(inbetween)); CHECK_EQUAL(doseAccessor1->getValueAt(inbetween), doseAccessor1-> getValueAt(inbetween3D)); inbetween2 = 6086; doseAccessor1->getGeometricInfo().convert(inbetween2, inbetween23D); CHECK(doseAccessor1->getGeometricInfo().validID(inbetween2)); CHECK(doseAccessor1->getGeometricInfo().validIndex(inbetween23D)); CHECK_EQUAL(7.0, doseAccessor1->getValueAt(inbetween2)); CHECK_EQUAL(doseAccessor1->getValueAt(inbetween2), doseAccessor1-> getValueAt(inbetween23D)); end = doseAccessor1->getGridSize() - 1; outside = end + 1; doseAccessor1->getGeometricInfo().convert(end, end3D); outside3D = VoxelGridIndex3D(end3D.x() + 2, end3D.y(), end3D.z()); CHECK(doseAccessor1->getGeometricInfo().validID(end)); CHECK(doseAccessor1->getGeometricInfo().validIndex(end3D)); CHECK_EQUAL(0, doseAccessor1->getValueAt(end)); CHECK_EQUAL(doseAccessor1->getValueAt(end), doseAccessor1-> getValueAt(end3D)); CHECK_EQUAL(-1, doseAccessor1->getValueAt(outside)); CHECK_EQUAL(-1, doseAccessor1->getValueAt(outside3D)); typedef itk::Image< DoseTypeGy, 3 > DoseImageType; typedef itk::ImageFileReader ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(RTDOSE_FILENAME); //important to update the reader (won't work without) reader->Update(); io::itk::ITKImageAccessorGenerator doseAccessorGenerator2(reader->GetOutput()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); //3) test ITK dose import accessing dose data and converting (ITKImageDoseAccessor) CHECK(doseAccessor2->getGeometricInfo().validID(start)); CHECK(doseAccessor2->getGeometricInfo().validIndex(start3D)); CHECK(!(doseAccessor2->getGeometricInfo().validID(doseAccessor2->getGridSize()))); CHECK(!(doseAccessor2->getGeometricInfo().validIndex(VoxelGridIndex3D( doseAccessor2->getGridSize())))); CHECK_EQUAL(0, doseAccessor2->getValueAt(start)); CHECK_EQUAL(doseAccessor2->getValueAt(start), doseAccessor2->getValueAt(start3D)); CHECK(doseAccessor2->getGeometricInfo().validID(inbetween)); CHECK(doseAccessor2->getGeometricInfo().validIndex(inbetween3D)); CHECK_EQUAL(162.0, doseAccessor2->getValueAt(inbetween)); CHECK_EQUAL(doseAccessor2->getValueAt(inbetween), doseAccessor2->getValueAt(inbetween3D)); CHECK(doseAccessor2->getGeometricInfo().validID(inbetween2)); CHECK(doseAccessor2->getGeometricInfo().validIndex(inbetween23D)); CHECK_EQUAL(7.0, doseAccessor2->getValueAt(inbetween2)); CHECK_EQUAL(doseAccessor2->getValueAt(inbetween2), doseAccessor2->getValueAt(inbetween23D)); end = doseAccessor2->getGridSize() - 1; doseAccessor2->getGeometricInfo().convert(end, end3D); CHECK(doseAccessor2->getGeometricInfo().validID(end)); CHECK(doseAccessor2->getGeometricInfo().validIndex(end3D)); CHECK_EQUAL(0, doseAccessor2->getValueAt(end)); CHECK_EQUAL(doseAccessor2->getValueAt(end), doseAccessor2-> getValueAt(end3D)); /* test ITKImageAccessor*/ typedef itk::Image< DoseTypeGy, 3 > DoseImageType; DoseImageType::Pointer invalidDose = DoseImageType::New(); CHECK_THROW_EXPLICIT(io::itk::ITKImageAccessor(invalidDose.GetPointer()), core::InvalidDoseException); /* test ITKImageMaskAccessor*/ CHECK_THROW_EXPLICIT(io::itk::ITKImageMaskAccessor(invalidDose.GetPointer()), core::InvalidDoseException); io::itk::ITKImageFileMaskAccessorGenerator maskAccessorGenerator(VOXELIZEDMASK_FILENAME.c_str()); MaskAccessorPointer maskAccessor(maskAccessorGenerator.generateMaskAccessor()); auto imageSize = maskAccessor->getGeometricInfo().getImageSize(); end = imageSize.x()*imageSize.y()*imageSize.z() - 1; outside = end + 1; maskAccessor->getGeometricInfo().convert(end, end3D); outside3D = VoxelGridIndex3D(end3D.x() + 2, end3D.y(), end3D.z()); inbetween3D = VoxelGridIndex3D(139, 61, 57); maskAccessor->getGeometricInfo().convert(inbetween3D, inbetween); core::MaskVoxel aVoxel(0); CHECK_EQUAL(maskAccessor->getMaskAt(start, aVoxel), true); CHECK_EQUAL(aVoxel.getRelevantVolumeFraction(), 0.0); CHECK_EQUAL(maskAccessor->getMaskAt(end, aVoxel), true); CHECK_EQUAL(aVoxel.getRelevantVolumeFraction(), 0.0); CHECK_EQUAL(maskAccessor->getMaskAt(end3D, aVoxel), true); CHECK_EQUAL(aVoxel.getRelevantVolumeFraction(), 0.0); CHECK_EQUAL(maskAccessor->getMaskAt(outside, aVoxel), false); CHECK_EQUAL(maskAccessor->getMaskAt(outside3D, aVoxel), false); CHECK_EQUAL(maskAccessor->getMaskAt(inbetween, aVoxel), true); CHECK_EQUAL(aVoxel.getRelevantVolumeFraction(), 1.0); CHECK_EQUAL(maskAccessor->getMaskAt(inbetween3D, aVoxel), true); CHECK_EQUAL(aVoxel.getRelevantVolumeFraction(), 1.0); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKMaskAccessorConverterTest.cpp b/testing/io/itk/ITKMaskAccessorConverterTest.cpp index 83f4884..47350d4 100644 --- a/testing/io/itk/ITKMaskAccessorConverterTest.cpp +++ b/testing/io/itk/ITKMaskAccessorConverterTest.cpp @@ -1,178 +1,170 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbBoostMaskAccessor.h" - - namespace rttb { namespace testing { /*!@brief MaskAccessorConverterTest - test the conversion rttb dose accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) 2) test with mhd file (ITKImageFileDoseAccessorGenerator) */ int ITKMaskAccessorConverterTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSet::Pointer StructureSetPointer; typedef core::MaskAccessorInterface::Pointer MaskAccessorPointer; typedef io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer ITKImageTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: //ARGUMENTS: 1: structure file name // 2: dose1 file name std::string RTStr_FILENAME; std::string RTDose_FILENAME; std::string Mask_FILENAME; if (argc > 3) { RTStr_FILENAME = argv[1]; RTDose_FILENAME = argv[2]; Mask_FILENAME = argv[3]; } //1) Read dicomFile and test getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDose_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTStr_FILENAME.c_str()).generateStructureSet(); MaskAccessorPointer maskAccessorPtr = boost::make_shared (rtStructureSet->getStructure(9), doseAccessor1->getGeometricInfo()); maskAccessorPtr->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskAccessorPtr); CHECK_NO_THROW(maskAccessorConverter.process()); CHECK_NO_THROW(maskAccessorConverter.getITKImage()); //2) Read itk image, generate mask and convert it back to itk image, check equal MaskAccessorPointer maskAccessorPtr2 = io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor(); maskAccessorPtr2->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter2(maskAccessorPtr2); maskAccessorConverter2.process(); typedef itk::Image< DoseTypeGy, 3 > MaskImageType; ITKImageTypePointer convertedImagePtr = maskAccessorConverter2.getITKImage(); io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer expectedImage = lit::TestImageIO::readImage( Mask_FILENAME); CHECK_EQUAL(convertedImagePtr->GetOrigin()[0], expectedImage->GetOrigin()[0]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[1], expectedImage->GetOrigin()[1]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[2], expectedImage->GetOrigin()[2]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[0], expectedImage->GetSpacing()[0]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[1], expectedImage->GetSpacing()[1]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[2], expectedImage->GetSpacing()[2]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[0], expectedImage->GetLargestPossibleRegion().GetSize()[0]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[1], expectedImage->GetLargestPossibleRegion().GetSize()[1]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[2], expectedImage->GetLargestPossibleRegion().GetSize()[2]); unsigned int sizeX = convertedImagePtr->GetLargestPossibleRegion().GetSize()[0]; unsigned int sizeY = convertedImagePtr->GetLargestPossibleRegion().GetSize()[1]; unsigned int sizeZ = convertedImagePtr->GetLargestPossibleRegion().GetSize()[2]; io::itk::ITKImageMaskAccessor::ITKMaskImageType::IndexType index; for (unsigned int i = 0; i < 20 && i < sizeX && i < sizeY && i < sizeZ; i++) { index[0] = i; index[1] = i; index[2] = i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for (unsigned int i = 0; i < 20; i++) { index[0] = sizeX - 1 - i; index[1] = sizeY - 1 - i; index[2] = sizeZ - 1 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for (unsigned int i = 0; i < 20 && (sizeX / 2 - i) < sizeX && (sizeY / 2 - i) < sizeY && (sizeZ / 2 - i) < sizeZ; i++) { index[0] = sizeX / 2 - i; index[1] = sizeY / 2 - i; index[2] = sizeZ / 2 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp index a4c011f..ac6cee6 100644 --- a/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp +++ b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp @@ -1,101 +1,94 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbInvalidDoseException.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbITKImageMaskAccessorGenerator.h" - namespace rttb { namespace testing { /*!@brief MaskAccessorGeneratorTest - test the generators for dicom data 1) test itk file generator generateDoseAccessor() 2) test itk generator generateDoseAccessor() */ int ITKMaskAccessorGeneratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: mhd/raw file name std::string Mask_FILENAME; if (argc > 1) { Mask_FILENAME = argv[1]; } /* test ITKImageFileMaskAccessorGenerator generateDoseAccessor()*/ CHECK_THROW_EXPLICIT(io::itk::ITKImageFileMaskAccessorGenerator("test.test").generateMaskAccessor(), core::InvalidDoseException); CHECK_NO_THROW(io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor()); /* test ITKImageMaskAccessorGenerator generateDoseAccessor()*/ typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; MaskImageType::Pointer invalidDose = MaskImageType::New(); ReaderType::Pointer reader = ReaderType::New(); CHECK_THROW_EXPLICIT(io::itk::ITKImageMaskAccessorGenerator( invalidDose.GetPointer()).generateMaskAccessor(), core::InvalidDoseException); reader->SetFileName(Mask_FILENAME); //important to update the reader (won't work without) reader->Update(); CHECK_NO_THROW(io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor()); io::itk::ITKImageMaskAccessorGenerator::MaskAccessorPointer maskAcc = io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor(); CHECK_NO_THROW(maskAcc->getRelevantVoxelVector()); CHECK_EQUAL(maskAcc->isGridHomogeneous(), true); CHECK_NO_THROW(maskAcc->getMaskUID()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/rttbITKIOTests.cpp b/testing/io/itk/rttbITKIOTests.cpp index c05d662..6571fa2 100644 --- a/testing/io/itk/rttbITKIOTests.cpp +++ b/testing/io/itk/rttbITKIOTests.cpp @@ -1,65 +1,59 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(ITKDoseAccessorGeneratorTest); LIT_REGISTER_TEST(ITKDoseAccessorConverterTest); LIT_REGISTER_TEST(ITKBioModelAccessorConverterTest); LIT_REGISTER_TEST(ITKIOTest); LIT_REGISTER_TEST(ITKMaskAccessorGeneratorTest); LIT_REGISTER_TEST(ITKMaskAccessorConverterTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/models/ModelsIOTest.cpp b/testing/io/models/ModelsIOTest.cpp index 3c73890..712d68c 100644 --- a/testing/io/models/ModelsIOTest.cpp +++ b/testing/io/models/ModelsIOTest.cpp @@ -1,142 +1,132 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // (c) Copyright 2007, DKFZ, Heidelberg, Germany // ALL RIGHTS RESERVED // // THIS FILE CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION OF DKFZ. // ANY DUPLICATION, MODIFICATION, DISTRIBUTION, OR // DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY PROHIBITED // WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF DKFZ. // //------------------------------------------------------------------------ -/*! -// @file -// @version $Revision: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author zhangl (last changed by) -// @author *none* (Reviewer) -// @author zhangl (Programmer) -// -// Subversion HeadURL: $HeadURL: http://sidt-hpc1/dkfz_repository/NotMeVisLab/SIDT/RTToolbox/trunk/testing/core/DVHCalculatorTest.cpp $ -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include #include #include "boost/filesystem.hpp" #include "rttbModelXMLWriter.h" namespace rttb { namespace testing { static std::string readFile(const std::string& filename); int ModelsIOTest(int argc, char* argv[]) { std::string expectedxmlfilenametcpleq; std::string expectedxmlfilenamentcplk; if (argc > 2) { expectedxmlfilenametcpleq = argv[1]; expectedxmlfilenamentcplk = argv[2]; } typedef core::DVH::DataDifferentialType DataDifferentialType; PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType aDataDifferential; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values for (int i = 0; i < 98; i++) { value = 0; numberOfVoxels += value; aDataDifferential.push_back(value); } aDataDifferential.push_back(10); aDataDifferential.push_back(20); const IDType structureID = "myStructure"; const IDType doseID = "myDose"; const IDType voxelizationID = "myVoxelization"; core::DVH::Pointer dvhPtr = boost::make_shared(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 8; boost::shared_ptr tcplq = boost::make_shared (dvhPtr, roh, numFractions, alpha / beta, alpha, 0.08); std::string filename = "BioModeltcpleqIOTest.xml"; rttb::io::models::ModelXMLWriter writer = rttb::io::models::ModelXMLWriter(filename, tcplq, false); CHECK_NO_THROW(writer.writeModel()); CHECK_EQUAL(boost::filesystem::exists(filename), true); std::string defaultAsIs = readFile(filename); std::string defaultExpected = readFile(expectedxmlfilenametcpleq); //Does not work due to double imprecisions. As long as we don't have a ModelXMLReader, a check does not makes sense. See T21832 //CHECK_EQUAL(defaultAsIs, defaultExpected); CHECK_EQUAL(std::remove(filename.c_str()), 0); //test NTCPLKBModel models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 35; boost::shared_ptr ntcplk = boost::make_shared(dvhPtr, d50Val, mVal, aVal); filename = "BioModelntcplkIOTest.xml"; rttb::io::models::ModelXMLWriter writer2 = rttb::io::models::ModelXMLWriter(filename, ntcplk); CHECK_NO_THROW(writer2.writeModel()); CHECK_EQUAL(boost::filesystem::exists(filename), true); defaultAsIs = readFile(filename); defaultExpected = readFile(expectedxmlfilenamentcplk); //Does not work due to double imprecisions. As long as we don't have a ModelXMLReader, a check does not makes sense. See T21832 //CHECK_EQUAL(defaultAsIs, defaultExpected); CHECK_EQUAL(std::remove(filename.c_str()), 0); std::string dvhFilename = "dvhfor" + ntcplk->getModelType() + ".xml"; CHECK_EQUAL(std::remove(dvhFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } } diff --git a/testing/io/models/rttbModelsIOTests.cpp b/testing/io/models/rttbModelsIOTests.cpp index 6ce7276..dc954aa 100644 --- a/testing/io/models/rttbModelsIOTests.cpp +++ b/testing/io/models/rttbModelsIOTests.cpp @@ -1,60 +1,54 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (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 { void registerTests() { LIT_REGISTER_TEST(ModelsIOTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/other/CompareDVH.cpp b/testing/io/other/CompareDVH.cpp index 8911b52..b092916 100644 --- a/testing/io/other/CompareDVH.cpp +++ b/testing/io/other/CompareDVH.cpp @@ -1,86 +1,79 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include "CompareDVH.h" #include namespace rttb { namespace testing { bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2) { bool result; const double errorConstantDVH = 1e-4; result = lit::AreClose(aDVH1->getDeltaD(), aDVH2->getDeltaD(), errorConstantDVH); result = result && lit::AreClose(aDVH1->getDeltaV(), aDVH2->getDeltaV(), errorConstantDVH); result = result && (aDVH1->getDoseID() == aDVH2->getDoseID()); result = result && (aDVH1->getStructureID() == aDVH2->getStructureID()); result = result && lit::AreClose(aDVH1->getMaximum(), aDVH2->getMaximum(), errorConstantDVH); result = result && lit::AreClose(aDVH1->getMinimum(), aDVH2->getMinimum(), errorConstantDVH); result = result && lit::AreClose(aDVH1->getMean(), aDVH2->getMean(), errorConstantDVH); result = result && (aDVH1->getDataDifferential().size() == aDVH2->getDataDifferential().size()); for (size_t i = 0; i < aDVH1->getDataDifferential().size(); i++) { result = result && lit::AreClose(aDVH1->getDataDifferential().at(i), aDVH2->getDataDifferential().at(i), errorConstantDVH); } return result; } rttb::testing::DVHPointer computeDiffDVH(DVHPointer aDVH1, DVHPointer aDVH2) { if (aDVH1->getDeltaD() == aDVH2->getDeltaD() && aDVH1->getDeltaV() == aDVH2->getDeltaV()){ rttb::core::DVH::DataDifferentialType dvhData1 = aDVH1->getDataDifferential(); rttb::core::DVH::DataDifferentialType dvhData2 = aDVH2->getDataDifferential(); rttb::core::DVH::DataDifferentialType dvhDataDifference; auto it1 = dvhData1.cbegin(); auto it2 = dvhData2.cbegin(); while (it1 != dvhData1.cend() && it2 != dvhData2.cend()) { dvhDataDifference.push_back(*it1-*it2); ++it1; ++it2; } auto differenceDVH = ::boost::make_shared(dvhDataDifference, aDVH1->getDeltaD(), aDVH1->getDeltaV(), aDVH1->getStructureID(), aDVH1->getDoseID()); return differenceDVH; } else { return aDVH1; } } }//testing }//rttb diff --git a/testing/io/other/CompareDVH.h b/testing/io/other/CompareDVH.h index bd5ce71..86329cc 100644 --- a/testing/io/other/CompareDVH.h +++ b/testing/io/other/CompareDVH.h @@ -1,46 +1,39 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - #include "litCheckMacros.h" #include "rttbDVH.h" #ifndef __DVH_COMPARER_H #define __DVH_COMPARER_H namespace rttb { namespace testing { typedef core::DVH::Pointer DVHPointer; /*! Compare 2 DVHs and return the results. @result Indicates if the test was successful (true) or if it failed (false) */ bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2); DVHPointer computeDiffDVH(DVHPointer aDVH1, DVHPointer aDVH2); }//testing }//rttb #endif diff --git a/testing/io/other/CompareDoseStatistic.cpp b/testing/io/other/CompareDoseStatistic.cpp index 9b55a51..75ed451 100644 --- a/testing/io/other/CompareDoseStatistic.cpp +++ b/testing/io/other/CompareDoseStatistic.cpp @@ -1,116 +1,107 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "CompareDoseStatistic.h" - - namespace rttb { namespace testing { const double errorConstant = 1e-3;// errorConstant is so small because the double are castet to float when they are written bool checkEqualDoseStatistic(DoseStatisticsPtr aDoseStatistic1, DoseStatisticsPtr aDoseStatistic2){ bool result = lit::AreClose(aDoseStatistic1->getNumberOfVoxels(), aDoseStatistic2->getNumberOfVoxels(), 0.01); result = result && lit::AreClose(aDoseStatistic1->getVolume(), aDoseStatistic2->getVolume(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMinimum(), aDoseStatistic2->getMinimum(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMaximum(), aDoseStatistic2->getMaximum(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMean(), aDoseStatistic2->getMean(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getStdDeviation(), aDoseStatistic2->getStdDeviation(), errorConstant); result = result && mapCompare(aDoseStatistic1->getDx().getAllValues(), aDoseStatistic2->getDx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getVx().getAllValues(), aDoseStatistic2->getVx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMaxOHx().getAllValues(), aDoseStatistic2->getMaxOHx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMinOCx().getAllValues(), aDoseStatistic2->getMinOCx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMOCx().getAllValues(), aDoseStatistic2->getMOCx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMOHx().getAllValues(), aDoseStatistic2->getMOHx().getAllValues()); return result; } std::map::const_iterator findNearestKeyInMap(const std::map& aMap, double key) { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(aMap); while (iterator != std::end(aMap)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(aMap)) { --iterator; return iterator; } else { return std::begin(aMap); } } } --iterator; return iterator; } double getValue(const std::map& aMap, double key) { if (aMap.find(key) != std::end(aMap)) { return aMap.find(key)->second; } else { auto iterator = findNearestKeyInMap(aMap, key); return iterator->second; } } bool mapCompare(const std::map& lhs, const std::map& rhs) { if (lhs.size() != rhs.size()){ return false; } for (std::map::const_iterator i = rhs.cbegin(); i != rhs.cend(); ++i) { double a = i->second; double b = getValue(lhs, i->first) ; if (std::abs(a - b ) > errorConstant){// errorConstant is 1e-3 because the double-->float cast when they are written return false; } } return true; } }//testing }//rttb diff --git a/testing/io/other/CompareDoseStatistic.h b/testing/io/other/CompareDoseStatistic.h index 23f3a74..f2b2b27 100644 --- a/testing/io/other/CompareDoseStatistic.h +++ b/testing/io/other/CompareDoseStatistic.h @@ -1,51 +1,43 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #ifndef __DOSE_STATISTICS_COMPARER_H #define __DOSE_STATISTICS_COMPARER_H - namespace rttb { namespace testing { typedef boost::shared_ptr DoseStatisticsPtr; /*! Compare 2 DoseStatistics and return the results. @result Indicates if the test was successful (true) or if it failed (false) */ bool checkEqualDoseStatistic(DoseStatisticsPtr aDoseStatistic1, DoseStatisticsPtr aDoseStatistic2); std::map::const_iterator findNearestKeyInMap(const std::map& aMap, double key); double getValue(const std::map& aMap, double key); bool mapCompare(const std::map& lhs, const std::map& rhs); }//testing }//rttb #endif diff --git a/testing/io/other/DVHXMLIOTest.cpp b/testing/io/other/DVHXMLIOTest.cpp index f7c4d97..eb7647c 100644 --- a/testing/io/other/DVHXMLIOTest.cpp +++ b/testing/io/other/DVHXMLIOTest.cpp @@ -1,107 +1,101 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbDVHXMLFileReader.h" #include "rttbDVHXMLFileWriter.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDVHGenerator.h" #include "CompareDVH.h" namespace rttb { namespace testing { /*! @brief DVHXMLIOTest - test the IO for DVH xml data 1) test writing dvh to xml file 2) test reading DVH from xml file */ int DVHXMLIOTest(int argc, char* argv[]) { typedef core::DVH::Pointer DVHPointer; PREPARE_DEFAULT_TEST_REPORTING; /* generate dummy DVH */ const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; DummyDVHGenerator dvhGenerator; DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix, doseID)); // 1) test writing DVH to xml file DVHType typeCum = {DVHType::Cumulative}; DVHType typeDiff = {DVHType::Differential}; FileNameString fN1 = "test.xml"; CHECK_NO_THROW(io::other::DVHXMLFileWriter(fN1, typeDiff)); CHECK_NO_THROW(io::other::DVHXMLFileWriter(fN1, typeCum)); io::other::DVHXMLFileWriter dvhWriter(fN1, typeCum); CHECK_EQUAL(fN1, dvhWriter.getFileName()); FileNameString fN2 = "otherFile.xml"; CHECK_NO_THROW(dvhWriter.setFileName(fN2)); CHECK_EQUAL(fN2, dvhWriter.getFileName()); CHECK_EQUAL(DVHType::Cumulative, dvhWriter.getDVHType().Type); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_EQUAL(DVHType::Differential, dvhWriter.getDVHType().Type); DVHPointer emptyDvh; CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh), core::NullPointerException); //CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(spMyDVH), core::InvalidParameterException); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_NO_THROW(dvhWriter.writeDVH(spMyDVH)); // 2) test reading DVH from xml file io::other::DVHXMLFileReader dvhReader(fN2); DVHPointer importedDVH = dvhReader.generateDVH(); CHECK_EQUAL(*importedDVH, *spMyDVH); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/DoseStatisticsIOTest.cpp b/testing/io/other/DoseStatisticsIOTest.cpp index 74a3f44..16ab4c2 100644 --- a/testing/io/other/DoseStatisticsIOTest.cpp +++ b/testing/io/other/DoseStatisticsIOTest.cpp @@ -1,138 +1,131 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include #include #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbDoseStatisticsXMLReader.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDoseAccessor.h" #include "CompareDoseStatistic.h" - namespace rttb { namespace testing { /*! @brief DoseStatisticsIOTest - test the DoseStatisticsIO for dose statistics 1) test writing statistics to xml file 2) test reading statistics from XML file and compare DoseStatistics 3) test writing statistics to string */ int DoseStatisticsIOTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::Pointer DoseIteratorPointer; PREPARE_DEFAULT_TEST_REPORTING; /* generate dummy dose */ boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); auto myDoseStatsSimple = myDoseStatsCalculator.calculateDoseStatistics(); auto myDoseStatsComplex = myDoseStatsCalculator.calculateDoseStatistics(true); auto doseStatisticsXMLWriter = io::other::DoseStatisticsXMLWriter(); //1) test writing statistics to xml file CHECK_THROW_EXPLICIT(doseStatisticsXMLWriter.writeDoseStatistics(nullptr, "aFilename.txt"), core::NullPointerException); FileNameString filenameSimple = "testStatisticsSimple.xml"; CHECK_NO_THROW(doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsSimple, filenameSimple)); CHECK(boost::filesystem::exists(filenameSimple)); FileNameString filenameComplex = "testStatisticsComplex.xml"; CHECK_NO_THROW(doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsComplex, filenameComplex)); CHECK(boost::filesystem::exists(filenameComplex)); //2) test reading statistics from XML file and compare DoseStatistics io::other::DoseStatisticsXMLReader readerSimple= io::other::DoseStatisticsXMLReader(filenameSimple); boost::shared_ptr rereadSimplyDose; CHECK_NO_THROW(rereadSimplyDose = readerSimple.generateDoseStatistic()); CHECK(checkEqualDoseStatistic(myDoseStatsSimple, rereadSimplyDose)); io::other::DoseStatisticsXMLReader readerComplex = io::other::DoseStatisticsXMLReader(filenameComplex); boost::shared_ptr rereadComplexDose; CHECK_NO_THROW(rereadComplexDose = readerComplex.generateDoseStatistic()); CHECK(checkEqualDoseStatistic(myDoseStatsComplex, rereadComplexDose)); io::other::DoseStatisticsXMLReader readerInvalidFilename = io::other::DoseStatisticsXMLReader("invalidFilename.xml"); CHECK_THROW_EXPLICIT(readerInvalidFilename.generateDoseStatistic(), core::InvalidParameterException); //delete files again CHECK_EQUAL(std::remove(filenameSimple.c_str()), 0); CHECK_EQUAL(std::remove(filenameComplex.c_str()),0); //3) test writing statistics to string boost::property_tree::ptree ptSimple = doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsSimple); XMLString strSimple = doseStatisticsXMLWriter.writerDoseStatisticsToString(myDoseStatsSimple); CHECK_THROW_EXPLICIT(doseStatisticsXMLWriter.writerDoseStatisticsToString(nullptr), core::NullPointerException); boost::property_tree::ptree ptComplex = doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsComplex); XMLString strComplex = doseStatisticsXMLWriter.writerDoseStatisticsToString(myDoseStatsComplex); std::stringstream sstrSimple; boost::property_tree::xml_parser::write_xml(sstrSimple, ptSimple, boost::property_tree::xml_writer_make_settings('\t', 1)); CHECK_EQUAL(strSimple, sstrSimple.str()); std::stringstream sstrComplex; boost::property_tree::xml_parser::write_xml(sstrComplex, ptComplex, boost::property_tree::xml_writer_make_settings('\t', 1)); CHECK_EQUAL(strComplex, sstrComplex.str()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/OtherIOTest.cpp b/testing/io/other/OtherIOTest.cpp index 72ebc75..30f310a 100644 --- a/testing/io/other/OtherIOTest.cpp +++ b/testing/io/other/OtherIOTest.cpp @@ -1,183 +1,172 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // (c) Copyright 2007, DKFZ, Heidelberg, Germany // ALL RIGHTS RESERVED // // THIS FILE CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION OF DKFZ. // ANY DUPLICATION, MODIFICATION, DISTRIBUTION, OR // DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY PROHIBITED // WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF DKFZ. // //------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author zhangl (last changed by) -// @author *none* (Reviewer) -// @author zhangl (Programmer) -// -// Subversion HeadURL: $HeadURL: http://sidt-hpc1/dkfz_repository/NotMeVisLab/SIDT/RTToolbox/trunk/testing/core/DVHCalculatorTest.cpp $ -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVHTxtFileWriter.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDVHGenerator.h" - namespace rttb { namespace testing { /*! @brief OtherIOTest - test the IO for DVH txt data 1) test writing dvh to text file 2) test reading DVH from text file 3) test reading and writing the same dvh */ int OtherIOTest(int argc, char* argv[]) { typedef core::DVHSet::DVHSetType DVHSetType; typedef core::DVH::DVHPointer DVHPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string DVHTXT_FILENAME; if (argc > 1) { DVHTXT_FILENAME = argv[1]; } /* generate dummy DVH */ const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; DummyDVHGenerator dvhGenerator; DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix, doseID)); // 1) test writing DVH to text file DVHType typeCum = {DVHType::Cumulative}; DVHType typeDiff = {DVHType::Differential}; FileNameString fN1 = "test.txt"; CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeDiff)); CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeCum)); io::other::DVHTxtFileWriter dvhWriter(fN1, typeCum); CHECK_EQUAL(fN1, dvhWriter.getFileName()); FileNameString fN2 = "otherFile.txt"; CHECK_NO_THROW(dvhWriter.setFileName(fN2)); CHECK_EQUAL(fN2, dvhWriter.getFileName()); CHECK_EQUAL(DVHType::Cumulative, dvhWriter.getDVHType().Type); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_EQUAL(DVHType::Differential, dvhWriter.getDVHType().Type); DVHPointer emptyDvh; CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh), core::NullPointerException); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_NO_THROW(dvhWriter.writeDVH(spMyDVH)); // 2) test reading DVH from text file CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN1)); io::other::DVHTxtFileReader dvhReaderTest(fN1); CHECK_THROW_EXPLICIT(dvhReaderTest.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN2)); io::other::DVHTxtFileReader dvhReader(fN2); CHECK_NO_THROW(dvhReader.resetFileName(fN1)); CHECK_THROW_EXPLICIT(dvhReader.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(dvhReader.resetFileName(fN2)); CHECK_NO_THROW(dvhReader.generateDVH()); DVHPointer importedDVH = dvhReader.generateDVH(); CHECK_EQUAL(*importedDVH, *spMyDVH); // 3) test reading and writing the same dvh //read dvh from a txt file io::other::DVHTxtFileReader dvhReader_R(DVHTXT_FILENAME); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_R = dvhReader_R.generateDVH(); //write the dvh to another file as cumulative io::other::DVHTxtFileWriter dvhWriter_R_Cum("test_Cum.txt", typeCum); dvhWriter_R_Cum.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Cum("test_Cum.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Cum = dvhReader_W_Cum.generateDVH(); //check equal const double errorConstant = 1e-7; CHECK_CLOSE(dvhP_R->getDeltaD(), dvhP_W_Cum->getDeltaD(), errorConstant); CHECK_CLOSE(dvhP_R->getDeltaV(), dvhP_W_Cum->getDeltaV(), errorConstant); CHECK(dvhP_R->getDoseID() == dvhP_W_Cum->getDoseID()); CHECK(dvhP_R->getStructureID() == dvhP_W_Cum->getStructureID()); CHECK_CLOSE(dvhP_R->getMaximum(), dvhP_W_Cum->getMaximum(), errorConstant); CHECK_CLOSE(dvhP_R->getMinimum(), dvhP_W_Cum->getMinimum(), errorConstant); CHECK_CLOSE(dvhP_R->getMean(), dvhP_W_Cum->getMean(), errorConstant); CHECK(dvhP_R->getDataDifferential().size() == dvhP_W_Cum->getDataDifferential().size()); for (int i = 0; i < dvhP_R->getDataDifferential().size(); i++) { CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Cum->getDataDifferential().at(i), errorConstant); } //write the dvh to another file as differential io::other::DVHTxtFileWriter dvhWriter_R_Diff("test_Diff.txt", typeDiff); dvhWriter_R_Diff.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Diff("test_Diff.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Diff = dvhReader_W_Diff.generateDVH(); //check equal CHECK_CLOSE(dvhP_R->getDeltaD(), dvhP_W_Diff->getDeltaD(), errorConstant); CHECK_CLOSE(dvhP_R->getDeltaV(), dvhP_W_Diff->getDeltaV(), errorConstant); CHECK(dvhP_R->getDoseID() == dvhP_W_Diff->getDoseID()); CHECK(dvhP_R->getStructureID() == dvhP_W_Diff->getStructureID()); CHECK_CLOSE(dvhP_R->getMaximum(), dvhP_W_Diff->getMaximum(), errorConstant); CHECK_CLOSE(dvhP_R->getMinimum(), dvhP_W_Diff->getMinimum(), errorConstant); CHECK_CLOSE(dvhP_R->getMean(), dvhP_W_Diff->getMean(), errorConstant); CHECK(dvhP_R->getDataDifferential().size() == dvhP_W_Diff->getDataDifferential().size()); for (int i = 0; i < dvhP_R->getDataDifferential().size(); i++) { CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Diff->getDataDifferential().at(i), errorConstant); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/rttbIOTests.cpp b/testing/io/other/rttbIOTests.cpp index 6d552b4..712151e 100644 --- a/testing/io/other/rttbIOTests.cpp +++ b/testing/io/other/rttbIOTests.cpp @@ -1,61 +1,55 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(DoseStatisticsIOTest); LIT_REGISTER_TEST(DVHXMLIOTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/io/rttbDoseAccessorTester.cpp b/testing/io/rttbDoseAccessorTester.cpp index 3b5a83a..a2a401a 100644 --- a/testing/io/rttbDoseAccessorTester.cpp +++ b/testing/io/rttbDoseAccessorTester.cpp @@ -1,152 +1,147 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include #include "rttbGeometricInfo.h" #include "rttbDoseAccessorTester.h" namespace rttb { namespace testing { DoseAccessorTester::DoseAccessorTester(DoseAccessorPointer aReferenceDose, DoseAccessorPointer aCompareDose) : _referenceDose(aReferenceDose), _compareDose(aCompareDose), _geometryIsSimilar(false), _sameGridSize(false), _conversionFailed(false), _numDifference(0) {} void DoseAccessorTester::setReferenceDose(const DoseAccessorPointer aReferenceDose) { _referenceDose = aReferenceDose; } void DoseAccessorTester::setCompareDose(const DoseAccessorPointer aCompareDose) { _compareDose = aCompareDose; } lit::StringType DoseAccessorTester::getTestDescription(void) const { return "Compare two DoseAccessors and determine if the contained doses are equal."; }; bool DoseAccessorTester::doCheck(void) const { _pResults->onTestStart(getCurrentTestLabel()); _geometryIsSimilar = (_referenceDose->getGeometricInfo() == _compareDose->getGeometricInfo()); if (!_geometryIsSimilar) { return false; } _sameGridSize = (_referenceDose->getGridSize() == _compareDose->getGridSize()); if (!_sameGridSize) { return false; } _numDifference = 0; _maxDifference = 0; VoxelGridIndex3D id3D; for (VoxelGridID id = 0; id < _referenceDose->getGridSize(); id++) { _compareDose->getGeometricInfo().convert(id, id3D); if (!_compareDose->getGeometricInfo().validIndex(id3D)) { _conversionFailed = true; _failedID = id; return false; } if ((_referenceDose-> getValueAt(id) != _referenceDose-> getValueAt(id3D)) || (_compareDose->getValueAt(id) != _compareDose-> getValueAt(id3D))) { _conversionFailed = true; _failedID = id; return false; } if ((_referenceDose->getValueAt(id) != _compareDose->getValueAt(id)) || (_referenceDose->getValueAt(id3D) != _compareDose->getValueAt(id3D))) { double tmpDifference = std::abs(_referenceDose->getValueAt(id) - _compareDose->getValueAt(id)); if (tmpDifference > _maxDifference) { _maxDifference = tmpDifference; } _numDifference++; } }//end for(VoxelGridID id = 0; id < _referenceDose->getGridSize(); id++) return (_numDifference == 0); } void DoseAccessorTester::handleSuccess(void) const { std::ostringstream stream; stream << "Both doses are equal" << std::endl; _pResults->onTestSuccess(getCurrentTestLabel(), stream.str()); } void DoseAccessorTester::handleFailure(void) const { std::ostringstream stream; stream << "Doses are different" << std::endl; if (_geometryIsSimilar) { if (_sameGridSize) { stream << std::endl << "Error voxel count: " << _numDifference << std::endl; stream << std::endl << "Maximum difference: " << _maxDifference << std::endl; if (_conversionFailed) { stream << std::endl << "Index conversion failed in: " << _failedID << std::endl; } } else { stream << "Doses have different grid sizes" << std::endl; stream << "Reference dose contains " << _referenceDose->getGridSize() << " voxels and comparison dose " << _compareDose->getGridSize() << std::endl; } } else { stream << "Doses have different geometry" << std::endl; } _pResults->onTestFailure(getCurrentTestLabel(), stream.str()); } } } \ No newline at end of file diff --git a/testing/io/rttbDoseAccessorTester.h b/testing/io/rttbDoseAccessorTester.h index 80e8e40..ff14e28 100644 --- a/testing/io/rttbDoseAccessorTester.h +++ b/testing/io/rttbDoseAccessorTester.h @@ -1,97 +1,91 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __DOSE_ACCESSOR_TESTER_H #define __DOSE_ACCESSOR_TESTER_H #include #include "litTesterBase.h" #include "litString.h" #include "rttbBaseType.h" #include "../../code/core/rttbDoseAccessorInterface.h" namespace rttb { namespace testing { /*! class DoseAccessorTester @brief Tester class for io classes. Compares two given DoseAccessors for similarity. These DoseAccessors are not similar if their geometry or grid size are not similar, if the conversion of a given ID is invalid for one of the accessors, or if the dose at a given ID is not the same for both accessors. */ class DoseAccessorTester: public lit::TesterBase { public: typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; private: DoseAccessorPointer _referenceDose; DoseAccessorPointer _compareDose; mutable double _maxDifference; mutable double _numDifference; mutable bool _geometryIsSimilar; mutable bool _sameGridSize; mutable bool _conversionFailed; mutable VoxelGridID _failedID; public: DoseAccessorTester(DoseAccessorPointer aReferenceDose, DoseAccessorPointer aCompareDose); /*! Set the dose accessor pointer for the dose comparison. */ void setReferenceDose(const DoseAccessorPointer aReferenceDose); void setCompareDose(const DoseAccessorPointer aCompareDose); /*! Returns a string that specifies the test the tester currently performs. */ lit::StringType getTestDescription(void) const; lit::StringType getTestName(void) const { return "DoseAccessorTester"; }; protected: /*! performs the test and checks the results. @result Indicates if the test was successful (true) or if it failed (false) */ bool doCheck(void) const; /*! Function will be called by check() if test was succesfull. */ void handleSuccess(void) const; /*! Function will be called by check() if test was a failure. */ void handleFailure(void) const; }; } } #endif \ No newline at end of file diff --git a/testing/masks/BoostMaskTest.cpp b/testing/masks/BoostMaskTest.cpp index 86a5868..a88f2f4 100644 --- a/testing/masks/BoostMaskTest.cpp +++ b/testing/masks/BoostMaskTest.cpp @@ -1,255 +1,247 @@ // ----------------------------------------------------------------------- // 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: 1127 $ (last changed revision) -// @date $Date: 2015-10-01 13:33:33 +0200 (Do, 01 Okt 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "../core/DummyStructure.h" #include "../core/DummyDoseAccessor.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbGenericDoseIterator.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbBoostMask.h" #include "rttbBoostMaskAccessor.h" #include "rttbInvalidParameterException.h" - namespace rttb { namespace testing { /*! @brief BoostMaskRedesignTest. 1) test constructors 2) test getRelevantVoxelVector 3) test getMaskAt */ int BoostMaskTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::Structure::Pointer StructTypePointer; // generate test dose. geometric info: patient position (-25, -2, 35), center of the 1st.voxel boost::shared_ptr spTestDoseAccessor = boost::make_shared(); boost::shared_ptr geometricPtr = boost::make_shared (spTestDoseAccessor->getGeometricInfo()); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); //generate test structure. contours are (-20,0.5,38.75); (-12.5,0.5,38.75); (-12.5,10.5,38.75); (-20,10.5,38.75); //(-20, 0.5, 41.25); (-12.5, 0.5, 41.25); (-12.5, 10.5, 41.25); (-20, 10.5, 41.25); core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(2,3); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); //generate test structure 2. contours are (-20,0.5,38.75); (-12.5,0.5,38.75); (-12.5,10.5,38.75); (-20,10.5,38.75); //(-20, 0.5, 40); (-12.5, 0.5, 40); (-12.5, 10.5, 40); (-20, 10.5, 40); core::Structure myTestStruct2 = myStructGenerator.CreateRectangularStructureCenteredContourPlaneThicknessNotEqualDosePlaneThickness(2); StructTypePointer spMyStruct2 = boost::make_shared(myTestStruct2); //generate test structure. contours are //(-20,0.5,38.75); (-12.5,0.5,38.75); (-12.5,10.5,38.75); (-20,10.5,38.75); //(-20, 0.5, 41.25); (-12.5, 0.5, 41.25); (-12.5, 10.5, 41.25); (-20, 10.5, 41.25); //(-20, 0.5, 48.75); (-12.5, 0.5, 48.75); (-12.5, 10.5, 48.75); (-20, 10.5, 48.75); //(-20, 0.5, 51.25); (-12.5, 0.5, 51.25); (-12.5, 10.5, 51.25); (-20, 10.5, 51.25); //to test calcVoxelizationThickness bug core::Structure myTestStruct3 = myStructGenerator.CreateRectangularStructureCentered(2, 3, 6, 7); StructTypePointer spMyStruct3 = boost::make_shared(myTestStruct3); //1) test BoostMask & BoostMaskAccessor constructor CHECK_NO_THROW(rttb::masks::boost::BoostMask(geometricPtr, spMyStruct)); rttb::masks::boost::BoostMask boostMask = rttb::masks::boost::BoostMask( geometricPtr, spMyStruct); CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo(), true)); rttb::masks::boost::BoostMaskAccessor boostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo(), true); //2) test getRelevantVoxelVector CHECK_NO_THROW(boostMask.getRelevantVoxelVector()); CHECK_NO_THROW(boostMaskAccessor.getRelevantVoxelVector()); //3) test getMaskAt const VoxelGridIndex3D inMask1(2, 1, 2); //corner between two contours slice -> volumeFraction = 0.25 const VoxelGridIndex3D inMask2(3, 4, 2); //inside between two contours slice ->volumeFraction = 1 const VoxelGridIndex3D inMask3(4, 5, 2); //side between two contours slice -> volumeFraction = 0.5 const VoxelGridIndex3D inMask4(2, 1, 1); //corner on the first contour slice -> volumeFraction = 0.25/2 = 0.125 const VoxelGridIndex3D inMask5(2, 1, 3); //corner on the last contour slice -> volumeFraction = 0.25/2 = 0.125 const VoxelGridIndex3D inMask6(3, 4, 1); //inside on the first contour slice ->volumeFraction = 1 /2 = 0.5 const VoxelGridIndex3D outMask1(7, 5, 4); const VoxelGridIndex3D outMask2(2, 1, 0); const VoxelGridIndex3D outMask3(2, 1, 4); VoxelGridID testId; double errorConstantBoostMask = 1e-7; core::MaskVoxel tmpMV1(0), tmpMV2(0); CHECK(boostMaskAccessor.getMaskAt(inMask1, tmpMV1)); geometricPtr->convert(inMask1, testId); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.25, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask2, tmpMV1)); CHECK(geometricPtr->convert(inMask2, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(1, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask3, tmpMV1)); CHECK(geometricPtr->convert(inMask3, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.5, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask4, tmpMV1)); CHECK(geometricPtr->convert(inMask4, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.125, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask5, tmpMV1)); CHECK(geometricPtr->convert(inMask5, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.125, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask6, tmpMV1)); CHECK(geometricPtr->convert(inMask6, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.5, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(!boostMaskAccessor.getMaskAt(outMask1, tmpMV1)); CHECK(geometricPtr->convert(outMask1, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); CHECK(!boostMaskAccessor.getMaskAt(outMask2, tmpMV1)); CHECK(geometricPtr->convert(outMask2, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); CHECK(!boostMaskAccessor.getMaskAt(outMask3, tmpMV1)); CHECK(geometricPtr->convert(outMask3, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); rttb::masks::boost::BoostMask boostMask2 = rttb::masks::boost::BoostMask( geometricPtr, spMyStruct2); CHECK_NO_THROW(boostMask2.getRelevantVoxelVector()); rttb::masks::boost::BoostMaskAccessor boostMaskAccessor2(spMyStruct2, spTestDoseAccessor->getGeometricInfo(), true); CHECK_NO_THROW(boostMaskAccessor2.getRelevantVoxelVector()); CHECK(boostMaskAccessor2.getMaskAt(inMask1, tmpMV1)); geometricPtr->convert(inMask1, testId); CHECK(boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); //corner, the first contour weight 0.25, the second contour weights 0.5 -> volumeFraction = 0.25*0.25 + 1.25*0.5 = 0.1875 CHECK_CLOSE(0.1875, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor2.getMaskAt(inMask2, tmpMV1)); CHECK(geometricPtr->convert(inMask2, testId)); CHECK(boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); //inside, the first contour weight 0.25, the second contour weights 0.5 -> ->volumeFraction = 1*0.25 + 1*0.5 = 0.75 CHECK_EQUAL(0.75, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor2.getMaskAt(inMask3, tmpMV1)); CHECK(geometricPtr->convert(inMask3, testId)); CHECK(boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); //side the first contour weight 0.25, the second contour weights 0.5 -> ->volumeFraction = 0.5*0.25 + 0.5*0.5 = 0.75 CHECK_CLOSE(0.375, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor2.getMaskAt(inMask4, tmpMV1)); CHECK(geometricPtr->convert(inMask4, testId)); CHECK(boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); //corner on the first contour slice, weight 0.25 -> volumeFraction = 0.25*0.25 = 0.0625 CHECK_CLOSE(0.0625, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor2.getMaskAt(inMask6, tmpMV1)); CHECK(geometricPtr->convert(inMask6, testId)); CHECK(boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); //inside on the first contour slice, weight 0.25 ->volumeFraction = 1 * 0.25 = 0.25 CHECK_CLOSE(0.25, tmpMV1.getRelevantVolumeFraction(), errorConstantBoostMask); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(!boostMaskAccessor2.getMaskAt(outMask1, tmpMV1)); CHECK(geometricPtr->convert(outMask1, testId)); CHECK(!boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask CHECK(!boostMaskAccessor2.getMaskAt(outMask2, tmpMV1)); CHECK(geometricPtr->convert(outMask2, testId)); CHECK(!boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask CHECK(!boostMaskAccessor2.getMaskAt(outMask3, tmpMV1)); CHECK(geometricPtr->convert(outMask3, testId)); CHECK(!boostMaskAccessor2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask //3) test calcVoxelizationThickness bug rttb::masks::boost::BoostMask boostMask3 = rttb::masks::boost::BoostMask( geometricPtr, spMyStruct3); CHECK_NO_THROW(boostMask3.getRelevantVoxelVector()); rttb::masks::boost::BoostMaskAccessor boostMaskAccessor3(spMyStruct3, spTestDoseAccessor->getGeometricInfo(), true); CHECK_NO_THROW(boostMaskAccessor3.getRelevantVoxelVector()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb - diff --git a/testing/masks/rttbBoostMaskTests.cpp b/testing/masks/rttbBoostMaskTests.cpp index a9bebe0..712fef3 100644 --- a/testing/masks/rttbBoostMaskTests.cpp +++ b/testing/masks/rttbBoostMaskTests.cpp @@ -1,63 +1,56 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ // this file defines the rttbAlgorithmsTests 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 { void registerTests() { LIT_REGISTER_TEST(BoostMaskTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/models/BioModelScatterPlotTest.cpp b/testing/models/BioModelScatterPlotTest.cpp index f620327..2b4c4fd 100644 --- a/testing/models/BioModelScatterPlotTest.cpp +++ b/testing/models/BioModelScatterPlotTest.cpp @@ -1,239 +1,233 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" #include "rttbBioModelScatterPlots.h" #include "../core/DummyDVHGenerator.h" #include "DummyModel.h" #include "rttbIntegration.h" #include #include #include namespace rttb { namespace testing { typedef models::ScatterPlotType ScatterPlotType; /*! @brief BioModelScatterPlotTest. Test the scatterplot methods. 1) test if parameters are set correctly 2) test if scatterData contain each model value exactly once */ int BioModelScatterPlotTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DummyDVHGenerator dummyDVH; const IDType structureID = "myStructure"; const IDType doseID = "myDose"; core::DVH::Pointer dvhPtr = boost::make_shared(dummyDVH.generateDVH(structureID, doseID, 0, 2000)); //test Dummy Model models::BioModelParamType param1 = 0.35; models::BioModelParamType param2 = 0.023333333333333; models::BioModelParamType param3 = 10000000; //model values will be dose/normalisationDose DoseTypeGy normalisationDose = 10; rttb::models::DummyModel model(dvhPtr); model.resetCounters(); //default number of points is 100 CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 0, param1, 0.5, normalisationDose)); model.resetCounters(); ScatterPlotType scatter = models::getScatterPlotVary1Parameter(model, 0, param1, 0.5, normalisationDose); //only 1st parameter should gave been changed CHECK_EQUAL(100, model.getSetParam1Count()); CHECK_EQUAL(0, model.getSetParam2Count()); CHECK_EQUAL(0, model.getSetParam3Count()); CHECK_EQUAL(100, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose ScatterPlotType::iterator iter; for (iter = scatter.begin(); iter != scatter.end(); ++iter) { double currentKey = iter->first; if ((currentKey / normalisationDose) != iter->second.first) { CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); //number of points is 50 CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose, 50)); model.resetCounters(); scatter = models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose, 50); //only 1st parameter should gave been changed CHECK_EQUAL(0, model.getSetParam1Count()); CHECK_EQUAL(50, model.getSetParam2Count()); CHECK_EQUAL(0, model.getSetParam3Count()); CHECK_EQUAL(50, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose for (iter = scatter.begin(); iter != scatter.end(); ++iter) { double currentKey = iter->first; if ((currentKey / normalisationDose) != iter->second.first) { CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); //number of points is 150 CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose, 150)); model.resetCounters(); scatter = models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose, 150); //only 1st parameter should gave been changed CHECK_EQUAL(0, model.getSetParam1Count()); CHECK_EQUAL(0, model.getSetParam2Count()); CHECK_EQUAL(150, model.getSetParam3Count()); CHECK_EQUAL(150, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose for (iter = scatter.begin(); iter != scatter.end(); ++iter) { double currentKey = iter->first; if ((currentKey / normalisationDose) != iter->second.first) { CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); std::vector paramIDVec; models::BioModel::ParamVectorType meanVec; models::BioModel::ParamVectorType varianceVec; paramIDVec.push_back(0); meanVec.push_back(1); varianceVec.push_back(0.6); paramIDVec.push_back(1); meanVec.push_back(10); varianceVec.push_back(0.5); paramIDVec.push_back(2); meanVec.push_back(100); varianceVec.push_back(0.4); //number of points is 50 CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose, 50)); model.resetCounters(); scatter = models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose, 50); //only 1st parameter should gave been changed CHECK_EQUAL(50, model.getSetParam1Count()); CHECK_EQUAL(50, model.getSetParam2Count()); CHECK_EQUAL(50, model.getSetParam3Count()); CHECK_EQUAL(50, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose for (iter = scatter.begin(); iter != scatter.end(); ++iter) { double currentKey = iter->first; if ((currentKey / normalisationDose) != iter->second.first) { CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); //test 2000 points CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose, 10000)); //test iterativeIntegration /*std::string bedFileName="d:/Temp/bed.txt"; std::ifstream dvh_ifstr(bedFileName,std::ios::in); std::vector volumeV2; std::vector bedV2; //std::cout << "iterative integration"<< std::endl; if ( !dvh_ifstr.is_open() ) { std::cerr<< "DVH file name invalid: could not open the dvh file!"<> volume; volumeV2.push_back(volume); //std::cout << "("<< volume << ","; std::string lineSub2 = line.substr(found2+1,found3-found2-1); //std::cout << lineSub2 << std::endl; std::stringstream ss2(lineSub2); double bed; ss2 >> bed; bedV2.push_back(bed); //std::cout << bed << ");"; } } } struct rttb::models::TcpParams params={0.302101,0.08,10000000,volumeV2,bedV2}; double result = rttb::models::integrateTCP(0, params);*/ RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/models/BioModelTest.cpp b/testing/models/BioModelTest.cpp index a4a6a36..6f4e9be 100644 --- a/testing/models/BioModelTest.cpp +++ b/testing/models/BioModelTest.cpp @@ -1,306 +1,297 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBaseTypeModels.h" #include "rttbBioModelCurve.h" #include "rttbInvalidParameterException.h" #include "rttbBioModelScatterPlots.h" - - - namespace rttb { namespace testing { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief RTBioModelTest. TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. TCPLQ: 1) test constructors (values as expected?) 2) test init (calcTCPxxx) 3) test set/get NTCP (LKB): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get NTCP (RS): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get */ int BioModelTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType aDataDifferential; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values for (int i = 0; i < 98; i++) { value = 0; numberOfVoxels += value; aDataDifferential.push_back(value); } aDataDifferential.push_back(10); aDataDifferential.push_back(20); const IDType structureID = "myStructure"; const IDType doseID = "myDose"; const IDType voxelizationID = "myVoxelization"; core::DVH::Pointer dvhPtr = boost::make_shared(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 8; DoseTypeGy normalizationDose = 50; //1) test constructors (values as expected?) rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(0, tcplq.getAlphaBeta()); CHECK_EQUAL(0, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(dvhPtr, roh, numFractions, alpha / beta, alpha, 0.08); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(0, tcplq.getAlphaBeta()); CHECK_EQUAL(0, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); //2) test init (calcTCPxxx) CHECK_NO_THROW(tcplq.init(1)); //3) test set/get CHECK_EQUAL(0, tcplq.getValue()); CHECK_NO_THROW(tcplq.setParameters(alpha, 10, roh, 0.08)); CHECK_EQUAL(10, tcplq.getAlphaBeta()); CHECK_EQUAL(0.08, tcplq.getAlphaVariance()); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_NO_THROW(models::getCurveDoseVSBioModel(tcplq, normalizationDose)); std::vector aParameterVector; aParameterVector.push_back(alpha + 0.02); CHECK_THROW_EXPLICIT(tcplq.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(0.06); aParameterVector.push_back(8); aParameterVector.push_back(roh / 10); CHECK_NO_THROW(tcplq.setParameterVector(aParameterVector)); CHECK_EQUAL(8, tcplq.getAlphaBeta()); CHECK_EQUAL(0.06, tcplq.getAlphaVariance()); CHECK_EQUAL(alpha + 0.02, tcplq.getAlphaMean()); CHECK_EQUAL(roh / 10, tcplq.getRho()); for (int i = 0; i < 4; i++) { CHECK_NO_THROW(tcplq.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(tcplq.setParameterByID(4, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, tcplq.getParameterID("alphaMean")); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(1, tcplq.getParameterID("alphaVariance")); CHECK_EQUAL(1, tcplq.getAlphaVariance()); CHECK_EQUAL(2, tcplq.getParameterID("alpha_beta")); CHECK_EQUAL(2, tcplq.getAlphaBeta()); CHECK_EQUAL(3, tcplq.getParameterID("rho")); CHECK_EQUAL(3, tcplq.getRho()); //test NTCPLKBModel //1) test constructors (values as expected?) models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 35; CHECK_NO_THROW(rttb::models::NTCPLKBModel()); rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); CHECK_EQUAL(0, lkb.getValue()); CHECK_NO_THROW(rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal)); lkb = rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal); CHECK_EQUAL(0, lkb.getValue()); CHECK_EQUAL(dvhPtr, lkb.getDVH()); CHECK_EQUAL(aVal, lkb.getA()); CHECK_EQUAL(mVal, lkb.getM()); CHECK_EQUAL(d50Val, lkb.getD50()); //2) test init (calcxxx) CHECK_NO_THROW(lkb.init(1)); lkb.getValue(); //3) test set/get lkb = rttb::models::NTCPLKBModel(); CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr); CHECK_EQUAL(dvhPtr, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(models::getCurveEUDVSBioModel(lkb)); aParameterVector.clear(); aParameterVector.push_back(d50Val + 5); CHECK_THROW_EXPLICIT(lkb.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(mVal + 0.2); aParameterVector.push_back(aVal + 0.5); CHECK_NO_THROW(lkb.setParameterVector(aParameterVector)); CHECK_EQUAL(aVal + 0.5, lkb.getA()); CHECK_EQUAL(mVal + 0.2, lkb.getM()); CHECK_EQUAL(d50Val + 5, lkb.getD50()); for (int i = 0; i < 3; i++) { CHECK_NO_THROW(lkb.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(lkb.setParameterByID(3, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, lkb.getParameterID("d50")); CHECK_EQUAL(0, lkb.getD50()); CHECK_EQUAL(1, lkb.getParameterID("m")); CHECK_EQUAL(1, lkb.getM()); CHECK_EQUAL(2, lkb.getParameterID("a")); CHECK_EQUAL(2, lkb.getA()); //test NTCPRSModel //1) test constructors (values as expected?) CHECK_NO_THROW(rttb::models::NTCPRSModel()); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; CHECK_NO_THROW(rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal)); rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal); CHECK_EQUAL(dvhPtr, rs.getDVH()); CHECK_EQUAL(d50Val, rs.getD50()); CHECK_EQUAL(gammaVal, rs.getGamma()); CHECK_EQUAL(sVal, rs.getS()); rs = rttb::models::NTCPRSModel(); CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); //3) test set/get rs.setDVH(dvhPtr); CHECK_EQUAL(dvhPtr, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); //2) test init (calcxxx) CHECK_NO_THROW(rs.init(1)); //3) test set/get continued aParameterVector.clear(); aParameterVector.push_back(d50Val + 5); CHECK_THROW_EXPLICIT(rs.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(gammaVal + 0.2); aParameterVector.push_back(sVal + 0.5); CHECK_NO_THROW(rs.setParameterVector(aParameterVector)); CHECK_EQUAL(gammaVal + 0.2, rs.getGamma()); CHECK_EQUAL(sVal + 0.5, rs.getS()); CHECK_EQUAL(d50Val + 5, rs.getD50()); for (int i = 0; i < 3; i++) { CHECK_NO_THROW(rs.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(rs.setParameterByID(3, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, rs.getParameterID("d50")); CHECK_EQUAL(0, rs.getD50()); CHECK_EQUAL(1, rs.getParameterID("gamma")); CHECK_EQUAL(1, rs.getGamma()); CHECK_EQUAL(2, rs.getParameterID("s")); CHECK_EQUAL(2, rs.getS()); //Scatter plot tests CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose)); //variance=0, will be set to 1e-30 CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, 0), core::InvalidParameterException);//normalisationdose=0 CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, normalizationDose, 10000, 0, 0), core::InvalidParameterException);//maxDose-minDose=0 RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/DummyModel.cpp b/testing/models/DummyModel.cpp index d3848f3..a5a025b 100644 --- a/testing/models/DummyModel.cpp +++ b/testing/models/DummyModel.cpp @@ -1,126 +1,121 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include "DummyModel.h" namespace rttb { namespace models { DummyModel::DummyModel(DVHPointer aDvh): BioModel(aDvh) { _calcCount = 0; _setParam1Count = 0; _setParam2Count = 0; _setParam3Count = 0; _name = "DummyModel"; } BioModelValueType DummyModel::calcModel(const double doseFactor) { _calcCount++; _value = doseFactor; return _value; } void DummyModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { std::cerr << "aParameterVector.size must be 3! Nothing will be done." << std::endl; } else { _param1 = aParameterVector.at(0); _setParam1Count++; _param2 = aParameterVector.at(1); _setParam2Count++; _param3 = aParameterVector.at(2); _setParam3Count++; } } void DummyModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _param1 = aValue; _setParam1Count++; } else if (aParamId == 1) { _param2 = aValue; _setParam2Count++; } else if (aParamId == 2) { _param3 = aValue; _setParam3Count++; } else { std::cerr << "aParamID must be 0(DummyParam1) or 1(DummyParam2) or 2(DummyParam3)! Nothing will be done." << std::endl; } } const int DummyModel::getParameterID(const std::string& aParamName) const { if (aParamName == "DummyParam1") { return 0; } else if (aParamName == "DummyParam2") { return 1; } else if (aParamName == "DummyParam3") { return 2; } else { std::cerr << "There is no parameter with the name " << aParamName << "!" << std::endl; return -1; } } void DummyModel::resetCounters() { _calcCount = 0; _setParam1Count = 0; _setParam2Count = 0; _setParam3Count = 0; } std::map DummyModel::getParameterMap() const { return parameterMap; } void DummyModel::fillParameterMap(){ parameterMap["Dummy"] = 2; } std::string DummyModel::getModelType() const{ return _name; } } } \ No newline at end of file diff --git a/testing/models/DummyModel.h b/testing/models/DummyModel.h index 742ba1c..2499831 100644 --- a/testing/models/DummyModel.h +++ b/testing/models/DummyModel.h @@ -1,97 +1,92 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_MODEL_H #define __DUMMY_MODEL_H #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" namespace rttb { namespace models { /*! @class DummyModel @brief generates a dummy model object used for unit tests */ class DummyModel: public BioModel { private: BioModelParamType _param1; BioModelParamType _param2; BioModelParamType _param3; int _calcCount; int _setParam1Count; int _setParam2Count; int _setParam3Count; protected: /*! @brief Calculate the model value @param doseFactor scaling factor for the dose. The model calculation will use the dvh with each di=old di*doseFactor. */ BioModelValueType calcModel(const double doseFactor = 1); std::map getParameterMap() const; void fillParameterMap() override; std::string getModelType() const; public: /*!@constructor initializes DVH pointer */ DummyModel(DVHPointer aDvh); /*! @brief Set parameter vector, where index of vector is the parameter ID. The length of the vector has to be 3. */ void setParameterVector(const ParamVectorType& aParameterVector); void setParameterByID(const int aParamId, const BioModelParamType aValue); /*! @brief Get parameter by ID. @return Return -1 if ID is not found. */ const int getParameterID(const std::string& aParamName) const; /*! return counting values */ const int getSetParam1Count() const { return _setParam1Count; }; const int getSetParam2Count() const { return _setParam2Count; }; const int getSetParam3Count() const { return _setParam3Count; }; const int getCalcCount() const { return _calcCount; }; void resetCounters(); }; } } #endif \ No newline at end of file diff --git a/testing/models/DvhBasedModelsTest.cpp b/testing/models/DvhBasedModelsTest.cpp index ee4ea26..318bc4d 100644 --- a/testing/models/DvhBasedModelsTest.cpp +++ b/testing/models/DvhBasedModelsTest.cpp @@ -1,110 +1,105 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #include #include #include "litCheckMacros.h" #include "rttbDVH.h" #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief DvhBasedModelsTest. 1) Test bed und lqed2 */ int DvhBasedModelsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test calcBEDDVH and calcLQED2DVH //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; const IDType structureID = "myStructure"; const IDType doseID = "myDose"; const IDType voxelizationID = "myVoxelization"; DataDifferentialType aDataDifferential; std::vector bedVector; std::vector lqed2Vector; int numberOfFractions = 2; double alpha_beta = 10; for (int i = 0; i < 100; i++) { double volume = DoseCalcType((double(rand()) / RAND_MAX) * 1000); double dose = (i + 0.5) * binSize; aDataDifferential.push_back(volume); bedVector.push_back(dose * (1 + dose / (numberOfFractions * alpha_beta))); lqed2Vector.push_back(dose * ((alpha_beta + (dose / numberOfFractions)) / (alpha_beta + 2))); } core::DVH myDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); core::DVH::Pointer dvhPtr = boost::make_shared(myDVH); CHECK_THROW_EXPLICIT(rttb::models::calcBEDDVH(dvhPtr, 0, 10), core::InvalidParameterException); CHECK_THROW_EXPLICIT(rttb::models::calcBEDDVH(dvhPtr, 10, -1), core::InvalidParameterException); CHECK_NO_THROW(rttb::models::calcBEDDVH(dvhPtr, 10, 10)); CHECK_EQUAL(rttb::models::calcBEDDVH(dvhPtr, 2, 10).size(), myDVH.getDataDifferential().size()); rttb::models::BEDDVHType bedDVH = rttb::models::calcBEDDVH(dvhPtr, numberOfFractions, alpha_beta); CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr, 1, 10), core::InvalidParameterException); CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr, 10, -1), core::InvalidParameterException); CHECK_NO_THROW(rttb::models::calcLQED2DVH(dvhPtr, 10, 10, true)); CHECK_EQUAL(rttb::models::calcLQED2DVH(dvhPtr, 2, 10).size(), myDVH.getDataDifferential().size()); rttb::models::BEDDVHType lqed2DVH = rttb::models::calcLQED2DVH(dvhPtr, numberOfFractions, alpha_beta); //check the calculation rttb::models::BEDDVHType::iterator itBED, itLQED2; std::vector::iterator itBEDVec, itLQED2Vec; DataDifferentialType::iterator itDiff; for (itBED = bedDVH.begin(), itLQED2 = lqed2DVH.begin(), itBEDVec = bedVector.begin(), itLQED2Vec = lqed2Vector.begin(), itDiff = aDataDifferential.begin(); itBED != bedDVH.end(), itLQED2 != lqed2DVH.end(), itBEDVec != bedVector.end(), itLQED2Vec != lqed2Vector.end(), itDiff != aDataDifferential.end(); ++itBED, ++itLQED2, ++itBEDVec, ++itLQED2Vec, ++itDiff) { //check volume CHECK_EQUAL(*itDiff, (*itBED).second); CHECK_EQUAL((*itBED).second, (*itLQED2).second); //check bed CHECK_EQUAL(*itBEDVec, (*itBED).first); //check lqed2 CHECK_EQUAL(*itLQED2Vec, (*itLQED2).first); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/LQModelAccessorTest.cpp b/testing/models/LQModelAccessorTest.cpp index 58627e7..c581f08 100644 --- a/testing/models/LQModelAccessorTest.cpp +++ b/testing/models/LQModelAccessorTest.cpp @@ -1,155 +1,150 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #include "litCheckMacros.h" #include #include "rttbLQModelAccessor.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*! @brief LQModelAccessorTest. 1) Test constructors 2) Test getGeometricInfo() 3) Test getValueAt() */ int LQModelAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for LQModelAccessorTest are expected" << std::endl; return -1; } typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); core::GeometricInfo doseAccessor2GeometricInfo = doseAccessor2->getGeometricInfo(); DoseAccessorPointer doseAccessorNull; core::AccessorInterface::Pointer LQWithConstantDose, LQWithConstantDoseDoseScalingTwo, LQWithConstantNFractionsTwo, LQWithIncreaseXDose, LQWithConstantDoseAndMap; //1) test constructor CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessorNull, 0, 0), core::InvalidDoseException); CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessor1, 0.2, 0.02, 1, -1), core::InvalidParameterException); CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessorNull, doseAccessorNull, doseAccessorNull), core::InvalidDoseException); CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessor1, doseAccessor1, doseAccessorNull), core::InvalidDoseException); CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessor1, doseAccessorNull, doseAccessor1), core::InvalidDoseException); CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessorNull, doseAccessor1, doseAccessor1), core::InvalidDoseException); CHECK_NO_THROW(LQWithConstantDose = boost::make_shared(doseAccessor1, 0.2, 0.02)); CHECK_NO_THROW(LQWithConstantNFractionsTwo = boost::make_shared(doseAccessor1, 0.2, 0.02, 2)); CHECK_NO_THROW(LQWithConstantDoseDoseScalingTwo = boost::make_shared (doseAccessor1, 0.2, 0.02, 1, 2.0)); CHECK_NO_THROW(LQWithIncreaseXDose = boost::make_shared(doseAccessor2, 0.3, 0.01)); CHECK_NO_THROW(LQWithConstantDoseAndMap = boost::make_shared(doseAccessor1, doseAccessor2, doseAccessor2)); //2) Test getGeometricInfo() CHECK_EQUAL(LQWithConstantDose->getGeometricInfo(), doseAccessor1GeometricInfo); CHECK_EQUAL(LQWithIncreaseXDose->getGeometricInfo(), doseAccessor2GeometricInfo); //3) Test getValueAt() models::BioModelParamType expectedLQWithDoseTwo = exp(-(0.2 * 2 + (0.02 * 2 * 2))); CHECK_EQUAL(LQWithConstantDose->getValueAt(0), expectedLQWithDoseTwo); CHECK_EQUAL(LQWithConstantDose->getValueAt(LQWithConstantDose->getGridSize() - 1), expectedLQWithDoseTwo); CHECK_EQUAL(LQWithConstantDose->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseTwo); CHECK_EQUAL(LQWithConstantDose->getValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseTwo); models::BioModelParamType expectedLQWithDoseTwoNFractionsTwo = exp(-(0.2 * 2 + (0.02 * 2 * 2/2))); CHECK_EQUAL(LQWithConstantNFractionsTwo->getValueAt(0), expectedLQWithDoseTwoNFractionsTwo); CHECK_EQUAL(LQWithConstantNFractionsTwo->getValueAt(LQWithConstantNFractionsTwo->getGridSize() - 1), expectedLQWithDoseTwoNFractionsTwo); CHECK_EQUAL(LQWithConstantNFractionsTwo->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseTwoNFractionsTwo); CHECK_EQUAL(LQWithConstantNFractionsTwo->getValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseTwoNFractionsTwo); models::BioModelParamType expectedLQWithDoseFour = exp(-(0.2 * 4 + (0.02 * 4 * 4))); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(0), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(LQWithConstantDose->getGridSize() - 1), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseFour); models::BioModelParamType expectedLQWithIncreaseX = exp(-(0.3 * 66 * 2.822386e-5 + (0.01 * 66 * 2.822386e-5 * 66 * 2.822386e-5))); CHECK_EQUAL(LQWithIncreaseXDose->getValueAt(0), 1); CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(LQWithIncreaseXDose->getGridSize() - 1), expectedLQWithIncreaseX, errorConstant); expectedLQWithIncreaseX = exp(-(0.3 * 1 * 2.822386e-5 + (0.01 * 1 * 2.822386e-5 * 1 * 2.822386e-5))); CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithIncreaseX, errorConstant); expectedLQWithIncreaseX = exp(-(0.3 * 45 * 2.822386e-5 + (0.01 * 45 * 2.822386e-5 * 45 * 2.822386e-5))); CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(VoxelGridIndex3D(45, 40, 60)), expectedLQWithIncreaseX, errorConstant); models::BioModelParamType expectedLQWithDoseAndMap = exp(-(66 * 2.822386e-5 * 2 + (66 * 2.822386e-5 * 2 * 2))); CHECK_EQUAL(LQWithConstantDoseAndMap->getValueAt(0), 1); CHECK_CLOSE(LQWithConstantDoseAndMap->getValueAt(LQWithIncreaseXDose->getGridSize() - 1), expectedLQWithDoseAndMap, errorConstant); CHECK_EQUAL(LQWithConstantDoseAndMap->getValueAt(0), LQWithConstantDoseAndMap->getValueAt(VoxelGridIndex3D(0, 0, 0))); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/rttbModelsTest.cpp b/testing/models/rttbModelsTest.cpp index ee706c1..f2245e3 100644 --- a/testing/models/rttbModelsTest.cpp +++ b/testing/models/rttbModelsTest.cpp @@ -1,66 +1,59 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (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 { void registerTests() { LIT_REGISTER_TEST(BioModelTest); LIT_REGISTER_TEST(BioModelScatterPlotTest); LIT_REGISTER_TEST(DvhBasedModelsTest); LIT_REGISTER_TEST(LQModelAccessorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/models/rttbScatterTester.cpp b/testing/models/rttbScatterTester.cpp index 4ea9ca9..e0ce3a6 100644 --- a/testing/models/rttbScatterTester.cpp +++ b/testing/models/rttbScatterTester.cpp @@ -1,199 +1,194 @@ // ----------------------------------------------------------------------- // 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 $ (last changed revision) -// @date $Date $ (last change date) -// @author $Author $ (last changed by) -*/ + #include #include "rttbScatterTester.h" namespace rttb { namespace testing { ScatterTester::ScatterTester(models::CurveDataType aReferenceCurve, models::ScatterPlotType aCompareScatter, models::BioModelParamType aVariance) { _referenceCurve = aReferenceCurve; _compareScatter = aCompareScatter; _variance = aVariance; _numDifference = 0; _allowExceptions = false; } void ScatterTester::setReferenceCurve(const models::CurveDataType aReferenceCurve) { _referenceCurve = aReferenceCurve; } void ScatterTester::setCompareScatter(const models::ScatterPlotType aCompareScatter) { _compareScatter = aCompareScatter; } void ScatterTester::setVariance(const models::BioModelParamType aVariance) { _variance = aVariance; } void ScatterTester::setAllowExceptions(const bool allow) { _allowExceptions = allow; }; lit::StringType ScatterTester::getTestDescription(void) const { return "Compare a model curve and the corresponding scatter plot. The values should be comparable."; }; bool ScatterTester::doCheck(void) const { _pResults->onTestStart(getCurrentTestLabel()); const double scatterError = errorConstant * 10 + _variance; _numDifference = 0; _maxDifference = 0; _meanDifference = 0; double lower, upper, difference, oldVal; models::CurveDataType::const_iterator iterC = _referenceCurve.begin(); oldVal = iterC->second; models::ScatterPlotType::const_iterator iter; for (iter = _compareScatter.begin(); iter != _compareScatter.end(); ++iter) { double currentKey = iter->first; //only set old value if the reference iterator iterC moves if (currentKey > iterC->first) { oldVal = iterC->second; while (currentKey > iterC->first) { ++iterC; } } if (iterC != _referenceCurve.end()) { //determine if curve is ascending or descending lower = oldVal; upper = iterC->second; if (upper < lower) { lower = iterC->second; upper = oldVal; } //check boundaries because no interpolation is done if (upper < (iter->second).first) { difference = std::abs(upper - (iter->second).first); if (difference < scatterError) { continue; } else if (difference > _maxDifference) { _maxDifference = difference; } _meanDifference += difference; ++_numDifference; } if (lower > (iter->second).first) { difference = std::abs(upper - (iter->second).first); if (difference < scatterError) { continue; } else if (difference > _maxDifference) { _maxDifference = difference; } _meanDifference += difference; ++_numDifference; } } }//end for(iter = _compareScatter.begin(); iter != _compareScatter.end(); ++iter) if (_numDifference > 0) { _meanDifference /= _numDifference; if (!_allowExceptions) { return false; } else { // allow up to 5% exceptions if (_numDifference / _compareScatter.size() <= 0.05) { return true; } return false; } } return true; } void ScatterTester::handleSuccess(void) const { std::ostringstream stream; if (!_allowExceptions) { stream << "Curve and scatter plot are similar" << std::endl; } else { stream << "Curve and scatter plot do not correspond" << std::endl; stream << std::endl << "Error voxel count: " << _numDifference << std::endl; stream << std::endl << "Maximum difference: " << _maxDifference << std::endl; stream << std::endl << "Mean difference: " << _meanDifference << ", variance was " << _variance << std::endl; } _pResults->onTestSuccess(getCurrentTestLabel(), stream.str()); } void ScatterTester::handleFailure(void) const { std::ostringstream stream; stream << "Curve and scatter plot do not correspond" << std::endl; stream << std::endl << "Error voxel count: " << _numDifference << std::endl; stream << std::endl << "Maximum difference: " << _maxDifference << std::endl; stream << std::endl << "Mean difference: " << _meanDifference << ", variance was " << _variance << std::endl; _pResults->onTestFailure(getCurrentTestLabel(), stream.str()); } } } \ No newline at end of file diff --git a/testing/models/rttbScatterTester.h b/testing/models/rttbScatterTester.h index 376ab91..0852ced 100644 --- a/testing/models/rttbScatterTester.h +++ b/testing/models/rttbScatterTester.h @@ -1,110 +1,104 @@ // ----------------------------------------------------------------------- // 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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #ifndef __SCATTER_TESTER_H #define __SCATTER_TESTER_H #include "litTesterBase.h" #include "litString.h" #include "rttbBaseType.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" namespace rttb { namespace testing { /*! class ScatterTester @brief Tester class for for model scatter plots. Compares a given scatter plot with a given model curve. The values should be similar for similar doses. Variations should only depend on the variance given for the scatter plot calculation. An additional deviation of 1e-4+givenVariance is ignored. */ class ScatterTester: public lit::TesterBase { private: models::CurveDataType _referenceCurve; models::ScatterPlotType _compareScatter; /*! Additional variance that is allowed in the comparison. This value usually corresponds to the value used in the generation of the scatter plot. */ models::BioModelParamType _variance; mutable float _maxDifference; mutable int _numDifference; mutable float _meanDifference; /*! If true allows up to 5% of the scatter points to deviate without failing. If false, all points have to correspond. */ bool _allowExceptions; public: ScatterTester(models::CurveDataType aReferenceCurve, models::ScatterPlotType aCompareScatter, models::BioModelParamType aVariance = 0); /*! Set the reference curve used in comparison. */ void setReferenceCurve(const models::CurveDataType aReferenceCurve); /*! Set the scatter data used in comparison. */ void setCompareScatter(const models::ScatterPlotType aCompareScatter); /*! Set the variance that is allowed for the scatter plot. Usually this matches the parameter used in the computation of the scattered values. */ void setVariance(const models::BioModelParamType aVariance); /*! If true allows up tp 5% of the scatter points to deviate without failing. If false, all points have to correspond. */ void setAllowExceptions(const bool allow); /*! Returns a string that specifies the test the tester currently performs. */ lit::StringType getTestDescription(void) const; lit::StringType getTestName(void) const { return "ScatterTester"; }; protected: /*! performes the test and checks the results. @result Indicates if the test was successfull (true) or if it failed (false) */ bool doCheck(void) const; /*! Function will be called be check() if test was succesfull. */ void handleSuccess(void) const; /*! Function will be called be check() if test was a failure. */ void handleFailure(void) const; }; } } #endif \ No newline at end of file diff --git a/testing/validation/VoxelizationDVHComparisonTest.cpp b/testing/validation/VoxelizationDVHComparisonTest.cpp index 11260a3..6d4aa17 100644 --- a/testing/validation/VoxelizationDVHComparisonTest.cpp +++ b/testing/validation/VoxelizationDVHComparisonTest.cpp @@ -1,176 +1,170 @@ // ----------------------------------------------------------------------- // 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: 1333 $ (last changed revision) -// @date $Date: 2016-04-22 11:12:14 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include #include "litCheckMacros.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbDVHCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbDVHXMLFileWriter.h" #include "rttbDVHXMLFileReader.h" #include "../io/other/CompareDVH.h" namespace rttb { namespace testing { /*! @brief VoxelizationDVHComparisonTests. Computes the DVH difference of different voxelizations (OTB/Boost legacy/Boost) Writes the difference in a DVH and saves in a file */ core::DoseIteratorInterface::Pointer createMaskDoseIterator(masks::boost::BoostMaskAccessor::StructTypePointer rtstruct, core::GenericDoseIterator::DoseAccessorPointer doseAccessor, const std::string& voxelizationType) { core::GenericMaskedDoseIterator::MaskAccessorPointer spMaskAccessor; if (voxelizationType == "Boost"){ auto spBoostRedesignMaskAccessor = ::boost::make_shared(rtstruct, doseAccessor->getGeometricInfo()); spBoostRedesignMaskAccessor->updateMask(); spMaskAccessor = spBoostRedesignMaskAccessor; } auto spMaskedDoseIteratorTmp = ::boost::make_shared(spMaskAccessor, doseAccessor); core::DoseIteratorInterface::Pointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); return spMaskedDoseIterator; } rttb::core::DVH calcDVH(core::DVHCalculator::DoseIteratorPointer doseIterator, const IDType& structUID, const IDType& doseUID) { rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); rttb::core::DVH dvh = *(calc.generateDVH()); return dvh; } void writeCumulativeDVH(const std::string& filename, rttb::core::DVH dvh) { DVHType typeCum = { DVHType::Cumulative }; io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); dvhWriter.writeDVH(boost::make_shared(dvh)); } int VoxelizationDVHComparisonTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSet::Pointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDVH_XML_OTB_DIRECTORY; std::string RTDVH_XML_BOOST_LEGACY_DIRECTORY; std::string RTDVH_XML_BOOST_DIRECTORY; if (argc > 5) { RTSTRUCT_FILENAME = argv[1]; RTDOSE_FILENAME = argv[2]; RTDVH_XML_OTB_DIRECTORY = argv[3]; RTDVH_XML_BOOST_LEGACY_DIRECTORY = argv[4]; RTDVH_XML_BOOST_DIRECTORY = argv[5]; } // read dicom-rt dose io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create a vector of MaskAccessors (one for each structure) StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); //create directory boost::filesystem::create_directories(RTDVH_XML_BOOST_DIRECTORY); //start evaluation clock_t start(clock()); if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < static_cast(rtStructureSet->getNumberOfStructures()); j++) { std::cout << rtStructureSet->getStructure(j)->getLabel() << std::endl; auto spMaskedDoseIteratorBoostRedesign = createMaskDoseIterator(rtStructureSet->getStructure(j), doseAccessor1, "Boost"); auto label = rtStructureSet->getStructure(j)->getLabel(); ::boost::replace_all(label, "/", "_"); boost::filesystem::path dvhOTBFilename(RTDVH_XML_OTB_DIRECTORY); dvhOTBFilename /= "DVH_" + label + ".xml"; boost::filesystem::path dvhBoostFilename(RTDVH_XML_BOOST_LEGACY_DIRECTORY); dvhBoostFilename /= "DVH_" + label + ".xml"; io::other::DVHXMLFileReader dvhReaderOTB(dvhOTBFilename.string()); auto dvhOTB = dvhReaderOTB.generateDVH(); io::other::DVHXMLFileReader dvhReaderBoost(dvhBoostFilename.string()); auto dvhBoost = dvhReaderBoost.generateDVH(); auto dvhBoostRedesign = calcDVH(spMaskedDoseIteratorBoostRedesign, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getUID()); boost::filesystem::path dvhBoostRedesignFilename(RTDVH_XML_BOOST_DIRECTORY); dvhBoostRedesignFilename /= "DVH_" + label + ".xml"; writeCumulativeDVH(dvhBoostRedesignFilename.string(), dvhBoostRedesign); std::cout << "=== Dose 1 Structure " << j << "===" << std::endl; std::cout << "with OTB voxelization: " << std::endl; std::cout << dvhOTB << std::endl; std::cout << "with Boost_LEGACY voxelization: " << std::endl; std::cout << dvhBoost << std::endl; std::cout << "with Boost voxelization: " << std::endl; std::cout << dvhBoostRedesign << std::endl; //compare DVH for different voxelizations auto diffDVH = computeDiffDVH(dvhOTB, boost::make_shared(dvhBoostRedesign)); boost::filesystem::path dvhBoostRedesignDiffFilename(RTDVH_XML_BOOST_DIRECTORY); dvhBoostRedesignDiffFilename /= "DVHDiff_" + label + ".xml"; writeCumulativeDVH(dvhBoostRedesignDiffFilename.string(), *diffDVH); } } clock_t finish(clock()); std::cout << "DVH Calculation time: " << finish - start << " ms" << std::endl; RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/validation/VoxelizationValidationTest.cpp b/testing/validation/VoxelizationValidationTest.cpp index 2d3ff95..55224bb 100644 --- a/testing/validation/VoxelizationValidationTest.cpp +++ b/testing/validation/VoxelizationValidationTest.cpp @@ -1,160 +1,154 @@ // ----------------------------------------------------------------------- // 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: 1495 $ (last changed revision) -// @date $Date: 2016-09-29 16:17:47 +0200 (Do, 29 Sep 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbImageWriter.h" #include "rttbBoostMask.h" #include "rttbBoostMaskAccessor.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbInvalidParameterException.h" #include "itkSubtractImageFilter.h" #include "itkImageFileReader.h" namespace rttb { namespace testing { io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer subtractImages(const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer image1, const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer image2) { typedef itk::SubtractImageFilter SubtractImageFilterType; SubtractImageFilterType::Pointer subtractFilter = SubtractImageFilterType::New(); subtractFilter->SetInput1(image1); subtractFilter->SetInput2(image2); //since the image origin may be modified through the writing process a bit subtractFilter->SetCoordinateTolerance(5e-2); subtractFilter->Update(); return subtractFilter->GetOutput(); } /*! @brief VoxelizationValidationTest. Compare the new boost voxelization to the OTB voxelization Check the creating of new boost masks for files where the old boost voxelization failed. */ int VoxelizationValidationTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::StructureSet::Pointer StructureSetPointer; std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string BoostMask_DIRNAME; std::string OTBMask_DIRNAME; if (argc > 4) { RTSTRUCT_FILENAME = argv[1]; RTDOSE_FILENAME = argv[2]; BoostMask_DIRNAME = argv[3]; OTBMask_DIRNAME = argv[4]; } //create directory boost::filesystem::create_directories(BoostMask_DIRNAME); /* read dicom-rt dose */ io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create a vector of MaskAccessors (one for each structure) StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); if (rtStructureSet->getNumberOfStructures() > 0) { - //do not compute structure "Aussenkontur" since it is very large (15000 cm³) + //do not compute structure "Aussenkontur" since it is very large (15000 cm³) for (size_t j = 1; j < rtStructureSet->getNumberOfStructures(); j++) { std::cout << j << ": " << rtStructureSet->getStructure(j)->getLabel() << std::endl; //read OTB mask image boost::filesystem::path otbMaskFilename(OTBMask_DIRNAME); otbMaskFilename /= boost::lexical_cast(j)+".mhd"; typedef itk::ImageFileReader ReaderType; ReaderType::Pointer readerOTB = ReaderType::New(); readerOTB->SetFileName(otbMaskFilename.string()); readerOTB->Update(); const io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer otbMaskImage = readerOTB->GetOutput(); //create Boost MaskAccessor clock_t startR(clock()); MaskAccessorPointer boostMaskRPtr = ::boost::make_shared (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); CHECK_NO_THROW(boostMaskRPtr->updateMask()); clock_t finishR(clock()); std::cout << "Boost Mask Calculation: " << finishR - startR << " ms" << std::endl; rttb::io::itk::ITKImageMaskAccessorConverter itkConverterR(boostMaskRPtr); CHECK(itkConverterR.process()); boost::filesystem::path redesignFilename(BoostMask_DIRNAME); redesignFilename /= boost::lexical_cast(j)+".nrrd"; rttb::io::itk::ImageWriter writerR(redesignFilename.string(), itkConverterR.getITKImage().GetPointer()); CHECK(writerR.writeFile()); auto subtractedRedesignImage = subtractImages(otbMaskImage, itkConverterR.getITKImage()); boost::filesystem::path subtractRedesignFilename(BoostMask_DIRNAME); subtractRedesignFilename /= boost::lexical_cast(j)+"_subtracted.nrrd"; rttb::io::itk::ImageWriter writerRSubtracted(subtractRedesignFilename.string(), subtractedRedesignImage.GetPointer()); CHECK(writerRSubtracted.writeFile()); } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/validation/rttbValidationTests.cpp b/testing/validation/rttbValidationTests.cpp index 352b629..5575cb1 100644 --- a/testing/validation/rttbValidationTests.cpp +++ b/testing/validation/rttbValidationTests.cpp @@ -1,65 +1,58 @@ // ----------------------------------------------------------------------- // 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: 1388 $ (last changed revision) -// @date $Date: 2016-07-04 14:03:35 +0200 (Mo, 04 Jul 2016) $ (last change date) -// @author $Author: hentsch $ (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" #include "RTToolboxConfigure.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(VoxelizationDVHComparisonTest); LIT_REGISTER_TEST(VoxelizationValidationTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; }