diff --git a/demoapps/DoseTool/DoseTool.cpp b/demoapps/DoseTool/DoseTool.cpp index 309bce6..299fe1d 100644 --- a/demoapps/DoseTool/DoseTool.cpp +++ b/demoapps/DoseTool/DoseTool.cpp @@ -1,142 +1,158 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #include "DoseToolApplicationData.h" #include "DoseToolHelper.h" #include "DoseToolCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbException.h" rttb::apps::doseTool::ApplicationData appData; int main(int argc, const char** argv) { int result = 0; boost::shared_ptr argParser; try { std::string appName = "DoseTool"; std::string appVersion = RTTB_FULL_VERSION_STRING; argParser = boost::make_shared(argc, argv, appName, appVersion); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return -1; } // This is vital. The application needs to exit if the "help" or "version" parameter is set // because this means the other parameters won't be parsed. if (argParser->isSet(argParser->OPTION_HELP) || argParser->isSet(argParser->OPTION_VERSION)) { return 0; } rttb::apps::doseTool::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose file: " << appData._doseFileName << std::endl; std::cout << "Struct file: " << appData._structFileName << std::endl; - std::cout << "Output file: " << appData._outputFileName << std::endl; std::cout << "Struct name: " << appData._structNameRegex << std::endl; + if (appData._computeDoseStatistics) + { + std::cout << "Dose Statistic output file: " << appData._doseStatisticOutputFileName << std::endl; + std::cout << "Compute complex statistics: " << appData._computeComplexDoseStatistics << std::endl; + + if (appData._computeComplexDoseStatistics) + { + std::cout << "Prescribed dose: " << appData._prescribedDose << std::endl; + } + + std::cout << "Allow self intersections: " << appData._allowSelfIntersection << std::endl; + } + + if (appData._computeDVH) + { + std::cout << "DVH output file: " << appData._dvhOutputFilename << std::endl; + } try { appData._dose = rttb::apps::doseTool::loadDose(appData._doseFileName, appData._doseLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "Error!!! unknown error while reading dose image." << std::endl; return 1; } //loading of structure file not necessary in ITK case as it can be used directly as mask input. if (appData._structLoadStyle.front() != "itk") { try { appData._struct = rttb::apps::doseTool::loadStruct(appData._structFileName, appData._structLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while reading struct image." << std::endl; return 2; } } try { rttb::apps::doseTool::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (...) { std::cerr << "Error!!! unknown error while processing the data or writing the image." << std::endl; return 3; } return result; } diff --git a/demoapps/DoseTool/DoseToolApplicationData.cpp b/demoapps/DoseTool/DoseToolApplicationData.cpp index 88c65fb..09a15f3 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.cpp +++ b/demoapps/DoseTool/DoseToolApplicationData.cpp @@ -1,72 +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: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #include "DoseToolApplicationData.h" namespace rttb { namespace apps { namespace doseTool { ApplicationData:: ApplicationData() { this->reset(); } void ApplicationData:: reset() { _doseFileName = ""; _structFileName = ""; _structNameRegex = ""; _structNameActual = ""; - _outputFileName = ""; + _doseStatisticOutputFileName = ""; _computeComplexDoseStatistics = false; _allowSelfIntersection = false; + _computeDVH = false; + _computeDoseStatistics = false; } void populateAppData(boost::shared_ptr argParser, ApplicationData& appData) { appData._doseFileName = argParser->get(argParser->OPTION_DOSE_FILE); appData._doseLoadStyle = argParser->get >(argParser->OPTION_DOSE_LOAD_STYLE); appData._structFileName = argParser->get(argParser->OPTION_STRUCT_FILE); appData._structLoadStyle = argParser->get >(argParser->OPTION_STRUCT_LOAD_STYLE); appData._structNameRegex = argParser->get(argParser->OPTION_STRUCT_NAME); - appData._outputFileName = argParser->get(argParser->OPTION_OUTPUT_FILE); - appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); - appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); - if (argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) + if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS)) + { + appData._computeDoseStatistics = true; + appData._doseStatisticOutputFileName = argParser->get(argParser->OPTION_DOSE_STATISTICS); + appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); + appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); + } + + if (argParser->isSet(argParser->OPTION_DVH)) + { + appData._computeDVH = true; + appData._dvhOutputFilename = argParser->get(argParser->OPTION_DVH); + } + + + if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS) && argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) { appData._prescribedDose = argParser->get(argParser->OPTION_PRESCRIBED_DOSE); } else { appData._prescribedDose = 1.0; } } } } } diff --git a/demoapps/DoseTool/DoseToolApplicationData.h b/demoapps/DoseTool/DoseToolApplicationData.h index 66dc12d..c08a790 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.h +++ b/demoapps/DoseTool/DoseToolApplicationData.h @@ -1,76 +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: 1070 $ (last changed revision) // @date $Date: 2015-08-19 14:50:28 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #ifndef __DOSETOOL_APPLICATION_DATA_H #define __DOSETOOL_APPLICATION_DATA_H #include #include "rttbDoseAccessorInterface.h" #include "rttbStructureSetGeneratorInterface.h" #include "DoseToolCmdLineParser.h" namespace rttb { namespace apps { namespace doseTool { /*! @class ApplicationData @brief Class for storing all relevant variables needed in DoseTool */ class ApplicationData { public: /**Vector of arguments used to specify the loading style (always the first argument) * and, if needed, additional arguments for the specified loading style (e.g. location of the * Virtuos plan file for the Virtuos IO style). */ typedef std::vector LoadingStyleArgType; core::DoseAccessorInterface::DoseAccessorPointer _dose; core::StructureSetGeneratorInterface::StructureSetPointer _struct; std::string _structNameRegex; std::string _structNameActual; unsigned int _structIndex; std::string _doseFileName; std::string _structFileName; LoadingStyleArgType _doseLoadStyle; LoadingStyleArgType _structLoadStyle; bool _computeComplexDoseStatistics; DoseTypeGy _prescribedDose; - std::string _outputFileName; + std::string _doseStatisticOutputFileName; bool _allowSelfIntersection; + bool _computeDVH; + bool _computeDoseStatistics; + std::string _dvhOutputFilename; /*! @brief Resets the variables. _prescribedDose is set to 1.0 because it produces no exception then (as it is not needed). Consistency checks are done in DoseToolCmdLineParser::validateInput() */ void reset(); ApplicationData(); }; /*! @brief Reads the necessary arguments from the DoseToolCmdLineParser and writes them in the respective variables of ApplicationData. */ void populateAppData(boost::shared_ptr argParser, ApplicationData& appData); - } } } #endif diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.cpp b/demoapps/DoseTool/DoseToolCmdLineParser.cpp index afffdc8..b859756 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.cpp +++ b/demoapps/DoseTool/DoseToolCmdLineParser.cpp @@ -1,158 +1,174 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #include "DoseToolCmdLineParser.h" namespace rttb { namespace apps { namespace doseTool { DoseToolCmdLineParser::DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version) : CmdLineParserBase(name, version) { typedef double DoseTypeGy; addOption(OPTION_DOSE_FILE, OPTION_GROUP_REQUIRED, "The name of the dose file. Can be omitted if used as " "positional argument (see above).", 'd', true); addOption(OPTION_STRUCT_FILE, OPTION_GROUP_REQUIRED, "The name of the struct file. Can be omitted if used as " "positional argument (see above).", 's', true); - addOptionWithDefaultValue(OPTION_OUTPUT_FILE, OPTION_GROUP_REQUIRED, - "The name of the output file. Can be omitted if used as " - "positional argument (see above).", "output.xml", "output.xml", 'o', true); addOptionWithDefaultValue(OPTION_STRUCT_NAME, OPTION_GROUP_REQUIRED, "The name of the struct as regular expression. Can be omitted if used as " "positional argument or with itk struct loadingStyle (see above).", "", "", 'n', true); addPositionalOption(OPTION_DOSE_FILE, 1); addPositionalOption(OPTION_STRUCT_FILE, 1); addPositionalOption(OPTION_STRUCT_NAME, 1); - addPositionalOption(OPTION_OUTPUT_FILE, 1); + addPositionalOption(OPTION_DOSE_STATISTICS, 1); std::vector defaultLoadingStyle; defaultLoadingStyle.push_back("dicom"); addOptionWithDefaultValue >(OPTION_DOSE_LOAD_STYLE, OPTION_GROUP_REQUIRED, "The loading style for the dose. Available styles are:\n" "\"dicom\": normal dicom dose\n" - "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle virtuos myFavorite.pln\")\n" + "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--" + + OPTION_DOSE_LOAD_STYLE + " virtuos myFavorite.pln\")\n" "\"itk\": use itk image loading\n\"helax\": load a helax dose (choosing this style, the dose path should only be a directory).", defaultLoadingStyle, defaultLoadingStyle.at(0), 't', true, true); addOptionWithDefaultValue >(OPTION_STRUCT_LOAD_STYLE, OPTION_GROUP_REQUIRED, "The loading style for the dose. Available styles are:\n" "\"dicom\": normal dicom dose\n" - "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle virtuos myFavorite.pln\")\n" + "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--" + + OPTION_DOSE_LOAD_STYLE + " virtuos myFavorite.pln\")\n" "\"itk\": use itk image loading.", defaultLoadingStyle, defaultLoadingStyle.at(0), 'u', true, true); + addOption(OPTION_DOSE_STATISTICS, OPTION_GROUP_OPTIONAL, + "If dose statistics should be computed. The argument is the output file. Can be omitted if used as " + "positional argument (see above).", 'y'); + + addOption(OPTION_DVH, OPTION_GROUP_OPTIONAL, + "If the DVH should be computed. The argument is the output file", 'z'); + addOption(OPTION_COMPLEX_STATISTICS, OPTION_GROUP_OPTIONAL, "If the complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) should be computed.", 'x'); addOption(OPTION_PRESCRIBED_DOSE, OPTION_GROUP_OPTIONAL, "The prescribed dose in Gy.", 'p'); addOption(OPTION_ALLOW_SELF_INTERSECTION_STRUCT, OPTION_GROUP_OPTIONAL, "If a struct file contains self intersecting contours: Allow the processing of these structures and ignore potential problems." "WARNING: only use this parameter if you know what you are doing.", 'a'); parse(argc, argv); } void DoseToolCmdLineParser::validateInput() const { std::vector doseLoadStyle = get >(OPTION_DOSE_LOAD_STYLE); std::string doseLoadStyleAbbreviation = doseLoadStyle.at(0); if (doseLoadStyleAbbreviation != "dicom" && doseLoadStyleAbbreviation != "virtuos" && doseLoadStyleAbbreviation != "itk" && doseLoadStyleAbbreviation != "helax") { throw cmdlineparsing::InvalidConstraintException("Unknown load style for dose file:" + doseLoadStyleAbbreviation + ".\nPlease refer to the help for valid loading style settings."); } if (doseLoadStyleAbbreviation == "virtuos") { if (doseLoadStyle.size() < 2) { throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io style argument."); } } std::vector structLoadStyle = get >(OPTION_STRUCT_LOAD_STYLE); std::string structLoadStyleAbbreviation = structLoadStyle.at(0); if (structLoadStyleAbbreviation != "dicom" && structLoadStyleAbbreviation != "virtuos" && structLoadStyleAbbreviation != "itk") { throw cmdlineparsing::InvalidConstraintException("Unknown load style for struct file:" + structLoadStyleAbbreviation + ".\nPlease refer to the help for valid loading style settings."); } if (structLoadStyleAbbreviation == "dicom" || structLoadStyleAbbreviation == "virtuos" || structLoadStyleAbbreviation == "helax") { if (get(OPTION_STRUCT_NAME) == "") { - throw cmdlineparsing::InvalidConstraintException("The struct name (--name) has to be defined for dicom, virtuos or helax struct files."); + throw cmdlineparsing::InvalidConstraintException("The struct name (--" + OPTION_STRUCT_NAME + + ") has to be defined for dicom, virtuos or helax struct files."); } } if (structLoadStyleAbbreviation == "virtuos") { if (structLoadStyle.size() < 2) { throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos struct file. CTX file is missing. Specify CTX file as 2nd io style argument."); } } - if (isSet(OPTION_COMPLEX_STATISTICS)) + if (!isSet(OPTION_DVH) && !isSet(OPTION_DOSE_STATISTICS)) + { + throw cmdlineparsing::InvalidConstraintException("Neither the Dose statistics (--" + OPTION_DOSE_STATISTICS + + "), nor the DVH (--" + OPTION_DVH + ") option was used."); + } + + if (isSet(OPTION_DOSE_STATISTICS) && isSet(OPTION_COMPLEX_STATISTICS)) { if (!isSet(OPTION_PRESCRIBED_DOSE)) { - throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--prescribedDose) has to be set for computation of complex dose statistics."); + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + ") has to be set for computation of complex dose statistics."); } else { if (get(OPTION_PRESCRIBED_DOSE) <= 0) { - throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--prescribedDose) has to be >0!"); + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + ") has to be >0!"); } } } } void DoseToolCmdLineParser::printHelp() const { cmdlineparsing::CmdLineParserBase::printHelp(); std::cout << "Example:" << std::endl << std::endl; std::cout << m_programName << - " dose.dcm struct.dcm Liver result.xml" << + " dose.dcm struct.dcm Liver result.xml --" + OPTION_DVH + " dvh.xml" << std::endl << std::endl; std::cout << - "This will calculate the Dose statistic for liver using \"dose.dcm\" and the struct file \"struct.dcm\" and will write the result to \"result.xml\". " + "This will calculate the Dose statistic for liver using \"dose.dcm\" and the struct file \"struct.dcm\" and will write the dose statistics to \"result.xml\". " + " The DVH is computed as well, its values are written to \"dvh.xml\". " << std::endl; } } } } diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.h b/demoapps/DoseTool/DoseToolCmdLineParser.h index 2c4a319..37fb40a 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.h +++ b/demoapps/DoseTool/DoseToolCmdLineParser.h @@ -1,63 +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: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #ifndef __DOSETOOL_CMD_LINE_PARSER #define __DOSETOOL_CMD_LINE_PARSER #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace doseTool { /*! @class BioModelCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class DoseToolCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version); void validateInput() const; void printHelp() const; // Option groups const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; // Parameters const std::string OPTION_DOSE_FILE = "doseFile"; const std::string OPTION_STRUCT_FILE = "structFile"; const std::string OPTION_STRUCT_NAME = "structName"; - const std::string OPTION_OUTPUT_FILE = "outputFile"; + const std::string OPTION_DOSE_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"; }; } } } #endif \ No newline at end of file diff --git a/demoapps/DoseTool/DoseToolHelper.cpp b/demoapps/DoseTool/DoseToolHelper.cpp index 09a9a09..70821ea 100644 --- a/demoapps/DoseTool/DoseToolHelper.cpp +++ b/demoapps/DoseTool/DoseToolHelper.cpp @@ -1,260 +1,294 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1095 $ (last changed revision) // @date $Date: 2015-09-11 11:12:40 +0200 (Fr, 11 Sep 2015) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include "DoseToolHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "boost/property_tree/ptree.hpp" #include "rttbExceptionMacros.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbStructureSetGeneratorInterface.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" +#include "rttbDVHCalculator.h" +#include "rttbDVHXMLFileWriter.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbVOIindexIdentifier.h" rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args) { rttb::core::DoseAccessorInterface::DoseAccessorPointer result; std::cout << std::endl << "read dose file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomDose(fileName); } else if (args[0] == "helax") { std::cout << "use RTTB Helax IO... "; result = loadHelaxDose(fileName); } else if (args[0] == "itk") { std::cout << "use RTTB itk IO... "; result = loadITKDose(fileName); } else if (args[0] == "virtuos") { if (args.size() < 2) { rttbDefaultExceptionStaticMacro( << "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); } std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos plan file: " << args[1] << " ... "; result = loadVirtuosDose(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDicomDose(const std::string& fileName) { rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadHelaxDose(const std::string& path) { rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadITKDose(const std::string& fileName) { rttb::io::itk::ITKImageFileAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) { rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); return generator.generateDoseAccessor(); }; rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadStruct( const std::string& fileName, const ApplicationData::LoadingStyleArgType& args) { rttb::core::StructureSetGeneratorInterface::StructureSetPointer result; std::cout << std::endl << "read struct file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomStruct(fileName); } else if (args[0] == "virtuos") { std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos CTX file: " << args[1] << " ... "; result = loadVirtuosStruct(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; } rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadDicomStruct( const std::string& fileName) { rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); return generator.generateStructureSet(); } rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadVirtuosStruct( const std::string& fileName, const std::string& ctxFileName) { rttb::io::virtuos::VirtuosFileStructureSetGenerator generator(fileName, ctxFileName.c_str()); return generator.generateStructureSet(); } void rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) { std::cout << std::endl << "generating mask... "; core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr = generateMask(appData); core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator(maskAccessorPtr, appData._dose)); std::cout << "done." << std::endl; - std::cout << std::endl << "computing dose statistics... "; - algorithms::DoseStatistics::DoseStatisticsPointer statistics = calculateDoseStatistics(spDoseIterator, - appData._computeComplexDoseStatistics, appData._prescribedDose); - std::cout << "done." << std::endl; + if (appData._computeDoseStatistics) + { + std::cout << std::endl << "computing dose statistics... "; + algorithms::DoseStatistics::DoseStatisticsPointer statistics = calculateDoseStatistics(spDoseIterator, + appData._computeComplexDoseStatistics, appData._prescribedDose); + std::cout << "done." << std::endl; + + std::cout << std::endl << "writing dose statistics to file... "; + writeDoseStatisticsFile(statistics, appData); + std::cout << "done." << std::endl; + } - std::cout << std::endl << "writing dose statistics to file... "; - writeDoseStatisticsFile(statistics, appData); - std::cout << "done." << std::endl; + if (appData._computeDVH) + { + std::cout << std::endl << "computing DVH... "; + core::DVH::DVHPointer dvh = calculateDVH(spDoseIterator, appData._struct->getUID(), appData._dose->getUID()); + std::cout << "done." << std::endl; + + std::cout << std::endl << "writing DVH to file... "; + writeDVHFile(dvh, appData._dvhOutputFilename); + std::cout << "done." << std::endl; + + } }; void rttb::apps::doseTool::determineStructIndex(rttb::apps::doseTool::ApplicationData& appData) { unsigned int index = rttb::masks::VOIindexIdentifier::getIndexByVoiName(appData._struct, appData._structNameRegex); appData._structIndex = index; appData._structNameActual = appData._struct->getStructure(index)->getLabel(); } rttb::core::MaskAccessorInterface::MaskAccessorPointer rttb::apps::doseTool::generateMask( rttb::apps::doseTool::ApplicationData& appData) { core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr; if (appData._structLoadStyle.front() == "itk") { maskAccessorPtr = rttb::io::itk::ITKImageFileMaskAccessorGenerator(appData._structFileName).generateMaskAccessor(); } else { determineStructIndex(appData); bool strict = !appData._allowSelfIntersection; maskAccessorPtr = boost::make_shared (appData._struct->getStructure(appData._structIndex), appData._dose->getGeometricInfo(), strict); } maskAccessorPtr->updateMask(); return maskAccessorPtr; } rttb::core::DoseIteratorInterface::DoseIteratorPointer rttb::apps::doseTool::generateMaskedDoseIterator( rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr) { boost::shared_ptr maskedDoseIterator = boost::make_shared(maskAccessorPtr, doseAccessorPtr); rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator(maskedDoseIterator); return doseIterator; } rttb::algorithms::DoseStatistics::DoseStatisticsPointer rttb::apps::doseTool::calculateDoseStatistics( core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, DoseTypeGy prescribedDose) { rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); if (calculateComplexDoseStatistics) { return doseStatsCalculator.calculateDoseStatistics(prescribedDose); } else { return doseStatsCalculator.calculateDoseStatistics(); } } + +rttb::core::DVH::DVHPointer rttb::apps::doseTool::calculateDVH(core::DoseIteratorInterface::DoseIteratorPointer + doseIterator, IDType structUID, IDType doseUID) +{ + rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); + rttb::core::DVH::DVHPointer dvh = calc.generateDVH(); + return dvh; +} + + void rttb::apps::doseTool::writeDoseStatisticsFile(rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, rttb::apps::doseTool::ApplicationData& appData) { boost::property_tree::ptree originalTree = rttb::io::other::writeDoseStatistics(statistics); //add config part to xml originalTree.add("statistics.config.requestedStructRegex", appData._structNameRegex); originalTree.add("statistics.config.structName", appData._structNameActual); originalTree.add("statistics.config.doseUID", appData._dose->getUID()); originalTree.add("statistics.config.doseFile", appData._doseFileName); originalTree.add("statistics.config.structFile", appData._structFileName); boost::property_tree::ptree reorderedTree, configTree, resultsTree; configTree = originalTree.get_child("statistics.config"); resultsTree = originalTree.get_child("statistics.results"); reorderedTree.add_child("statistics.config", configTree); reorderedTree.add_child("statistics.results", resultsTree); - boost::property_tree::write_xml(appData._outputFileName, reorderedTree, std::locale(), + boost::property_tree::write_xml(appData._doseStatisticOutputFileName, reorderedTree, std::locale(), boost::property_tree::xml_writer_make_settings('\t', 1)); } + +void rttb::apps::doseTool::writeDVHFile(core::DVH::DVHPointer dvh, const std::string& filename) +{ + DVHType typeCum = { DVHType::Cumulative }; + rttb::io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); + dvhWriter.writeDVH(dvh); +} diff --git a/demoapps/DoseTool/DoseToolHelper.h b/demoapps/DoseTool/DoseToolHelper.h index b81a178..549c03f 100644 --- a/demoapps/DoseTool/DoseToolHelper.h +++ b/demoapps/DoseTool/DoseToolHelper.h @@ -1,118 +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: 1066 $ (last changed revision) // @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) // @author $Author: floca $ (last changed by) */ #ifndef __DOSETOOL_HELPER_H #define __DOSETOOL_HELPER_H #include "DoseToolApplicationData.h" #include "rttbDoseAccessorInterface.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "rttbDoseStatistics.h" +#include "rttbDVH.h" namespace rttb { namespace apps { namespace doseTool { /*! @brief loads a dose from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails */ core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); /*! @brief loads a helax dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomHelaxFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); /*! @brief loads an itk dose from a file. @exception Throws an rttb::Exception if loading fails. @details Might be of all formats that ITK know (*.mhd, *.nrrd, ...). The absolute image values are taken as dose. @sa ITKImageFileAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); /*! @brief loads a virtuos dose from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, const std::string& planFileName); /*! @brief loads a struct from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails @details voxelized itk images are read in generateMask() directly */ core::StructureSetGeneratorInterface::StructureSetPointer loadStruct(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom struct from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileStructureSetGenerator */ core::StructureSetGeneratorInterface::StructureSetPointer loadDicomStruct(const std::string& fileName); /*! @brief loads a virtuos struct from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ core::StructureSetGeneratorInterface::StructureSetPointer loadVirtuosStruct(const std::string& fileName, const std::string& ctxFileName); /*! @brief Contains the business logic of processing all information to calculate the dose statistics and writing them to an xml file. @details Uses appData for the input data and the correct configuration. */ void processData(ApplicationData& appData); /*! @brief Searches for the struct index based on the regex */ void determineStructIndex(ApplicationData& appData); /*! @brief Generates a mask from the struct file by using the boostAccessor. In case of itk image, it directly loads the voxelized image. */ core::MaskAccessorInterface::MaskAccessorPointer generateMask(ApplicationData& appData); algorithms::DoseStatistics::DoseStatisticsPointer calculateDoseStatistics( core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, DoseTypeGy prescribedDose); + core::DVH::DVHPointer calculateDVH(core::DoseIteratorInterface::DoseIteratorPointer doseIterator, IDType structUID, + IDType doseUID); + /*! @brief Writes the dose statistics as XML to a file @details adds a .... part to the RTTB generated xml where the used files and struct names are stored. */ void writeDoseStatisticsFile(algorithms::DoseStatistics::DoseStatisticsPointer statistics, rttb::apps::doseTool::ApplicationData& appData); + void writeDVHFile(core::DVH::DVHPointer dvh, const std::string& filename); + core::DoseIteratorInterface::DoseIteratorPointer generateMaskedDoseIterator( core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr); } } } #endif diff --git a/testing/demoapps/DoseTool/CMakeLists.txt b/testing/demoapps/DoseTool/CMakeLists.txt index 535caf0..defc702 100644 --- a/testing/demoapps/DoseTool/CMakeLists.txt +++ b/testing/demoapps/DoseTool/CMakeLists.txt @@ -1,32 +1,34 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(DOSETOOL_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbDoseToolTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- IF(MSVC) ADD_DEFINITIONS(/bigobj) ENDIF() ADD_TEST(DoseToolBasicUsageTest ${DOSETOOL_TEST} DoseToolBasicUsageTest) ADD_TEST(DoseToolInvalidParametersTest ${DOSETOOL_TEST} DoseToolInvalidParametersTest) ADD_TEST(DoseToolVirtuosDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolVirtuosDoseTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "DARM" "${TEST_DATA_ROOT}/DoseStatistics/virtuos.xml" "${TEST_DATA_ROOT}/DoseStatistics/virtuosComplex.xml") ADD_TEST(DoseToolDicomDoseDicomStructTest ${DOSETOOL_TEST} DoseToolDicomDoseTest "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "Nodes" -"${TEST_DATA_ROOT}/DoseStatistics/dicom.xml" "${TEST_DATA_ROOT}/DoseStatistics/dicomComplex.xml") +"${TEST_DATA_ROOT}/DoseStatistics/dicom.xml" "${TEST_DATA_ROOT}/TestDVH/dicompylerDVH.xml" "${TEST_DATA_ROOT}/DoseStatistics/dicomComplex.xml") ADD_TEST(DoseToolITKDoseDicomStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/dicompylerTestDose.mhd" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "" "Nodes" "${TEST_DATA_ROOT}/DoseStatistics/itkDicomStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkDicomStructComplex.xml") ADD_TEST(DoseToolITKDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolITKDoseTest "${TEST_DATA_ROOT}/ITK/virtuosTestDose.mhd" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "DARM" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStruct.xml" "${TEST_DATA_ROOT}/DoseStatistics/itkVirtuosStructComplex.xml") +ADD_TEST(DoseToolDVHTest ${DOSETOOL_TEST} DoseToolDVHTest "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "Nodes" +"${TEST_DATA_ROOT}/TestDVH/dicompylerDVH.xml") RTTB_CREATE_APPLICATION_TESTS(DoseTool PACKAGE_DEPENDS Litmus BoostBinaries) diff --git a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolDVHTest.cpp similarity index 57% copy from testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp copy to testing/demoapps/DoseTool/DoseToolDVHTest.cpp index afd2c0e..d28b7ee 100644 --- a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDVHTest.cpp @@ -1,135 +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: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" -#include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); - int DoseToolDicomDoseTest(int argc, char* argv[]) + int DoseToolDVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const std::string doseToolExe = "DoseTool.exe"; std::string doseFilename; std::string planFilename; std::string structFilename; - std::string ctxFilename; std::string structName; std::string referenceXMLFilename; - std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; - if (argc > 5) + if (argc > 4) { doseFilename = argv[1]; structFilename = argv[2]; structName = argv[3]; referenceXMLFilename = argv[4]; - referenceXMLComplexFilename = argv[5]; } - std::string defaultOutputFilename = "dicomOutput.xml"; - std::string complexOutputFilename = "dicomOutputComplex.xml"; + std::string defaultOutputFilename = "dicomDVHOutput.xml"; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } - std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; - std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; - CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); - - std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; - //prescribed dose is 14 Gy - complexDoseStatisticsCommand += " -x -p 14"; - - std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; - CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); + 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); - CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); - //add doseFile and structFile - std::string emptyDoseFileTag = ""; - std::string validDoseFileTag = "" + doseFilename + ""; - boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); - - std::string emptyStructFileTag = ""; - std::string validStructFileTag = "" + structFilename + ""; - boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); - //add doseFile and structFile - std::string complexAsIs = readFile(complexOutputFilename); - std::string complexExpected = readFile(referenceXMLComplexFilename); - - boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); - boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); - - CHECK_EQUAL(complexAsIs, complexExpected); - //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); - CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp index afd2c0e..330ca6a 100644 --- a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp @@ -1,135 +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: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolDicomDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const std::string doseToolExe = "DoseTool.exe"; std::string doseFilename; std::string planFilename; std::string structFilename; std::string ctxFilename; std::string structName; std::string referenceXMLFilename; + std::string referenceDVHXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; - if (argc > 5) + if (argc > 6) { doseFilename = argv[1]; structFilename = argv[2]; structName = argv[3]; referenceXMLFilename = argv[4]; - referenceXMLComplexFilename = argv[5]; + referenceDVHXMLFilename = argv[5]; + referenceXMLComplexFilename = argv[6]; } std::string defaultOutputFilename = "dicomOutput.xml"; + std::string defaultDVHOutputFilename = "dicomDVHOutput.xml"; std::string complexOutputFilename = "dicomOutputComplex.xml"; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } - std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); - std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + 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 += " -x -p 14"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); + CHECK_EQUAL(boost::filesystem::exists(defaultDVHOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); + std::string defaultDVHAsIs = readFile(defaultDVHOutputFilename); + std::string defaultDVHExpected = readFile(referenceDVHXMLFilename); + CHECK_EQUAL(defaultDVHAsIs, defaultDVHExpected); + //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); + CHECK_EQUAL(std::remove(defaultDVHOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp index 98f0045..3a42ac7 100644 --- a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp @@ -1,142 +1,142 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolITKDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const std::string doseToolExe = "DoseTool.exe"; std::string doseFilename; std::string planFilename; std::string structFilename; std::string ctxFilename; std::string structName; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; if (argc > 6) { doseFilename = argv[1]; structFilename = argv[2]; ctxFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; referenceXMLComplexFilename = argv[6]; } std::string defaultOutputFilename = "itkOutput.xml"; std::string complexOutputFilename = "itkOutputComplex.xml"; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; baseCommand += " -t itk "; if (structName != "") { baseCommand += " -n " + structName; if (ctxFilename != "") { baseCommand += " -u virtuos " + ctxFilename; } } else { baseCommand += " -u itk "; } - std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); - std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 14 Gy complexDoseStatisticsCommand += " -x -p 14"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp index 6a68a8a..c8c530c 100644 --- a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp @@ -1,97 +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: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseToolInvalidParametersTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const std::string doseToolExe = "DoseTool.exe"; boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; //call with too few parameters std::string toofewParametersCommand = voxelizerToolExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -s test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); toofewParametersCommand = voxelizerToolExeWithPath; toofewParametersCommand += " -s test"; toofewParametersCommand += " -n test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); toofewParametersCommand = voxelizerToolExeWithPath; toofewParametersCommand += " test"; toofewParametersCommand += " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); + toofewParametersCommand = voxelizerToolExeWithPath; + toofewParametersCommand += " -d test"; + toofewParametersCommand += " -s test"; + toofewParametersCommand += " -n test"; + std::cout << "Command line call: " + toofewParametersCommand << std::endl; + CHECK_EQUAL(system(toofewParametersCommand.c_str()), -1); + //call with invalid dose load option std::string minimalCLI = voxelizerToolExeWithPath + " test test test "; std::string invalidDoseLoadOption = minimalCLI; invalidDoseLoadOption += "-t wrongOption"; std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidDoseLoadOption.c_str()), -1); //call with invalid struct load option std::string invalidStructLoadOption = minimalCLI; invalidStructLoadOption += "-u wrongOption"; std::cout << "Command line call: " + invalidStructLoadOption << std::endl; CHECK_EQUAL(system(invalidStructLoadOption.c_str()), -1); //call with virtuos dose load option, but without plan/ctx std::string invalidVirtuosDoseLoadOption = minimalCLI; invalidVirtuosDoseLoadOption += "-u virtuos"; std::cout << "Command line call: " + invalidVirtuosDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidVirtuosDoseLoadOption.c_str()), -1); std::string invalidVirtuosStructLoadOption = minimalCLI; invalidVirtuosStructLoadOption += "-t virtuos"; std::cout << "Command line call: " + invalidVirtuosStructLoadOption << std::endl; CHECK_EQUAL(system(invalidVirtuosStructLoadOption.c_str()), -1); //call with complex dose statistics, but without prescribed dose std::string complexDoseWithoutPrescribedDoseCommand = minimalCLI; complexDoseWithoutPrescribedDoseCommand += "-x"; std::cout << "Command line call: " + complexDoseWithoutPrescribedDoseCommand << std::endl; CHECK_EQUAL(system(complexDoseWithoutPrescribedDoseCommand.c_str()), -1); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolTests.cpp b/testing/demoapps/DoseTool/DoseToolTests.cpp index cbafbad..28444e0 100644 --- a/testing/demoapps/DoseTool/DoseToolTests.cpp +++ b/testing/demoapps/DoseTool/DoseToolTests.cpp @@ -1,71 +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: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called registerTests() #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { const char* _callingAppPath = NULL; void registerTests() { LIT_REGISTER_TEST(DoseToolBasicUsageTest); LIT_REGISTER_TEST(DoseToolInvalidParametersTest); LIT_REGISTER_TEST(DoseToolVirtuosDoseTest); LIT_REGISTER_TEST(DoseToolDicomDoseTest); LIT_REGISTER_TEST(DoseToolITKDoseTest); + 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/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp index 42b8b57..b8dd14c 100644 --- a/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp @@ -1,130 +1,130 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 771 $ (last changed revision) // @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolVirtuosDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const std::string doseToolExe = "DoseTool.exe"; std::string doseFilename; std::string planFilename; std::string structFilename; std::string ctxFilename; std::string structName; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExe; if (argc > 7) { doseFilename = argv[1]; planFilename = argv[2]; structFilename = argv[3]; ctxFilename = argv[4]; structName = argv[5]; referenceXMLFilename = argv[6]; referenceXMLComplexFilename = argv[7]; } std::string defaultOutputFilename = "virtuosOutput.xml"; std::string complexOutputFilename = "virtuosOutputComplex.xml"; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -t virtuos " + planFilename; baseCommand += " -s " + structFilename; baseCommand += " -u virtuos " + ctxFilename; baseCommand += " -n " + structName; - std::string defaultDoseStatisticsCommand = baseCommand + " -o " + defaultOutputFilename; + std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); - std::string complexDoseStatisticsCommand = baseCommand + " -o " + complexOutputFilename; + std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 50 Gy complexDoseStatisticsCommand += " -x -p 50"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/files.cmake b/testing/demoapps/DoseTool/files.cmake index 7bf5153..353a71a 100644 --- a/testing/demoapps/DoseTool/files.cmake +++ b/testing/demoapps/DoseTool/files.cmake @@ -1,11 +1,12 @@ SET(CPP_FILES DoseToolBasicUsageTest.cpp DoseToolInvalidParametersTest.cpp DoseToolVirtuosDoseTest.cpp DoseToolDicomDoseTest.cpp DoseToolITKDoseTest.cpp + DoseToolDVHTest.cpp DoseToolTests.cpp ) SET(H_FILES )