diff --git a/cmake/RemoveTemporaryFiles.cmake.in b/cmake/RemoveTemporaryFiles.cmake.in index 5e2d77e..9ea06df 100644 --- a/cmake/RemoveTemporaryFiles.cmake.in +++ b/cmake/RemoveTemporaryFiles.cmake.in @@ -1,22 +1,22 @@ # # Remove temporary files that are generated by build submissions, # cmake configure and testing # # Cleanup old dashboard submissions -FILE(GLOB OLD_DASHBOARDS "@RTToolbox_BINARY_DIR@/testing/20*") +FILE(GLOB OLD_DASHBOARDS "@RTToolbox_BINARY_DIR@/Testing/20*") FOREACH(OLD ${OLD_DASHBOARDS}) MESSAGE(" Removing old submission in ${OLD}") FILE(REMOVE_RECURSE "${OLD}") ENDFOREACH(OLD ${OLD_DASHBOARDS}) # Cleanup the Testing/Temporary directory -FILE(REMOVE_RECURSE "@RTToolbox_BINARY_DIR@/Testing/Temporary") +FILE(REMOVE_RECURSE "@RTToolbox_BINARY_DIR@/Testing/temporary") # Cleanup the CMake Error and Output logs FILE(REMOVE "@RTToolbox_BINARY_DIR@${CMAKE_FILES_DIRECTORY}/CMakeOutput.log") FILE(REMOVE "@RTToolbox_BINARY_DIR@${CMAKE_FILES_DIRECTORY}/CMakeOutput.log") FILE(REMOVE "@RTToolbox_BINARY_DIR@/CMakeOutput.log") FILE(REMOVE "@RTToolbox_BINARY_DIR@${CMAKE_FILES_DIRECTORY}/CMakeError.log") FILE(REMOVE "@RTToolbox_BINARY_DIR@${CMAKE_FILES_DIRECTORY}/CMakeError.log") FILE(REMOVE "@RTToolbox_BINARY_DIR@/CMakeError.log") diff --git a/code/algorithms/rttbDoseStatistics.h b/code/algorithms/rttbDoseStatistics.h index ab60b42..d57f62e 100644 --- a/code/algorithms/rttbDoseStatistics.h +++ b/code/algorithms/rttbDoseStatistics.h @@ -1,218 +1,218 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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 "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" namespace rttb { namespace algorithms { /*! @class DoseStatistics @brief This is a data class storing different statistical values from a rt dose distribution @sa DoseStatisticsCalculator */ class DoseStatistics { public: enum complexStatistics { Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx }; typedef boost::shared_ptr > > ResultListPointer; typedef boost::shared_ptr DoseStatisticsPointer; typedef std::map DoseToVolumeFunctionType; typedef std::map VolumeToDoseFunctionType; 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 _maximum; DoseStatisticType _minimum; ResultListPointer _maximumVoxelPositions; ResultListPointer _minimumVoxelPositions; DoseStatisticType _mean; DoseStatisticType _stdDeviation; unsigned int _numVoxels; VolumeType _volume; DoseTypeGy _referenceDose; //for Vx computation VolumeToDoseFunctionType _Dx; DoseToVolumeFunctionType _Vx; VolumeToDoseFunctionType _MOHx; VolumeToDoseFunctionType _MOCx; VolumeToDoseFunctionType _MaxOHx; VolumeToDoseFunctionType _MinOCx; - + public: /*! @brief Standard Constructor */ //DoseStatistics(); /*! @brief Constructor @detail 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, unsigned int numVoxels, VolumeType volume, ResultListPointer minimumVoxelPositions = boost::make_shared > > (std::vector >()), ResultListPointer maximumVoxelPositions = boost::make_shared > > (std::vector >()), VolumeToDoseFunctionType Dx = VolumeToDoseFunctionType(), DoseToVolumeFunctionType Vx = DoseToVolumeFunctionType(), VolumeToDoseFunctionType MOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MOCx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MaxOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MinOCx = VolumeToDoseFunctionType(), - DoseTypeGy referenceDose = -1); + DoseTypeGy referenceDose = -1); ~DoseStatistics(); void setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions); void setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions); void setDx(const DoseToVolumeFunctionType& DxValues); void setVx(const VolumeToDoseFunctionType& VxValues); void setMOHx(const VolumeToDoseFunctionType& MOHxValues); void setMOCx(const VolumeToDoseFunctionType& MOCxValues); void setMaxOHx(const VolumeToDoseFunctionType& MaxOHxValues); void setMinOCx(const VolumeToDoseFunctionType& MinOCxValues); void setReferenceDose(DoseTypeGy referenceDose); /*! @brief Get number of voxels in doseIterator, with sub-voxel accuracy. */ unsigned int 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 getMaximumPositions() 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 getMinimumPositions() 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; /*! @brief Get Vx: the volume irradiated with a dose >= x. @return Return absolute volume in absolute cm^3. @exception NoDataException if the Vx values have not been set (i.e. the vector is empty) @exception NoDataException if the requested Dose is not in the vector */ VolumeType getVx(DoseTypeGy xDoseAbsolute) const; VolumeType getVx(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const; DoseToVolumeFunctionType getAllVx() const; /*! @brief Get Dx: the minimal dose delivered to part x of the current volume. @return Return dose value in Gy. @exception InvalidDoseException if the Dx values have not been set (i.e. the vector is empty) */ DoseTypeGy getDx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getDx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllDx() const; /*! @brief Get MOHx: mean dose of the hottest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMOHx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMOHx() const; /*! @brief Get MOCx: mean dose of the coldest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMOCx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMOCx() const; /*! @brief Get MaxOHx: Maximum outside of the hottest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMaxOHx() const; /*! @brief Get MinOCx: Minimum outside of the coldest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMinOCx() const; }; } } #endif diff --git a/code/masks/rttbVOIindexIdentifier.cpp b/code/masks/rttbVOIindexIdentifier.cpp index e637510..ccb1f6c 100644 --- a/code/masks/rttbVOIindexIdentifier.cpp +++ b/code/masks/rttbVOIindexIdentifier.cpp @@ -1,100 +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: // @date $Date: // @author $Author: */ #include "rttbVOIindexIdentifier.h" #include #include "rttbExceptionMacros.h" namespace rttb { namespace masks { const std::vector VOIindexIdentifier::getIndicesByVoiRegex(StructSetTypePointer spStructSet, const std::string& nameAsRegEx) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL"); } std::vector voiLabelList; std::vector resultVOiIndices; + boost::regex e(nameAsRegEx); for (int i = 0; i < spStructSet->getNumberOfStructures(); i++) { voiLabelList.push_back(spStructSet->getStructure(i)->getLabel()); - boost::regex e(nameAsRegEx); + std::string s = spStructSet->getStructure(i)->getLabel(); if (boost::regex_match(s, e)) { resultVOiIndices.push_back(i); } } return resultVOiIndices; } const unsigned int VOIindexIdentifier::getIndexByVoiName(StructSetTypePointer spStructSet, const std::string& name) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL"); } for (unsigned int i = 0; i < spStructSet->getNumberOfStructures(); i++) { if (spStructSet->getStructure(i)->getLabel() == name) { return i; } } rttbDefaultExceptionStaticMacro("no VOI was found with the given name"); } const std::string VOIindexIdentifier::getVoiNameByIndex(StructSetTypePointer spStructSet, unsigned int index) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL!"); } if (index >= spStructSet->getNumberOfStructures()) { rttbDefaultExceptionStaticMacro("invalid index, voiLabelList out of range"); } return spStructSet->getStructure(index)->getLabel(); } } } diff --git a/demoapps/DoseTool/DoseTool.cpp b/demoapps/DoseTool/DoseTool.cpp index cda4053..69bf3d3 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 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)) { 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 3036855..ffd75e9 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.cpp +++ b/demoapps/DoseTool/DoseToolApplicationData.cpp @@ -1,72 +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: 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 = ""; - _outputFileName = ""; + _doseStatisticOutputFileName = ""; _computeComplexDoseStatistics = false; _allowSelfIntersection = false; _structIndices.clear(); _structNames.clear(); _prescribedDose = 1.0; _multipleStructsMode = 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._multipleStructsMode = argParser->isSet(argParser->OPTION_MULTIPLE_STRUCTS_MODE); + + 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); - appData._multipleStructsMode = argParser->isSet(argParser->OPTION_MULTIPLE_STRUCTS_MODE); + + } + + if (argParser->isSet(argParser->OPTION_DVH)) + { + appData._computeDVH = true; + appData._dvhOutputFilename = argParser->get(argParser->OPTION_DVH); + } + - if (argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) + if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS) && argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) { appData._prescribedDose = argParser->get(argParser->OPTION_PRESCRIBED_DOSE); } } } } } diff --git a/demoapps/DoseTool/DoseToolApplicationData.h b/demoapps/DoseTool/DoseToolApplicationData.h index 9733d2e..bc79970 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.h +++ b/demoapps/DoseTool/DoseToolApplicationData.h @@ -1,77 +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: 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::vector _structIndices; std::vector _structNames; std::string _doseFileName; std::string _structFileName; LoadingStyleArgType _doseLoadStyle; LoadingStyleArgType _structLoadStyle; bool _computeComplexDoseStatistics; DoseTypeGy _prescribedDose; - std::string _outputFileName; + std::string _doseStatisticOutputFileName; bool _allowSelfIntersection; bool _multipleStructsMode; + 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 553316e..a13d78f 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.cpp +++ b/demoapps/DoseTool/DoseToolCmdLineParser.cpp @@ -1,161 +1,177 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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'); addOption(OPTION_MULTIPLE_STRUCTS_MODE, OPTION_GROUP_OPTIONAL, "If the regex agrees with multiple structs: write a dose statistic for every struct file." "The struct name will be appended to the chosen output filename.", 'm'); 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 d569c84..b7e86d9 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.h +++ b/demoapps/DoseTool/DoseToolCmdLineParser.h @@ -1,64 +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: 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"; const std::string OPTION_MULTIPLE_STRUCTS_MODE = "multipleStructsMode"; }; } } } #endif \ No newline at end of file diff --git a/demoapps/DoseTool/DoseToolHelper.cpp b/demoapps/DoseTool/DoseToolHelper.cpp index ea192a3..66f5dc6 100644 --- a/demoapps/DoseTool/DoseToolHelper.cpp +++ b/demoapps/DoseTool/DoseToolHelper.cpp @@ -1,302 +1,347 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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 "boost/filesystem.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 masks... "; std::vector maskAccessorPtrVector = generateMasks(appData); + std::cout << "done." << std::endl; for (int i = 0; i < maskAccessorPtrVector.size(); i++) { core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator(maskAccessorPtrVector.at(i), 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... "; + std::cout << std::endl << "writing dose statistics to file... "; + std::string outputFilename; - std::string outputFilename; + if (appData._multipleStructsMode) + { + outputFilename = assembleFilenameWithStruct(appData._doseStatisticOutputFileName, appData._structNames.at(i)); + } + else + { + outputFilename = appData._doseStatisticOutputFileName; + } - if (appData._multipleStructsMode) - { - outputFilename = assembleFilenameWithStruct(appData._outputFileName, appData._structNames.at(i)); + writeDoseStatisticsFile(statistics, outputFilename, appData._structNames.at(i), appData); + std::cout << "done." << std::endl; } - else + + if (appData._computeDVH) { - outputFilename = appData._outputFileName; - } + 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... "; + std::string outputFilename; + + if (appData._multipleStructsMode) + { + outputFilename = assembleFilenameWithStruct(appData._dvhOutputFilename, appData._structNames.at(i)); + } + else + { + outputFilename = appData._dvhOutputFilename; + } - writeDoseStatisticsFile(statistics, outputFilename, appData._structNames.at(i), appData); - std::cout << "done." << std::endl; + + writeDVHFile(dvh, outputFilename); + std::cout << "done." << std::endl; + } } -}; + +} std::vector rttb::apps::doseTool::generateMasks( rttb::apps::doseTool::ApplicationData& appData) { std::vector maskAccessorPtrVector; if (appData._structLoadStyle.front() == "itk") { maskAccessorPtrVector.push_back(rttb::io::itk::ITKImageFileMaskAccessorGenerator( appData._structFileName).generateMaskAccessor()); } else { std::vector foundIndices = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex(appData._struct, appData._structNameRegex); std::vector relevantIndices; if (appData._multipleStructsMode) { relevantIndices = foundIndices; } else { if (!foundIndices.empty()) { relevantIndices.push_back(foundIndices.front()); } } appData._structIndices = relevantIndices; bool strict = !appData._allowSelfIntersection; for (int i = 0; i < appData._structIndices.size(); i++) { maskAccessorPtrVector.push_back( boost::make_shared (appData._struct->getStructure(appData._structIndices.at(i)), appData._dose->getGeometricInfo(), strict)); maskAccessorPtrVector.at(i)->updateMask(); appData._structNames.push_back(appData._struct->getStructure(appData._structIndices.at(i))->getLabel()); } } return maskAccessorPtrVector; } 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, const std::string& filename, const std::string& structName, 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", structName); 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(filename, reorderedTree, std::locale(), boost::property_tree::xml_writer_make_settings('\t', 1)); } std::string rttb::apps::doseTool::assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName) { boost::filesystem::path originalFile(originalFilename); std::string newFilename = originalFile.stem().string() + "_" + structName + originalFile.extension().string(); boost::filesystem::path newFile(originalFile.parent_path() / newFilename); return newFile.string(); } + +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 25d1392..e5caf22 100644 --- a/demoapps/DoseTool/DoseToolHelper.h +++ b/demoapps/DoseTool/DoseToolHelper.h @@ -1,116 +1,122 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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 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); 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, const std::string& filename, const std::string& structName, 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); std::string assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName); } } } #endif diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index b2c068c..ecffee2 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -1,70 +1,70 @@ MESSAGE(STATUS "processing RTToolbox testing code") # Testing branch PROJECT(RTTBTesting) #----------------------------------------------------------------------------- # Find Litmus. #----------------------------------------------------------------------------- MESSAGE(STATUS "searching Litmus") FIND_PACKAGE(Litmus) IF(Litmus_FOUND) INCLUDE(${Litmus_USE_FILE}) SET(ADDITIONAL_TEST_INCLUDES ${Litmus_USE_FILE}) ELSE(Litmus_FOUND) MESSAGE(FATAL_ERROR "Cannot build without Litmus. Please set Litmus_DIR.") ENDIF(Litmus_FOUND) #----------------------------------------------------------------------------- # Configure Testing branch #----------------------------------------------------------------------------- -MAKE_DIRECTORY(${RTTBTesting_BINARY_DIR}/temporary) +MAKE_DIRECTORY(${RTTBTesting_BINARY_DIR}/Temporary) MESSAGE(STATUS "Process All Tests...") #----------------------------------------------------------------------------- # Include sub directories #----------------------------------------------------------------------------- OPTION(BUILD_RTToolbox_core_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_Test_examples "build project on/off" OFF) OPTION(BUILD_RTToolbox_algorithms_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_models_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_io_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_masks_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_interpolation_Tester "build project on/off" OFF) OPTION(BUILD_RTToolbox_demoapps_Tester "build project on/off" OFF) IF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) ADD_SUBDIRECTORY(core) ENDIF(${BUILD_RTToolbox_core_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) ADD_SUBDIRECTORY(examples) ENDIF(${BUILD_RTToolbox_Test_examples} STREQUAL ON) IF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) ADD_SUBDIRECTORY(algorithms) ENDIF(${BUILD_RTToolbox_algorithms_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) ADD_SUBDIRECTORY(models) ENDIF(${BUILD_RTToolbox_models_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) ADD_SUBDIRECTORY(io) ENDIF(${BUILD_RTToolbox_io_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) ADD_SUBDIRECTORY(masks) ENDIF(${BUILD_RTToolbox_masks_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) ADD_SUBDIRECTORY(interpolation) ENDIF(${BUILD_RTToolbox_interpolation_Tester} STREQUAL ON) IF(${BUILD_RTToolbox_demoapps_Tester} STREQUAL ON) ADD_SUBDIRECTORY(demoapps) ENDIF(${BUILD_RTToolbox_demoapps_Tester} STREQUAL ON) diff --git a/testing/demoapps/DoseTool/CMakeLists.txt b/testing/demoapps/DoseTool/CMakeLists.txt index 0a47610..e7352c3 100644 --- a/testing/demoapps/DoseTool/CMakeLists.txt +++ b/testing/demoapps/DoseTool/CMakeLists.txt @@ -1,40 +1,42 @@ #----------------------------------------------------------------------------- # 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() IF (WIN32) SET(DOSETOOLEXE "DoseTool.exe") ELSE (WIN32) SET(DOSETOOLEXE "./DoseTool") ENDIF (WIN32) ADD_TEST(DoseToolBasicUsageTest ${DOSETOOL_TEST} DoseToolBasicUsageTest ${DOSETOOLEXE}) ADD_TEST(DoseToolInvalidParametersTest ${DOSETOOL_TEST} DoseToolInvalidParametersTest ${DOSETOOLEXE}) ADD_TEST(DoseToolVirtuosDoseVirtuosStructTest ${DOSETOOL_TEST} DoseToolVirtuosDoseTest ${DOSETOOLEXE} "${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 ${DOSETOOLEXE} "${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 ${DOSETOOLEXE} "${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 ${DOSETOOLEXE} "${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(DoseToolDicomDoseDicomStructRegexTest ${DOSETOOL_TEST} DoseToolRegexTest ${DOSETOOLEXE} "${TEST_DATA_ROOT}/DICOM/TestDose/dicompylerTestDose.dcm" "dicom" "${TEST_DATA_ROOT}/DICOM/StructureSet/rtss.dcm" "dicom" "Nodes|Heart" "${TEST_DATA_ROOT}/DoseStatistics/dicom.xml" "${TEST_DATA_ROOT}/DoseStatistics/dicom_heart.xml") +ADD_TEST(DoseToolDVHTest ${DOSETOOL_TEST} DoseToolDVHTest ${DOSETOOLEXE} "${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 54% copy from testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp copy to testing/demoapps/DoseTool/DoseToolDVHTest.cpp index cefc5d1..d76702e 100644 --- a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDVHTest.cpp @@ -1,136 +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: 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; std::string doseToolExecutable; std::string doseFilename; + std::string planFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; - std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); - - if (argc > 6) + if (argc > 5) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; - referenceXMLComplexFilename = argv[6]; } - std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; - std::string defaultOutputFilename = "dicomOutput.xml"; - std::string complexOutputFilename = "dicomOutputComplex.xml"; + std::string defaultOutputFilename = "dicomDVHOutput.xml"; - std::string baseCommand = doseToolExeWithPath; + 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.c_str()); 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 cefc5d1..e415bdc 100644 --- a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp @@ -1,136 +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: 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; 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 > 6) + if (argc > 7) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; - referenceXMLComplexFilename = argv[6]; + referenceDVHXMLFilename = argv[6]; + referenceXMLComplexFilename = argv[7]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "dicomOutput.xml"; + std::string defaultDVHOutputFilename = "dicomDVHOutput.xml"; std::string complexOutputFilename = "dicomOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; 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.c_str()); 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 e2a7e06..5d379b3 100644 --- a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp @@ -1,143 +1,143 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string ctxFilename; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 7) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; ctxFilename = argv[4]; structName = argv[5]; referenceXMLFilename = argv[6]; referenceXMLComplexFilename = argv[7]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "itkOutput.xml"; std::string complexOutputFilename = "itkOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; 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.c_str()); 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 045e18a..bec104f 100644 --- a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp @@ -1,102 +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: 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; 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); + 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); + 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); + 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); + 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); + CHECK_EQUAL(system(invalidStructLoadOption.c_str()) != 0, true); //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())!=0, true); + CHECK_EQUAL(system(invalidVirtuosDoseLoadOption.c_str()) != 0, true); std::string invalidVirtuosStructLoadOption = minimalCLI; invalidVirtuosStructLoadOption += "-t virtuos"; std::cout << "Command line call: " + invalidVirtuosStructLoadOption << std::endl; - CHECK_EQUAL(system(invalidVirtuosStructLoadOption.c_str())!=0, true); + CHECK_EQUAL(system(invalidVirtuosStructLoadOption.c_str()) != 0, true); //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())!=0, true); + CHECK_EQUAL(system(complexDoseWithoutPrescribedDoseCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolRegexTest.cpp b/testing/demoapps/DoseTool/DoseToolRegexTest.cpp index 0220e50..5226155 100644 --- a/testing/demoapps/DoseTool/DoseToolRegexTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolRegexTest.cpp @@ -1,143 +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: 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 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); + 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 += " -o " + defaultOutputFilename; + 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 is the same than reference file std::string defaultAsIs = readFile(defaultExpectedOutputFilename); 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); std::string requestedStructRegexTag = "Nodes"; std::string validStructRegexTag = "" + structName + ""; boost::replace_all(defaultExpected, requestedStructRegexTag, validStructRegexTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string default2AsIs = readFile(defaultExpectedOutputFilename2); std::string default2Expected = readFile(referenceXMLFilename2); boost::replace_all(default2Expected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(default2Expected, emptyStructFileTag, validStructFileTag); requestedStructRegexTag = "Heart"; validStructRegexTag = "" + structName + ""; boost::replace_all(default2Expected, requestedStructRegexTag, validStructRegexTag); CHECK_EQUAL(default2AsIs, default2Expected); //delete file again CHECK_EQUAL(std::remove(defaultExpectedOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultExpectedOutputFilename2.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; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolTests.cpp b/testing/demoapps/DoseTool/DoseToolTests.cpp index ec74bcc..18276bf 100644 --- a/testing/demoapps/DoseTool/DoseToolTests.cpp +++ b/testing/demoapps/DoseTool/DoseToolTests.cpp @@ -1,72 +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: 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(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/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp index 3b2cb7e..f339579 100644 --- a/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp @@ -1,133 +1,133 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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; std::string doseToolExecutable; 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); if (argc > 8) { doseToolExecutable = argv[1]; doseFilename = argv[2]; planFilename = argv[3]; structFilename = argv[4]; ctxFilename = argv[5]; structName = argv[6]; referenceXMLFilename = argv[7]; referenceXMLComplexFilename = argv[8]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "virtuosOutput.xml"; std::string complexOutputFilename = "virtuosOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; 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.c_str()); 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 08db870..56313aa 100644 --- a/testing/demoapps/DoseTool/files.cmake +++ b/testing/demoapps/DoseTool/files.cmake @@ -1,12 +1,13 @@ SET(CPP_FILES DoseToolBasicUsageTest.cpp DoseToolInvalidParametersTest.cpp DoseToolVirtuosDoseTest.cpp DoseToolDicomDoseTest.cpp DoseToolITKDoseTest.cpp DoseToolRegexTest.cpp + DoseToolDVHTest.cpp DoseToolTests.cpp ) SET(H_FILES )