diff --git a/apps/DoseTool/DoseToolHelper.cpp b/apps/DoseTool/DoseToolHelper.cpp index 484298b..7fea082 100644 --- a/apps/DoseTool/DoseToolHelper.cpp +++ b/apps/DoseTool/DoseToolHelper.cpp @@ -1,199 +1,201 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ #include "DoseToolHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "boost/property_tree/ptree.hpp" #include "boost/property_tree/xml_parser.hpp" #include "boost/filesystem.hpp" #include "DoseToolApplicationData.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbDoseStatistics.h" #include "rttbDVH.h" #include "rttbDVHCalculator.h" #include "rttbDVHXMLFileWriter.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseStatisticsXMLWriter.h" std::vector<rttb::core::MaskAccessorInterface::MaskAccessorPointer> rttb::apps::doseTool::generateMasks(rttb::apps::doseTool::ApplicationData& appData) { std::vector<core::MaskAccessorInterface::MaskAccessorPointer> maskAccessorPtrVector; if (appData._structLoadStyle == "itk" || appData._structLoadStyle == "itkDicom") { maskAccessorPtrVector.push_back(rttb::io::itk::ITKImageFileMaskAccessorGenerator(appData._structFileName).generateMaskAccessor()); appData._structNames.push_back(appData._structNameRegex); } else { if (appData._struct->getNumberOfStructures() > 0) { //default behavior: read only first struct that matches the regex unsigned int maxIterationCount = 1; //only if specified: read all structs that matches the regex if (appData._multipleStructsMode) { maxIterationCount = appData._struct->getNumberOfStructures(); } bool strict = !appData._allowSelfIntersection; for (size_t i = 0; i < maxIterationCount; i++) { maskAccessorPtrVector.emplace_back(boost::make_shared<rttb::masks::boost::BoostMaskAccessor>(appData._struct->getStructure(i), appData._dose->getGeometricInfo(), strict)); maskAccessorPtrVector.at(i)->updateMask(); appData._structNames.push_back(appData._struct->getStructure(i)->getLabel()); } } else { std::cout << "no structures in structure set!" << std::endl; } } return maskAccessorPtrVector; } rttb::core::DoseIteratorInterface::DoseIteratorPointer rttb::apps::doseTool::generateMaskedDoseIterator( rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr) { boost::shared_ptr<core::GenericMaskedDoseIterator> maskedDoseIterator = boost::make_shared<core::GenericMaskedDoseIterator>(maskAccessorPtr, doseAccessorPtr); rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator(maskedDoseIterator); return doseIterator; } rttb::algorithms::DoseStatistics::DoseStatisticsPointer calculateDoseStatistics( rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, rttb::DoseTypeGy prescribedDose) { rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); if (calculateComplexDoseStatistics) { return doseStatsCalculator.calculateDoseStatistics(prescribedDose); } else { return doseStatsCalculator.calculateDoseStatistics(); } } rttb::core::DVH::DVHPointer calculateDVH(rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator, rttb::IDType structUID, rttb::IDType doseUID) { rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); rttb::core::DVH::DVHPointer dvh = calc.generateDVH(); return dvh; } 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(); } /*! @brief Writes the dose statistics as XML to a file @details adds a <config>....</config> part to the RTTB generated xml where the used files and struct names are stored. */ void 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); + auto doseStatisticsXMLWriter = rttb::io::other::DoseStatisticsXMLWriter(); + + boost::property_tree::ptree originalTree = doseStatisticsXMLWriter.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<std::string>('\t', 1)); } void writeDVHFile(rttb::core::DVH::DVHPointer dvh, const std::string& filename) { rttb::DVHType typeCum = { rttb::DVHType::Cumulative }; rttb::io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); dvhWriter.writeDVH(dvh); } void rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) { std::cout << std::endl << "generating masks... "; std::vector<core::MaskAccessorInterface::MaskAccessorPointer> maskAccessorPtrVector = generateMasks(appData); std::cout << "done." << std::endl; for (size_t i = 0; i < maskAccessorPtrVector.size(); i++) { core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator( maskAccessorPtrVector.at(i), appData._dose)); 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::string outputFilename; if (appData._multipleStructsMode) { outputFilename = assembleFilenameWithStruct(appData._doseStatisticOutputFileName, appData._structNames.at(i)); } else { outputFilename = appData._doseStatisticOutputFileName; } writeDoseStatisticsFile(statistics, outputFilename, appData._structNames.at(i), appData); std::cout << "done." << std::endl; } if (appData._computeDVH) { std::cout << std::endl << "computing DVH... "; rttb::IDType structUID; rttb::IDType doseUID; //Generate random UID if (appData._structLoadStyle == "itk") { structUID = "struct42"; doseUID = "dose42"; } else { structUID = appData._struct->getUID(); doseUID = appData._dose->getUID(); } core::DVH::DVHPointer dvh = calculateDVH(spDoseIterator, structUID, doseUID); 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; } writeDVHFile(dvh, outputFilename); std::cout << "done." << std::endl; } } } diff --git a/code/io/other/rttbDoseStatisticsXMLWriter.cpp b/code/io/other/rttbDoseStatisticsXMLWriter.cpp index d0ac06a..5ed7159 100644 --- a/code/io/other/rttbDoseStatisticsXMLWriter.cpp +++ b/code/io/other/rttbDoseStatisticsXMLWriter.cpp @@ -1,302 +1,296 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include "rttbDoseStatisticsXMLWriter.h" #include <cmath> #include <ostream> #include <boost/property_tree/xml_parser.hpp> #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "rttbVolumeToDoseMeasureCollection.h" #include "rttbDoseToVolumeMeasureCollection.h" namespace rttb { namespace io { namespace other { static const std::string xmlattrXTag = "<xmlattr>.x"; static const std::string xmlattrNameTag = "<xmlattr>.name"; static const std::string statisticsTag = "statistics.results"; static const std::string propertyTag = "property"; static const std::string columnSeparator = "@"; - boost::property_tree::ptree writeDoseStatistics(DoseStatisticsPtr aDoseStatistics) + boost::property_tree::ptree DoseStatisticsXMLWriter::writeDoseStatistics(DoseStatisticsPtr aDoseStatistics) { using boost::property_tree::ptree; ptree pt; if (aDoseStatistics == nullptr){ throw core::NullPointerException("dose statistics is nullptr!"); } ptree numberOfVoxelsNode = createNodeWithNameAttribute(aDoseStatistics->getNumberOfVoxels(), "numberOfVoxels"); pt.add_child(statisticsTag + "." + propertyTag, numberOfVoxelsNode); ptree volumeNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getVolume()), "volume"); pt.add_child(statisticsTag + "." + propertyTag, volumeNode); ptree referenceNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getReferenceDose()), "referenceDose"); pt.add_child(statisticsTag + "." + propertyTag, referenceNode); ptree minimumNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getMinimum()), "minimum"); auto minimumPositions = aDoseStatistics->getMinimumVoxelPositions(); auto pairItMin = minimumPositions->begin(); int count = 0; for (; pairItMin != minimumPositions->end() && count < 100; ++pairItMin) //output max. 100 minimum { VoxelGridID voxelID = pairItMin->second; ptree voxelMinPositions; voxelMinPositions.add("voxelGridID", voxelID); minimumNode.add_child("voxel", voxelMinPositions); count++; } pt.add_child(statisticsTag + "." + propertyTag, minimumNode); ptree maximumNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getMaximum()), "maximum"); auto maximumPositions = aDoseStatistics->getMaximumVoxelPositions(); auto pairItMax = maximumPositions->begin(); count = 0; for (; pairItMax != maximumPositions->end() && count < 100; ++pairItMax) //output max. 100 maximum { VoxelGridID voxelID = pairItMax->second; ptree voxelMaxPositions; voxelMaxPositions.add("voxelGridID", voxelID); maximumNode.add_child("voxel", voxelMaxPositions); count++; } pt.add_child(statisticsTag + "." + propertyTag, maximumNode); ptree meanNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getMean()), "mean"); pt.add_child(statisticsTag + "." + propertyTag, meanNode); ptree sdNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getStdDeviation()), "standardDeviation"); pt.add_child(statisticsTag + "." + propertyTag, sdNode); ptree varianceNode = createNodeWithNameAttribute(static_cast<float>(aDoseStatistics->getVariance()), "variance"); pt.add_child(statisticsTag + "." + propertyTag, varianceNode); double absoluteVolume = aDoseStatistics->getVolume(); double referenceDose = aDoseStatistics->getReferenceDose(); rttb::algorithms::DoseToVolumeMeasureCollection::DoseToVolumeFunctionType AllVx = aDoseStatistics->getVx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllDx = aDoseStatistics->getDx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMOHx = aDoseStatistics->getMOHx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMOCx = aDoseStatistics->getMOCx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMaxOHx = aDoseStatistics->getMaxOHx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMinOCx = aDoseStatistics->getMinOCx().getAllValues(); rttb::algorithms::DoseToVolumeMeasureCollection::DoseToVolumeFunctionType::iterator vxIt; rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType::iterator it; for (it = AllDx.begin(); it != AllDx.end(); ++it) { ptree DxNode = createNodeWithNameAndXAttribute(static_cast<float>(it->second), "Dx", std::lround(convertToPercent(it->first, absoluteVolume))); pt.add_child(statisticsTag + "." + propertyTag, DxNode); } for (vxIt = AllVx.begin(); vxIt != AllVx.end(); ++vxIt) { ptree VxNode = createNodeWithNameAndXAttribute(static_cast<float>(vxIt->second), "Vx", std::lround(convertToPercent(vxIt->first, referenceDose))); pt.add_child(statisticsTag + "." + propertyTag, VxNode); } for (it = AllMOHx.begin(); it != AllMOHx.end(); ++it) { ptree mohxNode = createNodeWithNameAndXAttribute(static_cast<float>(it->second), "MOHx", std::lround(convertToPercent(it->first, absoluteVolume))); pt.add_child(statisticsTag + "." + propertyTag, mohxNode); } for (it = AllMOCx.begin(); it != AllMOCx.end(); ++it) { ptree mocxNode = createNodeWithNameAndXAttribute(static_cast<float>(it->second), "MOCx", std::lround(convertToPercent(it->first, absoluteVolume))); pt.add_child(statisticsTag + "." + propertyTag, mocxNode); } for (it = AllMaxOHx.begin(); it != AllMaxOHx.end(); ++it) { ptree maxOhxNode = createNodeWithNameAndXAttribute(static_cast<float>(it->second), "MaxOHx", std::lround(convertToPercent(it->first, absoluteVolume))); pt.add_child(statisticsTag + "." + propertyTag, maxOhxNode); } for (it = AllMinOCx.begin(); it != AllMinOCx.end(); ++it) { ptree minOCxNode = createNodeWithNameAndXAttribute(static_cast<float>(it->second), "MinOCx", std::lround(convertToPercent(it->first, absoluteVolume))); pt.add_child(statisticsTag + "." + propertyTag, minOCxNode); } return pt; } - void writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName) + void DoseStatisticsXMLWriter::writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName) { boost::property_tree::ptree pt = writeDoseStatistics(aDoseStatistics); try { boost::property_tree::xml_parser::write_xml(aFileName, pt, std::locale(), boost::property_tree::xml_writer_make_settings<std::string>('\t', 1)); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw core::InvalidParameterException("Write xml failed: xml_parser_error!"); } } - XMLString writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics) + XMLString DoseStatisticsXMLWriter::writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics) { boost::property_tree::ptree pt = writeDoseStatistics(aDoseStatistics); std::stringstream sstr; try { boost::property_tree::xml_parser::write_xml(sstr, pt, boost::property_tree::xml_writer_make_settings<std::string>('\t', 1)); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw core::InvalidParameterException("Write xml to string failed: xml_parser_error!"); } return sstr.str(); } - StatisticsString writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics) + StatisticsString DoseStatisticsXMLWriter::writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics) { if (aDoseStatistics == nullptr){ throw core::NullPointerException("dose statistics is nullptr!"); } std::stringstream sstr; sstr << static_cast<float>(aDoseStatistics->getVolume() * 1000) << columnSeparator; // cm3 to mm3 sstr << static_cast<float>(aDoseStatistics->getMaximum()) << columnSeparator; sstr << static_cast<float>(aDoseStatistics->getMinimum()) << columnSeparator; sstr << static_cast<float>(aDoseStatistics->getMean()) << columnSeparator; sstr << static_cast<float>(aDoseStatistics->getStdDeviation()) << columnSeparator; sstr << static_cast<float>(aDoseStatistics->getVariance()) << columnSeparator; rttb::algorithms::DoseToVolumeMeasureCollection::DoseToVolumeFunctionType AllVx = aDoseStatistics->getVx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllDx = aDoseStatistics->getDx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMOHx = aDoseStatistics->getMOHx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMOCx = aDoseStatistics->getMOCx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMaxOHx = aDoseStatistics->getMaxOHx().getAllValues(); rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType AllMinOCx = aDoseStatistics->getMinOCx().getAllValues(); rttb::algorithms::DoseToVolumeMeasureCollection::DoseToVolumeFunctionType::iterator vxIt; rttb::algorithms::VolumeToDoseMeasureCollection::VolumeToDoseFunctionType::iterator it; for (it = AllDx.begin(); it != AllDx.end(); ++it) { sstr << static_cast<float>((*it).second) << columnSeparator; } for (vxIt = AllVx.begin(); vxIt != AllVx.end(); ++vxIt) { // *1000 because of conversion cm3 to mm3 sstr << static_cast<float>((*vxIt).second * 1000) << columnSeparator; } for (it = AllMOHx.begin(); it != AllMOHx.end(); ++it) { sstr << static_cast<float>((*it).second) << columnSeparator; } for (it = AllMOCx.begin(); it != AllMOCx.end(); ++it) { sstr << static_cast<float>((*it).second) << columnSeparator; } for (it = AllMaxOHx.begin(); it != AllMaxOHx.end(); ++it) { sstr << static_cast<float>((*it).second) << columnSeparator; } for (it = AllMinOCx.begin(); it != AllMinOCx.end(); ++it) { sstr << static_cast<float>((*it).second) << columnSeparator; } return sstr.str(); } - boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, + boost::property_tree::ptree DoseStatisticsXMLWriter::createNodeWithNameAttribute(DoseTypeGy doseValue, const std::string& attributeName) { boost::property_tree::ptree node; node.put("", doseValue); node.put(xmlattrNameTag, attributeName); return node; } - boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, + boost::property_tree::ptree DoseStatisticsXMLWriter::createNodeWithNameAndXAttribute(DoseTypeGy doseValue, const std::string& attributeName, int xValue) { boost::property_tree::ptree node; node.put("", doseValue); node.put(xmlattrNameTag, attributeName); node.put(xmlattrXTag, xValue); return node; } - double convertToPercent(double value, double maximum) + double DoseStatisticsXMLWriter::convertToPercent(double value, double maximum) { return (value / maximum) * 100; } }//end namespace other }//end namespace io }//end namespace rttb \ No newline at end of file diff --git a/code/io/other/rttbDoseStatisticsXMLWriter.h b/code/io/other/rttbDoseStatisticsXMLWriter.h index d9cb436..bd9d195 100644 --- a/code/io/other/rttbDoseStatisticsXMLWriter.h +++ b/code/io/other/rttbDoseStatisticsXMLWriter.h @@ -1,98 +1,95 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DOSE_STATISTICS_XML_WRITER_H #define __DOSE_STATISTICS_XML_WRITER_H #include "rttbDoseStatistics.h" #include <boost/property_tree/ptree.hpp> #include <boost/shared_ptr.hpp> #include "RTTBOtherIOExports.h" namespace rttb { namespace io { namespace other { - using DoseStatisticsPtr = boost::shared_ptr<rttb::algorithms::DoseStatistics>; + class RTTBOtherIO_EXPORT DoseStatisticsXMLWriter + { + public: + + using DoseStatisticsPtr = boost::shared_ptr<rttb::algorithms::DoseStatistics>; - /*! @brief Write statistics to boost::property_tree::ptree. - @param aDoseStatistics DoseStatistics to write - @pre aReferenceDose must >0 - @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error - @note The precision is float - */ - boost::property_tree::ptree RTTBOtherIO_EXPORT writeDoseStatistics(DoseStatisticsPtr aDoseStatistics); + /*! @brief Write statistics to boost::property_tree::ptree. + @param aDoseStatistics DoseStatistics to write + @pre aReferenceDose must >0 + @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error + @note The precision is float + */ + boost::property_tree::ptree writeDoseStatistics(DoseStatisticsPtr aDoseStatistics); - /*! @brief Write statistics to String. - @param aDoseStatistics DoseStatistics to write - @pre aReferenceDose must >0 - @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error - @note The precision is float - */ - XMLString RTTBOtherIO_EXPORT writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics); + /*! @brief Write statistics to String. + @param aDoseStatistics DoseStatistics to write + @pre aReferenceDose must >0 + @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error + @note The precision is float + */ + XMLString writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics); - /*! @brief Write statistics to xml file. - @details includes the following statistics: - - numberOfVoxels, - - volume, - - minimum, - - maximum, - - mean, - - standard deviation, - - variance, - - D2,D5,D10,D90,D95,D98, - - V2,V5,V10,V90,V95,V98, - - MOH2,MOH5,MOH10, - - MOC2,MOC5,MOC10, - - MaxOH2,MaxOH5,MaxOH10, - - MinOC2,MinOC5,MinOC10. - @param aDoseStatistics DoseStatistics to write - @param aFileName To write dose statistics - @pre aReferenceDose must >0 - @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error - @note The precision is float - */ - void RTTBOtherIO_EXPORT writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName); + /*! @brief Write statistics to xml file. + @details includes the following statistics: + - numberOfVoxels, + - volume, + - minimum, + - maximum, + - mean, + - standard deviation, + - variance, + - D2,D5,D10,D90,D95,D98, + - V2,V5,V10,V90,V95,V98, + - MOH2,MOH5,MOH10, + - MOC2,MOC5,MOC10, + - MaxOH2,MaxOH5,MaxOH10, + - MinOC2,MinOC5,MinOC10. + @param aDoseStatistics DoseStatistics to write + @param aFileName To write dose statistics + @pre aReferenceDose must >0 + @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error + @note The precision is float + */ + void writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName); - boost::property_tree::ptree RTTBOtherIO_EXPORT createNodeWithNameAttribute(DoseTypeGy doseValue, - const std::string& attributeName); - boost::property_tree::ptree RTTBOtherIO_EXPORT createNodeWithNameAndXAttribute(DoseTypeGy doseValue, - const std::string& attributeName, - int xValue); + boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, const std::string& attributeName); + boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, const std::string& attributeName, int xValue); - /*! @brief Write statistics to String to generate a table - @details The table is: "Volume mm3@Max@Min@Mean@Std.Dev.@Variance@D2@D5@D10@D90@D95@D98@V2@V5@V10@V90@V95@V98@MOH2@MOH5@MOH10@MOC2@MOC5@MOC10@MaxOH2@MaxOH5@MaxOH10@MinOC2@MinOC5@MinOC10" - @param aDoseStatistics DoseStatistics to write - @pre aReferenceDose must >0 - @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error - @note is used for the Mevislab-Linking of RTTB - @note The precision is float - */ - StatisticsString RTTBOtherIO_EXPORT writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics); + /*! @brief Write statistics to String to generate a table + @details The table is: "Volume mm3@Max@Min@Mean@Std.Dev.@Variance@D2@D5@D10@D90@D95@D98@V2@V5@V10@V90@V95@V98@MOH2@MOH5@MOH10@MOC2@MOC5@MOC10@MaxOH2@MaxOH5@MaxOH10@MinOC2@MinOC5@MinOC10" + @param aDoseStatistics DoseStatistics to write + @pre aReferenceDose must >0 + @exception rttb::core::InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error + @note is used for the Mevislab-Linking of RTTB + @note The precision is float + */ + StatisticsString writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics); - double RTTBOtherIO_EXPORT convertToPercent(double value, double maximum); + double convertToPercent(double value, double maximum); + }; } } } #endif diff --git a/testing/io/other/DoseStatisticsIOTest.cpp b/testing/io/other/DoseStatisticsIOTest.cpp index b54cc70..8eed4a7 100644 --- a/testing/io/other/DoseStatisticsIOTest.cpp +++ b/testing/io/other/DoseStatisticsIOTest.cpp @@ -1,136 +1,138 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> #include <boost/filesystem.hpp> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbDoseStatisticsXMLReader.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDoseAccessor.h" #include "CompareDoseStatistic.h" namespace rttb { namespace testing { /*! @brief DoseStatisticsIOTest - test the DoseStatisticsIO for dose statistics 1) test writing statistics to xml file 2) test reading statistics from XML file and compare DoseStatistics 3) test writing statistics to string */ int DoseStatisticsIOTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; PREPARE_DEFAULT_TEST_REPORTING; /* generate dummy dose */ boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor = boost::make_shared<DummyDoseAccessor>(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); boost::shared_ptr<core::GenericDoseIterator> spTestDoseIterator = boost::make_shared<core::GenericDoseIterator>(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); auto myDoseStatsSimple = myDoseStatsCalculator.calculateDoseStatistics(); auto myDoseStatsComplex = myDoseStatsCalculator.calculateDoseStatistics(true); + auto doseStatisticsXMLWriter = io::other::DoseStatisticsXMLWriter(); + //1) test writing statistics to xml file - CHECK_THROW_EXPLICIT(io::other::writeDoseStatistics(nullptr, "aFilename.txt"), core::NullPointerException); + CHECK_THROW_EXPLICIT(doseStatisticsXMLWriter.writeDoseStatistics(nullptr, "aFilename.txt"), core::NullPointerException); FileNameString filenameSimple = "testStatisticsSimple.xml"; - CHECK_NO_THROW(io::other::writeDoseStatistics(myDoseStatsSimple, filenameSimple)); + CHECK_NO_THROW(doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsSimple, filenameSimple)); CHECK(boost::filesystem::exists(filenameSimple)); FileNameString filenameComplex = "testStatisticsComplex.xml"; - CHECK_NO_THROW(io::other::writeDoseStatistics(myDoseStatsComplex, filenameComplex)); + CHECK_NO_THROW(doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsComplex, filenameComplex)); CHECK(boost::filesystem::exists(filenameComplex)); //2) test reading statistics from XML file and compare DoseStatistics io::other::DoseStatisticsXMLReader readerSimple= io::other::DoseStatisticsXMLReader(filenameSimple); boost::shared_ptr<rttb::algorithms::DoseStatistics> rereadSimplyDose; CHECK_NO_THROW(rereadSimplyDose = readerSimple.generateDoseStatistic()); CHECK(checkEqualDoseStatistic(myDoseStatsSimple, rereadSimplyDose)); io::other::DoseStatisticsXMLReader readerComplex = io::other::DoseStatisticsXMLReader(filenameComplex); boost::shared_ptr<rttb::algorithms::DoseStatistics> rereadComplexDose; CHECK_NO_THROW(rereadComplexDose = readerComplex.generateDoseStatistic()); CHECK(checkEqualDoseStatistic(myDoseStatsComplex, rereadComplexDose)); io::other::DoseStatisticsXMLReader readerInvalidFilename = io::other::DoseStatisticsXMLReader("invalidFilename.xml"); CHECK_THROW_EXPLICIT(readerInvalidFilename.generateDoseStatistic(), core::InvalidParameterException); //delete files again CHECK_EQUAL(std::remove(filenameSimple.c_str()), 0); CHECK_EQUAL(std::remove(filenameComplex.c_str()),0); //3) test writing statistics to string - boost::property_tree::ptree ptSimple = io::other::writeDoseStatistics(myDoseStatsSimple); - XMLString strSimple = io::other::writerDoseStatisticsToString(myDoseStatsSimple); + boost::property_tree::ptree ptSimple = doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsSimple); + XMLString strSimple = doseStatisticsXMLWriter.writerDoseStatisticsToString(myDoseStatsSimple); - CHECK_THROW_EXPLICIT(io::other::writerDoseStatisticsToString(nullptr), core::NullPointerException); + CHECK_THROW_EXPLICIT(doseStatisticsXMLWriter.writerDoseStatisticsToString(nullptr), core::NullPointerException); - boost::property_tree::ptree ptComplex = io::other::writeDoseStatistics(myDoseStatsComplex); - XMLString strComplex = io::other::writerDoseStatisticsToString(myDoseStatsComplex); + boost::property_tree::ptree ptComplex = doseStatisticsXMLWriter.writeDoseStatistics(myDoseStatsComplex); + XMLString strComplex = doseStatisticsXMLWriter.writerDoseStatisticsToString(myDoseStatsComplex); std::stringstream sstrSimple; boost::property_tree::xml_parser::write_xml(sstrSimple, ptSimple, boost::property_tree::xml_writer_make_settings<std::string>('\t', 1)); CHECK_EQUAL(strSimple, sstrSimple.str()); std::stringstream sstrComplex; boost::property_tree::xml_parser::write_xml(sstrComplex, ptComplex, boost::property_tree::xml_writer_make_settings<std::string>('\t', 1)); CHECK_EQUAL(strComplex, sstrComplex.str()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb