diff --git a/apps/DoseTool/DoseToolHelper.cpp b/apps/DoseTool/DoseToolHelper.cpp index eb15e7c..edd598a 100644 --- a/apps/DoseTool/DoseToolHelper.cpp +++ b/apps/DoseTool/DoseToolHelper.cpp @@ -1,353 +1,353 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1374 $ (last changed revision) // @date $Date: 2016-05-30 14:15:42 +0200 (Mo, 30 Mai 2016) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include "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 "rttbExceptionMacros.h" #include "DoseToolApplicationData.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.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" #include "rttbVOIindexIdentifier.h" rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDose(const std::string& fileName, const 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 { 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::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadStruct( const std::string& fileName, const ApplicationData::LoadingStyleArgType& args, const std::string& structNameRegex) { 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, structNameRegex); } 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, const std::string& structNameRegex) { rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); if (!structNameRegex.empty()) { - generator.setStructureLableFilterActive(true); + generator.setStructureLabelFilterActive(true); generator.setFilterRegEx(structNameRegex); } return generator.generateStructureSet(); } 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()); appData._structNames.push_back(appData._structNameRegex); } else { auto 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 (size_t 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 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 .... 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); //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)); } 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 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.front() == "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/apps/VoxelizerTool/rttbStructDataReader.cpp b/apps/VoxelizerTool/rttbStructDataReader.cpp index 350879f..dbefca1 100644 --- a/apps/VoxelizerTool/rttbStructDataReader.cpp +++ b/apps/VoxelizerTool/rttbStructDataReader.cpp @@ -1,124 +1,124 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 1377 $ (last changed revision) // @date $Date: 2016-06-07 10:26:43 +0200 (Di, 07 Jun 2016) $ (last change date) // @author $Author: strubel $ (last changed by) */ #include "rttbStructDataReader.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace apps { namespace voxelizerTool { StructDataReader::StructDataReader(const std::string& structFileName, const std::string& referenceFileName, const std::vector& referenceFileLoadingStyle, const std::string& structRegex) : _referenceFilename(referenceFileName), _structFilename(structFileName), _referenceFileLoadingStyle(referenceFileLoadingStyle), _structRegex(structRegex) { } void StructDataReader::read() { _doseAccessor = readReferenceFile(_referenceFilename, _referenceFileLoadingStyle); _rtStructureSet = readStructFile(_structFilename, _structRegex); } std::vector StructDataReader::getAllLabels() const { std::vector allLabels; if (_rtStructureSet != NULL) { for (int j = 0; j < _rtStructureSet->getNumberOfStructures(); j++) { allLabels.push_back(_rtStructureSet->getStructure(j)->getLabel()); } } return allLabels; } StructDataReader::StructureSetPointer StructDataReader::getStructureSetPointer() const { return _rtStructureSet; } StructDataReader::DoseAccessorPointer StructDataReader::getDoseAccessorPointer() const { return _doseAccessor; } StructDataReader::DoseAccessorPointer StructDataReader::readReferenceFile( const std::string& filename, const std::vector& fileLoadingStyle) const { if (fileLoadingStyle.at(0) == "dicom") { return readDicomFile(filename); } else if (fileLoadingStyle.at(0) == "itk") { return readITKFile(filename); } else { return nullptr; } } StructDataReader::DoseAccessorPointer StructDataReader::readDicomFile( const std::string& filename) const { rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(filename.c_str()); return doseAccessorGenerator.generateDoseAccessor(); } StructDataReader::DoseAccessorPointer StructDataReader::readITKFile(const std::string& filename) const { rttb::io::itk::ITKImageFileAccessorGenerator generator(filename); return generator.generateDoseAccessor(); } StructDataReader::StructureSetPointer StructDataReader::readStructFile( const std::string& fileName, const std::string& structNameRegex) const { rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); if (!structNameRegex.empty()) { - generator.setStructureLableFilterActive(true); + generator.setStructureLabelFilterActive(true); generator.setFilterRegEx(structNameRegex); } return generator.generateStructureSet(); } } } } \ No newline at end of file diff --git a/code/core/rttbBaseType.h b/code/core/rttbBaseType.h index f2be4f7..6d7bdb3 100644 --- a/code/core/rttbBaseType.h +++ b/code/core/rttbBaseType.h @@ -1,601 +1,603 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __BASE_TYPE_NEW_H #define __BASE_TYPE_NEW_H #include #include #include #include #include #include +#include + namespace rttb { const double errorConstant = 1e-5; const double reducedErrorConstant = 0.0001; typedef unsigned short UnsignedIndex1D; /*! @class UnsignedIndex3D @brief 3D index. */ class UnsignedIndex3D: public boost::numeric::ublas::vector { public: - UnsignedIndex3D() : boost::numeric::ublas::vector(3) {} + UnsignedIndex3D() : boost::numeric::ublas::vector(3,0) {} UnsignedIndex3D(const UnsignedIndex1D value) : boost::numeric::ublas::vector(3, value) {} UnsignedIndex3D(const UnsignedIndex1D xValue, const UnsignedIndex1D yValue, const UnsignedIndex1D zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } const UnsignedIndex1D x() const { return (*this)(0); } const UnsignedIndex1D y() const { return (*this)(1); } const UnsignedIndex1D z() const { return (*this)(2); } friend bool operator==(const UnsignedIndex3D& gi1, const UnsignedIndex3D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const UnsignedIndex3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; typedef std::list UnsignedIndexList; typedef std::string FileNameString; typedef std::string ContourGeometricTypeString; typedef double WorldCoordinate; /*! @class WorldCoordinate3D @brief 3D coordinate in real world coordinates like in DICOM to define ImagePositionPatient. */ class WorldCoordinate3D: public boost::numeric::ublas::vector { public: - WorldCoordinate3D() : boost::numeric::ublas::vector(3) {} + WorldCoordinate3D() : boost::numeric::ublas::vector(3,0) {} WorldCoordinate3D(const WorldCoordinate value) : boost::numeric::ublas::vector(3, value) {} WorldCoordinate3D(const WorldCoordinate xValue, const WorldCoordinate yValue, const WorldCoordinate zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } WorldCoordinate3D(const WorldCoordinate3D& w): boost::numeric::ublas::vector(3) { (*this)(0) = w.x(); (*this)(1) = w.y(); (*this)(2) = w.z(); } const WorldCoordinate x() const { return (*this)(0); } const WorldCoordinate y() const { return (*this)(1); } const WorldCoordinate z() const { return (*this)(2); } //vector cross product (not included in boost.ublas) WorldCoordinate3D cross(WorldCoordinate3D aVector) const { WorldCoordinate3D result; WorldCoordinate x = (*this)(0); WorldCoordinate y = (*this)(1); WorldCoordinate z = (*this)(2); result(0) = y * aVector(2) - z * aVector(1); result(1) = z * aVector(0) - x * aVector(2); result(2) = x * aVector(1) - y * aVector(0); return result; } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } WorldCoordinate3D& operator=(const WorldCoordinate3D& wc) { (*this)(0) = wc.x(); (*this)(1) = wc.y(); (*this)(2) = wc.z(); return (*this); } WorldCoordinate3D& operator=(const boost::numeric::ublas::vector wc) { (*this)(0) = wc(0); (*this)(1) = wc(1); (*this)(2) = wc(2); return (*this); } WorldCoordinate3D operator-(const boost::numeric::ublas::vector wc) { return WorldCoordinate3D((*this)(0) - wc(0), (*this)(1) - wc(1), (*this)(2) - wc(2)); } WorldCoordinate3D operator+(const boost::numeric::ublas::vector wc) { return WorldCoordinate3D((*this)(0) + wc(0), (*this)(1) + wc(1), (*this)(2) + wc(2)); } friend bool operator==(const WorldCoordinate3D& wc1, const WorldCoordinate3D& wc2) { if (wc1.size() != wc2.size()) { return false; } for (size_t i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } bool equalsAlmost(const WorldCoordinate3D& another, double errorConstantWC = 1e-5) const { if (size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstantWC; } friend std::ostream& operator<<(std::ostream& s, const WorldCoordinate3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /* ! @brief continuous index */ typedef WorldCoordinate3D DoubleVoxelGridIndex3D; typedef UnsignedIndex3D ImageSize; typedef double GridVolumeType; /*! @class SpacingVectorType3D @brief 3D spacing vector. @pre values of this vector may not be negative. */ class SpacingVectorType3D: public boost::numeric::ublas::vector { public: - SpacingVectorType3D() : boost::numeric::ublas::vector(3) {} + SpacingVectorType3D() : boost::numeric::ublas::vector(3,0) {} SpacingVectorType3D(const GridVolumeType value) : boost::numeric::ublas::vector(3, value) {} SpacingVectorType3D(const GridVolumeType xValue, const GridVolumeType yValue, const GridVolumeType zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } SpacingVectorType3D(const SpacingVectorType3D& w): boost::numeric::ublas::vector(3) { (*this)(0) = w.x(); (*this)(1) = w.y(); (*this)(2) = w.z(); } const GridVolumeType x() const { return (*this)(0); } const GridVolumeType y() const { return (*this)(1); } const GridVolumeType z() const { return (*this)(2); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } SpacingVectorType3D& operator=(const SpacingVectorType3D& wc) { (*this)(0) = wc.x(); (*this)(1) = wc.y(); (*this)(2) = wc.z(); return (*this); } SpacingVectorType3D& operator=(const WorldCoordinate3D& wc) { (*this)(0) = GridVolumeType(wc.x()); (*this)(1) = GridVolumeType(wc.y()); (*this)(2) = GridVolumeType(wc.z()); return (*this); } SpacingVectorType3D& operator=(const boost::numeric::ublas::vector wc) { (*this)(0) = wc(0); (*this)(1) = wc(1); (*this)(2) = wc(2); return (*this); } friend bool operator==(const SpacingVectorType3D& wc1, const SpacingVectorType3D& wc2) { if (wc1.size() != wc2.size()) { return false; } for (size_t i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } - bool equalsAlmost(const SpacingVectorType3D& another, double errorConstantSV) const + bool equalsAlmost(const SpacingVectorType3D& another, double errorConstantSV = 1e-5) const { if ((*this).size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstantSV; } friend std::ostream& operator<<(std::ostream& s, const SpacingVectorType3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /*! @class OrientationMatrix @brief Used to store image orientation information */ class OrientationMatrix : public boost::numeric::ublas::matrix { public: /*! The default constructor generates a 3x3 unit matrix */ OrientationMatrix() : boost::numeric::ublas::matrix(3, 3, 0) { for (std::size_t m = 0; m < (*this).size1(); m++) { (*this)(m, m) = 1; } } OrientationMatrix(const WorldCoordinate value) : boost::numeric::ublas::matrix(3, 3, value) {} - bool equalsAlmost(const OrientationMatrix& anOrientationMatrix, double errorConstantOM) const + bool equalsAlmost(const OrientationMatrix& anOrientationMatrix, double errorConstantOM=1e-5) const { if (anOrientationMatrix.size1() == (*this).size1()) { if (anOrientationMatrix.size2() == (*this).size2()) { for (std::size_t m = 0; m < anOrientationMatrix.size1(); m++) { for (std::size_t n = 0; n < anOrientationMatrix.size2(); n++) { if ((std::abs((*this)(m, n) - anOrientationMatrix(m, n)) > errorConstantOM)) { return false; } } }// end element comparison } else { return false; } } else { return false; } return true; } friend bool operator==(const OrientationMatrix& om1, const OrientationMatrix& om2) { return om1.equalsAlmost(om2, 0.0); } friend std::ostream& operator<<(std::ostream& s, const OrientationMatrix& anOrientationMatrix) { s << "[ "; for (std::size_t m = 0; m < anOrientationMatrix.size1(); m++) { s << "[ "; for (std::size_t n = 0; n < anOrientationMatrix.size2(); n++) { if (n == 0) { s << anOrientationMatrix(m, n); } else { s << ", " << anOrientationMatrix(m, n); } } s << " ]"; } s << " ]"; return s; } }; /*! base for 2D and 3D VoxelIndex; Therefore required beside VoxelGridID */ typedef unsigned int GridIndexType; /*! @class VoxelGridIndex3D @brief 3D voxel grid index in a discret geometry (matrix/image). @details analogous to DICOM where ImagePositionPatient gives the position of the center of the first coordinate (0/0/0) */ class VoxelGridIndex3D: public boost::numeric::ublas::vector { public: - VoxelGridIndex3D() : boost::numeric::ublas::vector(3) {} + VoxelGridIndex3D() : boost::numeric::ublas::vector(3,0) {} VoxelGridIndex3D(const GridIndexType value) : boost::numeric::ublas::vector(3, value) {} VoxelGridIndex3D(const GridIndexType xValue, const GridIndexType yValue, const GridIndexType zValue) : boost::numeric::ublas::vector(3, xValue) { (*this)(1) = yValue; (*this)(2) = zValue; } const GridIndexType x() const { return (*this)(0); } const GridIndexType y() const { return (*this)(1); } const GridIndexType z() const { return (*this)(2); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()) + " " + std::to_string(z()); return s; } VoxelGridIndex3D& operator=(const UnsignedIndex3D& ui) { (*this)(0) = ui(0); (*this)(1) = ui(1); (*this)(2) = ui(2); return (*this); } friend bool operator==(const VoxelGridIndex3D& gi1, const VoxelGridIndex3D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const VoxelGridIndex3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; /*! @class VoxelGridIndex3D @brief 2D voxel grid index. */ class VoxelGridIndex2D: public boost::numeric::ublas::vector { public: - VoxelGridIndex2D() : boost::numeric::ublas::vector(2) {} + VoxelGridIndex2D() : boost::numeric::ublas::vector(2,0) {} VoxelGridIndex2D(const GridIndexType value) : boost::numeric::ublas::vector(2, value) {} VoxelGridIndex2D(const GridIndexType xValue, const GridIndexType yValue) : boost::numeric::ublas::vector(2, xValue) { (*this)(1) = yValue; } const GridIndexType x() const { return (*this)(0); } const GridIndexType y() const { return (*this)(1); } const std::string toString() const { std::string s = std::to_string(x()) + " " + std::to_string(y()); return s; } friend bool operator==(const VoxelGridIndex2D& gi1, const VoxelGridIndex2D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (size_t i = 0; i < gi1.size(); i++) { if (gi1(i) != gi2(i)) { return false; } } return true; } friend std::ostream& operator<<(std::ostream& s, const VoxelGridIndex2D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << " ]"; return s; } }; typedef long GridSizeType; typedef int VoxelGridID; //starts from 0 and is continuously counting all positions on the grid typedef unsigned int VoxelGridDimensionType; typedef double FractionType, DVHVoxelNumber; typedef double DoseCalcType, DoseTypeGy, GenericValueType, DoseVoxelVolumeType, VolumeType, GridVolumeType, PercentType, VoxelNumberType, BEDType, LQEDType; typedef std::string IDType; typedef std::string StructureLabel; struct DVHRole { enum Type { TargetVolume = 1, HealthyTissue = 2, WholeVolume = 4, UserDefined = 128 } Type; }; struct DVHType { enum Type { Differential = 1, Cumulative = 2 } Type; }; typedef std::string FileNameType; typedef std::vector PolygonType; typedef std::vector PolygonSequenceType; typedef double IndexValueType; typedef double DoseStatisticType; typedef std::string DICOMRTFileNameString; typedef unsigned short Uint16; typedef std::string XMLString, StatisticsString; }//end: namespace rttb #endif diff --git a/code/core/rttbDVH.cpp b/code/core/rttbDVH.cpp index 6de2824..b3bd1b9 100644 --- a/code/core/rttbDVH.cpp +++ b/code/core/rttbDVH.cpp @@ -1,434 +1,441 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDVH.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { DVH::~DVH() {} DVH::DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, IDType aStructureID, IDType aDoseID): _deltaD(aDeltaD), _deltaV(aDeltaV), _structureID(aStructureID), _doseID(aDoseID), _voxelizationID("NONE") { _dataDifferential.clear(); _dataDifferential = aDataDifferential; this->init(); } DVH::DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, IDType aStructureID, IDType aDoseID, IDType aVoxelizationID): _deltaD(aDeltaD), _deltaV(aDeltaV), _structureID(aStructureID), _doseID(aDoseID), _voxelizationID(aVoxelizationID) { _dataDifferential.clear(); _dataDifferential = aDataDifferential; this->init(); } DVH::DVH(const DVH& copy) : _structureID(copy._structureID), _doseID(copy._doseID), _voxelizationID(copy._voxelizationID), _label(copy._label) { _deltaD = copy._deltaD; _deltaV = copy._deltaV; _dataDifferential.clear(); _dataDifferential = copy._dataDifferential; this->init(); } DVH& DVH::operator=(const DVH& copy) { if (this != ©) { _deltaD = copy._deltaD; _deltaV = copy._deltaV; _structureID = copy._structureID; _doseID = copy._doseID; _voxelizationID = copy._voxelizationID; _label = copy._label; _dataDifferential.clear(); _dataDifferential = copy._dataDifferential; } this->init(); return *this; } bool operator==(const DVH& aDVH, const DVH& otherDVH) { - if (aDVH.getStructureID() != otherDVH.getStructureID()) - { - return false; - } - - if (aDVH.getDoseID() != otherDVH.getDoseID()) - { - return false; - } - - if (aDVH.getVoxelizationID() != otherDVH.getVoxelizationID()) - { - return false; - } - - if (aDVH.getNumberOfVoxels() != otherDVH.getNumberOfVoxels()) - { - return false; - } - - return true; + bool result; + //larger error constant because especially numberOfVoxels differ quite a bit after serialization + const double errorConstantDVH = 1e-4; + result = valueIsClose(aDVH.getDeltaD(), otherDVH.getDeltaD(), errorConstantDVH); + result = result && valueIsClose(aDVH.getDeltaV(), otherDVH.getDeltaV(), errorConstantDVH); + result = result && (aDVH.getDoseID() == otherDVH.getDoseID()); + result = result && (aDVH.getStructureID() == otherDVH.getStructureID()); + result = result && (aDVH.getVoxelizationID() == otherDVH.getVoxelizationID()); + result = result && valueIsClose(aDVH.getNumberOfVoxels(),otherDVH.getNumberOfVoxels(), errorConstantDVH); + result = result && valueIsClose(aDVH.getMaximum(), otherDVH.getMaximum(), errorConstantDVH); + result = result && valueIsClose(aDVH.getMinimum(), otherDVH.getMinimum(), errorConstantDVH); + result = result && valueIsClose(aDVH.getMean(), otherDVH.getMean(), errorConstantDVH); + result = result && (aDVH.getDataDifferential().size() == otherDVH.getDataDifferential().size()); + if (!result) { + return result; + } + for (size_t i = 0; i < aDVH.getDataDifferential().size(); i++) + { + result = result + && valueIsClose(aDVH.getDataDifferential().at(i), otherDVH.getDataDifferential().at(i), + errorConstantDVH); + } + + return result; } std::ostream& operator<<(std::ostream& s, const DVH& aDVH) { s << "[ " << aDVH.getStructureID() << ", " << aDVH.getDoseID() << ", " << aDVH.getVoxelizationID() << "\n " << "Number of Voxels: " << aDVH.getNumberOfVoxels() << " " << "Minimum/Maximum/Mean/Standard deviation: " << aDVH.getMinimum() << ", " << aDVH.getMaximum() << ", " << aDVH.getMean() << ", " << aDVH.getStdDeviation() << " ]"; return s; } std::deque DVH::getDataDifferential(bool relativeVolume) const { if (!relativeVolume) { return _dataDifferential; } else { return _dataDifferentialRelative; } } DoseVoxelVolumeType DVH::getDeltaV() const { return _deltaV; } DoseTypeGy DVH::getDeltaD() const { return _deltaD; } IDType DVH::getDoseID() const { return this->_doseID; } IDType DVH::getStructureID() const { return this->_structureID; } IDType DVH::getVoxelizationID() const { return this->_voxelizationID; } void DVH::setDoseID(IDType aDoseID) { _doseID = aDoseID; } void DVH::setStructureID(IDType aStrID) { _structureID = aStrID; } DoseStatisticType DVH::getMaximum() const { return _maximum; } DoseStatisticType DVH::getMinimum() const { return _minimum; } DoseStatisticType DVH::getMean() const { return _mean; } DVHVoxelNumber DVH::getNumberOfVoxels() const { return _numberOfVoxels; } DoseStatisticType DVH::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DVH::getVariance() const { return _variance; } void DVH::init() { if (_deltaD == 0 || _deltaV == 0) { throw InvalidParameterException("DVH init error: neither _deltaD nor _deltaV must be zero!"); } if (this->_dataDifferential.empty()) { throw InvalidParameterException("DVH init error: data differential is empty!"); } double sum = 0; double squareSum = 0; _numberOfVoxels = 0; _maximum = 0; _minimum = 0; _dataCumulative.clear(); this->_dataCumulativeRelative.clear(); this->_dataDifferentialRelative.clear(); DataDifferentialType::iterator it; int i = 0; for (it = _dataDifferential.begin(); it != _dataDifferential.end(); ++it) { _numberOfVoxels += (*it); if ((*it) > 0) { _maximum = (i + 0.5) * this->_deltaD; } if ((_minimum == 0.0f) && ((*it) > 0)) { _minimum = (i + 0.5) * this->_deltaD; } sum += (*it) * (i + 0.5) * this->_deltaD; squareSum += (*it) * pow((i + 0.5) * this->_deltaD, 2); i++; } _mean = sum / _numberOfVoxels; for (it = _dataDifferential.begin(); it != _dataDifferential.end(); ++it) { DoseCalcType datai = ((*it) * 1.0 / _numberOfVoxels); _dataDifferentialRelative.push_back(datai); } _variance = (squareSum / _numberOfVoxels - _mean * _mean); _stdDeviation = pow(_variance, 0.5); _dataCumulative = this->calcCumulativeDVH(); } std::deque DVH::calcCumulativeDVH(bool relativeVolume) { _dataCumulative.clear(); _dataCumulativeRelative.clear(); DoseCalcType cumulativeDVHi = 0; size_t size = _dataDifferential.size(); for (size_t i = 0; i < size; i++) { cumulativeDVHi += _dataDifferential.at(size - i - 1); if (!relativeVolume) { _dataCumulative.push_front(cumulativeDVHi); } else { _dataCumulativeRelative.push_front(cumulativeDVHi / this->getNumberOfVoxels()); } } if (!relativeVolume) { return _dataCumulative; } else { return _dataCumulativeRelative; } } DoseStatisticType DVH::getMedian() const { double median_voxel = 0; int median_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (median_voxel < (_numberOfVoxels - median_voxel)) { median_voxel += _dataDifferential[i]; median_i = i; } } double median = (median_i + 0.5) * this->_deltaD; return median; } DoseStatisticType DVH::getModal() const { double modal_voxel = 0; int modal_i = 0; for (GridIndexType i = 0; i < this->_dataDifferential.size(); i++) { if (modal_voxel < _dataDifferential[i]) { modal_voxel = _dataDifferential[i]; modal_i = i; } } double modal = (modal_i + 0.5) * this->_deltaD; return modal; } VolumeType DVH::getVx(DoseTypeGy xDoseAbsolute) { GridIndexType i = static_cast(xDoseAbsolute / _deltaD); if (i < _dataCumulative.size()) { VolumeType vx = (_dataCumulative.at(i)); vx = (vx * this->_deltaV); return vx; } else if (i < _dataCumulativeRelative.size()) { VolumeType vx = (_dataCumulativeRelative.at(i)); vx = (vx * this->_deltaV); return vx; } else { return 0; } } DoseTypeGy DVH::getDx(VolumeType xVolumeAbsolute) { GridIndexType i = 0; if (!_dataCumulative.empty()) { for (; i < _dataCumulative.size(); i++) { double volumeAbsoluteI = _dataCumulative[i] * this->_deltaV; if (xVolumeAbsolute > volumeAbsoluteI) { break; } } } else { for (; i < _dataCumulativeRelative.size(); i++) { double volumeAbsoluteI = _dataCumulativeRelative[i] * this->_deltaV; if (xVolumeAbsolute / this->getNumberOfVoxels() > volumeAbsoluteI) { break; } } } if (i <= _dataCumulative.size() && i > 0) { DoseTypeGy dx = (i - 1) * this->_deltaD; return dx; } else if (i < _dataCumulativeRelative.size() && i > 0) { DoseTypeGy dx = (i - 1) * this->_deltaD; return dx; } else { return 0; } } VolumeType DVH::getAbsoluteVolume(int relativePercent) { return (relativePercent * getNumberOfVoxels() * getDeltaV() / 100.0); } void DVH::setLabel(StructureLabel aLabel) { _label = aLabel; } StructureLabel DVH::getLabel() const { return _label; } std::map DVH::getNormalizedDVH(DVHType dvhType) { std::map normalizedDVH; DataDifferentialType data = getDataDifferential(); size_t numberOfVolumes = data.size(); if (dvhType.Type == DVHType::Cumulative) { data = calcCumulativeDVH(); } for (size_t i = 0; i < numberOfVolumes; i++) { normalizedDVH.insert(std::pair(i * getDeltaD(), data[i] * getDeltaV())); } return normalizedDVH; } + bool valueIsClose(double v1, double v2, double specificErrorConstant) { + return std::abs(v1 - v2) < specificErrorConstant; + } + }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVH.h b/code/core/rttbDVH.h index f66cf0a..348df41 100644 --- a/code/core/rttbDVH.h +++ b/code/core/rttbDVH.h @@ -1,200 +1,205 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_H #define __DVH_H #include #include #include #include "boost/shared_ptr.hpp" #include "rttbBaseType.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class DVH @brief This is a class representing a dose volume histogram (DVH) */ class RTTBCore_EXPORT DVH { public: typedef std::deque DataDifferentialType; typedef boost::shared_ptr DVHPointer; private: /*! @brief Differential dvh data index is the dose bin, value is the voxel number (sub voxel accuracy) of the dose bin */ DataDifferentialType _dataDifferential; /*! @brief Differential dvh data relative to the total number of voxels */ DataDifferentialType _dataDifferentialRelative; /*! @brief Absolute dose value of a dose-bin in Gy */ DoseTypeGy _deltaD; /*! @brief Volume of a voxel in cm3 */ DoseVoxelVolumeType _deltaV; IDType _structureID; IDType _doseID; IDType _voxelizationID; StructureLabel _label; DoseStatisticType _maximum; DoseStatisticType _minimum; DoseStatisticType _mean; DoseStatisticType _modal; DVHVoxelNumber _numberOfVoxels; DoseStatisticType _median; DoseStatisticType _stdDeviation; DoseStatisticType _variance; DataDifferentialType _dataCumulative; DataDifferentialType _dataCumulativeRelative; /*! @brief DVH initialization The DVH is initialized and all statistical values are calculated. @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ void init(); public: ~DVH(); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, const DoseTypeGy& aDeltaD, const DoseVoxelVolumeType& aDeltaV, IDType aStructureID, IDType aDoseID); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH(const DataDifferentialType& aDataDifferential, DoseTypeGy aDeltaD, DoseVoxelVolumeType aDeltaV, IDType aStructureID, IDType aDoseID, IDType aVoxelizationID); DVH(const DVH& copy); /*! @throw if _deltaV or _deltaD are zero @throw is _data differential is empty */ DVH& operator=(const DVH& copy); /*! equality operator - DVHs are considered equal if they have the same structure, dose and voxelization ID - and the same number of voxels. + DVHs are considered equal if the following are equal (let alone double inconsistencies): + - structureID + - doseID + - voxelizationID + - number of voxels + - Histogram entries. */ bool friend operator==(const DVH& aDVH, const DVH& otherDVH); friend std::ostream& operator<<(std::ostream& s, const DVH& aDVH); void setLabel(StructureLabel aLabel); StructureLabel getLabel() const; /*! @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @return Return differential data of the dvh (relative or absolute depending on the input parameter). */ DataDifferentialType getDataDifferential(bool relativeVolume = false) const; DoseVoxelVolumeType getDeltaV() const; DoseTypeGy getDeltaD() const; IDType getStructureID() const; IDType getDoseID() const; IDType getVoxelizationID() const; void setDoseID(IDType aDoseID); void setStructureID(IDType aStrID); /*! @brief Calculate number of the voxels (with sub voxel accuracy) @return Return -1 if not initialized */ DVHVoxelNumber getNumberOfVoxels() const; /*! @brief Get the maximum dose in Gy from dvh @return Return the maximum dose in Gy (i+0.5)*deltaD, i-the maximal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMaximum() const; /*! @brief Get the minimum dose in Gy from dvh @return Return the minimum dose (i+0.5)*deltaD, i-the minimal dose-bin with volume>0 Return -1 if not initialized */ DoseStatisticType getMinimum() const; DoseStatisticType getMean() const; DoseStatisticType getMedian() const; DoseStatisticType getModal() const; DoseStatisticType getStdDeviation() const; DoseStatisticType getVariance() const; /*! @brief Calculate the cumulative data of dvh @param relativeVolume default false-> Value is the voxel number of the dose bin; if true-> value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @return Return cumulative dvh value i-voxel number in dose-bin i */ DataDifferentialType calcCumulativeDVH(bool relativeVolume = false); /*! @brief Get Vx the volume irradiated to >= x @return Return absolute Volume in absolute cm3 Return -1 if not initialized */ VolumeType getVx(DoseTypeGy xDoseAbsolute); /*! @brief Get Dx the minimal dose delivered to x @return Return absolute dose value in Gy Return -1 if not initialized */ DoseTypeGy getDx(VolumeType xVolumeAbsolute); /*! @brief Calculate the absolute volume in cm3 @param relativePercent 0~100, the percent of the whole volume */ VolumeType getAbsoluteVolume(int relativePercent); /* @brief Multiplies each values with its Delta value. Values depend on DVHType. @param The DVHType that is being used DVHType::Cumulative or DVHType::Differential */ std::map getNormalizedDVH(DVHType dvhType = { DVHType::Cumulative }); }; + static bool valueIsClose(double v1, double v2, double specificErrorConstant = 1e-5); } } #endif diff --git a/code/core/rttbDoseIteratorInterface.h b/code/core/rttbDoseIteratorInterface.h index 5af0298..19bd11b 100644 --- a/code/core/rttbDoseIteratorInterface.h +++ b/code/core/rttbDoseIteratorInterface.h @@ -1,108 +1,97 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ITERATOR_INTERFACE_NEW_H #define __DOSE_ITERATOR_INTERFACE_NEW_H #include #include "rttbBaseType.h" #include "rttbDoseAccessorInterface.h" namespace rttb { namespace core { class GeometricInfo; /*! @class DoseIteratorInterface @brief This class represents the dose iterator interface. */ class DoseIteratorInterface { public: typedef boost::shared_ptr DoseAccessorPointer; typedef boost::shared_ptr DoseIteratorPointer; private: DoseIteratorInterface(const DoseIteratorInterface&); //not implemented on purpose -> non-copyable DoseIteratorInterface& operator=(const DoseIteratorInterface&);//not implemented on purpose -> non-copyable DoseIteratorInterface() {}; protected: /*! @brief DoseAccessor to get access to actual dose data */ DoseAccessorPointer _spDoseAccessor; public: /*! @brief Constructor with a DoseIterator this should be the default for all implementations. */ DoseIteratorInterface(DoseAccessorPointer aDoseAccessor); virtual ~DoseIteratorInterface() {}; /*! @brief Set the iterator to the start of the dose. */ virtual bool reset() = 0; /*! @brief Move to next position. If this position is valid is not necessarily tested. */ virtual void next() = 0; virtual bool isPositionValid() const = 0; /*! @brief Return volume of one voxel (in cm3)*/ //previously getDeltaV() virtual DoseVoxelVolumeType getCurrentVoxelVolume() const = 0; - virtual DoseTypeGy getCurrentDoseValue() const = 0; - inline const core::GeometricInfo& getGeometricInfo() const - { - return _spDoseAccessor->getGeometricInfo(); - }; - /*! @return If this is a masked dose iterator, return the voxel proportion inside a given structure, value 0~1; Otherwise, 1 */ virtual FractionType getCurrentRelevantVolumeFraction() const = 0; - inline const DoseAccessorPointer getDoseAccessor() const - { - return _spDoseAccessor; - }; - virtual VoxelGridID getCurrentVoxelGridID() const = 0; virtual IDType getVoxelizationID() const { return ""; }; IDType getDoseUID() const { return _spDoseAccessor->getUID(); }; }; //end class }//end: namespace core }//end: namespace rttb #endif diff --git a/code/core/rttbStructureSet.cpp b/code/core/rttbStructureSet.cpp index d90c74e..35cc7ce 100644 --- a/code/core/rttbStructureSet.cpp +++ b/code/core/rttbStructureSet.cpp @@ -1,88 +1,84 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include #include "rttbStructureSet.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { - - StructureSet::StructureSet() {} - - StructureSet::StructureSet(std::vector aStructureVector, + StructureSet::StructureSet(const std::vector& aStructureVector, IDType aPatientUID, IDType aUID) { _structureSetVector = aStructureVector; _patientUID = aPatientUID; _UID = aUID; if (_UID == "") { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _UID = ss.str(); } } StructureSet::StructTypePointer StructureSet::getStructure(size_t aStructureNo) const { auto size = this->getNumberOfStructures(); if (aStructureNo >= size) { std::stringstream sstr; sstr << "aStructureNo must be between 0 and " << size; throw InvalidParameterException(sstr.str()); } return _structureSetVector.at(aStructureNo); } StructureSet::NumberOfStructuresType StructureSet::getNumberOfStructures() const { return _structureSetVector.size(); } - IDType StructureSet::getUID() + IDType StructureSet::getUID() const { return _UID; } - IDType StructureSet::getPatientUID() + IDType StructureSet::getPatientUID() const { - return _patientUID; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbStructureSet.h b/code/core/rttbStructureSet.h index 9e2ceff..7fef5aa 100644 --- a/code/core/rttbStructureSet.h +++ b/code/core/rttbStructureSet.h @@ -1,92 +1,85 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ -/* Changes in Architecture: -The class is useful in the IO classes for structure import. It needs to contain no datatype specific information. -UIDs are omitted. - -Is "PhysicalInfo" important information that should be stored here? -*/ #ifndef __STRUCTURE_SET_H #define __STRUCTURE_SET_H #include #include #include "rttbBaseType.h" #include "rttbStructure.h" #include "RTTBCoreExports.h" namespace rttb { namespace core { /*! @class StructureSet @brief This is an class representing a structure set, which can be used to generate masks. */ class RTTBCore_EXPORT StructureSet { public: typedef Structure::StructTypePointer StructTypePointer; typedef size_t NumberOfStructuresType; protected: std::vector _structureSetVector; IDType _UID; IDType _patientUID; public: - StructureSet(); virtual ~StructureSet() {}; /*! @brief Constructor @param aPatientUID the patient UID. @param aUID the structure set UID. If it is empty, it will be calculated in the constructor */ - StructureSet(std::vector aStructureVector, IDType aPatientUID = "", + StructureSet(const std::vector& aStructureVector, IDType aPatientUID = "", IDType aUID = ""); /*! @brief Get the Structure with the index aStructureNo @return Return Structure pointer. @exception InvalidParameterException Thrown if structureNo not between 0 and number of structures of structureSet. */ StructTypePointer getStructure(size_t aStructureNo) const; /*! @brief Get the number of structures @return Return the number of structures. */ NumberOfStructuresType getNumberOfStructures() const; - virtual IDType getUID(); + virtual IDType getUID() const; - virtual IDType getPatientUID(); + virtual IDType getPatientUID() const; }; } } #endif diff --git a/code/core/rttbStructureSetGeneratorInterface.h b/code/core/rttbStructureSetGeneratorInterface.h index 9dc82f5..9b7880b 100644 --- a/code/core/rttbStructureSetGeneratorInterface.h +++ b/code/core/rttbStructureSetGeneratorInterface.h @@ -1,86 +1,86 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __STRUCTURE_SET_GENERATOR_INTERFACE_H #define __STRUCTURE_SET_GENERATOR_INTERFACE_H #include namespace rttb { namespace core { class StructureSet; /*! @class StructureSetGeneratorInterface @brief Interface for all structure set generating classes */ class StructureSetGeneratorInterface { public: typedef boost::shared_ptr StructureSetPointer; private: StructureSetGeneratorInterface(const StructureSetGeneratorInterface&); //not implemented on purpose -> non-copyable StructureSetGeneratorInterface& operator=(const StructureSetGeneratorInterface&);//not implemented on purpose -> non-copyable protected: StructureSetGeneratorInterface(): _activeFilter(false) { }; virtual ~StructureSetGeneratorInterface() {}; private: bool _activeFilter; std::string _filterRegEx; public: - void setStructureLableFilterActive(bool active) + void setStructureLabelFilterActive(bool active) { _activeFilter = active; }; bool getStructureLabelFilterActive() const { return _activeFilter; }; void setFilterRegEx(const std::string& filter) { _filterRegEx = filter; }; std::string getFilterRegEx() const { return _filterRegEx; }; /*! @brief Generate StructureSet @return Return shared pointer of StructureSet. */ virtual StructureSetPointer generateStructureSet() = 0; }; } } #endif diff --git a/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp b/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp index 3a64b1c..b5dee6d 100644 --- a/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp +++ b/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp @@ -1,112 +1,112 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include "rttbInvalidParameterException.h" #include "rttbStructure.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbDicomIODStructureSetGenerator.h" #include "rttbDcmrtException.h" #include "rttbDicomFileReaderHelper.h" namespace rttb { namespace io { namespace dicom { DicomFileStructureSetGenerator::DicomFileStructureSetGenerator(DICOMRTFileNameString aDICOMRTStrSetFileName) { _fileName = aDICOMRTStrSetFileName; } DicomFileStructureSetGenerator::~DicomFileStructureSetGenerator() { } DicomFileStructureSetGenerator::StructureSetPointer DicomFileStructureSetGenerator::generateStructureSet() { std::vector fileVector; //if a file if (isFile(_fileName)) { fileVector.push_back(_fileName); } //if a directory else if (isDirectory(_fileName)) { rttb::io::dicom::Modality strModality = {rttb::io::dicom::Modality::RTSTRUCT}; fileVector = getFileNamesWithSameUID(_fileName, strModality); } else { throw rttb::core::InvalidParameterException("Invalid file/directory name!"); } if (fileVector.size() < 1) { throw rttb::core::InvalidParameterException("There is no structure set files in the directory!"); } OFCondition status; DcmFileFormat fileformat; DRTStrSetIODPtr drtStrSetIODPtr = boost::make_shared(); //get the first structure set file status = fileformat.loadFile(fileVector.at(0).c_str()); if (!status.good()) { throw DcmrtException("Load rt structure set loadFile() failed!"); } status = drtStrSetIODPtr->read(*fileformat.getDataset()); if (!status.good()) { throw DcmrtException("Read DRTStructureSetIOD DRTStructureSetIOD.read() failed!"); } io::dicom::DicomIODStructureSetGenerator iodGenerator(drtStrSetIODPtr); - iodGenerator.setStructureLableFilterActive(this->getStructureLabelFilterActive()); + iodGenerator.setStructureLabelFilterActive(this->getStructureLabelFilterActive()); iodGenerator.setFilterRegEx(this->getFilterRegEx()); return iodGenerator.generateStructureSet(); } }//end namespace dicom }//end namespace io }//end namespace rttb diff --git a/testing/core/BaseTypeTest.cpp b/testing/core/BaseTypeTest.cpp new file mode 100644 index 0000000..4c180ed --- /dev/null +++ b/testing/core/BaseTypeTest.cpp @@ -0,0 +1,274 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) +*/ + +#include "litCheckMacros.h" + +#include "rttbBaseType.h" + +namespace rttb +{ + namespace testing + { + + /*! @brief BaseTypeTests - tests the API for the classes in baseType + 1) UnsignedIndex3D + 2) WorldCoordinate3D + 3) SpacingVectorType3D + 4) OrientationMatrix + 5) VoxelGridIndex3D + 6) VoxelGridIndex2D + */ + int BaseTypeTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + //1) UnsignedIndex3D + CHECK_NO_THROW(UnsignedIndex3D ui); + UnsignedIndex3D emptyUnsignedIndex3D; + CHECK_EQUAL(emptyUnsignedIndex3D.x(), 0); + CHECK_EQUAL(emptyUnsignedIndex3D.y(), 0); + CHECK_EQUAL(emptyUnsignedIndex3D.z(), 0); + + CHECK_NO_THROW(UnsignedIndex3D ui(5)); + UnsignedIndex3D sameValueUnsignedIndex(5); + CHECK_EQUAL(sameValueUnsignedIndex.x(), 5); + CHECK_EQUAL(sameValueUnsignedIndex.y(), 5); + CHECK_EQUAL(sameValueUnsignedIndex.z(), 5); + + CHECK_NO_THROW(UnsignedIndex3D ui(5, 8, 42)); + UnsignedIndex3D differentValueUnsignedIndex(5, 8, 42); + CHECK_EQUAL(differentValueUnsignedIndex.x(), 5); + CHECK_EQUAL(differentValueUnsignedIndex.y(), 8); + CHECK_EQUAL(differentValueUnsignedIndex.z(), 42); + + UnsignedIndex3D threeDimensionalUnsignedIndexSame(5, 8, 42); + UnsignedIndex3D threeDimensionalUnsignedIndexDifferent(1, 2, 3); + + CHECK(differentValueUnsignedIndex == threeDimensionalUnsignedIndexSame); + CHECK_EQUAL(differentValueUnsignedIndex == threeDimensionalUnsignedIndexDifferent, false); + CHECK_EQUAL(differentValueUnsignedIndex == sameValueUnsignedIndex, false); + CHECK_EQUAL(emptyUnsignedIndex3D == sameValueUnsignedIndex, false); + + //2) WorldCoordinate3D + CHECK_NO_THROW(WorldCoordinate3D wc); + WorldCoordinate3D emptyWC3D; + CHECK_EQUAL(emptyWC3D.x(), 0); + CHECK_EQUAL(emptyWC3D.y(), 0); + CHECK_EQUAL(emptyWC3D.z(), 0); + + CHECK_NO_THROW(WorldCoordinate3D wc(6.5)); + WorldCoordinate3D sameValueWC3D(6.5); + CHECK_EQUAL(sameValueWC3D.x(), 6.5); + CHECK_EQUAL(sameValueWC3D.y(), 6.5); + CHECK_EQUAL(sameValueWC3D.z(), 6.5); + + CHECK_NO_THROW(WorldCoordinate3D(5.8, 0.1, -2.7)); + WorldCoordinate3D differentValueWC3D(5.8, 0.1, -2.7); + CHECK_EQUAL(differentValueWC3D.x(), 5.8); + CHECK_EQUAL(differentValueWC3D.y(), 0.1); + CHECK_EQUAL(differentValueWC3D.z(), -2.7); + + CHECK_EQUAL(differentValueWC3D.toString(), "5.800000 0.100000 -2.700000"); + + WorldCoordinate3D differentValueWC3Dsecond(1.5, -3.9, 0.7); + WorldCoordinate3D resultWC3DCrossTrue(-10.46, -8.11, -22.77); + CHECK_NO_THROW(differentValueWC3D.cross(differentValueWC3Dsecond)); + auto resultWC3DCrossComputed = differentValueWC3D.cross(differentValueWC3Dsecond); + CHECK_CLOSE(resultWC3DCrossComputed.x(), resultWC3DCrossTrue.x(), errorConstant); + CHECK_CLOSE(resultWC3DCrossComputed.y(), resultWC3DCrossTrue.y(), errorConstant); + CHECK_CLOSE(resultWC3DCrossComputed.z(), resultWC3DCrossTrue.z(), errorConstant); + CHECK_NO_THROW(differentValueWC3Dsecond.cross(differentValueWC3D)); + auto resultWC3DCrossComputedOrder = differentValueWC3Dsecond.cross(differentValueWC3D); + CHECK_CLOSE(resultWC3DCrossComputed.x(), resultWC3DCrossComputedOrder.x()*-1, errorConstant); + CHECK_CLOSE(resultWC3DCrossComputed.y(), resultWC3DCrossComputedOrder.y()*-1, errorConstant); + CHECK_CLOSE(resultWC3DCrossComputed.z(), resultWC3DCrossComputedOrder.z()*-1, errorConstant); + + differentValueWC3D = differentValueWC3Dsecond; + CHECK_EQUAL(differentValueWC3D.x(), 1.5); + CHECK_EQUAL(differentValueWC3D.y(), -3.9); + CHECK_EQUAL(differentValueWC3D.z(), 0.7); + + boost::numeric::ublas::vector wcUblas(3, 4.5); + differentValueWC3D = wcUblas; + CHECK_EQUAL(differentValueWC3D.x(), 4.5); + CHECK_EQUAL(differentValueWC3D.y(), 4.5); + CHECK_EQUAL(differentValueWC3D.z(), 4.5); + + WorldCoordinate3D WCresultMinus; + CHECK_NO_THROW(WCresultMinus = differentValueWC3D- differentValueWC3Dsecond); + CHECK_EQUAL(WCresultMinus.x(), differentValueWC3D.x()- differentValueWC3Dsecond.x()); + CHECK_EQUAL(WCresultMinus.y(), differentValueWC3D.y() - differentValueWC3Dsecond.y()); + CHECK_EQUAL(WCresultMinus.z(), differentValueWC3D.z() - differentValueWC3Dsecond.z()); + + WorldCoordinate3D WCresultPlus; + CHECK_NO_THROW(WCresultPlus = differentValueWC3D + differentValueWC3Dsecond); + CHECK_EQUAL(WCresultPlus.x(), differentValueWC3D.x() + differentValueWC3Dsecond.x()); + CHECK_EQUAL(WCresultPlus.y(), differentValueWC3D.y() + differentValueWC3Dsecond.y()); + CHECK_EQUAL(WCresultPlus.z(), differentValueWC3D.z() + differentValueWC3Dsecond.z()); + + WorldCoordinate3D sameAsWcUblas(4.5); + CHECK_EQUAL(resultWC3DCrossTrue== differentValueWC3Dsecond, false); + CHECK_EQUAL(differentValueWC3D == sameAsWcUblas, true); + + WorldCoordinate3D sameAsWcUblasAlmost(4.5+1e-6, 4.5-1e-6, 4.5+2e-7); + CHECK_EQUAL(sameAsWcUblas.equalsAlmost(sameAsWcUblasAlmost), true); + CHECK_EQUAL(sameAsWcUblas.equalsAlmost(resultWC3DCrossComputedOrder), false); + + //3) SpacingVectorType + CHECK_NO_THROW(SpacingVectorType3D svt); + SpacingVectorType3D emptySvt; + CHECK_EQUAL(emptySvt.x(), 0); + CHECK_EQUAL(emptySvt.y(), 0); + CHECK_EQUAL(emptySvt.z(), 0); + + CHECK_NO_THROW(SpacingVectorType3D svt(1.5)); + SpacingVectorType3D sameValueSvt(1.5); + CHECK_EQUAL(sameValueSvt.x(), 1.5); + CHECK_EQUAL(sameValueSvt.y(), 1.5); + CHECK_EQUAL(sameValueSvt.z(), 1.5); + + CHECK_NO_THROW(SpacingVectorType3D svt(1.5, 1.5, 0.5)); + SpacingVectorType3D differentValuesSvt(1.5, 1.5, 0.5); + CHECK_EQUAL(differentValuesSvt.x(), 1.5); + CHECK_EQUAL(differentValuesSvt.y(), 1.5); + CHECK_EQUAL(differentValuesSvt.z(), 0.5); + + SpacingVectorType3D differentValuesSvtChanged(0.5, 0.5, 1.5); + CHECK_NO_THROW(SpacingVectorType3D svt(differentValuesSvtChanged)); + SpacingVectorType3D svtNew(differentValuesSvtChanged); + CHECK_EQUAL(svtNew.x(), 0.5); + CHECK_EQUAL(svtNew.y(), 0.5); + CHECK_EQUAL(svtNew.z(), 1.5); + + CHECK_NO_THROW(svtNew = differentValuesSvt); + CHECK_EQUAL(svtNew.x(), 1.5); + CHECK_EQUAL(svtNew.y(), 1.5); + CHECK_EQUAL(svtNew.z(), 0.5); + + CHECK_NO_THROW(svtNew = differentValueWC3D); + CHECK_EQUAL(svtNew.x(), 4.5); + CHECK_EQUAL(svtNew.y(), 4.5); + CHECK_EQUAL(svtNew.z(), 4.5); + + boost::numeric::ublas::vector ublasVector(3, 0.5); + CHECK_NO_THROW(svtNew = ublasVector); + CHECK_EQUAL(svtNew.x(), 0.5); + CHECK_EQUAL(svtNew.y(), 0.5); + CHECK_EQUAL(svtNew.z(), 0.5); + + SpacingVectorType3D sameAsUblasVector(0.5); + + CHECK_EQUAL(svtNew== differentValuesSvtChanged, false); + CHECK_EQUAL(svtNew == sameAsUblasVector, true); + + SpacingVectorType3D almostSameAsUblasVector(0.5+1e-6, 0.5-1e-6,0.5+2e-7); + CHECK(svtNew.equalsAlmost(almostSameAsUblasVector)); + + CHECK_EQUAL(differentValuesSvtChanged.toString(), "0.500000 0.500000 1.500000"); + + //4) OrientationMatrix + CHECK_NO_THROW(OrientationMatrix om); + OrientationMatrix om; + CHECK_EQUAL(om(0, 0), 1.0); + CHECK_EQUAL(om(1, 1), 1.0); + CHECK_EQUAL(om(2, 2), 1.0); + CHECK_EQUAL(om(0, 1), 0.0); + CHECK_EQUAL(om(0, 2), 0.0); + CHECK_EQUAL(om(1, 0), 0.0); + CHECK_EQUAL(om(1, 2), 0.0); + CHECK_EQUAL(om(2, 0), 0.0); + CHECK_EQUAL(om(2, 1), 0.0); + + CHECK_NO_THROW(OrientationMatrix omValue(0.1)); + OrientationMatrix omValue(0.1); + for (unsigned int i = 0; i < 3; i++) { + for (unsigned int j = 0; j < 3; j++) { + CHECK_EQUAL(omValue(i, j), 0.1); + } + } + + OrientationMatrix omValueAlmost(0.1+1e-6); + CHECK_EQUAL(omValue.equalsAlmost(omValueAlmost), true); + CHECK_EQUAL(omValue.equalsAlmost(om), false); + + OrientationMatrix omSame; + CHECK_EQUAL(om == omSame, true); + CHECK_EQUAL(omValue == omValueAlmost, false); + + //5) VoxelGridIndex3D + CHECK_NO_THROW(VoxelGridIndex3D vgi); + VoxelGridIndex3D vgi; + CHECK_EQUAL(vgi.x(), 0); + CHECK_EQUAL(vgi.y(), 0); + CHECK_EQUAL(vgi.z(), 0); + + CHECK_NO_THROW(VoxelGridIndex3D vgiValue(2)); + VoxelGridIndex3D vgiValue(2); + CHECK_EQUAL(vgiValue.x(), 2); + CHECK_EQUAL(vgiValue.y(), 2); + CHECK_EQUAL(vgiValue.z(), 2); + + CHECK_NO_THROW(VoxelGridIndex3D vgiValueDifferent(2,3,5)); + VoxelGridIndex3D vgiValueDifferent(2,3,5); + CHECK_EQUAL(vgiValueDifferent.x(), 2); + CHECK_EQUAL(vgiValueDifferent.y(), 3); + CHECK_EQUAL(vgiValueDifferent.z(), 5); + + CHECK_EQUAL(vgiValueDifferent.toString(), "2 3 5"); + + CHECK_NO_THROW(vgiValueDifferent = threeDimensionalUnsignedIndexSame); + CHECK_EQUAL(vgiValueDifferent.x(), 5); + CHECK_EQUAL(vgiValueDifferent.y(), 8); + CHECK_EQUAL(vgiValueDifferent.z(), 42); + + VoxelGridIndex3D vgiValueDifferentSame(5, 8, 42); + + CHECK_EQUAL(vgi==vgiValue, false); + CHECK_EQUAL(vgiValueDifferentSame == vgiValueDifferent, true); + + //6) VoxelGridIndex2D + CHECK_NO_THROW(VoxelGridIndex2D vgi); + VoxelGridIndex2D vgi2D; + CHECK_EQUAL(vgi2D.x(), 0); + CHECK_EQUAL(vgi2D.y(), 0); + + CHECK_NO_THROW(VoxelGridIndex2D vgi2DValue(2)); + VoxelGridIndex2D vgi2DValue(2); + CHECK_EQUAL(vgi2DValue.x(), 2); + CHECK_EQUAL(vgi2DValue.y(), 2); + + CHECK_NO_THROW(VoxelGridIndex2D vgi2DValueDifferent(2, 3)); + VoxelGridIndex2D vgi2DValueDifferent(2, 3); + CHECK_EQUAL(vgi2DValueDifferent.x(), 2); + CHECK_EQUAL(vgi2DValueDifferent.y(), 3); + + CHECK_EQUAL(vgi2DValueDifferent.toString(), "2 3"); + + VoxelGridIndex2D vgi2DValueDifferentSame(2, 3); + + CHECK_EQUAL(vgi2D == vgi2DValueDifferent, false); + CHECK_EQUAL(vgi2DValueDifferent == vgi2DValueDifferentSame, true); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing +}//rttb \ No newline at end of file diff --git a/testing/core/CMakeLists.txt b/testing/core/CMakeLists.txt index f94e7e1..1d65745 100644 --- a/testing/core/CMakeLists.txt +++ b/testing/core/CMakeLists.txt @@ -1,27 +1,29 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(CORE_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbCoreTests) SET(CORE_HEADER_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbCoreHeaderTest) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(GeometricInfoTest ${CORE_TESTS} GeometricInfoTest) ADD_TEST(MaskVoxelTest ${CORE_TESTS} MaskVoxelTest) ADD_TEST(GenericDoseIteratorTest ${CORE_TESTS} GenericDoseIteratorTest) ADD_TEST(GenericMaskedDoseIteratorTest ${CORE_TESTS} GenericMaskedDoseIteratorTest) ADD_TEST(DVHCalculatorTest ${CORE_TESTS} DVHCalculatorTest) ADD_TEST(DVHTest ${CORE_TESTS} DVHTest) ADD_TEST(DVHSetTest ${CORE_TESTS} DVHSetTest) ADD_TEST(StructureTest ${CORE_TESTS} StructureTest) ADD_TEST(StrVectorStructureSetGeneratorTest ${CORE_TESTS} StrVectorStructureSetGeneratorTest) +ADD_TEST(StructureSetTest ${CORE_TESTS} StructureSetTest) +ADD_TEST(BaseTypeTest ${CORE_TESTS} BaseTypeTest) RTTB_CREATE_TEST_MODULE(rttbCore DEPENDS RTTBCore PACKAGE_DEPENDS Boost Litmus) diff --git a/testing/core/DVHCalculatorTest.cpp b/testing/core/DVHCalculatorTest.cpp index a33a9f5..917e18e 100644 --- a/testing/core/DVHCalculatorTest.cpp +++ b/testing/core/DVHCalculatorTest.cpp @@ -1,128 +1,154 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" +#include "rttbGeometricInfo.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "DummyDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; /*!@brief DVHTest - test the API of DVH 1) test constructors (values as expected?) */ int DVHCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //create null pointer to DoseIterator DoseIteratorPointer spDoseIteratorNull; const IDType structureID = "myStructure"; const IDType doseIDNull = "myDose"; //1) test constructors (values as expected?) CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIteratorNull, structureID, doseIDNull), core::NullPointerException); //create dummy DoseAccessor boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); //create corresponding DoseIterator boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); const IDType doseID = spDoseAccessor->getUID(); CHECK_NO_THROW(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID)); CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, -1), core::InvalidParameterException); int numBins = 21; DoseTypeGy binSize = 0; DoseStatisticType maximum = 0; std::vector::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } ++doseIt; } binSize = maximum * 1.5 / numBins; CHECK_NO_THROW(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, binSize, numBins)); CHECK_THROW_EXPLICIT(core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, 0, 0), core::InvalidParameterException);//aNumberOfBins must be >=0 core::DVHCalculator myDVHCalc(spDoseIterator, structureID, doseID, binSize, 1); CHECK_THROW_EXPLICIT(myDVHCalc.generateDVH(), core::InvalidParameterException);//_numberOfBins must be > max(aDoseIterator)/aDeltaD! + //generateDVH (only test basic functionality here and test it in RTTBDicomIOTests and RTTBITKIOTests) + + //create dummy DoseAccessor with values 0 to check if _deltaD is set to 0.1 + std::vector zeros(1000, 0); + core::GeometricInfo geoInfo; + geoInfo.setNumColumns(10); + geoInfo.setNumRows(10); + geoInfo.setNumSlices(10); + geoInfo.setSpacing({1.0, 1.0, 1.0}); + + boost::shared_ptr spTestDoseAccessorZeros = boost::make_shared(zeros, geoInfo); + DoseAccessorPointer spDoseAccessorZeros(spTestDoseAccessorZeros); + boost::shared_ptr spTestDoseIteratorZeros = + boost::make_shared(spDoseAccessorZeros); + DoseIteratorPointer spDoseIteratorZeros(spTestDoseIteratorZeros); + CHECK_NO_THROW(core::DVHCalculator myDVHCalc2(spDoseIteratorZeros, structureID, doseID, 0, + numBins)); + core::DVHCalculator myDVHCalc2(spDoseIteratorZeros, structureID, doseID, 0, + numBins); + core::DVHCalculator::DVHPointer dvh; + CHECK_NO_THROW(dvh = myDVHCalc2.generateDVH()); + CHECK(dvh); + CHECK_CLOSE(dvh->getDeltaD(), 0.1, errorConstant); + //create dummy MaskAccessor boost::shared_ptr spTestMaskAccessor = boost::make_shared(spDoseAccessor->getGeometricInfo()); MaskAccessorPointer spMaskAccessor(spTestMaskAccessor); //create corresponding MaskedDoseIterator boost::shared_ptr spTestMaskedDoseIterator = boost::make_shared(spMaskAccessor, spDoseAccessor); - DoseIteratorPointer spMaskedDoseIterator(spTestMaskedDoseIterator); - - CHECK_NO_THROW(core::DVHCalculator myDVHCalc2(spMaskedDoseIterator, structureID, doseID)); + MaskedDoseIteratorPointer spMaskedDoseIterator(spTestMaskedDoseIterator); - //actual calculation is still missing + CHECK_NO_THROW(core::DVHCalculator myDVHCalc3(spMaskedDoseIterator, structureID, doseID)); + core::DVHCalculator myDVHCalc3(spMaskedDoseIterator, structureID, doseID); + CHECK_NO_THROW(dvh = myDVHCalc3.generateDVH()); + CHECK(dvh); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHSetTest.cpp b/testing/core/DVHSetTest.cpp index 157efa1..1d23a7f 100644 --- a/testing/core/DVHSetTest.cpp +++ b/testing/core/DVHSetTest.cpp @@ -1,183 +1,207 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "DummyDVHGenerator.h" namespace rttb { namespace testing { typedef core::DVHSet::DVHSetType DVHSetType; /*! @brief DVHTest - test the API of DVH 1) test constructors (values as expected?) 2) test size 3) test set/getIDs 4) test insert/retrieve individual DVHs 5) test getDVHSet 6) test getVolume */ int DVHSetTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; const IDType structureSetID = "myStructureSet"; const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; DummyDVHGenerator dvhGenerator; DVHSetType tvSet; IDType structureID = structureIDPrefix + "_TV_"; for (int i = 0; i < 3; i++) { tvSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } DVHSetType htSet; structureID = structureIDPrefix + "_HT_"; for (int i = 0; i < 5; i++) { htSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } DVHSetType wvSet; structureID = structureIDPrefix + "_WV_"; for (int i = 0; i < 1; i++) { wvSet.push_back(dvhGenerator.generateDVH(structureID + boost::lexical_cast(i), doseID)); } //1) test constructors (values as expected?) CHECK_NO_THROW(core::DVHSet(structureSetID, doseID)); CHECK_NO_THROW(core::DVHSet(tvSet, htSet, structureSetID, doseID)); CHECK_NO_THROW(core::DVHSet(tvSet, htSet, wvSet, structureSetID, doseID)); //2) test size core::DVHSet myDvhSet1(structureSetID, doseID); CHECK_EQUAL(myDvhSet1.size(), 0); core::DVHSet myDvhSet2(tvSet, htSet, structureSetID, doseID); CHECK_EQUAL(myDvhSet2.size(), tvSet.size() + htSet.size()); core::DVHSet myDvhSet3(tvSet, htSet, wvSet, structureSetID, doseID); CHECK_EQUAL(myDvhSet3.size(), tvSet.size() + htSet.size() + wvSet.size()); //3) test set/getIDs const IDType newStructureSetID = "myNewStructureSet"; const IDType newDoseID = "myNewDose"; CHECK_EQUAL(myDvhSet1.getStrSetID(), structureSetID); CHECK_EQUAL(myDvhSet1.getDoseID(), doseID); CHECK_NO_THROW(myDvhSet1.setStrSetID(newStructureSetID)); CHECK_NO_THROW(myDvhSet1.setDoseID(newDoseID)); CHECK_EQUAL(myDvhSet1.getStrSetID(), newStructureSetID); CHECK_EQUAL(myDvhSet1.getDoseID(), newDoseID); CHECK_EQUAL(myDvhSet3.getStrSetID(), structureSetID); CHECK_EQUAL(myDvhSet3.getDoseID(), doseID); CHECK_NO_THROW(myDvhSet3.setStrSetID(newStructureSetID)); CHECK_NO_THROW(myDvhSet3.setDoseID(newDoseID)); CHECK_EQUAL(myDvhSet3.getStrSetID(), newStructureSetID); CHECK_EQUAL(myDvhSet3.getDoseID(), newDoseID); //4) test insert/retrieve individual DVHs DVHRole roleTV = {DVHRole::TargetVolume}; + DVHRole roleUser = { DVHRole::UserDefined }; structureID = structureIDPrefix + "_TV_"; core::DVH tv = dvhGenerator.generateDVH(structureID + boost::lexical_cast (tvSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 0); CHECK_NO_THROW(myDvhSet1.insert(tv, roleTV)); CHECK_EQUAL(myDvhSet1.size(), 1); std::size_t currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(tv, roleTV)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); + CHECK_THROW_EXPLICIT(myDvhSet2.insert(tv, roleUser), core::InvalidParameterException); DVHRole roleHT = {DVHRole::HealthyTissue}; structureID = structureIDPrefix + "_HT_"; core::DVH ht = dvhGenerator.generateDVH(structureID + boost::lexical_cast (htSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 1); CHECK_NO_THROW(myDvhSet1.insert(ht, roleHT)); CHECK_EQUAL(myDvhSet1.size(), 2); currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(ht, roleHT)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); DVHRole roleWV = {DVHRole::WholeVolume}; structureID = structureIDPrefix + "_wv_"; IDType testID = structureID + boost::lexical_cast(wvSet.size()); core::DVH wv = dvhGenerator.generateDVH(structureID + boost::lexical_cast (wvSet.size()), doseID); CHECK_EQUAL(myDvhSet1.size(), 2); CHECK_NO_THROW(myDvhSet1.insert(wv, roleWV)); CHECK_EQUAL(myDvhSet1.size(), 3); currentSize = myDvhSet2.size(); CHECK_NO_THROW(myDvhSet2.insert(wv, roleWV)); CHECK_EQUAL(myDvhSet2.size(), currentSize + 1); //5) test getDVHSet core::DVH* dvhPtr = myDvhSet1.getDVH(testID); CHECK_EQUAL(*dvhPtr, wv); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_TV_0"); CHECK_EQUAL(*dvhPtr, tvSet.at(0)); dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_TV_2"); CHECK_EQUAL(*dvhPtr, tvSet.at(2)); + dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_HT_2"); + CHECK_EQUAL(*dvhPtr, htSet.at(2)); + + dvhPtr = myDvhSet3.getDVH(structureIDPrefix + "_WV_0"); + CHECK_EQUAL(*dvhPtr, wvSet.at(0)); + + dvhPtr = myDvhSet3.getDVH("wrongID"); + CHECK(!dvhPtr); + DVHSetType tvTest = myDvhSet3.getTargetVolumeSet(); CHECK_EQUAL(tvTest, tvSet); DVHSetType htTest = myDvhSet3.getHealthyTissueSet(); CHECK_EQUAL(htTest, htSet); DVHSetType wvTest = myDvhSet3.getWholeVolumeSet(); CHECK_EQUAL(wvTest, wvSet); //6) test getVolume DoseTypeGy aDoseAbsolute = 10; CHECK_EQUAL(0, myDvhSet3.getHealthyTissueVolume(aDoseAbsolute)); CHECK_EQUAL(0, myDvhSet3.getTargetVolume(aDoseAbsolute)); CHECK_EQUAL(0, myDvhSet3.getWholeVolume(aDoseAbsolute)); + //7) Test equality + core::DVHSet myDvhSet4(myDvhSet1.getStrSetID(), myDvhSet1.getDoseID()); + myDvhSet4.insert(tv, roleTV); + myDvhSet4.insert(ht, roleHT); + myDvhSet4.insert(wv, roleWV); + CHECK_EQUAL(myDvhSet1 == myDvhSet2, false); + CHECK_EQUAL(myDvhSet1 == myDvhSet4, true); + myDvhSet4.setDoseID("bla"); + CHECK_EQUAL(myDvhSet1 == myDvhSet4, false); + myDvhSet4.setDoseID(myDvhSet1.getDoseID()); + myDvhSet4.insert(tv, roleTV); + CHECK_EQUAL(myDvhSet1 == myDvhSet4, false); + RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHTest.cpp b/testing/core/DVHTest.cpp index 9ebe103..2768721 100644 --- a/testing/core/DVHTest.cpp +++ b/testing/core/DVHTest.cpp @@ -1,203 +1,241 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "DummyDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief DVHTest - test the API of DVH 1) test constructors (values as expected?) - 2) test asignement + 2) test assignement 3) test set/getLabel 4) test set/get 5) test equality */ int DVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType anEmptyDataDifferential; DataDifferentialType aDataDifferential; DataDifferentialType aDataDifferential2; DataDifferentialType aDataDifferentialRelative; DoseStatisticType maximum = 0; DoseStatisticType minimum = 0; double sum = 0; double squareSum = 0; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values [0,100) for (int i = 0; i < 100; i++) { value = DoseCalcType((double(rand()) / RAND_MAX) * 1000); numberOfVoxels += value; aDataDifferential.push_back(value); aDataDifferential2.push_back(value * 10); if (value > 0) { maximum = (i + 0.5) * binSize; if (minimum == 0) { minimum = (i + 0.5) * binSize; } } sum += value * (i + 0.5) * binSize; squareSum += value * pow((i + 0.5) * binSize, 2); } + double medianVoxel = 0; + double modalVoxel = 0; + unsigned int count = 0; + unsigned int medianCount = 0; + unsigned int modalCount = 0; + for (const auto& aValue : aDataDifferential) { + std::cout << aValue << std::endl; + if (medianVoxel < numberOfVoxels - medianVoxel) { + medianVoxel += aValue; + medianCount = count; + } + if (modalVoxel < aValue) { + modalVoxel = aValue; + modalCount = count; + } + count++; + } + DoseStatisticType median = (medianCount + 0.5)*binSize; + DoseStatisticType modal = (modalCount + 0.5)*binSize; + DoseStatisticType mean = sum / numberOfVoxels; DoseStatisticType variance = (squareSum / numberOfVoxels - mean * mean); DoseStatisticType stdDeviation = pow(variance, 0.5); std::deque::iterator it; for (it = aDataDifferential.begin(); it != aDataDifferential.end(); ++it) { aDataDifferentialRelative.push_back((*it) / numberOfVoxels); } - const IDType structureID = "myStructure"; - const IDType doseID = "myDose"; - const IDType voxelizationID = "myVoxelization"; + IDType structureID = "myStructure"; + IDType doseID = "myDose"; + IDType voxelizationID = "myVoxelization"; //1) test default constructor (values as expected?) CHECK_THROW(core::DVH(anEmptyDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(anEmptyDataDifferential, binSize, voxelVolume, structureID, doseID)); CHECK_NO_THROW(core::DVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID)); CHECK_NO_THROW(core::DVH(aDataDifferential, binSize, voxelVolume, structureID, doseID)); CHECK_THROW(core::DVH(aDataDifferential, 0, voxelVolume, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(aDataDifferential, 0, voxelVolume, structureID, doseID)); CHECK_THROW(core::DVH(aDataDifferential, binSize, 0, structureID, doseID, voxelizationID)); CHECK_THROW(core::DVH(aDataDifferential, binSize, 0, structureID, doseID)); - //2) test asignement + //2) test assignment core::DVH myTestDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID); CHECK_NO_THROW(core::DVH myOtherDVH = myTestDVH); - const core::DVH myOtherDVH = myTestDVH; + core::DVH myOtherDVH(myTestDVH); - CHECK_NO_THROW(core::DVH aDVH(myOtherDVH)); + CHECK_NO_THROW(myOtherDVH = myTestDVH); //3) test set/getLabel core::DVH myDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); StructureLabel label = ""; CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); label = "myLabel"; CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); label = "myLabel2"; CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_NO_THROW(myDVH.setLabel(label)); CHECK_EQUAL(myDVH.getLabel(), label); CHECK_EQUAL(myDVH.getLabel(), label); //4) test set/get //IDs CHECK_EQUAL(myDVH.getStructureID(), structureID); CHECK_EQUAL(myDVH.getDoseID(), doseID); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); /*! is related to #2029*/ myDVH.setDoseID("somethingElse"); CHECK_EQUAL(myDVH.getDoseID(), "somethingElse"); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); CHECK_EQUAL(myDVH.getStructureID(), structureID); /*! is related to #2029*/ myDVH.setStructureID("somethingOther"); CHECK_EQUAL(myDVH.getDoseID(), "somethingElse"); CHECK_EQUAL(myDVH.getVoxelizationID(), voxelizationID); CHECK_EQUAL(myDVH.getStructureID(), "somethingOther"); //dataDifferential CHECK(myDVH.getDataDifferential() == aDataDifferential); CHECK(myDVH.getDataDifferential(false) == aDataDifferential); CHECK(myDVH.getDataDifferential(true) == aDataDifferentialRelative); CHECK_EQUAL(myDVH.getNumberOfVoxels(), numberOfVoxels); CHECK_EQUAL(myDVH.getDeltaV(), voxelVolume); CHECK_EQUAL(myDVH.getDeltaD(), binSize); CHECK_EQUAL(myDVH.getMaximum(), maximum); CHECK_EQUAL(myDVH.getMinimum(), minimum); CHECK_EQUAL(myDVH.getMean(), mean); CHECK_EQUAL(myDVH.getVariance(), variance); CHECK_EQUAL(myDVH.getStdDeviation(), stdDeviation); + CHECK_EQUAL(myDVH.getMedian(), median); + CHECK_EQUAL(myDVH.getModal(), modal); + + CHECK_CLOSE(myDVH.getVx(0), 395848.994415, errorConstant); + CHECK_CLOSE(myDVH.getVx(7), 126268.990143, errorConstant); + CHECK_CLOSE(myDVH.getDx(0), 9.9, errorConstant); + CHECK_CLOSE(myDVH.getDx(100000), 7.5, errorConstant); int percentage = 20; VolumeType absVol = VolumeType(percentage * numberOfVoxels * voxelVolume / 100.0); CHECK_EQUAL(myDVH.getAbsoluteVolume(percentage), absVol); //5) test equality + structureID = myDVH.getStructureID(); + doseID = myDVH.getDoseID(); + voxelizationID = myDVH.getVoxelizationID(); core::DVH myDVH2(aDataDifferential2, binSize, voxelVolume, structureID, doseID); + core::DVH myDVH3(aDataDifferential, binSize, voxelVolume, structureID+"_diff", doseID); + core::DVH myDVH4(aDataDifferential, binSize, voxelVolume, structureID, doseID+"_diff"); + core::DVH myDVH5(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID+"_diff"); CHECK(!(myDVH == myDVH2)); + CHECK(!(myDVH == myDVH3)); + CHECK(!(myDVH == myDVH4)); + CHECK(!(myDVH == myDVH5)); CHECK_EQUAL(myDVH, myDVH); core::DVH aDVH(myOtherDVH); CHECK_EQUAL(aDVH, myOtherDVH); std::map normalizedDVHDiff = myDVH.getNormalizedDVH({ DVHType::Differential }); for (auto elem : normalizedDVHDiff) { CHECK_EQUAL(aDataDifferential.at(std::round(elem.first / binSize)), (elem.second / voxelVolume)); } std::map normalizedDVHCum = myDVH.getNormalizedDVH(); for (auto elem : normalizedDVHCum) { CHECK_EQUAL(myDVH.calcCumulativeDVH().at(std::round(elem.first / binSize)), (elem.second / voxelVolume)); } + CHECK_NO_THROW(myDVH.calcCumulativeDVH(true)); + RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DummyInhomogeneousDoseAccessor.cpp b/testing/core/DummyInhomogeneousDoseAccessor.cpp new file mode 100644 index 0000000..83c28f9 --- /dev/null +++ b/testing/core/DummyInhomogeneousDoseAccessor.cpp @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) +*/ + +#include "DummyInhomogeneousDoseAccessor.h" + +namespace rttb +{ + namespace testing + { + + DummyInhomogeneousDoseAccessor::~DummyInhomogeneousDoseAccessor() {} + + DummyInhomogeneousDoseAccessor::DummyInhomogeneousDoseAccessor() : DummyDoseAccessor() + { + } + + + + bool DummyInhomogeneousDoseAccessor::isGridHomogeneous() const + { + return false; + } + + }//end namespace testing +}//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyInhomogeneousDoseAccessor.h b/testing/core/DummyInhomogeneousDoseAccessor.h new file mode 100644 index 0000000..91260e4 --- /dev/null +++ b/testing/core/DummyInhomogeneousDoseAccessor.h @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) +*/ +#ifndef __DUMMY_DOSE_INHOMOGENEOUS_ACCESSOR_H +#define __DUMMY_DOSE_INHOMOGENEOUS_ACCESSOR_H + +#include "DummyDoseAccessor.h" + + +namespace rttb +{ + namespace testing + { + + /*! @class DummyInhomogeneousDoseAccessor + @brief A dummy DoseAccessor for testing with inhomogeneous grid + */ + class DummyInhomogeneousDoseAccessor: public DummyDoseAccessor + { + public: + ~DummyInhomogeneousDoseAccessor(); + + /*! @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. + The default grid size is [11,10,5] + */ + DummyInhomogeneousDoseAccessor(); + + bool isGridHomogeneous() const override; + }; + } +} + +#endif diff --git a/testing/core/DummyMaskAccessor.h b/testing/core/DummyMaskAccessor.h index 44bb02e..4255eab 100644 --- a/testing/core/DummyMaskAccessor.h +++ b/testing/core/DummyMaskAccessor.h @@ -1,86 +1,81 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DUMMY_MASK_ACCESSOR_H #define __DUMMY_MASK_ACCESSOR_H #include #include "rttbMaskAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @class DumyMaskAccessor @brief Create a dummy MaskAccessor for testing. */ class DummyMaskAccessor: public core::MaskAccessorInterface { public: typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; private: /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; core::GeometricInfo _geoInfo; IDType _maskUID; public: DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo); DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo, MaskVoxelListPointer voxelListPtr); ~DummyMaskAccessor() {}; void updateMask(); const core::GeometricInfo& getGeometricInfo() const { return _geoInfo; }; MaskVoxelListPointer getRelevantVoxelVector(); MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; bool getMaskAt(const VoxelGridIndex3D& gridIndex, core::MaskVoxel& voxel) const; - bool isGridHomogeneous() const - { - return true; - } - IDType getMaskUID() const { return _maskUID; }; }; } } #endif diff --git a/testing/core/GenericDoseIteratorTest.cpp b/testing/core/GenericDoseIteratorTest.cpp index b373de6..93d6657 100644 --- a/testing/core/GenericDoseIteratorTest.cpp +++ b/testing/core/GenericDoseIteratorTest.cpp @@ -1,93 +1,112 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "DummyDoseAccessor.h" +#include "DummyInhomogeneousDoseAccessor.h" +#include "rttbInvalidParameterException.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; /*! @brief GenericDoseIteratorTest - test the API of GenericDoseIterator 1) test constructor (values as expected?) 2) test reset/next/get current values/isPositionValid + 3) test DoseIteratorInterface functions */ int GenericDoseIteratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //create dummy DoseAccessor boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); + boost::shared_ptr spTestDoseAccessorInhomo = boost::make_shared(); + DoseAccessorPointer spDoseAccessorInhomo(spTestDoseAccessorInhomo); //1) test constructor (values as expected?) CHECK_NO_THROW(core::GenericDoseIterator genDoseIterator(spDoseAccessor)); core::GenericDoseIterator genDoseIterator(spDoseAccessor); const VoxelGridID defaultDoseVoxelGridID = 0; const DoseVoxelVolumeType defaultVoxelVolume = 0; CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK_EQUAL(defaultVoxelVolume, genDoseIterator.getCurrentVoxelVolume()); + core::GenericDoseIterator genDoseIteratorInhomo(spDoseAccessorInhomo); + //2) test reset/next genDoseIterator.reset(); const DoseVoxelVolumeType homogeneousVoxelVolume = genDoseIterator.getCurrentVoxelVolume(); CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK(!(defaultVoxelVolume == genDoseIterator.getCurrentVoxelVolume())); core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); SpacingVectorType3D spacing = geoInfo.getSpacing(); CHECK_EQUAL(spacing(0)*spacing(1)*spacing(2) / 1000, genDoseIterator.getCurrentVoxelVolume()); + CHECK_THROW_EXPLICIT(genDoseIteratorInhomo.reset(), core::InvalidParameterException); + //check if the correct voxels are accessed const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); genDoseIterator.reset(); VoxelGridID position = 0; while (genDoseIterator.isPositionValid()) { CHECK_EQUAL(genDoseIterator.getCurrentDoseValue(), doseVals->at(position)); CHECK_EQUAL(homogeneousVoxelVolume, genDoseIterator.getCurrentVoxelVolume()); CHECK_EQUAL(1, genDoseIterator.getCurrentRelevantVolumeFraction()); CHECK_EQUAL(position, genDoseIterator.getCurrentVoxelGridID()); genDoseIterator.next(); position++; } + CHECK_EQUAL(spTestDoseAccessor->getGridSize(), spTestDoseAccessor->getGeometricInfo().getNumberOfVoxels()); + //check isPositionValid() in invalid positions CHECK(!(genDoseIterator.isPositionValid())); //after end of dose + CHECK_EQUAL(genDoseIterator.getCurrentDoseValue(), 0); genDoseIterator.reset(); CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK(genDoseIterator.isPositionValid());//before start of dose + + + //3) test DoseIteratorInterface functions + CHECK_EQUAL(genDoseIterator.getVoxelizationID(), ""); + CHECK_EQUAL(genDoseIterator.getDoseUID(), spTestDoseAccessor->getUID()); + + CHECK_THROW_EXPLICIT(genDoseIteratorInhomo.getCurrentVoxelVolume(), core::InvalidParameterException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/GenericMaskedDoseIteratorTest.cpp b/testing/core/GenericMaskedDoseIteratorTest.cpp index c3dd042..e4fc188 100644 --- a/testing/core/GenericMaskedDoseIteratorTest.cpp +++ b/testing/core/GenericMaskedDoseIteratorTest.cpp @@ -1,129 +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$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbNullPointerException.h" +#include "rttbInvalidParameterException.h" #include "rttbException.h" #include "DummyDoseAccessor.h" +#include "DummyInhomogeneousDoseAccessor.h" #include "DummyMaskAccessor.h" namespace rttb { namespace testing { typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::GenericMaskedDoseIterator::DoseAccessorPointer DoseAccessorPointer; /*! @brief GenericMaskedDoseIteratorTest. 1) test constructor (values as expected?) 2) test reset/next/get current values/isPositionValid */ int GenericMaskedDoseIteratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); + boost::shared_ptr spTestDoseAccessorInhomo = boost::make_shared(); + DoseAccessorPointer spDoseAccessorInhomo(spTestDoseAccessorInhomo); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); core::GeometricInfo geoInfo; boost::shared_ptr spTestMaskAccessor = boost::make_shared (geoInfo); MaskAccessorPointer spMaskAccessor(spTestMaskAccessor); //1) test constructor (values as expected?) //not NULL pointer MaskAccessorPointer spNullMaskAccessor; DoseAccessorPointer spNullDoseAccessor; CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spNullMaskAccessor, spDoseAccessor), core::NullPointerException); CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spNullDoseAccessor), core::NullPointerException); //not same core::GeometricInfo CHECK_THROW_EXPLICIT(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor), core::Exception); //set correct GeometricInfo geoInfo = spDoseAccessor->getGeometricInfo(); boost::shared_ptr spTestMaskAccessor1 = boost::make_shared (geoInfo); MaskAccessorPointer spMaskAccessorTemp(spTestMaskAccessor1); spMaskAccessor.swap(spMaskAccessorTemp); CHECK_NO_THROW(core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor)); + CHECK_EQUAL(spMaskAccessor->isGridHomogeneous(), true); core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor); + core::GenericMaskedDoseIterator genMaskedDoseIteratorInhomo(spMaskAccessor, spDoseAccessorInhomo); //2) test reset/next const DummyMaskAccessor::MaskVoxelListPointer maskedVoxelListPtr = spTestMaskAccessor1->getRelevantVoxelVector(); genMaskedDoseIterator.reset(); const DoseVoxelVolumeType homogeneousVoxelVolume = genMaskedDoseIterator.getCurrentVoxelVolume(); CHECK_EQUAL((maskedVoxelListPtr->begin())->getVoxelGridID(), genMaskedDoseIterator.getCurrentVoxelGridID()); geoInfo = spDoseAccessor->getGeometricInfo(); SpacingVectorType3D spacing = geoInfo.getSpacing(); CHECK_EQUAL(spacing(0)*spacing(1)*spacing(2) / 1000, genMaskedDoseIterator.getCurrentVoxelVolume()); + CHECK_THROW_EXPLICIT(genMaskedDoseIteratorInhomo.getCurrentVoxelVolume(), core::InvalidParameterException); + + genMaskedDoseIterator.reset(); + for (unsigned int i = 0; i < maskedVoxelListPtr->size(); i++) { + CHECK_NO_THROW(genMaskedDoseIterator.next()); + } + CHECK_EQUAL(genMaskedDoseIterator.getCurrentRelevantVolumeFraction(), 0); + //check if the correct voxels are accessed genMaskedDoseIterator.reset(); VoxelGridID defaultDoseVoxelGridID = genMaskedDoseIterator.getCurrentVoxelGridID(); DoseTypeGy controlValue = 0; VoxelGridID position = 0; while (genMaskedDoseIterator.isPositionValid()) { controlValue = doseVals->at((maskedVoxelListPtr->at(position)).getVoxelGridID()); CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentDoseValue()); controlValue = controlValue * (maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(); CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentMaskedDoseValue()); CHECK_EQUAL(homogeneousVoxelVolume, genMaskedDoseIterator.getCurrentVoxelVolume()); CHECK_EQUAL((maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(), genMaskedDoseIterator.getCurrentRelevantVolumeFraction()); CHECK_EQUAL((maskedVoxelListPtr->at(position)).getVoxelGridID(), genMaskedDoseIterator.getCurrentVoxelGridID()); CHECK(genMaskedDoseIterator.isPositionValid()); genMaskedDoseIterator.next(); position++; } //check isPositionValid() in invalid positions CHECK(!(genMaskedDoseIterator.isPositionValid())); //after end of dose genMaskedDoseIterator.reset(); CHECK_EQUAL(defaultDoseVoxelGridID, genMaskedDoseIterator.getCurrentVoxelGridID()); CHECK(genMaskedDoseIterator.isPositionValid());//at start of dose RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/core/MaskVoxelTest.cpp b/testing/core/MaskVoxelTest.cpp index c232a57..f573f29 100644 --- a/testing/core/MaskVoxelTest.cpp +++ b/testing/core/MaskVoxelTest.cpp @@ -1,94 +1,101 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*! @brief MaskVoxelTest - test the API of MaskVoxel 1) test constructors (values as expected?) 2) test set/getRelevantVolumeFraction - 4) test operators "==" + 3) test operators "==" + 4) test operator "<" */ int MaskVoxelTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test constructors (values as expected?) //MaskVoxel(const VoxelGridID& aVoxelGridID); VoxelGridID anID = 5; const FractionType defaultFraction = 1; CHECK_NO_THROW(core::MaskVoxel MaskVoxel(anID)); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID), core::InvalidParameterException); core::MaskVoxel aMaskVoxel2(anID); CHECK_EQUAL(anID, aMaskVoxel2.getVoxelGridID()); CHECK_EQUAL(defaultFraction, aMaskVoxel2.getRelevantVolumeFraction()); //MaskVoxel(const VoxelGridID& aVoxelGridID, FractionType aVolumeFraction) anID = 15; FractionType aFraction = 0.73; CHECK_NO_THROW(core::MaskVoxel MaskVoxel(anID, aFraction)); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(anID, -aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, -aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(anID, aFraction + 2), core::InvalidParameterException); CHECK_THROW_EXPLICIT(core::MaskVoxel MaskVoxel(-anID, aFraction + 2), core::InvalidParameterException); core::MaskVoxel aMaskVoxel3(anID, aFraction); CHECK_EQUAL(anID, aMaskVoxel3.getVoxelGridID()); CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); //2) test set/getRelevantVolumeFraction aFraction = 0.42; anID = aMaskVoxel3.getVoxelGridID(); CHECK_NO_THROW(aMaskVoxel3.setRelevantVolumeFraction(aFraction)); CHECK_THROW_EXPLICIT(aMaskVoxel3.setRelevantVolumeFraction(-aFraction), core::InvalidParameterException); CHECK_THROW_EXPLICIT(aMaskVoxel3.setRelevantVolumeFraction(aFraction + 2), core::InvalidParameterException); aMaskVoxel3.setRelevantVolumeFraction(aFraction); CHECK_EQUAL(anID, aMaskVoxel3.getVoxelGridID()); CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); - //4) test operators "==" + //3) test operators "==" CHECK(!(aMaskVoxel2 == aMaskVoxel3)); //not equal core::MaskVoxel aMaskVoxel4(aMaskVoxel3.getVoxelGridID()); CHECK(!(aMaskVoxel4 == aMaskVoxel3)); //equal ID, but unequal volume fraction -> not equal aMaskVoxel4.setRelevantVolumeFraction(aMaskVoxel3.getRelevantVolumeFraction()); CHECK_EQUAL(aMaskVoxel4, aMaskVoxel3); //equal aMaskVoxel2.setRelevantVolumeFraction(aMaskVoxel3.getRelevantVolumeFraction()); CHECK(!(aMaskVoxel2 == aMaskVoxel3)); //no equal ID -> not equal + //4) test operator "<" + core::MaskVoxel aMaskVoxel5(2); + CHECK(aMaskVoxel2 < aMaskVoxel3); + CHECK(!(aMaskVoxel3 < aMaskVoxel4)); + CHECK(!(aMaskVoxel4 < aMaskVoxel5)); + RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/StrVectorStructureSetGeneratorTest.cpp b/testing/core/StrVectorStructureSetGeneratorTest.cpp index 8ff82aa..22a4afb 100644 --- a/testing/core/StrVectorStructureSetGeneratorTest.cpp +++ b/testing/core/StrVectorStructureSetGeneratorTest.cpp @@ -1,86 +1,97 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" #include "DummyStructure.h" #include "DummyDoseAccessor.h" #include "rttbInvalidParameterException.h" #include "rttbStructure.h" -#include "rttbStructureSet.h" namespace rttb { namespace testing { - /*! @brief StructureTest - tests the API for Structure - 1) constructors - 2) get/setXX + /*! @brief StrVectorStructureSetGeneratorTest - tests the API for Structure + 1) empty structure vector + 2) dummy structure + 3) with regex */ int StrVectorStructureSetGeneratorTest(int argc, char* argv[]) { typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef core::StructureSet::StructTypePointer StructTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //1) empty structure vector std::vector strVector; CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator1(strVector)); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); CHECK_EQUAL(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getNumberOfStructures(), 0); CHECK_THROW_EXPLICIT(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getStructure(0), core::InvalidParameterException); - //1) dummy structure + //2) dummy structure boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer rectStrPtr = boost::make_shared(rect); + rectStrPtr->setLabel("test"); strVector.push_back(rectStrPtr); CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator2(strVector)); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); CHECK_EQUAL(core::StrVectorStructureSetGenerator( strVector).generateStructureSet()->getNumberOfStructures(), 1); CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()->getStructure( 0)); - + //3) with regex + StructTypePointer rectStrPtr2 = boost::make_shared(rect); + rectStrPtr2->setLabel("none"); + strVector.push_back(rectStrPtr2); + + core::StrVectorStructureSetGenerator generator(strVector); + generator.setStructureLabelFilterActive(true); + generator.setFilterRegEx("test"); + CHECK_NO_THROW(generator.generateStructureSet()); + CHECK_EQUAL(generator.generateStructureSet()->getNumberOfStructures(), 1); + CHECK_EQUAL(generator.generateStructureSet()->getStructure(0)->getLabel(), "test"); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/core/StrVectorStructureSetGeneratorTest.cpp b/testing/core/StructureSetTest.cpp similarity index 52% copy from testing/core/StrVectorStructureSetGeneratorTest.cpp copy to testing/core/StructureSetTest.cpp index 8ff82aa..691fdb8 100644 --- a/testing/core/StrVectorStructureSetGeneratorTest.cpp +++ b/testing/core/StructureSetTest.cpp @@ -1,86 +1,82 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notices for more information. -// -//------------------------------------------------------------------------ -/*! -// @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ - -#include - -#include "litCheckMacros.h" - -#include "rttbBaseType.h" -#include "rttbStrVectorStructureSetGenerator.h" -#include "DummyStructure.h" -#include "DummyDoseAccessor.h" -#include "rttbInvalidParameterException.h" -#include "rttbStructure.h" -#include "rttbStructureSet.h" - -namespace rttb -{ - namespace testing - { - - /*! @brief StructureTest - tests the API for Structure - 1) constructors - 2) get/setXX - */ - int StrVectorStructureSetGeneratorTest(int argc, char* argv[]) - { - typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; - - typedef core::StructureSet::StructTypePointer StructTypePointer; - - PREPARE_DEFAULT_TEST_REPORTING; - - //1) empty structure vector - std::vector strVector; - - CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator1(strVector)); - CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); - CHECK_EQUAL(core::StrVectorStructureSetGenerator( - strVector).generateStructureSet()->getNumberOfStructures(), 0); - CHECK_THROW_EXPLICIT(core::StrVectorStructureSetGenerator( - strVector).generateStructureSet()->getStructure(0), core::InvalidParameterException); - - - //1) dummy structure - boost::shared_ptr spTestDoseAccessor = - boost::make_shared(); - - DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); - GridIndexType zPlane = 4; - core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); - StructTypePointer rectStrPtr = boost::make_shared(rect); - - strVector.push_back(rectStrPtr); - - CHECK_NO_THROW(core::StrVectorStructureSetGenerator generator2(strVector)); - CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()); - CHECK_EQUAL(core::StrVectorStructureSetGenerator( - strVector).generateStructureSet()->getNumberOfStructures(), 1); - CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()->getStructure( - 0)); - - - - RETURN_AND_REPORT_TEST_SUCCESS; - } - - }//testing +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) +*/ + +#include + +#include "litCheckMacros.h" + +#include "DummyStructure.h" +#include "DummyDoseAccessor.h" +#include "rttbInvalidParameterException.h" +#include "rttbStructure.h" +#include "rttbStructureSet.h" + +namespace rttb +{ + namespace testing + { + + /*! @brief StructureSet - tests the API for StructureSet + 1) constructor + 2) getters + */ + int StructureSetTest(int argc, char* argv[]) + { + typedef core::StructureSet::StructTypePointer StructTypePointer; + + PREPARE_DEFAULT_TEST_REPORTING; + + boost::shared_ptr spTestDoseAccessor = + boost::make_shared(); + + DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); + GridIndexType zPlane = 4; + core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); + StructTypePointer rectStrPtr = boost::make_shared(rect); + rectStrPtr->setLabel("test"); + StructTypePointer rectStrPtr2 = boost::make_shared(rect); + rectStrPtr2->setLabel("none"); + const IDType patientUID("patientUID"); + const IDType UID("UID"); + + //1) constructor + CHECK_NO_THROW(core::StructureSet({ })); + core::StructureSet structureSetDefault({ }); + CHECK_NO_THROW(core::StructureSet({ rectStrPtr, rectStrPtr2 }, patientUID, UID)); + core::StructureSet structureSet({rectStrPtr, rectStrPtr2}, patientUID, UID); + + //2) getters + CHECK_EQUAL(structureSetDefault.getNumberOfStructures(), 0); + CHECK_EQUAL(structureSet.getNumberOfStructures(), 2); + CHECK_EQUAL(structureSet.getStructure(0)->getLabel(), "test"); + CHECK_EQUAL(structureSet.getStructure(1)->getLabel(), "none"); + CHECK_THROW_EXPLICIT(structureSet.getStructure(2), core::InvalidParameterException); + + CHECK_EQUAL(structureSet.getUID(), UID); + CHECK_EQUAL(structureSet.getPatientUID(), patientUID); + CHECK_NO_THROW(structureSetDefault.getUID()); + CHECK_NO_THROW(structureSetDefault.getPatientUID()); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing }//rttb \ No newline at end of file diff --git a/testing/core/files.cmake b/testing/core/files.cmake index 5951c5e..612a4d6 100644 --- a/testing/core/files.cmake +++ b/testing/core/files.cmake @@ -1,27 +1,31 @@ SET(CPP_FILES rttbCoreTests.cpp DummyDoseAccessor.cpp + DummyInhomogeneousDoseAccessor.cpp DummyMaskAccessor.cpp DummyMutableDoseAccessor.cpp DummyDVHGenerator.cpp DummyStructure.cpp CreateTestStructure.cpp StructureTest.cpp GeometricInfoTest.cpp MaskVoxelTest.cpp GenericDoseIteratorTest.cpp GenericMaskedDoseIteratorTest.cpp DVHCalculatorTest.cpp DVHTest.cpp DVHSetTest.cpp StrVectorStructureSetGeneratorTest.cpp + StructureSetTest.cpp + BaseTypeTest.cpp ) SET(H_FILES DummyStructure.h CreateTestStructure.h DummyDoseAccessor.h + DummyInhomogeneousDoseAccessor.h DummyMaskAccessor.h DummyMutableDoseAccessor.h DummyDVHGenerator.h ) diff --git a/testing/core/rttbCoreTests.cpp b/testing/core/rttbCoreTests.cpp index 7502b20..fb9dd3b 100644 --- a/testing/core/rttbCoreTests.cpp +++ b/testing/core/rttbCoreTests.cpp @@ -1,71 +1,73 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(GeometricInfoTest); LIT_REGISTER_TEST(MaskVoxelTest); LIT_REGISTER_TEST(GenericDoseIteratorTest); LIT_REGISTER_TEST(GenericMaskedDoseIteratorTest); LIT_REGISTER_TEST(DVHCalculatorTest); LIT_REGISTER_TEST(DVHTest); LIT_REGISTER_TEST(DVHSetTest); LIT_REGISTER_TEST(GeometricInfoTest); LIT_REGISTER_TEST(MaskVoxelTest); LIT_REGISTER_TEST(GenericDoseIteratorTest); LIT_REGISTER_TEST(StructureTest); LIT_REGISTER_TEST(StrVectorStructureSetGeneratorTest); + LIT_REGISTER_TEST(StructureSetTest); + LIT_REGISTER_TEST(BaseTypeTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; }