diff --git a/code/algorithms/rttbDoseStatistics.cpp b/code/algorithms/rttbDoseStatistics.cpp index 3f737fd..14860e3 100644 --- a/code/algorithms/rttbDoseStatistics.cpp +++ b/code/algorithms/rttbDoseStatistics.cpp @@ -1,338 +1,344 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDoseStatistics.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { DoseStatistics::DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, DoseStatisticType stdDeviation, unsigned int numVoxels, VolumeType volume, ResultListPointer maximumVoxelPositions /*= ResultListPointer()*/, ResultListPointer minimumVoxelPositions /*= ResultListPointer()*/, VolumeToDoseFunctionType Dx /*= std::map()*/, DoseToVolumeFunctionType Vx /*= std::map()*/, VolumeToDoseFunctionType MOHx /*= std::map()*/, VolumeToDoseFunctionType MOCx /*= std::map()*/, VolumeToDoseFunctionType MaxOHx /*= std::map()*/, VolumeToDoseFunctionType MinOCx /*= std::map()*/, - DoseTypeGy referenceDose /*=-1*/): - _minimum(minimum), _maximum(maximum), _mean(mean), _stdDeviation(stdDeviation), _numVoxels(numVoxels), _volume(volume), + DoseTypeGy referenceDose /*=-1*/): + _minimum(minimum), _maximum(maximum), _mean(mean), _stdDeviation(stdDeviation), + _numVoxels(numVoxels), _volume(volume), _maximumVoxelPositions(maximumVoxelPositions), _minimumVoxelPositions(minimumVoxelPositions), _Dx(Dx), _Vx(Vx), _MOHx(MOHx), _MOCx(MOCx), _MaxOHx(MaxOHx), _MinOCx(MinOCx) { - if (referenceDose <= 0){ + if (referenceDose <= 0) + { _referenceDose = _maximum; } - else{ + else + { _referenceDose = referenceDose; } } DoseStatistics::~DoseStatistics() { } void DoseStatistics::setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions) { _minimumVoxelPositions = minimumVoxelPositions; } void DoseStatistics::setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions) { _maximumVoxelPositions = maximumVoxelPositions; } void DoseStatistics::setDx(const DoseToVolumeFunctionType& DxValues) { _Dx = DxValues; } void DoseStatistics::setVx(const VolumeToDoseFunctionType& VxValues) { _Vx = VxValues; } void DoseStatistics::setMOHx(const VolumeToDoseFunctionType& MOHxValues) { _MOHx = MOHxValues; } void DoseStatistics::setMOCx(const VolumeToDoseFunctionType& MOCxValues) { _MOCx = MOCxValues; } void DoseStatistics::setMaxOHx(const VolumeToDoseFunctionType& MaxOHValues) { _MaxOHx = MaxOHValues; } void DoseStatistics::setMinOCx(const VolumeToDoseFunctionType& MinOCValues) { _MinOCx = MinOCValues; } - void DoseStatistics::setReferenceDose(DoseTypeGy referenceDose){ - if (referenceDose <= 0){ + void DoseStatistics::setReferenceDose(DoseTypeGy referenceDose) + { + if (referenceDose <= 0) + { _referenceDose = _maximum; } - else{ + else + { _referenceDose = referenceDose; } } unsigned int DoseStatistics::getNumberOfVoxels() const { return _numVoxels; } VolumeType DoseStatistics::getVolume() const { return _volume; } DoseTypeGy DoseStatistics::getReferenceDose() const { return _referenceDose; } DoseStatisticType DoseStatistics::getMaximum() const { return _maximum; } DoseStatisticType DoseStatistics::getMinimum() const { return _minimum; } DoseStatisticType DoseStatistics::getMean() const { return _mean; } DoseStatisticType DoseStatistics::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DoseStatistics::getVariance() const { return _stdDeviation * _stdDeviation; } VolumeType DoseStatistics::getVx(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const { return getValue(_Vx, xDoseAbsolute, findNearestValue, nearestXDose); } VolumeType DoseStatistics::getVx(DoseTypeGy xDoseAbsolute) const { DoseTypeGy dummy; return getValue(_Vx, xDoseAbsolute, false, dummy); } DoseTypeGy DoseStatistics::getDx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const { return getValue(_Dx, xVolumeAbsolute, findNearestValue, nearestXVolume); } DoseTypeGy DoseStatistics::getDx(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getValue(_Dx, xVolumeAbsolute, false, dummy); } DoseTypeGy DoseStatistics::getMOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const { return getValue(_MOHx, xVolumeAbsolute, findNearestValue, nearestXVolume); } DoseTypeGy DoseStatistics::getMOHx(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getValue(_MOHx, xVolumeAbsolute, false, dummy); } DoseTypeGy DoseStatistics::getMOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& maximumDistanceFromOriginalVolume) const { return getValue(_MOCx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); } DoseTypeGy DoseStatistics::getMOCx(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getValue(_MOCx, xVolumeAbsolute, false, dummy); } DoseTypeGy DoseStatistics::getMaxOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& maximumDistanceFromOriginalVolume) const { return getValue(_MaxOHx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); } DoseTypeGy DoseStatistics::getMaxOHx(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getValue(_MaxOHx, xVolumeAbsolute, false, dummy); } DoseTypeGy DoseStatistics::getMinOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& maximumDistanceFromOriginalVolume) const { return getValue(_MinOCx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); } DoseTypeGy DoseStatistics::getMinOCx(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getValue(_MinOCx, xVolumeAbsolute, false, dummy); } double DoseStatistics::getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const { if (aMap.find(key) != std::end(aMap)) { return aMap.find(key)->second; } else { //value not in map. We have to find the nearest value if (aMap.empty()) { throw core::DataNotAvailableException("No Vx values are defined"); } else { if (findNearestValueInstead) { auto iterator = findNearestKeyInMap(aMap, key); storedKey = iterator->first; return iterator->second; } else { throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } } } std::map::const_iterator DoseStatistics::findNearestKeyInMap( const std::map& aMap, double key) const { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(aMap); while (iterator != std::end(aMap)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(aMap)) { --iterator; return iterator; } else { return std::begin(aMap); } } } --iterator; return iterator; } DoseStatistics::ResultListPointer DoseStatistics::getMaximumPositions() const { return _maximumVoxelPositions; } DoseStatistics::ResultListPointer DoseStatistics::getMinimumPositions() const { return _minimumVoxelPositions; } DoseStatistics::DoseToVolumeFunctionType DoseStatistics::getAllVx() const { return _Vx; } DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllDx() const { return _Dx; } DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMOHx() const { return _MOHx; } DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMOCx() const { return _MOCx; } DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMaxOHx() const { return _MaxOHx; } DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMinOCx() const { return _MinOCx; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatistics.h b/code/algorithms/rttbDoseStatistics.h index d57f62e..726436d 100644 --- a/code/algorithms/rttbDoseStatistics.h +++ b/code/algorithms/rttbDoseStatistics.h @@ -1,218 +1,220 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_STATISTICS_H #define __DOSE_STATISTICS_H #include #include #include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" namespace rttb { namespace algorithms { /*! @class DoseStatistics @brief This is a data class storing different statistical values from a rt dose distribution @sa DoseStatisticsCalculator */ class DoseStatistics { public: enum complexStatistics { Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx }; typedef boost::shared_ptr > > ResultListPointer; typedef boost::shared_ptr DoseStatisticsPointer; typedef std::map DoseToVolumeFunctionType; typedef std::map VolumeToDoseFunctionType; private: double getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const; std::map::const_iterator findNearestKeyInMap(const std::map& aMap, double key) const; DoseStatisticType _maximum; DoseStatisticType _minimum; ResultListPointer _maximumVoxelPositions; ResultListPointer _minimumVoxelPositions; DoseStatisticType _mean; DoseStatisticType _stdDeviation; unsigned int _numVoxels; VolumeType _volume; DoseTypeGy _referenceDose; //for Vx computation VolumeToDoseFunctionType _Dx; DoseToVolumeFunctionType _Vx; VolumeToDoseFunctionType _MOHx; VolumeToDoseFunctionType _MOCx; VolumeToDoseFunctionType _MaxOHx; VolumeToDoseFunctionType _MinOCx; public: /*! @brief Standard Constructor */ //DoseStatistics(); /*! @brief Constructor @detail the dose statistic values are set. Complex values maximumVoxelLocation, maximumVoxelLocation, Dx, Vx, MOHx, MOCx, MaxOHx and MinOCx are optional */ DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, DoseStatisticType stdDeviation, unsigned int numVoxels, VolumeType volume, - ResultListPointer minimumVoxelPositions = boost::make_shared > > + ResultListPointer minimumVoxelPositions = + boost::make_shared > > (std::vector >()), - ResultListPointer maximumVoxelPositions = boost::make_shared > > + ResultListPointer maximumVoxelPositions = + boost::make_shared > > (std::vector >()), VolumeToDoseFunctionType Dx = VolumeToDoseFunctionType(), DoseToVolumeFunctionType Vx = DoseToVolumeFunctionType(), VolumeToDoseFunctionType MOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MOCx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MaxOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MinOCx = VolumeToDoseFunctionType(), DoseTypeGy referenceDose = -1); ~DoseStatistics(); void setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions); void setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions); void setDx(const DoseToVolumeFunctionType& DxValues); void setVx(const VolumeToDoseFunctionType& VxValues); void setMOHx(const VolumeToDoseFunctionType& MOHxValues); void setMOCx(const VolumeToDoseFunctionType& MOCxValues); void setMaxOHx(const VolumeToDoseFunctionType& MaxOHxValues); void setMinOCx(const VolumeToDoseFunctionType& MinOCxValues); void setReferenceDose(DoseTypeGy referenceDose); /*! @brief Get number of voxels in doseIterator, with sub-voxel accuracy. */ unsigned int getNumberOfVoxels() const; /*! @brief Get the volume of the voxels in doseIterator (in cm3), with sub-voxel accuracy */ VolumeType getVolume() const; /*! @brief Get the reference dose for Vx computation */ DoseTypeGy getReferenceDose() const; /*! @brief Get the maximum of the current dose distribution. @return Return the maximum dose in Gy */ DoseStatisticType getMaximum() const; /*! @brief Get a vector of the the maximum dose VoxelGridIDs together with their dose value in Gy @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMaximumPositions() const; /*! @brief Get the minimum of the current dose distribution. @return Return the minimum dose in Gy */ DoseStatisticType getMinimum() const; /*! @brief Get a vector of the the minimum dose VoxelGridIDs together with their dose value in Gy @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMinimumPositions() const; /*! @brief Get the mean of the current dose distribution. @return Return the mean dose in Gy */ DoseStatisticType getMean() const; /*! @brief Get the standard deviation of the current dose distribution. @return Return the standard deviation in Gy */ DoseStatisticType getStdDeviation() const; /*! @brief Get the variance of of the current dose distribution. @return Return the variance in Gy */ DoseStatisticType getVariance() const; /*! @brief Get Vx: the volume irradiated with a dose >= x. @return Return absolute volume in absolute cm^3. @exception NoDataException if the Vx values have not been set (i.e. the vector is empty) @exception NoDataException if the requested Dose is not in the vector */ VolumeType getVx(DoseTypeGy xDoseAbsolute) const; VolumeType getVx(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const; DoseToVolumeFunctionType getAllVx() const; /*! @brief Get Dx: the minimal dose delivered to part x of the current volume. @return Return dose value in Gy. @exception InvalidDoseException if the Dx values have not been set (i.e. the vector is empty) */ DoseTypeGy getDx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getDx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllDx() const; /*! @brief Get MOHx: mean dose of the hottest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMOHx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMOHx() const; /*! @brief Get MOCx: mean dose of the coldest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMOCx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMOCx() const; /*! @brief Get MaxOHx: Maximum outside of the hottest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMaxOHx() const; /*! @brief Get MinOCx: Minimum outside of the coldest x voxels. @return Return dose value in Gy. @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute) const; VolumeToDoseFunctionType getAllMinOCx() const; }; } } #endif diff --git a/code/algorithms/rttbDoseStatisticsCalculator.cpp b/code/algorithms/rttbDoseStatisticsCalculator.cpp index cfbcb33..d51bfbc 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.cpp +++ b/code/algorithms/rttbDoseStatisticsCalculator.cpp @@ -1,600 +1,625 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDoseStatisticsCalculator.h" #include #include #include #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace algorithms { DoseStatisticsCalculator::DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator) { if (aDoseIterator == NULL) { throw core::NullPointerException("DoseIterator must not be NULL"); } else { _doseIterator = aDoseIterator; } _simpleDoseStatisticsCalculated = false; } DoseStatisticsCalculator::~DoseStatisticsCalculator() { } DoseStatisticsCalculator::DoseIteratorPointer DoseStatisticsCalculator::getDoseIterator() const { return _doseIterator; } - DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics(bool computeComplexMeasures, unsigned int maxNumberMinimaPositions, - unsigned int maxNumberMaximaPositions){ + DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( + bool computeComplexMeasures, unsigned int maxNumberMinimaPositions, + unsigned int maxNumberMaximaPositions) + { if (!_doseIterator) { throw core::NullPointerException("_doseIterator must not be NULL!"); } //"simple" dose statistics are mandatory calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); - if (computeComplexMeasures){ + if (computeComplexMeasures) + { //more complex dose statistics are optional with default maximum dose and default relative x values - calculateComplexDoseStatistics(_statistics->getMaximum(), std::vector(), std::vector()); + calculateComplexDoseStatistics(_statistics->getMaximum(), std::vector(), + std::vector()); } return _statistics; } - DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics(DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, - unsigned int maxNumberMaximaPositions){ + DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( + DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, + unsigned int maxNumberMaximaPositions) + { if (!_doseIterator) { throw core::NullPointerException("_doseIterator must not be NULL!"); } - if (referenceDose <= 0){ + if (referenceDose <= 0) + { throw rttb::core::InvalidParameterException("Reference dose must be > 0 !"); } //simple dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); //more complex dose statistics with given reference dose and default x values calculateComplexDoseStatistics(referenceDose, std::vector(), std::vector()); return _statistics; } - DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics(const std::vector& precomputeDoseValues, - const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, - unsigned int maxNumberMaximaPositions) + DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( + const std::vector& precomputeDoseValues, + const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose, + unsigned int maxNumberMinimaPositions, + unsigned int maxNumberMaximaPositions) { if (!_doseIterator) { throw core::NullPointerException("_doseIterator must not be NULL!"); } - //"simple" dose statistics + //"simple" dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); - if (referenceDose <= 0){ + if (referenceDose <= 0) + { //more complex dose statistics with default maximum dose and relative x values - calculateComplexDoseStatistics(_statistics->getMaximum(), precomputeDoseValues, precomputeVolumeValues); + calculateComplexDoseStatistics(_statistics->getMaximum(), precomputeDoseValues, + precomputeVolumeValues); } - else{ + else + { //more complex dose statistics with given reference dose and relative x values calculateComplexDoseStatistics(referenceDose, precomputeDoseValues, precomputeVolumeValues); } return _statistics; } void DoseStatisticsCalculator::calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { _doseVector.clear(); _voxelProportionVector.clear(); std::multimap doseValueVSIndexMap; std::vector voxelProportionVectorTemp; DoseStatisticType maximumDose = 0; DoseStatisticType minimumDose = std::numeric_limits::max(); DoseStatisticType meanDose; DoseStatisticType stdDeviationDose; DoseTypeGy sum = 0; VolumeType numVoxels = 0.0; DoseTypeGy squareSum = 0; VolumeType volume = 0; _doseIterator->reset(); int i = 0; DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid()) { doseValue = _doseIterator->getCurrentDoseValue(); if (i == 0) { minimumDose = doseValue; volume = _doseIterator->getCurrentVoxelVolume(); } rttb::FractionType voxelProportion = _doseIterator->getCurrentRelevantVolumeFraction(); sum += doseValue * voxelProportion; numVoxels += voxelProportion; squareSum += doseValue * doseValue * voxelProportion; if (doseValue > maximumDose) { maximumDose = doseValue; } else if (doseValue < minimumDose) { minimumDose = doseValue; } voxelProportionVectorTemp.push_back(voxelProportion); doseValueVSIndexMap.insert(std::pair(doseValue, i)); i++; _doseIterator->next(); } if (numVoxels != 0) { meanDose = sum / numVoxels; //standard deviation is defined only for n>=2 if (numVoxels >= 2) { //uncorrected variance is calculated DoseStatisticType varianceDose = (squareSum / numVoxels - meanDose * meanDose); if (varianceDose < errorConstant) { stdDeviationDose = 0; } else { stdDeviationDose = pow(varianceDose, 0.5); } } else { stdDeviationDose = 0; } } //sort dose values and corresponding volume fractions in member variables for (auto it = doseValueVSIndexMap.begin(); it != doseValueVSIndexMap.end(); ++it) { _doseVector.push_back((float)(*it).first); _voxelProportionVector.push_back(voxelProportionVectorTemp.at((*it).second)); } volume *= numVoxels; - _statistics = boost::make_shared(minimumDose, maximumDose, meanDose, stdDeviationDose, numVoxels, + _statistics = boost::make_shared(minimumDose, maximumDose, meanDose, + stdDeviationDose, numVoxels, volume); _simpleDoseStatisticsCalculated = true; ResultListPointer minimumVoxelPositions = computeMinimumPositions(maxNumberMinimaPositions); ResultListPointer maximumVoxelPositions = computeMaximumPositions(maxNumberMaximaPositions); _statistics->setMinimumVoxelPositions(minimumVoxelPositions); _statistics->setMaximumVoxelPositions(maximumVoxelPositions); } - void DoseStatisticsCalculator::calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector& precomputeDoseValues, + void DoseStatisticsCalculator::calculateComplexDoseStatistics(DoseTypeGy referenceDose, + const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues) { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call calculateComplexDoseStatistics()"); } std::vector precomputeDoseValuesNonConst = precomputeDoseValues; std::vector precomputeVolumeValuesNonConst = precomputeVolumeValues; //set default values if (precomputeDoseValues.empty()) { - std::vector defaultPrecomputeDoseValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)(0.95)(0.98); + std::vector defaultPrecomputeDoseValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( + 0.95)(0.98); precomputeDoseValuesNonConst = defaultPrecomputeDoseValues; } if (precomputeVolumeValues.empty()) { - std::vector defaultPrecomputeVolumeValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)(0.95)(0.98); + std::vector defaultPrecomputeVolumeValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( + 0.95)(0.98); precomputeVolumeValuesNonConst = defaultPrecomputeVolumeValues; } - DoseToVolumeFunctionType Vx = computeDoseToVolumeFunctionMulti(referenceDose, precomputeDoseValuesNonConst, DoseStatistics::Vx); - VolumeToDoseFunctionType Dx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, DoseStatistics::Dx); - VolumeToDoseFunctionType MOHx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, DoseStatistics::MOHx); - VolumeToDoseFunctionType MOCx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, DoseStatistics::MOCx); + DoseToVolumeFunctionType Vx = computeDoseToVolumeFunctionMulti(referenceDose, + precomputeDoseValuesNonConst, DoseStatistics::Vx); + VolumeToDoseFunctionType Dx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, + DoseStatistics::Dx); + VolumeToDoseFunctionType MOHx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, + DoseStatistics::MOHx); + VolumeToDoseFunctionType MOCx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, + DoseStatistics::MOCx); VolumeToDoseFunctionType MaxOHx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, DoseStatistics::MaxOHx); VolumeToDoseFunctionType MinOCx = computeVolumeToDoseFunctionMulti(precomputeVolumeValuesNonConst, DoseStatistics::MinOCx); _statistics->setVx(Vx); _statistics->setDx(Dx); _statistics->setMOHx(MOHx); _statistics->setMOCx(MOCx); _statistics->setMaxOHx(MaxOHx); _statistics->setMinOCx(MinOCx); _statistics->setReferenceDose(referenceDose); } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMaximumPositions( unsigned int maxNumberMaxima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMaximumPositions()"); } - ResultListPointer maxVoxelVector = boost::make_shared > >(); + ResultListPointer maxVoxelVector = + boost::make_shared > >(); unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMaxima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMaximum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair voxel(doseValue, currentID); maxVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return maxVoxelVector; } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMinimumPositions( unsigned int maxNumberMinima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMinimumPositions()"); } - ResultListPointer minVoxelVector = boost::make_shared > >(); + ResultListPointer minVoxelVector = + boost::make_shared > >(); /*! @todo: Architecture Annotation: Finding the positions for the minimum only once reduces computation time, but will require sensible use by the programmers. To be save the output vector minVoxelVector will be always cleared here to garantee that no false values are presented. This change may be revoced to increase computation speed later on (only compute if(minVoxelVector->size()==0)). */ unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMinima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMinimum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair voxel(doseValue, currentID); minVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return minVoxelVector; } VolumeType DoseStatisticsCalculator::computeVx(DoseTypeGy xDoseAbsolute) const { rttb::FractionType count = 0; _doseIterator->reset(); DoseTypeGy currentDose = 0; while (_doseIterator->isPositionValid()) { currentDose = _doseIterator->getCurrentDoseValue(); if (currentDose >= xDoseAbsolute) { count += _doseIterator->getCurrentRelevantVolumeFraction(); } _doseIterator->next(); } return count * this->_doseIterator->getCurrentVoxelVolume(); } DoseTypeGy DoseStatisticsCalculator::computeDx(VolumeType xVolumeAbsolute) const { double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); DoseTypeGy resultDose = 0; double countVoxels = 0; int i = static_cast(_doseVector.size() - 1); for (; i >= 0; i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { break; } } if (i >= 0) { resultDose = _doseVector.at(i); } else { resultDose = _statistics->getMinimum(); } return resultDose; } DoseTypeGy DoseStatisticsCalculator::computeMOHx(VolumeType xVolumeAbsolute) const { double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; for (int i = static_cast(_doseVector.size() - 1); i >= 0; i--) { double voxelProportion = _voxelProportionVector.at(i); countVoxels += voxelProportion; sum += _doseVector.at(i) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return (DoseTypeGy)(sum / noOfVoxel); } } DoseTypeGy DoseStatisticsCalculator::computeMOCx(DoseTypeGy xVolumeAbsolute) const { double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; std::vector::const_iterator it = _doseVector.begin(); std::vector::const_iterator itD = _voxelProportionVector.begin(); for (; it != _doseVector.end(); ++it, ++itD) { double voxelProportion = *itD; countVoxels += voxelProportion; sum += (*it) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return (DoseTypeGy)(sum / noOfVoxel); } } DoseTypeGy DoseStatisticsCalculator::computeMaxOHx(DoseTypeGy xVolumeAbsolute) const { double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); DoseTypeGy resultDose = 0; double countVoxels = 0; int i = static_cast(_doseVector.size() - 1); for (; i >= 0; i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { break; } } if (i - 1 >= 0) { resultDose = _doseVector.at(i - 1); } return resultDose; } DoseTypeGy DoseStatisticsCalculator::computeMinOCx(DoseTypeGy xVolumeAbsolute) const { double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); DoseTypeGy resultDose = 0; double countVoxels = 0; std::vector::const_iterator it = _doseVector.begin(); std::vector::const_iterator itD = _voxelProportionVector.begin(); for (; itD != _voxelProportionVector.end(); ++itD, ++it) { countVoxels += *itD; if (countVoxels >= noOfVoxel) { break; } } if (it != _doseVector.end()) { ++it; if (it != _doseVector.end()) { resultDose = *it; } else { resultDose = (DoseTypeGy)_statistics->getMaximum(); } } else { resultDose = (DoseTypeGy)_statistics->getMinimum(); } return resultDose; } - DoseStatisticsCalculator::DoseToVolumeFunctionType DoseStatisticsCalculator::computeDoseToVolumeFunctionMulti(DoseTypeGy referenceDose, - const std::vector& precomputeDoseValues, DoseStatistics::complexStatistics name) const + DoseStatisticsCalculator::DoseToVolumeFunctionType + DoseStatisticsCalculator::computeDoseToVolumeFunctionMulti(DoseTypeGy referenceDose, + const std::vector& precomputeDoseValues, DoseStatistics::complexStatistics name) const { DoseToVolumeFunctionType VxMulti; for (int i = 0; i < precomputeDoseValues.size(); ++i) { if (name == DoseStatistics::Vx) { double xAbsolue = precomputeDoseValues.at(i) * referenceDose; VxMulti.insert(std::pair(xAbsolue, - computeVx(xAbsolue))); + computeVx(xAbsolue))); } else { throw core::InvalidParameterException("unknown DoseStatistics name!"); } } return VxMulti; } - DoseStatisticsCalculator::VolumeToDoseFunctionType DoseStatisticsCalculator::computeVolumeToDoseFunctionMulti( + DoseStatisticsCalculator::VolumeToDoseFunctionType + DoseStatisticsCalculator::computeVolumeToDoseFunctionMulti( const std::vector& precomputeVolumeValues, DoseStatistics::complexStatistics name) const { VolumeToDoseFunctionType multiValues; VolumeType volume = _statistics->getVolume(); for (int i = 0; i < precomputeVolumeValues.size(); ++i) { double xAbsolute = precomputeVolumeValues.at(i) * volume; + switch (name) { case DoseStatistics::Dx: multiValues.insert(std::pair(xAbsolute, - computeDx(xAbsolute))); + computeDx(xAbsolute))); break; case DoseStatistics::MOHx: multiValues.insert(std::pair(xAbsolute, - computeMOHx(xAbsolute))); + computeMOHx(xAbsolute))); break; case DoseStatistics::MOCx: multiValues.insert(std::pair(xAbsolute, - computeMOCx(xAbsolute))); + computeMOCx(xAbsolute))); break; case DoseStatistics::MaxOHx: multiValues.insert(std::pair(xAbsolute, - computeMaxOHx(xAbsolute))); + computeMaxOHx(xAbsolute))); break; case DoseStatistics::MinOCx: multiValues.insert(std::pair(xAbsolute, - computeMinOCx(xAbsolute))); + computeMinOCx(xAbsolute))); break; default: throw core::InvalidParameterException("unknown DoseStatistics name!"); } } return multiValues; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatisticsCalculator.h b/code/algorithms/rttbDoseStatisticsCalculator.h index 99f1af2..ff979d0 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.h +++ b/code/algorithms/rttbDoseStatisticsCalculator.h @@ -1,175 +1,182 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_STATISTICS_CALCULATOR_H #define __DOSE_STATISTICS_CALCULATOR_H #include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDoseStatistics.h" namespace rttb { namespace algorithms { /*! @class DoseStatisticsCalculator @brief Class for calculating different statistical values from a RT dose distribution @details These values range from standard statistical values such as minimum, maximum and mean to more complex dose specific measures such as Vx (volume irradiated with a dose >=x), Dx (minimal dose delivered to x% of the VOI) or MOHx (mean in the hottest volume). For a complete list, see calculateDoseStatistics(). @note the complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set in calculateDoseStatistics() */ class DoseStatisticsCalculator { public: typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; typedef DoseStatistics::ResultListPointer ResultListPointer; typedef DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; typedef DoseStatistics::DoseToVolumeFunctionType DoseToVolumeFunctionType; typedef DoseStatistics::VolumeToDoseFunctionType VolumeToDoseFunctionType; private: DoseIteratorPointer _doseIterator; /*! @brief Contains relevant dose values sorted in descending order. */ std::vector _doseVector; /*! @brief Contains the corresponding voxel proportions to the values in doseVector. */ std::vector _voxelProportionVector; /*! @brief The doseStatistics are stored here. */ DoseStatisticsPointer _statistics; bool _simpleDoseStatisticsCalculated; /*! @brief Calculates the positions where the dose has its maximum @param maxNumberMaximaPositions the maximal amount of computed positions @pre maximumDose must be defined in _statistics with the correct value */ ResultListPointer computeMaximumPositions(unsigned int maxNumberMaximaPositions) const; /*! @brief Calculates the positions where the dose has its minimum @param maxNumberMinimaPositions the maximal amount of computed positions (they are read sequentially using the iterator until maxNumberMinimaPositions have been read, other positions are not considered) @pre minimumDose must be defined in _statistics with the correct value */ ResultListPointer computeMinimumPositions(unsigned int maxNumberMinimaPositions) const; VolumeType computeVx(DoseTypeGy xDoseAbsolute) const; DoseTypeGy computeDx(VolumeType xVolumeAbsolute) const; DoseTypeGy computeMOHx(VolumeType xVolumeAbsolute) const; DoseTypeGy computeMOCx(DoseTypeGy xVolumeAbsolute) const; DoseTypeGy computeMaxOHx(DoseTypeGy xVolumeAbsolute) const; DoseTypeGy computeMinOCx(DoseTypeGy xVolumeAbsolute) const; - DoseToVolumeFunctionType computeDoseToVolumeFunctionMulti(DoseTypeGy referenceDose, const std::vector& precomputeDoseValues, + DoseToVolumeFunctionType computeDoseToVolumeFunctionMulti(DoseTypeGy referenceDose, + const std::vector& precomputeDoseValues, DoseStatistics::complexStatistics name) const; - VolumeToDoseFunctionType computeVolumeToDoseFunctionMulti(const std::vector& precomputeVolumeValues, + VolumeToDoseFunctionType computeVolumeToDoseFunctionMulti(const std::vector& + precomputeVolumeValues, DoseStatistics::complexStatistics name) const; /*! @brief Calculates simple dose statistics (min, mean, max, stdDev, minDosePositions, maxDosePositions) @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed */ - void calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions); + void calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, + unsigned int maxNumberMaximaPositions); /*! @brief Calculates complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) @warning computations can take quite long (>1 min) for large structures as many statistics are precomputed */ - void calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector& precomputeDoseValues, + void calculateComplexDoseStatistics(DoseTypeGy referenceDose, + const std::vector& precomputeDoseValues, const std::vector& precomputeVolumeValues); public: ~DoseStatisticsCalculator(); /*! @brief Constructor @param aDoseIterator the dose to be analyzed */ DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator); DoseIteratorPointer getDoseIterator() const; /*! @brief Compute simple or complex dose statistics with default relative x values and the maximum dose as default reference dose (for Vx computation) @details The following statistics are calculated always (i.e. also if computeComplexMeasures=false):
  • minimum dose
  • mean dose
  • maximum dose
  • standard deviation dose
  • voxel positions of minimum dose
  • voxel positions of maximum dose
Additionally, these statistics are computed if computeComplexMeasures=true:
  • Dx (the minimal dose delivered to a volume >= x)
  • Vx (the volume irradiated with a dose >= x)
  • MOHx (mean dose of the hottest x volume)
  • MOCx (mean dose of the coldest x volume)
  • MaxOHx (Maximum outside of the hottest x volume)
  • MinOCx (Minimum outside of the coldest x volume)
Default x values for Vx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to maxDose. Default x values for Dx, MOHx, MOCx, MaxOHx and MinOCx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to volume. @param computeComplexMeasures should complex statistics be calculated? If it is true, the complex dose statistics will be calculated with default relative x values and the maximum dose as reference dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning If computeComplexMeasures==true, computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ - DoseStatisticsPointer calculateDoseStatistics(bool computeComplexMeasures = false, unsigned int maxNumberMinimaPositions = 10, - unsigned int maxNumberMaximaPositions = 10); + DoseStatisticsPointer calculateDoseStatistics(bool computeComplexMeasures = false, + unsigned int maxNumberMinimaPositions = 10, + unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given reference dose and default relative x values @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @exception InvalidParameterException thrown if referenceDose <= 0 @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ - DoseStatisticsPointer calculateDoseStatistics(DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions = 10, - unsigned int maxNumberMaximaPositions = 10); + DoseStatisticsPointer calculateDoseStatistics(DoseTypeGy referenceDose, + unsigned int maxNumberMinimaPositions = 10, + unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given relative x values and reference dose @param precomputeDoseValues the relative dose values for Vx precomputation, e.g. 0.02, 0.05, 0.95... @param precomputeVolumeValues the relative volume values for Dx, MOHx, MOCx, MaxOHx and MinOCx precomputation, e.g. 0.02, 0.05, 0.95... @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose. Default value is the maximum dose. @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set by in precomputeDoseValues and precomputeVolumeValues. Only these values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(const std::vector& precomputeDoseValues, - const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose = -1, unsigned int maxNumberMinimaPositions = 10, - unsigned int maxNumberMaximaPositions = 10); + const std::vector& precomputeVolumeValues, DoseTypeGy referenceDose = -1, + unsigned int maxNumberMinimaPositions = 10, + unsigned int maxNumberMaximaPositions = 10); }; } } #endif diff --git a/code/core/rttbBaseType.h b/code/core/rttbBaseType.h index ef3b651..b338a3e 100644 --- a/code/core/rttbBaseType.h +++ b/code/core/rttbBaseType.h @@ -1,741 +1,742 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __BASE_TYPE_NEW_H #define __BASE_TYPE_NEW_H #include #include #include #include #include #include #include #include #include #include namespace rttb { const double errorConstant = 1e-5; typedef unsigned short UnsignedIndex1D; /*! @class UnsignedIndex2D @brief 2D index. */ class UnsignedIndex2D: public boost::numeric::ublas::vector { public: UnsignedIndex2D() : boost::numeric::ublas::vector(2) {} UnsignedIndex2D(const UnsignedIndex1D value) : boost::numeric::ublas::vector(2, value) {} const UnsignedIndex1D x() const { return (*this)(0); } const UnsignedIndex1D y() const { return (*this)(1); } }; /*! @class UnsignedIndex3D @brief 3D index. */ class UnsignedIndex3D: public boost::numeric::ublas::vector { public: UnsignedIndex3D() : boost::numeric::ublas::vector(3) {} 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 (int 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 WorldCoordinate2D @brief 2D coordinate in real world coordinates. */ class WorldCoordinate2D: public boost::numeric::ublas::vector { public: WorldCoordinate2D() : boost::numeric::ublas::vector (2) {} WorldCoordinate2D(const WorldCoordinate value) : boost::numeric::ublas::vector(2, value) {} WorldCoordinate2D(const WorldCoordinate xValue, const WorldCoordinate yValue) : boost::numeric::ublas::vector(2, xValue) { (*this)(1) = yValue; } const WorldCoordinate x() const { return (*this)(0); } const WorldCoordinate y() const { return (*this)(1); } const std::string toString() const { std::stringstream ss; ss << x() << ' ' << y(); return ss.str(); } friend bool operator==(const WorldCoordinate2D& wc1, const WorldCoordinate2D& wc2) { if (wc1.size() != wc2.size()) { return false; } for (int i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } }; /*! @class WorldCoordinate3D @brief 3D coordinate in real world coordinates. */ class WorldCoordinate3D: public boost::numeric::ublas::vector { public: WorldCoordinate3D() : boost::numeric::ublas::vector(3) {} 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; } WorldCoordinate2D getXY() const { WorldCoordinate2D result; result(0) = (*this)(0); result(1) = (*this)(1); return result; } const std::string toString() const { std::stringstream ss; ss << x() << ' ' << y() << ' ' << z(); return ss.str(); } 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 (int i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } bool equalsAlmost(const WorldCoordinate3D& another, double errorConstant = 1e-5) const { if (size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstant; } friend std::ostream& operator<<(std::ostream& s, const WorldCoordinate3D& aVector) { s << "[ " << aVector(0) << ", " << aVector(1) << ", " << aVector(2) << " ]"; return s; } }; typedef WorldCoordinate3D DoubleVoxelGridIndex3D; typedef UnsignedIndex3D ImageSize; /*! @deprecated Use OrientationMatrix instead. */ typedef WorldCoordinate3D ImageOrientation; 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(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::stringstream ss; ss << x() << ' ' << y() << ' ' << z(); return ss.str(); } 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 (int i = 0; i < wc1.size(); i++) { if (wc1(i) != wc2(i)) { return false; } } return true; } bool equalsAlmost(const SpacingVectorType3D& another, double errorConstant) const { if ((*this).size() != another.size()) { return false; } double dist = norm_2(*this - another); return dist < errorConstant; } 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 errorConstant) 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 ((abs((*this)(m, n) - anOrientationMatrix(m, n)) > errorConstant)) { 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. */ class VoxelGridIndex3D: public boost::numeric::ublas::vector { public: VoxelGridIndex3D() : boost::numeric::ublas::vector(3) {} 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::stringstream ss; ss << x() << ' ' << y() << ' ' << z(); return ss.str(); } 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 (int 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(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::stringstream ss; ss << x() << ' ' << y(); return ss.str(); } friend bool operator==(const VoxelGridIndex2D& gi1, const VoxelGridIndex2D& gi2) { if (gi1.size() != gi2.size()) { return false; } for (int 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 int VoxelGridDimensionType; typedef boost::numeric::ublas::vector VoxelGridDimensionVectorType; typedef double FractionType, VoxelSizeType, DVHVoxelNumber; - typedef double DoseCalcType, DoseTypeGy, GenericValueType, DoseVoxelVolumeType, VolumeType, GridVolumeType, + typedef double DoseCalcType, DoseTypeGy, GenericValueType, DoseVoxelVolumeType, VolumeType, + GridVolumeType, 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 PatientInfoString; typedef std::string TimeString; typedef std::string FileNameType; typedef std::vector PolygonType; typedef std::vector PolygonSequenceType; typedef double IndexValueType; typedef double DoseStatisticType; typedef std::string DBStringType; typedef std::string VirtuosFileNameString, DICOMRTFileNameString; typedef unsigned short Uint16; struct Area2D { WorldCoordinate x_begin; WorldCoordinate x_end; WorldCoordinate y_begin; WorldCoordinate y_end; VoxelGridIndex2D index_begin; VoxelGridIndex2D index_end; void Init() { x_begin = -1000000; x_end = -1000000; y_begin = -1000000; y_end = -1000000; index_begin(0) = 0; index_begin(1) = 0; index_end(0) = 0; index_end(1) = 0; } }; struct Segment2D { WorldCoordinate2D begin; WorldCoordinate2D end; }; struct Segment3D { WorldCoordinate3D begin; WorldCoordinate3D end; }; typedef int DistributionType; typedef std::string PathType; typedef std::string XMLString, StatisticsString; }//end: namespace rttb #endif diff --git a/code/core/rttbDVH.cpp b/code/core/rttbDVH.cpp index 79379c2..74c0ac0 100644 --- a/code/core/rttbDVH.cpp +++ b/code/core/rttbDVH.cpp @@ -1,414 +1,418 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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), + 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, + 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; } std::ostream& operator<<(std::ostream& s, const DVH& aDVH) { - s << "[ " << aDVH.getStructureID() << ", " << aDVH.getDoseID() << ", " << aDVH.getVoxelizationID() << ", " << + s << "[ " << aDVH.getStructureID() << ", " << aDVH.getDoseID() << ", " << aDVH.getVoxelizationID() + << ", " << aDVH.getNumberOfVoxels() << " ]"; 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 (int 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; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVH.h b/code/core/rttbDVH.h index c413c95..5c49c66 100644 --- a/code/core/rttbDVH.h +++ b/code/core/rttbDVH.h @@ -1,190 +1,191 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_H #define __DVH_H #include #include #include "rttbBaseType.h" #include "rttbStructure.h" namespace rttb { namespace core { class Structure; /*! @class DVH @brief This is a class representing a dose volume histogram (DVH) */ class DVH { public: typedef std::deque DataDifferentialType; typedef boost::shared_ptr DVHPointer; private: IDType _structureID; IDType _doseID; IDType _voxelizationID; /*! @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 Volume of a voxel in cm3 */ DoseVoxelVolumeType _deltaV; /*! @brief Absolute dose value of a dose-bin in Gy */ DoseTypeGy _deltaD; StructureLabel _label; DoseStatisticType _maximum; DoseStatisticType _minimum; DoseStatisticType _mean; DoseStatisticType _modal; DVHVoxelNumber _numberOfVoxels; DoseStatisticType _median; DoseStatisticType _stdDeviation; DoseStatisticType _variance; DataDifferentialType _dataCumulative; DataDifferentialType _dataCumulativeRelative; /*! @brief DVH initialisation 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, + 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. */ 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 abolute 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); }; } } #endif diff --git a/code/core/rttbDVHCalculator.cpp b/code/core/rttbDVHCalculator.cpp index 660b391..2821aa7 100644 --- a/code/core/rttbDVHCalculator.cpp +++ b/code/core/rttbDVHCalculator.cpp @@ -1,130 +1,133 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDVHCalculator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbMaskedDoseIteratorInterface.h" namespace rttb { namespace core { - DVHCalculator::DVHCalculator(DoseIteratorPointer aDoseIterator, const IDType& aStructureID, const IDType& aDoseID, + DVHCalculator::DVHCalculator(DoseIteratorPointer aDoseIterator, const IDType& aStructureID, + const IDType& aDoseID, DoseTypeGy aDeltaD, const int aNumberOfBins) { if (!aDoseIterator) { throw NullPointerException("aDoseIterator must not be NULL! "); } _doseIteratorPtr = aDoseIterator; _structureID = aStructureID; _doseID = aDoseID; if (aNumberOfBins <= 0 || aDeltaD < 0) { throw InvalidParameterException("aNumberOfBins/aDeltaD must be >0! "); } _numberOfBins = aNumberOfBins; _deltaD = aDeltaD; if (_deltaD == 0) { aDoseIterator->reset(); DoseTypeGy max = 0; while (aDoseIterator->isPositionValid()) { DoseTypeGy currentVal = 0; currentVal = aDoseIterator->getCurrentDoseValue(); if (currentVal > max) { max = currentVal; } aDoseIterator->next(); } _deltaD = (max * 1.5 / _numberOfBins); if (_deltaD == 0) { _deltaD = 0.1; } } } DVHCalculator::~DVHCalculator() {} DVHCalculator::DVHPointer DVHCalculator::generateDVH() { std::deque dataDifferential(_numberOfBins, 0); // calculate DVH _doseIteratorPtr->reset(); while (_doseIteratorPtr->isPositionValid()) { DoseTypeGy currentVal = 0; FractionType voxelProportion = _doseIteratorPtr->getCurrentRelevantVolumeFraction(); currentVal = _doseIteratorPtr->getCurrentDoseValue(); int dose_bin = static_cast(currentVal / _deltaD); if (dose_bin < _numberOfBins) { dataDifferential[dose_bin] += voxelProportion; } else { throw InvalidParameterException("_numberOfBins is too small: dose bin out of bounds! "); } _doseIteratorPtr->next(); } if (boost::dynamic_pointer_cast(_doseIteratorPtr)) { - _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), _structureID, + _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), + _structureID, _doseID, _doseIteratorPtr->getVoxelizationID()); } else { - _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), _structureID, + _dvh = boost::make_shared(dataDifferential, _deltaD, _doseIteratorPtr->getCurrentVoxelVolume(), + _structureID, _doseID); } return _dvh; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbDVHGeneratorInterface.h b/code/core/rttbDVHGeneratorInterface.h index 05e3aaf..7ea6ce7 100644 --- a/code/core/rttbDVHGeneratorInterface.h +++ b/code/core/rttbDVHGeneratorInterface.h @@ -1,49 +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 __DVH_GENERATOR_INTERFACE_H #define __DVH_GENERATOR_INTERFACE_H #include #include "rttbDVH.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class DVHGeneratorInterface @brief Interface for all DVH generating classes */ class DVHGeneratorInterface - { - public: - typedef core::DVH::DVHPointer DVHPointer; - protected: - DVHPointer _dvh; - public: - /*! @brief Generate DVH - @return Return new shared pointer of DVH. - */ - virtual DVHPointer generateDVH() = 0; - }; - } + { + public: + typedef core::DVH::DVHPointer DVHPointer; + protected: + DVHPointer _dvh; + public: + /*! @brief Generate DVH + @return Return new shared pointer of DVH. + */ + virtual DVHPointer generateDVH() = 0; + }; } +} #endif diff --git a/code/core/rttbDVHSet.cpp b/code/core/rttbDVHSet.cpp index 34d6b23..2410755 100644 --- a/code/core/rttbDVHSet.cpp +++ b/code/core/rttbDVHSet.cpp @@ -1,220 +1,223 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDVHSet.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { - DVHSet::DVHSet(IDType aStructureSetID, IDType aDoseID) : _structureSetID(aStructureSetID), _doseID(aDoseID) {} + DVHSet::DVHSet(IDType aStructureSetID, IDType aDoseID) : _structureSetID(aStructureSetID), + _doseID(aDoseID) {} DVHSet::DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, IDType aStructureSetID, IDType aDoseID) { _dvhHTSet = aDVHHTSet; _dvhTVSet = aDVHTVSet; this->_structureSetID = aStructureSetID; this->_doseID = aDoseID; } - DVHSet::DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, IDType aStructureSetID, IDType aDoseID) + DVHSet::DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, + IDType aStructureSetID, IDType aDoseID) { _dvhHTSet = aDVHHTSet; _dvhTVSet = aDVHTVSet; _dvhWVSet = aDVHWVSet; this->_structureSetID = aStructureSetID; this->_doseID = aDoseID; } std::size_t DVHSet::size() const { return _dvhHTSet.size() + _dvhTVSet.size() + _dvhWVSet.size(); } void DVHSet::setStrSetID(IDType aStrSetID) { _structureSetID = aStrSetID; } void DVHSet::setDoseID(IDType aDoseID) { _doseID = aDoseID; } IDType DVHSet::getStrSetID() const { return _structureSetID; } IDType DVHSet::getDoseID() const { return _doseID; } DVH* DVHSet::getDVH(IDType structureID) { DVHSetType::iterator itTV = _dvhTVSet.begin(); for (; itTV != _dvhTVSet.end(); ++itTV) { if ((*(itTV)).getStructureID() == structureID) { return &(*itTV); } } DVHSetType::iterator itHT = _dvhHTSet.begin(); for (; itHT != _dvhHTSet.end(); ++itHT) { if ((*(itHT)).getStructureID() == structureID) { return &(*itHT); } } DVHSetType::iterator itWV = _dvhWVSet.begin(); for (; itWV != _dvhWVSet.end(); ++itWV) { if ((*(itWV)).getStructureID() == structureID) { return &(*itWV); } } std::cout << "No DVH with the structure id: " << structureID << " was found!" << std::endl; return NULL; } void DVHSet::insert(DVH& aDvh, DVHRole aDVHRole) { if (aDVHRole.Type == DVHRole::TargetVolume) { _dvhTVSet.push_back(aDvh); } else if (aDVHRole.Type == DVHRole::HealthyTissue) { _dvhHTSet.push_back(aDvh); } else if (aDVHRole.Type == DVHRole::WholeVolume) { _dvhWVSet.push_back(aDvh); } else { throw core::InvalidParameterException("aDVHType must be TV or HT or WV!"); } } VolumeType DVHSet::getWholeVolume(DoseTypeGy aDoseAbsolute) const { - VolumeType volume = this->getHealthyTissueVolume(aDoseAbsolute) + this->getTargetVolume(aDoseAbsolute); + VolumeType volume = this->getHealthyTissueVolume(aDoseAbsolute) + this->getTargetVolume( + aDoseAbsolute); return volume; } VolumeType DVHSet::getHealthyTissueVolume(DoseTypeGy aDoseAbsolute) const { DVHSetType::const_iterator itHT = _dvhHTSet.begin(); VolumeType volume = 0; while (itHT != _dvhHTSet.end()) { VolumeType testVol = 0; DVH dvh = *(itHT); testVol = dvh.getVx(aDoseAbsolute); if (testVol >= 0) { volume += testVol; } ++itHT; } return volume; } VolumeType DVHSet::getTargetVolume(DoseTypeGy aDoseAbsolute) const { DVHSetType::const_iterator itTV = _dvhTVSet.begin(); VolumeType volume = 0; while (itTV != _dvhTVSet.end()) { VolumeType testVol = 0; DVH dvh = *(itTV); testVol = dvh.getVx(aDoseAbsolute); if (testVol >= 0) { volume += testVol; } ++itTV; } return volume; } bool operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet) { if (aDVHSet.getStrSetID() != otherDVHSet.getStrSetID()) { return false; } if (aDVHSet.getDoseID() != otherDVHSet.getDoseID()) { return false; } if (aDVHSet.size() != otherDVHSet.size()) { return false; } return true; } std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet) { s << "[ " << aDVHSet.getStrSetID() << ", " << aDVHSet.getDoseID() << " ]"; return s; } std::ostream& operator<<(std::ostream& s, const DVHSet::DVHSetType& aDVHSet) { s << "[ "; for (int i = 0; i < aDVHSet.size(); i++) { s << aDVHSet.at(i); } s << " ]"; return s; } } } diff --git a/code/core/rttbDVHSet.h b/code/core/rttbDVHSet.h index 9ca3b05..2a8b044 100644 --- a/code/core/rttbDVHSet.h +++ b/code/core/rttbDVHSet.h @@ -1,126 +1,139 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_SET_H #define __DVH_SET_H #include #include #include #include "rttbBaseType.h" #include "rttbDVH.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class DVHSet @brief This is a class representing a RT DVHSet including Target Volume and Organ at Risk - A DVHSet consists of three subsets: one for the target volume (_dvhTVSet), one for healthy tissue (_dvhHTSet), + A DVHSet consists of three subsets: one for the target volume (_dvhTVSet), one for healthy tissue (_dvhHTSet), and one for the whole volume (_dvhWVSet). */ class DVHSet - { - public: - typedef std::vector DVHSetType; + { + public: + typedef std::vector DVHSetType; typedef DVHSetType::size_type IndexType; - private: - IDType _structureSetID; - IDType _doseID; - DVHSetType _dvhTVSet; - DVHSetType _dvhHTSet; - DVHSetType _dvhWVSet; - - public: - DVHSet(IDType aStructureSetID="", IDType aDoseID=""); - DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, IDType aStructureSetID="", IDType aDoseID=""); - DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, IDType aStructureSetID="", - IDType aDoseID=""); - - /*! @brief Get the size of the DVHSet, that is the sum of the numbers of DVHs in all sub-sets. - */ - std::size_t size() const; - - void setStrSetID(IDType aStrSetID); - void setDoseID(IDType aDoseID); - - IDType getStrSetID() const; - IDType getDoseID() const; - - /*! @brief Get the DVH according to the structure ID - @return Return NULL if not found - */ - DVH* getDVH(IDType aStructureID); - - /*! @brief Insert a DVH object. - @brief param aDVHType "TV" for target volume or "HT" for healthy tissue or "WV" for whole volume - @exception InvalidParameterException Thrown if no valid DVHRole was given. - */ - void insert(DVH& aDvh, DVHRole aDVHRole); - - /*! @brief Get DVH subset for target volume - */ - const DVHSetType& getTargetVolumeSet() const{return _dvhTVSet;}; + private: + IDType _structureSetID; + IDType _doseID; + DVHSetType _dvhTVSet; + DVHSetType _dvhHTSet; + DVHSetType _dvhWVSet; + + public: + DVHSet(IDType aStructureSetID = "", IDType aDoseID = ""); + DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, IDType aStructureSetID = "", + IDType aDoseID = ""); + DVHSet(DVHSetType aDVHTVSet, DVHSetType aDVHHTSet, DVHSetType aDVHWVSet, + IDType aStructureSetID = "", + IDType aDoseID = ""); + + /*! @brief Get the size of the DVHSet, that is the sum of the numbers of DVHs in all sub-sets. + */ + std::size_t size() const; + + void setStrSetID(IDType aStrSetID); + void setDoseID(IDType aDoseID); + + IDType getStrSetID() const; + IDType getDoseID() const; + + /*! @brief Get the DVH according to the structure ID + @return Return NULL if not found + */ + DVH* getDVH(IDType aStructureID); + + /*! @brief Insert a DVH object. + @brief param aDVHType "TV" for target volume or "HT" for healthy tissue or "WV" for whole volume + @exception InvalidParameterException Thrown if no valid DVHRole was given. + */ + void insert(DVH& aDvh, DVHRole aDVHRole); + + /*! @brief Get DVH subset for target volume + */ + const DVHSetType& getTargetVolumeSet() const + { + return _dvhTVSet; + }; - /*! @brief Get DVH subset for healthy tissue - */ - const DVHSetType& getHealthyTissueSet() const{return _dvhHTSet;}; + /*! @brief Get DVH subset for healthy tissue + */ + const DVHSetType& getHealthyTissueSet() const + { + return _dvhHTSet; + }; - /*! @brief Get DVH subset for whole volume - */ - const DVHSetType& getWholeVolumeSet() const{return _dvhWVSet;}; + /*! @brief Get DVH subset for whole volume + */ + const DVHSetType& getWholeVolumeSet() const + { + return _dvhWVSet; + }; - /*! @brief Get the whole volume irradiated to >= aDoseAbsolute - */ - VolumeType getWholeVolume(DoseTypeGy aDoseAbsolute) const; + /*! @brief Get the whole volume irradiated to >= aDoseAbsolute + */ + VolumeType getWholeVolume(DoseTypeGy aDoseAbsolute) const; - /*! @brief Get the healthy tissue volume irradiated to >= aDoseAbsolute - @return Return -1 if DVH of _dvhHTSet init() failed - */ + /*! @brief Get the healthy tissue volume irradiated to >= aDoseAbsolute + @return Return -1 if DVH of _dvhHTSet init() failed + */ VolumeType getHealthyTissueVolume(DoseTypeGy aDoseAbsolute) const; - /*! @brief Get the target volume irradiated to >= aDoseAbsolute - @return Return -1 if DVH of _dvhTVSet init() failed - */ + /*! @brief Get the target volume irradiated to >= aDoseAbsolute + @return Return -1 if DVH of _dvhTVSet init() failed + */ VolumeType getTargetVolume(DoseTypeGy aDoseAbsolute) const; - /*! DVHSets are considered equal if they have the same structureSet, dose and voxelization ID - and the number of DVHs are equal. - */ - bool friend operator==(const DVHSet &aDVHSet, const DVHSet &otherDVHSet); + /*! DVHSets are considered equal if they have the same structureSet, dose and voxelization ID + and the number of DVHs are equal. + */ + bool friend operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet); - friend std::ostream& operator<<(std::ostream& s, const DVHSet &aDVHSet); + friend std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet); - friend std::ostream& operator<<(std::ostream& s, const DVHSetType &aDVHSet); - }; + friend std::ostream& operator<<(std::ostream& s, const DVHSetType& aDVHSet); + }; - bool operator==(const DVHSet &aDVHSet, const DVHSet &otherDVHSet); + bool operator==(const DVHSet& aDVHSet, const DVHSet& otherDVHSet); - std::ostream& operator<<(std::ostream& s, const DVHSet &aDVHSet); + std::ostream& operator<<(std::ostream& s, const DVHSet& aDVHSet); - std::ostream& operator<<(std::ostream& s, const DVHSet::DVHSetType &aDVHSet); + std::ostream& operator<<(std::ostream& s, const DVHSet::DVHSetType& aDVHSet); - } + } } #endif diff --git a/code/core/rttbDoseAccessorGeneratorInterface.h b/code/core/rttbDoseAccessorGeneratorInterface.h index a772cb7..2abdf63 100644 --- a/code/core/rttbDoseAccessorGeneratorInterface.h +++ b/code/core/rttbDoseAccessorGeneratorInterface.h @@ -1,62 +1,63 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACCESSOR_GENERATOR_INTERFACE_H #define __DOSE_ACCESSOR_GENERATOR_INTERFACE_H #include #include "rttbDoseAccessorInterface.h" namespace rttb { namespace core { /*! @class DoseAccessorGeneratorInterface @brief Interface for all Dose Accessor generating classes */ class DoseAccessorGeneratorInterface { public: typedef core::AccessorInterface::AccessorPointer DoseAccessorPointer; private: - DoseAccessorGeneratorInterface(const DoseAccessorGeneratorInterface&); //not implemented on purpose -> non-copyable + DoseAccessorGeneratorInterface(const + DoseAccessorGeneratorInterface&); //not implemented on purpose -> non-copyable DoseAccessorGeneratorInterface& operator=(const DoseAccessorGeneratorInterface&);//not implemented on purpose -> non-copyable protected: DoseAccessorGeneratorInterface() {}; virtual ~DoseAccessorGeneratorInterface() {}; public: /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. */ virtual DoseAccessorPointer generateDoseAccessor() = 0; }; } } #endif diff --git a/code/core/rttbDoseIteratorInterface.cpp b/code/core/rttbDoseIteratorInterface.cpp index d3da9b1..2680ea8 100644 --- a/code/core/rttbDoseIteratorInterface.cpp +++ b/code/core/rttbDoseIteratorInterface.cpp @@ -1,36 +1,41 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - DoseIteratorInterface::DoseIteratorInterface(DoseAccessorPointer aDoseAccessor){ - if(! aDoseAccessor){ + DoseIteratorInterface::DoseIteratorInterface(DoseAccessorPointer aDoseAccessor) + { + if (! aDoseAccessor) + { throw NullPointerException(" dose accessor pointer must not be NULL!"); - } - _spDoseAccessor = aDoseAccessor; } - }//end: namespace core - }//end: namespace rttb + + _spDoseAccessor = aDoseAccessor; + } + }//end: namespace core +}//end: namespace rttb diff --git a/code/core/rttbDoseIteratorInterface.h b/code/core/rttbDoseIteratorInterface.h index e55f9a3..e33fe7b 100644 --- a/code/core/rttbDoseIteratorInterface.h +++ b/code/core/rttbDoseIteratorInterface.h @@ -1,108 +1,109 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ITERATOR_INTERFACE_NEW_H #define __DOSE_ITERATOR_INTERFACE_NEW_H #include #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbDoseAccessorInterface.h" namespace rttb { namespace core { /*! @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& 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 implememntations. */ DoseIteratorInterface(DoseAccessorPointer aDoseAccessor); virtual ~DoseIteratorInterface() {}; /*! @brief Set the itterator 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/rttbException.cpp b/code/core/rttbException.cpp index 0f0163d..f2271cc 100644 --- a/code/core/rttbException.cpp +++ b/code/core/rttbException.cpp @@ -1,39 +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 #include #include "rttbException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - const char* Exception::what() const throw() { + const char* Exception::what() const throw() + { return rttb_what.c_str(); - } + } - const char* Exception::GetNameOfClass() const{ - return "Exception"; - } + const char* Exception::GetNameOfClass() const + { + return "Exception"; + } - }//end namespace core - }//end namespace rttb + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbException.h b/code/core/rttbException.h index 4af8777..b4bac79 100644 --- a/code/core/rttbException.h +++ b/code/core/rttbException.h @@ -1,60 +1,62 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __EXCEPTION_H #define __EXCEPTION_H #include #include #include -namespace rttb{ - namespace core{ - - /*! @class Exception - @brief Exception interface used by all RTToolbox exceptions. - */ - - class Exception: public std::exception - { - protected: - std::string rttb_what; - - public: - explicit Exception(const std::string& aWhat) - :rttb_what(aWhat) - {} - virtual ~Exception() throw() {} - - /*! @brief Get the exception description - */ - const char * what() const throw(); - - /*! @brief Get the name of the exception class that was thrown - */ - const char* GetNameOfClass() const; - }; - - } +namespace rttb +{ + namespace core + { + + /*! @class Exception + @brief Exception interface used by all RTToolbox exceptions. + */ + + class Exception: public std::exception + { + protected: + std::string rttb_what; + + public: + explicit Exception(const std::string& aWhat) + : rttb_what(aWhat) + {} + virtual ~Exception() throw() {} + + /*! @brief Get the exception description + */ + const char* what() const throw(); + + /*! @brief Get the name of the exception class that was thrown + */ + const char* GetNameOfClass() const; + }; + + } } #endif diff --git a/code/core/rttbGenericDoseIterator.h b/code/core/rttbGenericDoseIterator.h index 9ee0bff..f617e0f 100644 --- a/code/core/rttbGenericDoseIterator.h +++ b/code/core/rttbGenericDoseIterator.h @@ -1,98 +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) */ #ifndef __GENERIC_DOSE_ITERATOR_INTERFACE_NEW_H #define __GENERIC_DOSE_ITERATOR_INTERFACE_NEW_H #include #include #include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class GenericDoseIterator @brief Standard implementation of the dose iterator interface. */ class GenericDoseIterator: public DoseIteratorInterface - { - public: - typedef DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; - typedef DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - - private: + { + public: + typedef DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; + typedef DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - VoxelGridID _currentDoseVoxelGridID; - DoseVoxelVolumeType _currentVoxelVolume; + private: - GenericDoseIterator(const GenericDoseIterator&); //not implemented on purpose -> non-copyable - GenericDoseIterator& operator=(const GenericDoseIterator&);//not implemented on purpose -> non-copyable + VoxelGridID _currentDoseVoxelGridID; + DoseVoxelVolumeType _currentVoxelVolume; - public: + GenericDoseIterator(const GenericDoseIterator&); //not implemented on purpose -> non-copyable + GenericDoseIterator& operator=(const + GenericDoseIterator&);//not implemented on purpose -> non-copyable - /*! @brief Constructor - @param aDoseAccessor contains the corresponding dose data - */ - GenericDoseIterator(DoseAccessorPointer aDoseAccessor); + public: - /*! @brief Set the itterator to the start of the Dose. - @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because - these grids are currently not supported. - */ - bool reset(); + /*! @brief Constructor + @param aDoseAccessor contains the corresponding dose data + */ + GenericDoseIterator(DoseAccessorPointer aDoseAccessor); - /*! @brief Test if next voxel position is still on the data grid, if so move to next position. - */ - void next(); + /*! @brief Set the itterator to the start of the Dose. + @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because + these grids are currently not supported. + */ + bool reset(); - /*! @brief Determine if the current voxel position is valid. - */ - bool isPositionValid() const; + /*! @brief Test if next voxel position is still on the data grid, if so move to next position. + */ + void next(); - /*! @brief Return volume of one voxel (in cm3) - @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because - these grids are currently not supported. - */ - DoseVoxelVolumeType getCurrentVoxelVolume() const; + /*! @brief Determine if the current voxel position is valid. + */ + bool isPositionValid() const; - DoseTypeGy getCurrentDoseValue() const; + /*! @brief Return volume of one voxel (in cm3) + @exception InvalidParameterException if a inhomogeneous grid is defined in the dose accessors, because + these grids are currently not supported. + */ + DoseVoxelVolumeType getCurrentVoxelVolume() const; - /*! @brief For DoseIterators this function returns 1, always, because no mask is applied. - */ - inline FractionType getCurrentRelevantVolumeFraction() const - { - return 1; - }; + DoseTypeGy getCurrentDoseValue() const; - inline VoxelGridID getCurrentVoxelGridID() const - { - return _currentDoseVoxelGridID; - }; + /*! @brief For DoseIterators this function returns 1, always, because no mask is applied. + */ + inline FractionType getCurrentRelevantVolumeFraction() const + { + return 1; + }; + inline VoxelGridID getCurrentVoxelGridID() const + { + return _currentDoseVoxelGridID; }; - } + + }; } +} #endif diff --git a/code/core/rttbGeometricInfo.cpp b/code/core/rttbGeometricInfo.cpp index aae96fa..8bfcfeb 100644 --- a/code/core/rttbGeometricInfo.cpp +++ b/code/core/rttbGeometricInfo.cpp @@ -1,339 +1,344 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbGeometricInfo.h" namespace rttb { namespace core { void GeometricInfo::setSpacing(const SpacingVectorType3D& aSpacingVector) { _spacing = aSpacingVector; } const SpacingVectorType3D& GeometricInfo::getSpacing() const { return _spacing; } void GeometricInfo::setImagePositionPatient(const WorldCoordinate3D& aImagePositionPatient) { _imagePositionPatient = aImagePositionPatient; } const WorldCoordinate3D& GeometricInfo::getImagePositionPatient() const { return _imagePositionPatient; } void GeometricInfo::setOrientationMatrix(const OrientationMatrix& anOrientationMatrix) { _orientationMatrix = anOrientationMatrix; computeInvertOrientation(); } bool GeometricInfo::computeInvertOrientation() { typedef boost::numeric::ublas::permutation_matrix pmatrix; boost::numeric::ublas::matrix A(_orientationMatrix); // create a permutation matrix for the LU-factorization pmatrix pm(A.size1()); size_t res = boost::numeric::ublas::lu_factorize(A, pm); if (res != 0) { return false; } _invertedOrientationMatrix.assign(boost::numeric::ublas::identity_matrix - (A.size1())); + (A.size1())); // backsubstitute to get the inverse boost::numeric::ublas::lu_substitute(A, pm, _invertedOrientationMatrix); return true; } const ImageOrientation GeometricInfo::getImageOrientationRow() const { ImageOrientation _imageOrientationRow(0); _imageOrientationRow(0) = _orientationMatrix(0, 0); _imageOrientationRow(1) = _orientationMatrix(1, 0); _imageOrientationRow(2) = _orientationMatrix(2, 0); return _imageOrientationRow; } const ImageOrientation GeometricInfo::getImageOrientationColumn() const { ImageOrientation _imageOrientationColumn(0); _imageOrientationColumn(0) = _orientationMatrix(0, 1); _imageOrientationColumn(1) = _orientationMatrix(1, 1); _imageOrientationColumn(2) = _orientationMatrix(2, 1); return _imageOrientationColumn; } void GeometricInfo::setPixelSpacingRow(const GridVolumeType aValue) { _spacing(0) = aValue; } const GridVolumeType GeometricInfo::getPixelSpacingRow() const { return _spacing(0); } void GeometricInfo::setPixelSpacingColumn(const GridVolumeType aValue) { _spacing(1) = aValue; } const GridVolumeType GeometricInfo::getPixelSpacingColumn() const { return _spacing(1); } void GeometricInfo::setSliceThickness(const GridVolumeType aValue) { _spacing(2) = aValue; } const GridVolumeType GeometricInfo::getSliceThickness() const { return _spacing(2); } void GeometricInfo::setImageSize(const ImageSize& aSize) { setNumColumns(aSize(0)); setNumRows(aSize(1)); setNumSlices(aSize(2)); } const ImageSize GeometricInfo::getImageSize() const { return ImageSize(getNumColumns(), getNumRows(), getNumSlices()); } void GeometricInfo::setNumColumns(const VoxelGridDimensionType aValue) { _numberOfColumns = aValue; } const VoxelGridDimensionType GeometricInfo::getNumColumns() const { return _numberOfColumns; } void GeometricInfo::setNumRows(const VoxelGridDimensionType aValue) { _numberOfRows = aValue; } const VoxelGridDimensionType GeometricInfo::getNumRows() const { return _numberOfRows; } void GeometricInfo::setNumSlices(const VoxelGridDimensionType aValue) { _numberOfFrames = aValue; } const VoxelGridDimensionType GeometricInfo::getNumSlices() const { return _numberOfFrames; } bool operator==(const GeometricInfo& gInfo, const GeometricInfo& gInfo1) { return (gInfo.getImagePositionPatient() == gInfo1.getImagePositionPatient() - && gInfo.getOrientationMatrix() == gInfo1.getOrientationMatrix() - && gInfo.getSpacing() == gInfo1.getSpacing() && gInfo.getNumColumns() == gInfo1.getNumColumns() - && gInfo.getNumRows() == gInfo1.getNumRows() && gInfo.getNumSlices() == gInfo1.getNumSlices()); + && gInfo.getOrientationMatrix() == gInfo1.getOrientationMatrix() + && gInfo.getSpacing() == gInfo1.getSpacing() && gInfo.getNumColumns() == gInfo1.getNumColumns() + && gInfo.getNumRows() == gInfo1.getNumRows() && gInfo.getNumSlices() == gInfo1.getNumSlices()); } - bool GeometricInfo::equalsAlmost(const GeometricInfo& another, double errorConstant /*= 1e-5*/) const + bool GeometricInfo::equalsAlmost(const GeometricInfo& another, + double errorConstant /*= 1e-5*/) const { return (getImagePositionPatient().equalsAlmost(another.getImagePositionPatient(), errorConstant) - && getOrientationMatrix().equalsAlmost(another.getOrientationMatrix(), errorConstant) - && getSpacing().equalsAlmost(another.getSpacing(), errorConstant) && getNumColumns() == another.getNumColumns() - && getNumRows() == another.getNumRows() && getNumSlices() == another.getNumSlices()); + && getOrientationMatrix().equalsAlmost(another.getOrientationMatrix(), errorConstant) + && getSpacing().equalsAlmost(another.getSpacing(), errorConstant) + && getNumColumns() == another.getNumColumns() + && getNumRows() == another.getNumRows() && getNumSlices() == another.getNumSlices()); } bool GeometricInfo::worldCoordinateToGeometryCoordinate(const WorldCoordinate3D& aWorldCoordinate, - DoubleVoxelGridIndex3D& aIndex) - const + DoubleVoxelGridIndex3D& aIndex) + const { WorldCoordinate3D distanceToIP; distanceToIP = aWorldCoordinate - _imagePositionPatient; boost::numeric::ublas::vector result = boost::numeric::ublas::prod( - _invertedOrientationMatrix, - distanceToIP); + _invertedOrientationMatrix, + distanceToIP); boost::numeric::ublas::vector resultS = boost::numeric::ublas::element_div(result, - _spacing); + _spacing); aIndex = DoubleVoxelGridIndex3D(resultS(0), resultS(1), resultS(2)); //check if it is inside - VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), GridIndexType(aIndex(1) + 0.5), - GridIndexType(aIndex(2) + 0.5)); + VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), + GridIndexType(aIndex(1) + 0.5), + GridIndexType(aIndex(2) + 0.5)); return isInside(indexInt); } bool GeometricInfo::worldCoordinateToIndex(const WorldCoordinate3D& aWorldCoordinate, - VoxelGridIndex3D& aIndex) - const + VoxelGridIndex3D& aIndex) + const { DoubleVoxelGridIndex3D doubleIndex; bool inside = worldCoordinateToGeometryCoordinate(aWorldCoordinate, doubleIndex); aIndex = VoxelGridIndex3D(GridIndexType(doubleIndex(0) + 0.5), GridIndexType(doubleIndex(1) + 0.5), - GridIndexType(doubleIndex(2) + 0.5)); + GridIndexType(doubleIndex(2) + 0.5)); return inside; } bool GeometricInfo::geometryCoordinateToWorldCoordinate(const DoubleVoxelGridIndex3D& aIndex, - WorldCoordinate3D& aWorldCoordinate) - const + WorldCoordinate3D& aWorldCoordinate) + const { boost::numeric::ublas::vector resultS = boost::numeric::ublas::element_prod( - aIndex, - _spacing); + aIndex, + _spacing); boost::numeric::ublas::vector result = boost::numeric::ublas::prod( - _orientationMatrix, - resultS); + _orientationMatrix, + resultS); aWorldCoordinate = result + _imagePositionPatient; - VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), GridIndexType(aIndex(1) + 0.5), - GridIndexType(aIndex(2) + 0.5)); + VoxelGridIndex3D indexInt = VoxelGridIndex3D(GridIndexType(aIndex(0) + 0.5), + GridIndexType(aIndex(1) + 0.5), + GridIndexType(aIndex(2) + 0.5)); return isInside(indexInt); } bool GeometricInfo::indexToWorldCoordinate(const VoxelGridIndex3D& aIndex, - WorldCoordinate3D& aWorldCoordinate) - const + WorldCoordinate3D& aWorldCoordinate) + const { - DoubleVoxelGridIndex3D indexDouble = DoubleVoxelGridIndex3D(aIndex(0) - 0.5, aIndex(1) - 0.5, aIndex(2) - 0.5); + DoubleVoxelGridIndex3D indexDouble = DoubleVoxelGridIndex3D(aIndex(0) - 0.5, aIndex(1) - 0.5, + aIndex(2) - 0.5); return geometryCoordinateToWorldCoordinate(indexDouble, aWorldCoordinate); } bool GeometricInfo::isInside(const VoxelGridIndex3D& aIndex) const { return (aIndex(0) >= 0 && aIndex(1) >= 0 && aIndex(2) >= 0 - && aIndex(0) < static_cast(_numberOfColumns) - && aIndex(1) < static_cast(_numberOfRows) - && aIndex(2) < static_cast(_numberOfFrames)); + && aIndex(0) < static_cast(_numberOfColumns) + && aIndex(1) < static_cast(_numberOfRows) + && aIndex(2) < static_cast(_numberOfFrames)); } bool GeometricInfo::isInside(const WorldCoordinate3D& aWorldCoordinate) { VoxelGridIndex3D currentIndex; return (worldCoordinateToIndex(aWorldCoordinate, currentIndex)); } const GridSizeType GeometricInfo::getNumberOfVoxels() const { return _numberOfRows * _numberOfColumns * _numberOfFrames; } bool GeometricInfo::convert(const VoxelGridID& gridID, VoxelGridIndex3D& gridIndex) const { if (validID(gridID)) { gridIndex(0) = gridID % getNumColumns(); VoxelGridID tempID = (gridID - gridIndex.x()) / getNumColumns(); gridIndex(1) = tempID % getNumRows(); gridIndex(2) = (tempID - gridIndex.y()) / getNumRows(); return true; } return false; } bool GeometricInfo::convert(const VoxelGridIndex3D& gridIndex, VoxelGridID& gridID) const { if ((gridIndex.x() >= static_cast(getNumColumns())) - || (gridIndex.y() >= static_cast(getNumRows())) - || (gridIndex.z() >= static_cast(getNumSlices()))) + || (gridIndex.y() >= static_cast(getNumRows())) + || (gridIndex.z() >= static_cast(getNumSlices()))) { return false; } else { gridID = gridIndex.z() * getNumColumns() * getNumRows() + gridIndex.y() * - getNumColumns() - + gridIndex.x(); + getNumColumns() + + gridIndex.x(); return validID(gridID); } } bool GeometricInfo::validID(const VoxelGridID aID) const { return (aID >= 0 && aID < getNumberOfVoxels()); } bool GeometricInfo::validIndex(const VoxelGridIndex3D& aIndex) const { VoxelGridID aID; if (!convert(aIndex, aID)) { return false; } else { return validID(aID); } } std::ostream& operator<<(std::ostream& s, const GeometricInfo& anGeometricInfo) { s << "[ " << anGeometricInfo.getImagePositionPatient() << "; " << - anGeometricInfo.getOrientationMatrix() - << "; " << anGeometricInfo.getSpacing() << "; " << "; " << anGeometricInfo.getNumColumns() - << "; " << anGeometricInfo.getNumRows() << "; " << anGeometricInfo.getNumSlices() << " ]"; + anGeometricInfo.getOrientationMatrix() + << "; " << anGeometricInfo.getSpacing() << "; " << "; " << anGeometricInfo.getNumColumns() + << "; " << anGeometricInfo.getNumRows() << "; " << anGeometricInfo.getNumSlices() << " ]"; return s; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbGeometricInfo.h b/code/core/rttbGeometricInfo.h index e6aa52e..f802ce7 100644 --- a/code/core/rttbGeometricInfo.h +++ b/code/core/rttbGeometricInfo.h @@ -1,189 +1,190 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __GEOMETRIC_INFO_NEW_H #define __GEOMETRIC_INFO_NEW_H #include #include #include #include #include "rttbBaseType.h" namespace rttb { namespace core { /*! @brief GeometricInfo objects contain all the information required for transformations between voxel grid coordinates and world coordinates. Corresponding converter functions are also available. @note ITK Pixel Indexing used (http://www.itk.org/Doxygen45/html/classitk_1_1Image.html): The Index type reverses the order so that with Index[0] = col, Index[1] = row, Index[2] = slice. */ class GeometricInfo { private: WorldCoordinate3D _imagePositionPatient; OrientationMatrix _orientationMatrix; OrientationMatrix _invertedOrientationMatrix; SpacingVectorType3D _spacing; VoxelGridDimensionType _numberOfColumns; VoxelGridDimensionType _numberOfRows; VoxelGridDimensionType _numberOfFrames; /* @brief Matrix inversion routine. Uses lu_factorize and lu_substitute in uBLAS to invert a matrix http://savingyoutime.wordpress.com/2009/09/21/c-matrix-inversion-boostublas/ */ bool computeInvertOrientation(); public: /*! @brief Constructor, initializes orientation matrix, spacing vector and patient position with zeros. */ - GeometricInfo() : _orientationMatrix(0), _spacing(0), _imagePositionPatient(0), _numberOfFrames(0), _numberOfRows(0), + GeometricInfo() : _orientationMatrix(0), _spacing(0), _imagePositionPatient(0), _numberOfFrames(0), + _numberOfRows(0), _numberOfColumns(0) {} void setSpacing(const SpacingVectorType3D& aSpacingVector); const SpacingVectorType3D& getSpacing() const; void setImagePositionPatient(const WorldCoordinate3D& aImagePositionPatient); const WorldCoordinate3D& getImagePositionPatient() const; void setOrientationMatrix(const OrientationMatrix& anOrientationMatrix); const OrientationMatrix getOrientationMatrix() const { return _orientationMatrix; }; /*! @brief Returns the 1st row of the OrientationMatrix. @deprecated please use getOrientationMatrix() (x,0) instead*/ const ImageOrientation getImageOrientationRow() const; /*! @brief Returns the 2nd row of the OrientationMatrix. @deprecated please use getOrientationMatrix() (x,1) instead*/ const ImageOrientation getImageOrientationColumn() const; void setPixelSpacingRow(const GridVolumeType aValue); /*! @brief Returns the spacing in the x-dimension (rows) of the data grid. @deprecated please use getSpacing() (0) instead*/ const GridVolumeType getPixelSpacingRow() const; void setPixelSpacingColumn(const GridVolumeType aValue); /*! @brief Returns the spacing in the y-dimension (columns) of the data grid. @deprecated please use getSpacing() (1) instead*/ const GridVolumeType getPixelSpacingColumn() const; void setSliceThickness(const GridVolumeType aValue); /*! @brief Returns the spacing in the z-dimension (slices) of the data grid. @deprecated please use getSpacing() (2) instead*/ const GridVolumeType getSliceThickness() const; void setImageSize(const ImageSize& aSize); const ImageSize getImageSize() const; void setNumColumns(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumColumns() const; void setNumRows(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumRows() const; void setNumSlices(const VoxelGridDimensionType aValue); const VoxelGridDimensionType getNumSlices() const; /*! @brief determines equality of two GeometricInfo objects. */ friend bool operator==(const GeometricInfo& gInfo, const GeometricInfo& gInfo1); bool equalsAlmost(const GeometricInfo& another, double errorConstant = 1e-5) const; /*! @brief convert world coordinates to voxel grid index. The conversion of values is done even if the target index is not inside the given voxel grid (return false). If the target is inside the grid return true. */ bool worldCoordinateToIndex(const WorldCoordinate3D& aWorldCoordinate, VoxelGridIndex3D& aIndex) const; /*! @brief convert world coordinates to double geometry coordinate. The world coordinate of the image position patient (center of the first voxel) will be convert to the double voxel (0.0, 0.0, 0.0) The conversion of values is done even if the target index is not inside the given voxel grid (return false). If the target is inside the grid return true. */ bool worldCoordinateToGeometryCoordinate(const WorldCoordinate3D& aWorldCoordinate, - DoubleVoxelGridIndex3D& aIndex) const; + DoubleVoxelGridIndex3D& aIndex) const; - /*! @brief convert double geometry coordinate to world coordinates. The double voxel index (0.0, 0.0, 0.0) will be convert to the world coordinate of the image postion patient (center of the first voxel) + /*! @brief convert double geometry coordinate to world coordinates. The double voxel index (0.0, 0.0, 0.0) will be convert to the world coordinate of the image postion patient (center of the first voxel) The conversion of values is done even if the target is not inside the given voxel grid (return false). If the target is inside the voxel grid return true. */ bool geometryCoordinateToWorldCoordinate(const DoubleVoxelGridIndex3D& aIndex, - WorldCoordinate3D& aWorldCoordinate) const; + WorldCoordinate3D& aWorldCoordinate) const; /*! @brief convert int voxel grid index to world coordinates. The conversion of values is done even if the target is not inside the given voxel grid (return false). If the target is inside the voxel grid return true. */ bool indexToWorldCoordinate(const VoxelGridIndex3D& aIndex, - WorldCoordinate3D& aWorldCoordinate) const; + WorldCoordinate3D& aWorldCoordinate) const; /*! @brief check if a given voxel grid index is inside the given voxel grid.*/ bool isInside(const VoxelGridIndex3D& aIndex) const; /*! @brief check if a given world coordinate is inside the given voxel grid.*/ bool isInside(const WorldCoordinate3D& aWorldCoordinate); const GridSizeType getNumberOfVoxels() const; bool convert(const VoxelGridID& gridID, VoxelGridIndex3D& gridIndex) const; bool convert(const VoxelGridIndex3D& gridIndex, VoxelGridID& gridID) const; /*! @brief test if given ID is inside current dose grid */ bool validID(const VoxelGridID aID) const; /*! @brief test if given index is inside current dose grid */ bool validIndex(const VoxelGridIndex3D& aIndex) const; /*!@ brief generates string stream representation of the GeometricInfo object. */ friend std::ostream& operator<<(std::ostream& s, const GeometricInfo& anGeometricInfo); }; } } #endif \ No newline at end of file diff --git a/code/core/rttbIndexOutOfBoundsException.cpp b/code/core/rttbIndexOutOfBoundsException.cpp index c0c6452..d21f802 100644 --- a/code/core/rttbIndexOutOfBoundsException.cpp +++ b/code/core/rttbIndexOutOfBoundsException.cpp @@ -1,39 +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 #include #include "rttbIndexOutOfBoundsException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - const char* IndexOutOfBoundsException::what() const throw(){ + const char* IndexOutOfBoundsException::what() const throw() + { return rttb_what.c_str(); - } + } - const char* IndexOutOfBoundsException::GetNameOfClass() const{ - return "IndexOutOfBoundsException"; - } + const char* IndexOutOfBoundsException::GetNameOfClass() const + { + return "IndexOutOfBoundsException"; + } - }//end namespace core - }//end namespace rttb + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbIndexOutOfBoundsException.h b/code/core/rttbIndexOutOfBoundsException.h index 0e21a46..38ef45e 100644 --- a/code/core/rttbIndexOutOfBoundsException.h +++ b/code/core/rttbIndexOutOfBoundsException.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __INDEX_OUT_OF_BOUNDS_EXCEPTION_H #define __INDEX_OUT_OF_BOUNDS_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ +namespace rttb +{ - namespace core{ + namespace core + { /*! @class IndexOutOfBoundsException @brief This exception will be thrown if any index out of bound. */ class IndexOutOfBoundsException: public Exception - { - public: - IndexOutOfBoundsException(const std::string& aWhat):Exception(aWhat){} + { + public: + IndexOutOfBoundsException(const std::string& aWhat): Exception(aWhat) {} - virtual ~IndexOutOfBoundsException() throw() {} + virtual ~IndexOutOfBoundsException() throw() {} - /*! @brief Get the exception description - */ - virtual const char * what() const throw(); + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); - /*! @brief Get the name of the exception class - */ - virtual const char* GetNameOfClass() const; - }; + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; - } } +} #endif diff --git a/code/core/rttbInvalidDoseException.cpp b/code/core/rttbInvalidDoseException.cpp index baa34fe..de222c7 100644 --- a/code/core/rttbInvalidDoseException.cpp +++ b/code/core/rttbInvalidDoseException.cpp @@ -1,40 +1,44 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbInvalidDoseException.h" -namespace rttb{ +namespace rttb +{ - namespace core{ + namespace core + { - const char* InvalidDoseException::what() const throw(){ + const char* InvalidDoseException::what() const throw() + { return rttb_what.c_str(); - } + } - const char* InvalidDoseException::GetNameOfClass() const{ - return "InvalidDoseException"; - } + const char* InvalidDoseException::GetNameOfClass() const + { + return "InvalidDoseException"; + } - }//end namespace core - }//end namespace rttb + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbInvalidDoseException.h b/code/core/rttbInvalidDoseException.h index dd9c239..a9aad15 100644 --- a/code/core/rttbInvalidDoseException.h +++ b/code/core/rttbInvalidDoseException.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __INVALID_DOSE_EXCEPTION_H #define __INVALID_DOSE_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class InvalidDoseException @brief This exception will be thrown if dose is invalid. */ class InvalidDoseException: public Exception - { - public: - InvalidDoseException(const std::string& aWhat):Exception(aWhat){} + { + public: + InvalidDoseException(const std::string& aWhat): Exception(aWhat) {} - virtual ~InvalidDoseException() throw() {} + virtual ~InvalidDoseException() throw() {} - /*! @brief Get the exception description - */ - virtual const char * what() const throw(); + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); - /*! @brief Get the name of the exception class - */ - virtual const char* GetNameOfClass() const; - }; + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; - } } +} #endif diff --git a/code/core/rttbInvalidParameterException.cpp b/code/core/rttbInvalidParameterException.cpp index bf563c4..ab7e762 100644 --- a/code/core/rttbInvalidParameterException.cpp +++ b/code/core/rttbInvalidParameterException.cpp @@ -1,39 +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 #include #include "rttbInvalidParameterException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - const char* InvalidParameterException::what() const throw() { + const char* InvalidParameterException::what() const throw() + { return rttb_what.c_str(); - } + } - const char* InvalidParameterException::GetNameOfClass() const{ - return "InvalidParameterException"; - } + const char* InvalidParameterException::GetNameOfClass() const + { + return "InvalidParameterException"; + } - }//end namespace core - }//end namespace rttb + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbInvalidParameterException.h b/code/core/rttbInvalidParameterException.h index 030ac83..5c99ff8 100644 --- a/code/core/rttbInvalidParameterException.h +++ b/code/core/rttbInvalidParameterException.h @@ -1,54 +1,56 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __INVALID_PARAMETER_EXCEPTION_H #define __INVALID_PARAMETER_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class InvalidParameterException @brief This exception will be thrown if any parameter is invalid. */ class InvalidParameterException: public Exception - { - public: - InvalidParameterException(const std::string& aWhat):Exception(aWhat){} + { + public: + InvalidParameterException(const std::string& aWhat): Exception(aWhat) {} - virtual ~InvalidParameterException() throw() {} + virtual ~InvalidParameterException() throw() {} - /*! @brief Get the exception description - */ - virtual const char * what() const throw(); + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); - /*! @brief Get the name of the exception class - */ - virtual const char* GetNameOfClass() const; - }; + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; - } } +} #endif diff --git a/code/core/rttbMaskAccessorGeneratorInterface.h b/code/core/rttbMaskAccessorGeneratorInterface.h index dd55e14..ee437d1 100644 --- a/code/core/rttbMaskAccessorGeneratorInterface.h +++ b/code/core/rttbMaskAccessorGeneratorInterface.h @@ -1,59 +1,62 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MASK_ACCESSOR_GENERATOR_INTERFACE_H #define __MASK_ACCESSOR_GENERATOR_INTERFACE_H #include "rttbMaskAccessorInterface.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class MaskAccessorGeneratorInterface @brief Interface for all MaskAccessor generating classes */ class MaskAccessorGeneratorInterface - { - public: - typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; - - - private: - MaskAccessorGeneratorInterface(const MaskAccessorGeneratorInterface&); //not implemented on purpose -> non-copyable - MaskAccessorGeneratorInterface& operator=(const MaskAccessorGeneratorInterface&);//not implemented on purpose -> non-copyable - - - protected: - MaskAccessorGeneratorInterface() {}; - virtual ~MaskAccessorGeneratorInterface() {}; - - public: - - - /*! @brief Generate MaskAccessor - @return Return shared pointer of MaskAccessor. - */ - virtual MaskAccessorPointer generateMaskAccessor() = 0; - }; - } + { + public: + typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; + + + private: + MaskAccessorGeneratorInterface(const + MaskAccessorGeneratorInterface&); //not implemented on purpose -> non-copyable + MaskAccessorGeneratorInterface& operator=(const + MaskAccessorGeneratorInterface&);//not implemented on purpose -> non-copyable + + + protected: + MaskAccessorGeneratorInterface() {}; + virtual ~MaskAccessorGeneratorInterface() {}; + + public: + + + /*! @brief Generate MaskAccessor + @return Return shared pointer of MaskAccessor. + */ + virtual MaskAccessorPointer generateMaskAccessor() = 0; + }; } +} #endif diff --git a/code/core/rttbMaskAccessorProcessorInterface.h b/code/core/rttbMaskAccessorProcessorInterface.h index be0b717..0fafd59 100644 --- a/code/core/rttbMaskAccessorProcessorInterface.h +++ b/code/core/rttbMaskAccessorProcessorInterface.h @@ -1,62 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MASK_ACCESSOR_PROCESSOR_INTERFACE_H #define __MASK_ACCESSOR_PROCESSOR_INTERFACE_H #include "rttbMaskAccessorInterface.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class MaskAccessorProcessorInterface @brief Interface for all MaskAccessor converter classes */ class MaskAccessorProcessorInterface - { - public: - typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; - - - private: - MaskAccessorProcessorInterface(const MaskAccessorProcessorInterface&); //not implemented on purpose -> non-copyable - MaskAccessorProcessorInterface& operator=(const MaskAccessorProcessorInterface&);//not implemented on purpose -> non-copyable - - - protected: - MaskAccessorProcessorInterface() {}; - virtual ~MaskAccessorProcessorInterface(){}; - - public: - - /*! @brief Sets the MaskAccessor that should be processed - @pre passed accessor must point to a valid instance. - */ - virtual void setMaskAccessor(MaskAccessorPointer accessor) = 0; - - /*! @brief Process the passed MaskAccessor - @return if the processing was successful. - */ - virtual bool process() = 0; - }; - } + { + public: + typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; + + + private: + MaskAccessorProcessorInterface(const + MaskAccessorProcessorInterface&); //not implemented on purpose -> non-copyable + MaskAccessorProcessorInterface& operator=(const + MaskAccessorProcessorInterface&);//not implemented on purpose -> non-copyable + + + protected: + MaskAccessorProcessorInterface() {}; + virtual ~MaskAccessorProcessorInterface() {}; + + public: + + /*! @brief Sets the MaskAccessor that should be processed + @pre passed accessor must point to a valid instance. + */ + virtual void setMaskAccessor(MaskAccessorPointer accessor) = 0; + + /*! @brief Process the passed MaskAccessor + @return if the processing was successful. + */ + virtual bool process() = 0; + }; } +} #endif diff --git a/code/core/rttbMaskVoxel.cpp b/code/core/rttbMaskVoxel.cpp index 4081533..f230eb1 100644 --- a/code/core/rttbMaskVoxel.cpp +++ b/code/core/rttbMaskVoxel.cpp @@ -1,95 +1,96 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbMaskVoxel.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { MaskVoxel::MaskVoxel(const rttb::VoxelGridID& aVoxelGridID) { if (aVoxelGridID < 0) { std::cout << aVoxelGridID << std::endl; throw InvalidParameterException("VoxelGridID is not valid!"); } else { _voxelGridID = aVoxelGridID; _volumeFraction = 1; } } MaskVoxel::MaskVoxel(const rttb::VoxelGridID& aVoxelGridID, FractionType aVolumeFraction) { if (aVoxelGridID < 0) { std::cout << aVoxelGridID << std::endl; throw InvalidParameterException("VoxelGridID is not valid!"); } else if (aVolumeFraction < 0 || aVolumeFraction > 1) { std::cout << aVolumeFraction << std::endl; throw InvalidParameterException("Volume fraction needs to be between 0 and 1!"); } else { _voxelGridID = aVoxelGridID; _volumeFraction = aVolumeFraction; } } bool MaskVoxel::operator==(const MaskVoxel& voxel) const { - return ((_voxelGridID == voxel.getVoxelGridID()) && (_volumeFraction == voxel.getRelevantVolumeFraction())); + return ((_voxelGridID == voxel.getVoxelGridID()) + && (_volumeFraction == voxel.getRelevantVolumeFraction())); } bool MaskVoxel::operator<(const MaskVoxel& maskVoxel) const { return (_voxelGridID < maskVoxel.getVoxelGridID()); } const VoxelGridID& MaskVoxel::getVoxelGridID() const { return _voxelGridID; } void MaskVoxel::setRelevantVolumeFraction(FractionType aVolumeFraction) { if (aVolumeFraction < 0 || aVolumeFraction > 1) { std::cout << aVolumeFraction << std::endl; throw InvalidParameterException("Volume fraction needs to be between 0 and 1!"); } _volumeFraction = aVolumeFraction; } FractionType MaskVoxel::getRelevantVolumeFraction() const { return _volumeFraction; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbMaskVoxel.h b/code/core/rttbMaskVoxel.h index 058facb..8c825b2 100644 --- a/code/core/rttbMaskVoxel.h +++ b/code/core/rttbMaskVoxel.h @@ -1,96 +1,100 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MASK_VOXEL_NEW_H #define __MASK_VOXEL_NEW_H #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class MaskVoxel * @brief AMaskVoxel stores the VoxelGridID of the corresponding dose voxel and the corresponding volume fraction - as defined by the given mask. + as defined by the given mask. */ class MaskVoxel - { - private: - /*! @brief A 1D voxel grid index on dose grid */ - VoxelGridID _voxelGridID; + { + private: + /*! @brief A 1D voxel grid index on dose grid */ + VoxelGridID _voxelGridID; - /*! @brief The relevant volume fraction that is masked by the given structure: 0~1 */ - FractionType _volumeFraction; + /*! @brief The relevant volume fraction that is masked by the given structure: 0~1 */ + FractionType _volumeFraction; - public: - /*! @brief Constructor - @pre aVoxelGridID needs to point to a valid grid position. - */ - MaskVoxel(const VoxelGridID& aVoxelGridID); + public: + /*! @brief Constructor + @pre aVoxelGridID needs to point to a valid grid position. + */ + MaskVoxel(const VoxelGridID& aVoxelGridID); - /*! @brief Constructor - @pre aVoxelGridID needs to point to a valid grid position. - */ - MaskVoxel(const VoxelGridID& aVoxelGridID, FractionType aVolumeFraction); + /*! @brief Constructor + @pre aVoxelGridID needs to point to a valid grid position. + */ + MaskVoxel(const VoxelGridID& aVoxelGridID, FractionType aVolumeFraction); /*! @brief Operator == - @return Return true if the id and volumeFraction are equal to these of the maskVoxel + @return Return true if the id and volumeFraction are equal to these of the maskVoxel */ - bool operator==(const MaskVoxel& maskVoxel) const; + bool operator==(const MaskVoxel& maskVoxel) const; /*! @brief Operator < @return Return true if the id < the id of the maskVoxel */ bool operator<(const MaskVoxel& maskVoxel) const; - const VoxelGridID& getVoxelGridID() const; + const VoxelGridID& getVoxelGridID() const; - void setRelevantVolumeFraction(const FractionType aVolumeFraction); + void setRelevantVolumeFraction(const FractionType aVolumeFraction); - /*! @brief Set the volume fraction of current voxel inside a given structure - @deprecated Please use setRelevantVolumeFraction instead. - @see setRelevantVolumeFraction - */ - void setProportionInStr(const FractionType aFraction){ - setRelevantVolumeFraction(aFraction); - }; + /*! @brief Set the volume fraction of current voxel inside a given structure + @deprecated Please use setRelevantVolumeFraction instead. + @see setRelevantVolumeFraction + */ + void setProportionInStr(const FractionType aFraction) + { + setRelevantVolumeFraction(aFraction); + }; - FractionType getRelevantVolumeFraction() const; + FractionType getRelevantVolumeFraction() const; - /*! @brief Get the volume fraction of current voxel inside a given structure - @deprecated Please use getRelevantVolumeFraction instead. - @see getRelevantVolumeFraction - */ - FractionType getProportionInStr() const{ - return getRelevantVolumeFraction(); - }; + /*! @brief Get the volume fraction of current voxel inside a given structure + @deprecated Please use getRelevantVolumeFraction instead. + @see getRelevantVolumeFraction + */ + FractionType getProportionInStr() const + { + return getRelevantVolumeFraction(); + }; - friend std::ostream& operator<<(std::ostream& s, const MaskVoxel& maskVoxel){ - s << "( " << maskVoxel.getVoxelGridID() << ": " << maskVoxel.getRelevantVolumeFraction() << " )"; - return s; - }; + friend std::ostream& operator<<(std::ostream& s, const MaskVoxel& maskVoxel) + { + s << "( " << maskVoxel.getVoxelGridID() << ": " << maskVoxel.getRelevantVolumeFraction() << " )"; + return s; }; - } + }; + } } #endif diff --git a/code/core/rttbMaskedDoseIteratorInterface.h b/code/core/rttbMaskedDoseIteratorInterface.h index c48c904..17ea2be 100644 --- a/code/core/rttbMaskedDoseIteratorInterface.h +++ b/code/core/rttbMaskedDoseIteratorInterface.h @@ -1,78 +1,80 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MASKED_DOSE_ITERATOR_INTERFACE_NEW_H #define __MASKED_DOSE_ITERATOR_INTERFACE_NEW_H #include #include #include #include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class MaskedDoseIteratorInterface @brief Give access to masked dose data. */ class MaskedDoseIteratorInterface: public DoseIteratorInterface - { - public: - typedef boost::shared_ptr MaskAccessorPointer; - typedef DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; - typedef DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - typedef boost::shared_ptr MaskedDoseIteratorPointer; - - private: - MaskedDoseIteratorInterface(const MaskedDoseIteratorInterface&); - MaskedDoseIteratorInterface& operator=(const MaskedDoseIteratorInterface&); + { + public: + typedef boost::shared_ptr MaskAccessorPointer; + typedef DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; + typedef DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; + typedef boost::shared_ptr MaskedDoseIteratorPointer; - protected: - /*! @brief Mask that is to be applied to currently loaded dose*/ - MaskAccessorPointer _spMask; + private: + MaskedDoseIteratorInterface(const MaskedDoseIteratorInterface&); + MaskedDoseIteratorInterface& operator=(const MaskedDoseIteratorInterface&); - public: - /* Constructor - @pre core::GeometricInfo represents the same geometric space for both mask and dose, - i.e. both live on the same data grid. Both accessors need to be valid. - */ - MaskedDoseIteratorInterface(MaskAccessorPointer aMaskAccessor, DoseAccessorPointer aDoseAccessor); + protected: + /*! @brief Mask that is to be applied to currently loaded dose*/ + MaskAccessorPointer _spMask; - virtual ~MaskedDoseIteratorInterface() {}; + public: + /* Constructor + @pre core::GeometricInfo represents the same geometric space for both mask and dose, + i.e. both live on the same data grid. Both accessors need to be valid. + */ + MaskedDoseIteratorInterface(MaskAccessorPointer aMaskAccessor, DoseAccessorPointer aDoseAccessor); - inline MaskAccessorPointer getMaskAccessor() const - { - return _spMask; - }; + virtual ~MaskedDoseIteratorInterface() {}; - /* Return doseValue*voxelFraction for the current position - */ - virtual DoseTypeGy getCurrentMaskedDoseValue() const = 0; + inline MaskAccessorPointer getMaskAccessor() const + { + return _spMask; }; - } + + /* Return doseValue*voxelFraction for the current position + */ + virtual DoseTypeGy getCurrentMaskedDoseValue() const = 0; + }; } +} #endif \ No newline at end of file diff --git a/code/core/rttbMutableDoseAccessorInterface.h b/code/core/rttbMutableDoseAccessorInterface.h index 107895b..1ce3cdc 100644 --- a/code/core/rttbMutableDoseAccessorInterface.h +++ b/code/core/rttbMutableDoseAccessorInterface.h @@ -1,47 +1,49 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MUTABLE_DOSE_ACCESSOR_INTERFACE_NEW_H #define __MUTABLE_DOSE_ACCESSOR_INTERFACE_NEW_H #include "rttbDoseAccessorInterface.h" #include "rttbBaseType.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class MutableAccessorInterface @brief Extends the DoseAccessorInterface to provide writing access to the data. */ class MutableDoseAccessorInterface: public DoseAccessorInterface - { + { - public: - typedef boost::shared_ptr MutableDoseAccessorPointer; + public: + typedef boost::shared_ptr MutableDoseAccessorPointer; - virtual void setDoseAt(const VoxelGridID aID, DoseTypeGy value) = 0; + virtual void setDoseAt(const VoxelGridID aID, DoseTypeGy value) = 0; - virtual void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) = 0; + virtual void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) = 0; - }; - } + }; + } } #endif diff --git a/code/core/rttbMutableMaskAccessorInterface.h b/code/core/rttbMutableMaskAccessorInterface.h index e4a8eb0..3ec5a6b 100644 --- a/code/core/rttbMutableMaskAccessorInterface.h +++ b/code/core/rttbMutableMaskAccessorInterface.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MUTABLE_MASK_ACCESSOR_INTERFACE_H #define __MUTABLE_MASK_ACCESSOR_INTERFACE_H #include #include "rttbMaskAccessorInterface.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" -namespace rttb{ - namespace core{ - - /*! @class MutableMaskAccessorInterface - @brief Extends the MaskAccessorInterface to provide writing access to the data. - This interface is created for external manipulation of generated masks. For example to store - the results of arithmetic operations on other masks. - */ - class MutableMaskAccessorInterface: public MaskAccessorInterface - { - public: - typedef boost::shared_ptr MutableMaskAccessorPointer; - typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; - typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; - - virtual void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer)= 0; - - virtual void setMaskAt(VoxelGridID aID, const MaskVoxel& voxel) = 0; - - virtual void setMaskAt(const VoxelGridIndex3D& gridIndex, const MaskVoxel& voxel) = 0; - - }; - } +namespace rttb +{ + namespace core + { + + /*! @class MutableMaskAccessorInterface + @brief Extends the MaskAccessorInterface to provide writing access to the data. + This interface is created for external manipulation of generated masks. For example to store + the results of arithmetic operations on other masks. + */ + class MutableMaskAccessorInterface: public MaskAccessorInterface + { + public: + typedef boost::shared_ptr MutableMaskAccessorPointer; + typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; + typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; + + virtual void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer) = 0; + + virtual void setMaskAt(VoxelGridID aID, const MaskVoxel& voxel) = 0; + + virtual void setMaskAt(const VoxelGridIndex3D& gridIndex, const MaskVoxel& voxel) = 0; + + }; + } } #endif diff --git a/code/core/rttbNullPointerException.cpp b/code/core/rttbNullPointerException.cpp index 10d1c8c..5af4c2d 100644 --- a/code/core/rttbNullPointerException.cpp +++ b/code/core/rttbNullPointerException.cpp @@ -1,39 +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 #include #include "rttbNullPointerException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - const char* NullPointerException::what() const throw() { + const char* NullPointerException::what() const throw() + { return rttb_what.c_str(); - } + } - const char* NullPointerException::GetNameOfClass() const{ - return "NullPointerException"; - } + const char* NullPointerException::GetNameOfClass() const + { + return "NullPointerException"; + } - }//end namespace core - }//end namespace rttb + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbNullPointerException.h b/code/core/rttbNullPointerException.h index bd377e2..1fcdd87 100644 --- a/code/core/rttbNullPointerException.h +++ b/code/core/rttbNullPointerException.h @@ -1,56 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __NULL_POINTER_EXCEPTION_H #define __NULL_POINTER_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class NullPointerException @brief This exception will be thrown if any pointer is NULL. */ class NullPointerException: public Exception - { - public: - NullPointerException(const std::string& aWhat):Exception(aWhat){} + { + public: + NullPointerException(const std::string& aWhat): Exception(aWhat) {} - virtual ~NullPointerException() throw() {} + virtual ~NullPointerException() throw() {} - /*! @brief Get the exception description - */ - virtual const char * what() const throw(); + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); - /*! @brief Get the name of the exception class - */ - virtual const char* GetNameOfClass() const; - }; + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; - } } +} #endif diff --git a/code/core/rttbPhysicalInfo.cpp b/code/core/rttbPhysicalInfo.cpp index a024c92..5ec896c 100644 --- a/code/core/rttbPhysicalInfo.cpp +++ b/code/core/rttbPhysicalInfo.cpp @@ -1,29 +1,37 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbPhysicalInfo.h" -namespace rttb{ - namespace core{ - void PhysicalInfo::setFullPath(PathType aPath){_fullPath=aPath;} - PathType PhysicalInfo::getFullPath(){return _fullPath;} +namespace rttb +{ + namespace core + { + void PhysicalInfo::setFullPath(PathType aPath) + { + _fullPath = aPath; + } + PathType PhysicalInfo::getFullPath() + { + return _fullPath; } } +} diff --git a/code/core/rttbPhysicalInfo.h b/code/core/rttbPhysicalInfo.h index 32a9a66..65defdc 100644 --- a/code/core/rttbPhysicalInfo.h +++ b/code/core/rttbPhysicalInfo.h @@ -1,48 +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 __PHYSICAL_INFO_H #define __PHYSICAL_INFO_H #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace core{ + namespace core + { /*! @class PhysicalInfo */ class PhysicalInfo - { - public: - void setFullPath(PathType aPath); - PathType getFullPath(); - private: - PathType _fullPath; + { + public: + void setFullPath(PathType aPath); + PathType getFullPath(); + private: + PathType _fullPath; - }; + }; - } } +} #endif diff --git a/code/core/rttbStrVectorStructureSetGenerator.cpp b/code/core/rttbStrVectorStructureSetGenerator.cpp index 44f8c2c..8966d61 100644 --- a/code/core/rttbStrVectorStructureSetGenerator.cpp +++ b/code/core/rttbStrVectorStructureSetGenerator.cpp @@ -1,42 +1,47 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbStrVectorStructureSetGenerator.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { - StrVectorStructureSetGenerator::StrVectorStructureSetGenerator(std::vector& aStructureVector,IDType aPatientUID) + StrVectorStructureSetGenerator::StrVectorStructureSetGenerator(std::vector& + aStructureVector, IDType aPatientUID) { - - _patientUID= aPatientUID; - _strVector=aStructureVector; - + + _patientUID = aPatientUID; + _strVector = aStructureVector; + } - StrVectorStructureSetGenerator::StructureSetPointer StrVectorStructureSetGenerator::generateStructureSet(){ - return boost::make_shared(_strVector,_patientUID); + StrVectorStructureSetGenerator::StructureSetPointer + StrVectorStructureSetGenerator::generateStructureSet() + { + return boost::make_shared(_strVector, _patientUID); } } }//end namespace rttb diff --git a/code/core/rttbStrVectorStructureSetGenerator.h b/code/core/rttbStrVectorStructureSetGenerator.h index e647e81..63d28ab 100644 --- a/code/core/rttbStrVectorStructureSetGenerator.h +++ b/code/core/rttbStrVectorStructureSetGenerator.h @@ -1,71 +1,74 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __STR_VECTOR_STRUCTURE_SET_GENERATOR_H #define __STR_VECTOR_STRUCTURE_SET_GENERATOR_H #include #include #include #include "rttbStructureSetGeneratorInterface.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class StrVectorStructureSetGenerator @brief Generate a structure set with a vector of Structures. */ class StrVectorStructureSetGenerator: public core::StructureSetGeneratorInterface { public: typedef core::StructureSet::StructTypePointer StructTypePointer; typedef StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; protected: IDType _patientUID; std::vector _strVector; StrVectorStructureSetGenerator() {}; public: /*! @brief Constructor @param aStructureVector the vector of structure shared pointer - @param aPatientUID the patient UID. + @param aPatientUID the patient UID. */ - StrVectorStructureSetGenerator(std::vector& aStructureVector,IDType aPatientUID=""); + StrVectorStructureSetGenerator(std::vector& aStructureVector, + IDType aPatientUID = ""); - /*! @brief Generate StructureSet - @return Return shared pointer of StructureSet. + /*! @brief Generate StructureSet + @return Return shared pointer of StructureSet. */ StructureSetPointer generateStructureSet(); }; } } #endif diff --git a/code/core/rttbStructure.cpp b/code/core/rttbStructure.cpp index e011e16..6850269 100644 --- a/code/core/rttbStructure.cpp +++ b/code/core/rttbStructure.cpp @@ -1,157 +1,158 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include #include #include "rttbStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace core { /*! Compares two polygons in the same plane. Helper function for sorting of polygons. */ bool comparePolygon(PolygonType A, PolygonType B) { PolygonType::iterator it; for (it = A.begin(); it != A.end(); ++it) { if ((*it)(2) != A.at(0)(2)) { throw std::range_error("Error: A must in the same _z plane!"); } } PolygonType::iterator it2; for (it2 = B.begin(); it2 != B.end(); ++it2) { if ((*it2)(2) != B.at(0)(2)) { throw std::range_error("Error: B must in the same _z plane!"); } } if (A.size() == 0 || B.size() == 0) { throw std::range_error("Error: A and B must not be empty!"); } return (A.at(0)(2) < B.at(0)(2)); } Structure::Structure() : _structureVector(0), _label("None") { if (_strUID.empty()) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _strUID = ss.str(); } } Structure::Structure(PolygonSequenceType strVector) : _structureVector(0), _label("None") { if (_strUID.empty()) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _strUID = ss.str(); } _structureVector = strVector; sort(_structureVector.begin(), _structureVector.end(), comparePolygon); } - Structure::Structure(const Structure& copy) : _structureVector(copy.getStructureVector()), _strUID(copy.getUID()), + Structure::Structure(const Structure& copy) : _structureVector(copy.getStructureVector()), + _strUID(copy.getUID()), _label(copy.getLabel()) { } Structure::~Structure() {} const PolygonSequenceType& Structure::getStructureVector() const { return _structureVector; } int Structure::getNumberOfEndpoints() const { int count = 0; PolygonSequenceType::const_iterator itVV; for (itVV = _structureVector.begin(); itVV != _structureVector.end(); ++itVV) { count += (int)(*itVV).size(); } return count; } IDType Structure::getUID() const { return _strUID; } void Structure::setUID(const IDType& aUID) { _strUID = aUID; } void Structure::setLabel(const StructureLabel& aLabel) { _label = aLabel; } StructureLabel Structure::getLabel() const { return _label; } }//end namespace core }//end namespace rttb diff --git a/code/core/rttbStructureSet.cpp b/code/core/rttbStructureSet.cpp index fc6f30f..0cc4a3d 100644 --- a/code/core/rttbStructureSet.cpp +++ b/code/core/rttbStructureSet.cpp @@ -1,78 +1,89 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include #include "rttbStructureSet.h" #include "rttbInvalidParameterException.h" -namespace rttb{ - namespace core{ - - StructureSet::StructureSet(){} - - StructureSet::StructureSet(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(); - } +namespace rttb +{ + namespace core + { + + StructureSet::StructureSet() {} + + StructureSet::StructureSet(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(int aStructureNo) const{ - int size = this->getNumberOfStructures()-1; - if(aStructureNo < 0 || aStructureNo > size){ + StructureSet::StructTypePointer StructureSet::getStructure(int aStructureNo) const + { + int size = this->getNumberOfStructures() - 1; + + if (aStructureNo < 0 || aStructureNo > size) + { std::stringstream sstr; - sstr << "aStructureNo must between 0 and "< #include #include "rttbBaseType.h" #include "rttbStructure.h" -namespace rttb{ - namespace core{ +namespace rttb +{ + namespace core + { /*! @class StructureSet @brief This is an class representing a structure set, which can be used to generate masks. */ class 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="", 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(int aStructureNo) const; - - /*! @brief Get the number of structures - @return Return the number of structures. - */ - NumberOfStructuresType getNumberOfStructures() const; - - virtual IDType getUID(); - - virtual IDType getPatientUID(); - - }; - } + { + 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 = "", + 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(int aStructureNo) const; + + /*! @brief Get the number of structures + @return Return the number of structures. + */ + NumberOfStructuresType getNumberOfStructures() const; + + virtual IDType getUID(); + + virtual IDType getPatientUID(); + + }; } +} #endif diff --git a/code/core/rttbStructureSetGeneratorInterface.h b/code/core/rttbStructureSetGeneratorInterface.h index bdb8f97..6092c01 100644 --- a/code/core/rttbStructureSetGeneratorInterface.h +++ b/code/core/rttbStructureSetGeneratorInterface.h @@ -1,61 +1,64 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __STRUCTURE_SET_GENERATOR_INTERFACE_H #define __STRUCTURE_SET_GENERATOR_INTERFACE_H #include #include "rttbStructureSet.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @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() {}; - virtual ~StructureSetGeneratorInterface() {}; - - public: - - - /*! @brief Generate StructureSet - @return Return shared pointer of StructureSet. - */ - virtual StructureSetPointer generateStructureSet() = 0; - }; - } + { + 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() {}; + virtual ~StructureSetGeneratorInterface() {}; + + public: + + + /*! @brief Generate StructureSet + @return Return shared pointer of StructureSet. + */ + virtual StructureSetPointer generateStructureSet() = 0; + }; } +} #endif diff --git a/code/indices/rttbConformalIndex.cpp b/code/indices/rttbConformalIndex.cpp index 06ba900..a251e20 100644 --- a/code/indices/rttbConformalIndex.cpp +++ b/code/indices/rttbConformalIndex.cpp @@ -1,101 +1,126 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbConformalIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { ConformalIndex::ConformalIndex(ConformalIndex::DVHSetPtr dvhSet, DoseTypeGy aDoseReference) - :DvhBasedDoseIndex(dvhSet, aDoseReference) - { + : DvhBasedDoseIndex(dvhSet, aDoseReference) + { init(); - } - - bool ConformalIndex::calcIndex() - { - VolumeType TV=_dvhSet->getTargetVolume(0); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(TV!=0 && Vref!=0){ - _value=(_dvhSet->getTargetVolume(_doseReference)/TV)* - (_dvhSet->getTargetVolume(_doseReference)/Vref); - - std::vector dvhHTSet=this->_dvhSet->getHealthyTissueSet(); - std::vector::iterator it; - - for(it=dvhHTSet.begin(); it!=dvhHTSet.end();++it) - { - core::DVH dvh=*(it); - VolumeType HT=dvh.getVx(0); - if(HT!=0) - _value*=(1-dvh.getVx(this->_doseReference)/HT); - } - } - else if(TV==0){ - throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); - } - else{ - rttbExceptionMacro(core::InvalidParameterException, << "Reference dose "<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } - return true; - } - - IndexValueType ConformalIndex::getValueAt(core::DVHSet::IndexType tvIndex){ - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(tvIndex>=dvhTVSet.size()){ - rttbExceptionMacro(core::InvalidParameterException, <<"tvIndex invalid: it should be <"<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } - - double value=dvh.getVx(_doseReference)/TV;//the irradiation factor of i-th target volume - value=value*dvh.getVx(_doseReference)/Vref;//conformation number - - std::vector dvhHTSet=this->_dvhSet->getHealthyTissueSet(); - std::vector::iterator it; - - for(it=dvhHTSet.begin(); it!=dvhHTSet.end();++it) - { - dvh=*(it); - VolumeType HT=dvh.getVx(0); - if(HT!=0){ - value*=(1-dvh.getVx(this->_doseReference)/HT); - } - } - return value; - } - } - - }//end namespace indices + } + + bool ConformalIndex::calcIndex() + { + VolumeType TV = _dvhSet->getTargetVolume(0); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (TV != 0 && Vref != 0) + { + _value = (_dvhSet->getTargetVolume(_doseReference) / TV) * + (_dvhSet->getTargetVolume(_doseReference) / Vref); + + std::vector dvhHTSet = this->_dvhSet->getHealthyTissueSet(); + std::vector::iterator it; + + for (it = dvhHTSet.begin(); it != dvhHTSet.end(); ++it) + { + core::DVH dvh = *(it); + VolumeType HT = dvh.getVx(0); + + if (HT != 0) + { + _value *= (1 - dvh.getVx(this->_doseReference) / HT); + } + } + } + else if (TV == 0) + { + throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); + } + else + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } + + return true; + } + + IndexValueType ConformalIndex::getValueAt(core::DVHSet::IndexType tvIndex) + { + std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (tvIndex >= dvhTVSet.size()) + { + rttbExceptionMacro(core::InvalidParameterException, + << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); + } + else + { + core::DVH dvh = dvhTVSet.at(tvIndex); + + VolumeType TV = dvh.getVx(0); + + if (TV == 0) + { + throw core::InvalidParameterException("DVH invalid: Volume of tvIndex should not be 0!"); + } + else if (Vref == 0) + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } + + double value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th target volume + value = value * dvh.getVx(_doseReference) / Vref; //conformation number + + std::vector dvhHTSet = this->_dvhSet->getHealthyTissueSet(); + std::vector::iterator it; + + for (it = dvhHTSet.begin(); it != dvhHTSet.end(); ++it) + { + dvh = *(it); + VolumeType HT = dvh.getVx(0); + + if (HT != 0) + { + value *= (1 - dvh.getVx(this->_doseReference) / HT); + } + } + + return value; + } + } + + }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbConformalIndex.h b/code/indices/rttbConformalIndex.h index cdc9f45..b702ef8 100644 --- a/code/indices/rttbConformalIndex.h +++ b/code/indices/rttbConformalIndex.h @@ -1,65 +1,67 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __CONFORMAL_INDEX_H #define __CONFORMAL_INDEX_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { - /*! @class ConformalIndex - @brief This class representing a ConformalIndex Object. Conformal Index (COIN)= Conformation Number(CN)* (1-Vref,0/Vnt,0)*(1-Vref,1/Vnt,1)... i: i-th critiacal organ - Conformation Number (CN)= (TVref/TV) * (TVref/Vref) - @ingroup indices - */ + /*! @class ConformalIndex + @brief This class representing a ConformalIndex Object. Conformal Index (COIN)= Conformation Number(CN)* (1-Vref,0/Vnt,0)*(1-Vref,1/Vnt,1)... i: i-th critiacal organ + Conformation Number (CN)= (TVref/TV) * (TVref/Vref) + @ingroup indices + */ class ConformalIndex: public DvhBasedDoseIndex - { - protected: - /*! @brief Calculate conformal index - @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid - */ - bool calcIndex(); + { + protected: + /*! @brief Calculate conformal index + @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid + */ + bool calcIndex(); - public: - /*! @brief Constructor - */ + public: + /*! @brief Constructor + */ ConformalIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference); - /*! @brief Dose index calculation for tvIndex-th treated volume - @param tvIndex index in the DVH in the current set of tv-DVHs - @return Return index value - @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid - */ + /*! @brief Dose index calculation for tvIndex-th treated volume + @param tvIndex index in the DVH in the current set of tv-DVHs + @return Return index value + @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid + */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex); - }; + }; - } + } } #endif diff --git a/code/indices/rttbConformationNumber.cpp b/code/indices/rttbConformationNumber.cpp index 1b58119..129a14f 100644 --- a/code/indices/rttbConformationNumber.cpp +++ b/code/indices/rttbConformationNumber.cpp @@ -1,77 +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 "rttbConformationNumber.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { ConformationNumber::ConformationNumber(DVHSetPtr dvhSet, DoseTypeGy aDoseReference) - :DvhBasedDoseIndex(dvhSet, aDoseReference) - { + : DvhBasedDoseIndex(dvhSet, aDoseReference) + { init(); - } + } bool ConformationNumber::calcIndex() + { + VolumeType TV = _dvhSet->getTargetVolume(0); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (TV != 0 && Vref != 0) + { + _value = (_dvhSet->getTargetVolume(_doseReference) / TV) * + (_dvhSet->getTargetVolume(_doseReference) / Vref); + } + else if (TV == 0) { - VolumeType TV=_dvhSet->getTargetVolume(0); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(TV!=0 && Vref!=0){ - _value=(_dvhSet->getTargetVolume(_doseReference)/TV)* - (_dvhSet->getTargetVolume(_doseReference)/Vref); - } - else if(TV==0){ throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); - } - else{ - rttbExceptionMacro(core::InvalidParameterException, << "Reference dose "<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } + } + else + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } return true; + } + + IndexValueType ConformationNumber::getValueAt(core::DVHSet::IndexType tvIndex) + { + std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (tvIndex >= dvhTVSet.size()) + { + rttbExceptionMacro(core::InvalidParameterException, + << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } + else + { + core::DVH dvh = dvhTVSet.at(tvIndex); + VolumeType TV = dvh.getVx(0); - IndexValueType ConformationNumber::getValueAt(core::DVHSet::IndexType tvIndex){ - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(tvIndex>=dvhTVSet.size()){ - rttbExceptionMacro(core::InvalidParameterException, <<"tvIndex invalid: it should be <"<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } - IndexValueType value=dvh.getVx(_doseReference)/TV;//the irradiation factor of i-th target volume - value=value*dvh.getVx(_doseReference)/Vref; - return value; } + else if (Vref == 0) + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } + + IndexValueType value = dvh.getVx(_doseReference) / + TV; //the irradiation factor of i-th target volume + value = value * dvh.getVx(_doseReference) / Vref; + return value; } + } - }//end namespace indices + }//end namespace indices }//end namespace rttb \ No newline at end of file diff --git a/code/indices/rttbConformationNumber.h b/code/indices/rttbConformationNumber.h index c636160..54e6e5d 100644 --- a/code/indices/rttbConformationNumber.h +++ b/code/indices/rttbConformationNumber.h @@ -1,67 +1,69 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __CONFORMATION_NUMBER_H #define __CONFORMATION_NUMBER_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { - /*! @class ConformationNumber - @brief This class representing a ConformationNumber Object. Conformation Number (CN)= (TVref/TV) * (TVref/Vref) - @ingroup indices - */ + /*! @class ConformationNumber + @brief This class representing a ConformationNumber Object. Conformation Number (CN)= (TVref/TV) * (TVref/Vref) + @ingroup indices + */ class ConformationNumber: public DvhBasedDoseIndex - { - protected: - /*! @brief Calculate conformation number - @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid - */ - bool calcIndex(); + { + protected: + /*! @brief Calculate conformation number + @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid + */ + bool calcIndex(); - public: + public: - /*! @brief Constructor - */ + /*! @brief Constructor + */ ConformationNumber(DVHSetPtr dvhSet, DoseTypeGy aDoseReference); - - /*! @brief Dose index calculation for tvIndex-th treated volume - @param tvIndex index in the DVH in the current set of tv-DVHs - @return Return index value - @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid - */ + + /*! @brief Dose index calculation for tvIndex-th treated volume + @param tvIndex index in the DVH in the current set of tv-DVHs + @return Return index value + @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid + */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex); - }; - } + }; + } } #endif diff --git a/code/indices/rttbConformityIndex.cpp b/code/indices/rttbConformityIndex.cpp index f1ed34a..35fcab9 100644 --- a/code/indices/rttbConformityIndex.cpp +++ b/code/indices/rttbConformityIndex.cpp @@ -1,76 +1,96 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbConformityIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { ConformityIndex::ConformityIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference) - :DvhBasedDoseIndex(dvhSet, aDoseReference) - { + : DvhBasedDoseIndex(dvhSet, aDoseReference) + { init(); - } + } bool ConformityIndex::calcIndex() - { - VolumeType TV=_dvhSet->getTargetVolume(0); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); + { + VolumeType TV = _dvhSet->getTargetVolume(0); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); - if(TV!=0 && Vref!=0){ - _value=(_dvhSet->getTargetVolume(this->_doseReference)/TV)*(1-_dvhSet->getHealthyTissueVolume(_doseReference)/Vref); - } - else if(TV==0){ + if (TV != 0 && Vref != 0) + { + _value = (_dvhSet->getTargetVolume(this->_doseReference) / TV) * (1 - + _dvhSet->getHealthyTissueVolume(_doseReference) / Vref); + } + else if (TV == 0) + { throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); - } - else{ - rttbExceptionMacro(core::InvalidParameterException, << "Reference dose "<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } + } + else + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } + return true; + } + + IndexValueType ConformityIndex::getValueAt(core::DVHSet::IndexType tvIndex) + { + std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (tvIndex >= dvhTVSet.size()) + { + rttbExceptionMacro(core::InvalidParameterException, + << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } + else + { + core::DVH dvh = dvhTVSet.at(tvIndex); + VolumeType TV = dvh.getVx(0); - IndexValueType ConformityIndex::getValueAt(core::DVHSet::IndexType tvIndex){ - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(tvIndex>=dvhTVSet.size()){ - rttbExceptionMacro(core::InvalidParameterException, <<"tvIndex invalid: it should be <"<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); - } - double value=dvh.getVx(_doseReference)/TV;//the irradiation factor of i-th treated volume - value=value*(1-_dvhSet->getHealthyTissueVolume(_doseReference)/Vref); - return value; } + else if (Vref == 0) + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); + } + + double value = dvh.getVx(_doseReference) / TV; //the irradiation factor of i-th treated volume + value = value * (1 - _dvhSet->getHealthyTissueVolume(_doseReference) / Vref); + return value; } + } - }//end namespace indices + }//end namespace indices }//end namespace rttb diff --git a/code/indices/rttbConformityIndex.h b/code/indices/rttbConformityIndex.h index c4f086c..3cc5a67 100644 --- a/code/indices/rttbConformityIndex.h +++ b/code/indices/rttbConformityIndex.h @@ -1,64 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __CONFORMITY_INDEX_H #define __CONFORMITY_INDEX_H #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { - /*! @class ConformityIndex - @brief This class representing a ConformityIndex Object. Conformity Index (CI): CI(D)=IFtv(D)*(1-IFht(D)), D:reference dose, - IFtv(D): the irradiation factor of the PTV, defined as the fraction of the PTV receiving a dose higher than D - IFht(D): the irradiation factor of healthy tissue, defined as the radio of the volume of tissue outside the PTV receiving a dose greater than D to the volume of isodose D - @ingroup indices - */ + /*! @class ConformityIndex + @brief This class representing a ConformityIndex Object. Conformity Index (CI): CI(D)=IFtv(D)*(1-IFht(D)), D:reference dose, + IFtv(D): the irradiation factor of the PTV, defined as the fraction of the PTV receiving a dose higher than D + IFht(D): the irradiation factor of healthy tissue, defined as the radio of the volume of tissue outside the PTV receiving a dose greater than D to the volume of isodose D + @ingroup indices + */ class ConformityIndex: public DvhBasedDoseIndex - { - protected: - /*! @brief Calculate Conformity index - @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid - */ - bool calcIndex(); + { + protected: + /*! @brief Calculate Conformity index + @exception InvalidParameterException Thrown if dvhSet or aDoseReference invalid + */ + bool calcIndex(); - public: - /*! @brief Constructor - */ + public: + /*! @brief Constructor + */ ConformityIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference); - /*! @brief Dose index calculation for tvIndex-th treated volume - @param tvIndex index in the DVH in the current set of tv-DVHs - @return Return index value - @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid - */ + /*! @brief Dose index calculation for tvIndex-th treated volume + @param tvIndex index in the DVH in the current set of tv-DVHs + @return Return index value + @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid + */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex); - }; + }; - } + } } #endif diff --git a/code/indices/rttbCoverageIndex.cpp b/code/indices/rttbCoverageIndex.cpp index b4c8652..426086f 100644 --- a/code/indices/rttbCoverageIndex.cpp +++ b/code/indices/rttbCoverageIndex.cpp @@ -1,64 +1,80 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbCoverageIndex.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { CoverageIndex::CoverageIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference) - :DvhBasedDoseIndex(dvhSet, aDoseReference) - { + : DvhBasedDoseIndex(dvhSet, aDoseReference) + { init(); - } + } bool CoverageIndex::calcIndex() + { + VolumeType TV = _dvhSet->getTargetVolume(0); + + if (TV != 0) + { + _value = _dvhSet->getTargetVolume(this->_doseReference) / TV; + } + else { - VolumeType TV=_dvhSet->getTargetVolume(0); - if(TV!=0) - _value=_dvhSet->getTargetVolume(this->_doseReference)/TV; - else{ throw core::InvalidParameterException("DVH Set invalid: Target volume should not be 0!"); - } + } + return true; + } + + IndexValueType CoverageIndex::getValueAt(core::DVHSet::IndexType tvIndex) + { + std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); + VolumeType Vref = _dvhSet->getWholeVolume(_doseReference); + + if (tvIndex >= dvhTVSet.size()) + { + rttbExceptionMacro(core::InvalidParameterException, + << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } - IndexValueType CoverageIndex::getValueAt(core::DVHSet::IndexType tvIndex){ - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); - VolumeType Vref=_dvhSet->getWholeVolume(_doseReference); - if(tvIndex>=dvhTVSet.size()){ - rttbExceptionMacro(core::InvalidParameterException, <<"tvIndex invalid: it should be <"< #include #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" #include "rttbDVHSet.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { - /*! @class CoverageIndex - @brief This class representing a CoverageIndex Object. Coverage Index fraction of the target volume receiving a dose >= the reference dose - @ingroup indices - */ + /*! @class CoverageIndex + @brief This class representing a CoverageIndex Object. Coverage Index fraction of the target volume receiving a dose >= the reference dose + @ingroup indices + */ class CoverageIndex: public DvhBasedDoseIndex - { + { - protected: - /*! @brief Calculate conformation number - @exception InvalidParameterException Thrown if dvhSet invalid - */ - bool calcIndex(); + protected: + /*! @brief Calculate conformation number + @exception InvalidParameterException Thrown if dvhSet invalid + */ + bool calcIndex(); - public: - /*! @brief Constructor - */ + public: + /*! @brief Constructor + */ CoverageIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference); - - /*! @brief Dose index calculation for tvIndex-th treated volume - * @param tvIndex: index in the vector of DVH TV - * @return Return index value - @exception InvalidParameterException Thrown if tvIndex invalid - */ + + /*! @brief Dose index calculation for tvIndex-th treated volume + * @param tvIndex: index in the vector of DVH TV + * @return Return index value + @exception InvalidParameterException Thrown if tvIndex invalid + */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex); - }; + }; - } + } } #endif diff --git a/code/indices/rttbDoseIndex.cpp b/code/indices/rttbDoseIndex.cpp index 9787cd9..c38378e 100644 --- a/code/indices/rttbDoseIndex.cpp +++ b/code/indices/rttbDoseIndex.cpp @@ -1,70 +1,79 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDoseIndex.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" -namespace rttb{ - namespace indices{ +namespace rttb +{ + namespace indices + { DoseIndex::DoseIndex(DoseTypeGy aDoseReference) - :_doseReference(aDoseReference),_initSuccess(false){} + : _doseReference(aDoseReference), _initSuccess(false) {} bool DoseIndex::init() - { - if(!(this->checkInputs())){ + { + if (!(this->checkInputs())) + { throw core::InvalidParameterException("Check inputs failed: invalid parameters! "); } - if( this->calcIndex()){ - _initSuccess=true; + + if (this->calcIndex()) + { + _initSuccess = true; } - else{ + else + { throw core::InvalidParameterException("Index calculation failed! "); } + return _initSuccess; } void DoseIndex::setDoseReference(DoseTypeGy aDoseReference) - { - _doseReference=aDoseReference; - _initSuccess=false; + { + _doseReference = aDoseReference; + _initSuccess = false; init(); - } + } DoseTypeGy DoseIndex::getDoseReference() const - { + { return _doseReference; - } + } IndexValueType DoseIndex::getValue() const + { + if (_initSuccess) { - if(_initSuccess){ return _value; - } - else{ - throw core::Exception("DoseIndex init error: init() must be called first!"); - } + } + else + { + throw core::Exception("DoseIndex init error: init() must be called first!"); } } + } } diff --git a/code/indices/rttbDoseIndex.h b/code/indices/rttbDoseIndex.h index e0e0830..4986285 100644 --- a/code/indices/rttbDoseIndex.h +++ b/code/indices/rttbDoseIndex.h @@ -1,87 +1,89 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_INDEX_H #define __DOSE_INDEX_H #include "rttbBaseType.h" #include "rttbDVHSet.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ - /*! @class DoseIndex - @brief This is the interface for dose/plan comparison indices. - @ingroup indices - */ - class DoseIndex - { - protected: + namespace indices + { + /*! @class DoseIndex + @brief This is the interface for dose/plan comparison indices. + @ingroup indices + */ + class DoseIndex + { + protected: - IndexValueType _value; + IndexValueType _value; - DoseTypeGy _doseReference; + DoseTypeGy _doseReference; - /*! @brief If init() successful*/ + /*! @brief If init() successful*/ bool _initSuccess; /*! @brief Initialize the calculation. It should be called in constructor or if any parameter of the calcualtion is changed. @return Return true if successfully @exception InvalidParameterException thrown if any input is invalid or index calculation failed */ bool init(); - /*! @brief Dose index calculation */ - virtual bool calcIndex()=0; + /*! @brief Dose index calculation */ + virtual bool calcIndex() = 0; /*! @brief Check all inputs for the index calculation*/ - virtual bool checkInputs()=0; + virtual bool checkInputs() = 0; - public: + public: /*! @brief Constructor with the referece dose*/ DoseIndex(DoseTypeGy aDoseReference); - - /*! @brief Set the reference dose - */ - void setDoseReference(DoseTypeGy aDoseReference); - - /*! @brief Get the reference dose - */ - DoseTypeGy getDoseReference() const; - - /*! @brief Get the value of dose/plan comparison index - @return Return the value of this index - @exception Exception Thrown if the class was not initialized previously. - */ - IndexValueType getValue() const; - - /*! @brief Get the value of dose/plan comparison index for a treated volume with the index in the DVH treated volume set + + /*! @brief Set the reference dose + */ + void setDoseReference(DoseTypeGy aDoseReference); + + /*! @brief Get the reference dose + */ + DoseTypeGy getDoseReference() const; + + /*! @brief Get the value of dose/plan comparison index + @return Return the value of this index + @exception Exception Thrown if the class was not initialized previously. + */ + IndexValueType getValue() const; + + /*! @brief Get the value of dose/plan comparison index for a treated volume with the index in the DVH treated volume set @param tvIndex index in the DVH in the current set of DVH subset for target volume: use DVHSet.getTargetVolumeSet() - */ - virtual IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex)=0; - }; - } + */ + virtual IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) = 0; + }; + } } #endif diff --git a/code/indices/rttbDvhBasedDoseIndex.cpp b/code/indices/rttbDvhBasedDoseIndex.cpp index 6232f9b..94649b6 100644 --- a/code/indices/rttbDvhBasedDoseIndex.cpp +++ b/code/indices/rttbDvhBasedDoseIndex.cpp @@ -1,44 +1,50 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbDvhBasedDoseIndex.h" -namespace rttb{ - namespace indices{ +namespace rttb +{ + namespace indices + { - DvhBasedDoseIndex::DvhBasedDoseIndex(DvhBasedDoseIndex::DVHSetPtr aDVHSet, DoseTypeGy aDoseReference) - :DoseIndex(aDoseReference),_dvhSet(aDVHSet) - { + DvhBasedDoseIndex::DvhBasedDoseIndex(DvhBasedDoseIndex::DVHSetPtr aDVHSet, + DoseTypeGy aDoseReference) + : DoseIndex(aDoseReference), _dvhSet(aDVHSet) + { } - bool DvhBasedDoseIndex::checkInputs(){ - if(!_dvhSet){ + bool DvhBasedDoseIndex::checkInputs() + { + if (!_dvhSet) + { return false; } - else{ + else + { return true; } } } } diff --git a/code/indices/rttbDvhBasedDoseIndex.h b/code/indices/rttbDvhBasedDoseIndex.h index 69a4319..eb87891 100644 --- a/code/indices/rttbDvhBasedDoseIndex.h +++ b/code/indices/rttbDvhBasedDoseIndex.h @@ -1,65 +1,67 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_BASED_DOSE_INDEX_H #define __DVH_BASED_DOSE_INDEX_H #include "rttbBaseType.h" #include "rttbDVHSet.h" #include "rttbDoseIndex.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ + namespace indices + { /*! @class DvhBasedDoseIndex @brief This is the interface for dose/plan comparison indices calculated by DVh set of the dose. */ class DvhBasedDoseIndex: public DoseIndex { public: typedef boost::shared_ptr DVHSetPtr; - protected: + protected: DVHSetPtr _dvhSet; /*! @brief Dose index calculation */ - virtual bool calcIndex()=0; + virtual bool calcIndex() = 0; /*! @brief Check inputs*/ bool checkInputs(); public: /*! @brief Constructor*/ DvhBasedDoseIndex(DVHSetPtr aDVHSet, DoseTypeGy aDoseReference); - + /*! @brief Dose/plan comparison index calculation for tvIndex-th treated volume (tv = target volume; th = healthy tissue) @param tvIndex index in the DVH in the current set of tv-DVHs */ - virtual IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex)=0; + virtual IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex) = 0; }; } } #endif diff --git a/code/indices/rttbHomogeneityIndex.cpp b/code/indices/rttbHomogeneityIndex.cpp index b56bce0..556c24d 100644 --- a/code/indices/rttbHomogeneityIndex.cpp +++ b/code/indices/rttbHomogeneityIndex.cpp @@ -1,76 +1,102 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbHomogeneityIndex.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" -namespace rttb{ - namespace indices{ +namespace rttb +{ + namespace indices + { HomogeneityIndex::HomogeneityIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference) - :DvhBasedDoseIndex(dvhSet, aDoseReference) + : DvhBasedDoseIndex(dvhSet, aDoseReference) { init(); } bool HomogeneityIndex::calcIndex() { - double max=0; + double max = 0; double min; - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); + std::vector dvhTVSet = this->_dvhSet->getTargetVolumeSet(); std::vector::iterator it; - for(it=dvhTVSet.begin(); it!=dvhTVSet.end();++it) + for (it = dvhTVSet.begin(); it != dvhTVSet.end(); ++it) { - core::DVH dvh=*(it); - if(it==dvhTVSet.begin()) - min=dvh.getMinimum(); - if(dvh.getMaximum()>max) - max=dvh.getMaximum(); - if(dvh.getMinimum() max) + { + max = dvh.getMaximum(); + } + + if (dvh.getMinimum() < min) + { + min = dvh.getMinimum(); + } } - if(this->getDoseReference()!=0){ - _value=(max-min)/this->getDoseReference(); + if (this->getDoseReference() != 0) + { + _value = (max - min) / this->getDoseReference(); } - else{ - rttbExceptionMacro(core::InvalidParameterException, << "Reference dose "<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); + else + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); } + return true; } - IndexValueType HomogeneityIndex::getValueAt(core::DVHSet::IndexType tvIndex){ - std::vector dvhTVSet=this->_dvhSet->getTargetVolumeSet(); - if(tvIndex>=dvhTVSet.size()){ - rttbExceptionMacro(core::InvalidParameterException, <<"tvIndex invalid: it should be <"< dvhTVSet = this->_dvhSet->getTargetVolumeSet(); + + if (tvIndex >= dvhTVSet.size()) + { + rttbExceptionMacro(core::InvalidParameterException, + << "tvIndex invalid: it should be <" << dvhTVSet.size() << "!"); } - core::DVH dvh=dvhTVSet.at(tvIndex); - if(this->getDoseReference()<=0){ - rttbExceptionMacro(core::InvalidParameterException, << "Reference dose "<getDoseReference()<<" invalid: Volume of reference dose should not be 0!"); + + core::DVH dvh = dvhTVSet.at(tvIndex); + + if (this->getDoseReference() <= 0) + { + rttbExceptionMacro(core::InvalidParameterException, + << "Reference dose " << this->getDoseReference() << + " invalid: Volume of reference dose should not be 0!"); } - return (dvh.getMaximum()-dvh.getMinimum())/this->getDoseReference(); + + return (dvh.getMaximum() - dvh.getMinimum()) / this->getDoseReference(); } }//end namespace indices }//end namespace rttb \ No newline at end of file diff --git a/code/indices/rttbHomogeneityIndex.h b/code/indices/rttbHomogeneityIndex.h index 4ed663b..c19516e 100644 --- a/code/indices/rttbHomogeneityIndex.h +++ b/code/indices/rttbHomogeneityIndex.h @@ -1,63 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __HOMOGENEITY_INDEX_H #define __HOMOGENEITY_INDEX_H #include #include #include "rttbDvhBasedDoseIndex.h" #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace indices{ - /*! @class HomogeneityIndex - @brief This class representing a HomogeneityIndex Object. Homogeneity Index (HI) = (Dmax(PTV)-Dmin(PTV))/Dref - @ingroup indices - */ + namespace indices + { + /*! @class HomogeneityIndex + @brief This class representing a HomogeneityIndex Object. Homogeneity Index (HI) = (Dmax(PTV)-Dmin(PTV))/Dref + @ingroup indices + */ class HomogeneityIndex: public DvhBasedDoseIndex - { - protected: - /*! @brief Calculate Conformity index - @exception InvalidParameterException Thrown if aDoseReference invalid - */ - bool calcIndex(); - - public: - /*! @brief Constructor - */ + { + protected: + /*! @brief Calculate Conformity index + @exception InvalidParameterException Thrown if aDoseReference invalid + */ + bool calcIndex(); + + public: + /*! @brief Constructor + */ HomogeneityIndex(DVHSetPtr dvhSet, DoseTypeGy aDoseReference); - /*! @brief Dose index calculation for tvIndex-th treated volume - @param tvIndex index in the DVH in the current set of tv-DVHs - @return Return index value - @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid - */ + /*! @brief Dose index calculation for tvIndex-th treated volume + @param tvIndex index in the DVH in the current set of tv-DVHs + @return Return index value + @exception InvalidParameterException Thrown if tvIndex or aDoseReference invalid + */ IndexValueType getValueAt(const core::DVHSet::IndexType tvIndex); - }; + }; - } + } } #endif diff --git a/code/interpolation/ITKTransformation/rttbITKTransformation.cpp b/code/interpolation/ITKTransformation/rttbITKTransformation.cpp index 4691acc..23686cd 100644 --- a/code/interpolation/ITKTransformation/rttbITKTransformation.cpp +++ b/code/interpolation/ITKTransformation/rttbITKTransformation.cpp @@ -1,91 +1,91 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 484 $ (last changed revision) -// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "rttbITKTransformation.h" #include "rttbNullPointerException.h" namespace rttb { namespace interpolation { ITKTransformation::ITKTransformation(const Transform3D3DType* aTransformation): _pTransformation(aTransformation) { //handle null pointer if (aTransformation == NULL) { throw core::NullPointerException("Pointer to registration is NULL."); } } void ITKTransformation::convert(const WorldCoordinate3D& aWorldCoordinate, InputPointType& aInputPoint) const { assert(aWorldCoordinate.size() == 3); assert(aInputPoint.Length == 3); for (unsigned int i = 0; i < aInputPoint.Length; ++i) { aInputPoint[i] = aWorldCoordinate[i]; } } void ITKTransformation::convert(const OutputPointType& aOutputPoint, WorldCoordinate3D& aWorldCoordinate) const { assert(aWorldCoordinate.size() == 3); assert(aOutputPoint.Length == 3); for (unsigned int i = 0; i < aOutputPoint.Length; ++i) { aWorldCoordinate[i] = aOutputPoint[i]; } } bool ITKTransformation::transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const { InputPointType aTargetPoint; OutputPointType aMovingPoint; convert(worldCoordinateTarget, aTargetPoint); aMovingPoint = _pTransformation->TransformPoint(aTargetPoint); convert(aMovingPoint, worldCoordinateMoving); //TransformPoint has no return value... return true; } bool ITKTransformation::transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const { OutputPointType aTargetPoint; InputPointType aMovingPoint; convert(worldCoordinateMoving, aMovingPoint); aTargetPoint = _pTransformation->TransformPoint(aMovingPoint); convert(aTargetPoint, worldCoordinateTarget); //TransformPoint has no return value... return true; } } } diff --git a/code/interpolation/ITKTransformation/rttbITKTransformation.h b/code/interpolation/ITKTransformation/rttbITKTransformation.h index 5d682e5..641b7b2 100644 --- a/code/interpolation/ITKTransformation/rttbITKTransformation.h +++ b/code/interpolation/ITKTransformation/rttbITKTransformation.h @@ -1,81 +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: 484 $ (last changed revision) -// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __ITK_MAPPABLE_DOSE_ACCESSOR_H #define __ITK_MAPPABLE_DOSE_ACCESSOR_H #include #include "itkTransform.h" #include "rttbDoseAccessorInterface.h" #include "rttbTransformationInterface.h" namespace rttb { namespace interpolation { /*! @class ITKMappableDoseAccessor @brief This class can deal with dose information that has to be transformed into another geometry than the original dose image (transformation specified by ITK transformation object). */ class ITKTransformation: public TransformationInterface { public: static const unsigned int InputDimension3D = 3; static const unsigned int OutputDimension3D = 3; typedef double TransformScalarType; typedef itk::Transform Transform3D3DType; typedef Transform3D3DType::InputPointType InputPointType; typedef Transform3D3DType::OutputPointType OutputPointType; typedef boost::shared_ptr Pointer; private: //! Has to be a Pointer type because of inheritance issues with itkSmartPointer (that doesn't recognize the inheritance) const Transform3D3DType* _pTransformation; protected: void convert(const WorldCoordinate3D& aWorldCoordinate, InputPointType& aInputPoint) const; void convert(const OutputPointType& aOutputPoint, WorldCoordinate3D& aWorldCoordinate) const; public: /*! @brief Constructor. @param aRegistration registration given in MatchPoint format (note the pointer format since itkSmartPointer does not support inheritance) @sa MappableDoseAccessorBase @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is NULL @exception core::PaddingException if the transformation is undefined and if _acceptPadding==false */ ITKTransformation(const Transform3D3DType* aTransformation); ~ITKTransformation() {}; /*! @brief performs a transformation targetImage --> movingImage */ bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const; /*! @brief performs a transformation movingImage --> targetImage */ bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const; }; } } #endif diff --git a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp index 0668bd8..513ca05 100644 --- a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp +++ b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.cpp @@ -1,88 +1,88 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 793 $ (last changed revision) -// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "rttbMatchPointTransformation.h" #include "rttbNullPointerException.h" namespace rttb { namespace interpolation { MatchPointTransformation::MatchPointTransformation( const Registration3D3DType* aRegistration): _pRegistration(aRegistration) { //handle null pointers if (aRegistration == NULL) { throw core::NullPointerException("Pointer to registration is NULL."); } } void MatchPointTransformation::convert(const WorldCoordinate3D& aWorldCoordinate, TargetPointType& aTargetPoint) const { assert(aWorldCoordinate.size() == 3); assert(aTargetPoint.Length == 3); for (unsigned int i = 0; i < aTargetPoint.Length; ++i) { aTargetPoint[i] = aWorldCoordinate[i]; } } void MatchPointTransformation::convert(const MovingPointType& aMovingPoint, WorldCoordinate3D& aWorldCoordinate) const { assert(aWorldCoordinate.size() == 3); assert(aMovingPoint.Length == 3); for (unsigned int i = 0; i < aMovingPoint.Length; ++i) { aWorldCoordinate[i] = aMovingPoint[i]; } } bool MatchPointTransformation::transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const { TargetPointType aTargetPoint; MovingPointType aMovingPoint; convert(worldCoordinateTarget, aTargetPoint); bool ok = _pRegistration->mapPointInverse(aTargetPoint, aMovingPoint); convert(aMovingPoint, worldCoordinateMoving); return ok; } bool MatchPointTransformation::transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const { TargetPointType aTargetPoint; MovingPointType aMovingPoint; convert(worldCoordinateMoving, aMovingPoint); bool ok = _pRegistration->mapPoint(aMovingPoint, aTargetPoint); convert(aTargetPoint, worldCoordinateTarget); return ok; } } } diff --git a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h index 4bd67fb..e96d10c 100644 --- a/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h +++ b/code/interpolation/MatchPointTransformation/rttbMatchPointTransformation.h @@ -1,82 +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: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __MATCHPOINT_TRANSFORMATION_H #define __MATCHPOINT_TRANSFORMATION_H #include #include "mapRegistration.h" #include "rttbTransformationInterface.h" #include "rttbBaseType.h" namespace rttb { namespace interpolation { /*! @class MatchPointTransformation @brief This class can deal with dose information that has to be transformed into another geometry than the original dose image (transformation specified by MatchPoint registration object). @ingroup interpolation */ class MatchPointTransformation: public TransformationInterface { public: static const unsigned int TargetDimension3D = 3; static const unsigned int MovingDimension3D = 3; typedef map::core::Registration Registration3D3DType; typedef map::core::Registration::MovingPointType MovingPointType; typedef map::core::Registration::TargetPointType TargetPointType; /*! @brief Constructor. @param aRegistration registration given in MatchPoint format (note the use of pointer since itkSmartPointer does not support inheritance) @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is NULL @exception core::PaddingException if the transformation is undefined and if _acceptPadding==false */ MatchPointTransformation(const Registration3D3DType* aRegistration); ~MatchPointTransformation() {}; /*! @brief performs a transformation targetImage --> movingImage */ bool transformInverse(const WorldCoordinate3D& worldCoordinateTarget, WorldCoordinate3D& worldCoordinateMoving) const override; /*! @brief performs a transformation movingImage --> targetImage */ bool transform(const WorldCoordinate3D& worldCoordinateMoving, WorldCoordinate3D& worldCoordinateTarget) const override; protected: void convert(const WorldCoordinate3D& aWorldCoordinate, TargetPointType& aTargetPoint) const; void convert(const MovingPointType& aMovingPoint, WorldCoordinate3D& aWorldCoordinate) const; private: //! Has to be a Pointer type because of inheritance issues with itkSmartPointer (that doesn't recognize the inheritance) const Registration3D3DType* _pRegistration; }; } } #endif diff --git a/code/io/dicom/rttbDVHDicomFileReader.h b/code/io/dicom/rttbDVHDicomFileReader.h index 17f77c1..b4a7d43 100644 --- a/code/io/dicom/rttbDVHDicomFileReader.h +++ b/code/io/dicom/rttbDVHDicomFileReader.h @@ -1,56 +1,59 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_DICOM_FILE_READER_H #define __DVH_DICOM_FILE_READER_H #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHGeneratorInterface.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { /*! @class DVHDicomFileReader @brief Read DVH data from a dicom file and create corresponding DVH object. */ class DVHDicomFileReader: public core::DVHGeneratorInterface { - private: + private: FileNameString _fileName; void createDVH(); public: - /*! @brief DVHDicomFileReader Constructor + /*! @brief DVHDicomFileReader Constructor @param aFileName the dicom dvh file name */ DVHDicomFileReader(FileNameString aFileName); /*! @brief Set the dicom dvh file name (triggers data import) @param aFileName the dicom dvh file name */ void setFileName(FileNameString aFileName); }; } } } #endif diff --git a/code/io/dicom/rttbDcmrtException.cpp b/code/io/dicom/rttbDcmrtException.cpp index ac1a2f2..45d315f 100644 --- a/code/io/dicom/rttbDcmrtException.cpp +++ b/code/io/dicom/rttbDcmrtException.cpp @@ -1,39 +1,44 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "rttbDcmrtException.h" -namespace rttb{ - namespace io{ - namespace dicom{ - const char* DcmrtException::what() const throw() { +namespace rttb +{ + namespace io + { + namespace dicom + { + const char* DcmrtException::what() const throw() + { return rttb_what.c_str(); } - const char* DcmrtException::GetNameOfClass() const{ - return "DcmrtException"; - } + const char* DcmrtException::GetNameOfClass() const + { + return "DcmrtException"; + } } }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDcmrtException.h b/code/io/dicom/rttbDcmrtException.h index ab325ed..951ad25 100644 --- a/code/io/dicom/rttbDcmrtException.h +++ b/code/io/dicom/rttbDcmrtException.h @@ -1,57 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DCMRT_EXCEPTION_H #define __DCMRT_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { /*! @class DcmrtException @brief This class represents a DcmrtException. Any dcmrt error will throw this exception. */ class DcmrtException: public core::Exception { - public: - DcmrtException(const std::string& aWhat):Exception(aWhat){} + public: + DcmrtException(const std::string& aWhat): Exception(aWhat) {} virtual ~DcmrtException() throw() {} /*! @brief Get the exception description */ - const char * what() const throw(); + const char* what() const throw(); - /*! @brief Get the name of the class that was thrown + /*! @brief Get the name of the class that was thrown */ const char* GetNameOfClass() const; }; } } } #endif diff --git a/code/io/dicom/rttbDicomFileDoseAccessorGenerator.cpp b/code/io/dicom/rttbDicomFileDoseAccessorGenerator.cpp index 159e216..9ea4c1c 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorGenerator.cpp +++ b/code/io/dicom/rttbDicomFileDoseAccessorGenerator.cpp @@ -1,107 +1,108 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbDicomFileReaderHelper.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace dicom { DicomFileDoseAccessorGenerator::~DicomFileDoseAccessorGenerator() {} DicomFileDoseAccessorGenerator::DicomFileDoseAccessorGenerator(FileNameType aDICOMRTDoseFileName) { _dicomDoseFileName = aDICOMRTDoseFileName; } - core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomFileDoseAccessorGenerator::generateDoseAccessor() + core::DoseAccessorGeneratorInterface::DoseAccessorPointer + DicomFileDoseAccessorGenerator::generateDoseAccessor() { std::vector fileVector; //if a file if (isFile(_dicomDoseFileName)) { fileVector.push_back(_dicomDoseFileName); } //if a directory else if (isDirectory(_dicomDoseFileName)) { rttb::io::dicom::Modality doseModality = {rttb::io::dicom::Modality::RTDOSE}; fileVector = getFileNamesWithSameUID(_dicomDoseFileName, doseModality); } 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; DRTDoseIODPtr dose = boost::make_shared(); status = fileformat.loadFile(fileVector.at(0).c_str()); if (!status.good()) { std::cerr << "Error: load rtdose loadFile(" << fileVector.at(0) << ") failed!" << std::endl; throw core::InvalidDoseException("Invalid dicom dose!"); } DcmItemPtr dataSet = boost::make_shared(*fileformat.getDataset()); status = dose->read(*dataSet); if (!status.good()) { std::cerr << "Error: read DRTDoseIOD failed!" << std::endl; throw core::InvalidDoseException("Invalid dicom dose!"); } _doseAccessor = boost::make_shared(dose, dataSet); return _doseAccessor; } } } } diff --git a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp index b7c1dad..a7ec2a5 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp +++ b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp @@ -1,257 +1,259 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include "rttbDicomFileDoseAccessorWriter.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "rttbGeometricInfo.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseStatisticsCalculator.h" namespace rttb { namespace io { namespace dicom { DicomFileDoseAccessorWriter::DicomFileDoseAccessorWriter() { _doseIOD = boost::make_shared(); _dataset = _fileformat.getDataset(); } void DicomFileDoseAccessorWriter::setFileName(DICOMRTFileNameString aFileName) { _fileName = aFileName; } bool DicomFileDoseAccessorWriter::process() { OFCondition status; /* Prepare dcmtk */ DcmItem* dcm_item = 0; //get geometric info rttb::core::GeometricInfo geometricInfo = _doseAccessor->getGeometricInfo(); /* ----------------------------------------------------------------- */ /* Part 1 -- General header */ /* ----------------------------------------------------------------- */ OFString CreationUID(_doseAccessor->getUID().c_str()); _dataset->putAndInsertString(DCM_ImageType, "DERIVED\\SECONDARY\\REFORMATTED"); _dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, "");//Creation Date _dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, "");//Creation Time _dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, CreationUID); _dataset->putAndInsertString(DCM_SOPClassUID, UID_RTDoseStorage); _dataset->putAndInsertString(DCM_SOPInstanceUID, _doseAccessor->getUID().c_str()); _dataset->putAndInsertOFStringArray(DCM_StudyDate, ""); _dataset->putAndInsertOFStringArray(DCM_StudyTime, ""); _dataset->putAndInsertOFStringArray(DCM_AccessionNumber, ""); _dataset->putAndInsertOFStringArray(DCM_Modality, "RTDOSE"); _dataset->putAndInsertString(DCM_Manufacturer, "RTToolbox"); _dataset->putAndInsertString(DCM_InstitutionName, ""); _dataset->putAndInsertString(DCM_ReferringPhysicianName, ""); _dataset->putAndInsertString(DCM_StationName, ""); _dataset->putAndInsertString(DCM_ManufacturerModelName, "RTToolbox"); /* (0008,1140) DCM_ReferencedImageSequence -- MIM likes this */ dcm_item = 0; _dataset->findOrCreateSequenceItem( DCM_ReferencedImageSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_CTImageStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); _dataset->putAndInsertString(DCM_PatientName, ""); _dataset->putAndInsertString(DCM_PatientID, ""); _dataset->putAndInsertString(DCM_PatientBirthDate, ""); _dataset->putAndInsertString(DCM_PatientSex, "O"); _dataset->putAndInsertString(DCM_SliceThickness, boost::lexical_cast(geometricInfo.getSliceThickness()).c_str()); _dataset->putAndInsertString(DCM_SoftwareVersions, ""); _dataset->putAndInsertString(DCM_StudyInstanceUID, ""); _dataset->putAndInsertString(DCM_SeriesInstanceUID, ""); _dataset->putAndInsertString(DCM_StudyID, "10001"); _dataset->putAndInsertString(DCM_SeriesNumber, ""); _dataset->putAndInsertString(DCM_InstanceNumber, "1"); /* GCS FIX: PatientOrientation */ std::ostringstream sstr; - sstr << geometricInfo.getImagePositionPatient().x() << "\\" << geometricInfo.getImagePositionPatient().y() + sstr << geometricInfo.getImagePositionPatient().x() << "\\" << + geometricInfo.getImagePositionPatient().y() << "\\" << geometricInfo.getImagePositionPatient().z(); _dataset->putAndInsertString(DCM_PatientOrientation, "L/P"); _dataset->putAndInsertString(DCM_ImagePositionPatient, sstr.str().c_str()); sstr.str(""); sstr << geometricInfo.getImageOrientationRow().x() << "\\" << geometricInfo.getImageOrientationRow().y() << "\\" << geometricInfo.getImageOrientationRow().z() << "\\" << geometricInfo.getImageOrientationColumn().x() << "\\" << geometricInfo.getImageOrientationColumn().y() << "\\" << geometricInfo.getImageOrientationColumn().z(); _dataset->putAndInsertString(DCM_ImageOrientationPatient, sstr.str().c_str()); _dataset->putAndInsertString(DCM_FrameOfReferenceUID, ""); _dataset->putAndInsertString(DCM_SamplesPerPixel, "1"); _dataset->putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2"); sstr.str(""); sstr << geometricInfo.getNumSlices(); _dataset->putAndInsertString(DCM_NumberOfFrames, sstr.str().c_str()); /* GCS FIX: Add FrameIncrementPointer */ _dataset->putAndInsertString(DCM_FrameIncrementPointer, "(3004,000c)"); _dataset->putAndInsertUint16(DCM_Rows, geometricInfo.getNumRows()); _dataset->putAndInsertUint16(DCM_Columns, geometricInfo.getNumColumns()); sstr.str(""); sstr << geometricInfo.getSpacing()(1) << "\\" << geometricInfo.getSpacing()(0); _dataset->putAndInsertString(DCM_PixelSpacing, sstr.str().c_str()); _dataset->putAndInsertString(DCM_BitsAllocated, "32"); _dataset->putAndInsertString(DCM_BitsStored, "32"); _dataset->putAndInsertString(DCM_HighBit, "31"); _dataset->putAndInsertString(DCM_DoseUnits, "GY"); _dataset->putAndInsertString(DCM_DoseSummationType, "PLAN"); sstr.str("0"); for (int i = 1; i < geometricInfo.getNumSlices(); i++) { sstr << "\\" << i* geometricInfo.getSpacing()(2); } _dataset->putAndInsertString(DCM_GridFrameOffsetVector, sstr.str().c_str()); /* We need to convert image to uint16_t, but first we need to scale it so that the maximum dose fits in a 16-bit unsigned integer. Compute an appropriate scaling factor based on the maximum dose. */ /* Find the maximum value in the image */ boost::shared_ptr spTestDoseIterator = boost::make_shared(_doseAccessor); rttb::core::GenericDoseIterator::DoseIteratorPointer spDoseIterator(spTestDoseIterator); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = myDoseStatsCalculator.calculateDoseStatistics(); //rttb::algorithms::DoseStatistics doseStat(spDoseIterator); //boost::shared_ptr< std::vector > > myResultPairs = // boost::make_shared< std::vector > >(); //rttb::algorithms::DoseStatistics::ResultListPointer spMyResultPairs(myResultPairs); double maxDose = doseStatistics->getMaximum(); /* Find scale factor */ float dose_scale; dose_scale = maxDose / PixelDataMaxValue; /* Scale the image and add scale factor to _dataset */ sstr.str(""); sstr << dose_scale; _dataset->putAndInsertString(DCM_DoseGridScaling, sstr.str().c_str()); /* (300c,0002) ReferencedRTPlanSequence -- for future expansion */ dcm_item = 0; _dataset->findOrCreateSequenceItem( DCM_ReferencedRTPlanSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_RTPlanStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); /* (300c,0060) DCM_ReferencedStructureSetSequence -- MIM likes this */ dcm_item = 0; _dataset->findOrCreateSequenceItem( DCM_ReferencedStructureSetSequence, dcm_item, -2); dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, UID_RTStructureSetStorage); dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, ""); /* Convert image bytes to integer, then add to _dataset */ Uint16* pixelData; - int pixelCount = geometricInfo.getNumRows() * geometricInfo.getNumColumns() * geometricInfo.getNumSlices(); + int pixelCount = geometricInfo.getNumRows() * geometricInfo.getNumColumns() * + geometricInfo.getNumSlices(); pixelData = new Uint16[pixelCount]; for (unsigned int i = 0; i < pixelCount; ++i) { double doseValue = _doseAccessor->getValueAt(i); double pixelValue = doseValue / dose_scale; if (pixelValue > PixelDataMaxValue) { pixelValue = PixelDataMaxValue; } pixelData[i] = boost::numeric_cast(pixelValue); } status = _dataset->putAndInsertUint16Array(DCM_PixelData, pixelData, pixelCount); if (!status.good()) { throw core::InvalidDoseException("Error: put and insert pixel data failed!"); } //Write dose to file status = _fileformat.saveFile(_fileName.c_str(), EXS_LittleEndianExplicit); if (status.bad()) { std::cerr << "Error: cannot write DICOM RTDOSE!" << std::endl; } return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDicomFileDoseAccessorWriter.h b/code/io/dicom/rttbDicomFileDoseAccessorWriter.h index c75743c..f5bbc94 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorWriter.h +++ b/code/io/dicom/rttbDicomFileDoseAccessorWriter.h @@ -1,82 +1,82 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DICOM_FILE_DOSE_ACCESSOR_WRITER_H #define __DICOM_FILE_DOSE_ACCESSOR_WRITER_H #include "../itk/rttbDoseAccessorProcessorBase.h" #include "../itk/rttbDoseAccessorConversionSettingInterface.h" #include "rttbDicomDoseAccessor.h" -//pixel data max value ‘UINT16_MAX’ +//pixel data max value ‘UINT16_MAX’ #define PixelDataMaxValue 0xffff namespace rttb { namespace io { namespace dicom { /*! @class DicomFileDoseAccessorWriter @brief Class converts/dumps the processed accessor into an dicom file @remark DoseAccessorConversionInterface defines how the converter should react on non valid dose values. */ class DicomFileDoseAccessorWriter: public core::DoseAccessorProcessorBase, public core::DoseAccessorConversionSettingInterface { public: typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; typedef DicomDoseAccessor::DRTDoseIODPtr DRTDoseIODPointer; /*! @brief Standard Constructor. */ DicomFileDoseAccessorWriter(); virtual ~DicomFileDoseAccessorWriter() {}; /*! Set a file name to write the dose - @param aFileName a file name to write the dose + @param aFileName a file name to write the dose */ void setFileName(DICOMRTFileNameString aFileName); /*! @brief Convert the accessor into dicom dataset and write dicom dataset to a file @exception InvalidDoseException thrown if put and insert pixel data into dicom dataset failed */ bool process(); - - + + private: DicomFileDoseAccessorWriter(const - DicomFileDoseAccessorWriter&); //not implemented on purpose -> non-copyable + DicomFileDoseAccessorWriter&); //not implemented on purpose -> non-copyable DicomFileDoseAccessorWriter& operator=(const - DicomFileDoseAccessorWriter&);//not implemented on purpose -> non-copyable + DicomFileDoseAccessorWriter&);//not implemented on purpose -> non-copyable DRTDoseIODPointer _doseIOD; DICOMRTFileNameString _fileName; DcmFileFormat _fileformat; - DcmDataset *_dataset; + DcmDataset* _dataset; }; } } } #endif diff --git a/code/io/dicom/rttbDicomFileReaderHelper.cpp b/code/io/dicom/rttbDicomFileReaderHelper.cpp index b767ec6..5ebb8b8 100644 --- a/code/io/dicom/rttbDicomFileReaderHelper.cpp +++ b/code/io/dicom/rttbDicomFileReaderHelper.cpp @@ -1,213 +1,254 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbDicomFileReaderHelper.h" #include #include #include #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" -namespace rttb{ - namespace io{ - namespace dicom{ - bool isFile(FileNameType aName){ - boost::filesystem::path path=boost::filesystem::path(aName); - if(boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path)) +namespace rttb +{ + namespace io + { + namespace dicom + { + bool isFile(FileNameType aName) + { + boost::filesystem::path path = boost::filesystem::path(aName); + + if (boost::filesystem::exists(path) && boost::filesystem::is_regular_file(path)) + { return true; + } else + { return false; + } } - bool isDirectory(FileNameType aName){ - boost::filesystem::path path=boost::filesystem::path(aName); - if(boost::filesystem::exists(path) && boost::filesystem::is_directory(path)) + bool isDirectory(FileNameType aName) + { + boost::filesystem::path path = boost::filesystem::path(aName); + + if (boost::filesystem::exists(path) && boost::filesystem::is_directory(path)) + { return true; + } else + { return false; + } } - OFString getModality(DcmDataSetPtr aDcmDataSet){ + OFString getModality(DcmDataSetPtr aDcmDataSet) + { OFString modality; OFCondition status; status = aDcmDataSet->findAndGetOFString(DcmTagKey(0x0008, 0x0060), modality); + if (!status.good()) { throw DcmrtException("Error: get modality failed!"); } + return modality; } - OFString getUID(DcmDataSetPtr aDcmDataSet){ + OFString getUID(DcmDataSetPtr aDcmDataSet) + { OFString uid; OFCondition status; status = aDcmDataSet->findAndGetOFString(DcmTagKey(0x0020, 0x000e), uid); + if (!status.good()) { throw DcmrtException("Error: get uid failed!"); } + return uid; } - std::vector getFileNamesWithSameUID(FileNameType aDirName, Modality aModality){ + std::vector getFileNamesWithSameUID(FileNameType aDirName, Modality aModality) + { std::vector fileNameVector; std::string modalityStrArray[] = {"RTDOSE", "RTSTRUCT", "RTPLAN"}; - boost::filesystem::path path=boost::filesystem::path(aDirName); + boost::filesystem::path path = boost::filesystem::path(aDirName); OFCondition status; DcmFileFormat fileformat; IDType uid = ""; DcmDataSetPtr datasetPtr; - if(aModality.Type != 1 && aModality.Type != 2 && aModality.Type != 3){ + if (aModality.Type != 1 && aModality.Type != 2 && aModality.Type != 3) + { throw core::InvalidParameterException("Error: invalid modality! The modality should be RTDOSE(1)/RTSTRUCT(2)/RTPLAN(3)."); } - //if a directory - if(isDirectory(aDirName)){ + //if a directory + if (isDirectory(aDirName)) + { boost::filesystem::directory_iterator end_iter; - bool isFirst=true; + bool isFirst = true; - for(boost::filesystem::directory_iterator dir_itr(path);dir_itr!=end_iter;++dir_itr) + for (boost::filesystem::directory_iterator dir_itr(path); dir_itr != end_iter; ++dir_itr) { - if(boost::filesystem::is_regular_file(dir_itr->status())) - { + if (boost::filesystem::is_regular_file(dir_itr->status())) + { boost::filesystem::path filePath(dir_itr->path().filename().string()); - filePath=boost::filesystem::system_complete(dir_itr->path()); + filePath = boost::filesystem::system_complete(dir_itr->path()); status = fileformat.loadFile(filePath.string().c_str()); + if (!status.good()) { - throw DcmrtException("Error: load dose file "+ filePath.string() +" failed!"); + throw DcmrtException("Error: load dose file " + filePath.string() + " failed!"); } datasetPtr = boost::make_shared(*fileformat.getDataset()); OFString modalityOFS = getModality(datasetPtr); - for(unsigned int i=0; i<3; i++){ - if (aModality.Type == (i+1) && modalityOFS == modalityStrArray[i].c_str()) + for (unsigned int i = 0; i < 3; i++) + { + if (aModality.Type == (i + 1) && modalityOFS == modalityStrArray[i].c_str()) { OFString currentUID = getUID(datasetPtr); - + //get the first uid of the given modality - if(isFirst) + if (isFirst) { uid = currentUID.c_str(); isFirst = false; } - if(uid == currentUID.c_str()) + + if (uid == currentUID.c_str()) { fileNameVector.push_back(filePath.string().c_str()); } + break; } } } } - } - else if(isFile(aDirName)){ - std::cout << "Important: the given name "+ aDirName +" is a file name, not a directory name. Given modality will be ignored, use the modality of the file." << std::endl; + } + else if (isFile(aDirName)) + { + std::cout << "Important: the given name " + aDirName + + " is a file name, not a directory name. Given modality will be ignored, use the modality of the file." + << std::endl; fileNameVector = getFileNames(aDirName); } - else{ + else + { throw core::InvalidParameterException("Error: file/directory does not exist!"); } + return fileNameVector; } - std::vector getFileNames(FileNameType aFileName){ + std::vector getFileNames(FileNameType aFileName) + { - if(!isFile(aFileName)){ + if (!isFile(aFileName)) + { throw core::InvalidParameterException("Error: file does not exist!"); } std::vector fileNameVector; - boost::filesystem::path path=boost::filesystem::path(aFileName); + boost::filesystem::path path = boost::filesystem::path(aFileName); OFCondition status; DcmFileFormat fileformat; DcmDataSetPtr datasetPtr; OFString modality;//modality of the given file OFString uid;//uid of the given file status = fileformat.loadFile(aFileName.c_str()); + if (!status.good()) { throw DcmrtException("Error: fileformat.loadFile failed!"); } - datasetPtr = boost::make_shared(*fileformat.getDataset()); + datasetPtr = boost::make_shared(*fileformat.getDataset()); modality = getModality(datasetPtr); uid = getUID(datasetPtr); //get parent directory - boost::filesystem::path parentDir = path.parent_path(); - if(boost::filesystem::is_directory(parentDir)){ + boost::filesystem::path parentDir = path.parent_path(); + + if (boost::filesystem::is_directory(parentDir)) + { boost::filesystem::directory_iterator end_iter; - for(boost::filesystem::directory_iterator dir_itr(parentDir);dir_itr!=end_iter;++dir_itr) + for (boost::filesystem::directory_iterator dir_itr(parentDir); dir_itr != end_iter; ++dir_itr) { - if(boost::filesystem::is_regular_file(dir_itr->status())) - { + if (boost::filesystem::is_regular_file(dir_itr->status())) + { boost::filesystem::path currentFilePath(dir_itr->path().filename().string()); currentFilePath = boost::filesystem::system_complete(dir_itr->path()); status = fileformat.loadFile(currentFilePath.string().c_str()); + if (!status.good()) { throw DcmrtException("Error: load dose fileformat.loadFile failed!"); } datasetPtr = boost::make_shared(*fileformat.getDataset()); OFString currentModality = getModality(datasetPtr); OFString currentUID = getUID(datasetPtr); //if the same modality - if (modality == currentModality && uid == currentUID){ + if (modality == currentModality && uid == currentUID) + { fileNameVector.push_back(currentFilePath.string().c_str()); } } } } + return fileNameVector; } } } } diff --git a/code/io/dicom/rttbDicomFileReaderHelper.h b/code/io/dicom/rttbDicomFileReaderHelper.h index e56e2a1..c8971b4 100644 --- a/code/io/dicom/rttbDicomFileReaderHelper.h +++ b/code/io/dicom/rttbDicomFileReaderHelper.h @@ -1,87 +1,90 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DICOM_FILE_READER_HELPER_H #define __DICOM_FILE_READER_HELPER_H #include #include #include #include "osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" #include "rttbBaseType.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { struct Modality { enum Type { RTDOSE = 1, RTSTRUCT = 2, RTPLAN = 3, UserDefined = 128 } Type; }; typedef boost::shared_ptr DRTDoseIODPtr; typedef boost::shared_ptr DcmDataSetPtr; /*! Return the vector of all files with the same UID in the given directory, the UID is defined by the first file with the modality. @exception InvalidParameterException thrown if the file/directory does not exist or the modality is invalid @exception DcmrtException thrown if load/read file failed */ - std::vector getFileNamesWithSameUID(FileNameType aDirName, Modality aModality); + std::vector getFileNamesWithSameUID(FileNameType aDirName, Modality aModality); - /*! Return the vector of all files with the same UID in the directory of the given file - @exception InvalidParameterException thrown if the file does not exist + /*! Return the vector of all files with the same UID in the directory of the given file + @exception InvalidParameterException thrown if the file does not exist @exception DcmrtException thrown if load/read file failed */ std::vector getFileNames(FileNameType aFileName); /*! Return if the given name is a file */ bool isFile(FileNameType aName); /*! Return if the given name is a directory */ bool isDirectory(FileNameType aName); /*! Return modality DcmTagKey(0x0008, 0x0060) @exception DcmrtException thrown if reading modality failed*/ OFString getModality(DcmDataSetPtr aDcmDataSet); /*! Return uid DcmTagKey(0x0020, 0x000e) @exception DcmrtException thrown if reading uid failed*/ OFString getUID(DcmDataSetPtr aDcmDataSet); }; } } #endif diff --git a/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp b/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp index dca9196..7ef6906 100644 --- a/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp +++ b/code/io/dicom/rttbDicomFileStructureSetGenerator.cpp @@ -1,95 +1,110 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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{ +namespace rttb +{ + namespace io + { + namespace dicom + { - DicomFileStructureSetGenerator::DicomFileStructureSetGenerator(DICOMRTFileNameString aDICOMRTStrSetFileName){ - - _fileName=aDICOMRTStrSetFileName; - + DicomFileStructureSetGenerator::DicomFileStructureSetGenerator(DICOMRTFileNameString + aDICOMRTStrSetFileName) + { + + _fileName = aDICOMRTStrSetFileName; + } - + DicomFileStructureSetGenerator::~DicomFileStructureSetGenerator() { - + } - DicomFileStructureSetGenerator::StructureSetPointer DicomFileStructureSetGenerator::generateStructureSet(){ + DicomFileStructureSetGenerator::StructureSetPointer + DicomFileStructureSetGenerator::generateStructureSet() + { std::vector fileVector; //if a file - if(isFile(_fileName)){ + if (isFile(_fileName)) + { fileVector.push_back(_fileName); } //if a directory - else if(isDirectory(_fileName)){ - rttb::io::dicom::Modality strModality= {rttb::io::dicom::Modality::RTSTRUCT}; + else if (isDirectory(_fileName)) + { + rttb::io::dicom::Modality strModality = {rttb::io::dicom::Modality::RTSTRUCT}; fileVector = getFileNamesWithSameUID(_fileName, strModality); } - else{ + else + { throw rttb::core::InvalidParameterException("Invalid file/directory name!"); } - if(fileVector.size()<1){ + 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(); + 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()) + + if (!status.good()) { throw DcmrtException("Read DRTStructureSetIOD DRTStructureSetIOD.read() failed!"); } - return (boost::make_shared(drtStrSetIODPtr))->generateStructureSet(); + return (boost::make_shared + (drtStrSetIODPtr))->generateStructureSet(); } }//end namespace dicom - }//end namespace io + }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDicomFileStructureSetGenerator.h b/code/io/dicom/rttbDicomFileStructureSetGenerator.h index 1ec34ff..5f4cb25 100644 --- a/code/io/dicom/rttbDicomFileStructureSetGenerator.h +++ b/code/io/dicom/rttbDicomFileStructureSetGenerator.h @@ -1,83 +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) */ /* Changes in Architecture: The DICOM specific classes will be removed and transfered to the corresponding IO classes. This class should only provide general structure functionality. */ #ifndef __DICOM_FILE_STRUCTURE_SET_GENERATOR_H #define __DICOM_FILE_STRUCTURE_SET_GENERATOR_H #include #include #include "drtstrct.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { /*! @class DicomFileStructureSetGenerator @brief Generate a structure set from a corresponding dicomRT file. */ class DicomFileStructureSetGenerator: public core::StrVectorStructureSetGenerator { public: typedef core::StructureSet::StructTypePointer StructTypePointer; typedef StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef boost::shared_ptr DRTStrSetIODPtr; private: IDType _UID; DICOMRTFileNameString _fileName; - DicomFileStructureSetGenerator(){}; + DicomFileStructureSetGenerator() {}; public: - - /*! @brief Constructor + + /*! @brief Constructor @param aDICOMRTStrSetFileName a DICOM-RT Structure set file name or a directory name @exception InvalidParameterException thrown if the file does not exist or the directory has no dicom structure file @exception DcmrtException thrown if load and read file failed */ DicomFileStructureSetGenerator(DICOMRTFileNameString aDICOMRTStrSetFileName); - /*! @brief Destructor + /*! @brief Destructor */ ~DicomFileStructureSetGenerator(); /*! @brief generate structure set @return return shared pointer of StructureSet @exception DcmrtException Thrown if loadFile and read failed @exception InvalidParameterException throw if the imported header tags are not numerical. */ StructureSetPointer generateStructureSet(); }; } } } #endif diff --git a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp index 95cc37b..9902e84 100644 --- a/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp +++ b/code/io/dicom/rttbDicomIODDoseAccessorGenerator.cpp @@ -1,70 +1,71 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace io { namespace dicom { DicomIODDoseAccessorGenerator::~DicomIODDoseAccessorGenerator() {} DicomIODDoseAccessorGenerator::DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP) { _doseIODPtr = aDRTDoseIODP; } - core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomIODDoseAccessorGenerator::generateDoseAccessor() + core::DoseAccessorGeneratorInterface::DoseAccessorPointer + DicomIODDoseAccessorGenerator::generateDoseAccessor() { DcmItem doseitem; OFCondition status; status = _doseIODPtr->write(doseitem);//write DoseIOD to DcmItem to get pixel data if (status.good()) { DcmItemPtr dataSetPtr = boost::make_shared(doseitem); _doseAccessor = boost::make_shared(_doseIODPtr, dataSetPtr); return _doseAccessor; } else { throw io::dicom::DcmrtException("Write DICOM RT Dose to DcmItem failed!"); } } } } } diff --git a/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp b/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp index 2fd28bf..76410d6 100644 --- a/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp +++ b/code/io/dicom/rttbDicomIODStructureSetGenerator.cpp @@ -1,164 +1,185 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbStructure.h" #include "rttbDicomIODStructureSetGenerator.h" #include "rttbDcmrtException.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { DicomIODStructureSetGenerator::DicomIODStructureSetGenerator(DRTStrSetIODPtr aDRTStructureSetIOD) { - _drtStrSetIOD=aDRTStructureSetIOD; + _drtStrSetIOD = aDRTStructureSetIOD; } - void DicomIODStructureSetGenerator::readStrSet(){ + void DicomIODStructureSetGenerator::readStrSet() + { OFString uid; _drtStrSetIOD->getSeriesInstanceUID(uid); - _UID=uid.c_str(); + _UID = uid.c_str(); OFString uid2; _drtStrSetIOD->getPatientID(uid2); - _patientUID=uid2.c_str(); + _patientUID = uid2.c_str(); - DRTStructureSetROISequence* rois=&_drtStrSetIOD->getStructureSetROISequence(); + DRTStructureSetROISequence* rois = &_drtStrSetIOD->getStructureSetROISequence(); /*A structure is a DRTROIContourSequence::Item. Each Item defines a roi. Each ROI contains a sequence of one or more contours, where a contour is either a single point (for a point ROI) or more than one point (representing an open or closed polygon). */ - DRTROIContourSequence *rcs; - rcs=&_drtStrSetIOD->getROIContourSequence(); - DRTROIContourSequence::Item *rcsItem; + DRTROIContourSequence* rcs; + rcs = &_drtStrSetIOD->getROIContourSequence(); + DRTROIContourSequence::Item* rcsItem; - long numberOfStructures=rcs->getNumberOfItems(); - bool isEmpty=rcs->isEmpty(); + long numberOfStructures = rcs->getNumberOfItems(); + bool isEmpty = rcs->isEmpty(); - if(numberOfStructures==0 || isEmpty){ + if (numberOfStructures == 0 || isEmpty) + { throw core::InvalidParameterException("Empty Structure Set!") ; } - int structureNo=0; - for (rcs->gotoFirstItem();(rcs->getCurrentItem(rcsItem)).good(); rcs->gotoNextItem()) + int structureNo = 0; + + for (rcs->gotoFirstItem(); (rcs->getCurrentItem(rcsItem)).good(); rcs->gotoNextItem()) { OFString refROINumber; rcsItem->getReferencedROINumber(refROINumber); - DRTContourSequence *cs; - cs=&rcsItem->getContourSequence(); - long no2=cs->getNumberOfItems(); + DRTContourSequence* cs; + cs = &rcsItem->getContourSequence(); + long no2 = cs->getNumberOfItems(); PolygonSequenceType structureVector; - for(int j=0; j< no2; j++){ + for (int j = 0; j < no2; j++) + { /*DRTContourSequence::Item represents a contour (either a single point (for a point ROI) or more than one point (representing an open or closed polygon))*/ - DRTContourSequence::Item *csItem; - csItem=&cs->getItem(j); + DRTContourSequence::Item* csItem; + csItem = &cs->getItem(j); OFString contourData; - OFString numberOfContourPoints; + OFString numberOfContourPoints; csItem->getNumberOfContourPoints(numberOfContourPoints); int numberOfContourPointsInt; std::stringstream is(numberOfContourPoints.c_str()); is >> numberOfContourPointsInt; OFString countourNumber; csItem->getContourNumber(countourNumber); PolygonType contourVector; char* pEnd; - for(int k=0; kgetContourData(contourData,k*3+i); - WorldCoordinate value=strtod(contourData.c_str(),&pEnd); - if( *pEnd != '\0'){ + for (int i = 0; i < 3; i++) + { + csItem->getContourData(contourData, k * 3 + i); + + WorldCoordinate value = strtod(contourData.c_str(), &pEnd); + + if (*pEnd != '\0') + { throw core::InvalidParameterException("Contour data not readable!") ; } - if(i==0) + if (i == 0) { - point(0)=value; + point(0) = value; } - else if(i==1) + else if (i == 1) { - point(1)=value; + point(1) = value; } - else{ - point(2)=value; + else + { + point(2) = value; } } + contourVector.push_back(point); } + structureVector.push_back(contourVector); } boost::shared_ptr spStruct = boost::make_shared(structureVector); StructTypePointer str(spStruct); - for(unsigned long i=0;igetNumberOfItems();i++){ - DRTStructureSetROISequence::Item *roisItem; - roisItem=&rois->getItem(i); + for (unsigned long i = 0; i < rois->getNumberOfItems(); i++) + { + DRTStructureSetROISequence::Item* roisItem; + roisItem = &rois->getItem(i); OFString roiNumber; roisItem->getROINumber(roiNumber); - if(roiNumber==refROINumber) + + if (roiNumber == refROINumber) { OFString roiName; roisItem->getROIName(roiName); str->setLabel(roiName.c_str()); - std::cout << roiName.c_str()<setUID(sstr.str()); _strVector.push_back(str); structureNo++; } } DicomIODStructureSetGenerator::~DicomIODStructureSetGenerator() - { + { } - DicomIODStructureSetGenerator::StructureSetPointer DicomIODStructureSetGenerator::generateStructureSet(){ + DicomIODStructureSetGenerator::StructureSetPointer + DicomIODStructureSetGenerator::generateStructureSet() + { this->readStrSet(); - return boost::make_shared(_strVector,_patientUID, _UID); + return boost::make_shared(_strVector, _patientUID, _UID); } }//end namespace dicom - }//end namespace io + }//end namespace io }//end namespace rttb diff --git a/code/io/dicom/rttbDicomIODStructureSetGenerator.h b/code/io/dicom/rttbDicomIODStructureSetGenerator.h index ffa7449..48553fd 100644 --- a/code/io/dicom/rttbDicomIODStructureSetGenerator.h +++ b/code/io/dicom/rttbDicomIODStructureSetGenerator.h @@ -1,90 +1,93 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ /* Changes in Architecture: The DICOM specific classes will be removed and transfered to the corresponding IO classes. This class should only provide general structure functionality. */ #ifndef __DICOM_IOD_STRUCTURE_SET_GENERATOR_H #define __DICOM_IOD_STRUCTURE_SET_GENERATOR_H #include #include #include #include "drtstrct.h" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" #include "rttbStructure.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { /*! @class DicomIODStructureSetGenerator @brief Generate a structure set from a DRTStructureSetIOD pointer. */ class DicomIODStructureSetGenerator: public core::StrVectorStructureSetGenerator { public: typedef core::StructureSet::StructTypePointer StructTypePointer; typedef StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef boost::shared_ptr DRTStrSetIODPtr; private: DRTStrSetIODPtr _drtStrSetIOD; IDType _UID; - - + + /*! Import Structure data from file. @exception InvalidParameterException Thrown if the imported header tags are not numerical. */ void readStrSet(); public: - /*! @brief Structure Constructor + /*! @brief Structure Constructor Get the vector of structures from DRTStructureSetIOD object @exception NullPointerException Thrown if structureSet is NULL */ DicomIODStructureSetGenerator(DRTStrSetIODPtr aDRTStructureSetIOD); - /*! @brief Destructor + /*! @brief Destructor */ ~DicomIODStructureSetGenerator(); /*! @brief generate structure set @return return shared pointer of StructureSet @exception InvalidParameterException throw if the imported header tags are not numerical. */ StructureSetPointer generateStructureSet(); - + }; } } } #endif diff --git a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp index f112b7d..850c9c0 100644 --- a/code/io/helax/rttbDicomHelaxDoseAccessor.cpp +++ b/code/io/helax/rttbDicomHelaxDoseAccessor.cpp @@ -1,325 +1,328 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace helax { DicomHelaxDoseAccessor::~DicomHelaxDoseAccessor() { } DicomHelaxDoseAccessor::DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector) { for (int i = 0; i < aDICOMRTDoseVector.size(); i++) { _doseVector.push_back(aDICOMRTDoseVector.at(i)); } this->begin(); } bool DicomHelaxDoseAccessor::begin() { if (_doseVector.size() == 0) { throw core::InvalidParameterException(" The size of aDICOMRTDoseVector is 0!"); } assembleGeometricInfo(); _doseData.clear(); OFString doseGridScalingStr; _doseVector.at(0)->getDoseGridScaling( doseGridScalingStr);//get the first dose grid scaling as _doseGridScaling try { _doseGridScaling = boost::lexical_cast(doseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } for (int i = 0; i < _doseVector.size(); i++) { DRTDoseIODPtr dose = _doseVector.at(i); OFString currentDoseGridScalingStr; dose->getDoseGridScaling(currentDoseGridScalingStr); double currentDoseGridScaling; try { currentDoseGridScaling = boost::lexical_cast(currentDoseGridScalingStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Dose grid scaling not readable or = 0!") ; } OFCondition status; DcmFileFormat fileformat; DcmItem doseitem; status = dose->write(doseitem); if (status.good()) { unsigned long count; const Uint16* pixelData; status = doseitem.findAndGetUint16Array(DcmTagKey(0x7fe0, 0x0010), pixelData, &count); if (status.good()) { for (unsigned int i = 0; i < static_cast(_geoInfo.getNumColumns()*_geoInfo.getNumRows()); i++) { this->_doseData.push_back(pixelData[i]*currentDoseGridScaling / _doseGridScaling); //recalculate dose data } } else { throw dicom::DcmrtException("Read Pixel Data (7FE0,0010) failed!"); } } else { throw dicom::DcmrtException("Read DICOM-RT Dose file failed!"); } } return true; } bool DicomHelaxDoseAccessor::assembleGeometricInfo() { DRTDoseIODPtr dose = _doseVector.at(0); Uint16 temp = 0; dose->getColumns(temp); _geoInfo.setNumColumns(temp); temp = 0; dose->getRows(temp); _geoInfo.setNumRows(temp); OFString numberOfFramesStr; dose->getNumberOfFrames(numberOfFramesStr); if (!numberOfFramesStr.empty()) { _geoInfo.setNumSlices(boost::lexical_cast(numberOfFramesStr.c_str())); } else { _geoInfo.setNumSlices((VoxelGridDimensionType)_doseVector.size()); } if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) { throw core::InvalidDoseException("Empty dicom dose!") ; } OFString imageOrientationRowX; dose->getImageOrientationPatient(imageOrientationRowX, 0); OFString imageOrientationRowY; dose->getImageOrientationPatient(imageOrientationRowY, 1); OFString imageOrientationRowZ; dose->getImageOrientationPatient(imageOrientationRowZ, 2); OFString imageOrientationColumnX; dose->getImageOrientationPatient(imageOrientationColumnX, 3); OFString imageOrientationColumnY; dose->getImageOrientationPatient(imageOrientationColumnY, 4); OFString imageOrientationColumnZ; dose->getImageOrientationPatient(imageOrientationColumnZ, 5); WorldCoordinate3D imageOrientationRow; WorldCoordinate3D imageOrientationColumn; try { imageOrientationRow(0) = boost::lexical_cast(imageOrientationRowX.c_str()); imageOrientationRow(1) = boost::lexical_cast(imageOrientationRowY.c_str()); imageOrientationRow(2) = boost::lexical_cast(imageOrientationRowZ.c_str()); imageOrientationColumn(0) = boost::lexical_cast(imageOrientationColumnX.c_str()); imageOrientationColumn(1) = boost::lexical_cast(imageOrientationColumnY.c_str()); imageOrientationColumn(2) = boost::lexical_cast(imageOrientationColumnZ.c_str()); } catch (boost::bad_lexical_cast&) { - throw core::InvalidDoseException("boost::lexical_cast ImageOrientation failed! Can not read image orientation X/Y/Z!") ; + throw core::InvalidDoseException("boost::lexical_cast ImageOrientation failed! Can not read image orientation X/Y/Z!") + ; } OrientationMatrix orientation; orientation(0, 0) = imageOrientationRow.x(); orientation(1, 0) = imageOrientationRow.y(); orientation(2, 0) = imageOrientationRow.z(); orientation(0, 1) = imageOrientationColumn.x(); orientation(1, 1) = imageOrientationColumn.y(); orientation(2, 1) = imageOrientationColumn.z(); WorldCoordinate3D perpendicular = imageOrientationRow.cross(imageOrientationColumn); orientation(0, 2) = perpendicular.x(); orientation(1, 2) = perpendicular.y(); orientation(2, 2) = perpendicular.z(); _geoInfo.setOrientationMatrix(orientation); OFString imagePositionX; dose->getImagePositionPatient(imagePositionX, 0); OFString imagePositionY; dose->getImagePositionPatient(imagePositionY, 1); OFString imagePositionZ; dose->getImagePositionPatient(imagePositionZ, 2); WorldCoordinate3D imagePositionPatient; try { imagePositionPatient(0) = boost::lexical_cast(imagePositionX.c_str()); imagePositionPatient(1) = boost::lexical_cast(imagePositionY.c_str()); imagePositionPatient(2) = boost::lexical_cast(imagePositionZ.c_str()); } catch (boost::bad_lexical_cast&) { - throw core::InvalidDoseException("boost::lexical_cast ImagePosition failed! Can not read image position X/Y/Z!") ; + throw core::InvalidDoseException("boost::lexical_cast ImagePosition failed! Can not read image position X/Y/Z!") + ; } _geoInfo.setImagePositionPatient(imagePositionPatient); SpacingVectorType3D spacingVector; OFString pixelSpacingRowStr; dose->getPixelSpacing(pixelSpacingRowStr, 0); OFString pixelSpacingColumnStr; dose->getPixelSpacing(pixelSpacingColumnStr, 1); try { spacingVector(1) = boost::lexical_cast(pixelSpacingRowStr.c_str()); spacingVector(0) = boost::lexical_cast(pixelSpacingColumnStr.c_str()); } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read Pixel Spacing Row/Column!") ; } _geoInfo.setSpacing(spacingVector); if (_geoInfo.getPixelSpacingRow() == 0 || _geoInfo.getPixelSpacingColumn() == 0) { throw core::InvalidDoseException("Pixel spacing not readable or = 0!"); } OFString sliceThicknessStr; dose->getSliceThickness(sliceThicknessStr); try { spacingVector(2) = boost::lexical_cast(sliceThicknessStr.c_str()); } catch (boost::bad_lexical_cast&) { spacingVector(2) = 0 ;//if no information about slice thickness, set to 0 and calculate it using z coordinate difference between 1. and 2. dose } if (spacingVector(2) == 0) { if (_doseVector.size() > 1) { DRTDoseIODPtr dose2 = _doseVector.at(1);//get the 2. dose OFString imagePositionZ2; dose2->getImagePositionPatient(imagePositionZ2, 2); try { - spacingVector(2) = boost::lexical_cast(imagePositionZ2.c_str()) - imagePositionPatient( + spacingVector(2) = boost::lexical_cast(imagePositionZ2.c_str()) - + imagePositionPatient( 2); //caculate slicethickness } catch (boost::bad_lexical_cast&) { throw core::InvalidDoseException("Can not read image position Z of the 2. dose!"); } } else { std::cerr << "sliceThickness == 0! It will be replaced with pixelSpacingRow=" << _geoInfo.getPixelSpacingRow() << "!" << std::endl; spacingVector(2) = spacingVector(0); } } _geoInfo.setSpacing(spacingVector); return true; } GenericValueType DicomHelaxDoseAccessor::getValueAt(const VoxelGridID aID) const { return _doseData.at(aID) * _doseGridScaling; } GenericValueType DicomHelaxDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getValueAt(aVoxelGridID); } else { return -1; } } } } } diff --git a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp index 2cecf9f..228dc8d 100644 --- a/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomHelaxFileDoseAccessorGenerator.cpp @@ -1,91 +1,94 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" #include "rttbDicomFileReaderHelper.h" namespace rttb { namespace io { namespace helax { DicomHelaxFileDoseAccessorGenerator::~DicomHelaxFileDoseAccessorGenerator() {} - DicomHelaxFileDoseAccessorGenerator::DicomHelaxFileDoseAccessorGenerator(FileNameType aDICOMRTDoseDirName) + DicomHelaxFileDoseAccessorGenerator::DicomHelaxFileDoseAccessorGenerator( + FileNameType aDICOMRTDoseDirName) { _doseDirName = aDICOMRTDoseDirName; } - core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomHelaxFileDoseAccessorGenerator::generateDoseAccessor() + core::DoseAccessorGeneratorInterface::DoseAccessorPointer + DicomHelaxFileDoseAccessorGenerator::generateDoseAccessor() { rttb::io::dicom::Modality doseModality = {rttb::io::dicom::Modality::RTDOSE}; - std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(_doseDirName, doseModality); + std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(_doseDirName, + doseModality); OFCondition status; DcmFileFormat fileformat; std::vector doseVector; for (int i = 0; i < fileVector.size(); i++) { DRTDoseIODPtr dose = boost::make_shared(); status = fileformat.loadFile(fileVector.at(i).c_str()); if (!status.good()) { throw core::InvalidDoseException("Error: load dose fileformat.loadFile failed!"); } status = dose->read(*fileformat.getDataset()); if (!status.good()) { throw core::InvalidDoseException("Error: read DRTDoseIOD failed!"); } doseVector.push_back(dose); } _doseAccessor = boost::make_shared(doseVector); return _doseAccessor; } } } } diff --git a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp index 355fa9b..6712b1b 100644 --- a/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomHelaxIODVecDoseAccessorGenerator.cpp @@ -1,63 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "boost/filesystem/operations.hpp" #include "boost/filesystem/path.hpp" #include "boost/progress.hpp" #include "rttbDicomHelaxIODVecDoseAccessorGenerator.h" #include "rttbDicomHelaxDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace io { namespace helax { DicomHelaxIODVecDoseAccessorGenerator::~DicomHelaxIODVecDoseAccessorGenerator() {} - DicomHelaxIODVecDoseAccessorGenerator::DicomHelaxIODVecDoseAccessorGenerator(std::vector& - aDICOMRTDoseVector) + DicomHelaxIODVecDoseAccessorGenerator::DicomHelaxIODVecDoseAccessorGenerator( + std::vector& + aDICOMRTDoseVector) { _dosePtrVector = aDICOMRTDoseVector; } - core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomHelaxIODVecDoseAccessorGenerator::generateDoseAccessor() + core::DoseAccessorGeneratorInterface::DoseAccessorPointer + DicomHelaxIODVecDoseAccessorGenerator::generateDoseAccessor() { _doseAccessor = boost::make_shared(_dosePtrVector); return _doseAccessor; } } } } diff --git a/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp b/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp index e8fe27f..ceca521 100644 --- a/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp +++ b/code/io/helax/rttbDicomIODDoseAccessorGenerator.cpp @@ -1,52 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbDicomIODDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbIndexOutOfBoundsException.h" -namespace rttb{ - namespace io{ - namespace dicom{ +namespace rttb +{ + namespace io + { + namespace dicom + { - DicomIODDoseAccessorGenerator::~DicomIODDoseAccessorGenerator(){} + DicomIODDoseAccessorGenerator::~DicomIODDoseAccessorGenerator() {} + + DicomIODDoseAccessorGenerator::DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP) + { + _doseIODPtr = aDRTDoseIODP; - DicomIODDoseAccessorGenerator::DicomIODDoseAccessorGenerator(DRTDoseIODPtr aDRTDoseIODP){ - _doseIODPtr=aDRTDoseIODP; - } - core::DoseAccessorGeneratorInterface::DoseAccessorPointer DicomIODDoseAccessorGenerator::generateDoseAccessor() { - _doseAccessor=boost::make_shared(_doseIODPtr); + core::DoseAccessorGeneratorInterface::DoseAccessorPointer + DicomIODDoseAccessorGenerator::generateDoseAccessor() + { + _doseAccessor = boost::make_shared(_doseIODPtr); return _doseAccessor; } - + } } } diff --git a/code/io/itk/itkDoseAccessorImageFilter.cpp b/code/io/itk/itkDoseAccessorImageFilter.cpp index da3be76..183d2c8 100644 --- a/code/io/itk/itkDoseAccessorImageFilter.cpp +++ b/code/io/itk/itkDoseAccessorImageFilter.cpp @@ -1,87 +1,89 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 4047 $ (last changed revision) -// @date $Date: 2012-10-29 16:19:15 +0100 (Mo, 29 Okt 2012) $ (last change date) -// @author $Author: zhang $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "itkDoseAccessorImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkProgressReporter.h" namespace itk { - /** - * Constructor - */ - DoseAccessorImageFilter - ::DoseAccessorImageFilter() - { - this->SetNumberOfRequiredInputs(1); - } - - void - DoseAccessorImageFilter - ::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, - ThreadIdType threadId) - { - ProgressReporter progress( this, threadId, - outputRegionForThread.GetNumberOfPixels() ); - - const unsigned int numberOfInputImages = - static_cast< unsigned int >( this->GetNumberOfIndexedInputs() ); - - const unsigned int numberOfOutputImages = - static_cast< unsigned int >( this->GetNumberOfIndexedOutputs() ); - - typedef ImageRegionConstIteratorWithIndex< InputImageType > ImageRegionConstIteratorType; - typedef ImageRegionIterator< OutputImageType > OutputImageRegionIteratorType; - - InputImagePointer inputPtr = dynamic_cast< InputImageType * >( ProcessObject::GetInput(0) ); - ImageRegionConstIteratorType inputItr; - if ( inputPtr ) - { - inputItr = ImageRegionConstIteratorType(inputPtr, outputRegionForThread); - } - - OutputImagePointer outputPtr = dynamic_cast< OutputImageType * >( ProcessObject::GetOutput(0) ); - OutputImageRegionIteratorType outputItr; - if ( outputPtr ) - { - outputItr = OutputImageRegionIteratorType(outputPtr, outputRegionForThread); - } - - if ( inputPtr && outputPtr ) - { - while ( !(outputItr.IsAtEnd()) ) - { - ImageRegionConstIteratorType::IndexType index = inputItr.GetIndex(); - rttb::VoxelGridIndex3D doseIndex(index[0],index[1],index[2]); - - outputItr.Set(m_Accessor->getValueAt(doseIndex)); - - ++outputItr; - ++inputItr; - - progress.CompletedPixel(); - } - } - } + /** + * Constructor + */ + DoseAccessorImageFilter + ::DoseAccessorImageFilter() + { + this->SetNumberOfRequiredInputs(1); + } + + void + DoseAccessorImageFilter + ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + ThreadIdType threadId) + { + ProgressReporter progress(this, threadId, + outputRegionForThread.GetNumberOfPixels()); + + const unsigned int numberOfInputImages = + static_cast< unsigned int >(this->GetNumberOfIndexedInputs()); + + const unsigned int numberOfOutputImages = + static_cast< unsigned int >(this->GetNumberOfIndexedOutputs()); + + typedef ImageRegionConstIteratorWithIndex< InputImageType > ImageRegionConstIteratorType; + typedef ImageRegionIterator< OutputImageType > OutputImageRegionIteratorType; + + InputImagePointer inputPtr = dynamic_cast< InputImageType* >(ProcessObject::GetInput(0)); + ImageRegionConstIteratorType inputItr; + + if (inputPtr) + { + inputItr = ImageRegionConstIteratorType(inputPtr, outputRegionForThread); + } + + OutputImagePointer outputPtr = dynamic_cast< OutputImageType* >(ProcessObject::GetOutput(0)); + OutputImageRegionIteratorType outputItr; + + if (outputPtr) + { + outputItr = OutputImageRegionIteratorType(outputPtr, outputRegionForThread); + } + + if (inputPtr && outputPtr) + { + while (!(outputItr.IsAtEnd())) + { + ImageRegionConstIteratorType::IndexType index = inputItr.GetIndex(); + rttb::VoxelGridIndex3D doseIndex(index[0], index[1], index[2]); + + outputItr.Set(m_Accessor->getValueAt(doseIndex)); + + ++outputItr; + ++inputItr; + + progress.CompletedPixel(); + } + } + } } // end namespace itk diff --git a/code/io/itk/itkDoseAccessorImageFilter.h b/code/io/itk/itkDoseAccessorImageFilter.h index 0a679a2..1576ecb 100644 --- a/code/io/itk/itkDoseAccessorImageFilter.h +++ b/code/io/itk/itkDoseAccessorImageFilter.h @@ -1,119 +1,119 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 4047 $ (last changed revision) -// @date $Date: 2012-10-29 16:19:15 +0100 (Mo, 29 Okt 2012) $ (last change date) -// @author $Author: zhang $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __itkDoseAccessorImageFilter_h #define __itkDoseAccessorImageFilter_h #include "itkImageToImageFilter.h" #include "itkImageIterator.h" #include "rttbDoseAccessorInterface.h" #include "rttbITKImageAccessor.h" namespace itk { - /** \class DoseAccessorImageFilter - * \brief Perform a generic pixel-wise operation on the input image by setting its pixel values according to the dose accessor output. - * - * \ingroup IntensityImageFilters MultiThreaded - * \ingroup ITKImageIntensity - */ - - typedef rttb::io::itk::ITKImageAccessor::ITKImageType RTTBDoseImageType; - - class ITK_EXPORT DoseAccessorImageFilter: - public ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > - - { - public: - /** Standard class typedefs. */ - typedef DoseAccessorImageFilter Self; - typedef ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > Superclass; - typedef SmartPointer< Self > Pointer; - typedef SmartPointer< const Self > ConstPointer; - /** Method for creation through the object factory. */ - itkNewMacro(Self); - - /** Run-time type information (and related methods). */ - itkTypeMacro(DoseAccessorImageFilter, ImageToImageFilter); - - /** Some typedefs. */ - typedef RTTBDoseImageType InputImageType; - typedef InputImageType::Pointer InputImagePointer; - typedef InputImageType::RegionType InputImageRegionType; - typedef InputImageType::PixelType InputImagePixelType; - typedef RTTBDoseImageType OutputImageType; - typedef OutputImageType::Pointer OutputImagePointer; - typedef OutputImageType::RegionType OutputImageRegionType; - typedef OutputImageType::PixelType OutputImagePixelType; - - typedef rttb::core::DoseAccessorInterface DoseAccessorType; - typedef rttb::core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; - - /** Get the accessor pointer. */ - DoseAccessorPointer GetAccessor() - { - return m_Accessor; - } - - /** Set the accessor pointer. */ - void SetAccessor(DoseAccessorPointer accessor) - { - if (m_Accessor != accessor) - { - m_Accessor = accessor; - this->Modified(); - } - } - - /** ImageDimension constants */ - itkStaticConstMacro( - InputImageDimension, unsigned int, InputImageType::ImageDimension); - itkStaticConstMacro( - OutputImageDimension, unsigned int, OutputImageType::ImageDimension); - - protected: - DoseAccessorImageFilter(); - virtual ~DoseAccessorImageFilter() {} - - /** DoseAccessorImageFilter can be implemented as a multi threaded filter. - * Therefore, this implementation provides a ThreadedGenerateData() routine - * which is called for each processing thread. The output image data is - * allocated automatically by the superclass prior to calling - * ThreadedGenerateData(). ThreadedGenerateData can only write to the - * portion of the output image specified by the parameter - * "outputRegionForThread" - * - * \sa ImageToImageFilter::ThreadedGenerateData(), - * ImageToImageFilter::GenerateData() */ - void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - ThreadIdType threadId); - - private: - DoseAccessorImageFilter(const Self&); //purposely not implemented - void operator=(const Self&); //purposely not implemented - - DoseAccessorPointer m_Accessor; - }; + /** \class DoseAccessorImageFilter + * \brief Perform a generic pixel-wise operation on the input image by setting its pixel values according to the dose accessor output. + * + * \ingroup IntensityImageFilters MultiThreaded + * \ingroup ITKImageIntensity + */ + + typedef rttb::io::itk::ITKImageAccessor::ITKImageType RTTBDoseImageType; + + class ITK_EXPORT DoseAccessorImageFilter: + public ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > + + { + public: + /** Standard class typedefs. */ + typedef DoseAccessorImageFilter Self; + typedef ImageToImageFilter< RTTBDoseImageType, RTTBDoseImageType > Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(DoseAccessorImageFilter, ImageToImageFilter); + + /** Some typedefs. */ + typedef RTTBDoseImageType InputImageType; + typedef InputImageType::Pointer InputImagePointer; + typedef InputImageType::RegionType InputImageRegionType; + typedef InputImageType::PixelType InputImagePixelType; + typedef RTTBDoseImageType OutputImageType; + typedef OutputImageType::Pointer OutputImagePointer; + typedef OutputImageType::RegionType OutputImageRegionType; + typedef OutputImageType::PixelType OutputImagePixelType; + + typedef rttb::core::DoseAccessorInterface DoseAccessorType; + typedef rttb::core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; + + /** Get the accessor pointer. */ + DoseAccessorPointer GetAccessor() + { + return m_Accessor; + } + + /** Set the accessor pointer. */ + void SetAccessor(DoseAccessorPointer accessor) + { + if (m_Accessor != accessor) + { + m_Accessor = accessor; + this->Modified(); + } + } + + /** ImageDimension constants */ + itkStaticConstMacro( + InputImageDimension, unsigned int, InputImageType::ImageDimension); + itkStaticConstMacro( + OutputImageDimension, unsigned int, OutputImageType::ImageDimension); + + protected: + DoseAccessorImageFilter(); + virtual ~DoseAccessorImageFilter() {} + + /** DoseAccessorImageFilter can be implemented as a multi threaded filter. + * Therefore, this implementation provides a ThreadedGenerateData() routine + * which is called for each processing thread. The output image data is + * allocated automatically by the superclass prior to calling + * ThreadedGenerateData(). ThreadedGenerateData can only write to the + * portion of the output image specified by the parameter + * "outputRegionForThread" + * + * \sa ImageToImageFilter::ThreadedGenerateData(), + * ImageToImageFilter::GenerateData() */ + void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + ThreadIdType threadId); + + private: + DoseAccessorImageFilter(const Self&); //purposely not implemented + void operator=(const Self&); //purposely not implemented + + DoseAccessorPointer m_Accessor; + }; } // end namespace itk #endif diff --git a/code/io/itk/rttbDoseAccessorConversionSettingInterface.h b/code/io/itk/rttbDoseAccessorConversionSettingInterface.h index 1d12a3b..714461a 100644 --- a/code/io/itk/rttbDoseAccessorConversionSettingInterface.h +++ b/code/io/itk/rttbDoseAccessorConversionSettingInterface.h @@ -1,76 +1,79 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACCESSOR_CONVERSION_SETTING_INTERFACE_H #define __DOSE_ACCESSOR_CONVERSION_SETTING_INTERFACE_H #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class DoseAccessorConversionSettingInterface @brief Interface for specifying settings for dose accessor convertors (e.g. how to handle invalid dose voxels) */ class DoseAccessorConversionSettingInterface + { + public: + /* Defines if the conversion process should fail (with an exception) if an invalid id/voxel occures.*/ + void setFailOnInvalidIDs(bool failOnInvalid) + { + _failedOnInvalidID = failOnInvalid; + } + + /* Indicates how the conversion should handle invalid ids/voxels.\n + * true: fails with an exception + * false: uses the specified "invalid dose value".*/ + bool failsOnInvalidIDs() const + { + return _failedOnInvalidID; + } + + /* Sets the value that should be used for invalid ids/voxels.*/ + void setInvalidDoseValue(DoseTypeGy value) { - public: - /* Defines if the conversion process should fail (with an exception) if an invalid id/voxel occures.*/ - void setFailOnInvalidIDs(bool failOnInvalid) - { - _failedOnInvalidID = failOnInvalid; - } - - /* Indicates how the conversion should handle invalid ids/voxels.\n - * true: fails with an exception - * false: uses the specified "invalid dose value".*/ - bool failsOnInvalidIDs() const - { - return _failedOnInvalidID; - } - - /* Sets the value that should be used for invalid ids/voxels.*/ - void setInvalidDoseValue(DoseTypeGy value) - { - _invalidDoseValue = value; - } - - /* Returns the value that is used for invalid ids/voxels.*/ - DoseTypeGy getInvalidDoseValue() const - { - return _invalidDoseValue; - } + _invalidDoseValue = value; + } + + /* Returns the value that is used for invalid ids/voxels.*/ + DoseTypeGy getInvalidDoseValue() const + { + return _invalidDoseValue; + } + + DoseAccessorConversionSettingInterface(): _failedOnInvalidID(false), _invalidDoseValue(-1.0) {}; + virtual ~DoseAccessorConversionSettingInterface() {}; + + private: + DoseAccessorConversionSettingInterface(const + DoseAccessorConversionSettingInterface&); //not implemented on purpose -> non-copyable + DoseAccessorConversionSettingInterface& operator=(const + DoseAccessorConversionSettingInterface&);//not implemented on purpose -> non-copyable + + protected: - DoseAccessorConversionSettingInterface():_failedOnInvalidID(false),_invalidDoseValue(-1.0){}; - virtual ~DoseAccessorConversionSettingInterface(){}; - - private: - DoseAccessorConversionSettingInterface(const DoseAccessorConversionSettingInterface&); //not implemented on purpose -> non-copyable - DoseAccessorConversionSettingInterface& operator=(const DoseAccessorConversionSettingInterface&);//not implemented on purpose -> non-copyable - - protected: - - bool _failedOnInvalidID; - DoseTypeGy _invalidDoseValue; - }; - } + bool _failedOnInvalidID; + DoseTypeGy _invalidDoseValue; + }; } +} #endif diff --git a/code/io/itk/rttbDoseAccessorProcessorInterface.h b/code/io/itk/rttbDoseAccessorProcessorInterface.h index b7bda9e..7297162 100644 --- a/code/io/itk/rttbDoseAccessorProcessorInterface.h +++ b/code/io/itk/rttbDoseAccessorProcessorInterface.h @@ -1,62 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACCESSOR_PROCESSOR_INTERFACE_H #define __DOSE_ACCESSOR_PROCESSOR_INTERFACE_H #include "rttbDoseAccessorInterface.h" -namespace rttb{ +namespace rttb +{ namespace core - { + { /*! @class DoseAccessorProcessorInterface @brief Interface for all DoseAccessor generating classes */ class DoseAccessorProcessorInterface - { - public: - typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; - - - private: - DoseAccessorProcessorInterface(const DoseAccessorProcessorInterface&); //not implemented on purpose -> non-copyable - DoseAccessorProcessorInterface& operator=(const DoseAccessorProcessorInterface&);//not implemented on purpose -> non-copyable - - - protected: - DoseAccessorProcessorInterface() {}; - virtual ~DoseAccessorProcessorInterface(){}; - - public: - - /*! @brief Sets the DoseAccessor that should be processed - @pre passed accessor must point to a valid instance. - */ - virtual void setDoseAccessor(DoseAccessorPointer accessor) = 0; - - /*! @brief Process the passed DoseAccessor - @return if the processing was successful. - */ - virtual bool process() = 0; - }; - } + { + public: + typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; + + + private: + DoseAccessorProcessorInterface(const + DoseAccessorProcessorInterface&); //not implemented on purpose -> non-copyable + DoseAccessorProcessorInterface& operator=(const + DoseAccessorProcessorInterface&);//not implemented on purpose -> non-copyable + + + protected: + DoseAccessorProcessorInterface() {}; + virtual ~DoseAccessorProcessorInterface() {}; + + public: + + /*! @brief Sets the DoseAccessor that should be processed + @pre passed accessor must point to a valid instance. + */ + virtual void setDoseAccessor(DoseAccessorPointer accessor) = 0; + + /*! @brief Process the passed DoseAccessor + @return if the processing was successful. + */ + virtual bool process() = 0; + }; } +} #endif diff --git a/code/io/itk/rttbITKException.cpp b/code/io/itk/rttbITKException.cpp index 14574e3..4335913 100644 --- a/code/io/itk/rttbITKException.cpp +++ b/code/io/itk/rttbITKException.cpp @@ -1,39 +1,44 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "rttbITKException.h" -namespace rttb{ - namespace io{ - namespace itk{ - const char* ITKException::what() const throw() { +namespace rttb +{ + namespace io + { + namespace itk + { + const char* ITKException::what() const throw() + { return rttb_what.c_str(); } - const char* ITKException::GetNameOfClass() const{ - return "ITKException"; - } + const char* ITKException::GetNameOfClass() const + { + return "ITKException"; + } } }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKException.h b/code/io/itk/rttbITKException.h index 43ed16f..94ad631 100644 --- a/code/io/itk/rttbITKException.h +++ b/code/io/itk/rttbITKException.h @@ -1,57 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __ITK_EXCEPTION_H #define __ITK_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace io{ - namespace itk{ +namespace rttb +{ + namespace io + { + namespace itk + { /*! @class ITKException @brief This class represents a ITKException. Any itk error will throw this exception. */ class ITKException: public core::Exception { - public: - ITKException(const std::string& aWhat):Exception(aWhat){} + public: + ITKException(const std::string& aWhat): Exception(aWhat) {} virtual ~ITKException() throw() {} /*! @brief Get the exception description */ - const char * what() const throw(); + const char* what() const throw(); - /*! @brief Get the name of the class that was thrown + /*! @brief Get the name of the class that was thrown */ const char* GetNameOfClass() const; }; } } } #endif diff --git a/code/io/itk/rttbITKIOHelper.h b/code/io/itk/rttbITKIOHelper.h index 0cbd82f..33ee7b0 100644 --- a/code/io/itk/rttbITKIOHelper.h +++ b/code/io/itk/rttbITKIOHelper.h @@ -1,65 +1,67 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __ITK_IO_HELPER_H #define __ITK_IO_HELPER_H #include "rttbDoseAccessorGeneratorBase.h" #include "rttbBaseType.h" #include "rttbITKImageAccessorConverter.h" #include "rttbGenericImageReader.h" #include "itkImage.h" #include "itkCastImageFilter.h" namespace rttb { namespace io { namespace itk { typedef ::itk::Image ITKImageType; /*! @brief Read a itk image file into itkImage */ ITKImageType::Pointer readITKDoubleImage(FileNameType aITKImageFile); /*! @brief Converts a generic image to itkImage @param itkGenericImage the image read by GenericImageReader @param loadedComponentType the component type (used for casting later on) @exception InvalidParameterException if component type is not supported @sa GenericImageReader */ - ITKImageType::Pointer handleGenericImage(GenericImageReader::GenericOutputImageType* itkGenericImage, + ITKImageType::Pointer handleGenericImage(GenericImageReader::GenericOutputImageType* + itkGenericImage, ::itk::ImageIOBase::IOComponentType& loadedComponentType); /*! @brief Casts into itkImage */ - template ITKImageType::Pointer doCasting(GenericImageReader::GenericOutputImageType* - genericImage); + template ITKImageType::Pointer doCasting( + GenericImageReader::GenericOutputImageType* + genericImage); }//end namespace itk }//end namespace io }//end namespace rttb #include "rttbITKIOHelper.tpp" #endif diff --git a/code/io/itk/rttbITKIOHelper.tpp b/code/io/itk/rttbITKIOHelper.tpp index f08c1f9..e772bdf 100644 --- a/code/io/itk/rttbITKIOHelper.tpp +++ b/code/io/itk/rttbITKIOHelper.tpp @@ -1,66 +1,67 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL: https://svn/sbr/Sources/SBR-Projects/MatchPoint/trunk/Code/IO/include/mapImageReader.tpp $ */ #ifndef __RTTB_ITK_IO_HELPER_TPP #define __RTTB_ITK_IO_HELPER_TPP #include "rttbITKImageAccessorConverter.h" #include "rttbInvalidParameterException.h" #include "rttbInvalidDoseException.h" #include "rttbITKImageAccessor.h" namespace rttb { namespace io { namespace itk { - template ITKImageType::Pointer doCasting(GenericImageReader::GenericOutputImageType* genericImage) + template ITKImageType::Pointer doCasting( + GenericImageReader::GenericOutputImageType* genericImage) { ITKImageType::Pointer itkDoubleImage; typedef ::itk::Image InputImageType; typedef ITKImageType OutputImageType; typename InputImageType::Pointer pCastedInput = dynamic_cast(genericImage); typedef ::itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); castFilter->SetInput(pCastedInput); try { //important to update the filter! castFilter->Update(); itkDoubleImage = castFilter->GetOutput(); } catch (::itk::ExceptionObject& e) { std::cerr << "ITK Error!!!" << std::endl; std::cerr << e << std::endl; } return itkDoubleImage; } } } } #endif diff --git a/code/io/itk/rttbITKImageAccessorConverter.cpp b/code/io/itk/rttbITKImageAccessorConverter.cpp index 0abaf99..c6de577 100644 --- a/code/io/itk/rttbITKImageAccessorConverter.cpp +++ b/code/io/itk/rttbITKImageAccessorConverter.cpp @@ -1,111 +1,111 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbITKImageAccessorConverter.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "itkDoseAccessorImageFilter.h" namespace rttb { - namespace io - { - namespace itk - { - - ITKImageAccessorConverter::ITKImageAccessorConverter(DoseAccessorPointer accessor) - { - setDoseAccessor(accessor); - } - - bool ITKImageAccessorConverter::process() - { - //Transfer GeometricInfo to ITK Properties - core::GeometricInfo geoInfo = _doseAccessor->getGeometricInfo(); - - ITKImageType::RegionType region; - ITKImageType::IndexType start; - - for (unsigned int i = 0; i < 3; ++i) - { - start[i] = 0; - } - - ITKImageType::SizeType size; - size[0] = geoInfo.getNumColumns(); - size[1] = geoInfo.getNumRows(); - size[2] = geoInfo.getNumSlices(); - - ITKImageType::SpacingType spacing; - - for (unsigned int i = 0; i < 3; ++i) - { - spacing[i] = geoInfo.getSpacing()[i]; - } - - ITKImageType::PointType origin; - - for (unsigned int i = 0; i < 3; ++i) - { - origin[i] = geoInfo.getImagePositionPatient()[i]; - } - - ITKImageType::DirectionType direction; - OrientationMatrix OM = geoInfo.getOrientationMatrix(); - - for (int col = 0; col < 3; ++col) - { - for (int row = 0; row < 3; ++row) - { - direction(col, row) = OM(col, row); - } - } - - //Create image, assign properties - region.SetSize(size); - region.SetIndex(start); - - _itkImage = ITKImageType::New(); - _itkImage->SetRegions(region); - _itkImage->SetSpacing(spacing); - _itkImage->SetDirection(direction); - _itkImage->SetOrigin(origin); - _itkImage->Allocate(); - - ::itk::DoseAccessorImageFilter::Pointer accessorFilter = ::itk::DoseAccessorImageFilter::New(); - accessorFilter->SetInput(_itkImage); - accessorFilter->SetAccessor(_doseAccessor); - accessorFilter->Update(); - - _itkImage = accessorFilter->GetOutput(); - - return true; - } - - }//end namespace itk - }//end namespace io + namespace io + { + namespace itk + { + + ITKImageAccessorConverter::ITKImageAccessorConverter(DoseAccessorPointer accessor) + { + setDoseAccessor(accessor); + } + + bool ITKImageAccessorConverter::process() + { + //Transfer GeometricInfo to ITK Properties + core::GeometricInfo geoInfo = _doseAccessor->getGeometricInfo(); + + ITKImageType::RegionType region; + ITKImageType::IndexType start; + + for (unsigned int i = 0; i < 3; ++i) + { + start[i] = 0; + } + + ITKImageType::SizeType size; + size[0] = geoInfo.getNumColumns(); + size[1] = geoInfo.getNumRows(); + size[2] = geoInfo.getNumSlices(); + + ITKImageType::SpacingType spacing; + + for (unsigned int i = 0; i < 3; ++i) + { + spacing[i] = geoInfo.getSpacing()[i]; + } + + ITKImageType::PointType origin; + + for (unsigned int i = 0; i < 3; ++i) + { + origin[i] = geoInfo.getImagePositionPatient()[i]; + } + + ITKImageType::DirectionType direction; + OrientationMatrix OM = geoInfo.getOrientationMatrix(); + + for (int col = 0; col < 3; ++col) + { + for (int row = 0; row < 3; ++row) + { + direction(col, row) = OM(col, row); + } + } + + //Create image, assign properties + region.SetSize(size); + region.SetIndex(start); + + _itkImage = ITKImageType::New(); + _itkImage->SetRegions(region); + _itkImage->SetSpacing(spacing); + _itkImage->SetDirection(direction); + _itkImage->SetOrigin(origin); + _itkImage->Allocate(); + + ::itk::DoseAccessorImageFilter::Pointer accessorFilter = ::itk::DoseAccessorImageFilter::New(); + accessorFilter->SetInput(_itkImage); + accessorFilter->SetAccessor(_doseAccessor); + accessorFilter->Update(); + + _itkImage = accessorFilter->GetOutput(); + + return true; + } + + }//end namespace itk + }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageAccessorGenerator.cpp b/code/io/itk/rttbITKImageAccessorGenerator.cpp index 6bdcab9..47b0885 100644 --- a/code/io/itk/rttbITKImageAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageAccessorGenerator.cpp @@ -1,59 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "rttbITKImageAccessor.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace io { namespace itk { ITKImageAccessorGenerator::ITKImageAccessorGenerator(const ITKImageType* aDoseImage) { if (aDoseImage == NULL) { throw core::InvalidDoseException("doseImage is NULL"); } _dosePtr = aDoseImage; } - core::DoseAccessorGeneratorBase::DoseAccessorPointer ITKImageAccessorGenerator::generateDoseAccessor() + core::DoseAccessorGeneratorBase::DoseAccessorPointer + ITKImageAccessorGenerator::generateDoseAccessor() { _doseAccessor = boost::make_shared(_dosePtr); return _doseAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp index dcf3ce1..b8c0353 100644 --- a/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp @@ -1,59 +1,59 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "../itk/rttbITKIOHelper.h" namespace rttb { namespace io { namespace itk { ITKImageFileMaskAccessorGenerator::~ITKImageFileMaskAccessorGenerator() { } ITKImageFileMaskAccessorGenerator::ITKImageFileMaskAccessorGenerator(const FileNameType& fileName) { _itkMaskFileName = fileName; } rttb::core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageFileMaskAccessorGenerator::generateMaskAccessor() - { + { _itkDoubleImage = rttb::io::itk::readITKDoubleImage(_itkMaskFileName); - + _maskAccessor = boost::make_shared(_itkDoubleImage.GetPointer()); return _maskAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageMaskAccessor.cpp b/code/io/itk/rttbITKImageMaskAccessor.cpp index 2aab824..be03864 100644 --- a/code/io/itk/rttbITKImageMaskAccessor.cpp +++ b/code/io/itk/rttbITKImageMaskAccessor.cpp @@ -1,165 +1,175 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbITKImageMaskAccessor.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace io { namespace itk { ITKImageMaskAccessor::ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage) : _mask(aMaskImage) { if (_mask.IsNull()) { throw core::InvalidDoseException("Mask image = 0!") ; } assembleGeometricInfo(); } ITKImageMaskAccessor::~ITKImageMaskAccessor() { }; bool ITKImageMaskAccessor::assembleGeometricInfo() { _geoInfo = boost::make_shared(); _geoInfo->setSpacing(SpacingVectorType3D(_mask->GetSpacing()[0], _mask->GetSpacing()[1], - _mask->GetSpacing()[2])); + _mask->GetSpacing()[2])); - if (_geoInfo->getSpacing()[0] == 0 || _geoInfo->getSpacing()[1] == 0 || _geoInfo->getSpacing()[2] == 0) + if (_geoInfo->getSpacing()[0] == 0 || _geoInfo->getSpacing()[1] == 0 + || _geoInfo->getSpacing()[2] == 0) { throw core::InvalidDoseException("Pixel spacing = 0!"); } _geoInfo->setImagePositionPatient(WorldCoordinate3D(_mask->GetOrigin()[0], _mask->GetOrigin()[1], - _mask->GetOrigin()[2])); + _mask->GetOrigin()[2])); OrientationMatrix OM(0); for (int col = 0; col < 3; ++col) { for (int row = 0; row < 3; ++row) { OM(col, row) = _mask->GetDirection()(col, row); } } _geoInfo->setOrientationMatrix(OM); _geoInfo->setNumColumns(_mask->GetLargestPossibleRegion().GetSize()[0]); _geoInfo->setNumRows(_mask->GetLargestPossibleRegion().GetSize()[1]); _geoInfo->setNumSlices(_mask->GetLargestPossibleRegion().GetSize()[2]); if (_geoInfo->getNumColumns() == 0 || _geoInfo->getNumRows() == 0 || _geoInfo->getNumSlices() == 0) { throw core::InvalidDoseException("Empty mask!") ; } return true; } void ITKImageMaskAccessor::updateMask() { return; } ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector() { updateMask(); _relevantVoxelVector = getRelevantVoxelVector(0); return _relevantVoxelVector; } - ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector(float lowerThreshold) + ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector( + float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); - int size = _geoInfo->getNumColumns()*_geoInfo->getNumRows()*_geoInfo->getNumSlices(); + int size = _geoInfo->getNumColumns() * _geoInfo->getNumRows() * _geoInfo->getNumSlices(); filteredVoxelVectorPointer->reserve(size); - for(int gridIndex =0 ; gridIndex < size; gridIndex++){ + + for (int gridIndex = 0 ; gridIndex < size; gridIndex++) + { core::MaskVoxel currentVoxel = core::MaskVoxel(gridIndex); - if(getMaskAt(gridIndex, currentVoxel)){ - if(currentVoxel.getRelevantVolumeFraction() > lowerThreshold){ + + if (getMaskAt(gridIndex, currentVoxel)) + { + if (currentVoxel.getRelevantVolumeFraction() > lowerThreshold) + { filteredVoxelVectorPointer->push_back(currentVoxel); } } } return filteredVoxelVectorPointer; } bool ITKImageMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { VoxelGridIndex3D aVoxelGridIndex; if (_geoInfo->convert(aID, aVoxelGridIndex)) { return getMaskAt(aVoxelGridIndex, voxel); } else { return false; } } bool ITKImageMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { voxel.setRelevantVolumeFraction(0); if (_geoInfo->validIndex(aIndex)) { const ITKMaskImageType::IndexType pixelIndex = {{aIndex[0], aIndex[1], aIndex[2]}}; double value = _mask->GetPixel(pixelIndex); VoxelGridID gridId; _geoInfo->convert(aIndex, gridId); - if(value >= 0 && value <=1 ){ + + if (value >= 0 && value <= 1) + { voxel.setRelevantVolumeFraction(value); } - else{ - std::cerr << "The pixel value of the mask should be >=0 and <=1!"<=0 and <=1!" << std::endl; return false; } } else { return false; } } const core::GeometricInfo& ITKImageMaskAccessor::getGeometricInfo() const { return *_geoInfo; }; } } } diff --git a/code/io/itk/rttbITKImageMaskAccessorConverter.cpp b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp index 8b51abf..1400def 100644 --- a/code/io/itk/rttbITKImageMaskAccessorConverter.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp @@ -1,129 +1,129 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "rttbITKImageMaskAccessorConverter.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "itkImageRegionIterator.h" #include "rttbITKImageMaskAccessor.h" namespace rttb { namespace io { namespace itk { ITKImageMaskAccessorConverter::ITKImageMaskAccessorConverter(MaskAccessorPointer accessor) { setMaskAccessor(accessor); } bool ITKImageMaskAccessorConverter::process() { //Transfer GeometricInfo to ITK Properties core::GeometricInfo geoInfo = _maskAccessor->getGeometricInfo(); ITKImageMaskAccessor::ITKMaskImageType::RegionType region; - + ITKImageMaskAccessor::ITKMaskImageType::IndexType start = {{0, 0, 0}}; ITKImageMaskAccessor::ITKMaskImageType::SizeType size = {{geoInfo.getNumColumns(), geoInfo.getNumRows(), geoInfo.getNumSlices()}}; ITKImageMaskAccessor::ITKMaskImageType::SpacingType spacing; for (unsigned int i = 0; i < 3; ++i) { spacing[i] = geoInfo.getSpacing()[i]; } ITKImageMaskAccessor::ITKMaskImageType::PointType origin; for (unsigned int i = 0; i < 3; ++i) { origin[i] = geoInfo.getImagePositionPatient()[i]; } ITKImageMaskAccessor::ITKMaskImageType::DirectionType direction; OrientationMatrix OM = geoInfo.getOrientationMatrix(); for (int col = 0; col < 3; ++col) { for (int row = 0; row < 3; ++row) { direction(col, row) = OM(col, row); } } //Create image, assign properties region.SetSize(size); region.SetIndex(start); _itkImage = ITKImageMaskAccessor::ITKMaskImageType::New(); _itkImage->SetRegions(region); _itkImage->SetSpacing(spacing); _itkImage->SetDirection(direction); _itkImage->SetOrigin(origin); _itkImage->Allocate(); ::itk::ImageRegionIterator imageIterator(_itkImage, region); VoxelGridID id = 0; //Transfer Mask values to itk image //Large advantage: rttbVoxelGridId ordering is the same as itk ordering while (!imageIterator.IsAtEnd()) { VoxelGridIndex3D aIndex; if (_maskAccessor->getGeometricInfo().validID(id)) { - rttb::core::MaskVoxel maskVoxel = core::MaskVoxel(id);; + rttb::core::MaskVoxel maskVoxel = core::MaskVoxel(id);; _maskAccessor->getMaskAt(id, maskVoxel); // Set the current pixel imageIterator.Set(maskVoxel.getRelevantVolumeFraction()); } else { if (failsOnInvalidIDs()) { throw core::InvalidDoseException("invalid Mask id!"); return false; } else { imageIterator.Set(_invalidDoseValue); } } ++imageIterator; ++id; } return true; } - + }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageMaskAccessorConverter.h b/code/io/itk/rttbITKImageMaskAccessorConverter.h index 9ae6495..1dbb86c 100644 --- a/code/io/itk/rttbITKImageMaskAccessorConverter.h +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.h @@ -1,68 +1,68 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #define __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorProcessorBase.h" #include "../itk/rttbDoseAccessorConversionSettingInterface.h" namespace rttb { namespace io { namespace itk { - + /*! @class ITKImageMaskAccessorConverter @brief Class converts/dumps the processed accessor into an itk image @remark MaskAccessorConversionInterface defines how the converter should react on non valid Mask values. */ class ITKImageMaskAccessorConverter: public core::MaskAccessorProcessorBase, public rttb::core::DoseAccessorConversionSettingInterface - + { public: typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; bool process(); - const ITKImageMaskAccessor::ITKMaskImageType::Pointer getITKImage() + const ITKImageMaskAccessor::ITKMaskImageType::Pointer getITKImage() { return _itkImage; } ITKImageMaskAccessorConverter(MaskAccessorPointer accessor); virtual ~ITKImageMaskAccessorConverter() {}; private: ITKImageMaskAccessorConverter(const ITKImageMaskAccessorConverter&); //not implemented on purpose -> non-copyable ITKImageMaskAccessorConverter& operator=(const ITKImageMaskAccessorConverter&);//not implemented on purpose -> non-copyable ITKImageMaskAccessor::ITKMaskImageType::Pointer _itkImage; }; } } } #endif diff --git a/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp index 53d7445..0d2adb3 100644 --- a/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp @@ -1,51 +1,59 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbITKImageMaskAccessorGenerator.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" -namespace rttb{ - namespace io{ - namespace itk{ - ITKImageMaskAccessorGenerator::ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage){ - if (aMaskImage == NULL){ +namespace rttb +{ + namespace io + { + namespace itk + { + ITKImageMaskAccessorGenerator::ITKImageMaskAccessorGenerator(const + ITKImageMaskAccessor::ITKMaskImageType* aMaskImage) + { + if (aMaskImage == NULL) + { throw core::InvalidDoseException("MaskImage is NULL"); } _maskPtr = aMaskImage; } - core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageMaskAccessorGenerator::generateMaskAccessor(){ + core::MaskAccessorGeneratorBase::MaskAccessorPointer + ITKImageMaskAccessorGenerator::generateMaskAccessor() + { _maskAccessor = boost::make_shared(_maskPtr); return _maskAccessor; } - + }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbITKImageMaskAccessorGenerator.h b/code/io/itk/rttbITKImageMaskAccessorGenerator.h index 51e95e3..9736e85 100644 --- a/code/io/itk/rttbITKImageMaskAccessorGenerator.h +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.h @@ -1,67 +1,67 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #include "rttbBaseType.h" #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorGeneratorBase.h" #include "itkImage.h" namespace rttb { namespace io { namespace itk { - + class ITKImageMaskAccessorGenerator: public core::MaskAccessorGeneratorBase { public: typedef MaskAccessorGeneratorBase::MaskAccessorPointer MaskAccessorPointer; private: /** @brief The Mask as itkImage */ ITKImageMaskAccessor::ITKMaskImageType::ConstPointer _maskPtr; ITKImageMaskAccessorGenerator(); public: virtual ~ITKImageMaskAccessorGenerator() {}; /*! @pre aMaskImage must point to a valid instance. @exception InvalidDoseException Thrown if aMaskImage is invalid. */ ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage); /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. */ MaskAccessorPointer generateMaskAccessor() ; }; } } } #endif diff --git a/code/io/itk/rttbImageWriter.cpp b/code/io/itk/rttbImageWriter.cpp index 1794f96..ff449fb 100644 --- a/code/io/itk/rttbImageWriter.cpp +++ b/code/io/itk/rttbImageWriter.cpp @@ -1,55 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbImageWriter.h" #include "rttbITKException.h" namespace rttb { namespace io { - namespace itk { + namespace itk + { ImageWriter::ImageWriter(FileNameString aFileName, ITKImageTypePointer aITKImage) - :_fileName(aFileName), _itkImage(aITKImage){ + : _fileName(aFileName), _itkImage(aITKImage) + { } - bool ImageWriter::writeFile(){ + bool ImageWriter::writeFile() + { WriterType::Pointer writer = WriterType::New(); writer->SetFileName(_fileName); writer->SetInput(_itkImage); - try{ + + try + { writer->Update(); } - catch( ::itk::ExceptionObject & excp ) + catch (::itk::ExceptionObject& excp) { std::cerr << "Error: ITK Exception caught " << excp << std::endl; throw rttb::io::itk::ITKException("ITK Exception in writing image: writer->Update()!"); return false; } return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/itk/rttbImageWriter.h b/code/io/itk/rttbImageWriter.h index 5034601..5658eeb 100644 --- a/code/io/itk/rttbImageWriter.h +++ b/code/io/itk/rttbImageWriter.h @@ -1,70 +1,71 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __RTTB_IMAGE_WRITER_H #define __RTTB_IMAGE_WRITER_H #include "itkImage.h" #include "itkImageSource.h" #include "itkImageFileWriter.h" #include "rttbBaseType.h" #include "rttbITKImageMaskAccessor.h" namespace rttb { namespace io { - namespace itk { + namespace itk + { /** @class ImageWriter * @brief Helper class writing 3D images to file ... * */ class ImageWriter { typedef ::itk::Image ITKMaskImageType; typedef ITKMaskImageType::Pointer ITKImageTypePointer; typedef ::itk::ImageFileWriter WriterType; private: FileNameString _fileName; ITKImageTypePointer _itkImage; public: ImageWriter(FileNameString aFileName, ITKImageTypePointer aITKImage); /*! @brief Write itk image to file @return Return true if successful. @exception InvalidParameterException thrown if itk exception by writing the image */ bool writeFile(); }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/other/rttbDVHTxtFileReader.h b/code/io/other/rttbDVHTxtFileReader.h index 9f605c8..28f2e65 100644 --- a/code/io/other/rttbDVHTxtFileReader.h +++ b/code/io/other/rttbDVHTxtFileReader.h @@ -1,69 +1,72 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_TXT_FILE_READER_H #define __DVH_TXT_FILE_READER_H #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHGeneratorInterface.h" -namespace rttb{ - namespace io{ - namespace other{ +namespace rttb +{ + namespace io + { + namespace other + { /*! @class DVHTxtFileReader @brief Reads DVH data from txt files. */ class DVHTxtFileReader: public core::DVHGeneratorInterface { - private: + private: FileNameString _fileName; bool _resetFile; /*! @brief Create new DVH object using the info from dvh txt file @exception InvalidParameterException Thrown if _fileName invalid */ void createDVH(); - public: + public: /*! @brief Constructor. */ DVHTxtFileReader(FileNameString aFileName); ~DVHTxtFileReader(); - /*! @brief Change file name. + /*! @brief Change file name. */ void resetFileName(FileNameString aFileName); /*! @brief Generate DVH, createDVH() will be called - @return Return new shared pointer of DVH. + @return Return new shared pointer of DVH. @exception InvalidParameterException Thrown if _fileName invalid */ DVHPointer generateDVH(); }; } } } #endif diff --git a/code/io/other/rttbDVHTxtFileWriter.cpp b/code/io/other/rttbDVHTxtFileWriter.cpp index 299d59b..ac6f8cd 100644 --- a/code/io/other/rttbDVHTxtFileWriter.cpp +++ b/code/io/other/rttbDVHTxtFileWriter.cpp @@ -1,115 +1,128 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbDVHTxtFileWriter.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbException.h" -namespace rttb{ - namespace io{ - namespace other{ +namespace rttb +{ + namespace io + { + namespace other + { - DVHTxtFileWriter::DVHTxtFileWriter(FileNameString aFileName, DVHType aDVHType){ - this->setFileName(aFileName); - this->setDVHType(aDVHType); + DVHTxtFileWriter::DVHTxtFileWriter(FileNameString aFileName, DVHType aDVHType) + { + this->setFileName(aFileName); + this->setDVHType(aDVHType); } - void DVHTxtFileWriter::setDVHType(DVHType aDVHType){ - _dvhType=aDVHType; + void DVHTxtFileWriter::setDVHType(DVHType aDVHType) + { + _dvhType = aDVHType; } - FileNameString DVHTxtFileWriter::getFileName() const{ - return _fileName; + FileNameString DVHTxtFileWriter::getFileName() const + { + return _fileName; } - void DVHTxtFileWriter::setFileName(FileNameString aFileName){ - _fileName=aFileName; + void DVHTxtFileWriter::setFileName(FileNameString aFileName) + { + _fileName = aFileName; } - DVHType DVHTxtFileWriter::getDVHType() const{ - return _dvhType; + DVHType DVHTxtFileWriter::getDVHType() const + { + return _dvhType; } - void DVHTxtFileWriter::writeDVH(DVHPointer aDvh) { - if(!aDvh) + void DVHTxtFileWriter::writeDVH(DVHPointer aDvh) + { + if (!aDvh) { throw core::NullPointerException("aDvh must not be NULL! "); } - std::ofstream out_dvh_ofstream(this->_fileName.c_str(),std::ios::out); - if (!out_dvh_ofstream.is_open() || !out_dvh_ofstream.good()) + std::ofstream out_dvh_ofstream(this->_fileName.c_str(), std::ios::out); + + if (!out_dvh_ofstream.is_open() || !out_dvh_ofstream.good()) { throw core::InvalidParameterException("Invalid dvh file name: could not open write file"); } - else{ - //setting string stream precission explicitly is mandatory to guarantee that tests - //run sucessfully on different systems! - out_dvh_ofstream.precision(10); + else + { + //setting string stream precission explicitly is mandatory to guarantee that tests + //run sucessfully on different systems! + out_dvh_ofstream.precision(10); - if(_dvhType.Type != DVHType::Differential && _dvhType.Type != DVHType::Cumulative) + if (_dvhType.Type != DVHType::Differential && _dvhType.Type != DVHType::Cumulative) { throw core::InvalidParameterException("DVH Type not acceptable: Only: DIFFERENTIAL/CUMULATIVE!"); } - if(_dvhType.Type == DVHType::Differential) + if (_dvhType.Type == DVHType::Differential) { out_dvh_ofstream << "DVH Type: DIFFERENTIAL\n"; } - else if(_dvhType.Type == DVHType::Cumulative) + else if (_dvhType.Type == DVHType::Cumulative) { out_dvh_ofstream << "DVH Type: CUMULATIVE\n"; } - out_dvh_ofstream << "DeltaD: "<getDeltaD() << "\n"; - out_dvh_ofstream << "DeltaV: "<getDeltaV() << "\n"; - out_dvh_ofstream << "StructureID: "<getStructureID()<< "\n"; - out_dvh_ofstream << "DoseID: "<getDoseID()<< "\n"; - out_dvh_ofstream << "DVH Data: "<< "\n"; + out_dvh_ofstream << "DeltaD: " << aDvh->getDeltaD() << "\n"; + out_dvh_ofstream << "DeltaV: " << aDvh->getDeltaV() << "\n"; + out_dvh_ofstream << "StructureID: " << aDvh->getStructureID() << "\n"; + out_dvh_ofstream << "DoseID: " << aDvh->getDoseID() << "\n"; + out_dvh_ofstream << "DVH Data: " << "\n"; - if(_dvhType.Type == DVHType::Differential) + if (_dvhType.Type == DVHType::Differential) { - DataDifferentialType dataDifferential=aDvh->getDataDifferential(); - int numberOfBins=dataDifferential.size(); - for(int i=0; igetDataDifferential(); + int numberOfBins = dataDifferential.size(); + + for (int i = 0; i < numberOfBins; i++) + { + out_dvh_ofstream << i << "," << dataDifferential[i] << "\n"; } } - else if(_dvhType.Type == DVHType::Cumulative) + else if (_dvhType.Type == DVHType::Cumulative) { - DataDifferentialType dataCumulative=aDvh->calcCumulativeDVH(); - int numberOfBins=dataCumulative.size(); - for(int i=0; icalcCumulativeDVH(); + int numberOfBins = dataCumulative.size(); + + for (int i = 0; i < numberOfBins; i++) { - out_dvh_ofstream << i << "," << dataCumulative[i] <<"\n"; + out_dvh_ofstream << i << "," << dataCumulative[i] << "\n"; } } - - } + } } } + } } \ No newline at end of file diff --git a/code/io/other/rttbDVHTxtFileWriter.h b/code/io/other/rttbDVHTxtFileWriter.h index d065a51..c0b1152 100644 --- a/code/io/other/rttbDVHTxtFileWriter.h +++ b/code/io/other/rttbDVHTxtFileWriter.h @@ -1,69 +1,72 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_TXT_FILE_WRITER_H #define __DVH_TXT_FILE_WRITER_H #include "rttbDVH.h" #include "../rttbDVHWriterInterface.h" #include "rttbBaseType.h" -namespace rttb{ - namespace io{ - namespace other{ +namespace rttb +{ + namespace io + { + namespace other + { /*! @class DVHTxtFileWriter @brief Writes DVHs to simple text files. */ class DVHTxtFileWriter: public DVHWriterInterface { public: typedef core::DVH::DataDifferentialType DataDifferentialType; typedef core::DVH::DVHPointer DVHPointer; - private: + private: FileNameString _fileName; DVHType _dvhType; - public: + public: /*! @brief Constructor @param aFileName a .txt file name to write the DVH to aDVHType: DIFFERENTIAL or CUMULATIVE. */ DVHTxtFileWriter(FileNameString aFileName, DVHType aDVHType); void setFileName(FileNameString aFileName); FileNameString getFileName() const; void setDVHType(DVHType aDVHType); DVHType getDVHType() const; /*! @brief Write aDvh to txt file with the name: _fileName @exception NullPointerException Thrown if _aDvh is NULL - @exception InvalidParameterException Thrown if _fileName invalid: could not open; - or if _dvhType invalid: only DIFFERENTIAL or CUMULATIVE is accepted! + @exception InvalidParameterException Thrown if _fileName invalid: could not open; + or if _dvhType invalid: only DIFFERENTIAL or CUMULATIVE is accepted! @exception Exception thrown if dvh init error */ void writeDVH(DVHPointer aDvh); }; } } } #endif diff --git a/code/io/other/rttbDVHXMLFileReader.h b/code/io/other/rttbDVHXMLFileReader.h index a675bd0..2d21d70 100644 --- a/code/io/other/rttbDVHXMLFileReader.h +++ b/code/io/other/rttbDVHXMLFileReader.h @@ -1,67 +1,70 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_XML_FILE_READER_H #define __DVH_XML_FILE_READER_H #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHGeneratorInterface.h" -namespace rttb{ - namespace io{ - namespace other{ +namespace rttb +{ + namespace io + { + namespace other + { /*! @class DVHXMLFileReader @brief Reads DVH data from xml files. */ class DVHXMLFileReader: public core::DVHGeneratorInterface { - private: + private: FileNameString _fileName; bool _resetFile; /*! @brief Create new DVH object using the info from dvh txt file @exception InvalidParameterException Thrown if _fileName invalid */ void createDVH(); - public: - /*! @brief Constructor. + public: + /*! @brief Constructor. */ DVHXMLFileReader(FileNameString aFileName); ~DVHXMLFileReader(); - /*! @brief Change file name. + /*! @brief Change file name. */ void resetFileName(FileNameString aFileName); - /*! @brief Generate DVH, createDVH() will be called - @return Return new shared pointer of DVH. + /*! @brief Generate DVH, createDVH() will be called + @return Return new shared pointer of DVH. @exception InvalidParameterException Thrown if _fileName invalid */ DVHPointer generateDVH(); }; } } } #endif diff --git a/code/io/other/rttbDVHXMLFileWriter.h b/code/io/other/rttbDVHXMLFileWriter.h index d06d707..a9ba5bb 100644 --- a/code/io/other/rttbDVHXMLFileWriter.h +++ b/code/io/other/rttbDVHXMLFileWriter.h @@ -1,69 +1,72 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_XML_FILE_WRITER_H #define __DVH_XML_FILE_WRITER_H #include "rttbDVH.h" #include "../rttbDVHWriterInterface.h" #include "rttbBaseType.h" -namespace rttb{ - namespace io{ - namespace other{ +namespace rttb +{ + namespace io + { + namespace other + { /*! @class DVHXMLFileWriter @brief Writes DVHs to xml files. */ class DVHXMLFileWriter: public DVHWriterInterface { public: typedef core::DVH::DataDifferentialType DataDifferentialType; typedef core::DVH::DVHPointer DVHPointer; - private: + private: FileNameString _fileName; DVHType _dvhType; - public: + public: /*! @brief Constructor @param aFileName a xml file name to write the DVH to aDVHType: DIFFERENTIAL or CUMULATIVE. */ DVHXMLFileWriter(FileNameString aFileName, DVHType aDVHType); void setFileName(FileNameString aFileName); FileNameString getFileName() const; void setDVHType(DVHType aDVHType); DVHType getDVHType() const; /*! @brief Write aDvh to xml file with the name: _fileName @exception NullPointerException Thrown if _aDvh is NULL - @exception InvalidParameterException Thrown if _fileName invalid: could not open; - or if _dvhType invalid: only DIFFERENTIAL or CUMULATIVE is accepted! + @exception InvalidParameterException Thrown if _fileName invalid: could not open; + or if _dvhType invalid: only DIFFERENTIAL or CUMULATIVE is accepted! @exception Exception thrown if dvh init error */ void writeDVH(DVHPointer aDvh); }; } } } #endif diff --git a/code/io/other/rttbDoseStatisticsXMLWriter.cpp b/code/io/other/rttbDoseStatisticsXMLWriter.cpp index 7fee2c7..c3693b9 100644 --- a/code/io/other/rttbDoseStatisticsXMLWriter.cpp +++ b/code/io/other/rttbDoseStatisticsXMLWriter.cpp @@ -1,271 +1,279 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbDoseStatisticsXMLWriter.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace io { namespace other { static const std::string xmlattrXTag = ".x"; static const std::string xmlattrNameTag = ".name"; static const std::string statisticsTag = "statistics.results"; static const std::string propertyTag = "property"; static const std::string columnSeparator = "@"; boost::property_tree::ptree writeDoseStatistics(DoseStatisticsPtr aDoseStatistics) { using boost::property_tree::ptree; ptree pt; - ptree numberOfVoxelsNode = createNodeWithNameAttribute(aDoseStatistics->getNumberOfVoxels(), "numberOfVoxels"); + ptree numberOfVoxelsNode = createNodeWithNameAttribute(aDoseStatistics->getNumberOfVoxels(), + "numberOfVoxels"); pt.add_child(statisticsTag + "." + propertyTag, numberOfVoxelsNode); ptree volumeNode = createNodeWithNameAttribute(aDoseStatistics->getVolume(), "volume"); pt.add_child(statisticsTag + "." + propertyTag, volumeNode); ptree minimumNode = createNodeWithNameAttribute(aDoseStatistics->getMinimum(), "minimum"); auto minimumPositions = aDoseStatistics->getMinimumPositions(); std::vector >::iterator pairItMin = minimumPositions->begin(); int count = 0; for (; pairItMin != minimumPositions->end() && count < 100; ++pairItMin) //output max. 100 minimum { VoxelGridID voxelID = pairItMin->second; ptree voxelMinPositions; voxelMinPositions.add("voxelGridID", voxelID); minimumNode.add_child("voxel", voxelMinPositions); count++; } pt.add_child(statisticsTag + "." + propertyTag, minimumNode); ptree maximumNode = createNodeWithNameAttribute(aDoseStatistics->getMaximum(), "maximum"); auto maximumPositions = aDoseStatistics->getMaximumPositions(); std::vector >::iterator pairItMax = maximumPositions->begin(); count = 0; for (; pairItMax != maximumPositions->end() && count < 100; ++pairItMax) //output max. 100 maximum { VoxelGridID voxelID = pairItMax->second; ptree voxelMaxPositions; voxelMaxPositions.add("voxelGridID", voxelID); maximumNode.add_child("voxel", voxelMaxPositions); count++; } pt.add_child(statisticsTag + "." + propertyTag, maximumNode); ptree meanNode = createNodeWithNameAttribute(aDoseStatistics->getMean(), "mean"); pt.add_child(statisticsTag + "." + propertyTag, meanNode); ptree sdNode = createNodeWithNameAttribute(aDoseStatistics->getStdDeviation(), "standardDeviation"); pt.add_child(statisticsTag + "." + propertyTag, sdNode); ptree varianceNode = createNodeWithNameAttribute(aDoseStatistics->getVariance(), "variance"); pt.add_child(statisticsTag + "." + propertyTag, varianceNode); double absoluteVolume = aDoseStatistics->getVolume(); double referenceDose = aDoseStatistics->getReferenceDose(); rttb::algorithms::DoseStatistics::DoseToVolumeFunctionType AllVx = aDoseStatistics->getAllVx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllDx = aDoseStatistics->getAllDx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMOHx = aDoseStatistics->getAllMOHx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMOCx = aDoseStatistics->getAllMOCx(); - rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMaxOHx = aDoseStatistics->getAllMaxOHx(); - rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMinOCx = aDoseStatistics->getAllMinOCx(); + rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMaxOHx = + aDoseStatistics->getAllMaxOHx(); + rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMinOCx = + aDoseStatistics->getAllMinOCx(); rttb::algorithms::DoseStatistics::DoseToVolumeFunctionType::iterator vxIt; rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType::iterator it; for (it = AllDx.begin(); it != AllDx.end(); it++) { ptree DxNode = createNodeWithNameAndXAttribute((*it).second, "Dx", - static_cast((*it).first / absoluteVolume * 100)); + static_cast((*it).first / absoluteVolume * 100)); pt.add_child(statisticsTag + "." + propertyTag, DxNode); } for (vxIt = AllVx.begin(); vxIt != AllVx.end(); vxIt++) { ptree VxNode = createNodeWithNameAndXAttribute((*vxIt).second, "Vx", - static_cast((*vxIt).first / referenceDose * 100)); + static_cast((*vxIt).first / referenceDose * 100)); pt.add_child(statisticsTag + "." + propertyTag, VxNode); } for (it = AllMOHx.begin(); it != AllMOHx.end(); it++) { ptree mohxNode = createNodeWithNameAndXAttribute((*it).second, "MOHx", - static_cast((*it).first / absoluteVolume * 100)); + static_cast((*it).first / absoluteVolume * 100)); pt.add_child(statisticsTag + "." + propertyTag, mohxNode); } for (it = AllMOCx.begin(); it != AllMOCx.end(); it++) { ptree mocxNode = createNodeWithNameAndXAttribute((*it).second, "MOCx", - static_cast((*it).first / absoluteVolume * 100)); + static_cast((*it).first / absoluteVolume * 100)); pt.add_child(statisticsTag + "." + propertyTag, mocxNode); } for (it = AllMaxOHx.begin(); it != AllMaxOHx.end(); it++) { ptree maxOhxNode = createNodeWithNameAndXAttribute((*it).second, "MaxOHx", - static_cast((*it).first / absoluteVolume * 100)); + static_cast((*it).first / absoluteVolume * 100)); pt.add_child(statisticsTag + "." + propertyTag, maxOhxNode); } for (it = AllMinOCx.begin(); it != AllMinOCx.end(); it++) { ptree minOCxNode = createNodeWithNameAndXAttribute((*it).second, "MinOCx", - static_cast((*it).first / absoluteVolume * 100)); + static_cast((*it).first / absoluteVolume * 100)); pt.add_child(statisticsTag + "." + propertyTag, minOCxNode); } return pt; } void writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName) { boost::property_tree::ptree pt = writeDoseStatistics(aDoseStatistics); try { boost::property_tree::xml_parser::write_xml(aFileName, pt, std::locale(), - boost::property_tree::xml_writer_make_settings('\t', 1)); + boost::property_tree::xml_writer_make_settings('\t', 1)); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw core::InvalidParameterException("Write xml failed: xml_parser_error!"); } } XMLString writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics) { boost::property_tree::ptree pt = writeDoseStatistics(aDoseStatistics); std::stringstream sstr; try { - boost::property_tree::xml_parser::write_xml(sstr, pt, boost::property_tree::xml_writer_make_settings('\t', - 1)); + boost::property_tree::xml_parser::write_xml(sstr, pt, + boost::property_tree::xml_writer_make_settings('\t', + 1)); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw core::InvalidParameterException("Write xml to string failed: xml_parser_error!"); } return sstr.str(); } StatisticsString writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics) { std::stringstream sstr; sstr << aDoseStatistics->getVolume() * 1000 << columnSeparator; // cm3 to mm3 sstr << aDoseStatistics->getMaximum() << columnSeparator; sstr << aDoseStatistics->getMinimum() << columnSeparator; sstr << aDoseStatistics->getMean() << columnSeparator; sstr << aDoseStatistics->getStdDeviation() << columnSeparator; sstr << aDoseStatistics->getVariance() << columnSeparator; double absoluteVolume = aDoseStatistics->getVolume(); rttb::algorithms::DoseStatistics::DoseToVolumeFunctionType AllVx = aDoseStatistics->getAllVx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllDx = aDoseStatistics->getAllDx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMOHx = aDoseStatistics->getAllMOHx(); rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMOCx = aDoseStatistics->getAllMOCx(); - rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMaxOHx = aDoseStatistics->getAllMaxOHx(); - rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMinOCx = aDoseStatistics->getAllMinOCx(); + rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMaxOHx = + aDoseStatistics->getAllMaxOHx(); + rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType AllMinOCx = + aDoseStatistics->getAllMinOCx(); rttb::algorithms::DoseStatistics::DoseToVolumeFunctionType::iterator vxIt; rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType::iterator it; for (it = AllDx.begin(); it != AllDx.end(); it++) { sstr << (*it).second << columnSeparator; } for (vxIt = AllVx.begin(); vxIt != AllVx.end(); vxIt++) { // *1000 because of conversion cm3 to mm3 sstr << (*vxIt).second * 1000 << columnSeparator; } for (it = AllMOHx.begin(); it != AllMOHx.end(); it++) { sstr << (*it).second << columnSeparator; } for (it = AllMOCx.begin(); it != AllMOCx.end(); it++) { sstr << (*it).second << columnSeparator; } for (it = AllMaxOHx.begin(); it != AllMaxOHx.end(); it++) { sstr << (*it).second << columnSeparator; } for (it = AllMinOCx.begin(); it != AllMinOCx.end(); it++) { sstr << (*it).second << columnSeparator; } return sstr.str(); } - boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, const std::string& attributeName) + boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, + const std::string& attributeName) { boost::property_tree::ptree node; node.put("", doseValue); node.put(xmlattrNameTag, attributeName); return node; } - boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, const std::string& attributeName, - int xValue) + boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, + const std::string& attributeName, + int xValue) { boost::property_tree::ptree node; node.put("", doseValue); node.put(xmlattrNameTag, attributeName); node.put(xmlattrXTag, xValue); return node; } }//end namespace other }//end namespace io }//end namespace rttb \ No newline at end of file diff --git a/code/io/other/rttbDoseStatisticsXMLWriter.h b/code/io/other/rttbDoseStatisticsXMLWriter.h index 02a0c99..f97c1b3 100644 --- a/code/io/other/rttbDoseStatisticsXMLWriter.h +++ b/code/io/other/rttbDoseStatisticsXMLWriter.h @@ -1,97 +1,99 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_STATISTICS_XML_WRITER_H #define __DOSE_STATISTICS_XML_WRITER_H #include "rttbDoseStatistics.h" #include "rttbBaseType.h" /*boost includes*/ #include #include #include #include namespace rttb { namespace io { namespace other { typedef boost::shared_ptr DoseStatisticsPtr; typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; /*! @brief Write statistics to boost::property_tree::ptree. @param aReferenceDose A reference dose for the calculation of Vx @param aDoseStatistics DoseStatistics to write @pre aReferenceDose must >0 @exception InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error */ boost::property_tree::ptree writeDoseStatistics(DoseStatisticsPtr aDoseStatistics); /*! @brief Write statistics to String. @param aReferenceDose A reference dose for the calculation of Vx @param aDoseStatistics DoseStatistics to write @pre aReferenceDose must >0 @exception InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error */ XMLString writerDoseStatisticsToString(DoseStatisticsPtr aDoseStatistics); /*! @brief Write statistics to xml file, including numberOfVoxels, volume, minimum, maximum, mean, standard deviation, variance, D2,D5,D10,D90,D95,D98, V2,V5,V10,V90,V95,V98, MOH2,MOH5,MOH10, MOC2,MOC5,MOC10, MaxOH2,MaxOH5,MaxOH10, MinOC2,MinOC5,MinOC10. @param aReferenceDose A reference dose for the calculation of Vx @param aDoseStatistics DoseStatistics to write @param aFileName To write dose statistics @pre aReferenceDose must >0 @exception InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error */ void writeDoseStatistics(DoseStatisticsPtr aDoseStatistics, FileNameString aFileName); - boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, const std::string& attributeName); - boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, const std::string& attributeName, + boost::property_tree::ptree createNodeWithNameAttribute(DoseTypeGy doseValue, + const std::string& attributeName); + boost::property_tree::ptree createNodeWithNameAndXAttribute(DoseTypeGy doseValue, + const std::string& attributeName, int xValue); /*! @brief Write statistics to String to generate a table: "Volume mm3@Max@Min@Mean@Std.Dev.@Variance@D2@D5@D10@D90@D95@D98@V2@V5@V10@V90@V95@V98@MOH2@MOH5@MOH10@MOC2@MOC5@MOC10@MaxOH2@MaxOH5@MaxOH10@MinOC2@MinOC5@MinOC10" @param aReferenceDose A reference dose for the calculation of Vx @param aDoseStatistics DoseStatistics to write @pre aReferenceDose must >0 @exception InvalidParameterException Thrown if aReferenceDose<=0 or xml_parse_error @note is used for the Mevislab-Linking of RTTB */ StatisticsString writerDoseStatisticsToTableString(DoseStatisticsPtr aDoseStatistics); } } } #endif diff --git a/code/io/rttbDVHWriterInterface.h b/code/io/rttbDVHWriterInterface.h index ca5e455..a29530d 100644 --- a/code/io/rttbDVHWriterInterface.h +++ b/code/io/rttbDVHWriterInterface.h @@ -1,43 +1,46 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DVH_WRITER_INTERFACE_H #define __DVH_WRITER_INTERFACE_H #include "rttbDVH.h" -namespace rttb{ - namespace io{ +namespace rttb +{ + namespace io + { /*! @class DVHWriterInterface @brief Interface for classes that write DVH data to files. */ class DVHWriterInterface { typedef core::DVH::DVHPointer DVHPointer; /*! @brief Write aDvh */ - public: virtual void writeDVH(DVHPointer aDvh) = 0; + public: + virtual void writeDVH(DVHPointer aDvh) = 0; }; } } #endif diff --git a/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.cpp b/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.cpp index c803c14..031c1d1 100644 --- a/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.cpp +++ b/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.cpp @@ -1,73 +1,76 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "rttbVirtuosCubeinfoDoseAccessorGenerator.h" #include "rttbVirtuosDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbIndexOutOfBoundsException.h" //VIRTUOS #include "pln1file.h" #include "plt_type.h" #include "rtp_type.h" namespace rttb { namespace io { namespace virtuos { VirtuosCubeinfoDoseAccessorGenerator::~VirtuosCubeinfoDoseAccessorGenerator() {} - VirtuosCubeinfoDoseAccessorGenerator::VirtuosCubeinfoDoseAccessorGenerator(Cubeinfo* aPointerOnVirtuosCube, - DoseTypeGy normalizationDose, DoseTypeGy prescribedDose): + VirtuosCubeinfoDoseAccessorGenerator::VirtuosCubeinfoDoseAccessorGenerator( + Cubeinfo* aPointerOnVirtuosCube, + DoseTypeGy normalizationDose, DoseTypeGy prescribedDose): _pPointerOnVirtuosCube(new Cubeinfo*) { //initialize cube pointer *_pPointerOnVirtuosCube = create_cubeinfo(0); *_pPointerOnVirtuosCube = aPointerOnVirtuosCube; _normalizationDose = normalizationDose; _prescribedDose = prescribedDose; } - VirtuosCubeinfoDoseAccessorGenerator::DoseAccessorPointer VirtuosCubeinfoDoseAccessorGenerator::generateDoseAccessor() + VirtuosCubeinfoDoseAccessorGenerator::DoseAccessorPointer + VirtuosCubeinfoDoseAccessorGenerator::generateDoseAccessor() { - _doseAccessor = boost::make_shared(*_pPointerOnVirtuosCube, false, _normalizationDose, + _doseAccessor = boost::make_shared(*_pPointerOnVirtuosCube, false, + _normalizationDose, _prescribedDose); return _doseAccessor; } } } } diff --git a/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.h b/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.h index 7e9145f..b1ab379 100644 --- a/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.h +++ b/code/io/virtuos/rttbVirtuosCubeinfoDoseAccessorGenerator.h @@ -1,81 +1,82 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __VIRTUOS_CUBEINFO_DOSE_ACCESSOR_GENERATOR_H #define __VIRTUOS_CUBEINFO_DOSE_ACCESSOR_GENERATOR_H #include #include #include #include "rttbDoseAccessorGeneratorBase.h" #include "rttbDoseAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "ncfile.h" namespace rttb { namespace io { namespace virtuos { /*! @class VirtuosCubeinfoDoseAccessorGenerator @brief Generate DoseAccessor with Virtuos Cubeinfo */ class VirtuosCubeinfoDoseAccessorGenerator: public core::DoseAccessorGeneratorBase { public: typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; private: Cubeinfo** _pPointerOnVirtuosCube; DoseTypeGy _normalizationDose; DoseTypeGy _prescribedDose; VirtuosCubeinfoDoseAccessorGenerator(); protected: public: ~VirtuosCubeinfoDoseAccessorGenerator(); /*! @brief Constructor. Initialisation with a Cubeinfo*. @param normalizationDose is defined as (prescribedDose*1000)/maxDoseInGy. Default is 1 Gy. @param prescribedDose the does that was planned in the reference point in Gy. Default is 1 Gy. */ - VirtuosCubeinfoDoseAccessorGenerator(Cubeinfo* aPointerOnVirtuosCube, DoseTypeGy normalizationDose = 1, + VirtuosCubeinfoDoseAccessorGenerator(Cubeinfo* aPointerOnVirtuosCube, + DoseTypeGy normalizationDose = 1, DoseTypeGy prescribedDose = 1); /*! @brief Generate DoseAccessor @return Return shared pointer of DoseAccessor. */ DoseAccessorPointer generateDoseAccessor() ; }; } } } #endif diff --git a/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.cpp b/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.cpp index 30a65d8..6dcecd9 100644 --- a/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.cpp +++ b/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.cpp @@ -1,234 +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 #include #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbStructure.h" #include "rttbVirtuosFileStructureSetGenerator.h" namespace rttb { namespace io { namespace virtuos { VirtuosFileStructureSetGenerator::VirtuosFileStructureSetGenerator(FileNameType aVirtuosVDXFileName, FileNameType aVirtuosCTXFileName) : _pPointerOnVirtuosCube(new Cubeinfo*), _patient(NULL) { _VDXFileName = aVirtuosVDXFileName; _CTXFileName = aVirtuosCTXFileName; //check if file names are valid if (!boost::filesystem::exists(_VDXFileName)) { throw core::InvalidParameterException("invalid vdx file name"); } if (!boost::filesystem::exists(_CTXFileName)) { throw core::InvalidParameterException("invalid ctx file name"); } *_pPointerOnVirtuosCube = create_cubeinfo(0); this->initializeVirtuosCube(_CTXFileName); } VirtuosFileStructureSetGenerator::~VirtuosFileStructureSetGenerator() { if (this->_patient != NULL) { delete this->_patient; } closecube((*(this->_pPointerOnVirtuosCube))); nc_free_cubeinfo((*(this->_pPointerOnVirtuosCube))); delete this->_pPointerOnVirtuosCube; } void VirtuosFileStructureSetGenerator::importStructureSet(FileNameType aVirtuosVDXFileName, FileNameType aVirtuosCTXFileName) { //check file name if (aVirtuosCTXFileName.empty() || aVirtuosVDXFileName.empty()) { throw core::InvalidParameterException("Virtuos VDX/CTX file name must not be empty!"); } int vdxPosition = aVirtuosVDXFileName.find(".vdx"); if (vdxPosition == std::string::npos) { throw core::InvalidParameterException("Virtuos VDX file name must be *.vdx!"); } //get patientFileName, patientDataPath for Virtuos function std::string patientFileName, patientName, patientDataPath; - patientFileName.assign(aVirtuosVDXFileName, aVirtuosVDXFileName.find_last_of("/") + 1, aVirtuosVDXFileName.length()); + patientFileName.assign(aVirtuosVDXFileName, aVirtuosVDXFileName.find_last_of("/") + 1, + aVirtuosVDXFileName.length()); patientName.assign(patientFileName, 0, patientFileName.find_first_of(".")); patientDataPath.assign(aVirtuosVDXFileName, 0, aVirtuosVDXFileName.find_last_of("/") + 1); //Virtuos: voi create voi model - int errorcode = voi_create_voi_model_dirolab(patientName.c_str(), patientDataPath.c_str(), 0, this->_patient); + int errorcode = voi_create_voi_model_dirolab(patientName.c_str(), patientDataPath.c_str(), 0, + this->_patient); if (errorcode != 0) { //throw std::string ("Virtuos Routines unable to create VOI Model! "); std::cerr << "voi_create_voi_model_dirolab error: error code " << errorcode << std::endl; } //Virtuos: voi read vdx - errorcode = voi_read_vdx_version_2_for_DIROlab(patientFileName.c_str(), patientDataPath.c_str(), this->_patient); + errorcode = voi_read_vdx_version_2_for_DIROlab(patientFileName.c_str(), patientDataPath.c_str(), + this->_patient); if (errorcode != 0) { //throw std::string ("voi_read_vdx_version_2_for_DIROlab failed! "); std::cerr << "voi_read_vdx_version_2_for_DIROlab error: error code " << errorcode << std::endl; } int numberOfVois = this->_patient->getNumberOfVois(); float firstSliceInFrame = (*_pPointerOnVirtuosCube)->pos_list[0].position; double sliceThickness = (*_pPointerOnVirtuosCube)->slicedist; float lastSliceInFrame = ((*_pPointerOnVirtuosCube)->dimz - 1) * sliceThickness + firstSliceInFrame; for (int currentVoiNumber = 0; currentVoiNumber < numberOfVois; currentVoiNumber++) { std::string voiName = ""; char tmpVoiName[1024]; voi_get_voi_name_by_index_dirolab(currentVoiNumber, 1024, tmpVoiName, this->_patient); voiName.assign(tmpVoiName); /* prepare contour extraction */ D3PointList* contours = NULL; contours = d3_list_create(1000000); D3Point origin = {0, 0, 0}, y_axis_point = {0, 0, 0}, x_axis_point = {0, 0, 0}; int maxNumberOfContours = 100000; int* pNoOFContours = &maxNumberOfContours; PolygonSequenceType polygonSequence; for (float z = firstSliceInFrame; z <= lastSliceInFrame; z += sliceThickness) { origin.x = 0.0; origin.y = 0.0; origin.z = z ; x_axis_point.x = 1.0; x_axis_point.y = 0.0; x_axis_point.z = z ; y_axis_point.x = 0.0; y_axis_point.y = 1.0; y_axis_point.z = z; *pNoOFContours = 100000; //<-- reason is the next function call - voi_get_CT_contours_dirolab(voiName.c_str(), origin, x_axis_point, y_axis_point, pNoOFContours, &contours, 1, + voi_get_CT_contours_dirolab(voiName.c_str(), origin, x_axis_point, y_axis_point, pNoOFContours, + &contours, 1, this->_patient); for (int i = 0; i < *pNoOFContours; i++) { PolygonType polygon; - for (int j = 0; j < contours[i].used - 1; j++) //Virtuos polygon the last point is the same as the first point + for (int j = 0; j < contours[i].used - 1; + j++) //Virtuos polygon the last point is the same as the first point { WorldCoordinate3D point; point(0) = contours[i].points[j].x; point(1) = contours[i].points[j].y; point(2) = contours[i].points[j].z; polygon.push_back(point); }//end for j polygonSequence.push_back(polygon); }//end for i }//end for z boost::shared_ptr spStruct = boost::make_shared(polygonSequence); spStruct->setLabel(voiName); _strVector.push_back(spStruct); }//end for currentVoiNumber } void VirtuosFileStructureSetGenerator::initializeVirtuosCube(FileNameType aVirtuosCTXFileName) { if (aVirtuosCTXFileName.empty()) { throw core::InvalidParameterException("Empty File Name"); } int gzPosition = aVirtuosCTXFileName.find(".gz"); if (gzPosition != std::string::npos) { aVirtuosCTXFileName.erase(gzPosition, aVirtuosCTXFileName.length()); } nc_init_cubeinfo(*_pPointerOnVirtuosCube); int opencubeErrorCode = opencube(aVirtuosCTXFileName.c_str() , *_pPointerOnVirtuosCube); if (opencubeErrorCode != 0) { std::stringstream opencubeErrorCodeAsStringStream; opencubeErrorCodeAsStringStream << opencubeErrorCode; - throw core::InvalidParameterException(std::string(std::string("VirtuosIO::openCube returned error Code: ") + - opencubeErrorCodeAsStringStream.str())); + throw core::InvalidParameterException(std::string( + std::string("VirtuosIO::openCube returned error Code: ") + + opencubeErrorCodeAsStringStream.str())); } if ((*_pPointerOnVirtuosCube)->dimx == 0 || (*_pPointerOnVirtuosCube)->dimy == 0 || (*_pPointerOnVirtuosCube)->dimz == 0) { throw core::InvalidParameterException("Invalid Cube dimension: dimX/dimY/dimZ must not be zero! "); } } - VirtuosFileStructureSetGenerator::StructureSetPointer VirtuosFileStructureSetGenerator::generateStructureSet() + VirtuosFileStructureSetGenerator::StructureSetPointer + VirtuosFileStructureSetGenerator::generateStructureSet() { this->importStructureSet(_VDXFileName, _CTXFileName); return boost::make_shared(_strVector); } }//end namespace virtuos }//end namespace io }//end namespace rttb diff --git a/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.h b/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.h index 961bc20..9a7618e 100644 --- a/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.h +++ b/code/io/virtuos/rttbVirtuosFileStructureSetGenerator.h @@ -1,105 +1,109 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ /* Changes in Architecture: The DICOM specific classes will be removed and transfered to the corresponding IO classes. This class should only provide general structure functionality. */ #ifndef __VIRTUOS_FILE_STRUCTURE_SET_GENERATOR_H #define __VIRTUOS_FILE_STRUCTURE_SET_GENERATOR_H #include #include #include // Virtuos includes #include "ncfile.h" #include "voi_man.hxx" #include "rttbBaseType.h" #include "rttbStrVectorStructureSetGenerator.h" #include "rttbStructure.h" -namespace rttb{ - namespace io{ - namespace virtuos{ +namespace rttb +{ + namespace io + { + namespace virtuos + { /*! @class VirtuosFileStructureSetGenerator @brief Genereate a structure set from a corresponding Virtuos data. */ class VirtuosFileStructureSetGenerator: public core::StrVectorStructureSetGenerator { public: typedef core::StructureSet::StructTypePointer StructTypePointer; typedef StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; private: // Pointer to Virtuos image data cube - Cubeinfo **_pPointerOnVirtuosCube; + Cubeinfo** _pPointerOnVirtuosCube; //Virtuos Patient Pointer - VoiModel *_patient; + VoiModel* _patient; IDType _UID; FileNameType _VDXFileName; FileNameType _CTXFileName; /*! open virtuos ctx cube - @throw InvalidParameterException if ctx cube could not be opened or dose dimensions are invalid + @throw InvalidParameterException if ctx cube could not be opened or dose dimensions are invalid */ void initializeVirtuosCube(FileNameType aVirtuosCTXFileName); /*! import virtuos vdx contours from file @throw InvalidParameterException if one of the file names is empty. @throw InvalidParameterException if aVirtuosVDXFileName, does not end with '.vdx'. */ void importStructureSet(FileNameType aVirtuosVDXFileName, FileNameType aVirtuosCTXFileName); public: - /*! @brief Constructor + /*! @brief Constructor @param aVirtuosVDXFileName a Virtuos structure set .vdx file name @param aVirtuosCTXFileName a Virtuos CT .ctx file name - + */ - VirtuosFileStructureSetGenerator(FileNameType aVirtuosVDXFileName, FileNameType aVirtuosCTXFileName); + VirtuosFileStructureSetGenerator(FileNameType aVirtuosVDXFileName, + FileNameType aVirtuosCTXFileName); - /*! @brief Destructor + /*! @brief Destructor Free Virtuos Cubeinfo. */ ~VirtuosFileStructureSetGenerator(); /*! @brief generate structure set @return return shared pointer of StructureSet @exception InvalidParameterException Thrown if loadFile and read failed @exception InvalidParameterException throw if structure data invalid. */ StructureSetPointer generateStructureSet(); }; } } } #endif diff --git a/code/masks/boost/rttbBoostMask.cpp b/code/masks/boost/rttbBoostMask.cpp index daa529b..a9b44a5 100644 --- a/code/masks/boost/rttbBoostMask.cpp +++ b/code/masks/boost/rttbBoostMask.cpp @@ -1,390 +1,490 @@ #include #include #include #include #include #include #include #include #include "rttbBoostMask.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace masks { namespace boost { - BoostMask::BoostMask(BoostMask::GeometricInfoPointer aDoseGeoInfo, BoostMask::StructPointer aStructure, bool strict) - :_geometricInfo(aDoseGeoInfo), _structure(aStructure), _strict(strict), _voxelInStructure(::boost::make_shared()){ + BoostMask::BoostMask(BoostMask::GeometricInfoPointer aDoseGeoInfo, + BoostMask::StructPointer aStructure, bool strict) + : _geometricInfo(aDoseGeoInfo), _structure(aStructure), _strict(strict), + _voxelInStructure(::boost::make_shared()) + { _isUpToDate = false; - if (!_geometricInfo){ + + if (!_geometricInfo) + { throw rttb::core::NullPointerException("Error: Geometric info is NULL!"); } - else if (!_structure){ + else if (!_structure) + { throw rttb::core::NullPointerException("Error: Structure is NULL!"); } } - void BoostMask::calcMask(){ - if (hasSelfIntersections()){ - if (_strict){ + void BoostMask::calcMask() + { + if (hasSelfIntersections()) + { + if (_strict) + { throw rttb::core::InvalidParameterException("Error: structure has self intersections!"); } - else{ - std::cerr << _structure->getLabel() << " has self intersections! It may cause errors in the voxelization results!" << std::endl; + else + { + std::cerr << _structure->getLabel() << + " has self intersections! It may cause errors in the voxelization results!" << std::endl; } } - std::vector intersectionSlicePolygonsVector;//store the polygons of intersection slice of each index z + std::vector + intersectionSlicePolygonsVector;//store the polygons of intersection slice of each index z //For each dose slice, get intersection structure slice and the contours on the structure slice - for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++){ + for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++) + { BoostMask::BoostPolygonVector boostPolygons = getIntersectionSlicePolygons(indexZ); BoostMask::BoostPolygonVector::iterator it; - for (it = boostPolygons.begin(); it != boostPolygons.end(); ++it){ + + for (it = boostPolygons.begin(); it != boostPolygons.end(); ++it) + { ::boost::geometry::correct(*it); } + intersectionSlicePolygonsVector.push_back(boostPolygons); } /* Use simple nearest neighbour interpolation (NNI) if dose and structure has different z spacing: If dose slice (indexZ) has no intersection with structure slice, but the last and the next do, that means the dose slice lies between two structure slices -> use the last slice intersection contours for this slice */ - for (unsigned int indexZ = 1; indexZ < _geometricInfo->getNumSlices() - 1; indexZ++){ - if (intersectionSlicePolygonsVector.at(indexZ).size() == 0 && intersectionSlicePolygonsVector.at(indexZ - 1).size() > 0 - && intersectionSlicePolygonsVector.at(indexZ + 1).size() > 0) + for (unsigned int indexZ = 1; indexZ < _geometricInfo->getNumSlices() - 1; indexZ++) + { + if (intersectionSlicePolygonsVector.at(indexZ).size() == 0 + && intersectionSlicePolygonsVector.at(indexZ - 1).size() > 0 + && intersectionSlicePolygonsVector.at(indexZ + 1).size() > 0) + { intersectionSlicePolygonsVector.at(indexZ) = intersectionSlicePolygonsVector.at(indexZ - 1); + } } - for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++){ - BoostMask::BoostPolygonVector intersectionSlicePolygons = intersectionSlicePolygonsVector.at(indexZ); + for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++) + { + BoostMask::BoostPolygonVector intersectionSlicePolygons = intersectionSlicePolygonsVector.at( + indexZ); //Get bounding box of this dose slice VoxelIndexVector voxelList = getBoundingBox(indexZ, intersectionSlicePolygons); rttb::VoxelGridIndex3D gridIndex3D0 = voxelList.at(0); rttb::VoxelGridIndex3D gridIndex3D1 = voxelList.at(1); - for (unsigned int indexX = gridIndex3D0[0]; indexX <= gridIndex3D1[0]; indexX++){ - for (unsigned int indexY = gridIndex3D0[1]; indexY <= gridIndex3D1[1]; indexY++){ + for (unsigned int indexX = gridIndex3D0[0]; indexX <= gridIndex3D1[0]; indexX++) + { + for (unsigned int indexY = gridIndex3D0[1]; indexY <= gridIndex3D1[1]; indexY++) + { rttb::VoxelGridIndex3D currentIndex; currentIndex[0] = indexX; currentIndex[1] = indexY; currentIndex[2] = indexZ; rttb::VoxelGridID gridID; _geometricInfo->convert(currentIndex, gridID); //Get intersection polygons of the dose voxel and the structure BoostPolygonDeque polygons = getIntersections(currentIndex, intersectionSlicePolygons); //Calc areas of all intersection polygons double intersectionArea = calcArea(polygons); double voxelSize = _geometricInfo->getSpacing()[0] * _geometricInfo->getSpacing()[1]; - if (intersectionArea > 0) { + if (intersectionArea > 0) + { double volumeFraction = intersectionArea / voxelSize; - if (volumeFraction > 1 && (volumeFraction - 1) <= 0.0001){ + + if (volumeFraction > 1 && (volumeFraction - 1) <= 0.0001) + { volumeFraction = 1; } + core::MaskVoxel maskVoxel = core::MaskVoxel(gridID, (volumeFraction)); _voxelInStructure->push_back(maskVoxel);//push back the mask voxel in structure } } } } sort(_voxelInStructure->begin(), _voxelInStructure->end()); } - bool BoostMask::hasSelfIntersections(){ + bool BoostMask::hasSelfIntersections() + { bool hasSelfIntersection = false; - for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++){ + for (unsigned int indexZ = 0; indexZ < _geometricInfo->getNumSlices(); indexZ++) + { rttb::VoxelGridIndex3D currentIndex(0, 0, indexZ); BoostMask::BoostPolygonVector boostPolygons = getIntersectionSlicePolygons(currentIndex[2]); BoostMask::BoostPolygonVector::iterator it; BoostMask::BoostPolygonVector::iterator it2; - for (it = boostPolygons.begin(); it != boostPolygons.end(); ++it){ + + for (it = boostPolygons.begin(); it != boostPolygons.end(); ++it) + { ::boost::geometry::correct(*it); + //test if polygon has self intersection - if (::boost::geometry::detail::overlay::has_self_intersections(*it, false)){ + if (::boost::geometry::detail::overlay::has_self_intersections(*it, false)) + { hasSelfIntersection = true; - std::cerr << _structure->getLabel() << " has self intersection polygon! Slice: " << indexZ << ". " << std::endl; + std::cerr << _structure->getLabel() << " has self intersection polygon! Slice: " << indexZ << ". " + << std::endl; break; } //test if the polygons on the same slice has intersection - for (it2 = boostPolygons.begin(); it2 != boostPolygons.end() && it2 != it; ++it2){ + for (it2 = boostPolygons.begin(); it2 != boostPolygons.end() && it2 != it; ++it2) + { ::boost::geometry::correct(*it2); BoostPolygonDeque intersection; ::boost::geometry::intersection(*it, *it2, intersection); - if (intersection.size() > 0){ + + if (intersection.size() > 0) + { //if no donut if (!(::boost::geometry::within(*it, *it2)) && !(::boost::geometry::within(*it2, *it))) { hasSelfIntersection = true; - std::cerr << _structure->getLabel() << ": Two polygons on the same slice has intersection! Slice: " << indexZ << "." << std::endl; + std::cerr << _structure->getLabel() << ": Two polygons on the same slice has intersection! Slice: " + << indexZ << "." << std::endl; break; } } } } } return hasSelfIntersection; } /*Get the 4 voxel index of the bounding box of the polygon in the slice with sliceNumber*/ - BoostMask::VoxelIndexVector BoostMask::getBoundingBox(unsigned int sliceNumber, const BoostPolygonVector& intersectionSlicePolygons){ - if (sliceNumber < 0 || sliceNumber >= _geometricInfo->getNumSlices()){ + BoostMask::VoxelIndexVector BoostMask::getBoundingBox(unsigned int sliceNumber, + const BoostPolygonVector& intersectionSlicePolygons) + { + if (sliceNumber < 0 || sliceNumber >= _geometricInfo->getNumSlices()) + { throw rttb::core::InvalidParameterException(std::string("Error: slice number is invalid!")); } rttb::VoxelGridIndex3D currentIndex(0, 0, sliceNumber); double xMin = 0; double yMin = 0; double xMax = 0; double yMax = 0; BoostPolygonVector::const_iterator it; - for (it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it){ + + for (it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it) + { ::boost::geometry::model::box box; ::boost::geometry::envelope(*it, box); BoostPoint2D minPoint = box.min_corner(); BoostPoint2D maxPoint = box.max_corner(); - if (it == intersectionSlicePolygons.begin()){ + + if (it == intersectionSlicePolygons.begin()) + { xMin = minPoint.x(); yMin = minPoint.y(); xMax = maxPoint.x(); yMax = maxPoint.y(); } + xMin = std::min(xMin, minPoint.x()); yMin = std::min(yMin, minPoint.y()); xMax = std::max(xMax, maxPoint.x()); yMax = std::max(yMax, maxPoint.y()); } rttb::WorldCoordinate3D nullWorldCoord; _geometricInfo->indexToWorldCoordinate(VoxelGridIndex3D(0, 0, 0), nullWorldCoord); rttb::WorldCoordinate3D minWorldCoord(xMin, yMin, nullWorldCoord.z()); rttb::WorldCoordinate3D maxWorldCoord(xMax, yMax, nullWorldCoord.z()); rttb::VoxelGridIndex3D index0; rttb::VoxelGridIndex3D index1; _geometricInfo->worldCoordinateToIndex(minWorldCoord, index0); _geometricInfo->worldCoordinateToIndex(maxWorldCoord, index1); VoxelIndexVector voxelList; voxelList.push_back(index0); voxelList.push_back(index1); return voxelList; } /*Get intersection polygons of the contour and a voxel polygon*/ - BoostMask::BoostPolygonDeque BoostMask::getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D, const BoostPolygonVector& intersectionSlicePolygons){ + BoostMask::BoostPolygonDeque BoostMask::getIntersections(const rttb::VoxelGridIndex3D& + aVoxelIndex3D, const BoostPolygonVector& intersectionSlicePolygons) + { BoostMask::BoostPolygonDeque polygonDeque; BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); ::boost::geometry::correct(voxelPolygon); BoostPolygonVector::const_iterator it; - for (it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it){ + + for (it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it) + { BoostPolygon2D contour = *it; ::boost::geometry::correct(contour); BoostPolygonDeque intersection; ::boost::geometry::intersection(voxelPolygon, contour, intersection); polygonDeque.insert(polygonDeque.end(), intersection.begin(), intersection.end()); } return polygonDeque; } /*Calculate the intersection area*/ - double BoostMask::calcArea(const BoostPolygonDeque& aPolygonDeque){ + double BoostMask::calcArea(const BoostPolygonDeque& aPolygonDeque) + { double area = 0; BoostPolygonDeque::const_iterator it; - for (it = aPolygonDeque.begin(); it != aPolygonDeque.end(); ++it){ + + for (it = aPolygonDeque.begin(); it != aPolygonDeque.end(); ++it) + { area += ::boost::geometry::area(*it); } + return area; } - VoxelGridIndex3D BoostMask::getGridIndex3D(const core::MaskVoxel& aMaskVoxel){ + VoxelGridIndex3D BoostMask::getGridIndex3D(const core::MaskVoxel& aMaskVoxel) + { rttb::VoxelGridIndex3D gridIndex3D; _geometricInfo->convert(aMaskVoxel.getVoxelGridID(), gridIndex3D); return gridIndex3D; } - BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector(){ - if (!_isUpToDate){ + BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector() + { + if (!_isUpToDate) + { calcMask(); } + return _voxelInStructure; } - BoostMask::BoostRing2D BoostMask::convert(const rttb::PolygonType& aRTTBPolygon){ + BoostMask::BoostRing2D BoostMask::convert(const rttb::PolygonType& aRTTBPolygon) + { BoostMask::BoostRing2D polygon2D; BoostPoint2D firstPoint; - for (unsigned int i = 0; i < aRTTBPolygon.size(); i++){ + + for (unsigned int i = 0; i < aRTTBPolygon.size(); i++) + { rttb::WorldCoordinate3D rttbPoint = aRTTBPolygon.at(i); BoostPoint2D boostPoint(rttbPoint[0], rttbPoint[1]); - if (i == 0){ + + if (i == 0) + { firstPoint = boostPoint; } + ::boost::geometry::append(polygon2D, boostPoint); } + ::boost::geometry::append(polygon2D, firstPoint); return polygon2D; } - BoostMask::BoostPolygonVector BoostMask::getIntersectionSlicePolygons(const rttb::GridIndexType aVoxelGridIndexZ){ + BoostMask::BoostPolygonVector BoostMask::getIntersectionSlicePolygons( + const rttb::GridIndexType aVoxelGridIndexZ) + { BoostMask::BoostRingVector boostRingVector; rttb::PolygonSequenceType polygonSequence = _structure->getStructureVector(); //get the polygons in the slice and convert to boost rings rttb::PolygonSequenceType::iterator it; - for (it = polygonSequence.begin(); it != polygonSequence.end(); ++it){ + + for (it = polygonSequence.begin(); it != polygonSequence.end(); ++it) + { PolygonType rttbPolygon = *it; - if (!rttbPolygon.empty()){ + + if (!rttbPolygon.empty()) + { double polygonZCoor = rttbPolygon.at(0)[2]; rttb::WorldCoordinate3D polygonPoint(0, 0, polygonZCoor); rttb::VoxelGridIndex3D polygonPointIndex3D; _geometricInfo->worldCoordinateToIndex(polygonPoint, polygonPointIndex3D); //if the z - if (aVoxelGridIndexZ == polygonPointIndex3D[2]){ + if (aVoxelGridIndexZ == polygonPointIndex3D[2]) + { boostRingVector.push_back(convert(rttbPolygon)); } } } return checkDonutAndConvert(boostRingVector); } - BoostMask::BoostRing2D BoostMask::get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D){ + BoostMask::BoostRing2D BoostMask::get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D) + { BoostMask::BoostRing2D polygon; rttb::WorldCoordinate3D rttbPoint; _geometricInfo->indexToWorldCoordinate(aVoxelGrid3D, rttbPoint); BoostPoint2D point1(rttbPoint[0], rttbPoint[1]); ::boost::geometry::append(polygon, point1); double xSpacing = _geometricInfo->getSpacing()[0]; double ySpacing = _geometricInfo->getSpacing()[1]; BoostPoint2D point2(rttbPoint[0] + xSpacing, rttbPoint[1]); ::boost::geometry::append(polygon, point2); BoostPoint2D point3(rttbPoint[0] + xSpacing, rttbPoint[1] + ySpacing); ::boost::geometry::append(polygon, point3); BoostPoint2D point4(rttbPoint[0], rttbPoint[1] + ySpacing); ::boost::geometry::append(polygon, point4); ::boost::geometry::append(polygon, point1); return polygon; } - BoostMask::BoostPolygonVector BoostMask::checkDonutAndConvert(const BoostMask::BoostRingVector& aRingVector){ + BoostMask::BoostPolygonVector BoostMask::checkDonutAndConvert(const BoostMask::BoostRingVector& + aRingVector) + { //check donut BoostMask::BoostRingVector::const_iterator it1; BoostMask::BoostRingVector::const_iterator it2; BoostMask::BoostPolygonVector boostPolygonVector; std::vector donutIndexVector;//store the outer and inner ring index BoostMask::BoostPolygonVector donutVector;//store new generated donut polygon //Get donut index and donut polygon unsigned int index1 = 0; - for (it1 = aRingVector.begin(); it1 != aRingVector.end(); it1++, index1++){ + + for (it1 = aRingVector.begin(); it1 != aRingVector.end(); it1++, index1++) + { bool it1IsDonut = false; + //check if the ring is already determined as a donut - for (unsigned int i = 0; i < donutIndexVector.size(); i++){ - if (donutIndexVector.at(i) == index1){ + for (unsigned int i = 0; i < donutIndexVector.size(); i++) + { + if (donutIndexVector.at(i) == index1) + { it1IsDonut = true; break; } } + //if not jet, check now - if (!it1IsDonut){ + if (!it1IsDonut) + { bool it2IsDonut = false; unsigned int index2 = 0; - for (it2 = aRingVector.begin(); it2 != aRingVector.end(); it2++, index2++){ - if (it2 != it1){ + + for (it2 = aRingVector.begin(); it2 != aRingVector.end(); it2++, index2++) + { + if (it2 != it1) + { BoostMask::BoostPolygon2D polygon2D; - if (::boost::geometry::within(*it1, *it2)){ + + if (::boost::geometry::within(*it1, *it2)) + { ::boost::geometry::append(polygon2D, *it2);//append an outer ring to the polygon ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring ::boost::geometry::append(polygon2D, *it1, 0);//append a ring to the interior ring it2IsDonut = true; } //if donut - else if (::boost::geometry::within(*it2, *it1)){ + else if (::boost::geometry::within(*it2, *it1)) + { ::boost::geometry::append(polygon2D, *it1);//append an outer ring to the polygon ::boost::geometry::interior_rings(polygon2D).resize(1);//create an interior ring ::boost::geometry::append(polygon2D, *it2, 0);//append a ring to the interior ring it2IsDonut = true; } - if (it2IsDonut){ + + if (it2IsDonut) + { donutIndexVector.push_back(index1); donutIndexVector.push_back(index2); donutVector.push_back(polygon2D);//store donut polygon break;//Only store the first donut! } } } } } //Store no donut polygon to boostPolygonVector index1 = 0; - for (it1 = aRingVector.begin(); it1 != aRingVector.end(); it1++, index1++){ + + for (it1 = aRingVector.begin(); it1 != aRingVector.end(); it1++, index1++) + { bool it1IsDonut = false; + //check if the ring is the outer or inner of a donut - for (unsigned int i = 0; i < donutIndexVector.size(); i++){ - if (donutIndexVector.at(i) == index1){ + for (unsigned int i = 0; i < donutIndexVector.size(); i++) + { + if (donutIndexVector.at(i) == index1) + { it1IsDonut = true; break; } } - if (!it1IsDonut){ + + if (!it1IsDonut) + { BoostMask::BoostPolygon2D polygon2D; ::boost::geometry::append(polygon2D, *it1); boostPolygonVector.push_back(polygon2D);//insert the ring, which is not a part of donut } } //Append donut polygon to boostPolygonVector BoostMask::BoostPolygonVector::iterator itDonut; - for (itDonut = donutVector.begin(); itDonut != donutVector.end(); itDonut++){ + + for (itDonut = donutVector.begin(); itDonut != donutVector.end(); itDonut++) + { boostPolygonVector.push_back(*itDonut);//append donuts } return boostPolygonVector; } } } } \ No newline at end of file diff --git a/code/masks/boost/rttbBoostMask.h b/code/masks/boost/rttbBoostMask.h index b7065a2..af2ced7 100644 --- a/code/masks/boost/rttbBoostMask.h +++ b/code/masks/boost/rttbBoostMask.h @@ -1,153 +1,156 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __BOOST_MASK_H #define __BOOST_MASK_H #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbGeometricInfo.h" #include "rttbMaskVoxel.h" #include "rttbMaskAccessorInterface.h" #include #include #include #include #include namespace rttb { namespace masks { namespace boost { /*! @class BoostMask - * @brief Implementation of voxelization using boost::geometry. + * @brief Implementation of voxelization using boost::geometry. * @attention If "strict" is set to true, an exception will be thrown when the given structure has self intersection. * (A structure without self interseciton means all contours of the structure have no self intersection, and - * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) - * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored - * and the mask will be calculated, however, it may cause errors in the mask results. + * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) + * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored + * and the mask will be calculated, however, it may cause errors in the mask results. */ class BoostMask { public: typedef ::boost::shared_ptr GeometricInfoPointer; typedef core::Structure::StructTypePointer StructPointer; typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; /*! @brief Constructor * @exception rttb::core::NullPointerException thrown if aDoseGeoInfo or aStructure is NULL * @param strict indicates whether to allow self intersection in the structure. If it is set to true, an exception will be thrown when the given structure has self intersection. * @exception InvalidParameterException thrown if strict is true and the structure has self intersections */ BoostMask(GeometricInfoPointer aDoseGeoInfo, StructPointer aStructure, bool strict = true); /*! @brief Generate mask and return the voxels in the mask * @exception rttb::core::InvalidParameterException thrown if the structure has self intersections */ MaskVoxelListPointer getRelevantVoxelVector(); private: typedef ::boost::geometry::model::d2::point_xy BoostPoint2D; - typedef ::boost::geometry::model::polygon< ::boost::geometry::model::d2::point_xy > BoostPolygon2D; - typedef ::boost::geometry::model::ring< ::boost::geometry::model::d2::point_xy > BoostRing2D; + typedef ::boost::geometry::model::polygon< ::boost::geometry::model::d2::point_xy > + BoostPolygon2D; + typedef ::boost::geometry::model::ring< ::boost::geometry::model::d2::point_xy > + BoostRing2D; typedef std::deque BoostPolygonDeque; typedef std::vector BoostRingVector;//polygon without holes typedef std::vector BoostPolygonVector;//polygon with or without holes typedef std::vector VoxelIndexVector; GeometricInfoPointer _geometricInfo; StructPointer _structure; bool _strict; //vector of the MaskVoxel inside the structure MaskVoxelListPointer _voxelInStructure; /*! @brief If the mask is up to date */ bool _isUpToDate; /*! @brief Voxelization and generate mask */ void calcMask(); /*! @brief Check if the structure has self intersections*/ bool hasSelfIntersections(); /*! @brief Get the min/max voxel index of the bounding box of the polygon in the slice with sliceNumber * @param sliceNumber slice number between 0 and _geometricInfo->getNumSlices() * @param intersectionSlicePolygons Get the polygons intersecting the slice * @exception InvalidParameterException thrown if sliceNumber < 0 or sliceNumber >= _geometricInfo->getNumSlices() * @return Return the 4 voxel index of the bounding box */ - VoxelIndexVector getBoundingBox(unsigned int sliceNumber, const BoostPolygonVector& intersectionSlicePolygons); + VoxelIndexVector getBoundingBox(unsigned int sliceNumber, + const BoostPolygonVector& intersectionSlicePolygons); /*! @brief Get intersection polygons of the contour and a voxel polygon * @param aVoxelIndex3D The 3d grid index of the voxel * @param intersectionSlicePolygons The polygons of the slice intersecting the voxel * @return Return all intersetion polygons of the structure and the voxel */ BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D, - const BoostPolygonVector& intersectionSlicePolygons); + const BoostPolygonVector& intersectionSlicePolygons); /*! @brief Calculate the area of all polygons * @param aPolygonDeque The deque of polygons * @return Return the area of all polygons */ double calcArea(const BoostPolygonDeque& aPolygonDeque); /*! @brief Get grid index of a mask voxel * @param aMaskVoxel A mask voxel * @return Return the 3d grid index of the mask voxel */ VoxelGridIndex3D getGridIndex3D(const core::MaskVoxel& aMaskVoxel); /*! @brief Convert RTTB polygon to boost polygon*/ BoostRing2D convert(const rttb::PolygonType& aRTTBPolygon); /*! @brief Get the intersection slice of the voxel, return the polygons (with (donut) or without holes) in the slice * @param aVoxelGridIndexZ The z grid index (slice number) of the voxel * @return Return the structure polygons intersecting the slice */ BoostPolygonVector getIntersectionSlicePolygons(const rttb::GridIndexType aVoxelGridIndexZ); /*! @brief Get the voxel 2d contour polygon*/ BoostRing2D get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D); /*! @brief If 2 rings in the vector build a donut, convert the 2 rings to a donut polygon, other rings unchanged*/ BoostPolygonVector checkDonutAndConvert(const BoostRingVector& aRingVector); }; } } } #endif \ No newline at end of file diff --git a/code/masks/boost/rttbBoostMaskAccessor.cpp b/code/masks/boost/rttbBoostMaskAccessor.cpp index c02b583..9b30567 100644 --- a/code/masks/boost/rttbBoostMaskAccessor.cpp +++ b/code/masks/boost/rttbBoostMaskAccessor.cpp @@ -1,161 +1,163 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbBoostMaskAccessor.h" #include "rttbBoostMask.h" #include #include #include #include namespace rttb { namespace masks { namespace boost { - BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo, bool strict) + BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, + const core::GeometricInfo& aGeometricInfo, bool strict) : _spStructure(aStructurePointer), _geoInfo(aGeometricInfo), _strict(strict) { _spRelevantVoxelVector = MaskVoxelListPointer(); //generate new structure set uid ::boost::uuids::uuid id; ::boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "BoostMask_" + ss.str(); } BoostMaskAccessor::~BoostMaskAccessor() { }; void BoostMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; // already calculated } BoostMask mask(::boost::make_shared(_geoInfo), _spStructure, _strict); _spRelevantVoxelVector = mask.getRelevantVoxelVector(); return; } BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() { // if not already generated start voxelization here updateMask(); return _spRelevantVoxelVector; } - BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector(float lowerThreshold) + BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector( + float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); // filter relevant voxels BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } bool BoostMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } } // returns false if mask was not calculated without triggering calculation (otherwise not const!) else { return false; } return false; } bool BoostMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const { return _geoInfo; }; } } } \ No newline at end of file diff --git a/code/masks/boost/rttbBoostMaskAccessor.h b/code/masks/boost/rttbBoostMaskAccessor.h index 0fdf506..96f1f42 100644 --- a/code/masks/boost/rttbBoostMaskAccessor.h +++ b/code/masks/boost/rttbBoostMaskAccessor.h @@ -1,127 +1,128 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __BOOST_MASK_ACCESSOR__H #define __BOOST_MASK_ACCESSOR__H #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbMaskVoxel.h" #include "rttbMaskAccessorInterface.h" #include "rttbGenericDoseIterator.h" #include "rttbStructure.h" #include namespace rttb { namespace masks { namespace boost { /*! @class BoostMaskAccessor * @brief Using the voxelization based on boost::geometry and generate the mask accessor. * @attention If "strict" is set to true, an exception will be thrown when the given structure has self intersection. * (A structure without self interseciton means all contours of the structure have no self intersection, and - * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) - * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored - * and the mask will be calculated, however, it may cause errors in the mask results. + * the polygons on the same slice have no intersection between each other, unless the case of a donut. A donut is accepted.) + * If "strict" is set to false, debug information will be displayed when the given structure has self intersection. Self intersections will be ignored + * and the mask will be calculated, however, it may cause errors in the mask results. */ class BoostMaskAccessor: public core::MaskAccessorInterface { public: typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; typedef core::Structure::StructTypePointer StructTypePointer; private: core::GeometricInfo _geoInfo; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; StructTypePointer _spStructure; IDType _maskUID; bool _strict; public: /*! @brief Constructor with a structure pointer and a geometric info pointer * @param aStructurePointer smart pointer of the structure * @param aGeometricInfoPtr smart pointer of the geometricinfo of the dose * @param strict indicates whether to allow self intersection in the structure. If it is set to true, an exception will be thrown when the given structure has self intersection. * @exception InvalidParameterException thrown if strict is true and the structure has self intersections */ - BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo, bool strict = true); + BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo, + bool strict = true); /*! @brief destructor*/ ~BoostMaskAccessor(); /*! @brief voxelization of the given structures using boost algorithms*/ void updateMask(); /*! @brief get vector containing all relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(); /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); /*!@brief determine how a given voxel on the dose grid is masked * @param aID ID of the voxel in grid. * @param voxel Reference to the voxel. * @post after a valid call voxel containes the information of the specified grid voxel. If aID is not valid, voxel values are undefined. * The relevant volume fraction will be set to zero. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; /*!@brief determine how a given voxel on the dose grid is masked * @param aIndex 3d index of the voxel in grid. * @param voxel Reference to the voxel. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; /*! @brief give access to GeometricInfo*/ const core::GeometricInfo& getGeometricInfo() const; /* @ brief is true if dose is on a homogeneous grid * @remark Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change.*/ bool isGridHomogeneous() const { return true; }; IDType getMaskUID() const { return _maskUID; }; }; } } } #endif diff --git a/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp b/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp index 8b52e02..88deb33 100644 --- a/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp +++ b/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp @@ -1,84 +1,93 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "DoseIteratorInterface_LEGACY.h" using namespace std; #include #include #include #include #include -namespace rttb{ +namespace rttb +{ - namespace masks{ - namespace legacy{ + namespace masks + { + namespace legacy + { - IDType DoseIteratorInterface::getDoseUID(){ - boost::uuids::uuid id; - boost::uuids::random_generator generator; - id=generator(); + IDType DoseIteratorInterface::getDoseUID() + { + boost::uuids::uuid id; + boost::uuids::random_generator generator; + id = generator(); - std::stringstream ss; - ss << id; - - _doseUID=ss.str(); - return _doseUID; + std::stringstream ss; + ss << id; - } + _doseUID = ss.str(); + return _doseUID; - IDType DoseIteratorInterface::getPatientUID(){ - boost::uuids::uuid id; - boost::uuids::random_generator generator; - id=generator(); + } - std::stringstream ss; - ss << id; - - _patientUID=ss.str(); - return _patientUID; + IDType DoseIteratorInterface::getPatientUID() + { + boost::uuids::uuid id; + boost::uuids::random_generator generator; + id = generator(); - } + std::stringstream ss; + ss << id; + + _patientUID = ss.str(); + return _patientUID; + + } + + int DoseIteratorInterface::size() + { + this->start(); + int size = 0; + + while (this->hasNextVoxel()) + { + this->next(); + size++; + } - int DoseIteratorInterface::size(){ - this->start(); - int size=0; - while(this->hasNextVoxel()){ - this->next(); - size++; - } - return size; - } + return size; + } } } } diff --git a/code/masks/legacy/DoseIteratorInterface_LEGACY.h b/code/masks/legacy/DoseIteratorInterface_LEGACY.h index 17d9498..981aaf1 100644 --- a/code/masks/legacy/DoseIteratorInterface_LEGACY.h +++ b/code/masks/legacy/DoseIteratorInterface_LEGACY.h @@ -1,115 +1,117 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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_H #define __DOSE_ITERATOR_INTERFACE_H #include #include #include #include "DoseVoxel_LEGACY.h" #include "rttbPhysicalInfo.h" -namespace rttb{ +namespace rttb +{ - namespace masks - { - namespace legacy { - /*! @class DoseIteratorInterface - * @brief This class represents the dose iterator interface. - */ - class DoseIteratorInterface: public core::PhysicalInfo - { - protected: - /*! @brief Dose voxel index (x,y,z)*/ - VoxelGridIndex3D _doseIndex; + namespace masks + { + namespace legacy + { + /*! @class DoseIteratorInterface + * @brief This class represents the dose iterator interface. + */ + class DoseIteratorInterface: public core::PhysicalInfo + { + protected: + /*! @brief Dose voxel index (x,y,z)*/ + VoxelGridIndex3D _doseIndex; - /*! @brief Dose UID*/ - IDType _doseUID; + /*! @brief Dose UID*/ + IDType _doseUID; - /*! @brief Patient UID*/ - IDType _patientUID; + /*! @brief Patient UID*/ + IDType _patientUID; - /*! @brief Current DoseVoxel*/ - DoseVoxel _currentVoxel; + /*! @brief Current DoseVoxel*/ + DoseVoxel _currentVoxel; - /*! @brief Read dose and structure information - * It will be called in constructor or if dose or structure is resetted - */ - virtual bool begin() = 0; + /*! @brief Read dose and structure information + * It will be called in constructor or if dose or structure is resetted + */ + virtual bool begin() = 0; - public: - /*! @brief Set the position before the first index. It must be called before hasNextVoxel() and next()! - */ - virtual void start()=0; + public: + /*! @brief Set the position before the first index. It must be called before hasNextVoxel() and next()! + */ + virtual void start() = 0; - /*! @brief Test if next voxel exists - * @pre start() must be called before it is called! - */ - virtual bool hasNextVoxel() const = 0; + /*! @brief Test if next voxel exists + * @pre start() must be called before it is called! + */ + virtual bool hasNextVoxel() const = 0; - /*! @brief Return dose value (in Gy) of the next index. After next() is called, current index of this iterator is at the next index. - * @pre hasNextVoxel() must =true before it is called! - */ - virtual DoseTypeGy next() = 0; + /*! @brief Return dose value (in Gy) of the next index. After next() is called, current index of this iterator is at the next index. + * @pre hasNextVoxel() must =true before it is called! + */ + virtual DoseTypeGy next() = 0; - //RALF: man sollte zumindest so ein interface auch einbauen um einen viruellen Call zu sparen - //virtual bool next(DoseTypeGy& nextValue) = 0; + //RALF: man sollte zumindest so ein interface auch einbauen um einen viruellen Call zu sparen + //virtual bool next(DoseTypeGy& nextValue) = 0; - /*! @brief Return volume of one voxel (in cm3)*/ - virtual DoseVoxelVolumeType getDeltaV() const = 0; + /*! @brief Return volume of one voxel (in cm3)*/ + virtual DoseVoxelVolumeType getDeltaV() const = 0; - /*! @brief Return geometric information*/ - virtual core::GeometricInfo getGeometricInfo() const=0; + /*! @brief Return geometric information*/ + virtual core::GeometricInfo getGeometricInfo() const = 0; - /*! @brief If masked dose iterator, return the voxel proportion inside a given structure, value 0~1; Otherwise, 1*/ - virtual double getCurrentVoxelProportion() const=0; + /*! @brief If masked dose iterator, return the voxel proportion inside a given structure, value 0~1; Otherwise, 1*/ + virtual double getCurrentVoxelProportion() const = 0; - /*! @brief Get dose uid. If there exists uuid for the dose, you should rewrite the method; otherwise, a uid will be - * randomly generated using boost::uuid library. - */ - IDType getDoseUID(); + /*! @brief Get dose uid. If there exists uuid for the dose, you should rewrite the method; otherwise, a uid will be + * randomly generated using boost::uuid library. + */ + IDType getDoseUID(); - /*! @brief Get patient uid. If there exists patient uuid for the dose, you should rewrite the method; otherwise, a uid will be - * randomly generated using boost::uuid library. - */ - IDType getPatientUID(); + /*! @brief Get patient uid. If there exists patient uuid for the dose, you should rewrite the method; otherwise, a uid will be + * randomly generated using boost::uuid library. + */ + IDType getPatientUID(); - /*! @brief Return the current RTVoxel Object*/ - virtual const DoseVoxel& getCurrentRTVoxel()=0; + /*! @brief Return the current RTVoxel Object*/ + virtual const DoseVoxel& getCurrentRTVoxel() = 0; - /*! @brief Return the size of the dose iterator*/ - virtual int size(); + /*! @brief Return the size of the dose iterator*/ + virtual int size(); - }; - } - } + }; + } + } } #endif diff --git a/code/masks/legacy/DoseIterator_LEGACY.cpp b/code/masks/legacy/DoseIterator_LEGACY.cpp index e4532b5..71c3616 100644 --- a/code/masks/legacy/DoseIterator_LEGACY.cpp +++ b/code/masks/legacy/DoseIterator_LEGACY.cpp @@ -1,163 +1,184 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "DoseIterator_LEGACY.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" using namespace std; -namespace rttb{ - - namespace masks { -namespace legacy - - { - - - DoseIterator::~DoseIterator() - { - - } - - DoseIterator::DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, DRTDoseIOD* maskIOD): doseData (aGeoInfo.getNumberOfVoxels(), 0){ - this->count=-1; - - _dose = doseIOD; - _mask = maskIOD; - - setDoseInfo(aGeoInfo); - } - - void DoseIterator::start() { - this->count=-1; - } +namespace rttb +{ - bool DoseIterator::setDoseInfo(core::GeometricInfo& aGeoInfo){ - /* get Columns (0028,0011) of the dicom dose _dose*/ - column = aGeoInfo.getNumColumns(); + namespace masks + { + namespace legacy - /*! get Rows (0028,0010) of the dicom dose _dose*/ - row = aGeoInfo.getNumRows(); + { - /* get NumberOfFrames (0028,0008) of the dicom dose _dose*/ - numberOfFrames=aGeoInfo.getNumSlices(); - //std::cout << "numberOfFrames: "<< numberOfFrames << std::endl; - if(column==0 || row==0 || numberOfFrames==0){ - throw rttb::core::InvalidDoseException("Empty dicom dose!"); - } - /* get DoseGridScaling (3004,000e) of the dicom dose _dose*/ - OFString doseGridScalingStr; - this->_dose->getDoseGridScaling(doseGridScalingStr); - this->doseGridScaling=1; + DoseIterator::~DoseIterator() + { - imagePositionPatient = aGeoInfo.getImagePositionPatient(); - imageOrientationRow = aGeoInfo.getImageOrientationRow(); - imageOrientationColumn = aGeoInfo.getImageOrientationColumn(); + } - /* get PixelSpacing (0028,0030) of the dicom dose _dose*/ - pixelSpacingRow=aGeoInfo.getPixelSpacingRow(); - pixelSpacingColumn=aGeoInfo.getPixelSpacingColumn(); - - /* get SliceThickness (0018,0050) of the dicom dose _dose*/ - sliceThickness=aGeoInfo.getSliceThickness(); + DoseIterator::DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, + DRTDoseIOD* maskIOD): doseData(aGeoInfo.getNumberOfVoxels(), 0) + { + this->count = -1; - return true; + _dose = doseIOD; + _mask = maskIOD; - } + setDoseInfo(aGeoInfo); + } + + void DoseIterator::start() + { + this->count = -1; + } + + bool DoseIterator::setDoseInfo(core::GeometricInfo& aGeoInfo) + { + /* get Columns (0028,0011) of the dicom dose _dose*/ + column = aGeoInfo.getNumColumns(); + + /*! get Rows (0028,0010) of the dicom dose _dose*/ + row = aGeoInfo.getNumRows(); + + /* get NumberOfFrames (0028,0008) of the dicom dose _dose*/ + numberOfFrames = aGeoInfo.getNumSlices(); + + //std::cout << "numberOfFrames: "<< numberOfFrames << std::endl; + if (column == 0 || row == 0 || numberOfFrames == 0) + { + throw rttb::core::InvalidDoseException("Empty dicom dose!"); + } + + /* get DoseGridScaling (3004,000e) of the dicom dose _dose*/ + OFString doseGridScalingStr; + this->_dose->getDoseGridScaling(doseGridScalingStr); + this->doseGridScaling = 1; + + imagePositionPatient = aGeoInfo.getImagePositionPatient(); + imageOrientationRow = aGeoInfo.getImageOrientationRow(); + imageOrientationColumn = aGeoInfo.getImageOrientationColumn(); + + /* get PixelSpacing (0028,0030) of the dicom dose _dose*/ + pixelSpacingRow = aGeoInfo.getPixelSpacingRow(); + pixelSpacingColumn = aGeoInfo.getPixelSpacingColumn(); + + /* get SliceThickness (0018,0050) of the dicom dose _dose*/ + sliceThickness = aGeoInfo.getSliceThickness(); + + return true; + + } - - - DoseTypeGy DoseIterator::next(){ - - int size=this->pixelDataIndexInStructure.size(); - if(count<(size-1)){ - count++; - DoseTypeGy dose; - int i=pixelDataIndexInStructure[count]; - dose=doseData.at(i)*this->doseGridScaling; - - return dose; - } - else{ - throw core::IndexOutOfBoundsException("hasNextVoxel()==false!"); - - } - - } - - bool DoseIterator::hasNextVoxel() const{ - - int size=this->pixelDataIndexInStructure.size(); - if(count<(size-1)){ - return true; - } - else - return false; - - } - - DoseVoxelVolumeType DoseIterator::getDeltaV() const{ - return this->pixelSpacingColumn*this->pixelSpacingRow*this->sliceThickness/1000; - } - - core::GeometricInfo DoseIterator::getGeometricInfo() const{ - core::GeometricInfo ginfo; - ginfo.setNumColumns(this->column); - ginfo.setNumRows(this->row); - OrientationMatrix orientation(0); - orientation(0,0) = this->imageOrientationRow.x(); - orientation(1,0) = this->imageOrientationRow.y(); - orientation(2,0) = this->imageOrientationRow.z(); - orientation(0,1) = this->imageOrientationColumn.x(); - orientation(1,1) = this->imageOrientationColumn.y(); - orientation(2,1) = this->imageOrientationColumn.z(); - WorldCoordinate3D ortho = this->imageOrientationRow.cross(this->imageOrientationColumn); - orientation(0,2) = ortho.x(); - orientation(1,2) = ortho.y(); - orientation(2,2) = ortho.z(); - ginfo.setOrientationMatrix(orientation); - ginfo.setImagePositionPatient(this->imagePositionPatient); - ginfo.setNumSlices(this->numberOfFrames); - ginfo.setPixelSpacingColumn(this->pixelSpacingColumn); - ginfo.setPixelSpacingRow(this->pixelSpacingRow); - ginfo.setSliceThickness(this->sliceThickness); - return ginfo; - } - double DoseIterator::getCurrentVoxelProportion() const{ - return 1; - } - const DoseVoxel& DoseIterator::getCurrentRTVoxel(){ - return _currentVoxel; - } + DoseTypeGy DoseIterator::next() + { + int size = this->pixelDataIndexInStructure.size(); - } + if (count < (size - 1)) + { + count++; + DoseTypeGy dose; + int i = pixelDataIndexInStructure[count]; + dose = doseData.at(i) * this->doseGridScaling; + + return dose; + } + else + { + throw core::IndexOutOfBoundsException("hasNextVoxel()==false!"); + + } + + } + + bool DoseIterator::hasNextVoxel() const + { + + int size = this->pixelDataIndexInStructure.size(); + + if (count < (size - 1)) + { + return true; + } + else + { + return false; + } + + } + + DoseVoxelVolumeType DoseIterator::getDeltaV() const + { + return this->pixelSpacingColumn * this->pixelSpacingRow * this->sliceThickness / 1000; + } + + core::GeometricInfo DoseIterator::getGeometricInfo() const + { + core::GeometricInfo ginfo; + ginfo.setNumColumns(this->column); + ginfo.setNumRows(this->row); + OrientationMatrix orientation(0); + orientation(0, 0) = this->imageOrientationRow.x(); + orientation(1, 0) = this->imageOrientationRow.y(); + orientation(2, 0) = this->imageOrientationRow.z(); + orientation(0, 1) = this->imageOrientationColumn.x(); + orientation(1, 1) = this->imageOrientationColumn.y(); + orientation(2, 1) = this->imageOrientationColumn.z(); + WorldCoordinate3D ortho = this->imageOrientationRow.cross(this->imageOrientationColumn); + orientation(0, 2) = ortho.x(); + orientation(1, 2) = ortho.y(); + orientation(2, 2) = ortho.z(); + ginfo.setOrientationMatrix(orientation); + ginfo.setImagePositionPatient(this->imagePositionPatient); + ginfo.setNumSlices(this->numberOfFrames); + ginfo.setPixelSpacingColumn(this->pixelSpacingColumn); + ginfo.setPixelSpacingRow(this->pixelSpacingRow); + ginfo.setSliceThickness(this->sliceThickness); + return ginfo; + } + + double DoseIterator::getCurrentVoxelProportion() const + { + return 1; + } + + const DoseVoxel& DoseIterator::getCurrentRTVoxel() + { + return _currentVoxel; + } + + + } - } + } } diff --git a/code/masks/legacy/DoseIterator_LEGACY.h b/code/masks/legacy/DoseIterator_LEGACY.h index 82f976a..91f9a1a 100644 --- a/code/masks/legacy/DoseIterator_LEGACY.h +++ b/code/masks/legacy/DoseIterator_LEGACY.h @@ -1,156 +1,162 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DICOM_DOSE_ITERATOR_USE_MASK_H #define __DICOM_DOSE_ITERATOR_USE_MASK_H #include #include #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmrt/drtdose.h" #include "DoseIteratorInterface_LEGACY.h" #include "DoseVoxel_LEGACY.h" #include "rttbGeometricInfo.h" -namespace rttb{ - namespace masks{ -namespace legacy - { +namespace rttb +{ + namespace masks + { + namespace legacy + { - /*! @class DoseIterator - * @brief This class represents the iterator of the dose voxels in a DRTDoseIOD Object within the >0 region of a image mask - */ + /*! @class DoseIterator + * @brief This class represents the iterator of the dose voxels in a DRTDoseIOD Object within the >0 region of a image mask + */ - class DoseIterator: public DoseIteratorInterface - { + class DoseIterator: public DoseIteratorInterface + { - private: - /*! DICOM-RT dose pointer*/ - DRTDoseIOD* _dose; + private: + /*! DICOM-RT dose pointer*/ + DRTDoseIOD* _dose; - /*! DICOM-RT mask pointer. It must have the same image properties as _dose. The structure is masked with 1.*/ - DRTDoseIOD* _mask; + /*! DICOM-RT mask pointer. It must have the same image properties as _dose. The structure is masked with 1.*/ + DRTDoseIOD* _mask; - /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ - std::vector doseData; - /*! Columns (0028,0011) of the dicom dose _dose*/ - Uint16 column; - /*! Rows (0028,0010) of the dicom dose _dose*/ - Uint16 row; - /*! NumberOfFrames (0028,0008) of the dicom dose _dose*/ - Uint16 numberOfFrames; - /*! DoseGridScaling (3004,000e) of the dicom dose _dose*/ - double doseGridScaling; - /*! ImagePositionPatient (0020,0032) of the dicom dose _dose*/ - WorldCoordinate3D imagePositionPatient; - /*! ImageOrientationPatient (0020,0037) of the dicom dose _dose*/ - ImageOrientation imageOrientationRow; - ImageOrientation imageOrientationColumn; - /*! PixelSpacing (0028,0030) of the dicom dose _dose*/ - double pixelSpacingRow; - double pixelSpacingColumn; - /*! SliceThickness (0018,0050) of the dicom dose _dose*/ - double sliceThickness; + /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ + std::vector doseData; + /*! Columns (0028,0011) of the dicom dose _dose*/ + Uint16 column; + /*! Rows (0028,0010) of the dicom dose _dose*/ + Uint16 row; + /*! NumberOfFrames (0028,0008) of the dicom dose _dose*/ + Uint16 numberOfFrames; + /*! DoseGridScaling (3004,000e) of the dicom dose _dose*/ + double doseGridScaling; + /*! ImagePositionPatient (0020,0032) of the dicom dose _dose*/ + WorldCoordinate3D imagePositionPatient; + /*! ImageOrientationPatient (0020,0037) of the dicom dose _dose*/ + ImageOrientation imageOrientationRow; + ImageOrientation imageOrientationColumn; + /*! PixelSpacing (0028,0030) of the dicom dose _dose*/ + double pixelSpacingRow; + double pixelSpacingColumn; + /*! SliceThickness (0018,0050) of the dicom dose _dose*/ + double sliceThickness; - /*! The current position in pixelDataIndexInStructure*/ - int count; + /*! The current position in pixelDataIndexInStructure*/ + int count; - /*! The vector stores all indices with pixel data >0 in the mask*/ - std::vector pixelDataIndexInStructure; + /*! The vector stores all indices with pixel data >0 in the mask*/ + std::vector pixelDataIndexInStructure; - /*! @brief Get information from dose distribution:column, row, numberOfFramesdose, - * GridScaling, imageOrientation, pixelSpacing, getSliceThickness() and absolute dose value in each voxel - */ + /*! @brief Get information from dose distribution:column, row, numberOfFramesdose, + * GridScaling, imageOrientation, pixelSpacing, getSliceThickness() and absolute dose value in each voxel + */ - bool setDoseInfo(core::GeometricInfo& aGeoInfo); + bool setDoseInfo(core::GeometricInfo& aGeoInfo); - protected: + protected: - /*! @brief Traverse dose distribution, get the dose voxels in the structure: doseVoxelInStructure. - * It will be called in constructor or if structure is resetted. - * @exception RTTBNullPointerException Thrown if _dose or _structure is NULL - * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 - * @exception RTTBDcmrtException Throw if dcmrt error - */ - bool begin() { start(); return true;}; + /*! @brief Traverse dose distribution, get the dose voxels in the structure: doseVoxelInStructure. + * It will be called in constructor or if structure is resetted. + * @exception RTTBNullPointerException Thrown if _dose or _structure is NULL + * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 + * @exception RTTBDcmrtException Throw if dcmrt error + */ + bool begin() + { + start(); + return true; + }; - public: - /*! @brief Destructor*/ - virtual ~DoseIterator(); + public: + /*! @brief Destructor*/ + virtual ~DoseIterator(); - /*! @brief Standard constructor - * @exception RTTBNullPointerException Thrown if _dose or _mask is NULL - * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 - * @exception RTTBDcmrtException Throw if dcmrt error - */ - DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, DRTDoseIOD* maskIOD); + /*! @brief Standard constructor + * @exception RTTBNullPointerException Thrown if _dose or _mask is NULL + * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 + * @exception RTTBDcmrtException Throw if dcmrt error + */ + DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, DRTDoseIOD* maskIOD); - /*! @brief Set the position before the first index. - * It must be called before hasNextVoxel() and next()! - */ - void start(); + /*! @brief Set the position before the first index. + * It must be called before hasNextVoxel() and next()! + */ + void start(); - /*! @brief Test if next voxel existiert - * @pre start() must be called before it is called! - */ - bool hasNextVoxel() const; + /*! @brief Test if next voxel existiert + * @pre start() must be called before it is called! + */ + bool hasNextVoxel() const; - /*! @brief Return dose value (in Gy) of the next index - * @pre hasNextVoxel() must =true before it is called! - * @exception RTTBIndexOutOfBoundsException Thrown if hasNextVoxel()==false - */ - DoseTypeGy next(); + /*! @brief Return dose value (in Gy) of the next index + * @pre hasNextVoxel() must =true before it is called! + * @exception RTTBIndexOutOfBoundsException Thrown if hasNextVoxel()==false + */ + DoseTypeGy next(); - /*! @brief Volume of one voxel (in cm3)*/ - DoseVoxelVolumeType getDeltaV() const; + /*! @brief Volume of one voxel (in cm3)*/ + DoseVoxelVolumeType getDeltaV() const; - /*! @brief Return geometric information*/ - core::GeometricInfo getGeometricInfo() const; + /*! @brief Return geometric information*/ + core::GeometricInfo getGeometricInfo() const; - /*! @brief Return 1? To be modified...*/ - double getCurrentVoxelProportion() const; + /*! @brief Return 1? To be modified...*/ + double getCurrentVoxelProportion() const; - /*! @brief Return the current RTVoxel Object*/ - const DoseVoxel& getCurrentRTVoxel(); - }; -} - } + /*! @brief Return the current RTVoxel Object*/ + const DoseVoxel& getCurrentRTVoxel(); + }; + } + } } #endif diff --git a/code/masks/legacy/DoseVoxel_LEGACY.cpp b/code/masks/legacy/DoseVoxel_LEGACY.cpp index 628255e..c3c64ba 100644 --- a/code/masks/legacy/DoseVoxel_LEGACY.cpp +++ b/code/masks/legacy/DoseVoxel_LEGACY.cpp @@ -1,867 +1,1077 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "DoseVoxel_LEGACY.h" #include "rttbInvalidParameterException.h" #include "rttbContour_LEGACY.h" using namespace std; -namespace rttb{ - namespace masks{ -namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { + + DoseVoxel::DoseVoxel() + { + //default 1 + _proportionInStr = 1; + } - DoseVoxel::DoseVoxel(){ - //default 1 - _proportionInStr=1; - } + DoseVoxel::DoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo) + { + if (aDoseIndex(0) < 0 || aDoseIndex(1) < 0 || aDoseIndex(2) < 0) + { + std::cout << aDoseIndex.toString() << std::endl; + throw rttb::core::InvalidParameterException("Invalid dose index!"); + } + else if (aGeometricInfo->getPixelSpacingRow() <= 0 || aGeometricInfo->getPixelSpacingColumn() <= 0 + || aGeometricInfo->getSliceThickness() <= 0) + { + throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); + } + else + { + _voxelIndex3D.x = aDoseIndex(0); + _voxelIndex3D.y = aDoseIndex(1); + _voxelIndex3D.z = aDoseIndex(2); + _geoInfo = aGeometricInfo; + + WorldCoordinate3D currentWorld(0); + aGeometricInfo->indexToWorldCoordinate(aDoseIndex, currentWorld); + _x = currentWorld(0); + _y = currentWorld(1); + _z = currentWorld(2); + //std::cout << "zIndex:"<getPixelSpacingRow(); + _deltaY = aGeometricInfo->getPixelSpacingColumn(); + _deltaZ = aGeometricInfo->getSliceThickness(); + } - DoseVoxel::DoseVoxel(const VoxelGridIndex3D &aDoseIndex, const core::GeometricInfo* aGeometricInfo){ - if(aDoseIndex(0)<0 || aDoseIndex(1)<0 || aDoseIndex(2)<0){ - std::cout << aDoseIndex.toString()<getPixelSpacingRow()<=0 || aGeometricInfo->getPixelSpacingColumn()<=0 || aGeometricInfo->getSliceThickness() <=0) - throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); - else{ - _voxelIndex3D.x=aDoseIndex(0); - _voxelIndex3D.y=aDoseIndex(1); - _voxelIndex3D.z=aDoseIndex(2); - _geoInfo=aGeometricInfo; - - WorldCoordinate3D currentWorld(0); - aGeometricInfo->indexToWorldCoordinate(aDoseIndex,currentWorld); - _x=currentWorld(0); - _y=currentWorld(1); - _z=currentWorld(2); - //std::cout << "zIndex:"<getPixelSpacingRow(); - _deltaY=aGeometricInfo->getPixelSpacingColumn(); - _deltaZ=aGeometricInfo->getSliceThickness(); + //default 1 + _proportionInStr = 1; } - //default 1 - _proportionInStr=1; - } + DoseVoxel::DoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, + const rttb::core::GeometricInfo* aGeometricInfo) + { + if (aDoseIndex.x < 0 || aDoseIndex.y < 0 || aDoseIndex.z < 0) + { + std::cout << aDoseIndex.toString() << std::endl; + throw rttb::core::InvalidParameterException("Invalid dose index!"); + } + else if (aGeometricInfo->getPixelSpacingRow() <= 0 || aGeometricInfo->getPixelSpacingColumn() <= 0 + || aGeometricInfo->getSliceThickness() <= 0) + { + throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); + } + else + { + _voxelIndex3D = aDoseIndex; + _geoInfo = aGeometricInfo; + + // old + //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.x; + //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.y; + //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z); + + //Martina + WorldCoordinate3D currentWorld(0); + VoxelGridIndex3D currentIndex(aDoseIndex.x, aDoseIndex.y, aDoseIndex.z); + aGeometricInfo->indexToWorldCoordinate(currentIndex, currentWorld); + _x = currentWorld(0); + _y = currentWorld(1); + _z = currentWorld(2); + + //Lanlan + //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; + //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; + + //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; + + //std::cout << "zIndex:"<getPixelSpacingRow(); + _deltaY = aGeometricInfo->getPixelSpacingColumn(); + _deltaZ = aGeometricInfo->getSliceThickness(); - DoseVoxel::DoseVoxel(const LegacyDoseVoxelIndex3D &aDoseIndex, const rttb::core::GeometricInfo* aGeometricInfo){ - if(aDoseIndex.x<0 || aDoseIndex.y<0 || aDoseIndex.z<0){ - std::cout << aDoseIndex.toString()<getPixelSpacingRow()<=0 || aGeometricInfo->getPixelSpacingColumn()<=0 || aGeometricInfo->getSliceThickness() <=0) - throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); - else{ - _voxelIndex3D=aDoseIndex; - _geoInfo=aGeometricInfo; - - // old - //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.x; - //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.y; - //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z); - - //Martina - WorldCoordinate3D currentWorld(0); - VoxelGridIndex3D currentIndex(aDoseIndex.x,aDoseIndex.y,aDoseIndex.z); - aGeometricInfo->indexToWorldCoordinate(currentIndex,currentWorld); - _x=currentWorld(0); - _y=currentWorld(1); - _z=currentWorld(2); - - //Lanlan - //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; - //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; - - //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; - - //std::cout << "zIndex:"<getPixelSpacingRow(); - _deltaY=aGeometricInfo->getPixelSpacingColumn(); - _deltaZ=aGeometricInfo->getSliceThickness(); - + } + + //default 1 + _proportionInStr = 1; } - //default 1 - _proportionInStr=1; - } + bool DoseVoxel::operator==(const DoseVoxel& doseVoxel) const + { + return (_x == doseVoxel._x) && (_y == doseVoxel._y) && (_z == doseVoxel._z) + && (_deltaX == doseVoxel._deltaX) && (_deltaY == doseVoxel._deltaY) && (_deltaZ == _deltaZ); + } - bool DoseVoxel::operator==(const DoseVoxel& doseVoxel) const{ - return (_x==doseVoxel._x)&& (_y==doseVoxel._y)&& (_z==doseVoxel._z) - && (_deltaX==doseVoxel._deltaX) && (_deltaY==doseVoxel._deltaY)&& (_deltaZ==_deltaZ); - } + bool DoseVoxel::operator<(const DoseVoxel& doseVoxel) const + { + WorldCoordinate3D leftP = doseVoxel.getLeftUpperPoint(); + WorldCoordinate3D deltaP = doseVoxel.getDelta(); - bool DoseVoxel::operator<(const DoseVoxel& doseVoxel) const{ - WorldCoordinate3D leftP=doseVoxel.getLeftUpperPoint(); - WorldCoordinate3D deltaP=doseVoxel.getDelta(); - if(_zindexToWorldCoordinate(aDoseIndex , aWorldCoordinate)) + { + _x = aWorldCoordinate(0); + _y = aWorldCoordinate(1); + _z = aWorldCoordinate(2); + } + else + { + //something went wrong! + } + + /* //Martina + _x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(0); + _y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(1); + _z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2)-0.5); + */ + //Lanlan + //_x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(0)-0.5*aGeometricInfo->getPixelSpacingRow(); + //_y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(1)-0.5*aGeometricInfo->getPixelSpacingColumn(); + + //_z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2))-0.5*aGeometricInfo->getSliceThickness(); + + //std::cout << "zIndex:"<getPixelSpacingRow(); + _deltaY = aGeometricInfo->getPixelSpacingColumn(); + _deltaZ = aGeometricInfo->getSliceThickness(); + } - /*! @brief Transform dose index to world coordinate - * - */ -void DoseVoxel::setDoseVoxel(const VoxelGridIndex3D &aDoseIndex, const core::GeometricInfo* aGeometricInfo) { - WorldCoordinate3D aWorldCoordinate(0); - if(aDoseIndex(0)<0 || aDoseIndex(1)<0 || aDoseIndex(2)<0) - throw rttb::core::InvalidParameterException("Invalid dose index!"); - else{ - _voxelIndex3D.x=aDoseIndex(0); - _voxelIndex3D.y=aDoseIndex(1); - _voxelIndex3D.z=aDoseIndex(2); - _geoInfo=aGeometricInfo; - - if(aGeometricInfo->indexToWorldCoordinate(aDoseIndex , aWorldCoordinate)){ - _x = aWorldCoordinate(0); - _y = aWorldCoordinate(1); - _z = aWorldCoordinate(2); - } - else{ - //something went wrong! - } + //default 1 + _proportionInStr = 1; + + } + void DoseVoxel::setDoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, + const rttb::core::GeometricInfo* aGeometricInfo) + { + + if (aDoseIndex.x < 0 || aDoseIndex.y < 0 || aDoseIndex.z < 0) + { + throw rttb::core::InvalidParameterException("Invalid dose index!"); + } + else + { + _voxelIndex3D = aDoseIndex; + _geoInfo = aGeometricInfo; + + + //Martina + WorldCoordinate3D aWorldCoordinate(0); + VoxelGridIndex3D currentIndex(aDoseIndex.x, aDoseIndex.y, aDoseIndex.z); + + if (aGeometricInfo->indexToWorldCoordinate(currentIndex , aWorldCoordinate)) + { + _x = aWorldCoordinate(0); + _y = aWorldCoordinate(1); + _z = aWorldCoordinate(2); + } + + //Lanlan + //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; + //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; + + //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; + + //std::cout << "zIndex:"<getPixelSpacingRow(); + _deltaY = aGeometricInfo->getPixelSpacingColumn(); + _deltaZ = aGeometricInfo->getSliceThickness(); + } + + //default 1 + _proportionInStr = 1; - /* //Martina - _x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(0); - _y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(1); - _z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2)-0.5); -*/ - //Lanlan - //_x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(0)-0.5*aGeometricInfo->getPixelSpacingRow(); - //_y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(1)-0.5*aGeometricInfo->getPixelSpacingColumn(); - - //_z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2))-0.5*aGeometricInfo->getSliceThickness(); - - //std::cout << "zIndex:"<getPixelSpacingRow(); - _deltaY=aGeometricInfo->getPixelSpacingColumn(); - _deltaZ=aGeometricInfo->getSliceThickness(); - } - - //default 1 - _proportionInStr=1; - -} -void DoseVoxel::setDoseVoxel(const LegacyDoseVoxelIndex3D &aDoseIndex, const rttb::core::GeometricInfo* aGeometricInfo) { - - if(aDoseIndex.x<0 || aDoseIndex.y<0 || aDoseIndex.z<0) - throw rttb::core::InvalidParameterException("Invalid dose index!"); - else{ - _voxelIndex3D=aDoseIndex; - _geoInfo=aGeometricInfo; - - - //Martina - WorldCoordinate3D aWorldCoordinate(0); - VoxelGridIndex3D currentIndex(aDoseIndex.x,aDoseIndex.y,aDoseIndex.z); - if(aGeometricInfo->indexToWorldCoordinate(currentIndex , aWorldCoordinate)){ - _x = aWorldCoordinate(0); - _y = aWorldCoordinate(1); - _z = aWorldCoordinate(2); - } - //Lanlan - //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; - //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; - - //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; - - //std::cout << "zIndex:"<getPixelSpacingRow(); - _deltaY=aGeometricInfo->getPixelSpacingColumn(); - _deltaZ=aGeometricInfo->getSliceThickness(); - } - - //default 1 - _proportionInStr=1; - - -} -/*! @brief Set dose voxel with the left upper point and delta - * - */ -void DoseVoxel::setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta){ - _x=aWorldCoordinate(0); - _y=aWorldCoordinate(1); - _z=aWorldCoordinate(2); - _deltaX=aVoxelDelta(0); - _deltaY=aVoxelDelta(1); - _deltaZ=aVoxelDelta(2); - -} -void DoseVoxel::setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, LegacyWorldCoordinate3D aVoxelDelta){ - _x=aWorldCoordinate.x; - _y=aWorldCoordinate.y; - _z=aWorldCoordinate.z; - _deltaX=aVoxelDelta.x; - _deltaY=aVoxelDelta.y; - _deltaZ=aVoxelDelta.z; - -} - -/*! @brief Tests if a point is inside the voxel - * - */ -bool DoseVoxel::pointInVoxel(const WorldCoordinate3D& aPoint) const { - if ((aPoint(0) <=(_x+_deltaX) && aPoint(0) >=_x ) && - (aPoint(1) <=(_y+_deltaY) && aPoint(1) >=_y ) && - (aPoint(2) <=(_z+_deltaZ) && aPoint(2) >=_z )) - return true; - else - return false; -} - -bool DoseVoxel::pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const { - if ((aPoint.x <=(_x+_deltaX) && aPoint.x >=_x ) && - (aPoint.y <=(_y+_deltaY) && aPoint.y >=_y ) && - (aPoint.z <=(_z+_deltaZ) && aPoint.z >=_z )) - return true; - else - return false; -} - -/*! @brief Calculates how many relative volume of the voxel inside the structure. - * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error - * @pre aRTStructure must not be NULL - */ -double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure) const{ - - //bool voxelInStr=false; - const PolygonSequenceType& strVector=aRTStructure.getStructureVector(); - - int size=strVector.size(); - - if(size==0){ - std::cerr << "Error: structure vector of aRTStructure is empty! "< roi=strVector[i]; - vector roiNext; - if(i==size-1) - roiNext=strVector[0]; - else - roiNext=strVector[i+1]; - - WorldCoordinate3D* p1=roi[0]; - WorldCoordinate3D* p2=roiNext[0]; - - - if(_z>= p1->z && _zz) - roiNumber[0]=i; - else if(_z+_deltaZ/5 >= p1->z && _z+_deltaZ/5 z) - roiNumber[1]=i; - else if(_z+2*_deltaZ/5 >= p1->z && _z+2*_deltaZ/5 z) - roiNumber[2]=i; - else if(_z+3*_deltaZ/5 >= p1->z && _z+3*_deltaZ/5 z) - roiNumber[3]=i; - else if(_z+4*_deltaZ/5 >= p1->z && _z+4*_deltaZ/5 z) - roiNumber[4]=i; - - } - - //get 5^3=125 points from the voxel - for(int i=0; i<5; i++){ - //std::cout <<"------------"< voxelPoints; - //std::cout << "----------------------------Voxel Points: "<_x<x=(_x+k*_deltaX/5); - p->y=(_y+j*_deltaY/5); - p->z=(_z+i*_deltaZ/5); - //std::cout << "("<x<<","<y<<","<z< roi=strVector[roiNumber[i]]; - if(this->pointInPolygon(roi,voxelPoint)) - voxelPointInStructure++; - //} - - //~ - vector::iterator it; - for(it=voxelPoints.begin();it!=voxelPoints.end();it++){ - delete (*it); - } - - - }*/ - - - /*PolygonType roi=strVector[i]; - if(roi.size()==0){ - std::cerr << "Error: corresponding roi of aRTStructure is empty! "<pointInPolygon(roi,p)) - voxelPointInStructure++;*/ - - //return voxelPointInStructure/125; - //return voxelPointInStructure/1; - - std::vector sliceV=this->getZIntersectPolygonIndexVector(aRTStructure); - - for(int i=0;i0: voxel in structure, =0: voxel not in structure, <0: error - * @pre aRTStructure must not be NULL -*/ -double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const{ - - - - const LegacyPolygonSequenceType& strVector=aRTStructure.getLegacyStructureVector(); - int size=strVector.size(); - - if(size==0){ - std::cerr << "Error: structure vector of aRTStructure is empty! "<size){ - std::cerr << "Error: sliceNumber must between -1 and "<getArea(); - }*/ - - - - - //if the next contour not in the same slice, break - if(isize){ - std::cerr << "Error: polygonIndex must between -1 and "<getArea(); - }*/ - - - - //std::cout << voxelPointInStructure/4.0<= last polygon - - //Reduce copying of values, since boost_vector constructors are expensive - //Anmerkung fuer Lanlan zwecks mergen : Eine Kontur, die direkt in einem slice liegt sollte nicht in beiden angrenzenden Slices voxelisiert werden. - if(_z<=strVector[i][0].z && _z+_deltaZ > strVector[i][0].z) - return i; - else - return size;//out of structure and _z bigger than the last structure slice - } - //else - else{ - - //if roi and roiNext in the same slice - if(strVector[i][0].z==strVector[i+1][0].z){ - //if voxel intersect the slice - if(_z<=strVector[i][0].z && _z+_deltaZ>=strVector[i][0].z) - return i; - } - else{ - if(_z+_deltaZ>= strVector[i][0].z && _zz<<", p2(2):"<z<=roiNext, set i+1 - } - - } - } - - } - return -1;//out of structure and _z smaller than the first structure slice - -} - -std::vector DoseVoxel::getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) const{ - - - std::vector sliceNumberVector; - - const LegacyPolygonSequenceType& strVector=aRTStructure.getLegacyStructureVector();//strVector is ranked by _z of the contour - int size=strVector.size(); - - if(size==0){ - throw std::out_of_range( "Error: structure vector of aRTStructure is empty! "); - } - - - int firstSlice=this->getCorrespondingSlice(aRTStructure); - if(firstSlice>=0 && firstSlice DoseVoxel::calcIntersectionPoints(WorldCoordinate3D firstPoint, WorldCoordinate3D secondPoint){ - - //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] - - //segment: (y-first(1))*(secont(0)-first(0))=(x-first(0))*(secont(1)-first(1)) - int a=secondPoint(0)-firstPoint(0); - int b=secondPoint(1)-firstPoint(1); - - std::vector intersectionPoints; - - if(a==0){ - if(firstPoint(0)>=_x && firstPoint(0)<=(_x+_deltaX)){ - if(min(firstPoint(1),secondPoint(1))<=_y && max(firstPoint(1), secondPoint(1))>=_y){ - WorldCoordinate3D p; - p(0) = firstPoint(0); - p(1) = _y; - p(2) = _z; - intersectionPoints.push_back(p); } - if(min(firstPoint(1),secondPoint(1))<=(_y+_deltaY) && max(firstPoint(1), secondPoint(1))>=(_y+_deltaY)){ - WorldCoordinate3D p; - p(0) = firstPoint(0); - p(1) = _y+_deltaY; - p(2) = _z; - intersectionPoints.push_back(p); + /*! @brief Set dose voxel with the left upper point and delta + * + */ + void DoseVoxel::setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta) + { + _x = aWorldCoordinate(0); + _y = aWorldCoordinate(1); + _z = aWorldCoordinate(2); + _deltaX = aVoxelDelta(0); + _deltaY = aVoxelDelta(1); + _deltaZ = aVoxelDelta(2); + } + void DoseVoxel::setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, + LegacyWorldCoordinate3D aVoxelDelta) + { + _x = aWorldCoordinate.x; + _y = aWorldCoordinate.y; + _z = aWorldCoordinate.z; + _deltaX = aVoxelDelta.x; + _deltaY = aVoxelDelta.y; + _deltaZ = aVoxelDelta.z; - } + } - } - else if(b==0){ - if(firstPoint(1)>=_y && firstPoint(1)<=(_y+_deltaY)){ - if(min(firstPoint(0),secondPoint(0))<=_x && max(firstPoint(0), secondPoint(0))>=_x){ - WorldCoordinate3D p; - p(0) = _x; - p(1) = firstPoint(1); - p(2) = _z; - intersectionPoints.push_back(p); + /*! @brief Tests if a point is inside the voxel + * + */ + bool DoseVoxel::pointInVoxel(const WorldCoordinate3D& aPoint) const + { + if ((aPoint(0) <= (_x + _deltaX) && aPoint(0) >= _x) && + (aPoint(1) <= (_y + _deltaY) && aPoint(1) >= _y) && + (aPoint(2) <= (_z + _deltaZ) && aPoint(2) >= _z)) + { + return true; + } + else + { + return false; + } } - if(min(firstPoint(0),secondPoint(0))<=(_x+_deltaX) && max(firstPoint(0), secondPoint(0))>=(_x+_deltaX)){ - WorldCoordinate3D p; - p(0) = _x+_deltaX; - p(1) = firstPoint(1); - p(2) = _z; - intersectionPoints.push_back(p); + + bool DoseVoxel::pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const + { + if ((aPoint.x <= (_x + _deltaX) && aPoint.x >= _x) && + (aPoint.y <= (_y + _deltaY) && aPoint.y >= _y) && + (aPoint.z <= (_z + _deltaZ) && aPoint.z >= _z)) + { + return true; + } + else + { + return false; + } } - } + /*! @brief Calculates how many relative volume of the voxel inside the structure. + * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error + * @pre aRTStructure must not be NULL + */ + double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure) const + { - } - else{ - //1.[(_x,_y),(_x+_deltaX,_y)] - double interX=(_y-firstPoint(1))*a/b+firstPoint(0); - if(interX>=_x && interX<=(_x+_deltaX)){ - WorldCoordinate3D p; - p(0) = interX; - p(1) = _y; - p(2) = _z; - intersectionPoints.push_back(p); - } + //bool voxelInStr=false; + const PolygonSequenceType& strVector = aRTStructure.getStructureVector(); - //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] - double interY=(_x+_deltaX-firstPoint(0))*b/a+firstPoint(1); - if(interY>=_y && interY<=(_y+_deltaY)){ - WorldCoordinate3D p; - p(0) = _x+_deltaX; - p(1) = interY; - p(2) = _z; - intersectionPoints.push_back(p); - } + int size = strVector.size(); - //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] - interX=(_y+_deltaY-firstPoint(1))*a/b+firstPoint(0); - if(interX>=_x && interX<=(_x+_deltaX)){ - WorldCoordinate3D p; - p(0) = interX; - p(1) = _y+_deltaY; - p(2) = _z; - intersectionPoints.push_back(p); - } + if (size == 0) + { + std::cerr << "Error: structure vector of aRTStructure is empty! " << std::endl; + return -1; + } - //4.[(_x,_y+_deltaY),(_x,_y)] - interY=(_x-firstPoint(0))*b/a+firstPoint(1); - if(interY>=_y && interY<=(_y+_deltaY)){ - WorldCoordinate3D p; - p(0) = _x; - p(1) = interY; - p(2) = _z; - intersectionPoints.push_back(p); - } - } - return intersectionPoints; -} -std::vector DoseVoxel::calcIntersectionPoints(LegacyWorldCoordinate3D firstPoint, LegacyWorldCoordinate3D secondPoint){ + double voxelInStructure = 0; + + /*roiNumber[i]=j means _z+i*_deltaZ lies between the j-th and (j+1)-th ROI*/ + /*int roiNumber[5]={0,0,0,0,0}; + for(int i=0;i roi=strVector[i]; + vector roiNext; + if(i==size-1) + roiNext=strVector[0]; + else + roiNext=strVector[i+1]; + + WorldCoordinate3D* p1=roi[0]; + WorldCoordinate3D* p2=roiNext[0]; + + + if(_z>= p1->z && _zz) + roiNumber[0]=i; + else if(_z+_deltaZ/5 >= p1->z && _z+_deltaZ/5 z) + roiNumber[1]=i; + else if(_z+2*_deltaZ/5 >= p1->z && _z+2*_deltaZ/5 z) + roiNumber[2]=i; + else if(_z+3*_deltaZ/5 >= p1->z && _z+3*_deltaZ/5 z) + roiNumber[3]=i; + else if(_z+4*_deltaZ/5 >= p1->z && _z+4*_deltaZ/5 z) + roiNumber[4]=i; + + } + + //get 5^3=125 points from the voxel + for(int i=0; i<5; i++){ + //std::cout <<"------------"< voxelPoints; + //std::cout << "----------------------------Voxel Points: "<_x<x=(_x+k*_deltaX/5); + p->y=(_y+j*_deltaY/5); + p->z=(_z+i*_deltaZ/5); + //std::cout << "("<x<<","<y<<","<z< roi=strVector[roiNumber[i]]; + if(this->pointInPolygon(roi,voxelPoint)) + voxelPointInStructure++; + //} + + //~ + vector::iterator it; + for(it=voxelPoints.begin();it!=voxelPoints.end();it++){ + delete (*it); + } + + + }*/ + + + /*PolygonType roi=strVector[i]; + if(roi.size()==0){ + std::cerr << "Error: corresponding roi of aRTStructure is empty! "<pointInPolygon(roi,p)) + voxelPointInStructure++;*/ + + //return voxelPointInStructure/125; + //return voxelPointInStructure/1; + + std::vector sliceV = this->getZIntersectPolygonIndexVector(aRTStructure); + + for (int i = 0; i < sliceV.size(); i++) + { + voxelInStructure += voxelInStructureAtIndex(aRTStructure, sliceV.at(i)); + } + + return voxelInStructure; + } + + /*! @brief Calculates how many relative volume of the voxel inside the structure, with the corresponding polygon index number. + * It will be tested if the dose voxel in any Polygon with the same z coord.. + * @param sliceNumber: fist index number of the polygon stored in strVector (ranked by z coord. of the polygon) if the z coord. + * of the dose voxel between the last Polygon and this Polygon!!! + * + * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error + * @pre aRTStructure must not be NULL + */ + double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const + { + + + + const LegacyPolygonSequenceType& strVector = aRTStructure.getLegacyStructureVector(); + int size = strVector.size(); + + if (size == 0) + { + std::cerr << "Error: structure vector of aRTStructure is empty! " << std::endl; + return -1; + } + + if (sliceNumber < -1 || sliceNumber > size) + { + std::cerr << "Error: sliceNumber must between -1 and " << size << std::endl; + return -1; + } + + //out of structure and _z bigger than z coordi.of the last polygon: voxel not in structure. + if (sliceNumber == size) + { + return 0; + } + + //out of structure and _z smaller than z coordi.of the first polygon: + if (sliceNumber == -1) + { + //if _z+_deltaZ smaller than z coordi.of the first polygon: voxel not in structure + if (_z + _deltaZ < strVector.at(0).at(0).z) + { + return 0; + } + //else test from the first polygon + else + { + sliceNumber = 0; + } + } + + int voxelPointInStructure = 0; + + + double interArea = 0; + double voxelArea = _deltaX * _deltaY; + + + + for (int i = sliceNumber; i < size; i++) + { + LegacyPolygonType roi = strVector[i]; + Contour contour(roi); + + //test, if any of the 4 points of this dose voxel lie in the roi + LegacyWorldCoordinate1D zPlane = roi.at(0).z; + LegacyWorldCoordinate3D p; + p.x = _x + _deltaX / 4; + p.y = _y + _deltaY / 4; + p.z = zPlane; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.x = _x + _deltaX * 3 / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.y = _y + _deltaY * 3 / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.z = _x + _deltaX / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + /*p(0)=_x; + p(1)=_y; + + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(0)=_x+_deltaX; + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(1)=_y+_deltaY; + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(0)=_x; + if(contour.pointInPolygon(p)) voxelPointInStructure++;*/ + + + /*get intersection*/ - //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] + /*if(voxelPointInStructure=4) + return 1; + else{ + PolygonType voxelPolygon; + WorldCoordinate3D p1={_x,_y,zPlane}; + WorldCoordinate3D p2={_x,_y+_deltaY,zPlane}; + WorldCoordinate3D p3={_x+_deltaX,_y+_deltaY,zPlane}; + WorldCoordinate3D p4={_x+_deltaX,_y,zPlane}; + voxelPolygon.push_back(p1); + voxelPolygon.push_back(p2); + voxelPolygon.push_back(p3); + voxelPolygon.push_back(p4); + Contour voxelContour=Contour(voxelPolygon); - //segment: (y-first.y)*(secont.x-first.x)=(x-first.x)*(secont.y-first.y) - int a=secondPoint.x-firstPoint.x; - int b=secondPoint.y-firstPoint.y; + Contour* interContour=voxelContour.calcIntersection(contour); - std::vector intersectionPoints; + if(interContour) + interArea+=interContour->getArea(); + }*/ - if(a==0){ - if(firstPoint.x>=_x && firstPoint.x<=(_x+_deltaX)){ - if(min(firstPoint.y,secondPoint.y)<=_y && max(firstPoint.y, secondPoint.y)>=_y){ - LegacyWorldCoordinate3D p(firstPoint.x,_y,_z); - intersectionPoints.push_back(p); + + + + //if the next contour not in the same slice, break + if (i < size - 1) + { + if (strVector.at(i + 1).at(0).z != roi.at(0).z) + { + break; + } + } + + + } + + //std::cout << voxelPointInStructure/4.0<=(_y+_deltaY)){ - LegacyWorldCoordinate3D p(firstPoint.x,_y+_deltaY,_z); - intersectionPoints.push_back(p); + + double DoseVoxel::voxelInStructureAtIndex(const StructureLegacy& aRTStructure, + int polygonIndex) const + { + + + const LegacyPolygonSequenceType& strVector = aRTStructure.getLegacyStructureVector(); + int size = strVector.size(); + + if (size == 0) + { + std::cerr << "Error: structure vector of aRTStructure is empty! " << std::endl; + return -1; + } + + if (polygonIndex < -1 || polygonIndex > size) + { + std::cerr << "Error: polygonIndex must between -1 and " << size << std::endl; + return -1; + } + + //out of structure and _z bigger than z coordi.of the last polygon: voxel not in structure. + if (polygonIndex == size) + { + return 0; + } + + //out of structure and _z smaller than z coordi.of the first polygon: + if (polygonIndex == -1) + { + return 0; + } + + + int voxelPointInStructure = 0; + + + + double interArea = 0; + double voxelArea = _deltaX * _deltaY; + + LegacyPolygonType roi = strVector[polygonIndex]; + Contour contour = Contour(roi); + + //test, if any of the 4 points of this dose voxel lie in the roi + LegacyWorldCoordinate1D zPlane = roi.at(0).z; + LegacyWorldCoordinate3D p; + p.x = _x + _deltaX / 4; + p.y = _y + _deltaY / 4; + p.z = zPlane; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.x = _x + _deltaX * 3 / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.y = _y + _deltaY * 3 / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + p.z = _x + _deltaX / 4; + + if (contour.pointInPolygon(p)) + { + voxelPointInStructure++; + } + + /*p(0)=_x; + p(1)=_y; + + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(0)=_x+_deltaX; + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(1)=_y+_deltaY; + if(contour.pointInPolygon(p)) voxelPointInStructure++; + p(0)=_x; + if(contour.pointInPolygon(p)) voxelPointInStructure++;*/ + + /*get intersection*/ + + /*if(voxelPointInStructure=4) + return 1; + else{ + PolygonType voxelPolygon; + WorldCoordinate3D p1={_x,_y,zPlane}; + WorldCoordinate3D p2={_x,_y+_deltaY,zPlane}; + WorldCoordinate3D p3={_x+_deltaX,_y+_deltaY,zPlane}; + WorldCoordinate3D p4={_x+_deltaX,_y,zPlane}; + voxelPolygon.push_back(p1); + voxelPolygon.push_back(p2); + voxelPolygon.push_back(p3); + voxelPolygon.push_back(p4); + Contour voxelLegacyContour=Contour(voxelPolygon); + + Contour* interLegacyContour=voxelLegacyContour.calcIntersection(contour); + + if(interLegacyContour) + interArea+=interLegacyContour->getArea(); + }*/ + + + + //std::cout << voxelPointInStructure/4.0<= last polygon + + //Reduce copying of values, since boost_vector constructors are expensive + //Anmerkung fuer Lanlan zwecks mergen : Eine Kontur, die direkt in einem slice liegt sollte nicht in beiden angrenzenden Slices voxelisiert werden. + if (_z <= strVector[i][0].z && _z + _deltaZ > strVector[i][0].z) + { + return i; + } + else + { + return size; //out of structure and _z bigger than the last structure slice + } + } + //else + else + { + + //if roi and roiNext in the same slice + if (strVector[i][0].z == strVector[i + 1][0].z) + { + //if voxel intersect the slice + if (_z <= strVector[i][0].z && _z + _deltaZ >= strVector[i][0].z) + { + return i; + } + } + else + { + if (_z + _deltaZ >= strVector[i][0].z && _z < strVector[i + 1][0].z) + { + if (_z + _deltaZ <= strVector[i + 1][0].z) + //std::cout << "_z:"<<_z<<", p1(2):"<z<<", p2(2):"<z<=roiNext, set i+1 + } + } + + } + } + + } + + return -1;//out of structure and _z smaller than the first structure slice - } - else if(b==0){ - if(firstPoint.y>=_y && firstPoint.y<=(_y+_deltaY)){ - if(min(firstPoint.x,secondPoint.x)<=_x && max(firstPoint.x, secondPoint.x)>=_x){ - LegacyWorldCoordinate3D p(_x,firstPoint.y,_z); - intersectionPoints.push_back(p); } - if(min(firstPoint.x,secondPoint.x)<=(_x+_deltaX) && max(firstPoint.x, secondPoint.x)>=(_x+_deltaX)){ - LegacyWorldCoordinate3D p(_x+_deltaX,firstPoint.y,_z); - intersectionPoints.push_back(p); + + std::vector DoseVoxel::getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) + const + { + + + std::vector sliceNumberVector; + + const LegacyPolygonSequenceType& strVector = + aRTStructure.getLegacyStructureVector(); //strVector is ranked by _z of the contour + int size = strVector.size(); + + if (size == 0) + { + throw std::out_of_range("Error: structure vector of aRTStructure is empty! "); + } + + + int firstSlice = this->getCorrespondingSlice(aRTStructure); + + if (firstSlice >= 0 && firstSlice < size) + { + sliceNumberVector.push_back(firstSlice); + + LegacyWorldCoordinate1D zCoord = strVector.at(firstSlice).at(0).z; + + //add all polygon index with the same z + for (int i = 0; i < size; i++) + if (strVector.at(i).at(0).z == zCoord && i != firstSlice) + { + sliceNumberVector.push_back(i); + } + } + + + return sliceNumberVector; + } - } + WorldCoordinate3D DoseVoxel::getLeftUpperPoint() const + { + WorldCoordinate3D p; + p(0) = _x; + p(1) = _y; + p(2) = _z; + return p; + } - } - else{ - //1.[(_x,_y),(_x+_deltaX,_y)] - double interX=(_y-firstPoint.y)*a/b+firstPoint.x; - if(interX>=_x && interX<=(_x+_deltaX)){ - LegacyWorldCoordinate3D p(interX,_y,_z); - intersectionPoints.push_back(p); - } + WorldCoordinate3D DoseVoxel::getDelta() const + { + WorldCoordinate3D p; + p(0) = _deltaX; + p(1) = _deltaY; + p(2) = _deltaZ; + return p; + } + LegacyWorldCoordinate3D DoseVoxel::getLeftUpperPointLegacy() const + { + LegacyWorldCoordinate3D p(_x, _y, _z); + return p; + } - //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] - double interY=(_x+_deltaX-firstPoint.x)*b/a+firstPoint.y; - if(interY>=_y && interY<=(_y+_deltaY)){ - LegacyWorldCoordinate3D p(_x+_deltaX,interY,_z); - intersectionPoints.push_back(p); - } + LegacyWorldCoordinate3D DoseVoxel::getDeltaLegacy() const + { + LegacyWorldCoordinate3D p(_deltaX, _deltaY, _deltaZ); + return p; + } + std::vector DoseVoxel::calcIntersectionPoints(WorldCoordinate3D firstPoint, + WorldCoordinate3D secondPoint) + { + + //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] + + //segment: (y-first(1))*(secont(0)-first(0))=(x-first(0))*(secont(1)-first(1)) + int a = secondPoint(0) - firstPoint(0); + int b = secondPoint(1) - firstPoint(1); + + std::vector intersectionPoints; + + if (a == 0) + { + if (firstPoint(0) >= _x && firstPoint(0) <= (_x + _deltaX)) + { + if (min(firstPoint(1), secondPoint(1)) <= _y && max(firstPoint(1), secondPoint(1)) >= _y) + { + WorldCoordinate3D p; + p(0) = firstPoint(0); + p(1) = _y; + p(2) = _z; + intersectionPoints.push_back(p); + } + + if (min(firstPoint(1), secondPoint(1)) <= (_y + _deltaY) + && max(firstPoint(1), secondPoint(1)) >= (_y + _deltaY)) + { + WorldCoordinate3D p; + p(0) = firstPoint(0); + p(1) = _y + _deltaY; + p(2) = _z; + intersectionPoints.push_back(p); + } + + } - //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] - interX=(_y+_deltaY-firstPoint.y)*a/b+firstPoint.x; - if(interX>=_x && interX<=(_x+_deltaX)){ - LegacyWorldCoordinate3D p(interX,_y+_deltaY,_z); - intersectionPoints.push_back(p); - } + } + else if (b == 0) + { + if (firstPoint(1) >= _y && firstPoint(1) <= (_y + _deltaY)) + { + if (min(firstPoint(0), secondPoint(0)) <= _x && max(firstPoint(0), secondPoint(0)) >= _x) + { + WorldCoordinate3D p; + p(0) = _x; + p(1) = firstPoint(1); + p(2) = _z; + intersectionPoints.push_back(p); + } + + if (min(firstPoint(0), secondPoint(0)) <= (_x + _deltaX) + && max(firstPoint(0), secondPoint(0)) >= (_x + _deltaX)) + { + WorldCoordinate3D p; + p(0) = _x + _deltaX; + p(1) = firstPoint(1); + p(2) = _z; + intersectionPoints.push_back(p); + } + + } - //4.[(_x,_y+_deltaY),(_x,_y)] - interY=(_x-firstPoint.x)*b/a+firstPoint.y; - if(interY>=_y && interY<=(_y+_deltaY)){ - LegacyWorldCoordinate3D p(_x,interY,_z); - intersectionPoints.push_back(p); - } + } + else + { + //1.[(_x,_y),(_x+_deltaX,_y)] + double interX = (_y - firstPoint(1)) * a / b + firstPoint(0); + + if (interX >= _x && interX <= (_x + _deltaX)) + { + WorldCoordinate3D p; + p(0) = interX; + p(1) = _y; + p(2) = _z; + intersectionPoints.push_back(p); + } + + //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] + double interY = (_x + _deltaX - firstPoint(0)) * b / a + firstPoint(1); + + if (interY >= _y && interY <= (_y + _deltaY)) + { + WorldCoordinate3D p; + p(0) = _x + _deltaX; + p(1) = interY; + p(2) = _z; + intersectionPoints.push_back(p); + } + + //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] + interX = (_y + _deltaY - firstPoint(1)) * a / b + firstPoint(0); + + if (interX >= _x && interX <= (_x + _deltaX)) + { + WorldCoordinate3D p; + p(0) = interX; + p(1) = _y + _deltaY; + p(2) = _z; + intersectionPoints.push_back(p); + } + + //4.[(_x,_y+_deltaY),(_x,_y)] + interY = (_x - firstPoint(0)) * b / a + firstPoint(1); + + if (interY >= _y && interY <= (_y + _deltaY)) + { + WorldCoordinate3D p; + p(0) = _x; + p(1) = interY; + p(2) = _z; + intersectionPoints.push_back(p); + } + + } - } - return intersectionPoints; -} + return intersectionPoints; + } -/*! @brief Get the voxel index*/ -const LegacyDoseVoxelIndex3D& DoseVoxel::getVoxelIndex3D() const{ - return _voxelIndex3D; -} + std::vector DoseVoxel::calcIntersectionPoints( + LegacyWorldCoordinate3D firstPoint, LegacyWorldCoordinate3D secondPoint) + { -/*! @brief Get the geometric information*/ -const core::GeometricInfo* DoseVoxel::getGeometricInfo() const{ - return _geoInfo; -} + //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] -void DoseVoxel::setProportionInStr(FractionType aProportionInStr){ - _proportionInStr=aProportionInStr; -} + //segment: (y-first.y)*(secont.x-first.x)=(x-first.x)*(secont.y-first.y) + int a = secondPoint.x - firstPoint.x; + int b = secondPoint.y - firstPoint.y; -FractionType DoseVoxel::getProportionInStr() const{ - return _proportionInStr; -} -} + std::vector intersectionPoints; + + if (a == 0) + { + if (firstPoint.x >= _x && firstPoint.x <= (_x + _deltaX)) + { + if (min(firstPoint.y, secondPoint.y) <= _y && max(firstPoint.y, secondPoint.y) >= _y) + { + LegacyWorldCoordinate3D p(firstPoint.x, _y, _z); + intersectionPoints.push_back(p); + } + + if (min(firstPoint.y, secondPoint.y) <= (_y + _deltaY) + && max(firstPoint.y, secondPoint.y) >= (_y + _deltaY)) + { + LegacyWorldCoordinate3D p(firstPoint.x, _y + _deltaY, _z); + intersectionPoints.push_back(p); + } + + } + + } + else if (b == 0) + { + if (firstPoint.y >= _y && firstPoint.y <= (_y + _deltaY)) + { + if (min(firstPoint.x, secondPoint.x) <= _x && max(firstPoint.x, secondPoint.x) >= _x) + { + LegacyWorldCoordinate3D p(_x, firstPoint.y, _z); + intersectionPoints.push_back(p); + } + + if (min(firstPoint.x, secondPoint.x) <= (_x + _deltaX) + && max(firstPoint.x, secondPoint.x) >= (_x + _deltaX)) + { + LegacyWorldCoordinate3D p(_x + _deltaX, firstPoint.y, _z); + intersectionPoints.push_back(p); + } + + } + + } + else + { + //1.[(_x,_y),(_x+_deltaX,_y)] + double interX = (_y - firstPoint.y) * a / b + firstPoint.x; + + if (interX >= _x && interX <= (_x + _deltaX)) + { + LegacyWorldCoordinate3D p(interX, _y, _z); + intersectionPoints.push_back(p); + } + + //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] + double interY = (_x + _deltaX - firstPoint.x) * b / a + firstPoint.y; + + if (interY >= _y && interY <= (_y + _deltaY)) + { + LegacyWorldCoordinate3D p(_x + _deltaX, interY, _z); + intersectionPoints.push_back(p); + } + + //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] + interX = (_y + _deltaY - firstPoint.y) * a / b + firstPoint.x; + + if (interX >= _x && interX <= (_x + _deltaX)) + { + LegacyWorldCoordinate3D p(interX, _y + _deltaY, _z); + intersectionPoints.push_back(p); + } + + //4.[(_x,_y+_deltaY),(_x,_y)] + interY = (_x - firstPoint.x) * b / a + firstPoint.y; + + if (interY >= _y && interY <= (_y + _deltaY)) + { + LegacyWorldCoordinate3D p(_x, interY, _z); + intersectionPoints.push_back(p); + } + + } + + return intersectionPoints; + } + + /*! @brief Get the voxel index*/ + const LegacyDoseVoxelIndex3D& DoseVoxel::getVoxelIndex3D() const + { + return _voxelIndex3D; + } + + /*! @brief Get the geometric information*/ + const core::GeometricInfo* DoseVoxel::getGeometricInfo() const + { + return _geoInfo; + } + + void DoseVoxel::setProportionInStr(FractionType aProportionInStr) + { + _proportionInStr = aProportionInStr; + } + + FractionType DoseVoxel::getProportionInStr() const + { + return _proportionInStr; + } + } }//end namespace core }//end namespace rttb diff --git a/code/masks/legacy/DoseVoxel_LEGACY.h b/code/masks/legacy/DoseVoxel_LEGACY.h index dda073e..5693d95 100644 --- a/code/masks/legacy/DoseVoxel_LEGACY.h +++ b/code/masks/legacy/DoseVoxel_LEGACY.h @@ -1,210 +1,215 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 __RT_DOSE_VOXEL_H #define __RT_DOSE_VOXEL_H //#include "rttbStructure.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" #include "rttbStructure_LEGACY.h" -namespace rttb{ - - namespace masks - { -namespace legacy{ - /*! @class DoseVoxel - * @brief This is a class representing a DoseVoxel. - */ - - class DoseVoxel - { - - private: - /*! @brief Voxel index */ - LegacyDoseVoxelIndex3D _voxelIndex3D; - - /*! @brief WorldCoordinate (_x,_y,_z): the left upper point, the point in voxel with minimal x y and z coordinate*/ - WorldCoordinate _x; - WorldCoordinate _y; - WorldCoordinate _z; - /*! @brief(_x+_deltaX, _y+_deltaY,_z+_deltaZ): the point in voxel with maximal x y and z coordinate*/ - WorldCoordinate _deltaX; - WorldCoordinate _deltaY; - WorldCoordinate _deltaZ; - - /*! @brief Geometric information*/ - const core::GeometricInfo* _geoInfo; - - /*! @brief The proportion of voxel which is inside a given structure: 0~1 */ - FractionType _proportionInStr; - - - public: - - /* @brief Standard Constructor*/ - DoseVoxel(); - - /*! @brief Constructor - @param aDoseIndex: a dose voxel index, aGeometricInfo: the geometric information (imagePosition, ImageOrientation, - pixelSpacing and getSliceThickness()) - */ - DoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); - //same method with legacy data structures - DoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); - - /*! @brief Operator = - */ - bool operator==(const DoseVoxel& doseVoxel) const; - - /*! @brief Operator < - */ - bool operator<(const DoseVoxel& doseVoxel) const; - - - /*! @brief Initialisation of the dose voxel with dose voxel index and DICOM-RT information. Transform dose index to world coordinate - * @param imagePosition: RT Image Position(3002,0012), - * @param getImageOrientationRow(), getImageOrientationColumn(): Image Orientation (Patient) (0020,0037), - * @param getPixelSpacingRow(), getPixelSpacingColumn(): Pixel Spacing (0028,0030) - * @param getSliceThickness(): Slice Thickness (0018,0050). - * @exception RTTBInvalidParameterException thrown if aDoseIndex /Pixel spacing/slice thickness invalid - * - */ - - //void setDoseIndex(const VoxelGridIndex3D& aDoseIndex, const WorldCoordinate3D& imagePosition, - //const ImageOrientation& getImageOrientationRow(), const ImageOrientation& getImageOrientationColumn(), - //double getPixelSpacingRow(), double getPixelSpacingColumn(), double getSliceThickness()); - void setDoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); - //same method with legacy data structures - void setDoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); - - - /*! @brief Initialisation of the dose voxel with world coordinate. Set dose voxel with the left upper point and delta - * - */ - - void setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta); - //same method with legacy data structures - void setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, LegacyWorldCoordinate3D aVoxelDelta); - - /*! @brief Tests if a point is inside the voxel - * - */ - bool pointInVoxel(const WorldCoordinate3D& aPoint) const; - //same method with legacy data structures - bool pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const; - - /*! @brief Calculates how many relative volume of the voxel inside the structure. - * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error - */ - double voxelInStructure(const StructureLegacy& aRTStructure) const; - - - /*! @brief Calculates how many relative volume of the voxel inside the structure, with the corresponding polygon index number. - * It will be tested if the dose voxel in any Polygon with the same z coord.. - * @param sliceNumber: fist index number of the polygon stored in strVector (ranked by z coord. of the polygon) if the z coord. - * of the dose voxel between the last Polygon and this Polygon!!! - * - * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error - * @pre aRTStructure must not be NULL - */ - double voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const; - - - /*! @brief Calculates how many relative volume of the voxel inside the corresponding polygon with polygon index number. - * - * @param polygonIndex: the index number of the polygon stored in strVector (ranked by z coord. of the polygon) - * - * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error - * @pre aRTStructure must not be NULL - */ - double voxelInStructureAtIndex(const StructureLegacy& aRTStructure, int polygonIndex) const; - - - /*! @brief Tests if a point is inside a polygon. - * @return Return true if the point is inside the polygon or the point is on an edge of the polygon - ! Make sure that the point and the list of positions lies both in the z-plane - */ - //bool pointInPolygon(const PolygonType& aPolygon, const WorldCoordinate3D& aPoint) const; - - /*! @brief Tests if the voxel intersect the polygon defined by the given list of positions. - ! Make sure that the point and the list of positions lies both in the z-plane - */ - //public: bool voxelInROI(vector aRoi); - - - - - - /*! @brief get the first corresponding slice number: - * !!!Important: not the actual slice number, but the index number of the polygon stored in the structure vector (ranked by z coord. of the polygon) - if the z coord. of the dose voxel between the last Polygon and this Polygon!!! - * @return i from (0~strVector.size()-1): voxel between the i-th and (i+1)-th polygon or _z on the i-th polygon; - * -1: out of structure and _z smaller than z coordi.of the first polygon - * strVector.size(): out of structure and _z bigger than z coordi.of the last polygon - */ - - int getCorrespondingSlice(const StructureLegacy& aRTStructure) const; - - /*! @brief Get polygon indexs in the same contour-slice, which has intersection with this voxel. If the voxel intersect > 1 Slice, the slice with smallert - * index will be used. - * @return Return vector of index number of the polygons stored in the structure vector(ranked by z coord. of the polygon), if size=0: out of structure - */ - - std::vector getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) const; - - /*! @brief Get the left upper point of the dose voxel in world coordinate. - * - */ - WorldCoordinate3D getLeftUpperPoint() const; - LegacyWorldCoordinate3D getLeftUpperPointLegacy() const; - - /*! @brief Get (_deltaX, _deltaY, _deltaZ) of the dose voxel in world coordinate. - * - */ - WorldCoordinate3D getDelta() const; - LegacyWorldCoordinate3D getDeltaLegacy() const; - - /*! @brief Calculate the interseciton points with the segment [firstPoint, secontPoint]*/ - std::vector calcIntersectionPoints(WorldCoordinate3D firstPoint, WorldCoordinate3D secondPoint); - //same method with legacy data structures - std::vector calcIntersectionPoints(LegacyWorldCoordinate3D firstPoint, LegacyWorldCoordinate3D secondPoint); - - /*! @brief Get the voxel index*/ - const LegacyDoseVoxelIndex3D& getVoxelIndex3D() const; - - /*! @brief Get the geometric information*/ - const core::GeometricInfo* getGeometricInfo() const; - - /*! @brief Set the voxel proportion inside a given structure*/ - void setProportionInStr(FractionType aProportionInStr); - - /*! @brief Get the voxel proportion inside a given structure*/ - FractionType getProportionInStr() const; - }; -} - } +namespace rttb +{ + + namespace masks + { + namespace legacy + { + /*! @class DoseVoxel + * @brief This is a class representing a DoseVoxel. + */ + + class DoseVoxel + { + + private: + /*! @brief Voxel index */ + LegacyDoseVoxelIndex3D _voxelIndex3D; + + /*! @brief WorldCoordinate (_x,_y,_z): the left upper point, the point in voxel with minimal x y and z coordinate*/ + WorldCoordinate _x; + WorldCoordinate _y; + WorldCoordinate _z; + /*! @brief(_x+_deltaX, _y+_deltaY,_z+_deltaZ): the point in voxel with maximal x y and z coordinate*/ + WorldCoordinate _deltaX; + WorldCoordinate _deltaY; + WorldCoordinate _deltaZ; + + /*! @brief Geometric information*/ + const core::GeometricInfo* _geoInfo; + + /*! @brief The proportion of voxel which is inside a given structure: 0~1 */ + FractionType _proportionInStr; + + + public: + + /* @brief Standard Constructor*/ + DoseVoxel(); + + /*! @brief Constructor + @param aDoseIndex: a dose voxel index, aGeometricInfo: the geometric information (imagePosition, ImageOrientation, + pixelSpacing and getSliceThickness()) + */ + DoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); + //same method with legacy data structures + DoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); + + /*! @brief Operator = + */ + bool operator==(const DoseVoxel& doseVoxel) const; + + /*! @brief Operator < + */ + bool operator<(const DoseVoxel& doseVoxel) const; + + + /*! @brief Initialisation of the dose voxel with dose voxel index and DICOM-RT information. Transform dose index to world coordinate + * @param imagePosition: RT Image Position(3002,0012), + * @param getImageOrientationRow(), getImageOrientationColumn(): Image Orientation (Patient) (0020,0037), + * @param getPixelSpacingRow(), getPixelSpacingColumn(): Pixel Spacing (0028,0030) + * @param getSliceThickness(): Slice Thickness (0018,0050). + * @exception RTTBInvalidParameterException thrown if aDoseIndex /Pixel spacing/slice thickness invalid + * + */ + + //void setDoseIndex(const VoxelGridIndex3D& aDoseIndex, const WorldCoordinate3D& imagePosition, + //const ImageOrientation& getImageOrientationRow(), const ImageOrientation& getImageOrientationColumn(), + //double getPixelSpacingRow(), double getPixelSpacingColumn(), double getSliceThickness()); + void setDoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); + //same method with legacy data structures + void setDoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, + const core::GeometricInfo* aGeometricInfo); + + + /*! @brief Initialisation of the dose voxel with world coordinate. Set dose voxel with the left upper point and delta + * + */ + + void setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta); + //same method with legacy data structures + void setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, LegacyWorldCoordinate3D aVoxelDelta); + + /*! @brief Tests if a point is inside the voxel + * + */ + bool pointInVoxel(const WorldCoordinate3D& aPoint) const; + //same method with legacy data structures + bool pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const; + + /*! @brief Calculates how many relative volume of the voxel inside the structure. + * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error + */ + double voxelInStructure(const StructureLegacy& aRTStructure) const; + + + /*! @brief Calculates how many relative volume of the voxel inside the structure, with the corresponding polygon index number. + * It will be tested if the dose voxel in any Polygon with the same z coord.. + * @param sliceNumber: fist index number of the polygon stored in strVector (ranked by z coord. of the polygon) if the z coord. + * of the dose voxel between the last Polygon and this Polygon!!! + * + * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error + * @pre aRTStructure must not be NULL + */ + double voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const; + + + /*! @brief Calculates how many relative volume of the voxel inside the corresponding polygon with polygon index number. + * + * @param polygonIndex: the index number of the polygon stored in strVector (ranked by z coord. of the polygon) + * + * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error + * @pre aRTStructure must not be NULL + */ + double voxelInStructureAtIndex(const StructureLegacy& aRTStructure, int polygonIndex) const; + + + /*! @brief Tests if a point is inside a polygon. + * @return Return true if the point is inside the polygon or the point is on an edge of the polygon + ! Make sure that the point and the list of positions lies both in the z-plane + */ + //bool pointInPolygon(const PolygonType& aPolygon, const WorldCoordinate3D& aPoint) const; + + /*! @brief Tests if the voxel intersect the polygon defined by the given list of positions. + ! Make sure that the point and the list of positions lies both in the z-plane + */ + //public: bool voxelInROI(vector aRoi); + + + + + + /*! @brief get the first corresponding slice number: + * !!!Important: not the actual slice number, but the index number of the polygon stored in the structure vector (ranked by z coord. of the polygon) + if the z coord. of the dose voxel between the last Polygon and this Polygon!!! + * @return i from (0~strVector.size()-1): voxel between the i-th and (i+1)-th polygon or _z on the i-th polygon; + * -1: out of structure and _z smaller than z coordi.of the first polygon + * strVector.size(): out of structure and _z bigger than z coordi.of the last polygon + */ + + int getCorrespondingSlice(const StructureLegacy& aRTStructure) const; + + /*! @brief Get polygon indexs in the same contour-slice, which has intersection with this voxel. If the voxel intersect > 1 Slice, the slice with smallert + * index will be used. + * @return Return vector of index number of the polygons stored in the structure vector(ranked by z coord. of the polygon), if size=0: out of structure + */ + + std::vector getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) const; + + /*! @brief Get the left upper point of the dose voxel in world coordinate. + * + */ + WorldCoordinate3D getLeftUpperPoint() const; + LegacyWorldCoordinate3D getLeftUpperPointLegacy() const; + + /*! @brief Get (_deltaX, _deltaY, _deltaZ) of the dose voxel in world coordinate. + * + */ + WorldCoordinate3D getDelta() const; + LegacyWorldCoordinate3D getDeltaLegacy() const; + + /*! @brief Calculate the interseciton points with the segment [firstPoint, secontPoint]*/ + std::vector calcIntersectionPoints(WorldCoordinate3D firstPoint, + WorldCoordinate3D secondPoint); + //same method with legacy data structures + std::vector calcIntersectionPoints(LegacyWorldCoordinate3D firstPoint, + LegacyWorldCoordinate3D secondPoint); + + /*! @brief Get the voxel index*/ + const LegacyDoseVoxelIndex3D& getVoxelIndex3D() const; + + /*! @brief Get the geometric information*/ + const core::GeometricInfo* getGeometricInfo() const; + + /*! @brief Set the voxel proportion inside a given structure*/ + void setProportionInStr(FractionType aProportionInStr); + + /*! @brief Get the voxel proportion inside a given structure*/ + FractionType getProportionInStr() const; + }; + } + } } #endif diff --git a/code/masks/legacy/rttbBaseType_LEGACY.h b/code/masks/legacy/rttbBaseType_LEGACY.h index 16a7e01..560c3c0 100644 --- a/code/masks/legacy/rttbBaseType_LEGACY.h +++ b/code/masks/legacy/rttbBaseType_LEGACY.h @@ -1,254 +1,294 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __RT_BASE_TYPE_H #define __RT_BASE_TYPE_H #include #include #include #include #include #include #include "rttbBaseType.h" -namespace rttb{ - namespace masks{ - namespace legacy{ - - typedef double LegacyWorldCoordinate1D; - - struct LegacyWorldCoordinate2D{ - LegacyWorldCoordinate1D x; - LegacyWorldCoordinate1D y; - - std::string toString() const{ - std::stringstream sstr; - sstr<<"("<x = 0; - this->y = 0; - this->z = 0; - } - - LegacyWorldCoordinate3D( LegacyWorldCoordinate1D a, LegacyWorldCoordinate1D b, LegacyWorldCoordinate1D c){ - this->x = a; - this->y = b; - this->z = c; - } - - LegacyWorldCoordinate3D(rttb::WorldCoordinate3D aCoordinate){ - this->x = aCoordinate.x(); - this->y = aCoordinate.y(); - this->z = aCoordinate.z(); - } - - bool operator==(const LegacyWorldCoordinate3D& p) const - { - return(x==p.x && y==p.y && z==p.z); - } - - /** assigment operator - * @param copy LegacyWorldCoordinate3D object to be copied - */ - LegacyWorldCoordinate3D& operator=(const LegacyWorldCoordinate3D& copy){ - if (this != ©) - { - x=copy.x; - y=copy.y; - z=copy.z; - } - return *this; - } - //vector cross product (not included in boost.ublas) - LegacyWorldCoordinate3D cross(LegacyWorldCoordinate3D aVector) const{ - LegacyWorldCoordinate3D result; - LegacyWorldCoordinate1D x = this->x; - LegacyWorldCoordinate1D y = this->y; - LegacyWorldCoordinate1D z = this->z; - - result.x = y*aVector.z-z*aVector.y; - result.y = z*aVector.x-x*aVector.z; - result.z = x*aVector.y-y*aVector.x; - - return result; - } - - }LegacyImageOrientation; - - - - - - typedef int LegacyDoseVoxelIndex1D; - - - struct LegacyDoseVoxelIndex3D{ - LegacyDoseVoxelIndex1D x; - LegacyDoseVoxelIndex1D y; - LegacyDoseVoxelIndex1D z; - - std::string toString() const{ - std::stringstream sstr; - sstr<<"("<index.z) - return false; - else{ - if(yindex.y) - return false; - else{ - if(xx = 0; + this->y = 0; + this->z = 0; + } + + LegacyWorldCoordinate3D(LegacyWorldCoordinate1D a, LegacyWorldCoordinate1D b, + LegacyWorldCoordinate1D c) + { + this->x = a; + this->y = b; + this->z = c; + } + + LegacyWorldCoordinate3D(rttb::WorldCoordinate3D aCoordinate) + { + this->x = aCoordinate.x(); + this->y = aCoordinate.y(); + this->z = aCoordinate.z(); + } + + bool operator==(const LegacyWorldCoordinate3D& p) const + { + return (x == p.x && y == p.y && z == p.z); + } + + /** assigment operator + * @param copy LegacyWorldCoordinate3D object to be copied + */ + LegacyWorldCoordinate3D& operator=(const LegacyWorldCoordinate3D& copy) + { + if (this != ©) + { + x = copy.x; + y = copy.y; + z = copy.z; + } + + return *this; + } + //vector cross product (not included in boost.ublas) + LegacyWorldCoordinate3D cross(LegacyWorldCoordinate3D aVector) const + { + LegacyWorldCoordinate3D result; + LegacyWorldCoordinate1D x = this->x; + LegacyWorldCoordinate1D y = this->y; + LegacyWorldCoordinate1D z = this->z; + + result.x = y * aVector.z - z * aVector.y; + result.y = z * aVector.x - x * aVector.z; + result.z = x * aVector.y - y * aVector.x; + + return result; + } + + } LegacyImageOrientation; + + + + + + typedef int LegacyDoseVoxelIndex1D; + + + struct LegacyDoseVoxelIndex3D + { + LegacyDoseVoxelIndex1D x; + LegacyDoseVoxelIndex1D y; + LegacyDoseVoxelIndex1D z; + + std::string toString() const + { + std::stringstream sstr; + sstr << "(" << x << "," << y << "," << z << ")"; + return sstr.str(); + } + + bool operator<(const LegacyDoseVoxelIndex3D& index) const + { + if (z < index.z) + { + return true; + } + else if (z > index.z) + { + return false; + } + else + { + if (y < index.y) + { + return true; + } + else if (y > index.y) + { + return false; + } + else + { + if (x < index.x) + { + return true; + } + else + { + return false; + } + } + } + } + + }; + + typedef struct + { + LegacyDoseVoxelIndex1D x; + LegacyDoseVoxelIndex1D y; + + std::string toString() const + { + std::stringstream sstr; + sstr << "(" << x << "," << y << ")"; + return sstr.str(); + } + + + } LegacyDoseVoxelIndex2D; + + + typedef unsigned short LegacyUnsignedIndex1D; + + typedef struct + { + LegacyUnsignedIndex1D x; + LegacyUnsignedIndex1D y; + } LegacyUnsignedIndex2D; + + typedef struct + { + LegacyUnsignedIndex1D x; + LegacyUnsignedIndex1D y; + LegacyUnsignedIndex1D z; + } LegacyUnsignedIndex3D; - }LegacyDoseVoxelIndex2D; + typedef std::vector LegacyPolygonType; + typedef std::vector LegacyPolygonSequenceType; - typedef unsigned short LegacyUnsignedIndex1D; - typedef struct{ - LegacyUnsignedIndex1D x; - LegacyUnsignedIndex1D y; - }LegacyUnsignedIndex2D; + typedef struct + { - typedef struct{ - LegacyUnsignedIndex1D x; - LegacyUnsignedIndex1D y; - LegacyUnsignedIndex1D z; - }LegacyUnsignedIndex3D; + LegacyWorldCoordinate1D x_begin; - typedef std::vector LegacyPolygonType; + LegacyWorldCoordinate1D x_end; - typedef std::vector LegacyPolygonSequenceType; + LegacyWorldCoordinate1D y_begin; + LegacyWorldCoordinate1D y_end; + + LegacyDoseVoxelIndex2D index_begin; + + LegacyDoseVoxelIndex2D index_end; + + void Init() + { + x_begin = -1000000; + x_end = -1000000; + y_begin = -1000000; + y_end = -1000000; + index_begin.x = 0; + index_begin.y = 0; + index_end.x = 0; + index_end.y = 0; + + } + + } LegacyArea2D; + + typedef struct + { + LegacyWorldCoordinate2D begin; + LegacyWorldCoordinate2D end; + } LegacySegment2D; + + typedef struct + { + LegacyWorldCoordinate3D begin; + LegacyWorldCoordinate3D end; + } LegacySegment3D; - typedef struct{ + /*! @brief area_vector specifies an image region. So its a vector of 2d areas. That means it is a 3D area. + */ + typedef std::vector area_vector; + typedef std::vector< std::vector > vector_of_area_vectors; - LegacyWorldCoordinate1D x_begin; - - LegacyWorldCoordinate1D x_end; - - LegacyWorldCoordinate1D y_begin; - - LegacyWorldCoordinate1D y_end; - - LegacyDoseVoxelIndex2D index_begin; - - LegacyDoseVoxelIndex2D index_end; - - void Init(){ - x_begin = -1000000; - x_end = -1000000; - y_begin = -1000000; - y_end = -1000000; - index_begin.x = 0; - index_begin.y = 0; - index_end.x = 0; - index_end.y = 0; - - } - - }LegacyArea2D; - - typedef struct{ - LegacyWorldCoordinate2D begin; - LegacyWorldCoordinate2D end; - }LegacySegment2D; - - typedef struct{ - LegacyWorldCoordinate3D begin; - LegacyWorldCoordinate3D end; - }LegacySegment3D; - - /*! @brief area_vector specifies an image region. So its a vector of 2d areas. That means it is a 3D area. - */ - typedef std::vector area_vector; - typedef std::vector< std::vector > vector_of_area_vectors; - -} + } - } + } } #endif diff --git a/code/masks/legacy/rttbContour_LEGACY.cpp b/code/masks/legacy/rttbContour_LEGACY.cpp index 7ec0657..be5658e 100644 --- a/code/masks/legacy/rttbContour_LEGACY.cpp +++ b/code/masks/legacy/rttbContour_LEGACY.cpp @@ -1,442 +1,594 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbContour_LEGACY.h" #include #include #include -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { - - Contour::Contour(LegacyPolygonType aPolygon) - { - _polygon=aPolygon; - } - /*Contour::Contour(int i){ + Contour::Contour(LegacyPolygonType aPolygon) + { + _polygon = aPolygon; + } + + /*Contour::Contour(int i){ - }*/ + }*/ - Contour::~Contour(){ - } + Contour::~Contour() + { + } - const LegacyPolygonType& Contour::getPolygon() const{ - return _polygon; - } + const LegacyPolygonType& Contour::getPolygon() const + { + return _polygon; + } - - /*calculate contour area*/ - double Contour::getArea() const{ - - double area=0; - size_t numberOfPoints=_polygon.size(); - for(int j1=0, j2=1; j1=std::min(q1.x,q2.x))&& - (std::max(q1.x,q2.x)>=std::min(p1.x,p2.x))&& - (std::max(p1.y,p2.y)>=std::min(q1.y,q2.y))&& - (std::max(q1.y,q2.y)>=std::min(p1.y,p2.y))&& - (multiply(q1,p2,p1)*multiply(p2,q2,p1)>=0)&& - (multiply(p1,q2,q1)*multiply(q2,p2,q1)>=0)); - //if(intersect) std::cout << "intersect: "<= pnt1.y ); - - GridIndexType i=0; - - do{ - i++; - - if(i==_polygon.size()) - pnt2=_polygon[0]; - else - pnt2 = _polygon[i]; - - //if the point lies on an edge of the polygon, return true - if((pnt2.y-aPoint.y)*(pnt1.x-pnt2.x)==(pnt2.x-aPoint.x)*(pnt1.y-pnt2.y) && - (aPoint.x>=std::min(pnt1.x,pnt2.x)) && (aPoint.x <=std::max(pnt1.x,pnt2.x)) && - (aPoint.y>=std::min(pnt1.y,pnt2.y)) && (aPoint.y <=std::max(pnt1.y,pnt2.y))) - return true; - - //else - flag2=( aPoint.y >= pnt2.y ); - if(flag1 != flag2) - { - if(((pnt2.y-aPoint.y)*(pnt1.x-pnt2.x)>=(pnt2.x-aPoint.x)*(pnt1.y-pnt2.y)) - ==flag2) - inside=!inside; - } - pnt1=pnt2; - flag1=flag2; - } while(i<_polygon.size()); - - //} - - - return inside; - } - - - - bool Contour::point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const{ - if(this->_polygon.size()>0){ - LegacyWorldCoordinate3D p; - p.x = aPoint.x; - p.y = aPoint.y; - p.z = this->_polygon.at(0).z; - return this->pointInPolygon(p); - } - else{ - std::cerr << "_polygon is empty! "<< std::endl; - return false; - } - } - - NumberOfEndpointsType Contour::getNumberOfEndpoints() const{ - - return _polygon.size(); - } - - LegacyPolygonType Contour::getMinimalBox() const{ - LegacyPolygonType box; - - WorldCoordinate maxX; - WorldCoordinate maxY; - WorldCoordinate minX; - WorldCoordinate minY; - WorldCoordinate z; - for(GridIndexType i=0;i<_polygon.size();i++){ - LegacyWorldCoordinate3D p=_polygon.at(i); - z=p.z; - if(i==0){ - minX=p.x; - minY=p.y; - maxX=p.x; - maxY=p.y; + + bool Contour::intersect(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, + const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2) + { + bool intersect = ((std::max(p1.x, p2.x) >= std::min(q1.x, q2.x)) && + (std::max(q1.x, q2.x) >= std::min(p1.x, p2.x)) && + (std::max(p1.y, p2.y) >= std::min(q1.y, q2.y)) && + (std::max(q1.y, q2.y) >= std::min(p1.y, p2.y)) && + (multiply(q1, p2, p1) * multiply(p2, q2, p1) >= 0) && + (multiply(p1, q2, q1) * multiply(q2, p2, q1) >= 0)); + //if(intersect) std::cout << "intersect: "<maxX) - maxX=p.x; - if(p.ymaxY) - maxY=p.y; + //parallel, intersect means in the same line + else + { + //return the mittel point of intersect as interpoint + p.x = (WorldCoordinate)((std::min(std::max(p1.x, p2.x), std::max(q1.x, + q2.x)) + std::max(std::min(p1.x, p2.x), std::min(q1.x, q2.x))) / 2); + p.y = (WorldCoordinate)((std::min(std::max(p1.y, p2.y), std::max(q1.y, + q2.y)) + std::max(std::min(p1.y, p2.y), std::min(q1.y, q2.y))) / 2); + } + + //std::cout << "p.x: " << p.x << std::endl; + //std::cout << "p.y: " << p.y << std::endl; + return p; } - LegacyWorldCoordinate3D pLU; - pLU.x = minX; pLU.y = minY; pLU.z = z; - LegacyWorldCoordinate3D pRU; - pRU.x = maxX; pRU.y = minY; pRU.z = z; - LegacyWorldCoordinate3D pRB; - pRB.x = maxX; pRB.y = maxY; pRB.z = z; - LegacyWorldCoordinate3D pLB; - pLB.x = minX; pLB.y = maxY; pLB.z = z; - box.push_back(pLU); - box.push_back(pRU); - box.push_back(pRB); - box.push_back(pLB); - return box; - } - - Contour* Contour::calcIntersection(Contour& contour2){ - - LegacyPolygonType box1=this->getMinimalBox(); - LegacyWorldCoordinate3D box1P1=box1.at(0); - LegacyWorldCoordinate3D box1P2=box1.at(1); - LegacyWorldCoordinate3D box1P3=box1.at(2); - LegacyWorldCoordinate3D box1P4=box1.at(3); - LegacyPolygonType box2=contour2.getMinimalBox(); - LegacyWorldCoordinate3D box2P1=box2.at(0); - LegacyWorldCoordinate3D box2P2=box2.at(1); - LegacyWorldCoordinate3D box2P3=box2.at(2); - LegacyWorldCoordinate3D box2P4=box2.at(3); - - Contour box1Contour=Contour(box1); - //if box1 and box2 have no intersection, that means no intersection between this contour and contour2 - if(!box1Contour.pointInPolygon(box2P1) && !box1Contour.pointInPolygon(box2P2) - && !box1Contour.pointInPolygon(box2P3) && !box1Contour.pointInPolygon(box2P4) ){ - //std::cout << "No intersection!"< segments1InBox2; - for(GridIndexType i=0;i<_polygon.size();i++){ - LegacyWorldCoordinate3D segmentL=_polygon.at(i);//segment left corner - LegacyWorldCoordinate3D segmentR;//segment right corner - if(i==_polygon.size()-1) - segmentR=_polygon.at(0); + bool Contour::pointInPolygon(const LegacyWorldCoordinate3D& aPoint) const + { + + + if (_polygon.size() == 0) + { + std::cerr << "_polygon is empty! " << std::endl; + return false; + } + + bool isZPlane = true; + + if (_polygon[0].z != aPoint.z) + { + isZPlane = false; + } + + bool inside = false; + + if (!isZPlane) + { + // std::cerr << "Make sure that the point and the polygon lies both in the z-plane"<= pnt1.y); + + GridIndexType i = 0; + + do + { + i++; + + if (i == _polygon.size()) + { + pnt2 = _polygon[0]; + } + else + { + pnt2 = _polygon[i]; + } + + //if the point lies on an edge of the polygon, return true + if ((pnt2.y - aPoint.y) * (pnt1.x - pnt2.x) == (pnt2.x - aPoint.x) * (pnt1.y - pnt2.y) && + (aPoint.x >= std::min(pnt1.x, pnt2.x)) && (aPoint.x <= std::max(pnt1.x, pnt2.x)) && + (aPoint.y >= std::min(pnt1.y, pnt2.y)) && (aPoint.y <= std::max(pnt1.y, pnt2.y))) + { + return true; + } + + //else + flag2 = (aPoint.y >= pnt2.y); + + if (flag1 != flag2) + { + if (((pnt2.y - aPoint.y) * (pnt1.x - pnt2.x) >= (pnt2.x - aPoint.x) * (pnt1.y - pnt2.y)) + == flag2) + { + inside = !inside; + } + } + + pnt1 = pnt2; + flag1 = flag2; + } + while (i < _polygon.size()); + + //} + + + return inside; + } + + + + bool Contour::point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const + { + if (this->_polygon.size() > 0) + { + LegacyWorldCoordinate3D p; + p.x = aPoint.x; + p.y = aPoint.y; + p.z = this->_polygon.at(0).z; + return this->pointInPolygon(p); + } else - segmentR=_polygon.at(i+1); + { + std::cerr << "_polygon is empty! " << std::endl; + return false; + } + } + + NumberOfEndpointsType Contour::getNumberOfEndpoints() const + { + + return _polygon.size(); + } + + LegacyPolygonType Contour::getMinimalBox() const + { + LegacyPolygonType box; + + WorldCoordinate maxX; + WorldCoordinate maxY; + WorldCoordinate minX; + WorldCoordinate minY; + WorldCoordinate z; + + for (GridIndexType i = 0; i < _polygon.size(); i++) + { + LegacyWorldCoordinate3D p = _polygon.at(i); + z = p.z; + + if (i == 0) + { + minX = p.x; + minY = p.y; + maxX = p.x; + maxY = p.y; + } - //if this segment not inside box2 - if(!(std::max(segmentL.x,segmentR.x)box2P2.x - || (std::max(segmentL.y,segmentR.y)box2P3.y))){ + if (p.x < minX) + { + minX = p.x; + } + + if (p.x > maxX) + { + maxX = p.x; + } + + if (p.y < minY) + { + minY = p.y; + } + + if (p.y > maxY) + { + maxY = p.y; + } + + } + + LegacyWorldCoordinate3D pLU; + pLU.x = minX; + pLU.y = minY; + pLU.z = z; + LegacyWorldCoordinate3D pRU; + pRU.x = maxX; + pRU.y = minY; + pRU.z = z; + LegacyWorldCoordinate3D pRB; + pRB.x = maxX; + pRB.y = maxY; + pRB.z = z; + LegacyWorldCoordinate3D pLB; + pLB.x = minX; + pLB.y = maxY; + pLB.z = z; + box.push_back(pLU); + box.push_back(pRU); + box.push_back(pRB); + box.push_back(pLB); + return box; + } + + Contour* Contour::calcIntersection(Contour& contour2) + { + + LegacyPolygonType box1 = this->getMinimalBox(); + LegacyWorldCoordinate3D box1P1 = box1.at(0); + LegacyWorldCoordinate3D box1P2 = box1.at(1); + LegacyWorldCoordinate3D box1P3 = box1.at(2); + LegacyWorldCoordinate3D box1P4 = box1.at(3); + LegacyPolygonType box2 = contour2.getMinimalBox(); + LegacyWorldCoordinate3D box2P1 = box2.at(0); + LegacyWorldCoordinate3D box2P2 = box2.at(1); + LegacyWorldCoordinate3D box2P3 = box2.at(2); + LegacyWorldCoordinate3D box2P4 = box2.at(3); + + Contour box1Contour = Contour(box1); + + //if box1 and box2 have no intersection, that means no intersection between this contour and contour2 + if (!box1Contour.pointInPolygon(box2P1) && !box1Contour.pointInPolygon(box2P2) + && !box1Contour.pointInPolygon(box2P3) && !box1Contour.pointInPolygon(box2P4)) + { + //std::cout << "No intersection!"< segments1InBox2; + + for (GridIndexType i = 0; i < _polygon.size(); i++) + { + LegacyWorldCoordinate3D segmentL = _polygon.at(i); //segment left corner + LegacyWorldCoordinate3D segmentR;//segment right corner + + if (i == _polygon.size() - 1) + { + segmentR = _polygon.at(0); + } + else + { + segmentR = _polygon.at(i + 1); + } + + //if this segment not inside box2 + if (!(std::max(segmentL.x, segmentR.x) < box2P1.x || std::min(segmentL.x, segmentR.x) > box2P2.x + || (std::max(segmentL.y, segmentR.y) < box2P1.y) || (std::min(segmentL.y, segmentR.y) > box2P3.y))) + { LegacySegment3D segment; - segment.begin=segmentL; - segment.end=segmentR; + segment.begin = segmentL; + segment.end = segmentR; segments1InBox2.push_back(segment); + } } - } - //Remove segments of contour2 which not inside box1 - std::vector segments2InBox1; - LegacyPolygonType polygon2=contour2.getPolygon(); - for(GridIndexType i=0;i segments2InBox1; + LegacyPolygonType polygon2 = contour2.getPolygon(); + + for (GridIndexType i = 0; i < polygon2.size(); i++) + { + LegacyWorldCoordinate3D segmentL = polygon2.at(i); //segment left corner + LegacyWorldCoordinate3D segmentR;//segment right corner + + if (i == polygon2.size() - 1) + { + segmentR = polygon2.at(0); + } + else + { + segmentR = polygon2.at(i + 1); + } - //if this segment not inside box2 - if(!(std::max(segmentL.x,segmentR.x)box1P2.x - || (std::max(segmentL.y,segmentR.y)box1P3.y))){ + //if this segment not inside box2 + if (!(std::max(segmentL.x, segmentR.x) < box1P1.x || std::min(segmentL.x, segmentR.x) > box1P2.x + || (std::max(segmentL.y, segmentR.y) < box1P1.y) || (std::min(segmentL.y, segmentR.y) > box1P3.y))) + { LegacySegment3D segment; - segment.begin=segmentL; - segment.end=segmentR; + segment.begin = segmentL; + segment.end = segmentR; segments2InBox1.push_back(segment); + } } - } - //Get the points of this contour inside contour2 and all intersect points - std::vector points1InContour2;//store points of this contour inside contour2 and all intersect points - std::vector::iterator it; - std::vector::iterator it2; - for(it=segments1InBox2.begin();it!=segments1InBox2.end();it++){ - LegacySegment3D segment=*it; - if(contour2.pointInPolygon(segment.begin)) - points1InContour2.push_back(segment.begin); - - //test: if segment has intersection with any segment in segments2InBox1 - for(it2=segments2InBox1.begin();it2!=segments2InBox1.end();it2++){ - if(Contour::intersect(segment.begin,segment.end,(*it2).begin,(*it2).end)){ - LegacyWorldCoordinate3D interP=Contour::calcInterPoint(segment.begin,segment.end,(*it2).begin,(*it2).end); - if(Contour(points1InContour2).contains(interP)) - points1InContour2.push_back(interP); + //Get the points of this contour inside contour2 and all intersect points + std::vector + points1InContour2;//store points of this contour inside contour2 and all intersect points + std::vector::iterator it; + std::vector::iterator it2; + + for (it = segments1InBox2.begin(); it != segments1InBox2.end(); it++) + { + LegacySegment3D segment = *it; + + if (contour2.pointInPolygon(segment.begin)) + { + points1InContour2.push_back(segment.begin); + } + + //test: if segment has intersection with any segment in segments2InBox1 + for (it2 = segments2InBox1.begin(); it2 != segments2InBox1.end(); it2++) + { + if (Contour::intersect(segment.begin, segment.end, (*it2).begin, (*it2).end)) + { + LegacyWorldCoordinate3D interP = Contour::calcInterPoint(segment.begin, segment.end, (*it2).begin, + (*it2).end); + + if (Contour(points1InContour2).contains(interP)) + { + points1InContour2.push_back(interP); + } + } } } - } - //sort points1InContour2 clockwise - Contour tempContour=Contour(points1InContour2); - tempContour.sortClockwise(); - points1InContour2=tempContour.getPolygon(); - - - //Get the points of contour2 inside this contour and all intersect points - std::vector points2InContour1;//store points of contour2 inside this contour and all intersect points - for(it=segments2InBox1.begin();it!=segments2InBox1.end();it++){ - LegacySegment3D segment=*it; - if(pointInPolygon(segment.begin)) - points2InContour1.push_back(segment.begin); - - //test: if segment has intersection with any segment in segments2InBox1 - for(it2=segments1InBox2.begin();it2!=segments1InBox2.end();it2++){ - if(Contour::intersect(segment.begin,segment.end,(*it2).begin,(*it2).end)){ - LegacyWorldCoordinate3D interP=Contour::calcInterPoint(segment.begin,segment.end,(*it2).begin,(*it2).end); - if(Contour(points2InContour1).contains(interP)) - points2InContour1.push_back(interP); + + //sort points1InContour2 clockwise + Contour tempContour = Contour(points1InContour2); + tempContour.sortClockwise(); + points1InContour2 = tempContour.getPolygon(); + + + //Get the points of contour2 inside this contour and all intersect points + std::vector + points2InContour1;//store points of contour2 inside this contour and all intersect points + + for (it = segments2InBox1.begin(); it != segments2InBox1.end(); it++) + { + LegacySegment3D segment = *it; + + if (pointInPolygon(segment.begin)) + { + points2InContour1.push_back(segment.begin); + } + + //test: if segment has intersection with any segment in segments2InBox1 + for (it2 = segments1InBox2.begin(); it2 != segments1InBox2.end(); it2++) + { + if (Contour::intersect(segment.begin, segment.end, (*it2).begin, (*it2).end)) + { + LegacyWorldCoordinate3D interP = Contour::calcInterPoint(segment.begin, segment.end, (*it2).begin, + (*it2).end); + + if (Contour(points2InContour1).contains(interP)) + { + points2InContour1.push_back(interP); + } + } } } - } - //sort points1InContour2 clockwise - tempContour=Contour(points2InContour1); - tempContour.sortClockwise(); - points2InContour1=tempContour.getPolygon(); + + //sort points1InContour2 clockwise + tempContour = Contour(points2InContour1); + tempContour.sortClockwise(); + points2InContour1 = tempContour.getPolygon(); - LegacyPolygonType intersectionPolygon=points1InContour2; - LegacyPolygonType::iterator itP; - for(itP=points2InContour1.begin();itP!=points2InContour1.end();itP++){ - if(!Contour(intersectionPolygon).contains((*itP))) - intersectionPolygon.push_back((*itP)); + LegacyPolygonType intersectionPolygon = points1InContour2; + LegacyPolygonType::iterator itP; + for (itP = points2InContour1.begin(); itP != points2InContour1.end(); itP++) + { + if (!Contour(intersectionPolygon).contains((*itP))) + { + intersectionPolygon.push_back((*itP)); + } + + } + + //sort intersectionPolygon + Contour* intersection = new Contour(intersectionPolygon); + intersection->sortClockwise(); + + return intersection; } - //sort intersectionPolygon - Contour* intersection=new Contour(intersectionPolygon); - intersection->sortClockwise(); - - return intersection; - } - - /*! @brief Sort the points in _polygon in clockwise order*/ - void Contour::sortClockwise(){ - size_t numberOfP=_polygon.size(); - if(numberOfP>=3){ - LegacyWorldCoordinate3D p1=_polygon.at(0); - LegacyWorldCoordinate3D p2=_polygon.at(1); - LegacyWorldCoordinate3D p3=_polygon.at(2); - - LegacyWorldCoordinate2D pInPolygon = {(p1.x+p2.x+p3.x)/3,(p1.y+p2.y+p3.y)/3};//get a point inside the polygon - - std::map pointsI; - std::map pointsII; - std::map pointsIII; - std::map pointsIV; - for(int i=0;i=0 && dy>=0){ - pointsI.insert(std::pair(sin*(-1.0),p)); + + /*! @brief Sort the points in _polygon in clockwise order*/ + void Contour::sortClockwise() + { + size_t numberOfP = _polygon.size(); + + if (numberOfP >= 3) + { + LegacyWorldCoordinate3D p1 = _polygon.at(0); + LegacyWorldCoordinate3D p2 = _polygon.at(1); + LegacyWorldCoordinate3D p3 = _polygon.at(2); + + LegacyWorldCoordinate2D pInPolygon = {(p1.x + p2.x + p3.x) / 3, (p1.y + p2.y + p3.y) / 3}; //get a point inside the polygon + + std::map pointsI; + std::map pointsII; + std::map pointsIII; + std::map pointsIV; + + for (int i = 0; i < numberOfP; i++) + { + LegacyWorldCoordinate3D p = _polygon.at(i); + double dx = p.x - pInPolygon.x; + double dy = p.y - pInPolygon.y; + double ds = sqrt(dx * dx + dy * dy); + double sin = dy / ds; + + if (dx >= 0 && dy >= 0) + { + pointsI.insert(std::pair(sin * (-1.0), p)); + } + else if (dx >= 0 && dy < 0) + { + pointsIV.insert(std::pair(sin * (-1.0), p)); + } + else if (dx < 0 && dy < 0) + { + pointsIII.insert(std::pair(sin, p)); + } + else + { + pointsII.insert(std::pair(sin, p)); + } } - else if(dx>=0 && dy<0) - pointsIV.insert(std::pair(sin*(-1.0),p)); - else if(dx<0 && dy<0) - pointsIII.insert(std::pair(sin,p)); - else - pointsII.insert(std::pair(sin,p)); + + LegacyPolygonType sorted; + std::map::iterator it; + + for (it = pointsII.begin(); it != pointsII.end(); it++) + { + sorted.push_back((*it).second); + } + + for (it = pointsI.begin(); it != pointsI.end(); it++) + { + sorted.push_back((*it).second); + } + + for (it = pointsIV.begin(); it != pointsIV.end(); it++) + { + sorted.push_back((*it).second); + } + + for (it = pointsIII.begin(); it != pointsIII.end(); it++) + { + sorted.push_back((*it).second); + } + + _polygon = sorted; + } - LegacyPolygonType sorted; - std::map::iterator it; - for(it=pointsII.begin();it!=pointsII.end();it++) - sorted.push_back((*it).second); - for(it=pointsI.begin();it!=pointsI.end();it++) - sorted.push_back((*it).second); - for(it=pointsIV.begin();it!=pointsIV.end();it++) - sorted.push_back((*it).second); - for(it=pointsIII.begin();it!=pointsIII.end();it++) - sorted.push_back((*it).second); + } - _polygon=sorted; + std::string Contour::toString() const + { + std::stringstream sstr; + sstr << "{"; + + for (GridIndexType i = 0; i < _polygon.size(); i++) + { + sstr << _polygon.at(i).toString() << ", "; + } + sstr << "}"; + return sstr.str(); } - } - - std::string Contour::toString() const{ - std::stringstream sstr; - sstr<<"{"; - for(GridIndexType i=0;i<_polygon.size();i++) - sstr<<_polygon.at(i).toString()<<", "; - sstr<<"}"; - return sstr.str(); - } - - bool Contour::contains(const LegacyWorldCoordinate3D& aPoint) const{ - for(GridIndexType i=0;i<_polygon.size();i++){ - if(aPoint==_polygon.at(i)) - return true; + bool Contour::contains(const LegacyWorldCoordinate3D& aPoint) const + { + for (GridIndexType i = 0; i < _polygon.size(); i++) + { + if (aPoint == _polygon.at(i)) + { + return true; + } + } + + return false; } - return false; - } -}//end namespace legacy + }//end namespace legacy }//end namespace masks }//end namespace rttb diff --git a/code/masks/legacy/rttbContour_LEGACY.h b/code/masks/legacy/rttbContour_LEGACY.h index c7b67f3..d999e39 100644 --- a/code/masks/legacy/rttbContour_LEGACY.h +++ b/code/masks/legacy/rttbContour_LEGACY.h @@ -1,129 +1,138 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __CONTOUR_H #define __CONTOUR_H #include #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" -namespace rttb{ - - namespace masks{ - namespace legacy{ - - typedef size_t NumberOfEndpointsType; - - /*! @class Contour - * @brief This is a class representing a RT Contour. A RT contour is either a single point (for a point ROI) or more than - * one point (representing an open or closed polygon). - */ - class Contour - { - - private: - /*! @brief WorldCoordinate3D in mm - */ - LegacyPolygonType _polygon; - - static double multiply(const LegacyWorldCoordinate3D& p1,const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& p0); - - static LegacyWorldCoordinate2D calcInterPoint2D(const LegacyWorldCoordinate2D& p1, const LegacyWorldCoordinate2D& p2, const LegacyWorldCoordinate2D& q1, const LegacyWorldCoordinate2D& q2); - - public: - - //Contour(int i); - /*! @brief Contour Constructor - @param aPolygon: a polygon used to generate the contour - */ - Contour(LegacyPolygonType aPolygon); - - /*! @brief Destructor - */ - ~Contour(); - - /*! @brief Calculate contour area using Formel 0.5*abs(x1*y2-y1*x2+x2*y3-y2*x3+...+xn*y1-yn*x1) - @return Return a double value of contour area - */ - double getArea() const; - - /*! @brief Tests if a point is inside _polygon. If the point lies on an edge of the polygon, return true - *! Make sure that the point and the list of positions lies both in the z-plane - */ - bool pointInPolygon(const LegacyWorldCoordinate3D& aPoint) const; - - /*! @brief Tests if a 2Dpoint is inside _polygon in 2D. If the point lies on an edge of the polygon, return true - * - */ - bool point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const; - - /*! @brief Get the polygon - */ - const LegacyPolygonType& getPolygon() const; - - /*! @brief Tests if a point is inside the polygon defined by the given list of positions. - ! Make sure that the point and the list of positions lies both in the z-plane - */ - //bool pointInStructure(const WorldCoordinate3D& aPoint) const; - - /*! @brief Get the number of end points of the polygon*/ - NumberOfEndpointsType getNumberOfEndpoints() const; - - /*! @brief Get the minimal bounding box - * @return Return Polygon{{minX,minY,z},{maxX,minY,z},{maxX,maxY,z},{minX,maxY,z}} - */ - LegacyPolygonType getMinimalBox() const; - - /*! @brief Get the intersection of this Contour and contour2 - ! Make sure that the 2 Contours lies both in the z-plane - * @return Return NULL if no intersection - */ - Contour* calcIntersection(Contour& contour2); - - /*! @brief Sort the points in _polygon in clockwise order*/ - void sortClockwise(); - - /*! @brief Calculate the intersection between the two segments (p1,p2) and (q1,q2) - * Make sure that the points lies in the same z-plane - */ - static LegacyWorldCoordinate3D calcInterPoint(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2); - - /*! @brief Tests if an intersection exists between two segments (p1, p2) and (q1, q2) */ - static bool intersect(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2); - - std::string toString() const; - - /*! @brief If aPoint stored in _polygon - */ - bool contains(const LegacyWorldCoordinate3D& aPoint) const; - - }; - } - } +namespace rttb +{ + + namespace masks + { + namespace legacy + { + + typedef size_t NumberOfEndpointsType; + + /*! @class Contour + * @brief This is a class representing a RT Contour. A RT contour is either a single point (for a point ROI) or more than + * one point (representing an open or closed polygon). + */ + class Contour + { + + private: + /*! @brief WorldCoordinate3D in mm + */ + LegacyPolygonType _polygon; + + static double multiply(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, + const LegacyWorldCoordinate3D& p0); + + static LegacyWorldCoordinate2D calcInterPoint2D(const LegacyWorldCoordinate2D& p1, + const LegacyWorldCoordinate2D& p2, const LegacyWorldCoordinate2D& q1, + const LegacyWorldCoordinate2D& q2); + + public: + + //Contour(int i); + /*! @brief Contour Constructor + @param aPolygon: a polygon used to generate the contour + */ + Contour(LegacyPolygonType aPolygon); + + /*! @brief Destructor + */ + ~Contour(); + + /*! @brief Calculate contour area using Formel 0.5*abs(x1*y2-y1*x2+x2*y3-y2*x3+...+xn*y1-yn*x1) + @return Return a double value of contour area + */ + double getArea() const; + + /*! @brief Tests if a point is inside _polygon. If the point lies on an edge of the polygon, return true + *! Make sure that the point and the list of positions lies both in the z-plane + */ + bool pointInPolygon(const LegacyWorldCoordinate3D& aPoint) const; + + /*! @brief Tests if a 2Dpoint is inside _polygon in 2D. If the point lies on an edge of the polygon, return true + * + */ + bool point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const; + + /*! @brief Get the polygon + */ + const LegacyPolygonType& getPolygon() const; + + /*! @brief Tests if a point is inside the polygon defined by the given list of positions. + ! Make sure that the point and the list of positions lies both in the z-plane + */ + //bool pointInStructure(const WorldCoordinate3D& aPoint) const; + + /*! @brief Get the number of end points of the polygon*/ + NumberOfEndpointsType getNumberOfEndpoints() const; + + /*! @brief Get the minimal bounding box + * @return Return Polygon{{minX,minY,z},{maxX,minY,z},{maxX,maxY,z},{minX,maxY,z}} + */ + LegacyPolygonType getMinimalBox() const; + + /*! @brief Get the intersection of this Contour and contour2 + ! Make sure that the 2 Contours lies both in the z-plane + * @return Return NULL if no intersection + */ + Contour* calcIntersection(Contour& contour2); + + /*! @brief Sort the points in _polygon in clockwise order*/ + void sortClockwise(); + + /*! @brief Calculate the intersection between the two segments (p1,p2) and (q1,q2) + * Make sure that the points lies in the same z-plane + */ + static LegacyWorldCoordinate3D calcInterPoint(const LegacyWorldCoordinate3D& p1, + const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& q1, + const LegacyWorldCoordinate3D& q2); + + /*! @brief Tests if an intersection exists between two segments (p1, p2) and (q1, q2) */ + static bool intersect(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, + const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2); + + std::string toString() const; + + /*! @brief If aPoint stored in _polygon + */ + bool contains(const LegacyWorldCoordinate3D& aPoint) const; + + }; + } + } } #endif diff --git a/code/masks/legacy/rttbField_LEGACY.h b/code/masks/legacy/rttbField_LEGACY.h index 63480b9..7c2cb26 100644 --- a/code/masks/legacy/rttbField_LEGACY.h +++ b/code/masks/legacy/rttbField_LEGACY.h @@ -1,594 +1,708 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 __FIELD_H #define __FIELD_H #include #include #include "rttbBaseType.h" #include "rttbMaskType_LEGACY.h" #include "rttbBaseType_LEGACY.h" #include "rttbIndexOutOfBoundsException.h" -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { /*! @class BaseField @brief This is a class representing a field to be inherited. */ class BaseField { public: - BaseField(){} + BaseField() {} - BaseField( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ):dimx(dimx_in), dimy(dimy_in), dimz(dimz_in){} + BaseField(Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in): dimx(dimx_in), dimy(dimy_in), + dimz(dimz_in) {} /*! @return extend of the field in x-direction. */ - virtual Uint16 GetDimX(){ return dimx; } + virtual Uint16 GetDimX() + { + return dimx; + } /*! @return extend of the field in y-direction. */ - virtual Uint16 GetDimY(){ return dimy; } + virtual Uint16 GetDimY() + { + return dimy; + } /*! @return extend of the field in z-direction. */ - virtual Uint16 GetDimZ(){ return dimz; } + virtual Uint16 GetDimZ() + { + return dimz; + } protected: Uint16 dimx; Uint16 dimy; - Uint16 dimz; + Uint16 dimz; }; /*! @class FieldOfScalar @brief This is a class representing a field of scalar values - @todo uses UnsignedIndexList and other types from legacy code. Needs to be reimplemented. Close connection to + @todo uses UnsignedIndexList and other types from legacy code. Needs to be reimplemented. Close connection to legacy mask need to be resolved. */ template class FieldOfScalar : public BaseField { public: /*! @param dimx_in field extend in direction x. @param dimy_in field extend in direction y. @param dimz_in field extend in direction z. */ - FieldOfScalar( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ): BaseField( dimx_in , dimy_in , dimz_in ) + FieldOfScalar(Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in): BaseField(dimx_in , dimy_in , + dimz_in) { create(); } - ~FieldOfScalar(){ + ~FieldOfScalar() + { clear(); } typedef TYPE type; /*! @brief Get the data stored in this FieldOfScalar at index (x,y,z) @return value of interest @exception IndexOutOfBoundsException */ - inline TYPE GetData( Uint16 x, Uint16 y, Uint16 z ); + inline TYPE GetData(Uint16 x, Uint16 y, Uint16 z); /*! @brief Set all values to zero. */ void SetZero(); /*! @brief Set value at index (x,y,z) to value. @exception IndexOutOfBoundsException */ - inline void PutData( Uint16 x, Uint16 y, Uint16 z , TYPE value ); + inline void PutData(Uint16 x, Uint16 y, Uint16 z , TYPE value); - /*! @brief Check whether a 3D block of the length block_length with upper left corner (x,y,z) has the + /*! @brief Check whether a 3D block of the length block_length with upper left corner (x,y,z) has the intensity of value. @return True if the entire block does have the value of interest. */ - bool CheckBlockSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); + bool CheckBlockSameIntensity(Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value); - /*! @brief Set 3D block of the length block_length with upper left corner (x,y,z) to the value of input + /*! @brief Set 3D block of the length block_length with upper left corner (x,y,z) to the value of input parameter "value". - */ - void SetBlockThisIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); + */ + void SetBlockThisIntensity(Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value); - /*! @brief This function investigates a specific area of the field, given by the parameter av. Those voxels - that are yet not clearly determined to be located inside or outside the contour and that are not part of - the border region are of interest. Depending on the neighbours of these voxels they are now defined as + /*! @brief This function investigates a specific area of the field, given by the parameter av. Those voxels + that are yet not clearly determined to be located inside or outside the contour and that are not part of + the border region are of interest. Depending on the neighbours of these voxels they are now defined as inside or outside, if possible. @param av Specifies the region of interest within the field. - @param indexListInside The function fills this list with voxels that are determined inside during this + @param indexListInside The function fills this list with voxels that are determined inside during this procedure. - @param indexListOutside The function fills this list with voxels that are determined outside during this + @param indexListOutside The function fills this list with voxels that are determined outside during this procedure. - @param unclear_intensity Intensity or value (does not necessarily have to be an intensity) that + @param unclear_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes uncertainty with respect to association (inside/outside). - @param inside_intensity Intensity or value (does not necessarily have to be an intensity) that + @param inside_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes inside. - @param outside_intensity Intensity or value (does not necessarily have to be an intensity) that + @param outside_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes outside. */ - void GetBorderRegion( masks::legacy::area_vector av, - std::vector< masks::legacy::UnsignedIndexList >& indexListInside , - std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, - TYPE inside_intensity , TYPE outside_intensity ); + void GetBorderRegion(masks::legacy::area_vector av, + std::vector< masks::legacy::UnsignedIndexList >& indexListInside , + std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, + TYPE inside_intensity , TYPE outside_intensity); /*! @returns true in case one of the voxels within the regarded block does have the value "value". @param x x-position of the upper left corner of the block under investigation. @param y y-position of the upper left corner of the block under investigation. @param z z-position of the upper left corner of the block under investigation. @param block_length lenght of the block that is processed. - */ - bool CheckOneOutOfThisBlockHasSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); + */ + bool CheckOneOutOfThisBlockHasSameIntensity(Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , + TYPE value); private: /*! Return to initial state. */ void clear(); /*! Initialize all. */ void create(); TYPE* data; /*! Number of values within a slice. */ int slice_size; /*! Number of values within a raw. */ Uint16 raw_size; /*! Number of values within the field. */ int cube_size; - }; + }; template - void FieldOfScalar::SetZero(){ - int size = ( dimz * dimy * dimx ) * sizeof(TYPE); - memset( data , 0 , size ); + void FieldOfScalar::SetZero() + { + int size = (dimz * dimy * dimx) * sizeof(TYPE); + memset(data , 0 , size); } template - inline TYPE FieldOfScalar::GetData( Uint16 x, Uint16 y, Uint16 z ){ + inline TYPE FieldOfScalar::GetData(Uint16 x, Uint16 y, Uint16 z) + { TYPE val; int offset; - offset = ( z * slice_size + y * raw_size + x ) ; + offset = (z * slice_size + y * raw_size + x) ; - if(offset<0) + if (offset < 0) { - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) { - val = *( (TYPE*) data + offset ); + val = *((TYPE*) data + offset); return val; } - else{ - throw core::IndexOutOfBoundsException( " Out of range ! " ); + else + { + throw core::IndexOutOfBoundsException(" Out of range ! "); } } template - inline void FieldOfScalar::PutData( Uint16 x, Uint16 y, Uint16 z, TYPE value ){ + inline void FieldOfScalar::PutData(Uint16 x, Uint16 y, Uint16 z, TYPE value) + { int offset; - if( x >= dimx ) + if (x >= dimx) { - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } - if( y >= dimy ) + + if (y >= dimy) { - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } - if( z >= dimz ) + + if (z >= dimz) { - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } - offset = ( z * slice_size + y * raw_size + x ) ; + offset = (z * slice_size + y * raw_size + x) ; - if(offset<0) + if (offset < 0) { - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) + { + *((TYPE*) data + offset) = value; + } + else { - *( (TYPE*) data + offset ) = value; - } - else{ - throw core::IndexOutOfBoundsException( " Out of range ! " ); + throw core::IndexOutOfBoundsException(" Out of range ! "); } } template - void FieldOfScalar::clear(){ - free(data); + void FieldOfScalar::clear() + { + free(data); } template - void FieldOfScalar::create(){ - int size = ( dimz * dimy * dimx ) * sizeof(TYPE); - data = (type*) malloc( size ); + void FieldOfScalar::create() + { + int size = (dimz * dimy * dimx) * sizeof(TYPE); + data = (type*) malloc(size); slice_size = dimy * dimx; raw_size = dimx; cube_size = dimy * dimx * dimz; - memset( data , 0, cube_size * sizeof(TYPE) ); + memset(data , 0, cube_size * sizeof(TYPE)); } template - bool FieldOfScalar::CheckBlockSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ){ - if( x >= dimx ) + bool FieldOfScalar::CheckBlockSameIntensity(Uint16 x, Uint16 y, Uint16 z , + Uint16 block_length , TYPE value) + { + if (x >= dimx) { assert(0); } - if( y >= dimy ) + + if (y >= dimy) { assert(0); } - if( z >= dimz ) + + if (z >= dimz) { assert(0); } Uint16 x_block_length = block_length; - if( ( (dimx-1) - x ) <= x_block_length ) + + if (((dimx - 1) - x) <= x_block_length) { - x_block_length = ( (dimx-1) - x ); + x_block_length = ((dimx - 1) - x); } - Uint16 y_block_length = block_length; - if( ( (dimy-1) - y ) <= y_block_length ) + + Uint16 y_block_length = block_length; + + if (((dimy - 1) - y) <= y_block_length) { - y_block_length = ( (dimy-1) - y ); + y_block_length = ((dimy - 1) - y); } TYPE* local_data_pointer; - for( int pos = 0 ; pos < y_block_length ; pos++ ){ + for (int pos = 0 ; pos < y_block_length ; pos++) + { - int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; + int offset = (z * slice_size + (y + pos) * raw_size + x) ; - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) { - local_data_pointer = (TYPE*) (data + offset); + local_data_pointer = (TYPE*)(data + offset); - for( Uint16 counter = 0 ; counter < x_block_length ; counter++ ){ + for (Uint16 counter = 0 ; counter < x_block_length ; counter++) + { - if( *(local_data_pointer) != value ) + if (*(local_data_pointer) != value) { return false; - } + } + local_data_pointer++; } } // if offset - else{ + else + { assert(0); } - } // for pos + } // for pos + return true; } template - void FieldOfScalar::SetBlockThisIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ){ - if( x >= dimx ) + void FieldOfScalar::SetBlockThisIntensity(Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , + TYPE value) + { + if (x >= dimx) { assert(0); } - if( y >= dimy ) + + if (y >= dimy) { assert(0); } - if( z >= dimz ) + + if (z >= dimz) { assert(0); } Uint16 x_block_length = block_length; - if( ( (dimx-1) - x ) <= x_block_length ) + + if (((dimx - 1) - x) <= x_block_length) { - x_block_length = ( (dimx-1) - x ); + x_block_length = ((dimx - 1) - x); } - Uint16 y_block_length = block_length; - if( ( (dimy-1) - y ) <= y_block_length ) + + Uint16 y_block_length = block_length; + + if (((dimy - 1) - y) <= y_block_length) { - y_block_length = ( (dimy-1) - y ); + y_block_length = ((dimy - 1) - y); } TYPE* local_data_pointer; - for( int pos = 0 ; pos < y_block_length ; pos++ ){ - int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; + for (int pos = 0 ; pos < y_block_length ; pos++) + { + int offset = (z * slice_size + (y + pos) * raw_size + x) ; - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) { - local_data_pointer = (TYPE*) (data + offset); + local_data_pointer = (TYPE*)(data + offset); - for( Uint16 counter = 0 ; counter < x_block_length ; counter++ ){ + for (Uint16 counter = 0 ; counter < x_block_length ; counter++) + { *(local_data_pointer) = value; local_data_pointer++; } } // if offset - else{ + else + { assert(0); } - } // for pos + } // for pos } template - void FieldOfScalar::GetBorderRegion( masks::legacy::area_vector av, - std::vector< masks::legacy::UnsignedIndexList >& indexListInside , - std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, TYPE inside_intensity , - TYPE outside_intensity ){ - for( GridIndexType z = 0 ; z < dimz ; z++ ){ - for( GridIndexType y = av.at(z).index_begin.y ; y <= av.at(z).index_end.y ; y++ ){ - for( GridIndexType x = av.at(z).index_begin.x ; x <= av.at(z).index_end.x ; x++ ){ + void FieldOfScalar::GetBorderRegion(masks::legacy::area_vector av, + std::vector< masks::legacy::UnsignedIndexList >& indexListInside , + std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, + TYPE inside_intensity , + TYPE outside_intensity) + { + for (GridIndexType z = 0 ; z < dimz ; z++) + { + for (GridIndexType y = av.at(z).index_begin.y ; y <= av.at(z).index_end.y ; y++) + { + for (GridIndexType x = av.at(z).index_begin.x ; x <= av.at(z).index_end.x ; x++) + { - TYPE* data_pointer; - TYPE* data_pointer_check_neighbour; + TYPE* data_pointer; + TYPE* data_pointer_check_neighbour; - int offset = ( z * slice_size + y * raw_size + x ) ; + int offset = (z * slice_size + y * raw_size + x) ; - data_pointer = (TYPE*) (data + offset); + data_pointer = (TYPE*)(data + offset); - if( *data_pointer == unclear_intensity ) + if (*data_pointer == unclear_intensity) + { + bool its_inside = false; + bool its_outside = false; + + if (x > av.at(z).index_begin.x) { - bool its_inside = false; - bool its_outside = false; + int offset_neighbour = (z * slice_size + y * raw_size + (x - 1)) ; + data_pointer_check_neighbour = (TYPE*)(data + offset_neighbour); - if( x > av.at(z).index_begin.x ) + if (*data_pointer_check_neighbour == inside_intensity) { - int offset_neighbour = ( z * slice_size + y * raw_size + (x-1) ) ; - data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); - if( *data_pointer_check_neighbour == inside_intensity )its_inside = true; - if( *data_pointer_check_neighbour == outside_intensity)its_outside = true; - } + its_inside = true; + } + + if (*data_pointer_check_neighbour == outside_intensity) + { + its_outside = true; + } + } + + if (x < av.at(z).index_end.x) + { + int offset_neighbour = (z * slice_size + y * raw_size + (x + 1)) ; + data_pointer_check_neighbour = (TYPE*)(data + offset_neighbour); + + if (*data_pointer_check_neighbour == inside_intensity) + { + its_inside = true; + } - if( x < av.at(z).index_end.x ) + if (*data_pointer_check_neighbour == outside_intensity) { - int offset_neighbour = ( z * slice_size + y * raw_size + (x+1) ) ; - data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); - if( *data_pointer_check_neighbour == inside_intensity ) its_inside = true; - if( *data_pointer_check_neighbour == outside_intensity) its_outside = true; - } + its_outside = true; + } + } - if( y > av.at(z).index_begin.y ) + if (y > av.at(z).index_begin.y) + { + int offset_neighbour = (z * slice_size + (y - 1) * raw_size + x) ; + data_pointer_check_neighbour = (TYPE*)(data + offset_neighbour); + + if (*data_pointer_check_neighbour == inside_intensity) { - int offset_neighbour = ( z * slice_size + (y-1) * raw_size + x ) ; - data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); - if( *data_pointer_check_neighbour == inside_intensity )its_inside = true; - if( *data_pointer_check_neighbour == outside_intensity)its_outside = true; - } + its_inside = true; + } - if( y < av.at(z).index_end.y ) + if (*data_pointer_check_neighbour == outside_intensity) { - int offset_neighbour = ( z * slice_size + (y+1) * raw_size + x ) ; - data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); - if( *data_pointer_check_neighbour == inside_intensity ) its_inside = true; - if( *data_pointer_check_neighbour == outside_intensity) its_outside = true; + its_outside = true; } + } + + if (y < av.at(z).index_end.y) + { + int offset_neighbour = (z * slice_size + (y + 1) * raw_size + x) ; + data_pointer_check_neighbour = (TYPE*)(data + offset_neighbour); - if( its_inside && its_outside ) + if (*data_pointer_check_neighbour == inside_intensity) { - assert(0); + its_inside = true; } - if( its_inside || its_outside ) + + if (*data_pointer_check_neighbour == outside_intensity) { - masks::legacy::LegacyUnsignedIndex3D index = {x,y,z}; - - if( its_inside ) - { - indexListInside.at(z).push_back(index); - } - if( its_outside ) - { - indexListOutside.at(z).push_back(index); - } - } + its_outside = true; + } } - } + + if (its_inside && its_outside) + { + assert(0); + } + + if (its_inside || its_outside) + { + masks::legacy::LegacyUnsignedIndex3D index = {x, y, z}; + + if (its_inside) + { + indexListInside.at(z).push_back(index); + } + + if (its_outside) + { + indexListOutside.at(z).push_back(index); + } + } + } } } + } } template - bool FieldOfScalar::CheckOneOutOfThisBlockHasSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , - TYPE value ){ - if( x >= dimx ) - { - assert(0); - } - if( y >= dimy ) - { - assert(0); - } - if( z >= dimz ) - { - assert(0); - } + bool FieldOfScalar::CheckOneOutOfThisBlockHasSameIntensity(Uint16 x, Uint16 y, Uint16 z , + Uint16 block_length , + TYPE value) + { + if (x >= dimx) + { + assert(0); + } + + if (y >= dimy) + { + assert(0); + } - bool its_fine = false; + if (z >= dimz) + { + assert(0); + } - Uint16 x_block_length = block_length; - if( ( (dimx-1) - x ) <= x_block_length ) - { - x_block_length = ( (dimx-1) - x ); - } - Uint16 y_block_length = block_length; - if( ( (dimy-1) - y ) <= y_block_length ) - { - y_block_length = ( (dimy-1) - y ); - } + bool its_fine = false; - TYPE* local_data_pointer; + Uint16 x_block_length = block_length; - for( int pos = 0 ; pos < y_block_length ; pos++ ){ + if (((dimx - 1) - x) <= x_block_length) + { + x_block_length = ((dimx - 1) - x); + } - int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; + Uint16 y_block_length = block_length; - if( offset <= ( cube_size - 1 ) ) - { - local_data_pointer = (TYPE*) data + offset; + if (((dimy - 1) - y) <= y_block_length) + { + y_block_length = ((dimy - 1) - y); + } - for( int counter = 0 ; counter < x_block_length ; counter++ ){ + TYPE* local_data_pointer; - if( *local_data_pointer == value ) - { - its_fine = true; - } - local_data_pointer++; + for (int pos = 0 ; pos < y_block_length ; pos++) + { + + int offset = (z * slice_size + (y + pos) * raw_size + x) ; + + if (offset <= (cube_size - 1)) + { + local_data_pointer = (TYPE*) data + offset; + + for (int counter = 0 ; counter < x_block_length ; counter++) + { + + if (*local_data_pointer == value) + { + its_fine = true; } - } // if offset - else{ - assert(0); + + local_data_pointer++; } - } // for pos - return its_fine; + } // if offset + else + { + assert(0); + } + } // for pos + + return its_fine; } /*! @class FieldOfPointer - @brief This is a class representing a field of pointers to whatever. + @brief This is a class representing a field of pointers to whatever. */ template class FieldOfPointer : public BaseField { public: - FieldOfPointer( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ): BaseField( dimx_in , dimy_in , dimz_in ) + FieldOfPointer(Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in): BaseField(dimx_in , dimy_in , + dimz_in) { create(); } - ~FieldOfPointer(){ + ~FieldOfPointer() + { clear(); } typedef TYPE type; /*! @brief Get the data stored in this FieldOfPointer at index (x,y,z) - @see FieldOfScalar. + @see FieldOfScalar. */ - inline TYPE GetData( Uint16 x, Uint16 y, Uint16 z ); + inline TYPE GetData(Uint16 x, Uint16 y, Uint16 z); /*! @brief Set all entries to Null - @see FieldOfScalar. Here zero is NULL. + @see FieldOfScalar. Here zero is NULL. */ void SetZero(); /*! @brief Set value at index (x,y,z) @see FieldOfScalar. */ - inline void PutData( Uint16 x, Uint16 y, Uint16 z , TYPE value ); + inline void PutData(Uint16 x, Uint16 y, Uint16 z , TYPE value); - private: + private: void clear(); /*! Initialize all. - */ + */ void create(); TYPE* data; /*! Number of values within a slice. */ int slice_size; /*! Number of values in a raw. - */ + */ Uint16 raw_size; /*! Number of values within a cube. - */ + */ int cube_size; - }; + }; template - void FieldOfPointer::SetZero(){ - for( int offset = 0 ; offset < cube_size ; offset++ ){ - delete *( (TYPE*) data + offset ); - *( (TYPE*) data + offset ) = NULL; - } + void FieldOfPointer::SetZero() + { + for (int offset = 0 ; offset < cube_size ; offset++) + { + delete *((TYPE*) data + offset); + *((TYPE*) data + offset) = NULL; + } } template - inline TYPE FieldOfPointer::GetData( Uint16 x, Uint16 y, Uint16 z ){ + inline TYPE FieldOfPointer::GetData(Uint16 x, Uint16 y, Uint16 z) + { TYPE val; int offset; - offset = ( z * slice_size + y * raw_size + x ) ; + offset = (z * slice_size + y * raw_size + x) ; - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) { - val = *( (TYPE*) data + offset ); + val = *((TYPE*) data + offset); return val; } - else{ - throw core::IndexOutOfBoundsException( " Out of range ! " ); + else + { + throw core::IndexOutOfBoundsException(" Out of range ! "); } } template - inline void FieldOfPointer::PutData( Uint16 x, Uint16 y, Uint16 z, TYPE value ){ + inline void FieldOfPointer::PutData(Uint16 x, Uint16 y, Uint16 z, TYPE value) + { int offset; - offset = ( z * slice_size + y * raw_size + x ) ; + offset = (z * slice_size + y * raw_size + x) ; - if( offset <= ( cube_size - 1 ) ) + if (offset <= (cube_size - 1)) { - delete *( (TYPE*) data + offset ); - *( (TYPE*) data + offset ) = value; - } - else{ - throw core::IndexOutOfBoundsException( " Out of range ! " ); + delete *((TYPE*) data + offset); + *((TYPE*) data + offset) = value; + } + else + { + throw core::IndexOutOfBoundsException(" Out of range ! "); } } template - void FieldOfPointer::clear(){ - for( int offset = 0 ; offset < cube_size ; offset++ ) delete *( (TYPE*) data + offset ); - free(data); + void FieldOfPointer::clear() + { + for (int offset = 0 ; offset < cube_size ; offset++) + { + delete *((TYPE*) data + offset); + } + + free(data); } template - void FieldOfPointer::create(){ - int size = ( dimz * dimy * dimx ) * sizeof(TYPE); - data = (type*) malloc( size ); + void FieldOfPointer::create() + { + int size = (dimz * dimy * dimx) * sizeof(TYPE); + data = (type*) malloc(size); slice_size = dimy * dimx; raw_size = dimx; cube_size = dimy * dimx * dimz; - for( int offset = 0 ; offset < cube_size ; offset++ ){ - *( (TYPE*) data + offset ) = NULL; + + for (int offset = 0 ; offset < cube_size ; offset++) + { + *((TYPE*) data + offset) = NULL; } } } } } -#endif +#endif diff --git a/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp index 4dcfb3a..b85f45c 100644 --- a/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp +++ b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp @@ -1,1525 +1,2219 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ //Relocate? #include "rttbMask.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include "rttbNullPointerException.h" #include #include #include #include #include // Generelle Anmerkung: // Koordinatensystem von Bild und Strukturen auf Kompatibilitaet pruefen! // Strukturen auf Gutartigkeit pruefen: -// Ein Polygonzug darf sich nicht mit sich selbst schneiden. Ist eine Struktur innerhalb eines Slices durch +// Ein Polygonzug darf sich nicht mit sich selbst schneiden. Ist eine Struktur innerhalb eines Slices durch // zwei Polygonzuege repraesentiert, so muessen diese distinkt sein, duerfen eineander also nicht ueberschneiden! -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { + + + IterativePolygonInTermsOfIntersections::IterativePolygonInTermsOfIntersections() + { + number_of_intersections = -1; + } + + + bool IterativePolygonInTermsOfIntersections::selfTest() + { + + std::cout << + " Hallo, ich bin die funktion selfTest von IterativePolygonInTermsOfIntersections und ich bin noch nicht implementiert. Trotzdem returne ich true. Das musst du aendern. " + << std::endl; + return true; + } + + + bool IterativePolygonInTermsOfIntersections::CheckCurrentIndexInitForTest() + { + if ((current_index_internal.point_index != 0) || (current_index_internal.intersection_index != 0) + || (current_index_internal.column_raw_or_unified != 2)) + { + return false; + } + else + { + return true; + } + } + + + void IterativePolygonInTermsOfIntersections::SetIntersectionsAndResetIntersectionIndex( + const masks::legacy::PolygonInTermsOfIntersections& Polygon_Intersections_In) + { + Polygon_Intersections = Polygon_Intersections_In; + //CreateUnifiedListOfRawAndColumnIntersections(); + ResetIntersectionIndex(); + } + + + void IterativePolygonInTermsOfIntersections::ResetIntersectionIndex() + { + current_index_internal.point_index = 0; + current_index_internal.intersection_index = 0; + current_index_internal.column_raw_or_unified = 2; + } + + + void IterativePolygonInTermsOfIntersections::PrintIntersectionIndex() + { + std::cout << " current_index_internal.point_index : " << current_index_internal.point_index << + std::endl; + std::cout << " current_index_internal.intersection_index : " << + current_index_internal.intersection_index << std::endl; + } + + unsigned int IterativePolygonInTermsOfIntersections::GetRestpectiveIntersectionVectorLength( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref) + { + if (the_intersection_index_ref.column_raw_or_unified == 0) + { + return Polygon_Intersections.at(the_intersection_index_ref.point_index).column_intersections.size(); + } + else if (the_intersection_index_ref.column_raw_or_unified == 1) + { + return Polygon_Intersections.at(the_intersection_index_ref.point_index).raw_intersections.size(); + } + else + { + return Polygon_Intersections.at( + the_intersection_index_ref.point_index).intersections_raw_and_column.size(); + } + } + + + LegacyWorldCoordinate2D IterativePolygonInTermsOfIntersections::GetRestpectiveIntersection( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref) + { + + LegacyWorldCoordinate2D coordinates_return; + + if (the_intersection_index_ref.column_raw_or_unified == 0) + { + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).column_intersections.at( + the_intersection_index_ref.intersection_index); + } + else if (the_intersection_index_ref.column_raw_or_unified == 1) + { + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).raw_intersections.at( + the_intersection_index_ref.intersection_index); + } + else + { + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).intersections_raw_and_column.at( + the_intersection_index_ref.intersection_index); + } + + return coordinates_return; + + } + + + + LegacyWorldCoordinate2D IterativePolygonInTermsOfIntersections::GetRestpectiveIntersectionFurther( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , int ahead) + { + + LegacyWorldCoordinate2D coordinates_return; + + if (GetRestpectiveIntersectionVectorLength(the_intersection_index_ref) > + (the_intersection_index_ref.intersection_index + ahead)) + { + + if (the_intersection_index_ref.column_raw_or_unified == 0) + { + + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).column_intersections.at( + the_intersection_index_ref.intersection_index + ahead); + + } + else if (the_intersection_index_ref.column_raw_or_unified == 1) + { + + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).raw_intersections.at( + the_intersection_index_ref.intersection_index + ahead); + + } + else + { + + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).intersections_raw_and_column.at( + the_intersection_index_ref.intersection_index + ahead); + + } + + } + else + { + + if (GetRestpectiveIntersectionVectorLength(the_intersection_index_ref) <= + (the_intersection_index_ref.intersection_index + ahead)) + { + + GridIndexType control_index = ((the_intersection_index_ref.intersection_index + ahead) - + GetRestpectiveIntersectionVectorLength(the_intersection_index_ref)); + + if ((control_index >= 0) + && (control_index < GetRestpectiveIntersectionVectorLength(the_intersection_index_ref))) + { + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).intersections_raw_and_column.at((( + the_intersection_index_ref.intersection_index + ahead) - GetRestpectiveIntersectionVectorLength( + the_intersection_index_ref))); + } + else + { + assert(0); // the_intersection_index_ref and ahead have been initially unreasonalble + } + } - IterativePolygonInTermsOfIntersections::IterativePolygonInTermsOfIntersections(){ - number_of_intersections = -1; - } + } + return coordinates_return; - bool IterativePolygonInTermsOfIntersections::selfTest(){ + } - std::cout<< " Hallo, ich bin die funktion selfTest von IterativePolygonInTermsOfIntersections und ich bin noch nicht implementiert. Trotzdem returne ich true. Das musst du aendern. " < (the_intersection_index_ref.point_index)) + && ((the_intersection_index_ref.point_index) >= 0)) + { + return true; + } + else + { + return false; + } + } - void IterativePolygonInTermsOfIntersections::SetIntersectionsAndResetIntersectionIndex( const masks::legacy::PolygonInTermsOfIntersections& Polygon_Intersections_In ){ - Polygon_Intersections = Polygon_Intersections_In; - //CreateUnifiedListOfRawAndColumnIntersections(); - ResetIntersectionIndex(); - } + LegacyWorldCoordinate3D + IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinates( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref) + { - void IterativePolygonInTermsOfIntersections::ResetIntersectionIndex(){ - current_index_internal.point_index = 0; - current_index_internal.intersection_index = 0; - current_index_internal.column_raw_or_unified = 2; - } + LegacyWorldCoordinate3D coordinates_return; + if (PointIndexIsFine(the_intersection_index_ref)) + { + coordinates_return = Polygon_Intersections.at( + the_intersection_index_ref.point_index).contour_point_voxel_coord; + } + else + { + // exception to be implemented + assert(0); + } - void IterativePolygonInTermsOfIntersections::PrintIntersectionIndex(){ - std::cout<< " current_index_internal.point_index : " << current_index_internal.point_index < (the_intersection_index_ref.point_index + ahead)) + { + coordinates_return = Polygon_Intersections.at(the_intersection_index_ref.point_index + + ahead).contour_point_voxel_coord; + } + else + { - } + if ((ahead - (Polygon_Intersections.size() - the_intersection_index_ref.point_index)) >= + Polygon_Intersections.size()) + { + assert(0); // this must never happen. Probably the contour consists of just one point. That does not make any sense in context of radiotherapy. + } + coordinates_return = Polygon_Intersections.at(ahead - (Polygon_Intersections.size() - + the_intersection_index_ref.point_index)).contour_point_voxel_coord; + } - LegacyWorldCoordinate2D IterativePolygonInTermsOfIntersections::GetRestpectiveIntersectionFurther( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , int ahead ){ + return coordinates_return; - LegacyWorldCoordinate2D coordinates_return; + } - if( GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) > ( the_intersection_index_ref.intersection_index + ahead ) ){ - if( the_intersection_index_ref.column_raw_or_unified == 0 ){ + LegacyWorldCoordinate3D + IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinatesPrevious( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , + unsigned int back) + { - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).column_intersections.at( the_intersection_index_ref.intersection_index + ahead ); + LegacyWorldCoordinate3D coordinates_return; - } - else if( the_intersection_index_ref.column_raw_or_unified == 1 ){ + if (((the_intersection_index_ref.point_index) >= back) + && ((the_intersection_index_ref.point_index) < (Polygon_Intersections.size() + back))) + { - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).raw_intersections.at( the_intersection_index_ref.intersection_index + ahead ); + coordinates_return = Polygon_Intersections.at(the_intersection_index_ref.point_index - + back).contour_point_voxel_coord; - } - else{ + } + else + { - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).intersections_raw_and_column.at( the_intersection_index_ref.intersection_index + ahead ); + if (the_intersection_index_ref.point_index < back) + { - } + int control_index = (Polygon_Intersections.size() - (back - + the_intersection_index_ref.point_index)); - } - else{ + if (control_index < 0) + { + assert(0); // This must never happen. Probably the contour consists of just one point. Each point has already been regarded. That does not make any sense in radiotherapy. + } - if( GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) <= ( the_intersection_index_ref.intersection_index + ahead ) ){ + coordinates_return = Polygon_Intersections.at(Polygon_Intersections.size() - + (back - the_intersection_index_ref.point_index)).contour_point_voxel_coord; - GridIndexType control_index = ( ( the_intersection_index_ref.intersection_index + ahead ) - GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ); - if( ( control_index >= 0 ) && ( control_index < GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ) ){ - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).intersections_raw_and_column.at( ( ( the_intersection_index_ref.intersection_index + ahead ) - GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ) ); - } - else assert(0); // the_intersection_index_ref and ahead have been initially unreasonalble + } - } + if (!((the_intersection_index_ref.point_index) < (Polygon_Intersections.size() + back))) + { - } + assert(0); // that can't be right the_intersection_index_ref.point_index must have been initially unreasonable - return coordinates_return; + } - } + } + return coordinates_return; - bool IterativePolygonInTermsOfIntersections::PointIndexIsFine( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ + } - if( ( Polygon_Intersections.size() > ( the_intersection_index_ref.point_index ) ) && ( ( the_intersection_index_ref.point_index ) >= 0 ) ){ - return true; - } - else return false; - } + LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetFirstPointThisPolygon( + IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref) + { + LegacyWorldCoordinate3D first_one_this_Polygon(0, 0, 0); - LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinates( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ + if (Polygon_Intersections.size() > 0) + { + first_one_this_Polygon = Polygon_Intersections.at(0).contour_point_voxel_coord; + return first_one_this_Polygon; + } + else + { + assert(0); + // exception implementieren + } - LegacyWorldCoordinate3D coordinates_return; - if( PointIndexIsFine( the_intersection_index_ref ) ){ - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).contour_point_voxel_coord; - } - else{ - // exception to be implemented - assert(0); - } - return coordinates_return; + return first_one_this_Polygon; - } + } - LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinatesFurther( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , int ahead ){ - // Baustelle zyklisch machen + void IterativePolygonInTermsOfIntersections::ResetIntersectionIndex( + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_set_to) + { + current_index_internal.point_index = intersection_set_to.point_index ; + current_index_internal.intersection_index = intersection_set_to.intersection_index ; + current_index_internal.column_raw_or_unified = intersection_set_to.column_raw_or_unified ; + } - LegacyWorldCoordinate3D coordinates_return; - if( Polygon_Intersections.size() > ( the_intersection_index_ref.point_index + ahead ) ){ - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index + ahead ).contour_point_voxel_coord; - } - else{ + // index goes in for debug and will be removed later ... + bool IterativePolygonInTermsOfIntersections::RunForwardToNextIntersection( + LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref , + LegacyDoseVoxelIndex3D the_dose_index) + { - if( ( ahead - ( Polygon_Intersections.size() - the_intersection_index_ref.point_index ) ) >= Polygon_Intersections.size() ) assert( 0 ); // this must never happen. Probably the contour consists of just one point. That does not make any sense in context of radiotherapy. - coordinates_return = Polygon_Intersections.at( ahead - ( Polygon_Intersections.size() - the_intersection_index_ref.point_index ) ).contour_point_voxel_coord; + bool success = false; + bool done = false; + bool success_first_increment = false; - } + RememberPosition(); - return coordinates_return; + if (ThisIntersection(point_of_interest_start_ref)) + { - } + snippet_intermediate_content_ref.clear(); + if (! CloseWithoutIncrement(point_of_interest_start_ref, point_of_interest_end_ref , + snippet_intermediate_content_ref)) + { - LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinatesPrevious( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , unsigned int back ){ + PeriodicPolygonPointIncrement(); - LegacyWorldCoordinate3D coordinates_return; + AppendThisIntermediatePoint(snippet_intermediate_content_ref); - if( ( ( the_intersection_index_ref.point_index ) >= back ) && ( ( the_intersection_index_ref.point_index ) < ( Polygon_Intersections.size() + back ) ) ){ + while (!done) + { - coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index - back ).contour_point_voxel_coord; + // done = AppendIntermediatePointOrCloseForward( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref ); + done = CloseWithoutIncrement(point_of_interest_start_ref, point_of_interest_end_ref , + snippet_intermediate_content_ref); - } - else{ + if (!done) + { - if( the_intersection_index_ref.point_index < back ){ + PeriodicPolygonPointIncrement(); - int control_index = ( Polygon_Intersections.size() - ( back - the_intersection_index_ref.point_index ) ); + AppendThisIntermediatePoint(snippet_intermediate_content_ref); - if( control_index < 0 ){ - assert(0); // This must never happen. Probably the contour consists of just one point. Each point has already been regarded. That does not make any sense in radiotherapy. - } + } - coordinates_return = Polygon_Intersections.at( Polygon_Intersections.size() - ( back - the_intersection_index_ref.point_index ) ).contour_point_voxel_coord; + } - } + } - if( ! ( ( the_intersection_index_ref.point_index ) < ( Polygon_Intersections.size() + back ) ) ){ + } + else + { + assert(0); + } - assert(0); // that can't be right the_intersection_index_ref.point_index must have been initially unreasonable + CleanOut(point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref); - } + JumpToRememberedPosition(); - } + return success; - return coordinates_return; + } - } + void IterativePolygonInTermsOfIntersections::CleanOut(LegacyWorldCoordinate2D& + point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { - LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetFirstPointThisPolygon( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ + if (snippet_intermediate_content_ref.size() > 0) + { - LegacyWorldCoordinate3D first_one_this_Polygon(0,0,0); + bool im_done_a = false; - if( Polygon_Intersections.size() > 0 ){ - first_one_this_Polygon = Polygon_Intersections.at( 0 ).contour_point_voxel_coord; - return first_one_this_Polygon; - } - else{ - assert(0); - // exception implementieren - } + while ((!im_done_a) && (snippet_intermediate_content_ref.size() > 0)) + { - return first_one_this_Polygon; + if ((point_of_interest_start_ref.x == snippet_intermediate_content_ref.at(0).x) + && (point_of_interest_start_ref.y == snippet_intermediate_content_ref.at(0).y)) + { + snippet_intermediate_content_ref.erase(snippet_intermediate_content_ref.begin()); + } + else + { + im_done_a = true; + } - } + } + bool im_done_b = false; + while ((!im_done_b) && (snippet_intermediate_content_ref.size() > 0)) + { - void IterativePolygonInTermsOfIntersections::ResetIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_set_to ){ - current_index_internal.point_index = intersection_set_to.point_index ; - current_index_internal.intersection_index = intersection_set_to.intersection_index ; - current_index_internal.column_raw_or_unified = intersection_set_to.column_raw_or_unified ; - } + if ((point_of_interest_end_ref.x == snippet_intermediate_content_ref.at( + snippet_intermediate_content_ref.size() - 1).x) + && (point_of_interest_end_ref.y == snippet_intermediate_content_ref.at( + snippet_intermediate_content_ref.size() - 1).y)) + { + snippet_intermediate_content_ref.pop_back(); + } + else + { + im_done_b = true; + } + } - // index goes in for debug and will be removed later ... - bool IterativePolygonInTermsOfIntersections::RunForwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref , LegacyDoseVoxelIndex3D the_dose_index ){ + } + } - bool success = false; - bool done = false; - bool success_first_increment = false; - RememberPosition(); + bool IterativePolygonInTermsOfIntersections::RunBackwardToNextIntersection( + LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { - if( ThisIntersection( point_of_interest_start_ref ) ){ + bool success = false; + bool done = false; + bool success_first_increment = false; - snippet_intermediate_content_ref.clear(); + RememberPosition(); - if( ! CloseWithoutIncrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ) ){ + if (ThisIntersection(point_of_interest_start_ref)) + { - PeriodicPolygonPointIncrement(); + snippet_intermediate_content_ref.clear(); - AppendThisIntermediatePoint( snippet_intermediate_content_ref ); - while( !done ){ + if (! CloseWithoutDecrement(point_of_interest_start_ref, point_of_interest_end_ref , + snippet_intermediate_content_ref)) + { - // done = AppendIntermediatePointOrCloseForward( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref ); - done = CloseWithoutIncrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); - if( !done ){ + AppendThisIntermediatePoint(snippet_intermediate_content_ref); - PeriodicPolygonPointIncrement(); - - AppendThisIntermediatePoint( snippet_intermediate_content_ref ); + PeriodicPolygonPointDecrement(); - } + while ((!done)) + { - } + done = CloseWithoutDecrement(point_of_interest_start_ref, point_of_interest_end_ref , + snippet_intermediate_content_ref); - } + if (!done) + { - } - else assert(0); - - CleanOut( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); + AppendThisIntermediatePoint(snippet_intermediate_content_ref); - JumpToRememberedPosition(); + PeriodicPolygonPointDecrement(); - return success; + } - } + } + } - void IterativePolygonInTermsOfIntersections::CleanOut( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ + } + else + { + assert(0); // This must never happen ! + } - if( snippet_intermediate_content_ref.size() > 0 ){ + CleanOut(point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref); - bool im_done_a = false; - while( (!im_done_a) && (snippet_intermediate_content_ref.size() > 0) ){ - - if( ( point_of_interest_start_ref.x == snippet_intermediate_content_ref.at( 0 ).x ) && ( point_of_interest_start_ref.y == snippet_intermediate_content_ref.at( 0 ).y ) )snippet_intermediate_content_ref.erase( snippet_intermediate_content_ref.begin() ); - else im_done_a = true; - - } - - bool im_done_b = false; - while( (!im_done_b) && (snippet_intermediate_content_ref.size() > 0) ){ - - if( ( point_of_interest_end_ref.x == snippet_intermediate_content_ref.at( snippet_intermediate_content_ref.size() - 1 ).x ) && ( point_of_interest_end_ref.y == snippet_intermediate_content_ref.at( snippet_intermediate_content_ref.size() - 1 ).y ) )snippet_intermediate_content_ref.pop_back(); - else im_done_b = true; - - } - - } - - } + JumpToRememberedPosition(); + return success; - bool IterativePolygonInTermsOfIntersections::RunBackwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ + } - bool success = false; - bool done = false; - bool success_first_increment = false; - RememberPosition(); + bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseForward( + LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { - if( ThisIntersection( point_of_interest_start_ref ) ){ + bool got_it = false; - snippet_intermediate_content_ref.clear(); + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + != 0) + { - if( ! CloseWithoutDecrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ) ){ - + while (current_index_internal.intersection_index < (Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1)) + { - AppendThisIntermediatePoint( snippet_intermediate_content_ref ); + current_index_internal.intersection_index++; + LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - PeriodicPolygonPointDecrement(); - while( ( !done ) ){ + } - done = CloseWithoutDecrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); - if( !done ){ + if ((static_cast(point_of_interest_start_ref.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.at( + 0).x)) || (static_cast(point_of_interest_start_ref.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.at( + 0).y))) + { - AppendThisIntermediatePoint( snippet_intermediate_content_ref ); - - PeriodicPolygonPointDecrement(); + got_it = true; - } + point_of_interest_end_ref = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at(0); - } + snippet_intermediate_content_ref.push_back(Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord); - } + } + else + { - } - else assert(0); // This must never happen ! + // Anmerkung : man kann die else Bedingung auch oben in die if Bedingung mit reinpacken, je nachdem, was der code-reviewer leserlicher findet + // sie sind gleich. Die Frage ist nun, ob es Zwischenpunkte gab, ob die Punkte also noch, oder wieder gleich sind. + if (snippet_intermediate_content_ref.size() > 0) + { - CleanOut( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); + got_it = true; - JumpToRememberedPosition(); + point_of_interest_end_ref = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at(0); - return success; + snippet_intermediate_content_ref.push_back(Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord); - } + } + } - bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseForward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ - bool got_it = false; + } + else + { - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() != 0 ){ + snippet_intermediate_content_ref.push_back(Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord); - - while( current_index_internal.intersection_index < ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ){ - - current_index_internal.intersection_index++; - LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - - - } + } + return got_it; - if( ( static_cast( point_of_interest_start_ref.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at(0).x) ) || ( static_cast( point_of_interest_start_ref.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at(0).y ) ) ){ + } - got_it = true; - point_of_interest_end_ref = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( 0 ); - snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); + bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseBackward( + LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { - } - else{ - // Anmerkung : man kann die else Bedingung auch oben in die if Bedingung mit reinpacken, je nachdem, was der code-reviewer leserlicher findet - // sie sind gleich. Die Frage ist nun, ob es Zwischenpunkte gab, ob die Punkte also noch, oder wieder gleich sind. - if( snippet_intermediate_content_ref.size() > 0 ){ + if (current_index_internal.intersection_index != (Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1)) + { + assert(0); //this should not happen + } - got_it = true; + while (current_index_internal.intersection_index > 0) + { - point_of_interest_end_ref = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( 0 ); + current_index_internal.intersection_index--; + LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); + if ((static_cast(point_of_interest.x) != static_cast(point_of_interest_start_ref.x)) + && (static_cast(point_of_interest.y) != static_cast(point_of_interest_start_ref.y))) + { - } + point_of_interest_end_ref = point_of_interest; + return true; - } + } + } - } - else{ - snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); + snippet_intermediate_content_ref.push_back(Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord); - } + return false; - return got_it; + } - } + void IterativePolygonInTermsOfIntersections::AppendThisIntermediatePoint( + std::vector& snippet_intermediate_content_ref) + { + snippet_intermediate_content_ref.push_back(Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord); + } - bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseBackward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ - + bool IterativePolygonInTermsOfIntersections::IncrementNeeded() + { + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + <= (current_index_internal.intersection_index + 1)) + { + return true; + } - if( current_index_internal.intersection_index != ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ) assert(0); //this should not happen - - while( current_index_internal.intersection_index > 0 ){ - - current_index_internal.intersection_index--; - LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) && ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ - - point_of_interest_end_ref = point_of_interest; - return true; - - } - - } + return false; + } - snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); + bool IterativePolygonInTermsOfIntersections::DecrementNeeded() + { + bool is_needed = false; - return false; + if (current_index_internal.intersection_index < 1) + { + is_needed = true; + } - } + return is_needed; + } - void IterativePolygonInTermsOfIntersections::AppendThisIntermediatePoint( std::vector& snippet_intermediate_content_ref ){ - snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); - } + bool IterativePolygonInTermsOfIntersections::CloseWithoutIncrement(LegacyWorldCoordinate2D& + point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { + LegacyWorldCoordinate2D point_of_interest; - bool IterativePolygonInTermsOfIntersections::IncrementNeeded(){ - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() <= ( current_index_internal.intersection_index + 1 ) ) return true; - return false; - } + if (CheckIndex()) + { + point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - bool IterativePolygonInTermsOfIntersections::DecrementNeeded(){ - bool is_needed = false; - if( current_index_internal.intersection_index < 1 ) is_needed = true; - return is_needed; - } + if (((static_cast(point_of_interest.x) != static_cast(point_of_interest_start_ref.x)) + || (static_cast(point_of_interest.y) != static_cast(point_of_interest_start_ref.y))) + || OneDiffers(snippet_intermediate_content_ref , point_of_interest_start_ref)) + { + point_of_interest_end_ref = point_of_interest; - bool IterativePolygonInTermsOfIntersections::CloseWithoutIncrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ - - LegacyWorldCoordinate2D point_of_interest; + return true; - if( CheckIndex() ){ - - point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); + } - if( ( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ) || OneDiffers( snippet_intermediate_content_ref , point_of_interest_start_ref ) ){ + } - point_of_interest_end_ref = point_of_interest; - - return true; - - } - - } - - if( ! IncrementNeeded() ){ - - while( current_index_internal.intersection_index < ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ){ - - current_index_internal.intersection_index++; - - point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); + if (! IncrementNeeded()) + { - if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ + while (current_index_internal.intersection_index < (Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1)) + { + current_index_internal.intersection_index++; - point_of_interest_end_ref = point_of_interest; + point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - - return true; - - } - - } - - return false; - - } - else return false; - - } + if ((static_cast(point_of_interest.x) != static_cast + (point_of_interest_start_ref.x)) + || (static_cast(point_of_interest.y) != static_cast(point_of_interest_start_ref.y))) + { + point_of_interest_end_ref = point_of_interest; - bool IterativePolygonInTermsOfIntersections::OneDiffers( std::vector& snippet_intermediate_content_ref , LegacyWorldCoordinate2D& point_of_interest_start_ref ){ - - for( GridIndexType i = 0 ; i < snippet_intermediate_content_ref.size() ; i++ ){ - - LegacyWorldCoordinate3D a_point = snippet_intermediate_content_ref.at( i ); - - if( ( a_point.x != point_of_interest_start_ref.x ) || ( a_point.y != point_of_interest_start_ref.y ) )return true; - - } - - return false; - - } + return true; + } - bool IterativePolygonInTermsOfIntersections::CloseWithoutDecrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ - - LegacyWorldCoordinate2D point_of_interest; - - if(CheckIndex()){ - - point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); + } - if( ( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ) || OneDiffers( snippet_intermediate_content_ref , point_of_interest_start_ref ) ){ - - point_of_interest_end_ref = point_of_interest; + return false; - return true; - - } - - } + } + else + { + return false; + } - if( ! DecrementNeeded() ){ + } - while( current_index_internal.intersection_index > 0 ){ - - current_index_internal.intersection_index--; - - point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ - - point_of_interest_end_ref = point_of_interest; - return true; - - } - - } - - return false; + bool IterativePolygonInTermsOfIntersections::OneDiffers(std::vector& + snippet_intermediate_content_ref , LegacyWorldCoordinate2D& point_of_interest_start_ref) + { - - } - else return false; - - } + for (GridIndexType i = 0 ; i < snippet_intermediate_content_ref.size() ; i++) + { + LegacyWorldCoordinate3D a_point = snippet_intermediate_content_ref.at(i); + if ((a_point.x != point_of_interest_start_ref.x) || (a_point.y != point_of_interest_start_ref.y)) + { + return true; + } - void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointIncrement(){ - if( current_index_internal.point_index < ( Polygon_Intersections.size() - 1 ) ){ - current_index_internal.point_index++; - } - else{ - current_index_internal.point_index = 0; - } - current_index_internal.intersection_index = 0; - } + } + return false; - void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointDecrement(){ - if( current_index_internal.point_index > 0 ){ - current_index_internal.point_index--; - } - else{ - current_index_internal.point_index = ( Polygon_Intersections.size() - 1 ); - } - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ; - else current_index_internal.intersection_index = 0; - } + } - /// - /// returns true, in case intersection - /// - bool IterativePolygonInTermsOfIntersections::CheckIsIntersection( LegacyWorldCoordinate2D& edge_coord , IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ - // Baustelle all control paths should return a value + bool IterativePolygonInTermsOfIntersections::CloseWithoutDecrement(LegacyWorldCoordinate2D& + point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref) + { - LegacyWorldCoordinate2D local_current_position = {0,0}; + LegacyWorldCoordinate2D point_of_interest; - RememberPosition(); + if (CheckIndex()) + { - ResetIntersectionIndex(); + point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - bool was_able_to_increment = true; + if (((static_cast(point_of_interest.x) != static_cast(point_of_interest_start_ref.x)) + || (static_cast(point_of_interest.y) != static_cast(point_of_interest_start_ref.y))) + || OneDiffers(snippet_intermediate_content_ref , point_of_interest_start_ref)) + { - while( was_able_to_increment == true ){ + point_of_interest_end_ref = point_of_interest; - // if( CheckToBeRegarded() ){ + return true; - if( ThisIntersection( local_current_position ) ){ + } + } - if( ( static_cast( edge_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( edge_coord.y ) == static_cast( local_current_position.y ) ) ){ + if (! DecrementNeeded()) + { - IterativePolygonInTermsOfIntersections::WhichIntersection& current_index_internal_ref = current_index_internal; - CopyIntersectionIndex( the_intersection_index_ref , current_index_internal_ref ); + while (current_index_internal.intersection_index > 0) + { - JumpToRememberedPosition(); + current_index_internal.intersection_index--; - return true; + point_of_interest = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - } + if ((static_cast(point_of_interest.x) != static_cast(point_of_interest_start_ref.x)) + || (static_cast(point_of_interest.y) != static_cast(point_of_interest_start_ref.y))) + { - } + point_of_interest_end_ref = point_of_interest; - // } + return true; - was_able_to_increment = IncremtentIntersection(); + } - } + } - JumpToRememberedPosition(); + return false; - return false; - } + } + else + { + return false; + } + } - void IterativePolygonInTermsOfIntersections::CopyIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& from_ref ){ - to_ref.point_index = from_ref.point_index; - to_ref.intersection_index = from_ref.intersection_index; - to_ref.column_raw_or_unified = from_ref.column_raw_or_unified; - } - bool IterativePolygonInTermsOfIntersections::IncremtentIntersection(){ + void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointIncrement() + { + if (current_index_internal.point_index < (Polygon_Intersections.size() - 1)) + { + current_index_internal.point_index++; + } + else + { + current_index_internal.point_index = 0; + } - + current_index_internal.intersection_index = 0; + } - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > ( current_index_internal.intersection_index + 1 ) ){ - current_index_internal.intersection_index++; - return true; - } - else{ - bool success = false; + void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointDecrement() + { + if (current_index_internal.point_index > 0) + { + current_index_internal.point_index--; + } + else + { + current_index_internal.point_index = (Polygon_Intersections.size() - 1); + } - while( success == false ){ + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + current_index_internal.intersection_index = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1 ; + } + else + { + current_index_internal.intersection_index = 0; + } + } - if( Polygon_Intersections.size() > ( current_index_internal.point_index + 1 ) ){ - current_index_internal.intersection_index = 0; - current_index_internal.point_index++; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ + /// + /// returns true, in case intersection + /// + bool IterativePolygonInTermsOfIntersections::CheckIsIntersection(LegacyWorldCoordinate2D& edge_coord + , IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref) + { + // Baustelle all control paths should return a value - return true; + LegacyWorldCoordinate2D local_current_position = {0, 0}; - } + RememberPosition(); - } - else return false; + ResetIntersectionIndex(); - } + bool was_able_to_increment = true; - } + while (was_able_to_increment == true) + { - + // if( CheckToBeRegarded() ){ - return false; + if (ThisIntersection(local_current_position)) + { - } + if ((static_cast(edge_coord.x) == static_cast(local_current_position.x)) + && (static_cast(edge_coord.y) == static_cast(local_current_position.y))) + { - bool IterativePolygonInTermsOfIntersections::IncremtentIntersectionPeriodically(){ + IterativePolygonInTermsOfIntersections::WhichIntersection& current_index_internal_ref = + current_index_internal; + CopyIntersectionIndex(the_intersection_index_ref , current_index_internal_ref); - if( ( CheckIndex() ) && ( ThereAreIntersections() ) ){ + JumpToRememberedPosition(); - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > ( current_index_internal.intersection_index + 1 ) ){ - current_index_internal.intersection_index++; - return true; - } - else{ + return true; - bool success = false; + } - while( success == false ){ + } - if( Polygon_Intersections.size() > ( current_index_internal.point_index + 1 ) ){ + // } - current_index_internal.intersection_index = 0; - current_index_internal.point_index++; + was_able_to_increment = IncremtentIntersection(); - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ + } - return true; + JumpToRememberedPosition(); - } + return false; - } - else{ + } - current_index_internal.intersection_index = 0; - current_index_internal.point_index = 0; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ + void IterativePolygonInTermsOfIntersections::CopyIntersectionIndex( + IterativePolygonInTermsOfIntersections::WhichIntersection& to_ref , + IterativePolygonInTermsOfIntersections::WhichIntersection& from_ref) + { + to_ref.point_index = from_ref.point_index; + to_ref.intersection_index = from_ref.intersection_index; + to_ref.column_raw_or_unified = from_ref.column_raw_or_unified; + } - return true; - } + bool IterativePolygonInTermsOfIntersections::IncremtentIntersection() + { - } - } - } + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > (current_index_internal.intersection_index + 1)) + { + current_index_internal.intersection_index++; + return true; + } + else + { - } - else return false; - return false; + bool success = false; - } + while (success == false) + { + if (Polygon_Intersections.size() > (current_index_internal.point_index + 1)) + { - bool IterativePolygonInTermsOfIntersections::CheckIndex(){ + current_index_internal.intersection_index = 0; + current_index_internal.point_index++; - if( Polygon_Intersections.size() > current_index_internal.point_index ){ + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { - if( ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ) ){ - return true; - } - else return false; + return true; - } - else return false; + } - } + } + else + { + return false; + } + } - // Caution : This function can end up with a bad intersedction index. - bool IterativePolygonInTermsOfIntersections::DecrementPointOrIntersectionPeriodically(){ + } - if( /*CheckIndex() &&*/ ( ThereAreIntersections() ) ){ - if( 0 < ( current_index_internal.intersection_index ) ){ - current_index_internal.intersection_index--; - return true; - } - else{ + return false; - if( ( 0 < ( current_index_internal.point_index ) ) ){ + } - current_index_internal.point_index--; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; - else current_index_internal.intersection_index = 0; + bool IterativePolygonInTermsOfIntersections::IncremtentIntersectionPeriodically() + { - return true; + if ((CheckIndex()) && (ThereAreIntersections())) + { + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > (current_index_internal.intersection_index + 1)) + { + current_index_internal.intersection_index++; + return true; + } + else + { - } - else if( Polygon_Intersections.size() > 0 ){ + bool success = false; - current_index_internal.point_index = Polygon_Intersections.size() - 1; + while (success == false) + { - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ); - else current_index_internal.intersection_index = 0; + if (Polygon_Intersections.size() > (current_index_internal.point_index + 1)) + { + current_index_internal.intersection_index = 0; + current_index_internal.point_index++; - } - else assert(0); // this should never happen since there are intersections, see ThereAreIntersections() + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { - } + return true; - } - else{ - std::cout<< " could not decrement !!!!!!!" < 0) + { + return true; - bool IterativePolygonInTermsOfIntersections::DecrementIntersectionPeriodically(){ + } - if( CheckIndex() && ( ThereAreIntersections() ) ){ + } - if( 0 < ( current_index_internal.intersection_index ) ){ - current_index_internal.intersection_index--; - return true; - } - else{ + } - while( ( 0 < ( current_index_internal.point_index ) ) ){ + } + } + else + { + return false; + } - current_index_internal.point_index--; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; - else current_index_internal.intersection_index = 0; + return false; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ + } - return true; - } + bool IterativePolygonInTermsOfIntersections::CheckIndex() + { - } + if (Polygon_Intersections.size() > current_index_internal.point_index) + { - if( current_index_internal.point_index != 0 ){ - assert(0); // This should never happen. - } - else if( Polygon_Intersections.size() > 0 ){ + if ((Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() > + current_index_internal.intersection_index)) + { + return true; + } + else + { + return false; + } - current_index_internal.point_index = Polygon_Intersections.size() - 1; + } + else + { + return false; + } - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ); - else{ + } - while( ( 0 < ( current_index_internal.point_index ) ) ){ + // Caution : This function can end up with a bad intersedction index. + bool IterativePolygonInTermsOfIntersections::DecrementPointOrIntersectionPeriodically() + { - current_index_internal.point_index--; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; - else current_index_internal.intersection_index = 0; - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ + if (/*CheckIndex() &&*/ (ThereAreIntersections())) + { - return true; + if (0 < (current_index_internal.intersection_index)) + { + current_index_internal.intersection_index--; + return true; + } + else + { - } + if ((0 < (current_index_internal.point_index))) + { - } - assert(0); // should never get here, since there are interesections + current_index_internal.point_index--; - } + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + current_index_internal.intersection_index = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1; + } + else + { + current_index_internal.intersection_index = 0; + } - } - else assert(0); // this should never happen since there are intersections, see ThereAreIntersections() + return true; - } - } - else return false; - return false; - } + } + else if (Polygon_Intersections.size() > 0) + { + current_index_internal.point_index = Polygon_Intersections.size() - 1; - bool IterativePolygonInTermsOfIntersections::CheckToBeRegarded(){ + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + current_index_internal.intersection_index = (Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1); + } + else + { + current_index_internal.intersection_index = 0; + } - return Polygon_Intersections.at( current_index_internal.point_index ).to_be_Regarded; - } + } + else + { + assert(0); // this should never happen since there are intersections, see ThereAreIntersections() + } + } - bool IterativePolygonInTermsOfIntersections::PreviousIntersectionPeriodically( LegacyWorldCoordinate2D& the_intersection ){ + } + else + { + std::cout << " could not decrement !!!!!!!" << std::endl; - if( DecrementIntersectionPeriodically() ){ - the_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - return true; - } - else{ - the_intersection.x =0; - the_intersection.y = 0; - return false; - } - return false; + bool check_index = CheckIndex(); + std::cout << " check_index : " << check_index << std::endl; - } + bool there_are_intersections = ThereAreIntersections(); + std::cout << " there_are_intersections : " << there_are_intersections << std::endl; + return false; + } - bool IterativePolygonInTermsOfIntersections::IsInside( LegacyWorldCoordinate3D& point_check , LegacyDoseVoxelIndex3D& the_dose_index ){ + return false; + } - if( ( point_check.x > the_dose_index.x ) && ( point_check.x < ( the_dose_index.x + 1 ) ) && ( point_check.y > the_dose_index.y ) && ( point_check.y < ( the_dose_index.y + 1 ) ) ){ - return true; - } - else return false; + bool IterativePolygonInTermsOfIntersections::DecrementIntersectionPeriodically() + { - } + if (CheckIndex() && (ThereAreIntersections())) + { + if (0 < (current_index_internal.intersection_index)) + { + current_index_internal.intersection_index--; + return true; + } + else + { + while ((0 < (current_index_internal.point_index))) + { + current_index_internal.point_index--; - bool IterativePolygonInTermsOfIntersections::ThisIntersection( LegacyWorldCoordinate2D& the_intersection ){ + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + current_index_internal.intersection_index = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1; + } + else + { + current_index_internal.intersection_index = 0; + } - if( CheckIndex() ){ - the_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - return true; - } - else{ - the_intersection.x =0; - the_intersection.y = 0; - return false; - } + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { - } - - - void IterativePolygonInTermsOfIntersections::ShowSelf(){ - - if( Polygon_Intersections.size() > 0 ){ - - for( GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++ ){ + return true; - std::cout<< " Polygon_Intersections.at( counter ).contour_point_voxel_coord.z : " << Polygon_Intersections.at( counter ).contour_point_voxel_coord.z <= 78 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.x <= 79 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.y >= 70 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.y <= 71 ) ){ - std::cout<< " Polygon_Intersections.at( counter ).contour_point_voxel_coord.x : " << Polygon_Intersections.at( counter ).contour_point_voxel_coord.x < 0) + { - if( ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).x >= 78 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).x <= 79 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).y >= 70 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).y <= 71 ) ){ - std::cout<< " Polygon bla ns_raw_and_column.at( internal_counter ).x : " << Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).x < 0) + { + current_index_internal.intersection_index = (Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1); + } + else + { - bool IterativePolygonInTermsOfIntersections::NextIntersection( LegacyWorldCoordinate2D& the_next_intersection ){ + while ((0 < (current_index_internal.point_index))) + { - if( IncremtentIntersection() ){ - the_next_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - return true; - } - else{ - the_next_intersection.x =0; - the_next_intersection.y = 0; - return false; - } + current_index_internal.point_index--; - } + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + current_index_internal.intersection_index = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.size() - 1; + } + else + { + current_index_internal.intersection_index = 0; + } + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > 0) + { + return true; + } - bool IterativePolygonInTermsOfIntersections::NextIntersectionPeriodically( LegacyWorldCoordinate2D& the_next_intersection ){ + } - if( IncremtentIntersectionPeriodically() ){ + assert(0); // should never get here, since there are interesections - the_next_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - return true; - } - else{ + } - the_next_intersection.x =0; - the_next_intersection.y = 0; - return false; - } + } + else + { + assert(0); // this should never happen since there are intersections, see ThereAreIntersections() + } - } + } + } + else + { + return false; + } + return false; + } - bool IterativePolygonInTermsOfIntersections::NextPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& next_point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ){ + bool IterativePolygonInTermsOfIntersections::CheckToBeRegarded() + { + return Polygon_Intersections.at(current_index_internal.point_index).to_be_Regarded; - if( IncremtentIntersectionPeriodically() ){ + } - // In der naechsten Zeile wird erst mal geprueft, ob eben um einen Konturpunkt weiter gesprungen wurde. - // Falls das der Fall ist ( current_index_internal.intersection_index == 0 ), wird geprueft, ob - // der Punkt, der eben uebersprungen wurde ungleich dem previous_point_or_intersection ist -// Falls es nicht direkt einen naechsten Schnittpunt gib, ohne dass ein Konturpunkt dazwischen leigt, springt -// IncremtentIntersectionPeriodically() so lange ueber Kontur-Zwischenpunkte hinweg, bis man an einem -// Konturpunkt angelangt ist, auf den ein Schnittpunkt folgt. Zunaechst wird in diesem Fall dann dieser Konturpunkt, -// nicht der darauf folgende Schnittpunkt betrachtet. + bool IterativePolygonInTermsOfIntersections::PreviousIntersectionPeriodically( + LegacyWorldCoordinate2D& the_intersection) + { - if( ( current_index_internal.intersection_index == 0 ) /*&& ( IsInside( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord , the_dose_index ) )*/ && ( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) ) ){ + if (DecrementIntersectionPeriodically()) + { + the_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); + return true; + } + else + { + the_intersection.x = 0; + the_intersection.y = 0; + return false; + } -//Hier erst den Kontur-Punkt anschauen -//erst wenn der nicht geht, dann schauen, ob es einen Schnittpunkt gibt und den Pruefen. -//Dabei darauf achten, -//dass der current_index_internal.intersection_index null sein kann, obwohl es kein nulltes Element gibt !! + return false; + } - next_point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; - next_point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; - - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( next_point_or_intersection.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( next_point_or_intersection.y ) ) ) return true; - } - else{ - - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() <= current_index_internal.intersection_index ) assert(0); // this should never happen, since IncrementIntersection should not end up with a bad index - - next_point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( next_point_or_intersection.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( next_point_or_intersection.y ) ) ) return true; - - - } + bool IterativePolygonInTermsOfIntersections::IsInside(LegacyWorldCoordinate3D& point_check , + LegacyDoseVoxelIndex3D& the_dose_index) + { - } - else{ + if ((point_check.x > the_dose_index.x) && (point_check.x < (the_dose_index.x + 1)) + && (point_check.y > the_dose_index.y) && (point_check.y < (the_dose_index.y + 1))) + { - assert(0); - - return false; - - } + return true; - return false; + } + else + { + return false; + } + } - } + bool IterativePolygonInTermsOfIntersections::ThisIntersection(LegacyWorldCoordinate2D& + the_intersection) + { - bool IterativePolygonInTermsOfIntersections::PreviousPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ){ + if (CheckIndex()) + { + the_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); + return true; + } + else + { + the_intersection.x = 0; + the_intersection.y = 0; + return false; + } - if( /*( IsInside( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord , the_dose_index ) ) && */ ( current_index_internal.intersection_index == 0 ) && ( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) ) ){ + } - point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; - point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; + void IterativePolygonInTermsOfIntersections::ShowSelf() + { - } - else{ - + if (Polygon_Intersections.size() > 0) + { - if( DecrementPointOrIntersectionPeriodically() ){ - - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ){ - - point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; - - } - else{ - - point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; - point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; - - } - - } - else{ - - - bool decrement = true; - - while(decrement){ - - decrement = DecrementPointOrIntersectionPeriodically(); + for (GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++) + { - if( decrement ){ - - if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ){ - - point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; - - } - else{ - - point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; - point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; - if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; - - } - - } - - - } - - assert(0); // this must not happen - - - } - return false; + std::cout << " Polygon_Intersections.at( counter ).contour_point_voxel_coord.z : " << + Polygon_Intersections.at(counter).contour_point_voxel_coord.z << std::endl; + if ((Polygon_Intersections.at(counter).contour_point_voxel_coord.x >= 78) + && (Polygon_Intersections.at(counter).contour_point_voxel_coord.x <= 79) + && (Polygon_Intersections.at(counter).contour_point_voxel_coord.y >= 70) + && (Polygon_Intersections.at(counter).contour_point_voxel_coord.y <= 71)) + { + std::cout << " Polygon_Intersections.at( counter ).contour_point_voxel_coord.x : " << + Polygon_Intersections.at(counter).contour_point_voxel_coord.x << std::endl; + std::cout << " Polygon_Intersections.at( counter ).contour_point_voxel_coord.y : " << + Polygon_Intersections.at(counter).contour_point_voxel_coord.y << std::endl; + } - } + for (GridIndexType internal_counter = 0 ; + internal_counter < Polygon_Intersections.at(counter).intersections_raw_and_column.size() ; + internal_counter++) + { - return false; + if ((Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).x >= 78) + && (Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).x <= 79) + && (Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).y >= 70) + && (Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).y <= 71)) + { + std::cout << " Polygon bla ns_raw_and_column.at( internal_counter ).x : " << + Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).x << std::endl; + std::cout << " Polygon bla ns_raw_and_column.at( internal_counter ).y : " << + Polygon_Intersections.at(counter).intersections_raw_and_column.at(internal_counter).y << std::endl; + } - } + } + } - int IterativePolygonInTermsOfIntersections::MaximumNumberOfElements(){ - if( number_of_intersections == (-1) ){ + } - int resulting_number = 0; + } - for( GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++ ){ - resulting_number += Polygon_Intersections.at( counter ).intersections_raw_and_column.size(); + bool IterativePolygonInTermsOfIntersections::NextIntersection(LegacyWorldCoordinate2D& + the_next_intersection) + { - } + if (IncremtentIntersection()) + { + the_next_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); + return true; + } + else + { + the_next_intersection.x = 0; + the_next_intersection.y = 0; + return false; + } - number_of_intersections = resulting_number; + } - return number_of_intersections; - } - else return number_of_intersections; - } + bool IterativePolygonInTermsOfIntersections::NextIntersectionPeriodically( + LegacyWorldCoordinate2D& the_next_intersection) + { - bool IterativePolygonInTermsOfIntersections::ThereAreIntersections(){ - if( number_of_intersections == (-1) ) number_of_intersections = MaximumNumberOfElements(); - if( number_of_intersections > 0 )return true; - else return false; - } + if (IncremtentIntersectionPeriodically()) + { + the_next_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); + return true; + } + else + { - void IterativePolygonInTermsOfIntersections::CreateUnifiedListOfRawAndColumnIntersections(){ + the_next_intersection.x = 0; + the_next_intersection.y = 0; + return false; + } - // iteration along polygon + } - for( unsigned int point_index = 0 ; point_index < ( Polygon_Intersections.size() ); point_index++ ){ - if( Polygon_Intersections.at( point_index ).intersections_raw_and_column.size() == 0 ){ - bool do_continue = true; + bool IterativePolygonInTermsOfIntersections::NextPointOrIntersectionPeriodically( + LegacyWorldCoordinate2D& previous_point_or_intersection , + LegacyWorldCoordinate2D& next_point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index) + { - Polygon_Intersections.at( point_index ).intersections_raw_and_column.clear(); - unsigned int raw_index = 0; - unsigned int column_index = 0; - LegacyWorldCoordinate3D coordinates_return = Polygon_Intersections.at( point_index ).contour_point_voxel_coord; + if (IncremtentIntersectionPeriodically()) + { - std::vector raw_intersections_work = Polygon_Intersections.at( point_index ).raw_intersections; - std::vector& raw_intersections_work_ref = raw_intersections_work; - std::vector column_intersections_work = Polygon_Intersections.at( point_index ).column_intersections; - std::vector& column_intersections_work_ref = column_intersections_work; + // In der naechsten Zeile wird erst mal geprueft, ob eben um einen Konturpunkt weiter gesprungen wurde. + // Falls das der Fall ist ( current_index_internal.intersection_index == 0 ), wird geprueft, ob + // der Punkt, der eben uebersprungen wurde ungleich dem previous_point_or_intersection ist - double last_distance = -1; + // Falls es nicht direkt einen naechsten Schnittpunt gib, ohne dass ein Konturpunkt dazwischen leigt, springt + // IncremtentIntersectionPeriodically() so lange ueber Kontur-Zwischenpunkte hinweg, bis man an einem + // Konturpunkt angelangt ist, auf den ein Schnittpunkt folgt. Zunaechst wird in diesem Fall dann dieser Konturpunkt, + // nicht der darauf folgende Schnittpunkt betrachtet. - while( do_continue ){ + if ((current_index_internal.intersection_index == + 0) /*&& ( IsInside( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord , the_dose_index ) )*/ + && ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y)))) + { - LegacyWorldCoordinate2D coordinates_raw_intersection; - coordinates_raw_intersection.x =0; - coordinates_raw_intersection.y = 0; + //Hier erst den Kontur-Punkt anschauen + //erst wenn der nicht geht, dann schauen, ob es einen Schnittpunkt gibt und den Pruefen. + //Dabei darauf achten, + //dass der current_index_internal.intersection_index null sein kann, obwohl es kein nulltes Element gibt !! - LegacyWorldCoordinate2D coordinates_column_intersection; - coordinates_column_intersection.x =0; - coordinates_column_intersection.y = 0; - LegacyWorldCoordinate2D coordinates_final_intersection; - coordinates_final_intersection.x =0; - coordinates_final_intersection.y = 0; + next_point_or_intersection.x = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.x; + next_point_or_intersection.y = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.y; - double distance_raw = 1000000000; - double distance_column = 1000000000; + if ((static_cast(previous_point_or_intersection.x) != static_cast + (next_point_or_intersection.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (next_point_or_intersection.y))) + { + return true; + } - if( raw_intersections_work.size() > 0 ){ + } + else + { - coordinates_raw_intersection = raw_intersections_work.at( 0 ); - distance_raw = ( coordinates_raw_intersection.x - coordinates_return.x ) * ( coordinates_raw_intersection.x - coordinates_return.x ) + ( coordinates_raw_intersection.y - coordinates_return.y ) * ( coordinates_raw_intersection.y - coordinates_return.y ); - distance_raw = sqrt( distance_raw ); - if( distance_raw < last_distance )assert(0); // this must never happen + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + <= current_index_internal.intersection_index) + { + assert(0); // this should never happen, since IncrementIntersection should not end up with a bad index + } - } + next_point_or_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - if( column_intersections_work.size() > 0 ){ + if ((static_cast(previous_point_or_intersection.x) != static_cast + (next_point_or_intersection.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (next_point_or_intersection.y))) + { + return true; + } - coordinates_column_intersection = column_intersections_work.at( 0 ); - distance_column = ( coordinates_column_intersection.x - coordinates_return.x ) * ( coordinates_column_intersection.x - coordinates_return.x ) + ( coordinates_column_intersection.y - coordinates_return.y ) * ( coordinates_column_intersection.y - coordinates_return.y ); - distance_column = sqrt( distance_column ); - if( distance_column < last_distance )assert(0); // this must never happen - } + } - if( ( distance_raw != 1000000000 ) && ( distance_column != 1000000000 ) ){ + } + else + { - if( distance_raw < distance_column ){ - coordinates_final_intersection = raw_intersections_work.at( raw_index ); - Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); - last_distance = distance_raw; - } - else if( distance_raw > distance_column ){ - coordinates_final_intersection = column_intersections_work.at( column_index ); - Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); - last_distance = distance_column; - } - else if( distance_raw == distance_column ){ - coordinates_final_intersection = column_intersections_work.at( column_index ); - Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); - // man muss diesen Punkt nicht zweimal beachten. - // deshalb nicht : Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); - last_distance = distance_column; - } + assert(0); - } - else if( distance_raw != 1000000000 ){ - coordinates_final_intersection = raw_intersections_work.at( raw_index ); - Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); - last_distance = distance_raw; - } - else if( distance_column != 1000000000 ){ - coordinates_final_intersection = column_intersections_work.at( column_index ); - Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); - last_distance = distance_column; - } - else{ + return false; - do_continue = false; + } - } + return false; - /* std::cout << " Here are the values : " << std::endl; - std::cout << " coordinates_return.x : " << coordinates_return.x << std::endl; - std::cout << " coordinates_return.y : " << coordinates_return.y << std::endl; + } - std::cout << " coordinates_final_intersection.x : " << coordinates_final_intersection.x << std::endl; - std::cout << " coordinates_final_intersection.y : " << coordinates_final_intersection.y << std::endl; - for( int counter = 0 ; counter < Polygon_Intersections.at( point_index ).intersections_raw_and_column.size() ; counter++ ){ - std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x << std::endl; - std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y << std::endl; + bool IterativePolygonInTermsOfIntersections::PreviousPointOrIntersectionPeriodically( + LegacyWorldCoordinate2D& previous_point_or_intersection , + LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index) + { - } + if (/*( IsInside( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord , the_dose_index ) ) && */ + (current_index_internal.intersection_index == 0) + && ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y)))) + { - for( int counter = 0 ; counter < raw_intersections_work.size() ; counter++ ){ + point_or_intersection.x = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.x; + point_or_intersection.y = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.y; - std::cout << " raw_intersections_work.at( counter ).x : " << raw_intersections_work.at( counter ).x << std::endl; - std::cout << " raw_intersections_work.at( counter ).y : " << raw_intersections_work.at( counter ).y << std::endl; + if ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y))) + { + return true; + } - } + } + else + { - for( int counter = 0 ; counter < column_intersections_work.size() ; counter++ ){ + if (DecrementPointOrIntersectionPeriodically()) + { - std::cout << " column_intersections_work.at( counter ).x : " << column_intersections_work.at( counter ).x << std::endl; - std::cout << " column_intersections_work.at( counter ).y : " << column_intersections_work.at( counter ).y << std::endl; + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > current_index_internal.intersection_index) + { - } */ + point_or_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); + if ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y))) + { + return true; + } - if( ( distance_raw != 1000000000 ) || ( distance_column != 1000000000 ) ) removeThisCoordinateFromBothLists( coordinates_final_intersection , raw_intersections_work_ref , column_intersections_work_ref ); + } + else + { - } + point_or_intersection.x = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.x; + point_or_intersection.y = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.y; - } + if ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y))) + { + return true; + } - } + } - } + } + else + { + bool decrement = true; - void IterativePolygonInTermsOfIntersections::removeThisCoordinateFromBothLists( LegacyWorldCoordinate2D the_coordinate , std::vector& raw_intersections_work_ref , std::vector& column_intersections_work_ref ){ + while (decrement) + { - LegacyWorldCoordinate2D coordinates_this_intersection; - coordinates_this_intersection.x =0; - coordinates_this_intersection.y = 0; + decrement = DecrementPointOrIntersectionPeriodically(); - std::vector::iterator iter; + if (decrement) + { + if (Polygon_Intersections.at(current_index_internal.point_index).intersections_raw_and_column.size() + > current_index_internal.intersection_index) + { - for( GridIndexType counter = 0 ; counter < raw_intersections_work_ref.size() ; counter++ ){ - coordinates_this_intersection = raw_intersections_work_ref.at( counter ); - if( ( coordinates_this_intersection.x == the_coordinate.x ) && ( coordinates_this_intersection.y == the_coordinate.y ) ){ - iter = raw_intersections_work_ref.begin(); - raw_intersections_work_ref.erase( iter ); - } - else break; - } + point_or_intersection = Polygon_Intersections.at( + current_index_internal.point_index).intersections_raw_and_column.at( + current_index_internal.intersection_index); - for( GridIndexType counter = 0 ; counter < column_intersections_work_ref.size() ; counter++ ){ - coordinates_this_intersection = column_intersections_work_ref.at( counter ); - if( ( coordinates_this_intersection.x == the_coordinate.x ) && ( coordinates_this_intersection.y == the_coordinate.y ) ){ - iter = column_intersections_work_ref.begin(); - column_intersections_work_ref.erase( iter ); - } - else break; - } + if ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y))) + { + return true; + } - } + } + else + { + point_or_intersection.x = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.x; + point_or_intersection.y = Polygon_Intersections.at( + current_index_internal.point_index).contour_point_voxel_coord.y; + if ((static_cast(previous_point_or_intersection.x) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.x)) + || (static_cast(previous_point_or_intersection.y) != static_cast + (Polygon_Intersections.at(current_index_internal.point_index).contour_point_voxel_coord.y))) + { + return true; + } - bool IterativePolygonInTermsOfIntersections::ItIsAsExpected( masks::legacy::PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ){ + } + } - if( Expected_Unified_Polygon_Intersections.size() != Polygon_Intersections.size() ) return false; - for( GridIndexType a_counter = 0 ; a_counter < Expected_Unified_Polygon_Intersections.size() ; a_counter++ ){ + } - if( ! IdenticalUniList( Expected_Unified_Polygon_Intersections.at( a_counter ) , Polygon_Intersections.at( a_counter ) ) ) return false; + assert(0); // this must not happen - } - return true; + } - } + return false; + } - bool IterativePolygonInTermsOfIntersections::IdenticalUniList( masks::legacy::PointLevelVector plv_a , masks::legacy::PointLevelVector plv_b ){ + return false; - if( plv_a.intersections_raw_and_column.size() != plv_b.intersections_raw_and_column.size() ) return false; + } - LegacyWorldCoordinate2D wco2da; - wco2da.x =0; - wco2da.y = 0; - LegacyWorldCoordinate2D wco2db; - wco2db.x =0; - wco2db.y = 0; + int IterativePolygonInTermsOfIntersections::MaximumNumberOfElements() + { - for( GridIndexType this_counter = 0 ; this_counter < plv_a.intersections_raw_and_column.size() ; this_counter++ ){ - wco2da = plv_a.intersections_raw_and_column.at( this_counter ); - wco2db = plv_b.intersections_raw_and_column.at( this_counter ); - if( ( static_cast( wco2da.x ) != static_cast( wco2db.x ) ) || ( static_cast( wco2da.y ) != static_cast( wco2db.y ) ) ) return false; - } + if (number_of_intersections == (-1)) + { - return true; + int resulting_number = 0; - } + for (GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++) + { + resulting_number += Polygon_Intersections.at(counter).intersections_raw_and_column.size(); - void IterativePolygonInTermsOfIntersections::RememberPosition(){ + } - IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal_remember; - IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = current_index_internal; + number_of_intersections = resulting_number; - CopyIntersectionIndex( intersection_index_to_ref , intersection_index_from_ref ); + return number_of_intersections; - } + } + else + { + return number_of_intersections; + } + } - void IterativePolygonInTermsOfIntersections::JumpToRememberedPosition(){ - IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = current_index_internal_remember; - IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal; + bool IterativePolygonInTermsOfIntersections::ThereAreIntersections() + { + if (number_of_intersections == (-1)) + { + number_of_intersections = MaximumNumberOfElements(); + } - CopyIntersectionIndex( intersection_index_to_ref , intersection_index_from_ref ); + if (number_of_intersections > 0) + { + return true; + } + else + { + return false; + } + } - } + void IterativePolygonInTermsOfIntersections::CreateUnifiedListOfRawAndColumnIntersections() + { - void IterativePolygonInTermsOfIntersections::SetCurrentIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_new_ref ){ + // iteration along polygon - IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal; + for (unsigned int point_index = 0 ; point_index < (Polygon_Intersections.size()); point_index++) + { - CopyIntersectionIndex( intersection_index_to_ref , intersection_index_new_ref ); + if (Polygon_Intersections.at(point_index).intersections_raw_and_column.size() == 0) + { - } - - - bool IterativePolygonInTermsOfIntersections::CheckCurrentIntersectionIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref ){ - - if( ( current_index_internal.point_index == intersection_index_compare_ref.point_index ) && ( current_index_internal.intersection_index == intersection_index_compare_ref.intersection_index ) ){ - return true; - } - else{ - return false; - } - - } + bool do_continue = true; + Polygon_Intersections.at(point_index).intersections_raw_and_column.clear(); - void IterativePolygonInTermsOfIntersections::MarkRelevantItems( LegacyDoseVoxelIndex3D aDoseIndex ){ + unsigned int raw_index = 0; + unsigned int column_index = 0; - WhichIntersection the_intersection_index; // the_intersection_index initialized to zero by constructor + LegacyWorldCoordinate3D coordinates_return = Polygon_Intersections.at( + point_index).contour_point_voxel_coord; - for( the_intersection_index.point_index = 0 ; the_intersection_index.point_index < ( Polygon_Intersections.size() ) ; the_intersection_index.point_index++ ){ - Polygon_Intersections.at( the_intersection_index.point_index ).to_be_Regarded = false; - } + std::vector raw_intersections_work = Polygon_Intersections.at( + point_index).raw_intersections; + std::vector& raw_intersections_work_ref = raw_intersections_work; + std::vector column_intersections_work = Polygon_Intersections.at( + point_index).column_intersections; + std::vector& column_intersections_work_ref = column_intersections_work; - for( the_intersection_index.point_index = 0 ; the_intersection_index.point_index < ( Polygon_Intersections.size() - 1 ) ; the_intersection_index.point_index++ ){ + double last_distance = -1; - LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at( the_intersection_index.point_index ).contour_point_voxel_coord; - LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at( the_intersection_index.point_index + 1 ).contour_point_voxel_coord; + while (do_continue) + { - if( VoxelInBetween( aDoseIndex , wc3da , wc3db ) ){ - Polygon_Intersections.at( the_intersection_index.point_index ).to_be_Regarded = true; - Polygon_Intersections.at( the_intersection_index.point_index + 1 ).to_be_Regarded = true; - } + LegacyWorldCoordinate2D coordinates_raw_intersection; + coordinates_raw_intersection.x = 0; + coordinates_raw_intersection.y = 0; - } + LegacyWorldCoordinate2D coordinates_column_intersection; + coordinates_column_intersection.x = 0; + coordinates_column_intersection.y = 0; - if( Polygon_Intersections.size() > 0 ){ + LegacyWorldCoordinate2D coordinates_final_intersection; + coordinates_final_intersection.x = 0; + coordinates_final_intersection.y = 0; - LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at( ( Polygon_Intersections.size() - 1 ) ).contour_point_voxel_coord; - LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at( 0 ).contour_point_voxel_coord; + double distance_raw = 1000000000; + double distance_column = 1000000000; - if( VoxelInBetween( aDoseIndex , wc3da , wc3db ) ){ - Polygon_Intersections.at( ( Polygon_Intersections.size() - 1 ) ).to_be_Regarded = true; - Polygon_Intersections.at( 0 ).to_be_Regarded = true; - } + if (raw_intersections_work.size() > 0) + { - } + coordinates_raw_intersection = raw_intersections_work.at(0); + distance_raw = (coordinates_raw_intersection.x - coordinates_return.x) * + (coordinates_raw_intersection.x - coordinates_return.x) + (coordinates_raw_intersection.y - + coordinates_return.y) * (coordinates_raw_intersection.y - coordinates_return.y); + distance_raw = sqrt(distance_raw); - } + if (distance_raw < last_distance) + { + assert(0); // this must never happen + } + } + if (column_intersections_work.size() > 0) + { + coordinates_column_intersection = column_intersections_work.at(0); + distance_column = (coordinates_column_intersection.x - coordinates_return.x) * + (coordinates_column_intersection.x - coordinates_return.x) + (coordinates_column_intersection.y - + coordinates_return.y) * (coordinates_column_intersection.y - coordinates_return.y); + distance_column = sqrt(distance_column); - bool IterativePolygonInTermsOfIntersections::VoxelInBetween( LegacyDoseVoxelIndex3D aDoseIndex , LegacyWorldCoordinate3D wc3da, LegacyWorldCoordinate3D wc3db ){ + if (distance_column < last_distance) + { + assert(0); // this must never happen + } - LegacyWorldCoordinate3D wc3dc_min; - LegacyWorldCoordinate3D wc3dc_max; + } - if( wc3da.x <= wc3db.x ){ - wc3dc_min.x =wc3da.x; - wc3dc_max.x =wc3db.x; - } - else{ - wc3dc_min.x =wc3db.x; - wc3dc_max.x =wc3da.x; - } + if ((distance_raw != 1000000000) && (distance_column != 1000000000)) + { - if( static_cast(wc3dc_min.x) > static_cast( aDoseIndex.x + 1.1 ) ) return false; - if( static_cast(wc3dc_max.x) < static_cast( aDoseIndex.x - 0.1 ) ) return false; + if (distance_raw < distance_column) + { + coordinates_final_intersection = raw_intersections_work.at(raw_index); + Polygon_Intersections.at(point_index).intersections_raw_and_column.push_back( + coordinates_raw_intersection); + last_distance = distance_raw; + } + else if (distance_raw > distance_column) + { + coordinates_final_intersection = column_intersections_work.at(column_index); + Polygon_Intersections.at(point_index).intersections_raw_and_column.push_back( + coordinates_column_intersection); + last_distance = distance_column; + } + else if (distance_raw == distance_column) + { + coordinates_final_intersection = column_intersections_work.at(column_index); + Polygon_Intersections.at(point_index).intersections_raw_and_column.push_back( + coordinates_column_intersection); + // man muss diesen Punkt nicht zweimal beachten. + // deshalb nicht : Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); + last_distance = distance_column; + } - if( wc3da.y <= wc3db.y ){ - wc3dc_min.y = wc3da.y; - wc3dc_max.y = wc3db.y; - } - else{ - wc3dc_min.y = wc3db.y; - wc3dc_max.y = wc3da.y; - } + } + else if (distance_raw != 1000000000) + { + coordinates_final_intersection = raw_intersections_work.at(raw_index); + Polygon_Intersections.at(point_index).intersections_raw_and_column.push_back( + coordinates_raw_intersection); + last_distance = distance_raw; + } + else if (distance_column != 1000000000) + { + coordinates_final_intersection = column_intersections_work.at(column_index); + Polygon_Intersections.at(point_index).intersections_raw_and_column.push_back( + coordinates_column_intersection); + last_distance = distance_column; + } + else + { - if( static_cast(wc3dc_min.y) > static_cast( aDoseIndex.y + 1.1 ) ) return false; - if( static_cast(wc3dc_max.y) < static_cast( aDoseIndex.y - 0.1 ) ) return false; + do_continue = false; - if( wc3da.z <= wc3db.z ){ - wc3dc_min.z = wc3da.z; - wc3dc_max.z = wc3db.z; - } - else{ - wc3dc_min.z = wc3db.z; - wc3dc_max.z = wc3da.z; - } + } + /* std::cout << " Here are the values : " << std::endl; - if( static_cast(wc3dc_min.z) > static_cast( aDoseIndex.z + 1.1 ) ) return false; // it can not be in between - if( static_cast(wc3dc_max.z) < static_cast( aDoseIndex.z - 0.1 ) ) return false; + std::cout << " coordinates_return.x : " << coordinates_return.x << std::endl; + std::cout << " coordinates_return.y : " << coordinates_return.y << std::endl; - return true; // can't be sure - } + std::cout << " coordinates_final_intersection.x : " << coordinates_final_intersection.x << std::endl; + std::cout << " coordinates_final_intersection.y : " << coordinates_final_intersection.y << std::endl; -}//namespace - }//namespace + for( int counter = 0 ; counter < Polygon_Intersections.at( point_index ).intersections_raw_and_column.size() ; counter++ ){ + + std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x << std::endl; + std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y << std::endl; + + } + + for( int counter = 0 ; counter < raw_intersections_work.size() ; counter++ ){ + + std::cout << " raw_intersections_work.at( counter ).x : " << raw_intersections_work.at( counter ).x << std::endl; + std::cout << " raw_intersections_work.at( counter ).y : " << raw_intersections_work.at( counter ).y << std::endl; + + } + + + for( int counter = 0 ; counter < column_intersections_work.size() ; counter++ ){ + + std::cout << " column_intersections_work.at( counter ).x : " << column_intersections_work.at( counter ).x << std::endl; + std::cout << " column_intersections_work.at( counter ).y : " << column_intersections_work.at( counter ).y << std::endl; + + } */ + + + if ((distance_raw != 1000000000) || (distance_column != 1000000000)) + { + removeThisCoordinateFromBothLists(coordinates_final_intersection , raw_intersections_work_ref , + column_intersections_work_ref); + } + + } + + } + + } + + } + + + + void IterativePolygonInTermsOfIntersections::removeThisCoordinateFromBothLists( + LegacyWorldCoordinate2D the_coordinate , + std::vector& raw_intersections_work_ref , + std::vector& column_intersections_work_ref) + { + + LegacyWorldCoordinate2D coordinates_this_intersection; + coordinates_this_intersection.x = 0; + coordinates_this_intersection.y = 0; + + std::vector::iterator iter; + + + for (GridIndexType counter = 0 ; counter < raw_intersections_work_ref.size() ; counter++) + { + coordinates_this_intersection = raw_intersections_work_ref.at(counter); + + if ((coordinates_this_intersection.x == the_coordinate.x) + && (coordinates_this_intersection.y == the_coordinate.y)) + { + iter = raw_intersections_work_ref.begin(); + raw_intersections_work_ref.erase(iter); + } + else + { + break; + } + } + + for (GridIndexType counter = 0 ; counter < column_intersections_work_ref.size() ; counter++) + { + coordinates_this_intersection = column_intersections_work_ref.at(counter); + + if ((coordinates_this_intersection.x == the_coordinate.x) + && (coordinates_this_intersection.y == the_coordinate.y)) + { + iter = column_intersections_work_ref.begin(); + column_intersections_work_ref.erase(iter); + } + else + { + break; + } + } + + } + + + + bool IterativePolygonInTermsOfIntersections::ItIsAsExpected( + masks::legacy::PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections) + { + + + if (Expected_Unified_Polygon_Intersections.size() != Polygon_Intersections.size()) + { + return false; + } + + for (GridIndexType a_counter = 0 ; a_counter < Expected_Unified_Polygon_Intersections.size() ; + a_counter++) + { + + if (! IdenticalUniList(Expected_Unified_Polygon_Intersections.at(a_counter) , + Polygon_Intersections.at(a_counter))) + { + return false; + } + + } + + return true; + + } + + + + bool IterativePolygonInTermsOfIntersections::IdenticalUniList(masks::legacy::PointLevelVector plv_a + , masks::legacy::PointLevelVector plv_b) + { + + if (plv_a.intersections_raw_and_column.size() != plv_b.intersections_raw_and_column.size()) + { + return false; + } + + LegacyWorldCoordinate2D wco2da; + wco2da.x = 0; + wco2da.y = 0; + + LegacyWorldCoordinate2D wco2db; + wco2db.x = 0; + wco2db.y = 0; + + for (GridIndexType this_counter = 0 ; this_counter < plv_a.intersections_raw_and_column.size() ; + this_counter++) + { + wco2da = plv_a.intersections_raw_and_column.at(this_counter); + wco2db = plv_b.intersections_raw_and_column.at(this_counter); + + if ((static_cast(wco2da.x) != static_cast(wco2db.x)) + || (static_cast(wco2da.y) != static_cast(wco2db.y))) + { + return false; + } + } + + return true; + + } + + + void IterativePolygonInTermsOfIntersections::RememberPosition() + { + + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = + current_index_internal_remember; + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = + current_index_internal; + + CopyIntersectionIndex(intersection_index_to_ref , intersection_index_from_ref); + + } + + + void IterativePolygonInTermsOfIntersections::JumpToRememberedPosition() + { + + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = + current_index_internal_remember; + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = + current_index_internal; + + CopyIntersectionIndex(intersection_index_to_ref , intersection_index_from_ref); + + } + + + void IterativePolygonInTermsOfIntersections::SetCurrentIntersectionIndex( + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_new_ref) + { + + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = + current_index_internal; + + CopyIntersectionIndex(intersection_index_to_ref , intersection_index_new_ref); + + } + + + bool IterativePolygonInTermsOfIntersections::CheckCurrentIntersectionIndexIdentical( + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref) + { + + if ((current_index_internal.point_index == intersection_index_compare_ref.point_index) + && (current_index_internal.intersection_index == + intersection_index_compare_ref.intersection_index)) + { + return true; + } + else + { + return false; + } + + } + + + void IterativePolygonInTermsOfIntersections::MarkRelevantItems(LegacyDoseVoxelIndex3D aDoseIndex) + { + + WhichIntersection + the_intersection_index; // the_intersection_index initialized to zero by constructor + + for (the_intersection_index.point_index = 0 ; + the_intersection_index.point_index < (Polygon_Intersections.size()) ; + the_intersection_index.point_index++) + { + Polygon_Intersections.at(the_intersection_index.point_index).to_be_Regarded = false; + } + + for (the_intersection_index.point_index = 0 ; + the_intersection_index.point_index < (Polygon_Intersections.size() - 1) ; + the_intersection_index.point_index++) + { + + LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at( + the_intersection_index.point_index).contour_point_voxel_coord; + LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at(the_intersection_index.point_index + + 1).contour_point_voxel_coord; + + if (VoxelInBetween(aDoseIndex , wc3da , wc3db)) + { + Polygon_Intersections.at(the_intersection_index.point_index).to_be_Regarded = true; + Polygon_Intersections.at(the_intersection_index.point_index + 1).to_be_Regarded = true; + } + + } + + if (Polygon_Intersections.size() > 0) + { + + LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at((Polygon_Intersections.size() - + 1)).contour_point_voxel_coord; + LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at(0).contour_point_voxel_coord; + + if (VoxelInBetween(aDoseIndex , wc3da , wc3db)) + { + Polygon_Intersections.at((Polygon_Intersections.size() - 1)).to_be_Regarded = true; + Polygon_Intersections.at(0).to_be_Regarded = true; + } + + } + + } + + + + + bool IterativePolygonInTermsOfIntersections::VoxelInBetween(LegacyDoseVoxelIndex3D aDoseIndex , + LegacyWorldCoordinate3D wc3da, LegacyWorldCoordinate3D wc3db) + { + + LegacyWorldCoordinate3D wc3dc_min; + LegacyWorldCoordinate3D wc3dc_max; + + if (wc3da.x <= wc3db.x) + { + wc3dc_min.x = wc3da.x; + wc3dc_max.x = wc3db.x; + } + else + { + wc3dc_min.x = wc3db.x; + wc3dc_max.x = wc3da.x; + } + + if (static_cast(wc3dc_min.x) > static_cast(aDoseIndex.x + 1.1)) + { + return false; + } + + if (static_cast(wc3dc_max.x) < static_cast(aDoseIndex.x - 0.1)) + { + return false; + } + + if (wc3da.y <= wc3db.y) + { + wc3dc_min.y = wc3da.y; + wc3dc_max.y = wc3db.y; + } + else + { + wc3dc_min.y = wc3db.y; + wc3dc_max.y = wc3da.y; + } + + if (static_cast(wc3dc_min.y) > static_cast(aDoseIndex.y + 1.1)) + { + return false; + } + + if (static_cast(wc3dc_max.y) < static_cast(aDoseIndex.y - 0.1)) + { + return false; + } + + if (wc3da.z <= wc3db.z) + { + wc3dc_min.z = wc3da.z; + wc3dc_max.z = wc3db.z; + } + else + { + wc3dc_min.z = wc3db.z; + wc3dc_max.z = wc3da.z; + } + + + if (static_cast(wc3dc_min.z) > static_cast(aDoseIndex.z + 1.1)) + { + return false; // it can not be in between + } + + if (static_cast(wc3dc_max.z) < static_cast(aDoseIndex.z - 0.1)) + { + return false; + } + + return true; // can't be sure + + } + + + }//namespace + }//namespace }//namespace diff --git a/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h index 3cc2c35..4bda207 100644 --- a/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h +++ b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h @@ -1,151 +1,189 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 __IterativePolygonInTermsOfIntersections_H #define __IterativePolygonInTermsOfIntersections_H #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbDoseIteratorInterface.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" // sollen Typen in Core neu definiert werden? #include "rttbContour_LEGACY.h" #include #include -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { // Die folgende Klasse handhabt die konkrete Speicherung der Schnittpunkte. // Kennt sich also mit der Speicherung der Schnittpunkte der Konturen mit den Voxelkanten aus. // Information auf Struktur-Polygonebene. - // Nimmt PolygonInfo den Zugriff auf diese Information ab. + // Nimmt PolygonInfo den Zugriff auf diese Information ab. - class IterativePolygonInTermsOfIntersections{ + class IterativePolygonInTermsOfIntersections + { public: IterativePolygonInTermsOfIntersections(); - ~IterativePolygonInTermsOfIntersections(){}; + ~IterativePolygonInTermsOfIntersections() {}; - void MarkRelevantItems( LegacyDoseVoxelIndex3D aDoseIndex ); - bool ItIsAsExpected( masks::legacy::PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ); + void MarkRelevantItems(LegacyDoseVoxelIndex3D aDoseIndex); + bool ItIsAsExpected(masks::legacy::PolygonInTermsOfIntersections + Expected_Unified_Polygon_Intersections); bool CheckToBeRegarded(); void ShowSelf(); - class WhichIntersection{ + class WhichIntersection + { public: - WhichIntersection(){ + WhichIntersection() + { point_index = 0; intersection_index = 0; - column_raw_or_unified = 0; - } + column_raw_or_unified = 0; + } - ~WhichIntersection(){}; + ~WhichIntersection() {}; unsigned int point_index; unsigned int intersection_index; - unsigned int column_raw_or_unified; - // 0 bedeutet Spalte, 1 bedeutet Zeile und 2 bedeutet vereinheitlichte Liste der Zeilen uns Spaltenschnittpunkte + unsigned int column_raw_or_unified; + // 0 bedeutet Spalte, 1 bedeutet Zeile und 2 bedeutet vereinheitlichte Liste der Zeilen uns Spaltenschnittpunkte }; - void ResetIntersectionIndex(); - bool ThisIntersection( LegacyWorldCoordinate2D& the_intersection ); + void ResetIntersectionIndex(); + bool ThisIntersection(LegacyWorldCoordinate2D& the_intersection); void RememberPosition(); bool IncremtentIntersection(); bool IncremtentIntersectionPeriodically(); - bool NextIntersectionPeriodically( LegacyWorldCoordinate2D& the_next_intersection ); - bool NextPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& next_point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ); + bool NextIntersectionPeriodically(LegacyWorldCoordinate2D& the_next_intersection); + bool NextPointOrIntersectionPeriodically(LegacyWorldCoordinate2D& previous_point_or_intersection , + LegacyWorldCoordinate2D& next_point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index); int MaximumNumberOfElements(); bool ThereAreIntersections(); void JumpToRememberedPosition(); - bool RunForwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref , LegacyDoseVoxelIndex3D the_dose_index ); - bool RunBackwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - void CleanOut( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - bool NextIntersection( LegacyWorldCoordinate2D& the_next_intersection ); - bool PreviousPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ); - bool PreviousIntersectionPeriodically( LegacyWorldCoordinate2D& the_intersection ); - void ResetIntersectionIndex( WhichIntersection& intersection_set_to ); - void SetIntersectionsAndResetIntersectionIndex( const masks::legacy::PolygonInTermsOfIntersections& Polygon_Intersections_In ); - bool CheckIsIntersection( LegacyWorldCoordinate2D& edge_coord , WhichIntersection& the_intersection_index_ref ); - LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinates( WhichIntersection& the_intersection_index_ref ); - LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesFurther( WhichIntersection& the_intersection_index_ref , int ahead ); - LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesPrevious( WhichIntersection& the_intersection_index_ref , unsigned int back ); + bool RunForwardToNextIntersection(LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref , + LegacyDoseVoxelIndex3D the_dose_index); + bool RunBackwardToNextIntersection(LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + void CleanOut(LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + bool NextIntersection(LegacyWorldCoordinate2D& the_next_intersection); + bool PreviousPointOrIntersectionPeriodically(LegacyWorldCoordinate2D& previous_point_or_intersection + , LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index); + bool PreviousIntersectionPeriodically(LegacyWorldCoordinate2D& the_intersection); + void ResetIntersectionIndex(WhichIntersection& intersection_set_to); + void SetIntersectionsAndResetIntersectionIndex(const masks::legacy::PolygonInTermsOfIntersections& + Polygon_Intersections_In); + bool CheckIsIntersection(LegacyWorldCoordinate2D& edge_coord , + WhichIntersection& the_intersection_index_ref); + LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinates(WhichIntersection& + the_intersection_index_ref); + LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesFurther( + WhichIntersection& the_intersection_index_ref , int ahead); + LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesPrevious( + WhichIntersection& the_intersection_index_ref , unsigned int back); bool selfTest(); bool CheckCurrentIndexInitForTest(); - void SetCurrentIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_new_ref ); - bool CheckCurrentIntersectionIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref ); + void SetCurrentIntersectionIndex(IterativePolygonInTermsOfIntersections::WhichIntersection& + intersection_index_new_ref); + bool CheckCurrentIntersectionIndexIdentical( + IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref); void PrintIntersectionIndex(); - private: - - unsigned int GetRestpectiveIntersectionVectorLength( WhichIntersection& the_intersection_index_ref ); - LegacyWorldCoordinate2D GetRestpectiveIntersection( WhichIntersection& the_intersection_index_ref ); - LegacyWorldCoordinate2D GetRestpectiveIntersectionFurther( WhichIntersection& the_intersection_index_ref , int ahead ); - bool PointIndexIsFine( WhichIntersection& the_intersection_index_ref ); - LegacyWorldCoordinate3D GetFirstPointThisPolygon( WhichIntersection& the_intersection_index_ref ); - bool AppendIntermediatePointOrCloseForward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - bool AppendIntermediatePointOrCloseBackward(LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - void AppendThisIntermediatePoint( std::vector& snippet_intermediate_content_ref ); + private: + + unsigned int GetRestpectiveIntersectionVectorLength(WhichIntersection& the_intersection_index_ref); + LegacyWorldCoordinate2D GetRestpectiveIntersection(WhichIntersection& the_intersection_index_ref); + LegacyWorldCoordinate2D GetRestpectiveIntersectionFurther(WhichIntersection& + the_intersection_index_ref , int ahead); + bool PointIndexIsFine(WhichIntersection& the_intersection_index_ref); + LegacyWorldCoordinate3D GetFirstPointThisPolygon(WhichIntersection& the_intersection_index_ref); + bool AppendIntermediatePointOrCloseForward(LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + bool AppendIntermediatePointOrCloseBackward(LegacyWorldCoordinate2D& point_of_interest_start_ref , + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + void AppendThisIntermediatePoint(std::vector& + snippet_intermediate_content_ref); bool IncrementNeeded(); - bool DecrementNeeded(); - bool OneDiffers( std::vector& snippet_intermediate_content_ref , LegacyWorldCoordinate2D& point_of_interest_start_ref ); - bool IdenticalUniList( masks::legacy::PointLevelVector plv_a , masks::legacy::PointLevelVector plv_b ); - bool CloseWithoutIncrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - bool CloseWithoutDecrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); - void PeriodicPolygonPointIncrement(); - void PeriodicPolygonPointDecrement(); - void CopyIntersectionIndex( WhichIntersection& to_ref , WhichIntersection& from_ref ); - bool CheckIndex(); - bool DecrementPointOrIntersectionPeriodically(); - bool DecrementIntersectionPeriodically(); - void CreateUnifiedListOfRawAndColumnIntersections(); - void removeThisCoordinateFromBothLists( LegacyWorldCoordinate2D the_coordinate , std::vector& raw_intersections_work_ref , std::vector& column_intersections_work_ref ); - bool VoxelInBetween( LegacyDoseVoxelIndex3D aDoseIndex , LegacyWorldCoordinate3D wc3da, LegacyWorldCoordinate3D wc3db ); - bool IsInside( LegacyWorldCoordinate3D& point_check , LegacyDoseVoxelIndex3D& the_dose_index ); + bool DecrementNeeded(); + bool OneDiffers(std::vector& snippet_intermediate_content_ref , + LegacyWorldCoordinate2D& point_of_interest_start_ref); + bool IdenticalUniList(masks::legacy::PointLevelVector plv_a , + masks::legacy::PointLevelVector plv_b); + bool CloseWithoutIncrement(LegacyWorldCoordinate2D& point_of_interest_start_ref, + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + bool CloseWithoutDecrement(LegacyWorldCoordinate2D& point_of_interest_start_ref, + LegacyWorldCoordinate2D& point_of_interest_end_ref , + std::vector& snippet_intermediate_content_ref); + void PeriodicPolygonPointIncrement(); + void PeriodicPolygonPointDecrement(); + void CopyIntersectionIndex(WhichIntersection& to_ref , WhichIntersection& from_ref); + bool CheckIndex(); + bool DecrementPointOrIntersectionPeriodically(); + bool DecrementIntersectionPeriodically(); + void CreateUnifiedListOfRawAndColumnIntersections(); + void removeThisCoordinateFromBothLists(LegacyWorldCoordinate2D the_coordinate , + std::vector& raw_intersections_work_ref , + std::vector& column_intersections_work_ref); + bool VoxelInBetween(LegacyDoseVoxelIndex3D aDoseIndex , LegacyWorldCoordinate3D wc3da, + LegacyWorldCoordinate3D wc3db); + bool IsInside(LegacyWorldCoordinate3D& point_check , LegacyDoseVoxelIndex3D& the_dose_index); PolygonInTermsOfIntersections Polygon_Intersections; WhichIntersection current_index_internal; - WhichIntersection current_index_internal_remember; - int number_of_intersections; + WhichIntersection current_index_internal_remember; + int number_of_intersections; }; } } -} +} -#endif \ No newline at end of file +#endif \ No newline at end of file diff --git a/code/masks/legacy/rttbMask.cpp b/code/masks/legacy/rttbMask.cpp index bdeb4e2..0371d1e 100644 --- a/code/masks/legacy/rttbMask.cpp +++ b/code/masks/legacy/rttbMask.cpp @@ -1,3721 +1,4825 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbMask.h" #include "rttbNullPointerException.h" #include "rttbSelfIntersectingStructureException.h" #include #include #include #include #include using namespace std; -namespace rttb{ - namespace masks{ - namespace legacy{ - - - Mask::Mask( DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure ) { - - MaskField.resize(1); - for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; - - FieldOfIntersections = NULL; - do_detailed_subvox = false; - - this->_doseIter=aDoseIter; - this->_structure=aStructure; - //this->_withSubVoxelFraction=withSubVoxelFraction; - - if(!_doseIter) - throw core::NullPointerException("aDoseIter must not be NULL!"); - if(!_structure) - throw core::NullPointerException("aStructure must not be NULL!"); - - this->_doseIter->start(); - this->GInf.push_back( _doseIter->getGeometricInfo() ); - - //std::cout << "init begin"<~FieldOfScalar(); - //MaskField.resize(0); - - sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); - this->calcDoseData(); - - this->clearMaskField(); - - } - - Mask::Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure ) { - - if(!aDoseGeoInfo){ - throw core::NullPointerException("aDoseGeoInfo must not be NULL!"); - } - - MaskField.resize(1); - for(int i = 0 ; i < MaskField.size() ; i++ ) - { - MaskField.at(i) = NULL; - } - - FieldOfIntersections = NULL; - do_detailed_subvox = false; - - if(!aStructure){ - throw core::NullPointerException("aStructure must not be NULL!"); - } - this->_structure=aStructure; - //this->_withSubVoxelFraction=withSubVoxelFraction; - - this->GInf.push_back( *aDoseGeoInfo ); - - //std::cout << "init begin"<~FieldOfScalar(); - //MaskField.resize(0); - - sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); - - this->clearMaskField(); - - } -/* - Mask::Mask(rttb::core::DoseIteratorInterface *aDoseIter, const std::vector& aDoseVoxelVector){ - _structure=NULL; - FieldOfIntersections = NULL; - do_detailed_subvox = false; - - MaskField.resize(1); - for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; - - _doseIter=aDoseIter; - if(!_doseIter) - throw core::NullPointerException("aDoseIter must not be NULL!"); - this->_doseIter->start(); - this->GInf.push_back( _doseIter->getGeometricInfo() ); - //Get valid DoseVoxel - for(int i=0;icalcDoseData(); - - this->clearMaskField(); - - } +namespace rttb +{ + namespace masks + { + namespace legacy + { + + + Mask::Mask(DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure) + { + + MaskField.resize(1); + + for (int i = 0 ; i < MaskField.size() ; i++) + { + MaskField.at(i) = NULL; + } + + FieldOfIntersections = NULL; + do_detailed_subvox = false; + + this->_doseIter = aDoseIter; + this->_structure = aStructure; + //this->_withSubVoxelFraction=withSubVoxelFraction; + + if (!_doseIter) + { + throw core::NullPointerException("aDoseIter must not be NULL!"); + } + + if (!_structure) + { + throw core::NullPointerException("aStructure must not be NULL!"); + } + + this->_doseIter->start(); + this->GInf.push_back(_doseIter->getGeometricInfo()); + + //std::cout << "init begin"<~FieldOfScalar(); + //MaskField.resize(0); + + sort(_doseVoxelInStructure.begin(), _doseVoxelInStructure.end()); + this->calcDoseData(); + + this->clearMaskField(); + + } + + Mask::Mask(core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure) + { + + if (!aDoseGeoInfo) + { + throw core::NullPointerException("aDoseGeoInfo must not be NULL!"); + } + + MaskField.resize(1); + + for (int i = 0 ; i < MaskField.size() ; i++) + { + MaskField.at(i) = NULL; + } + + FieldOfIntersections = NULL; + do_detailed_subvox = false; + + if (!aStructure) + { + throw core::NullPointerException("aStructure must not be NULL!"); + } + + this->_structure = aStructure; + //this->_withSubVoxelFraction=withSubVoxelFraction; + + this->GInf.push_back(*aDoseGeoInfo); + + //std::cout << "init begin"<~FieldOfScalar(); + //MaskField.resize(0); + + sort(_doseVoxelInStructure.begin(), _doseVoxelInStructure.end()); + + this->clearMaskField(); + + } + /* + Mask::Mask(rttb::core::DoseIteratorInterface *aDoseIter, const std::vector& aDoseVoxelVector){ + _structure=NULL; + FieldOfIntersections = NULL; + do_detailed_subvox = false; + + MaskField.resize(1); + for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; + + _doseIter=aDoseIter; + if(!_doseIter) + throw core::NullPointerException("aDoseIter must not be NULL!"); + this->_doseIter->start(); + this->GInf.push_back( _doseIter->getGeometricInfo() ); + //Get valid DoseVoxel + for(int i=0;icalcDoseData(); + + this->clearMaskField(); + + } + + */ + + Mask::~Mask() + { + + /*if( FieldOfIntersections != NULL )FieldOfIntersections->~FieldOfPointer(); + + for( int i = 0 ; i < MaskField.size() ; i++ ){ + if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); + } + MaskField.resize(1); + for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL;*/ + + } + + void Mask::clearMaskField() + { + if (FieldOfIntersections != NULL) + { + FieldOfIntersections->~FieldOfPointer(); + } + + for (int i = 0 ; i < MaskField.size() ; i++) + { + if (MaskField.at(i) != NULL) + { + MaskField.at(i)->~FieldOfScalar(); + } + } + + MaskField.resize(1); + + for (int i = 0 ; i < MaskField.size() ; i++) + { + MaskField.at(i) = NULL; + } + } + + void Mask::resetDose(DoseIteratorInterface* aDoseIterator) + { + _doseIter = aDoseIterator; + + if (!_doseIter) + { + throw core::NullPointerException("aDoseIter must not be NULL!"); + } + + this->_doseIter->start(); + + //if geometric info not changed or if the voxelization external + if (_doseIter->getGeometricInfo() == this->GInf.at(0) || this->_structure == NULL) + { + //std::cout << "reset dose."<calcDoseData(); + } + else + { + //std::cout << "recalculate mask"<GInf.push_back(_doseIter->getGeometricInfo()); + + Init(); + + Calc(); + sort(_doseVoxelInStructure.begin(), _doseVoxelInStructure.end()); + this->calcDoseData(); + + this->clearMaskField(); + + } + } + + + /*const std::vector& Mask::getDoseVoxelIndexInStructure() const{ + return doseVoxelIndexInStructure; + }*/ + + /*! @brief Get the dose voxels which lie inside the structure + * @return Return the vector of DoseVoxel which are inside the structure (with voxel proportion information) + */ + const std::vector& Mask::getDoseVoxelInStructure() const + { + return this->_doseVoxelInStructure; + } + + /*! @brief Set the dose voxels which lie inside the structure + * @return Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) + */ + void Mask::setDoseVoxelInStructure(std::vector aDoseVoxelVector) + { + _doseVoxelInStructure = aDoseVoxelVector; + + } + + const DoseIteratorInterface& Mask::getDoseIterator() const + { + return *_doseIter; + } + + const StructureLegacy& Mask::getRTStructure() const + { + return *_structure; + } + + /*const std::vector Mask::getDoseData() const{ + return _doseData; + }*/ + + + + //get absolute dose data of the voxels which are inside the structure; + void Mask::calcDoseData() + { + _doseData.clear(); + /*this->_doseIter->start(); + std::vector doseDis;//dose distribution + while(_doseIter->hasNextVoxel()){ + doseDis.push_back(_doseIter->next()); + }*/ + + _doseIter->start(); + int count = 0; + + std::vector::iterator it = _doseVoxelInStructure.begin(); + + while (_doseIter->hasNextVoxel() && it != _doseVoxelInStructure.end()) + { + // Anmerkung von Martina fuer Lanlan: Eigentlich ist der Witz beim Iterator gerade, dass man sich ueber die + // Innereien des Iterators als Programmierer, der ihn einsetzt keine Gedanken machen muss. Hier ist die fehlerfreie Funktion + // des Codes jedoch von einigen Eigenschaften des Iterators, insbesondere von der Richtung in der iteriert wird, + // abhaengig. Das kommt daher, dass der Programmierer den Iterator von innen kannte und Eigenschaften nutzt, die er eigentlich + // nicht kennem wuerde, als Anwendungsprogrammierer des Iterators. Weil der Programmierer den Iterator aber selbst geschrieben hatte, + // deshalb wuste er es hier ... + // Das kann zur Folgen haben, dass nach einer Aenderung in Code des Iterators Mask nicht mehr korrekt + // funktioniert (z.B. wenn die Richtung der iteration im Koordinatensystem sich umkehren wuerde) man kann darueber + // nachdenken ob das problematisch ist .... + // Es ist ja auch so, dass die RTToolbox dafuer gemacht ist erweitert zu werden. Es koennen andere Iteratoren dazu kommen. + // Wollen wir hier spezifischer werden was den Typ des erlaubten Iterators betrifft? Das wuerde helfen. + double doseValue = _doseIter->next(); + LegacyDoseVoxelIndex3D doseVoxel = (*it).getVoxelIndex3D(); + + if (count == doseVoxel.z * GInf.at(0).getNumColumns()*GInf.at(0).getNumRows() + doseVoxel.y * + GInf.at(0).getNumColumns() + doseVoxel.x) + { + _doseData.push_back(doseValue); + it++; + } + + count++; + } + + } + + + void Mask::Calc() + { + //std::cout << "calc begin"<= 0 ; resolution_level--) + { + + //std::cout << "GetIntersections"<= 0 ; resolution_level--) + { + + for (int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++) + { + + LegacyUnsignedIndex3D index_internal; + index_internal.x = 0; + index_internal.y = 0; + index_internal.z = index_z; + + for (int resolution_level = (GInf.size() - 1) ; resolution_level >= 0 ; resolution_level--) + { + + if ((MarkInterestingArea.at(resolution_level).at(index_z).index_end.x != 0) + && (MarkInterestingArea.at(resolution_level).at(index_z).index_end.y != 0)) + { + + for (index_internal.x = MarkInterestingArea.at(resolution_level).at(index_z).index_begin.x ; + index_internal.x <= MarkInterestingArea.at(resolution_level).at(index_z).index_end.x ; + index_internal.x++) + { + for (index_internal.y = MarkInterestingArea.at(resolution_level).at(index_z).index_begin.y ; + index_internal.y <= MarkInterestingArea.at(resolution_level).at(index_z).index_end.y ; + index_internal.y++) + { + + + if (MaskField.at(resolution_level)->GetData(index_internal.x, index_internal.y, + index_internal.z) == brightness_inside) + { + + CheckUppwardBlockSameIntensity(resolution_level , index_internal, brightness_inside); + + } + + if (MaskField.at(resolution_level)->GetData(index_internal.x, index_internal.y, + index_internal.z) == brightness_outside) + { + + CheckUppwardBlockSameIntensity(resolution_level , index_internal, brightness_outside); + + } + + if (MaskField.at(resolution_level)->GetData(index_internal.x, index_internal.y, + index_internal.z) == brightness_border) + { + + CheckUppwardOneOutOfThisBlockHasSameIntensity(resolution_level , index_internal , + brightness_border); + + } + + if (MaskField.at(resolution_level)->GetData(index_internal.x, index_internal.y, + index_internal.z) == brightness_unknown) + { + assert(0); // This should not happen since each voxel must be regarded. + } + + + + + + } // for( index_internal.y + + } // for( index_internal.x + + + } // if( ( MarkInterestingArea.at(resolution_level).at( index_z + + } // for( int resolution_level + + } + + } // resolution_level + + } + + + void Mask::CheckUppwardBlockSameIntensity(int resolution_level_in , LegacyUnsignedIndex3D index_in , + int brightness) + { + + if (resolution_level_in > 0) + { + + for (int resolution_level = (resolution_level_in - 1) ; resolution_level >= 0 ; resolution_level--) + { + + int resolution_difference = (resolution_level_in - resolution_level); + + double block_length = GetBlockLengthThisResolutionLevel(resolution_difference); + + LegacyUnsignedIndex3D index_internal; + index_internal.x = index_in.x * block_length; + index_internal.y = index_in.y * block_length; + index_internal.z = index_in.z; + + if ((index_internal.x >= MarkInterestingArea.at(resolution_level).at( + index_internal.z).index_begin.x) + && (index_internal.x <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.x - + block_length)) + && (index_internal.y >= MarkInterestingArea.at(resolution_level).at(index_internal.z).index_begin.y) + && (index_internal.y <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.y - + block_length))) + { + if ((index_in.x >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.x) + && (index_in.x <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.x - + block_length)) + && (index_in.y >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.y) + && (index_in.y <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.y - + block_length))) + { + + bool its_fine = MaskField.at(resolution_level)->CheckBlockSameIntensity(index_internal.x , + index_internal.y, index_internal.z , block_length , brightness); + + + assert(its_fine); + + } + } + + } + + } + + } + + + void Mask::SetUppwardBlockThisIntensity(int resolution_level_in , LegacyUnsignedIndex3D index_in , + int brightness) + { + + if (resolution_level_in > 0) + { + + for (int resolution_level = (resolution_level_in - 1) ; resolution_level >= 0 ; resolution_level--) + { + + int resolution_difference = (resolution_level_in - resolution_level); + + double block_length = GetBlockLengthThisResolutionLevel(resolution_difference); + + LegacyUnsignedIndex3D index_internal; + index_internal.x = index_in.x * block_length; + index_internal.y = index_in.y * block_length; + index_internal.z = index_in.z; + + + + if ((index_internal.x >= MarkInterestingArea.at(resolution_level).at( + index_internal.z).index_begin.x) + && (index_internal.x <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.x - + block_length)) + && (index_internal.y >= MarkInterestingArea.at(resolution_level).at(index_internal.z).index_begin.y) + && (index_internal.y <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.y - + block_length))) + { + if ((index_in.x >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.x) + && (index_in.x <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.x - + block_length)) + && (index_in.y >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.y) + && (index_in.y <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.y - + block_length))) + { + + MaskField.at(resolution_level)->SetBlockThisIntensity(index_internal.x , index_internal.y, + index_internal.z , block_length , brightness); + + } + } + + } + + } + + } + + + void Mask::CheckUppwardOneOutOfThisBlockHasSameIntensity(int resolution_level_in , + LegacyUnsignedIndex3D index_in , int brightness) + { + + if ((resolution_level_in > 0) && (resolution_level_in < (MaskField.size() - 1))) + { + + for (int resolution_level = (resolution_level_in - 1) ; resolution_level >= 0 ; resolution_level--) + { + + int resolution_difference = (resolution_level_in - resolution_level); + + double block_length = GetBlockLengthThisResolutionLevel(resolution_difference); + + LegacyUnsignedIndex3D index_internal; + index_internal.x = index_in.x * block_length; + index_internal.y = index_in.y * block_length; + index_internal.z = index_in.z; + + if ((index_internal.x >= MarkInterestingArea.at(resolution_level).at( + index_internal.z).index_begin.x) + && (index_internal.x <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.x - + block_length)) + && (index_internal.y >= MarkInterestingArea.at(resolution_level).at(index_internal.z).index_begin.y) + && (index_internal.y <= (MarkInterestingArea.at(resolution_level).at(index_internal.z).index_end.y - + block_length))) + { + if ((index_in.x >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.x) + && (index_in.x <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.x - + block_length)) + && (index_in.y >= MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_begin.y) + && (index_in.y <= (MarkInterestingArea.at(resolution_level_in).at(index_in.z).index_end.y - + block_length))) + { + + bool its_fine = MaskField.at(resolution_level)->CheckOneOutOfThisBlockHasSameIntensity( + index_internal.x , index_internal.y, index_internal.z , block_length , brightness); + + assert(its_fine); + + } + + } + + } + + } + + } + + + bool Mask::ContourFine() + { + + //std::cout << "ContourFine begin"<getLegacyStructureVector(); + LegacyPolygonSequenceType& strVector_ref = strVector; + + correspoinding_structure_vector str_v; + std::vector wich_slice; + + for (unsigned int struct_index = 0 ; struct_index < Intersections.at(0).size() ; struct_index++) + { + + wich_slice.clear(); + + /* if( strVector.at( struct_index ).size() < 2 ){ + std::cerr<< " The Polygon consists of just one point ! That doesn't make sense in Radiotherapy. Program will be terminated. " < ( i+1 ) ) secondPoint = pitoiA.at( i+1 ).contour_point_voxel_coord; + else + { + secondPoint = pitoiA.at(0).contour_point_voxel_coord; + } + + for (; itB != pitoiB.end() ; itB++) + { + //for( ; j ( j+1 ) ) fourthPoint = pitoiB.at( j+1 ).contour_point_voxel_coord; + else + { + fourthPoint = pitoiB.at(0).contour_point_voxel_coord; + } + + //std::cout < firstPoint.x) + { + x_min = firstPoint.x; + x_max = secondPoint.x; + } + + bool it_is_in_between = 1; + + if ((x < x_min) || (x > x_max)) + { + it_is_in_between = 0; + } + + + if ((beta > 0) && (beta < 1) && it_is_in_between) + { + return true; + } + else + { + return false; + } + + } + else + { + return false; + } + + } + + if ((secondPoint.x - firstPoint.x) == 0) + { + + if ((fourthPoint.x - thirdPoint.x) != 0) + { + + float beta = (firstPoint.x - thirdPoint.x) / (fourthPoint.x - thirdPoint.x); + + float y = (fourthPoint.y - thirdPoint.y) * beta + thirdPoint.y; + + float y_min = secondPoint.y; + float y_max = firstPoint.y; + + if (secondPoint.y > firstPoint.y) + { + y_min = firstPoint.y; + y_max = secondPoint.y; + } + + bool it_is_in_between = 1; + + if ((y < y_min) || (y > y_max)) + { + it_is_in_between = 0; + } + + if ((beta > 0) && (beta < 1) && it_is_in_between) + { + + return true; + } + else + { + return false; + } + } + else + { + return false; + } + + } + + + if (((secondPoint.y - firstPoint.y) == 0) || ((secondPoint.x - firstPoint.x) == 0)) + { + assert(0); + } + + + if ((((fourthPoint.x - thirdPoint.x) / (secondPoint.x - firstPoint.x)) - (( + fourthPoint.y - thirdPoint.y) / (secondPoint.y - firstPoint.y))) == 0) + { + return false; // parallel, schneiden sich nicht ! + } + + + if ((((fourthPoint.x - thirdPoint.x) / (secondPoint.x - firstPoint.x)) - (( + fourthPoint.y - thirdPoint.y) / (secondPoint.y - firstPoint.y))) == 0) + { + assert(0); + } + + + float beta = (((thirdPoint.y - firstPoint.y) / (secondPoint.y - firstPoint.y)) - (( + thirdPoint.x - firstPoint.x) / (secondPoint.x - firstPoint.x))) / ((( + fourthPoint.x - thirdPoint.x) / (secondPoint.x - firstPoint.x)) - ((fourthPoint.y - + thirdPoint.y) / (secondPoint.y - firstPoint.y))) ; + float alpha = ((fourthPoint.x - thirdPoint.x) * beta + thirdPoint.x - firstPoint.x) / + (secondPoint.x - firstPoint.x); + + if (((beta > 0) && (beta < 1)) && ((alpha > 0) + && (alpha < 1))) // falls diese Bedingung nicht erfuellt ist, gibt es zwar einen Schnittpunkt der Geraden, aber nicht im relevanten Bereich + { + + return true; + + } + + return false; + + } + + + + + + void Mask::FloodFill4(UnsignedIndexList indexList, int oldcolor, int newcolor, int resolution_level) + { + + + LegacyUnsignedIndex3D index; + index.x = 0; + index.y = 0; + index.z = 0; + + while (!indexList.empty()) + { + LegacyUnsignedIndex3D frontIndex = indexList.front(); + index.z = frontIndex.z; + + if (MaskField.at(resolution_level)->GetData(frontIndex.x, frontIndex.y, frontIndex.z) == oldcolor) + { + //insert index + if (frontIndex.y + 1 <= MarkInterestingArea.at(resolution_level).at(frontIndex.z).index_end.y + && MaskField.at(resolution_level)->GetData(frontIndex.x, frontIndex.y + 1, + frontIndex.z) == oldcolor) + { + index.x = frontIndex.x; + index.y = frontIndex.y + 1; + indexList.push_back(index); + } + + if (frontIndex.y - 1 >= MarkInterestingArea.at(resolution_level).at(frontIndex.z).index_begin.y + && MaskField.at(resolution_level)->GetData(frontIndex.x, frontIndex.y - 1, + frontIndex.z) == oldcolor) + { + index.x = frontIndex.x; + index.y = frontIndex.y - 1; + indexList.push_back(index); + } + + if (frontIndex.x - 1 >= MarkInterestingArea.at(resolution_level).at(frontIndex.z).index_begin.x + && MaskField.at(resolution_level)->GetData(frontIndex.x - 1, frontIndex.y, + frontIndex.z) == oldcolor) + { + index.x = frontIndex.x - 1; + index.y = frontIndex.y; + indexList.push_back(index); + } + + if (frontIndex.x + 1 <= MarkInterestingArea.at(resolution_level).at(frontIndex.z).index_end.x + && MaskField.at(resolution_level)->GetData(frontIndex.x + 1, frontIndex.y, + frontIndex.z) == oldcolor) + { + index.x = frontIndex.x + 1; + index.y = frontIndex.y; + indexList.push_back(index); + } + + //mark newcolor + MaskField.at(resolution_level)->PutData(frontIndex.x, frontIndex.y, frontIndex.z, newcolor); + SetUppwardBlockThisIntensity(resolution_level , frontIndex , newcolor); + //delete front + indexList.pop_front(); + + } + else + { + //delete front + indexList.pop_front(); + } + } + + } + + + + void Mask::setInsideVoxelPreviousVersion(int resolution_level) + { + + /* //doseVoxelIndexInStructure.clear(); + _doseVoxelInStructure.clear(); + + LegacyUnsignedIndex3D index; + index.x = 0; + index.y = 0; + index.z = 0; + + bool first=true; + + for( index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++ ){ + + LegacyUnsignedIndex3D index_internal; + index_internal.x = 0; + index_internal.y = 0; + index_internal.z = index.z; + + /*First: Mark all voxels as unknown*/ + /* if( ( MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y != 0 ) ){ + + for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index_internal.x++ ){ + for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index_internal.y++ ){ + + //set all no border voxels as outside + if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ + MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_unknown ); + //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); + + }//end if + else{ + LegacyDoseVoxelIndex3D index2; + index2.x = index_internal.x; + + index2.y = index_internal.y; + + index2.z = index_internal.z; + + DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); + //std::cout <GInf.at(resolution_level)); + if(doseVoxel.voxelInStructure(*_structure)==0){ + //std::cout << "first outside voxel: "<FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); + + + //get corresponding polygons + DoseVoxel doseVoxelZPlane=DoseVoxel(index2,this->GInf.at(resolution_level)); + std::vector sliceV=doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); + + for(int i=0;igetLegacyStructureVector().at(sliceV.at(i)); + + Contour contour=Contour(polygon);//get the contour in this slice + + LegacyPolygonType box=contour.getMinimalBox(); + Contour boxContour=Contour(box); + + bool firstVoxelInStr=false; + + + /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ + /* for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelInStr ; index2.x++ ){ + + for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelInStr ; index2.y++ ){ + if(MaskField.at( resolution_level )->GetData( index2.x, index2.y, index2.z )==brightness_unknown) { + + DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); + + //if doseVoxel inside the box + + LegacyWorldCoordinate2D luP={doseVoxel.getLeftUpperPoint().x,doseVoxel.getLeftUpperPoint().y}; + + //if left upper point of this voxel inside the box + + if(luP.x>=box.at(0).x && luP.y>=box.at(0).y && luP.x<=box.at(2).x && luP.y<=box.at(2).y){ + + if(doseVoxel.voxelInStructure(*_structure)==1){ + + //std::cout << "first inside voxel: "<FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); + + }//end for i + + //check unknown voxels + int sizeUnknown=0; + for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index2.x++ ){ + for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index2.y++ ){ + if(MaskField.at( resolution_level )->GetData(index2.x,index2.y,index2.z)==brightness_unknown){ + //std::cout << index2.toString()<<"---"; + //sizeUnknown++; + DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); + double voxelInStr=doseVoxel.voxelInStructure(*_structure); + if(voxelInStr>0){ + this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); + } + else{ + this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); + } + } + } + } + /*if(sizeUnknown!=0) + std::cout << "Unknown: "< indexListInside, + std::vector< UnsignedIndexList > indexListOutside) + { + + + _doseVoxelInStructure.clear(); + + LegacyUnsignedIndex3D index; + index.x = 0; + index.y = 0; + index.z = 0; + + bool first = true; + + for (index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++) + { + + if (indexListOutside.at(index.z).size() == 0) + { + + LegacyDoseVoxelIndex3D index2; + + index2.x = 0; + index2.y = 0; + index2.z = index.z; + /*Mark all voxels outside the structure: using FloodFill4*/ + bool firstVoxelOutStr = false; + + for (index2.x = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.x ; + index2.x <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.x + && !firstVoxelOutStr ; index2.x++) + { + for (index2.y = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.y ; + index2.y <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.y + && !firstVoxelOutStr ; index2.y++) + { + + DoseVoxel doseVoxel = DoseVoxel(index2, &(this->GInf.at(resolution_level))); + + if (doseVoxel.voxelInStructure(*_structure) == 0) + { + + LegacyUnsignedIndex3D indexUint; + indexUint.x = static_cast(index2.x); + indexUint.y = static_cast(index2.y); + indexUint.z = static_cast(index2.z); + + indexListOutside.at(index.z).push_back(indexUint); + firstVoxelOutStr = true; + break; + + }//end if + + }//end for index2.y + + if (firstVoxelOutStr) + { + break; + } + }//end for index2.x + + } + + if (indexListOutside.at(index.z).size() > 0) + { + this->FloodFill4(indexListOutside.at(index.z), brightness_unknown, brightness_outside, + resolution_level); + } + + if (indexListInside.at(index.z).size() == 0) + { + + LegacyDoseVoxelIndex3D index2; + + index2.x = 0; + index2.y = 0; + index2.z = index.z; + + //get corresponding polygons + DoseVoxel doseVoxelZPlane = DoseVoxel(index2, &(this->GInf.at(resolution_level))); + std::vector sliceV = doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); + + for (int i = 0; i < sliceV.size(); i++) + { + const LegacyPolygonType polygon = _structure->getLegacyStructureVector().at(sliceV.at(i)); + + Contour contour = Contour(polygon); //get the contour in this slice + + LegacyPolygonType box = contour.getMinimalBox(); + Contour boxContour = Contour(box); + + bool firstVoxelInStr = false; + + + /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ + for (index2.x = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.x ; + index2.x <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.x + && !firstVoxelInStr ; index2.x++) + { + + for (index2.y = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.y ; + index2.y <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.y + && !firstVoxelInStr ; index2.y++) + { + if (MaskField.at(resolution_level)->GetData(index2.x, index2.y, index2.z) == brightness_unknown) + { + + DoseVoxel doseVoxel = DoseVoxel(index2, &(this->GInf.at(resolution_level))); + + //if doseVoxel inside the box + + LegacyWorldCoordinate2D luP = {doseVoxel.getLeftUpperPoint().x(), doseVoxel.getLeftUpperPoint().y()}; + + //if left upper point of this voxel inside the box + + if (luP.x >= box.at(0).x && luP.y >= box.at(0).y && luP.x <= box.at(2).x && luP.y <= box.at(2).y) + { + + if (doseVoxel.voxelInStructure(*_structure) == 1) + { + + //std::cout << "first inside voxel: "<(index2.x); + indexUint.y = static_cast(index2.y); + indexUint.z = static_cast(index2.z); + indexListInside.at(index.z).push_back(indexUint); + } + + }//end for i + + } + + if (indexListInside.at(index.z).size() > 0) + { + this->FloodFill4(indexListInside.at(index.z), brightness_unknown, brightness_inside, + resolution_level); + } + + //check unknown voxels + int sizeUnknown = 0; + + LegacyDoseVoxelIndex3D index2; + + index2.x = 0; + index2.y = 0; + index2.z = index.z; + + for (index2.x = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.x ; + index2.x <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.x ; index2.x++) + { + for (index2.y = MarkInterestingArea.at(resolution_level).at(index.z).index_begin.y ; + index2.y <= MarkInterestingArea.at(resolution_level).at(index.z).index_end.y ; index2.y++) + { + if (MaskField.at(resolution_level)->GetData(index2.x, index2.y, index2.z) == brightness_unknown) + { + //std::cout << index2.toString()<<"---"; + //sizeUnknown++; + DoseVoxel doseVoxel = DoseVoxel(index2, &(this->GInf.at(resolution_level))); + double voxelInStr = doseVoxel.voxelInStructure(*_structure); + + if (voxelInStr > 0) + { + indexListInside.at(index.z).resize(0); + LegacyUnsignedIndex3D indexUint; + indexUint.x = static_cast(index2.x); + indexUint.y = static_cast(index2.y); + indexUint.z = static_cast(index2.z); + indexListInside.at(index.z).push_back(indexUint); + this->FloodFill4(indexListInside.at(index.z), brightness_unknown, brightness_inside, + resolution_level); + } + else + { + indexListOutside.at(index.z).resize(0); + LegacyUnsignedIndex3D indexUint; + indexUint.x = static_cast(index2.x); + indexUint.y = static_cast(index2.y); + indexUint.z = static_cast(index2.z); + indexListOutside.at(index.z).push_back(indexUint); + this->FloodFill4(indexListOutside.at(index.z), brightness_unknown, brightness_outside, + resolution_level); + } + } + } + } + + /*if(sizeUnknown!=0) + std::cout << "Unknown: "<GetDimX() ; x++) + { + for (int y = 0 ; y < MaskField.at(resolution_level)->GetDimY() ; y++) + { + for (int z = 0 ; z < MaskField.at(resolution_level)->GetDimZ() ; z++) + { + + if (MaskField.at(resolution_level)->GetData(x, y, z) == brightness_inside) + { + counter_inside++; + } + + if (MaskField.at(resolution_level)->GetData(x, y, z) == brightness_outside) + { + counter_outside++; + } + + if (MaskField.at(resolution_level)->GetData(x, y, z) == brightness_border) + { + counter_border++; + } + + if (MaskField.at(resolution_level)->GetData(x, y, z) == brightness_unknown) + { + counter_unknown++; + } + + } + } + } + + std::cout << " counter_inside : " << counter_inside << std::endl; + // std::cout<< " counter_outside : " << counter_outside < indexListInside; + std::vector< UnsignedIndexList > indexListOutside; + + for (int z = 0 ; z < GInf.at(resolution_level).getNumSlices() ; z++) + { + UnsignedIndexList a_list; + a_list.resize(0); + indexListInside.push_back(a_list); + indexListOutside.push_back(a_list); + } + + if (resolution_level < (MaskField.size() - 1)) + { + MaskField.at(resolution_level)->GetBorderRegion(MarkInterestingArea.at(resolution_level), + indexListInside , indexListOutside, brightness_unknown, brightness_inside, brightness_outside); + } + + setInsideVoxel(resolution_level , indexListInside, indexListOutside); + + } + + + + void Mask::SetContentUnknown() + { + + for (int resolution_level = 0 ; resolution_level < GInf.size() ; resolution_level++) + { + + for (int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++) + { + + + LegacyUnsignedIndex3D index_internal; + index_internal.x = 0; + index_internal.y = 0; + index_internal.z = index_z; + + + /*First: Mark all voxels as unknown*/ + if ((MarkInterestingArea.at(resolution_level).at(index_z).index_end.x != 0) + && (MarkInterestingArea.at(resolution_level).at(index_z).index_end.y != 0)) + { + + for (index_internal.x = MarkInterestingArea.at(resolution_level).at(index_z).index_begin.x ; + index_internal.x <= MarkInterestingArea.at(resolution_level).at(index_z).index_end.x ; + index_internal.x++) + { + for (index_internal.y = MarkInterestingArea.at(resolution_level).at(index_z).index_begin.y ; + index_internal.y <= MarkInterestingArea.at(resolution_level).at(index_z).index_end.y ; + index_internal.y++) + { + + + //set all no border voxels as outside + if (MaskField.at(resolution_level)->GetData(index_internal.x, index_internal.y, + index_internal.z) != brightness_border) + { + MaskField.at(resolution_level)->PutData(index_internal.x, index_internal.y, index_internal.z, + brightness_unknown); + //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); + + }//end if + + + }//end for index_internal.y + }//end for index_internal.x + + //std::cout << std::endl; + + }//end if + + } + + } + + } + + + void Mask::SeperateRegionsQuick() + { + + //doseVoxelIndexInStructure.clear(); + _doseVoxelInStructure.clear(); + + LegacyUnsignedIndex3D index; + index.x = 0; + index.y = 0; + index.z = 0; + + for (index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++) + { + + LegacyUnsignedIndex3D index_internal; + index_internal.x = 0; + index_internal.y = 0; + index_internal.z = index.z; + + if ((MarkInterestingArea.at(0).at(index.z).index_end.x != 0) + && (MarkInterestingArea.at(0).at(index.z).index_end.y != 0)) + { + + for (index_internal.x = MarkInterestingArea.at(0).at(index.z).index_begin.x ; + index_internal.x <= MarkInterestingArea.at(0).at(index.z).index_end.x ; index_internal.x++) + { + for (index_internal.y = MarkInterestingArea.at(0).at(index.z).index_begin.y ; + index_internal.y <= MarkInterestingArea.at(0).at(index.z).index_end.y ; index_internal.y++) + { + + if (MaskField.at(0)->GetData(index_internal.x, index_internal.y, + index_internal.z) != brightness_border) + { + + MaskField.at(0)->PutData(index_internal.x, index_internal.y, index_internal.z, brightness_inside); + + } + + } + } + + } + + index.y = MarkInterestingArea.at(0).at(index.z).index_begin.y; + + for (index.x = MarkInterestingArea.at(0).at(index.z).index_begin.x ; + index.x <= MarkInterestingArea.at(0).at(index.z).index_end.x ; index.x++) + { + + if (MaskField.at(0)->GetData(index.x, index.y, index.z) == brightness_inside) + { + MaskField.at(0)->PutData(index.x, index.y, index.z, brightness_outside); + ConnectArea(brightness_inside , brightness_outside , index , + MarkInterestingArea.at(0).at(index.z).index_begin , + MarkInterestingArea.at(0).at(index.z).index_end); + } + + } + + index.y = MarkInterestingArea.at(0).at(index.z).index_end.y; + + for (index.x = MarkInterestingArea.at(0).at(index.z).index_begin.x ; + index.x <= MarkInterestingArea.at(0).at(index.z).index_end.x ; index.x++) + { + + if (MaskField.at(0)->GetData(index.x, index.y, index.z) == brightness_inside) + { + MaskField.at(0)->PutData(index.x, index.y, index.z, brightness_outside); + ConnectArea(brightness_inside , brightness_outside , index , + MarkInterestingArea.at(0).at(index.z).index_begin , + MarkInterestingArea.at(0).at(index.z).index_end); + } + + } + + index.x = MarkInterestingArea.at(0).at(index.z).index_begin.x; + + for (index.y = MarkInterestingArea.at(0).at(index.z).index_begin.y ; + index.y <= MarkInterestingArea.at(0).at(index.z).index_end.y ; index.y++) + { + + if (MaskField.at(0)->GetData(index.x, index.y, index.z) == brightness_inside) + { + MaskField.at(0)->PutData(index.x, index.y, index.z, brightness_outside); + ConnectArea(brightness_inside , brightness_outside , index , + MarkInterestingArea.at(0).at(index.z).index_begin , + MarkInterestingArea.at(0).at(index.z).index_end); + } + + } + + index.x = MarkInterestingArea.at(0).at(index.z).index_end.x; + + for (index.y = MarkInterestingArea.at(0).at(index.z).index_begin.y ; + index.y <= MarkInterestingArea.at(0).at(index.z).index_end.y ; index.y++) + { + + if (MaskField.at(0)->GetData(index.x, index.y, index.z) == brightness_inside) + { + MaskField.at(0)->PutData(index.x, index.y, index.z, brightness_outside); + ConnectArea(brightness_inside , brightness_outside , index , + MarkInterestingArea.at(0).at(index.z).index_begin , + MarkInterestingArea.at(0).at(index.z).index_end); + } + + } + + + + } + + + } + + + + + + + void Mask::SetDoseVoxelInStructureVector() + { + + _doseVoxelInStructure.clear(); + + DoseVoxel aDoseVoxel; + + LegacyUnsignedIndex3D index; + index.x = 0; + index.y = 0; + index.z = 0; + + LegacyDoseVoxelIndex3D aDoseIndex; + aDoseIndex.x = 0; + aDoseIndex.y = 0; + aDoseIndex.z = 0; + + double fraction = 0; + + + for (index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++) + { + + if (FieldOfIntersections) + { + FieldOfIntersections->SetZero(); + GetIntersectionInformationThisSlice(index.z); + + } + + for (index.x = 0 ; index.x < GInf.at(0).getNumColumns() ; index.x++) + { + for (index.y = 0 ; index.y < GInf.at(0).getNumRows() ; index.y++) + { + + + aDoseIndex.x = index.x; + aDoseIndex.y = index.y; + aDoseIndex.z = index.z; + + + if (brightness_inside == MaskField.at(0)->GetData(index.x, index.y, index.z)) + { + + //doseVoxelIndexInStructure.push_back( aDoseIndex ); + fraction = 1.0; + + + DoseVoxel doseVoxel = DoseVoxel(aDoseIndex, &(GInf.at(0))); + doseVoxel.setProportionInStr(fraction); + this->_doseVoxelInStructure.push_back(doseVoxel); + // und jetzt fraction irgendwie anhaengen an geeignete Struktur und dann raus damit + //std::cout << "inside: "<~FieldOfPointer(); - - for( int i = 0 ; i < MaskField.size() ; i++ ){ - if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); - } - MaskField.resize(1); - for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL;*/ - - } - - void Mask::clearMaskField(){ - if( FieldOfIntersections != NULL )FieldOfIntersections->~FieldOfPointer(); - - for( int i = 0 ; i < MaskField.size() ; i++ ){ - if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); - } - MaskField.resize(1); - for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; - } - - void Mask::resetDose(DoseIteratorInterface* aDoseIterator){ - _doseIter=aDoseIterator; - if(!_doseIter) - throw core::NullPointerException("aDoseIter must not be NULL!"); - this->_doseIter->start(); - - //if geometric info not changed or if the voxelization external - if(_doseIter->getGeometricInfo()==this->GInf.at(0) || this->_structure==NULL){ - //std::cout << "reset dose."<calcDoseData(); - } - else{ - //std::cout << "recalculate mask"<GInf.push_back( _doseIter->getGeometricInfo() ); - - Init(); - - Calc(); - sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); - this->calcDoseData(); - - this->clearMaskField(); - - } - } - - - /*const std::vector& Mask::getDoseVoxelIndexInStructure() const{ - return doseVoxelIndexInStructure; - }*/ - - /*! @brief Get the dose voxels which lie inside the structure - * @return Return the vector of DoseVoxel which are inside the structure (with voxel proportion information) - */ - const std::vector& Mask::getDoseVoxelInStructure() const{ - return this->_doseVoxelInStructure; - } - - /*! @brief Set the dose voxels which lie inside the structure - * @return Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) - */ - void Mask::setDoseVoxelInStructure(std::vector aDoseVoxelVector){ - _doseVoxelInStructure=aDoseVoxelVector; - - } - - const DoseIteratorInterface& Mask::getDoseIterator() const{ - return *_doseIter; - } - - const StructureLegacy& Mask::getRTStructure() const{ - return *_structure; - } - - /*const std::vector Mask::getDoseData() const{ - return _doseData; - }*/ - - - - //get absolute dose data of the voxels which are inside the structure; - void Mask::calcDoseData(){ - _doseData.clear(); - /*this->_doseIter->start(); - std::vector doseDis;//dose distribution - while(_doseIter->hasNextVoxel()){ - doseDis.push_back(_doseIter->next()); - }*/ - - _doseIter->start(); - int count=0; - - std::vector::iterator it=_doseVoxelInStructure.begin(); - while(_doseIter->hasNextVoxel() && it!=_doseVoxelInStructure.end()){ - // Anmerkung von Martina fuer Lanlan: Eigentlich ist der Witz beim Iterator gerade, dass man sich ueber die - // Innereien des Iterators als Programmierer, der ihn einsetzt keine Gedanken machen muss. Hier ist die fehlerfreie Funktion - // des Codes jedoch von einigen Eigenschaften des Iterators, insbesondere von der Richtung in der iteriert wird, - // abhaengig. Das kommt daher, dass der Programmierer den Iterator von innen kannte und Eigenschaften nutzt, die er eigentlich - // nicht kennem wuerde, als Anwendungsprogrammierer des Iterators. Weil der Programmierer den Iterator aber selbst geschrieben hatte, - // deshalb wuste er es hier ... - // Das kann zur Folgen haben, dass nach einer Aenderung in Code des Iterators Mask nicht mehr korrekt - // funktioniert (z.B. wenn die Richtung der iteration im Koordinatensystem sich umkehren wuerde) man kann darueber - // nachdenken ob das problematisch ist .... - // Es ist ja auch so, dass die RTToolbox dafuer gemacht ist erweitert zu werden. Es koennen andere Iteratoren dazu kommen. - // Wollen wir hier spezifischer werden was den Typ des erlaubten Iterators betrifft? Das wuerde helfen. - double doseValue=_doseIter->next(); - LegacyDoseVoxelIndex3D doseVoxel=(*it).getVoxelIndex3D(); - if(count==doseVoxel.z*GInf.at(0).getNumColumns()*GInf.at(0).getNumRows()+doseVoxel.y*GInf.at(0).getNumColumns()+doseVoxel.x){ - _doseData.push_back(doseValue); - it++; - } - count++; - } - - } - - - void Mask::Calc(){ - //std::cout << "calc begin"<= 0 ; resolution_level-- ){ - - //std::cout << "GetIntersections"<= 0 ; resolution_level-- ){ - - for( int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ - - LegacyUnsignedIndex3D index_internal; - index_internal.x = 0; - index_internal.y = 0; - index_internal.z = index_z; - - for( int resolution_level = ( GInf.size() - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ - - if( ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y != 0 ) ){ - - for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x ; index_internal.x++ ){ - for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y ; index_internal.y++ ){ - - - if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_inside ){ - - CheckUppwardBlockSameIntensity( resolution_level , index_internal, brightness_inside ); - - } - - if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_outside ){ - - CheckUppwardBlockSameIntensity( resolution_level , index_internal, brightness_outside ); - - } - - if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_border ){ - - CheckUppwardOneOutOfThisBlockHasSameIntensity( resolution_level , index_internal , brightness_border ); - - } - - if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_unknown )assert(0); // This should not happen since each voxel must be regarded. - - - - - - } // for( index_internal.y - - } // for( index_internal.x - - - } // if( ( MarkInterestingArea.at(resolution_level).at( index_z - - } // for( int resolution_level - - } - - } // resolution_level - - } - - - void Mask::CheckUppwardBlockSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ - - if( resolution_level_in > 0 ){ - - for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ - - int resolution_difference = ( resolution_level_in - resolution_level ); - - double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); - - LegacyUnsignedIndex3D index_internal; - index_internal.x = index_in.x * block_length; - index_internal.y = index_in.y * block_length; - index_internal.z = index_in.z; - - if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ - if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ - - bool its_fine = MaskField.at( resolution_level )->CheckBlockSameIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); - - - assert( its_fine ); - - } - } - - } - - } - - } - - - void Mask::SetUppwardBlockThisIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ - - if( resolution_level_in > 0 ){ - - for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ - - int resolution_difference = ( resolution_level_in - resolution_level ); - - double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); - - LegacyUnsignedIndex3D index_internal; - index_internal.x = index_in.x * block_length; - index_internal.y = index_in.y * block_length; - index_internal.z = index_in.z; - - - - if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ - if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ - - MaskField.at( resolution_level )->SetBlockThisIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); - - } - } - - } - - } - - } - - - void Mask::CheckUppwardOneOutOfThisBlockHasSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ - - if( ( resolution_level_in > 0 ) && ( resolution_level_in < (MaskField.size()-1) ) ){ - - for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ - - int resolution_difference = ( resolution_level_in - resolution_level ); - - double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); - - LegacyUnsignedIndex3D index_internal; - index_internal.x = index_in.x * block_length; - index_internal.y = index_in.y * block_length; - index_internal.z = index_in.z; - - if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ - if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ - - bool its_fine = MaskField.at( resolution_level )->CheckOneOutOfThisBlockHasSameIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); - - assert( its_fine ); - - } - - } - - } - - } - - } - - - bool Mask::ContourFine(){ - - //std::cout << "ContourFine begin"<getLegacyStructureVector(); - LegacyPolygonSequenceType& strVector_ref = strVector; - - correspoinding_structure_vector str_v; - std::vector wich_slice; - - for(unsigned int struct_index = 0 ; struct_index < Intersections.at(0).size() ; struct_index++ ){ - - wich_slice.clear(); - - /* if( strVector.at( struct_index ).size() < 2 ){ - std::cerr<< " The Polygon consists of just one point ! That doesn't make sense in Radiotherapy. Program will be terminated. " < ( i+1 ) ) secondPoint = pitoiA.at( i+1 ).contour_point_voxel_coord; - else secondPoint = pitoiA.at( 0 ).contour_point_voxel_coord; - - for( ; itB!=pitoiB.end() ;itB++ ){ - //for( ; j ( j+1 ) ) fourthPoint = pitoiB.at( j+1 ).contour_point_voxel_coord; - else fourthPoint = pitoiB.at( 0 ).contour_point_voxel_coord; - - //std::cout < firstPoint.x ){ - x_min = firstPoint.x; - x_max = secondPoint.x; - } - - bool it_is_in_between = 1; - if( (x < x_min) || (x > x_max) ) it_is_in_between = 0; - - - if( (beta>0)&&(beta<1) && it_is_in_between ){ - return true; - } - else return false; - - } - else return false; - - } - - if( ( secondPoint.x - firstPoint.x ) == 0 ){ - - if( ( fourthPoint.x - thirdPoint.x ) != 0 ){ - - float beta = ( firstPoint.x - thirdPoint.x ) / ( fourthPoint.x - thirdPoint.x ); - - float y = ( fourthPoint.y - thirdPoint.y ) * beta + thirdPoint.y; - - float y_min = secondPoint.y; - float y_max = firstPoint.y; - - if( secondPoint.y > firstPoint.y ){ - y_min = firstPoint.y; - y_max = secondPoint.y; - } - - bool it_is_in_between = 1; - if( (y < y_min) || (y > y_max) ) it_is_in_between = 0; - - if( (beta>0)&&(beta<1) && it_is_in_between ){ - - return true; - } - else return false; - } - else return false; - - } - - - if( ( ( secondPoint.y - firstPoint.y ) == 0 ) || ( ( secondPoint.x - firstPoint.x ) == 0 ) ) assert(0); - - - if( ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) == 0 ){ - return false; // parallel, schneiden sich nicht ! - } - - - if( ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) == 0 ) assert( 0 ); - - - float beta = ( ( ( thirdPoint.y - firstPoint.y ) / ( secondPoint.y - firstPoint.y ) ) - ( ( thirdPoint.x - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) ) ) / ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) ; - float alpha = ( ( fourthPoint.x - thirdPoint.x ) * beta + thirdPoint.x - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); - - if( ( (beta>0)&&(beta<1) ) && ( (alpha>0) && (alpha<1) ) ){ // falls diese Bedingung nicht erfuellt ist, gibt es zwar einen Schnittpunkt der Geraden, aber nicht im relevanten Bereich - - return true; - - } - - return false; - - } - - - - - - void Mask::FloodFill4( UnsignedIndexList indexList,int oldcolor,int newcolor,int resolution_level) - { - - - LegacyUnsignedIndex3D index; - index.x = 0; - index.y = 0; - index.z = 0; - - while(!indexList.empty()){ - LegacyUnsignedIndex3D frontIndex=indexList.front(); - index.z = frontIndex.z; - if(MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y, frontIndex.z )==oldcolor){ - //insert index - if(frontIndex.y+1<=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_end.y && MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y+1, frontIndex.z )==oldcolor){ - index.x=frontIndex.x; - index.y=frontIndex.y+1; - indexList.push_back(index); - } - if(frontIndex.y-1>=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_begin.y && MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y-1, frontIndex.z )==oldcolor ){ - index.x=frontIndex.x; - index.y=frontIndex.y-1; - indexList.push_back(index); - } - if(frontIndex.x-1>=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_begin.x && MaskField.at( resolution_level )->GetData( frontIndex.x-1, frontIndex.y, frontIndex.z )==oldcolor){ - index.x=frontIndex.x-1; - index.y=frontIndex.y; - indexList.push_back(index); - } - if(frontIndex.x+1<=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_end.x && MaskField.at( resolution_level )->GetData( frontIndex.x+1, frontIndex.y, frontIndex.z )==oldcolor){ - index.x=frontIndex.x+1; - index.y=frontIndex.y; - indexList.push_back(index); - } - - //mark newcolor - MaskField.at( resolution_level )->PutData( frontIndex.x, frontIndex.y, frontIndex.z, newcolor ); - SetUppwardBlockThisIntensity( resolution_level , frontIndex , newcolor ); - //delete front - indexList.pop_front(); - - } - else{ - //delete front - indexList.pop_front(); - } - } - - } - - - - void Mask::setInsideVoxelPreviousVersion(int resolution_level){ - - /* //doseVoxelIndexInStructure.clear(); - _doseVoxelInStructure.clear(); - - LegacyUnsignedIndex3D index; - index.x = 0; - index.y = 0; - index.z = 0; - - bool first=true; - - for( index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++ ){ - - LegacyUnsignedIndex3D index_internal; - index_internal.x = 0; - index_internal.y = 0; - index_internal.z = index.z; + if (brightness_border == MaskField.at(0)->GetData(index.x, index.y, index.z)) + { + + + + if (!do_detailed_subvox) /*Lanlan*/ + { + + + DoseVoxel doseVoxel = DoseVoxel(aDoseIndex, &(GInf.at(0))); + fraction = doseVoxel.voxelInStructure(*_structure); //simple test + + if (fraction > 0) + { + //doseVoxelIndexInStructure.push_back( aDoseIndex ); + doseVoxel.setProportionInStr(fraction); + this->_doseVoxelInStructure.push_back(doseVoxel); + } + + + + } + else /*Martina..............*/ + { + + //doseVoxelIndexInStructure.push_back( aDoseIndex ); + + fraction = 1.0; + + + + fraction = GetFractionInside(aDoseIndex); + + if ((fraction < 0) || (fraction > 1.0)) + { + assert(0); + } + + + + DoseVoxel doseVoxel = DoseVoxel(aDoseIndex, &(GInf.at(0))); + doseVoxel.setProportionInStr(fraction); + _doseVoxelInStructure.push_back(doseVoxel); + + } + + + + } + } + } + } + + + + + double total_volume = 0; + + for (int counter = 0 ; counter < _doseVoxelInStructure.size() ; counter++) + { + + total_volume += _doseVoxelInStructure.at(counter).getProportionInStr(); + + } + + //std::cout<< " total_volume : " << total_volume <= index_begin.x) && (start_index.y >= index_begin.y) + && (start_index.x <= index_end.x) && (start_index.y <= index_end.y)) + { + + std::deque index_list; + + LegacyUnsignedIndex2D this_index; + this_index.x = start_index.x; + this_index.y = start_index.y; + + LegacyUnsignedIndex2D another_index; + another_index.x = 0; + another_index.y = 0; + + MaskField.at(0)->PutData(start_index.x, start_index.y, start_index.z, brightness_to); + index_list.push_back(this_index); + + int counter = 1; + + while (index_list.size() > 0) + { + + // std::cout<< " counter " << counter < index_begin.x) + { + another_index.x = this_index.x - 1; + another_index.y = this_index.y; + + if (MaskField.at(0)->GetData(another_index.x , another_index.y , start_index.z) == brightness_from) + { + index_list.push_back(another_index); + counter++; + MaskField.at(0)->PutData(another_index.x, another_index.y, start_index.z, brightness_to); + } + } + + if (this_index.y > index_begin.y) + { + another_index.x = this_index.x; + another_index.y = this_index.y - 1; + + if (MaskField.at(0)->GetData(another_index.x , another_index.y , start_index.z) == brightness_from) + { + index_list.push_back(another_index); + counter++; + MaskField.at(0)->PutData(another_index.x, another_index.y, start_index.z, brightness_to); + } + } + + + if (this_index.x < index_end.x) + { + another_index.x = this_index.x + 1; + another_index.y = this_index.y; + + if (MaskField.at(0)->GetData(another_index.x , another_index.y , start_index.z) == brightness_from) + { + index_list.push_back(another_index); + counter++; + MaskField.at(0)->PutData(another_index.x, another_index.y, start_index.z, brightness_to); + } + } + + if (this_index.y < index_end.y) + { + another_index.x = this_index.x; + another_index.y = this_index.y + 1; + + if (MaskField.at(0)->GetData(another_index.x , another_index.y , start_index.z) == brightness_from) + { + index_list.push_back(another_index); + counter++; + MaskField.at(0)->PutData(another_index.x, another_index.y, start_index.z, brightness_to); + } + } + + + } + + } + + } + + + // die folgende Funktion prueft immer erst, ob es sich um einen Schnittpunkt mit der Ecke handelt. Falls nicht wird er in die Reihe der Kantenschnittpunkte einsortiert. Betrachtet wird lediglich die erste Ecke. + void Mask::SetThisIntersectionToCornerOrEdge(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D, unsigned int edge_number, + IntersectionsThisVoxel& voxel_intersections) + { + + + if (edge_number == 0) + { + SetThisIntersection(index_x , (index_x + 1) , index_y , intersection , coord2D.x, coord2D.y , + voxel_intersections, edge_number); + } + else if (edge_number == 1) + { + SetThisIntersection(index_y , (index_y + 1) , (index_x + 1) , intersection , coord2D.y, coord2D.x , + voxel_intersections, edge_number); + //SetThisIntersectionYIncreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); + } + else if (edge_number == 2) + { + SetThisIntersection((index_x + 1) , index_x , (index_y + 1) , intersection , coord2D.x, coord2D.y , + voxel_intersections, edge_number); + //SetThisIntersectionXDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); + } + else if (edge_number == 3) + { + SetThisIntersection((index_y + 1) , index_y , index_x , intersection , coord2D.y, coord2D.x , + voxel_intersections, edge_number); + //SetThisIntersectionYDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); + } + else + { + assert(0); + } + + } + + + + void Mask::SetThisIntersection(unsigned int corner_of_interest , unsigned int corner_next, + unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection + , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , + unsigned int edge_number) + { + + if (coord_fixed != static_cast(corner_fixed)) + { + assert(0); // this should never happen since coord_fixed is the coordinate which is the same all along the edge that starts with corner_fixed + } + + + if (coord_of_interest == static_cast + (corner_of_interest)) // falls der Schnittpunkt direkt am Anfang der Kante liegt also der Anfangspunkt der Kante ist + { + + voxel_intersections.corner_intersections_intersection_coord.at(edge_number).push_back( + intersection); // dann haenge den Schnittpunkt an die Liste der Schnittpunkte mit eben diesem Anfangspunkt der Kante an + return; + + } + else + { + + if (voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() > + 0) // falls die Kante schon Schnittpunkte hat + { + double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( + 0).at(0); + + // In der naechsten Zeile wird geprueft, ob der Schnittpunkt zwischen dem Anfang der Kante und dem ersten bereits bekannten Schnittpunkt liegt. Falls ja, wird er entsprechend eingefuegt. + if (CompareIfBetweenInsertAtBeginning(coord_of_interest , static_cast(corner_of_interest) , + first_coord_double , edge_number, intersection , voxel_intersections)) + { + return; + } + } + + // naechste Zeile: Pruefe, ob der Schnittpunkt in der Liste der Schnittpunkte mit dieser Kante schon vorhanden ist und falls ja, verlaengere die Liste der Punkte, die eben in diesem Punkt schneiden um den neuen Schnittpunkt. + // Puntemaessig ist das zwar der selbe, der schon mindestens einmal da ist, aber intersection ist ja eine Art Index im PolygonOfIntersections + // und muss dann hier einsortiert werden. Denn das Polygon kann tatsaechlich mehrfach durch den selben Punkt laufen. + // Falls der Schnittpunkt noch nicht vorkommt, aber zwischen zweien ist, die bereits vorkommen, wird er entsprechend eingefuegt. + if (CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert(coord_of_interest , edge_number, + intersection , voxel_intersections)) + { + return; + } + + double that_coord_double = 0; + + // Die folgenden beiden Zeilen sind dafuer zustaendig that_coord_double mit entweder dem letzten bereits bekannten Schnittpunkt dieser Kante, + // oder alternativ mit dem Anfangspunkt der Kante zu belegen. + if (voxel_intersections.edge_intersections_vox_coord.at(edge_number).size() > 0) + { + that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(( + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1)).at(0) ; + } + else + { + that_coord_double = static_cast(corner_of_interest); + } + + if (that_coord_double == coord_of_interest) + { + + if (coord_of_interest == static_cast(corner_of_interest)) + { + assert(0); // Das kann nicht sein, denn falls der Schnittpunkt wirklich der erste Punkt der Kante waere, muesste das ganz zu Beginn dieser Funktion bereits erkannt worden sein und die Funktion haette dann bereits returned. Falls that_coord_double also coord_of_interest (eizusortierender Punk) ist, kann dieser nicht der Anfangspunkt der Kante sein. + } + + // der einzusortierende Punkt coord_of_interest ist gerade gleich dem letzten bereits gefundenen Schnittpunkt that_coord_double und wird der Liste seinder Vorkommnisse entsprechend hinzugefuegt. + voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(( + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1)).push_back( + coord_of_interest); + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at(( + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1)).push_back( + intersection); + return; + + } + else + { + + // Hier wird geprueft, ob der betrachtete Punkt zwischen dem letzten bereits gefundenen Schnittpunkt und dem Ende der Kante liegt. Falls ja, wird er vor dem Kantenende entsprechend eingefuegt. + if (CompareIfBetweenAppend(coord_of_interest , that_coord_double, static_cast(corner_next), + edge_number, intersection , voxel_intersections)) + { + + return; + + } + + if (coord_of_interest == static_cast(corner_next)) + { + assert(0); // this case is not supposed to be considered here. Its the next edge and should have gone elsewhere. Das Ende der Kante ist der Anfang der naechsten Kante uns haette daher bei dieser naechsten Kante landen muessen. + } + } + + assert(0); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be considered here. + } + + } + + + + void Mask::SetThisIntersectionXIncreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , + unsigned int edge_number) + { + + if (coord2D.y != static_cast(index_y)) + { + assert(0); // this should never happen + } + + if (coord2D.x == static_cast(index_x)) + { + + voxel_intersections.corner_intersections_intersection_coord.at(0).push_back(intersection); + return; + + } + else + { + + if (voxel_intersections.edge_intersections_intersection_coord.at(0).size() > 0) + { + + double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at(0).at(0); + + if (CompareIfBetweenInsertAtBeginning(coord2D.x , static_cast(index_x) , + first_coord_double , edge_number, intersection , voxel_intersections)) + { + return; + } + + } + + if (CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert(coord2D.x , edge_number, + intersection , voxel_intersections)) + { + return; + } + + double that_coord_double = 0; + + if (voxel_intersections.edge_intersections_vox_coord.at(0).size() > 0) + { + that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at(( + voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1)).at(0) ; + } + else + { + that_coord_double = static_cast(index_x); + } + + + if (that_coord_double == coord2D.x) + { + + if (coord2D.x == static_cast(index_x)) + { + assert(0); + } + + voxel_intersections.edge_intersections_vox_coord.at(0).at(( + voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1)).push_back(coord2D.x); + voxel_intersections.edge_intersections_intersection_coord.at(0).at(( + voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1)).push_back( + intersection); + return; + + } + else + { + + if (CompareIfBetweenAppend(coord2D.x , that_coord_double, static_cast(index_x + 1), + edge_number, intersection , voxel_intersections)) + { + return; + } + + if (coord2D.x == static_cast(index_x + 1)) + { + assert(0); // this case is not supposed to be treated here. + } + + } + + assert(0); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be treated here. + + } + + } + + + bool Mask::CompareIfBetweenAppend(double value_to_compare , double small_value_to_compare_with , + double big_value_to_compare_with, unsigned int edge_number, + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections) + { + + if (((value_to_compare < big_value_to_compare_with) + && (value_to_compare > small_value_to_compare_with)) + || ((value_to_compare > big_value_to_compare_with) + && (value_to_compare < small_value_to_compare_with))) + { + + std::vector< double > double_vec; + double_vec.push_back(value_to_compare) ; + + std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; + intersection_vec.push_back(intersection); + + voxel_intersections.edge_intersections_vox_coord.at(edge_number).push_back(double_vec); + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).push_back( + intersection_vec); + return true; + + } + else + { + return false; + } + + } + + + bool Mask::CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert(double value_to_compare , + unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections) + { + + for (int i = 0 ; + i < (static_cast(voxel_intersections.edge_intersections_intersection_coord.at( + edge_number).size()) - 1) ; i++) + { + + double the_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).at( + 0) ; + + if (value_to_compare == the_coord_double) + { + + voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).push_back(value_to_compare); + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at(i).push_back( + intersection); + return true; + + } + else + { + + double another_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( + i + 1).at(0) ; + + if (((another_double > value_to_compare) && (the_coord_double < value_to_compare)) + || ((another_double < value_to_compare) && (the_coord_double > value_to_compare))) + { + + std::vector< double > double_vec; + double_vec.push_back(value_to_compare) ; + std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; + intersection_vec.push_back(intersection); + intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at( + edge_number).begin() + (i + 1); + + voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert(( + voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin() + (i + 1)) , double_vec); + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert(it , + intersection_vec); + + return true; + + } + } + + } + + return false; + + } + + + bool Mask::CompareIfBetweenInsertAtBeginning(double value_to_compare , + double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections) + { + + if (((value_to_compare > small_value_to_compare_with) + && (value_to_compare < big_value_to_compare_with)) + || ((value_to_compare < small_value_to_compare_with) + && (value_to_compare > big_value_to_compare_with))) + { + + std::vector< double > double_vec; + double_vec.push_back(value_to_compare) ; + std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; + intersection_vec.push_back(intersection); + intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at( + edge_number).begin(); + + voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert( + voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin(), double_vec); + voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert(it , + intersection_vec); + + return true; + + } + + return false; + + } + + + void Mask::SetThisIntersectionYIncreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections) + { + + if (coord2D.x != static_cast(index_x + 1)) + { + assert(0); // this should never happen + } + + // to be implemented + + + } + + + void Mask::SetThisIntersectionXDecreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections) + { + + if (coord2D.y != static_cast(index_y + 1)) + { + assert(0); // this should never happen + } + + // to be implemented + + } + + + void Mask::SetThisIntersectionYDecreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections) + { + + if (coord2D.x != static_cast(index_x)) + { + assert(0); // this should never happen + } + + // to be implemented + + } + + + void Mask::Init() + { + + SliceStructureCorrespondency.clear(); + do_detailed_subvox = true; + + if (do_detailed_subvox) + { + FieldOfIntersections = new rttb::masks::legacy::FieldOfPointer + (GInf.at(0).getNumColumns() , GInf.at(0).getNumRows() , 1); + } + + for (int i = 0 ; i < MaskField.size() ; i++) + { + if (MaskField.at(i) != NULL) + { + MaskField.at(i)->~FieldOfScalar(); + } + } + + MaskField.resize(0); + rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new + rttb::masks::legacy::FieldOfScalar(GInf.at(0).getNumColumns() , + GInf.at(0).getNumRows() , GInf.at(0).getNumSlices()); + MaskField.push_back(a_field_of_scalar); + + brightness_inside = 50; + brightness_border = 10; + brightness_outside = 0; + brightness_unknown = -10; + + LegacyDoseVoxelIndex3D doseVoxelIndex; + doseVoxelIndex.x = 0; + doseVoxelIndex.y = 0; + doseVoxelIndex.z = 0 ; + + int currentSliceNumber = 0; + + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); + LegacyPolygonSequenceType& strVector_ref = strVector; + StructureInTermsOfIntersections inters; + inters.resize(strVector.size()); + Intersections.push_back(inters); + + + StructureInTermsOfIntersections sitoi = Intersections.at(0); + //StructureInTermsOfIntersections:: + + for (unsigned int i = 0 ; i < strVector.size() ; i++) + { + + Intersections.at(0).at(i).resize(strVector.at(i).size()); + + LegacyWorldCoordinate2D index_coord; + index_coord.x = 0; + index_coord.y = 0; + + LegacyWorldCoordinate3D contour_point_world; + contour_point_world.x = 0; + contour_point_world.y = 0; + contour_point_world.z = 0; + + for (unsigned int j = 0 ; j < strVector.at(i).size() ; j++) + { + + contour_point_world = strVector.at(i).at(j); + index_coord = GetDoubleIndex2D(contour_point_world.x , contour_point_world.y); + Intersections.at(0).at(i).at(j).contour_point_voxel_coord.x = index_coord.x; + Intersections.at(0).at(i).at(j).contour_point_voxel_coord.y = index_coord.y; + Intersections.at(0).at(i).at(j).contour_point_voxel_coord.z = GetZIndex(contour_point_world.z); + + + } + + } + + + // iteration slices + for (doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++) + { + + correspoinding_structure_vector str_v; + + LegacyWorldCoordinate2D the_index; + the_index.x = 0; + the_index.y = 0; + + DoseVoxel doseVoxel; + //from dose index to worldcoordinate + doseVoxel.setDoseVoxel(doseVoxelIndex , &(GInf.at(0))); + + str_v = doseVoxel.getZIntersectPolygonIndexVector(*_structure); //Lanlan + + + SliceStructureCorrespondency.push_back(str_v); + + + } + + + InitInterestingArea(); + InitMultiResolution(); + + } + + + + + + void Mask::InitInterestingArea() + { + + MarkInterestingArea.clear(); + + std::vector interesting_area_this_resolution; + + LegacyDoseVoxelIndex3D doseVoxelIndex; + doseVoxelIndex.x = 0; + doseVoxelIndex.y = 0; + doseVoxelIndex.z = 0 ; + + int currentSliceNumber = 0; + + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); + LegacyPolygonSequenceType& strVector_ref = strVector; + + // iteration slices + for (doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++) + { + + LegacyWorldCoordinate1D x_min = 1000000000; + LegacyWorldCoordinate1D x_max = -1000000000; + LegacyWorldCoordinate1D y_min = 1000000000; + LegacyWorldCoordinate1D y_max = -1000000000; + + LegacyWorldCoordinate1D x_index_min = 1000000000; + LegacyWorldCoordinate1D x_index_max = -1000000000; + LegacyWorldCoordinate1D y_index_min = 1000000000; + LegacyWorldCoordinate1D y_index_max = -1000000000; + + LegacyWorldCoordinate2D the_index; + the_index.x = 0; + the_index.y = 0; + + DoseVoxel doseVoxel; + //from dose index to worldcoordinate + doseVoxel.setDoseVoxel(doseVoxelIndex , &(GInf.at(0))); + std::vector sliceV = doseVoxel.getZIntersectPolygonIndexVector(*_structure); + + + + //if( ( strVector.size() != currentSliceNumber ) && ( currentSliceNumber != (-1) ) ){ + for (int indexV = 0; indexV < sliceV.size(); indexV++) + { + currentSliceNumber = sliceV.at(indexV); + + // iteration polygon + + for (int i = 0 ; i < strVector.at(currentSliceNumber).size() ; i++) + { + + LegacyWorldCoordinate3D firstPoint = strVector.at(currentSliceNumber).at(i); + //LegacyWorldCoordinate3D secondPoint = strVector.at(currentSliceNumber).at(i+1); + + if (firstPoint.x < x_min) + { + x_min = firstPoint.x; + } + + if (firstPoint.y < y_min) + { + y_min = firstPoint.y; + } + + if (firstPoint.x > x_max) + { + x_max = firstPoint.x; + } + + if (firstPoint.y > y_max) + { + y_max = firstPoint.y; + } + + the_index = GetDoubleIndex2D(firstPoint.x , firstPoint.y); + + if (the_index.x < x_index_min) + { + x_index_min = the_index.x; + } + + if (the_index.y < y_index_min) + { + y_index_min = the_index.y; + } + + if (the_index.x > x_index_max) + { + x_index_max = the_index.x; + } + + if (the_index.y > y_index_max) + { + y_index_max = the_index.y; + } + + } + }//end for indexV + + + if (sliceV.size() > 0) + { + LegacyArea2D area_2d; + area_2d.x_begin = x_min; + area_2d.x_end = x_max; + area_2d.y_begin = y_min; + area_2d.y_end = y_max; + + int small_enough_x = static_cast(floor(x_index_min) - 1); + + if (small_enough_x < 0) + { + small_enough_x = 0; + } + + area_2d.index_begin.x = small_enough_x; + + int small_enough_y = static_cast(floor(y_index_min) - 1); + + if (small_enough_y < 0) + { + small_enough_y = 0; + } + + area_2d.index_begin.y = small_enough_y; + + int large_enough_x = static_cast(floor(x_index_max) + 1); + + if (large_enough_x >= GInf.at(0).getNumColumns()) + { + large_enough_x = (GInf.at(0).getNumColumns() - 1); + } + + area_2d.index_end.x = large_enough_x; + + int large_enough_y = static_cast(floor(y_index_max) + 1); + + if (large_enough_y >= GInf.at(0).getNumRows()) + { + large_enough_y = (GInf.at(0).getNumRows() - 1); + } + + area_2d.index_end.y = large_enough_y; + interesting_area_this_resolution.push_back(area_2d); // std::vector + } + else + { + + LegacyArea2D area_2d; + area_2d.Init(); + interesting_area_this_resolution.push_back(area_2d); + + } + + } + + MarkInterestingArea.push_back(interesting_area_this_resolution); + + } + + + void Mask::InitMultiResolution() + { + + bool done = false; + + + while (done == false) + { + + int new_dim_x = MaskField.at(0)->GetDimX() / static_cast(GetBlockLengthThisResolutionLevel( + MaskField.size())) + 1; + int new_dim_y = MaskField.at(0)->GetDimY() / static_cast(GetBlockLengthThisResolutionLevel( + MaskField.size())) + 1; + + + + if (new_dim_x > 20 && new_dim_y > 20) + { + + + core::GeometricInfo NewGeomInf; + + NewGeomInf.setImagePositionPatient(GInf.at(GInf.size() - 1).getImagePositionPatient()); + + NewGeomInf.setOrientationMatrix(GInf.at(GInf.size() - 1).getOrientationMatrix()); + + NewGeomInf.setSliceThickness(GInf.at(GInf.size() - 1).getSliceThickness()); + NewGeomInf.setNumSlices(GInf.at(GInf.size() - 1).getNumSlices()); + + NewGeomInf.setNumColumns(new_dim_x); + NewGeomInf.setNumRows(new_dim_y); + + double power = 1; + + for (int i = 0 ; i < GInf.size() ; i++) + { + power *= 2; + } + + NewGeomInf.setPixelSpacingRow(GInf.at(0).getPixelSpacingRow() * power); + NewGeomInf.setPixelSpacingColumn(GInf.at(0).getPixelSpacingColumn() * power); + + GInf.push_back(NewGeomInf); + + rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new + rttb::masks::legacy::FieldOfScalar(GInf.at(GInf.size() - 1).getNumColumns() , + GInf.at(GInf.size() - 1).getNumRows() , GInf.at(GInf.size() - 1).getNumSlices()); + MaskField.push_back(a_field_of_scalar); + + std::vector interesting_area_this_resolution; + + + for (int z = 0 ; z < MarkInterestingArea.at(0).size() ; z++) + { + + LegacyArea2D NewArea; + NewArea.x_begin = MarkInterestingArea.at(0).at(z).x_begin; + NewArea.x_end = MarkInterestingArea.at(0).at(z).x_end; + NewArea.y_begin = MarkInterestingArea.at(0).at(z).y_begin; + NewArea.y_end = MarkInterestingArea.at(0).at(z).y_end; + + NewArea.index_begin.x = (MarkInterestingArea.at(0).at(z).index_begin.x / power); + + if (NewArea.index_begin.x > 0) + { + NewArea.index_begin.x -= 1; + } + + NewArea.index_begin.y = (MarkInterestingArea.at(0).at(z).index_begin.y / power); + + if (NewArea.index_begin.y > 0) + { + NewArea.index_begin.y -= 1; + } + + NewArea.index_end.x = (MarkInterestingArea.at(0).at(z).index_end.x / power); + NewArea.index_end.x += 1; + + if (NewArea.index_end.x >= MaskField.at(MaskField.size() - 1)->GetDimX()) + { + NewArea.index_end.x = (MaskField.at(MaskField.size() - 1)->GetDimX() - 1); + } + + NewArea.index_end.y = (MarkInterestingArea.at(0).at(z).index_end.y / power); + NewArea.index_end.y += 1; + + if (NewArea.index_end.y >= MaskField.at(MaskField.size() - 1)->GetDimY()) + { + NewArea.index_end.y = (MaskField.at(MaskField.size() - 1)->GetDimY() - 1); + } + + interesting_area_this_resolution.push_back(NewArea); + + } + + MarkInterestingArea.push_back(interesting_area_this_resolution); + + } + else + { + done = true; + } + + } + + /* + std::cout<< " MaskField.size() " << MaskField.size() <GetDimX() : " << MaskField.at( i )->GetDimX() <GetDimY() : " << MaskField.at( i )->GetDimY() <pixelSpacingColumn : " << GInf.at( i ).getPixelSpacingColumn() <sliceThickness : " << GInf.at( i ).getSliceThickness() <column : " << GInf.at( i )getNumColumns() <row : " << GInf.at( i )getNumRows() <numberOfFrames : " << GInf.at( i ).getNumSlices() < 1 ) || ( MarkInterestingArea.at( i ).at( z ).index_end.y > 1 ) ){ + + std::cout<< " z : " << z <GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ - MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_unknown ); - //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); + }*/ - }//end if - else{ - LegacyDoseVoxelIndex3D index2; - index2.x = index_internal.x; - index2.y = index_internal.y; + InitIntersections(); - index2.z = index_internal.z; - - DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); - //std::cout <GInf.at(resolution_level)); - if(doseVoxel.voxelInStructure(*_structure)==0){ - //std::cout << "first outside voxel: "<FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); + LegacyPolygonSequenceType& strVector_ref = strVector; + StructureInTermsOfIntersections inters; + inters.resize(strVector.size()); + Intersections.push_back(inters); + for (unsigned int i = 0 ; i < strVector.size() ; i++) + { - //get corresponding polygons - DoseVoxel doseVoxelZPlane=DoseVoxel(index2,this->GInf.at(resolution_level)); - std::vector sliceV=doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); + Intersections.at(counter).at(i).resize(strVector.at(i).size()); - for(int i=0;igetLegacyStructureVector().at(sliceV.at(i)); + LegacyWorldCoordinate2D index_coord; + index_coord.x = 0; + index_coord.y = 0; - Contour contour=Contour(polygon);//get the contour in this slice + LegacyWorldCoordinate3D contour_point_world; + contour_point_world.x = 0; + contour_point_world.y = 0; + contour_point_world.z = 0; - LegacyPolygonType box=contour.getMinimalBox(); - Contour boxContour=Contour(box); + for (unsigned int j = 0 ; j < strVector.at(i).size() ; j++) + { - bool firstVoxelInStr=false; + contour_point_world = strVector.at(i).at(j); + index_coord = GetDoubleIndex2D(contour_point_world.x , contour_point_world.y , counter); + Intersections.at(counter).at(i).at(j).contour_point_voxel_coord.x = index_coord.x; + Intersections.at(counter).at(i).at(j).contour_point_voxel_coord.y = index_coord.y; + Intersections.at(counter).at(i).at(j).contour_point_voxel_coord.z = GetZIndex( + contour_point_world.z); - /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ -/* for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelInStr ; index2.x++ ){ + } - for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelInStr ; index2.y++ ){ - if(MaskField.at( resolution_level )->GetData( index2.x, index2.y, index2.z )==brightness_unknown) { + } - DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); + } - //if doseVoxel inside the box + if (Intersections.size() != GInf.size()) + { + assert(0); + } - LegacyWorldCoordinate2D luP={doseVoxel.getLeftUpperPoint().x,doseVoxel.getLeftUpperPoint().y}; + /* + for( int counter = 0 ; counter < GInf.size() ; counter++ ){ - //if left upper point of this voxel inside the box + std::cout<< " next resolution level " << counter <=box.at(0).x && luP.y>=box.at(0).y && luP.x<=box.at(2).x && luP.y<=box.at(2).y){ + for( int i = 0 ; i < Intersections.at(counter).size() ; i++ ){ - if(doseVoxel.voxelInStructure(*_structure)==1){ + std::cout<< " next structure index : " << i <FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); + } - }//end for i - - //check unknown voxels - int sizeUnknown=0; - for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index2.x++ ){ - for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index2.y++ ){ - if(MaskField.at( resolution_level )->GetData(index2.x,index2.y,index2.z)==brightness_unknown){ - //std::cout << index2.toString()<<"---"; - //sizeUnknown++; - DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); - double voxelInStr=doseVoxel.voxelInStructure(*_structure); - if(voxelInStr>0){ - this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); - } - else{ - this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); - } - } - } - } - /*if(sizeUnknown!=0) - std::cout << "Unknown: "<getLegacyStructureVector(); + LegacyPolygonSequenceType& strVector_ref = strVector; - void Mask::setInsideVoxel( int resolution_level , std::vector< UnsignedIndexList > indexListInside, std::vector< UnsignedIndexList > indexListOutside ){ + LegacyWorldCoordinate3D firstPoint; + firstPoint.x = 0; + firstPoint.y = 0; + firstPoint.z = 0; + LegacyWorldCoordinate3D secondPoint; + secondPoint.x = 0; + secondPoint.y = 0; + secondPoint.z = 0; - _doseVoxelInStructure.clear(); + // iteration z direction + for (unsigned int struct_index = 0 ; struct_index < strVector.size() ; struct_index++) + { - LegacyUnsignedIndex3D index; - index.x = 0; - index.y = 0; - index.z = 0; - - bool first=true; - - for( index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++ ){ - if( indexListOutside.at(index.z).size() == 0 ){ - - LegacyDoseVoxelIndex3D index2; + // iteration polygon + for (int point_index = 0 ; point_index < (strVector.at(struct_index).size() - 1); point_index++) + { - index2.x = 0; - index2.y = 0; - index2.z = index.z; - /*Mark all voxels outside the structure: using FloodFill4*/ - bool firstVoxelOutStr=false; - for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelOutStr ; index2.x++ ){ - for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelOutStr ; index2.y++ ){ - DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); - if(doseVoxel.voxelInStructure(*_structure)==0){ + firstPoint = strVector.at(struct_index).at(point_index); + secondPoint = strVector.at(struct_index).at(point_index + 1); - LegacyUnsignedIndex3D indexUint; - indexUint.x = static_cast(index2.x); - indexUint.y = static_cast(index2.y); - indexUint.z = static_cast(index2.z); - indexListOutside.at(index.z).push_back( indexUint ); - firstVoxelOutStr=true; - break; - - }//end if + std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( + struct_index).at(point_index).raw_intersections; + std::vector& column_intersections_ref = Intersections.at( + resolution_level).at(struct_index).at(point_index).column_intersections; - }//end for index2.y - if(firstVoxelOutStr) - break; - }//end for index2.x + std::vector& intersections_raw_and_column_ref = Intersections.at( + resolution_level).at(struct_index).at(point_index).intersections_raw_and_column; - } - if( indexListOutside.at(index.z).size() > 0 ) - this->FloodFill4(indexListOutside.at(index.z),brightness_unknown, brightness_outside,resolution_level); + GoIntersectRaw(firstPoint , secondPoint , raw_intersections_ref, resolution_level); + GoIntersectColumn(firstPoint , secondPoint , column_intersections_ref, resolution_level); - if( indexListInside.at(index.z).size() == 0 ){ + UnifyRawAndColumn(firstPoint , raw_intersections_ref , column_intersections_ref , + intersections_raw_and_column_ref, resolution_level); - LegacyDoseVoxelIndex3D index2; - index2.x = 0; - index2.y = 0; - index2.z = index.z; + } - //get corresponding polygons - DoseVoxel doseVoxelZPlane=DoseVoxel(index2,&(this->GInf.at(resolution_level))); - std::vector sliceV=doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); - for(int i=0;igetLegacyStructureVector().at(sliceV.at(i)); + // the connection between the last and the first Point of the Polygon needs to be checked as well - Contour contour=Contour(polygon);//get the contour in this slice + if (strVector.at(struct_index).size() > 0) + { - LegacyPolygonType box=contour.getMinimalBox(); - Contour boxContour=Contour(box); + firstPoint = strVector.at(struct_index).at((strVector.at(struct_index).size() - 1)); + secondPoint = strVector.at(struct_index).at(0); - bool firstVoxelInStr=false; + std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( + struct_index).at((strVector.at(struct_index).size() - 1)).raw_intersections; + std::vector& column_intersections_ref = Intersections.at( + resolution_level).at(struct_index).at((strVector.at(struct_index).size() - 1)).column_intersections; + std::vector& intersections_raw_and_column_ref = Intersections.at( + resolution_level).at(struct_index).at((strVector.at(struct_index).size() - + 1)).intersections_raw_and_column; - /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ - for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelInStr ; index2.x++ ){ + GoIntersectRaw(firstPoint , secondPoint , raw_intersections_ref, resolution_level); + GoIntersectColumn(firstPoint , secondPoint , column_intersections_ref, resolution_level); - for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelInStr ; index2.y++ ){ - if(MaskField.at( resolution_level )->GetData( index2.x, index2.y, index2.z )==brightness_unknown) { + UnifyRawAndColumn(firstPoint, raw_intersections_ref , column_intersections_ref, + intersections_raw_and_column_ref, resolution_level); - DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); + } - //if doseVoxel inside the box - LegacyWorldCoordinate2D luP={doseVoxel.getLeftUpperPoint().x(),doseVoxel.getLeftUpperPoint().y()}; + } - //if left upper point of this voxel inside the box + /*for( int struct_index = 0 ; struct_index < strVector.size() ; struct_index++ ){ - if(luP.x>=box.at(0).x && luP.y>=box.at(0).y && luP.x<=box.at(2).x && luP.y<=box.at(2).y){ + // iteration polygon - if(doseVoxel.voxelInStructure(*_structure)==1){ + for( int point_index = 0 ; point_index < ( strVector.at(struct_index).size() - 1 ); point_index++ ){ - //std::cout << "first inside voxel: "<& raw_intersections_ref = Intersections.at(0).at(0).at( struct_index ).at( point_index ).raw_intersections; - break; - - }//end if - - }//end if - - } - - }//end for index2.y - if(firstVoxelInStr) - break; - }//end for index2.x - - if(firstVoxelInStr){ - LegacyUnsignedIndex3D indexUint; - indexUint.x = static_cast(index2.x); - indexUint.y = static_cast(index2.y); - indexUint.z = static_cast(index2.z); - indexListInside.at(index.z).push_back(indexUint); - } - - }//end for i - - } - - if(indexListInside.at(index.z).size() > 0)this->FloodFill4(indexListInside.at(index.z),brightness_unknown,brightness_inside,resolution_level); - - //check unknown voxels - int sizeUnknown=0; - - LegacyDoseVoxelIndex3D index2; - - index2.x = 0; - index2.y = 0; - index2.z = index.z; - - for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index2.x++ ){ - for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index2.y++ ){ - if(MaskField.at( resolution_level )->GetData(index2.x,index2.y,index2.z)==brightness_unknown){ - //std::cout << index2.toString()<<"---"; - //sizeUnknown++; - DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); - double voxelInStr=doseVoxel.voxelInStructure(*_structure); - if(voxelInStr>0){ - indexListInside.at(index.z).resize(0); - LegacyUnsignedIndex3D indexUint; - indexUint.x = static_cast(index2.x); - indexUint.y = static_cast(index2.y); - indexUint.z = static_cast(index2.z); - indexListInside.at(index.z).push_back(indexUint); - this->FloodFill4(indexListInside.at(index.z),brightness_unknown,brightness_inside,resolution_level); - } - else{ - indexListOutside.at(index.z).resize(0); - LegacyUnsignedIndex3D indexUint; - indexUint.x = static_cast(index2.x); - indexUint.y = static_cast(index2.y); - indexUint.z = static_cast(index2.z); - indexListOutside.at(index.z).push_back(indexUint); - this->FloodFill4(indexListOutside.at(index.z),brightness_unknown, brightness_outside,resolution_level); - } - } - } - } - /*if(sizeUnknown!=0) - std::cout << "Unknown: "<& column_intersections_ref = Intersections.at(0).at( struct_index ).at( point_index ).column_intersections; - }//end for index.z - } + for(int i=0;iGetDimX() ; x++ ){ - for( int y = 0 ; y < MaskField.at( resolution_level )->GetDimY() ; y++ ){ - for( int z = 0 ; z < MaskField.at( resolution_level )->GetDimZ() ; z++ ){ - - if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_inside ) counter_inside++; - if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_outside ) counter_outside++; - if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_border ) counter_border++; - if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_unknown ) counter_unknown++; - - } - } - } - - std::cout<< " counter_inside : " << counter_inside < indexListInside; - std::vector< UnsignedIndexList > indexListOutside; - - for( int z = 0 ; z < GInf.at(resolution_level).getNumSlices() ; z++ ){ - UnsignedIndexList a_list; - a_list.resize(0); - indexListInside.push_back(a_list); - indexListOutside.push_back(a_list); - } - - if( resolution_level < ( MaskField.size() - 1 ) )MaskField.at( resolution_level )->GetBorderRegion( MarkInterestingArea.at(resolution_level), indexListInside , indexListOutside, brightness_unknown, brightness_inside, brightness_outside ); - setInsideVoxel( resolution_level , indexListInside, indexListOutside ); - - } - - - - void Mask::SetContentUnknown(){ - - for( int resolution_level = 0 ; resolution_level < GInf.size() ; resolution_level++ ){ - - for( int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ - - - LegacyUnsignedIndex3D index_internal; - index_internal.x = 0; - index_internal.y = 0; - index_internal.z = index_z; + } - /*First: Mark all voxels as unknown*/ - if( ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y != 0 ) ){ - - for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x ; index_internal.x++ ){ - for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y ; index_internal.y++ ){ - + void Mask::UnifyRawAndColumn(LegacyWorldCoordinate3D the_firstPoint, + std::vector& raw_intersections_ref , + std::vector& column_intersections_ref , + std::vector& intersections_raw_and_column_ref, int resolution_level) + { - //set all no border voxels as outside - if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ - MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_unknown ); - //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); + if ((column_intersections_ref.size() > 0) && (raw_intersections_ref.size() == 0)) + { + intersections_raw_and_column_ref = column_intersections_ref; + } - }//end if + if ((raw_intersections_ref.size() > 0) && (column_intersections_ref.size() == 0)) + { + intersections_raw_and_column_ref = raw_intersections_ref; + } - }//end for index_internal.y - }//end for index_internal.x - //std::cout << std::endl; + if ((intersections_raw_and_column_ref.size() == + 0)) // falls das nicht der Fall ist ist der Verlauf der Konturpunkte horizontal oder vertikal. Dann gibt es sowiso nur horizontale oder vertikale Schnittpunkte und die Vereinigung ist in GoIntersect... bereits geschehen. + { - }//end if - - } + bool done = false; - } + int internal_counter = 0; + int counter = 0 ; - } - + LegacyWorldCoordinate2D rawPoint; + rawPoint.x = 0; + rawPoint.y = 0; - void Mask::SeperateRegionsQuick(){ - - //doseVoxelIndexInStructure.clear(); - _doseVoxelInStructure.clear(); + LegacyWorldCoordinate2D columnPoint; + columnPoint.x = 0; + columnPoint.y = 0; - LegacyUnsignedIndex3D index; - index.x = 0; - index.y = 0; - index.z = 0; - for( index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++ ){ + LegacyWorldCoordinate2D firstPoint = GetDoubleIndex2D(the_firstPoint.x , the_firstPoint.y, + resolution_level); - LegacyUnsignedIndex3D index_internal; - index_internal.x = 0; - index_internal.y = 0; - index_internal.z = index.z; - if( ( MarkInterestingArea.at(0).at( index.z ).index_end.x != 0 ) && ( MarkInterestingArea.at(0).at( index.z ).index_end.y != 0 ) ){ + while (! done) + { - for( index_internal.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index_internal.x++ ){ - for( index_internal.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(0).at( index.z ).index_end.y ; index_internal.y++ ){ - if( MaskField.at( 0 )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ + if (counter < raw_intersections_ref.size()) + { + rawPoint = raw_intersections_ref.at(counter); + } + else if (raw_intersections_ref.size() > 0) + { + rawPoint = raw_intersections_ref.at(raw_intersections_ref.size() - 1); + } - MaskField.at( 0 )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); + if (internal_counter < column_intersections_ref.size()) + { + columnPoint = column_intersections_ref.at(internal_counter); + } + else if (column_intersections_ref.size() > 0) + { + columnPoint = column_intersections_ref.at(column_intersections_ref.size() - 1); + } - } + double distance_raw = (firstPoint.y - rawPoint.y) * (firstPoint.y - rawPoint.y) + + (firstPoint.x - rawPoint.x) * (firstPoint.x - rawPoint.x); + double distance_column = (firstPoint.x - columnPoint.x) * (firstPoint.x - columnPoint.x) + + (firstPoint.y - columnPoint.y) * (firstPoint.y - columnPoint.y); - } - } - } - index.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y; - for( index.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index.x++ ){ + if (distance_raw == distance_column) + { + if (internal_counter >= column_intersections_ref.size()) + { + counter++; + } + else + { + intersections_raw_and_column_ref.push_back(columnPoint); + internal_counter++; + counter++; + } + } + else if (((distance_raw > distance_column) + && (internal_counter < column_intersections_ref.size())) + || (counter >= (raw_intersections_ref.size()))) + { + intersections_raw_and_column_ref.push_back(columnPoint); + internal_counter++; + } + else if ((distance_raw < distance_column) + || (internal_counter >= column_intersections_ref.size())) + { + if ((counter < (raw_intersections_ref.size()))) + { + intersections_raw_and_column_ref.push_back(rawPoint); + counter++; + } + } - if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ - MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); - ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); - } + if ((internal_counter >= column_intersections_ref.size()) + && (counter >= raw_intersections_ref.size())) + { + done = true; + } - } - index.y = MarkInterestingArea.at(0).at( index.z ).index_end.y; + } - for( index.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index.x++ ){ - if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ - MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); - ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); - } + /* for( int i = 0 ; i < column_intersections_ref.size() ; i++ ){ - } + LegacyWorldCoordinate2D Point = column_intersections_ref.at( i ); + std::cout<< " column_intersections_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!: " << Point.x <GetData( index.x, index.y, index.z ) == brightness_inside ){ - MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); - ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); - } + for( int i = 0 ; i < raw_intersections_ref.size() ; i++ ){ - } + LegacyWorldCoordinate2D Point = raw_intersections_ref.at( i ); + std::cout<< " raw_intersections_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1111 : " << Point.x <GetData( index.x, index.y, index.z ) == brightness_inside ){ - MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); - ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); - } - } + for( int i = 0 ; i < intersections_raw_and_column_ref.size() ; i++ ){ + LegacyWorldCoordinate2D Point = intersections_raw_and_column_ref.at( i ); + std::cout<< " intersections_raw_and_column_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : " << Point.x <& raw_intersections_ref, int resolution_level) + { - LegacyUnsignedIndex3D index; - index.x = 0; - index.y = 0; - index.z = 0; - LegacyDoseVoxelIndex3D aDoseIndex; - aDoseIndex.x = 0; - aDoseIndex.y = 0; - aDoseIndex.z = 0; + if ((secondPoint.y - firstPoint.y) != 0) + { + if ((secondPoint.x - firstPoint.x) != 0) + { - double fraction = 0; + /* + Siehe GoIntersectColumn (ist eigentlich das selbe) + Auf der einen Gerade liegt das Strutkur Segment und die andere Gerade ist die Spalte + Beziehungsweise die Zeile. + Zwei Geleichungen und zwei Unbekannte .... + */ - for( index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++ ){ - if( FieldOfIntersections ){ - FieldOfIntersections->SetZero(); - GetIntersectionInformationThisSlice( index.z ); - - } - - for( index.x = 0 ; index.x < GInf.at(0).getNumColumns() ; index.x++ ){ - for( index.y = 0 ; index.y < GInf.at(0).getNumRows() ; index.y++ ){ + /* + NEBENRECHNUNG : - aDoseIndex.x = index.x; - aDoseIndex.y = index.y; - aDoseIndex.z = index.z; - + linear connection between both points : - if( brightness_inside == MaskField.at( 0 )->GetData( index.x, index.y, index.z ) ){ - - //doseVoxelIndexInStructure.push_back( aDoseIndex ); - fraction = 1.0; + x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda + y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda + with lambda between zero and one representing the regarded structure segment - DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); - doseVoxel.setProportionInStr(fraction); - this->_doseVoxelInStructure.push_back(doseVoxel); - // und jetzt fraction irgendwie anhaengen an geeignete Struktur und dann raus damit - //std::cout << "inside: "<GetData( index.x, index.y, index.z ) ){ + x = imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) + y = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) + x_offset_raw gibt die rauemliche Verschiebung beim aendern des zeilen index an + raw_index repraesentiert den index der betrachteten Zeile also die y-Position innerhalb der Spalte - - if( !do_detailed_subvox ){ /*Lanlan*/ - - - DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); - fraction=doseVoxel.voxelInStructure(*_structure);//simple test - if(fraction>0){ - //doseVoxelIndexInStructure.push_back( aDoseIndex ); - doseVoxel.setProportionInStr(fraction); - this->_doseVoxelInStructure.push_back(doseVoxel); - } + x_offset_raw = imageOrientationColumn.x*pixelSpacingColumn; + y_offset_raw = imageOrientationColumn.y*pixelSpacingColumn; + unknown : lambda and the_index.x + the_index.x and raw_index represent the voxel - - } - else{ /*Martina..............*/ + Solution : - //doseVoxelIndexInStructure.push_back( aDoseIndex ); - - fraction = 1.0; - + First Equation: imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda + Second Equation: imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda - - fraction = GetFractionInside( aDoseIndex ); - - if( ( fraction < 0 ) || ( fraction > 1.0 ) ) assert(0); + Lambda from second equation: + ( imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) - firstPoint.y ) / ( secondPoint.y - firstPoint.y ) = lambda - - DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); - doseVoxel.setProportionInStr( fraction ); - _doseVoxelInStructure.push_back( doseVoxel ); - } + First Equation: + ( imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) = lambda + First into Second Equation : + imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = - imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) ) - } - } - } - } + First into Second Equation : + imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = (the_index.x-0.5) * ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) + First into SecondEquation : + (the_index.x-0.5) = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) / ( ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) ) + Der andere index ist raw_index und daher bereits bekannt. + Vorsicht, bevor ein Schnittpunkt als solcher akzeptiert werden kann muss untersucht werden + ob lambda zwischen null und eins liegt + da ansonsten Schnittpunkte der Segmentgeraden betrachtet werden, + die ausserhalb des eigentlichen Struktursegmentes liegen. + */ - double total_volume = 0; - for( int counter = 0 ; counter < _doseVoxelInStructure.size() ; counter++ ){ + double x_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at( + resolution_level).getPixelSpacingColumn(); + double y_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at( + resolution_level).getPixelSpacingColumn(); - total_volume += _doseVoxelInStructure.at( counter ).getProportionInStr(); + LegacyWorldCoordinate2D index_first_point; + index_first_point.x = 0; + index_first_point.y = 0; + LegacyWorldCoordinate2D index_second_point; + index_second_point.x = 0; + index_second_point.y = 0; - } + // indicees der beiden uebergebenen Punkte bestimmen + index_first_point = GetDoubleIndex2D(firstPoint.x , firstPoint.y, resolution_level); + index_second_point = GetDoubleIndex2D(secondPoint.x , secondPoint.y, resolution_level); - //std::cout<< " total_volume : " << total_volume < 0) + { - } + begin_ind = static_cast(floor(index_first_point.y)); + end_ind = static_cast(floor(index_second_point.y) + 1); + } + else if (index_diff < 0) + { + do_swap = 1; + begin_ind = static_cast(floor(index_second_point.y)); + end_ind = static_cast(floor(index_first_point.y) + 1); + } + else + { + begin_ind = 0; + end_ind = 0; - void Mask::ConnectArea( field_content_type brightness_from , field_content_type brightness_to , LegacyUnsignedIndex3D start_index, LegacyDoseVoxelIndex2D index_begin, LegacyDoseVoxelIndex2D index_end ){ + } - if( ( start_index.x >= index_begin.x ) && ( start_index.y >= index_begin.y ) && ( start_index.x <= index_end.x ) && ( start_index.y <= index_end.y ) ){ + if (begin_ind < 0) + { + begin_ind = 0; + } - std::deque index_list; + if (end_ind > (GInf.at(resolution_level).getNumRows() - 1)) + { + end_ind = GInf.at(resolution_level).getNumRows() - 1; + } - LegacyUnsignedIndex2D this_index; - this_index.x = start_index.x; - this_index.y = start_index.y; + LegacyWorldCoordinate2D coord2D; + coord2D.x = 0; + coord2D.y = 0; + LegacyWorldCoordinate3D the_index; + the_index.x = 0; + the_index.y = 0; + the_index.z = 0; - LegacyUnsignedIndex2D another_index; - another_index.x = 0; - another_index.y = 0; + double multi_res_offset = GetWorldCoordinateOffsetThisResolutionLevel(resolution_level); - MaskField.at( 0 )->PutData( start_index.x, start_index.y, start_index.z, brightness_to ); - index_list.push_back( this_index ); + //std::cout <<"go intersection raw: "< 0 ){ + // neu multi resoltuion + the_index.x = multi_res_offset + (GInf.at(resolution_level).getImagePositionPatient()( + 1) + y_offset_raw * (raw_index - multi_res_offset) - firstPoint.y - (GInf.at( + resolution_level).getImagePositionPatient()(0) - firstPoint.x + x_offset_raw * + (raw_index - multi_res_offset)) * ((secondPoint.y - firstPoint.y) / (secondPoint.x - + firstPoint.x))) / (((-1) * GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at( + resolution_level).getPixelSpacingRow() + (secondPoint.y - firstPoint.y) / + (secondPoint.x - firstPoint.x) * (GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at( + resolution_level).getPixelSpacingRow()))); - // std::cout<< " counter " << counter < index_begin.x ){ - another_index.x = this_index.x - 1; - another_index.y = this_index.y; - if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ - index_list.push_back( another_index ); - counter++; - MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); - } - } + // neu multi resolution + double lambda = (GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_raw * + (raw_index - multi_res_offset) + GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at( + resolution_level).getPixelSpacingRow() * (the_index.x - multi_res_offset) - firstPoint.x) / + (secondPoint.x - firstPoint.x) ; - if( this_index.y > index_begin.y ){ - another_index.x = this_index.x; - another_index.y = this_index.y - 1; - if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ - index_list.push_back( another_index ); - counter++; - MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); - } - } + if ((lambda >= 0) && (lambda <= 1)) + { + raw_intersections_ref.push_back(coord2D); + //std::cout << coord2D.toString()<GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ - index_list.push_back( another_index ); - counter++; - MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); - } - } + /* + core::LegacyDoseVoxelIndex3D index={static_cast(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z) )}; + DoseVoxel voxel=DoseVoxel(index,GInf.at(resolution_level)); + std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); + this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(index, interPs));!!!Lanlan */ - if( this_index.y < index_end.y ){ - another_index.x = this_index.x; - another_index.y = this_index.y + 1; - if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ - index_list.push_back( another_index ); - counter++; - MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); - } - } + /*std::cout << "intersections: "< vecW; + LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(end_ind-raw_index)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; + LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(end_ind-raw_index+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; + vecW.push_back(p1); + vecW.push_back(p2); + LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast( this->GetZIndex(firstPoint.z) )}; + this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW));*/ + } - } - } + } + if (do_swap) + { - // die folgende Funktion prueft immer erst, ob es sich um einen Schnittpunkt mit der Ecke handelt. Falls nicht wird er in die Reihe der Kantenschnittpunkte einsortiert. Betrachtet wird lediglich die erste Ecke. - void Mask::SetThisIntersectionToCornerOrEdge( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D, unsigned int edge_number, IntersectionsThisVoxel& voxel_intersections ){ - - - if(edge_number==0){ - SetThisIntersection( index_x , (index_x+1) , index_y , intersection , coord2D.x, coord2D.y , voxel_intersections, edge_number ); - } - else if(edge_number==1){ - SetThisIntersection( index_y , (index_y+1) , ( index_x + 1 ) , intersection , coord2D.y, coord2D.x , voxel_intersections, edge_number ); - //SetThisIntersectionYIncreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); - } - else if(edge_number==2){ - SetThisIntersection( ( index_x + 1 ) , index_x , ( index_y + 1 ) , intersection , coord2D.x, coord2D.y , voxel_intersections, edge_number ); - //SetThisIntersectionXDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); - } - else if(edge_number==3){ - SetThisIntersection( ( index_y + 1 ) , index_y , index_x , intersection , coord2D.y, coord2D.x , voxel_intersections, edge_number ); - //SetThisIntersectionYDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); - } - else assert(0); - - } - - - - void Mask::SetThisIntersection( unsigned int corner_of_interest , unsigned int corner_next, unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ){ - - if( coord_fixed != static_cast(corner_fixed) ) assert(0); // this should never happen since coord_fixed is the coordinate which is the same all along the edge that starts with corner_fixed - - - if( coord_of_interest == static_cast(corner_of_interest) ){ // falls der Schnittpunkt direkt am Anfang der Kante liegt also der Anfangspunkt der Kante ist - - voxel_intersections.corner_intersections_intersection_coord.at(edge_number).push_back( intersection ); // dann haenge den Schnittpunkt an die Liste der Schnittpunkte mit eben diesem Anfangspunkt der Kante an - return; - - } - else{ - - if( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() > 0 ){ // falls die Kante schon Schnittpunkte hat - double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(0).at(0); - // In der naechsten Zeile wird geprueft, ob der Schnittpunkt zwischen dem Anfang der Kante und dem ersten bereits bekannten Schnittpunkt liegt. Falls ja, wird er entsprechend eingefuegt. - if( CompareIfBetweenInsertAtBeginning( coord_of_interest , static_cast(corner_of_interest) , first_coord_double , edge_number, intersection , voxel_intersections ) ) return; - } - // naechste Zeile: Pruefe, ob der Schnittpunkt in der Liste der Schnittpunkte mit dieser Kante schon vorhanden ist und falls ja, verlaengere die Liste der Punkte, die eben in diesem Punkt schneiden um den neuen Schnittpunkt. - // Puntemaessig ist das zwar der selbe, der schon mindestens einmal da ist, aber intersection ist ja eine Art Index im PolygonOfIntersections - // und muss dann hier einsortiert werden. Denn das Polygon kann tatsaechlich mehrfach durch den selben Punkt laufen. - // Falls der Schnittpunkt noch nicht vorkommt, aber zwischen zweien ist, die bereits vorkommen, wird er entsprechend eingefuegt. - if( CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( coord_of_interest , edge_number, intersection , voxel_intersections ) ) return; - - double that_coord_double = 0; - - // Die folgenden beiden Zeilen sind dafuer zustaendig that_coord_double mit entweder dem letzten bereits bekannten Schnittpunkt dieser Kante, - // oder alternativ mit dem Anfangspunkt der Kante zu belegen. - if( voxel_intersections.edge_intersections_vox_coord.at(edge_number).size() > 0 ) that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).at(0) ; - else that_coord_double = static_cast( corner_of_interest ); - - if( that_coord_double == coord_of_interest ){ - - if( coord_of_interest == static_cast( corner_of_interest ) ) assert( 0 ); // Das kann nicht sein, denn falls der Schnittpunkt wirklich der erste Punkt der Kante waere, muesste das ganz zu Beginn dieser Funktion bereits erkannt worden sein und die Funktion haette dann bereits returned. Falls that_coord_double also coord_of_interest (eizusortierender Punk) ist, kann dieser nicht der Anfangspunkt der Kante sein. - - // der einzusortierende Punkt coord_of_interest ist gerade gleich dem letzten bereits gefundenen Schnittpunkt that_coord_double und wird der Liste seinder Vorkommnisse entsprechend hinzugefuegt. - voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).push_back( coord_of_interest ); - voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).push_back( intersection ); - return; - - } - else{ - - // Hier wird geprueft, ob der betrachtete Punkt zwischen dem letzten bereits gefundenen Schnittpunkt und dem Ende der Kante liegt. Falls ja, wird er vor dem Kantenende entsprechend eingefuegt. - if( CompareIfBetweenAppend( coord_of_interest , that_coord_double, static_cast( corner_next ), edge_number, intersection , voxel_intersections ) ){ - - return; - - } - - if( coord_of_interest == static_cast( corner_next ) ) assert(0); // this case is not supposed to be considered here. Its the next edge and should have gone elsewhere. Das Ende der Kante ist der Anfang der naechsten Kante uns haette daher bei dieser naechsten Kante landen muessen. - } - assert( 0 ); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be considered here. - } - - } - - - - void Mask::SetThisIntersectionXIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ){ - - if( coord2D.y != static_cast(index_y) ) assert(0); // this should never happen - - if( coord2D.x == static_cast(index_x) ){ - - voxel_intersections.corner_intersections_intersection_coord.at(0).push_back( intersection ); - return; - - } - else{ - - if( voxel_intersections.edge_intersections_intersection_coord.at(0).size() > 0 ){ - - double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at(0).at(0); - if( CompareIfBetweenInsertAtBeginning( coord2D.x , static_cast(index_x) , first_coord_double , edge_number, intersection , voxel_intersections ) ) return; - - } - - if( CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( coord2D.x , edge_number, intersection , voxel_intersections ) ) return; - - double that_coord_double = 0; - - if( voxel_intersections.edge_intersections_vox_coord.at(0).size() > 0 ) that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).at(0) ; - else that_coord_double = static_cast( index_x ); - - - if( that_coord_double == coord2D.x ){ - - if( coord2D.x == static_cast( index_x ) ) assert( 0 ); - - voxel_intersections.edge_intersections_vox_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).push_back( coord2D.x ); - voxel_intersections.edge_intersections_intersection_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).push_back( intersection ); - return; - - } - else{ - - if( CompareIfBetweenAppend( coord2D.x , that_coord_double, static_cast( index_x + 1 ), edge_number, intersection , voxel_intersections ) ) return; - - if( coord2D.x == static_cast( index_x + 1 ) ) assert(0); // this case is not supposed to be treated here. - - } - - assert( 0 ); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be treated here. - - } - - } - - - bool Mask::CompareIfBetweenAppend( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ - - if( ( ( value_to_compare < big_value_to_compare_with ) && ( value_to_compare > small_value_to_compare_with ) ) || ( ( value_to_compare > big_value_to_compare_with ) && ( value_to_compare < small_value_to_compare_with ) ) ){ - - std::vector< double > double_vec; - double_vec.push_back(value_to_compare) ; - - std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; - intersection_vec.push_back( intersection ); - - voxel_intersections.edge_intersections_vox_coord.at(edge_number).push_back( double_vec ); - voxel_intersections.edge_intersections_intersection_coord.at(edge_number).push_back( intersection_vec ); - return true; - - } - else return false; - - } - - - bool Mask::CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( double value_to_compare , unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ - - for( int i = 0 ; i < ( static_cast(voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size()) - 1 ) ; i++ ){ - - double the_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).at(0) ; - - if( value_to_compare == the_coord_double ){ - - voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).push_back( value_to_compare ); - voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at(i).push_back( intersection ); - return true; - - } - else{ - - double another_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i+1).at(0) ; - - if( ( ( another_double > value_to_compare ) && ( the_coord_double < value_to_compare ) ) || ( ( another_double < value_to_compare ) && ( the_coord_double > value_to_compare ) ) ){ - - std::vector< double > double_vec; - double_vec.push_back( value_to_compare ) ; - std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; - intersection_vec.push_back( intersection ); - intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at(edge_number).begin() + ( i + 1 ); - - voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert( ( voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin() + ( i + 1 ) ) , double_vec ); - voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert( it , intersection_vec ); - - return true; - - } - } - - } - - return false; - - } - - - bool Mask::CompareIfBetweenInsertAtBeginning( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ - - if( ( ( value_to_compare > small_value_to_compare_with ) && ( value_to_compare < big_value_to_compare_with ) ) || ( ( value_to_compare < small_value_to_compare_with ) && ( value_to_compare > big_value_to_compare_with ) ) ){ - - std::vector< double > double_vec; - double_vec.push_back(value_to_compare) ; - std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; - intersection_vec.push_back( intersection ); - intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at(edge_number).begin(); - - voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert( voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin(), double_vec ); - voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert( it , intersection_vec ); - - return true; - - } - return false; - - } - - - void Mask::SetThisIntersectionYIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ - - if( coord2D.x != static_cast(index_x+1) ) assert(0); // this should never happen - - // to be implemented - - - } - - - void Mask::SetThisIntersectionXDecreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ - - if( coord2D.y != static_cast(index_y+1) ) assert(0); // this should never happen - - // to be implemented - - } - - - void Mask::SetThisIntersectionYDecreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ - - if( coord2D.x != static_cast(index_x) ) assert(0); // this should never happen - - // to be implemented - - } - - - void Mask::Init(){ - - SliceStructureCorrespondency.clear(); - do_detailed_subvox = true; - if( do_detailed_subvox ){ - FieldOfIntersections = new rttb::masks::legacy::FieldOfPointer( GInf.at(0).getNumColumns() , GInf.at(0).getNumRows() , 1 ); - } - - for( int i = 0 ; i < MaskField.size() ; i++ ){ - if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); - } - MaskField.resize(0); - rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new rttb::masks::legacy::FieldOfScalar( GInf.at(0).getNumColumns() , GInf.at(0).getNumRows() , GInf.at(0).getNumSlices() ); - MaskField.push_back( a_field_of_scalar ); - - brightness_inside = 50; - brightness_border = 10; - brightness_outside = 0; - brightness_unknown = -10; - - LegacyDoseVoxelIndex3D doseVoxelIndex; - doseVoxelIndex.x = 0; - doseVoxelIndex.y = 0; - doseVoxelIndex.z = 0 ; - - int currentSliceNumber=0; - - LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - LegacyPolygonSequenceType& strVector_ref = strVector; - StructureInTermsOfIntersections inters; - inters.resize( strVector.size() ); - Intersections.push_back( inters ); - + std::vector raw_intersections_to_be_swaped; - StructureInTermsOfIntersections sitoi=Intersections.at(0); - //StructureInTermsOfIntersections:: + for (int this_one = (raw_intersections_ref.size() - 1) ; this_one >= 0 ; this_one--) + { - for(unsigned int i = 0 ; i < strVector.size() ; i++ ){ + raw_intersections_to_be_swaped.push_back(raw_intersections_ref.at(this_one)); - Intersections.at(0).at( i ).resize( strVector.at( i ).size() ); + } - LegacyWorldCoordinate2D index_coord; - index_coord.x = 0; - index_coord.y = 0; + raw_intersections_ref.swap(raw_intersections_to_be_swaped); - LegacyWorldCoordinate3D contour_point_world; - contour_point_world.x = 0; - contour_point_world.y = 0; - contour_point_world.z = 0; - - for(unsigned int j = 0 ; j < strVector.at( i ).size() ; j++ ){ - contour_point_world = strVector.at( i ).at( j ); - index_coord = GetDoubleIndex2D( contour_point_world.x , contour_point_world.y ); - Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.x = index_coord.x; - Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.y = index_coord.y; - Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.z = GetZIndex(contour_point_world.z); + } + } + else + { + GoGetRawIntersectionsAlongThisColumn(firstPoint , secondPoint , raw_intersections_ref , + resolution_level); + } - } + } + } - } - // iteration slices - for( doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++ ){ - correspoinding_structure_vector str_v; + void Mask::GoGetRawIntersectionsAlongThisColumn(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, + int resolution_level) + { - LegacyWorldCoordinate2D the_index; - the_index.x = 0; - the_index.y = 0; + LegacyWorldCoordinate2D index_first_point; + index_first_point.x = 0; + index_first_point.y = 0; + LegacyWorldCoordinate2D index_second_point; + index_second_point.x = 0; + index_second_point.y = 0; - DoseVoxel doseVoxel; - //from dose index to worldcoordinate - doseVoxel.setDoseVoxel( doseVoxelIndex , &(GInf.at(0)) ); + if (firstPoint.x != secondPoint.x) + { + assert(0); + } - str_v=doseVoxel.getZIntersectPolygonIndexVector(*_structure ); //Lanlan + // indicees der beiden uebergebenen Punkte bestimmen + index_first_point = GetDoubleIndex2D(firstPoint.x , firstPoint.y, resolution_level); + index_second_point = GetDoubleIndex2D(secondPoint.x , secondPoint.y, resolution_level); + double index_diff = (index_second_point.y - index_first_point.y); - SliceStructureCorrespondency.push_back( str_v ); + int begin_ind = 0; + int end_ind = 0; + bool do_swap = 0; + if (index_diff > 0) + { - } + begin_ind = static_cast(floor(index_first_point.y)); - - InitInterestingArea(); - InitMultiResolution(); + if (floor(index_first_point.y) < index_first_point.y) + { + begin_ind += 1; + } - } + end_ind = static_cast(floor(index_second_point.y)); + } + else if (index_diff < 0) + { + do_swap = 1; + begin_ind = static_cast(floor(index_second_point.y)); + if (floor(index_second_point.y) < index_second_point.y) + { + begin_ind += 1; + } + end_ind = static_cast(floor(index_first_point.y)); - void Mask::InitInterestingArea(){ + } + else + { - MarkInterestingArea.clear(); + begin_ind = 0; + end_ind = 0; - std::vector interesting_area_this_resolution; + } - LegacyDoseVoxelIndex3D doseVoxelIndex; - doseVoxelIndex.x = 0; - doseVoxelIndex.y = 0; - doseVoxelIndex.z = 0 ; + if (begin_ind < 0) + { + begin_ind = 0; + } - int currentSliceNumber=0; + if (end_ind > (GInf.at(resolution_level).getNumRows() - 1)) + { + end_ind = GInf.at(resolution_level).getNumRows() - 1; + } - LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - LegacyPolygonSequenceType& strVector_ref = strVector; + LegacyWorldCoordinate2D coord2D; + coord2D.x = 0; + coord2D.y = 0; - // iteration slices - for( doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++ ){ + //std::cout <<"go intersection raw along column: "< vecW; + //LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(raw_index-begin_ind)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; + //LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(raw_index-begin_ind+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; + //vecW.push_back(p1); + //vecW.push_back(p2); + //LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z))}; + //this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW)); - DoseVoxel doseVoxel; - //from dose index to worldcoordinate - doseVoxel.setDoseVoxel( doseVoxelIndex ,&( GInf.at(0)) ); - std::vector sliceV = doseVoxel.getZIntersectPolygonIndexVector( *_structure ); + //core::LegacyDoseVoxelIndex3D index={static_cast(coord2D.x),static_cast(coord2D.y),0}; + /*DoseVoxel voxel=DoseVoxel(dosevoxel,GInf.at(resolution_level)); + std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); + this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, interPs));*/ + /*std::cout << "intersections: "< raw_intersections_to_be_swaped; - // iteration polygon + for (int this_one = (raw_intersections_ref.size() - 1) ; this_one >= 0 ; this_one--) + { - for( int i = 0 ; i < strVector.at(currentSliceNumber).size() ; i++){ + raw_intersections_to_be_swaped.push_back(raw_intersections_ref.at(this_one)); - LegacyWorldCoordinate3D firstPoint = strVector.at(currentSliceNumber).at(i); - //LegacyWorldCoordinate3D secondPoint = strVector.at(currentSliceNumber).at(i+1); + } - if( firstPoint.x < x_min ){ - x_min = firstPoint.x; - } - if( firstPoint.y < y_min ){ - y_min = firstPoint.y; - } - if( firstPoint.x > x_max ){ - x_max = firstPoint.x; - } - if( firstPoint.y > y_max ){ - y_max = firstPoint.y; - } + raw_intersections_ref.swap(raw_intersections_to_be_swaped); - the_index = GetDoubleIndex2D( firstPoint.x , firstPoint.y ); - if( the_index.x < x_index_min ){ - x_index_min = the_index.x; - } - if( the_index.y < y_index_min ){ - y_index_min = the_index.y; - } - if( the_index.x > x_index_max ){ - x_index_max = the_index.x; - } - if( the_index.y > y_index_max ){ - y_index_max = the_index.y; - } + } - } - }//end for indexV + } - if(sliceV.size()>0){ - LegacyArea2D area_2d; - area_2d.x_begin = x_min; - area_2d.x_end = x_max; - area_2d.y_begin = y_min; - area_2d.y_end = y_max; - - int small_enough_x = static_cast(floor( x_index_min ) - 1); - if( small_enough_x < 0 ) small_enough_x = 0; - area_2d.index_begin.x = small_enough_x; - - int small_enough_y = static_cast(floor( y_index_min ) - 1); - if( small_enough_y < 0 ) small_enough_y = 0; - area_2d.index_begin.y = small_enough_y; - - int large_enough_x = static_cast(floor( x_index_max ) + 1); - if( large_enough_x >= GInf.at(0).getNumColumns() ) large_enough_x = ( GInf.at(0).getNumColumns() - 1 ); - area_2d.index_end.x = large_enough_x; - - int large_enough_y = static_cast(floor( y_index_max ) + 1); - if( large_enough_y >= GInf.at(0).getNumRows() ) large_enough_y = ( GInf.at(0).getNumRows() - 1 ); - area_2d.index_end.y = large_enough_y; - interesting_area_this_resolution.push_back( area_2d ); // std::vector - } - else{ - - LegacyArea2D area_2d; - area_2d.Init(); - interesting_area_this_resolution.push_back( area_2d ); - - } - - } - - MarkInterestingArea.push_back( interesting_area_this_resolution ); - - } - - - void Mask::InitMultiResolution(){ - - bool done = false; - - - while( done == false ){ - - int new_dim_x = MaskField.at( 0 )->GetDimX() / static_cast( GetBlockLengthThisResolutionLevel( MaskField.size() ) ) + 1; - int new_dim_y = MaskField.at( 0 )->GetDimY() / static_cast( GetBlockLengthThisResolutionLevel( MaskField.size() ) ) + 1; - - - - if( new_dim_x > 20 && new_dim_y > 20 ){ - - - core::GeometricInfo NewGeomInf; - - NewGeomInf.setImagePositionPatient(GInf.at( GInf.size() - 1 ).getImagePositionPatient()); - - NewGeomInf.setOrientationMatrix(GInf.at( GInf.size() - 1 ).getOrientationMatrix()); - - NewGeomInf.setSliceThickness(GInf.at( GInf.size() - 1 ).getSliceThickness()); - NewGeomInf.setNumSlices(GInf.at( GInf.size() - 1 ).getNumSlices()); - - NewGeomInf.setNumColumns(new_dim_x); - NewGeomInf.setNumRows(new_dim_y); - - double power = 1; - for( int i = 0 ; i < GInf.size() ; i++ ){ - power *= 2; - } - - NewGeomInf.setPixelSpacingRow(GInf.at( 0 ).getPixelSpacingRow() * power); - NewGeomInf.setPixelSpacingColumn(GInf.at( 0 ).getPixelSpacingColumn() * power); - - GInf.push_back( NewGeomInf ); - - rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new rttb::masks::legacy::FieldOfScalar( GInf.at( GInf.size() - 1 ).getNumColumns() , GInf.at( GInf.size() - 1 ).getNumRows() , GInf.at( GInf.size() - 1 ).getNumSlices() ); - MaskField.push_back( a_field_of_scalar ); - - std::vector interesting_area_this_resolution; - - - for( int z = 0 ; z < MarkInterestingArea.at( 0 ).size() ; z++ ){ - - LegacyArea2D NewArea; - NewArea.x_begin = MarkInterestingArea.at( 0 ).at( z ).x_begin; - NewArea.x_end = MarkInterestingArea.at( 0 ).at( z ).x_end; - NewArea.y_begin = MarkInterestingArea.at( 0 ).at( z ).y_begin; - NewArea.y_end = MarkInterestingArea.at( 0 ).at( z ).y_end; - - NewArea.index_begin.x = ( MarkInterestingArea.at( 0 ).at( z ).index_begin.x / power ); - if( NewArea.index_begin.x > 0 ) NewArea.index_begin.x -= 1; - NewArea.index_begin.y = ( MarkInterestingArea.at( 0 ).at( z ).index_begin.y / power ); - if( NewArea.index_begin.y > 0 ) NewArea.index_begin.y -= 1; - NewArea.index_end.x = ( MarkInterestingArea.at( 0 ).at( z ).index_end.x / power ); - NewArea.index_end.x += 1; - if( NewArea.index_end.x >= MaskField.at( MaskField.size() - 1 )->GetDimX() ) NewArea.index_end.x = ( MaskField.at( MaskField.size() - 1 )->GetDimX() - 1 ); - NewArea.index_end.y = ( MarkInterestingArea.at( 0 ).at( z ).index_end.y / power ); - NewArea.index_end.y += 1; - if( NewArea.index_end.y >= MaskField.at( MaskField.size() - 1 )->GetDimY() ) NewArea.index_end.y = ( MaskField.at( MaskField.size() - 1 )->GetDimY() - 1 ); - - interesting_area_this_resolution.push_back( NewArea ); - - } - - MarkInterestingArea.push_back( interesting_area_this_resolution ); - - } - else done = true; - - } - - /* - std::cout<< " MaskField.size() " << MaskField.size() <GetDimX() : " << MaskField.at( i )->GetDimX() <GetDimY() : " << MaskField.at( i )->GetDimY() <pixelSpacingColumn : " << GInf.at( i ).getPixelSpacingColumn() <sliceThickness : " << GInf.at( i ).getSliceThickness() <column : " << GInf.at( i )getNumColumns() <row : " << GInf.at( i )getNumRows() <numberOfFrames : " << GInf.at( i ).getNumSlices() < 1 ) || ( MarkInterestingArea.at( i ).at( z ).index_end.y > 1 ) ){ - - std::cout<< " z : " << z <getLegacyStructureVector(); - LegacyPolygonSequenceType& strVector_ref = strVector; - StructureInTermsOfIntersections inters; - inters.resize( strVector.size() ); - Intersections.push_back( inters ); - - for(unsigned int i = 0 ; i < strVector.size() ; i++ ){ - - Intersections.at(counter).at( i ).resize( strVector.at( i ).size() ); - - LegacyWorldCoordinate2D index_coord; - index_coord.x = 0; - index_coord.y = 0; - - LegacyWorldCoordinate3D contour_point_world; - contour_point_world.x = 0; - contour_point_world.y = 0; - contour_point_world.z = 0; - - for(unsigned int j = 0 ; j < strVector.at( i ).size() ; j++ ){ - - contour_point_world = strVector.at( i ).at( j ); - index_coord = GetDoubleIndex2D( contour_point_world.x , contour_point_world.y , counter ); - Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.x = index_coord.x; - Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.y = index_coord.y; - Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.z = GetZIndex(contour_point_world.z); - - - } - - } - - } - - if( Intersections.size() != GInf.size() ) assert(0); - - /* - for( int counter = 0 ; counter < GInf.size() ; counter++ ){ - std::cout<< " next resolution level " << counter <& column_intersections_ref, int resolution_level) + { - std::cout<< " x : " << Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.x <getLegacyStructureVector(); - LegacyPolygonSequenceType& strVector_ref = strVector; + linear connection between the two points : - LegacyWorldCoordinate3D firstPoint; - firstPoint.x = 0; - firstPoint.y = 0; - firstPoint.z = 0; - LegacyWorldCoordinate3D secondPoint; - secondPoint.x = 0; - secondPoint.y = 0; - secondPoint.z = 0; + x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda + y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda - - // iteration z direction - for(unsigned int struct_index = 0 ; struct_index < strVector.size() ; struct_index++ ){ + with lambda between zero and one representing the regarded structure segment + equation column : - // iteration polygon - for( int point_index = 0 ; point_index < ( strVector.at(struct_index).size() - 1 ); point_index++ ){ + x_offset_column gibt die rauemliche Verschiebung beim aendern des spalten index an + column_index repraesentiert den index der betrachteten Spalte also die x Position innerhalb der Zeile + x = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y + y = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y - firstPoint = strVector.at(struct_index).at( point_index ); - secondPoint = strVector.at(struct_index).at( point_index + 1 ); + x_offset_column = imageOrientationRow.x * pixelSpacingRow; + y_offset_column = imageOrientationRow.y * pixelSpacingRow; - std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).raw_intersections; - std::vector& column_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).column_intersections; + Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y + Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y - std::vector& intersections_raw_and_column_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).intersections_raw_and_column; + Erste Gleuchung aufloesen nach lambda : + Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) + Lambda in zweite Gleichung einsetzen : + firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index = imageOrientationColumn.y * pixelSpacingColumn * the_index.y - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y ) = the_index.y * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) + Lambda in zweite Gleichung einsetzen : + the_index.y = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) + */ - GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); - GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); - - UnifyRawAndColumn( firstPoint , raw_intersections_ref , column_intersections_ref , intersections_raw_and_column_ref, resolution_level ); + /* + Nach Koordinatentransformation nochmal ueberlegt: - } + Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) + Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) - // the connection between the last and the first Point of the Polygon needs to be checked as well + Erste Gleuchung aufloesen nach lambda : + Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) + Lambda in zweite Gleichung einsetzen : + firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) = imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y - 0.5 ) = ( the_index.y - 0.5 ) * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) + Lambda in zweite Gleichung einsetzen : + ( the_index.y - 0.5 ) = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) - if( strVector.at(struct_index).size() > 0 ){ - firstPoint = strVector.at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ); - secondPoint = strVector.at( struct_index ).at( 0 ); - std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).raw_intersections; - std::vector& column_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).column_intersections; + */ - std::vector& intersections_raw_and_column_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).intersections_raw_and_column; - GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); - GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); + double x_offset_column = GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at( + resolution_level).getPixelSpacingRow(); + double y_offset_column = GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at( + resolution_level).getPixelSpacingRow(); - UnifyRawAndColumn( firstPoint, raw_intersections_ref , column_intersections_ref, intersections_raw_and_column_ref, resolution_level ); + LegacyWorldCoordinate2D index_first_point; + index_first_point.x = 0; + index_first_point.y = 0; + LegacyWorldCoordinate2D index_second_point; + index_second_point.x = 0; + index_second_point.y = 0; - } + // indicees der beiden uebergebenen Punkte bestimmen + index_first_point = GetDoubleIndex2D(firstPoint.x , firstPoint.y, resolution_level); + index_second_point = GetDoubleIndex2D(secondPoint.x , secondPoint.y, resolution_level); + double index_diff = (index_second_point.x - index_first_point.x); - } - - /*for( int struct_index = 0 ; struct_index < strVector.size() ; struct_index++ ){ - - // iteration polygon - - for( int point_index = 0 ; point_index < ( strVector.at(struct_index).size() - 1 ); point_index++ ){ - - - std::vector& raw_intersections_ref = Intersections.at(0).at(0).at( struct_index ).at( point_index ).raw_intersections; - - std::vector& column_intersections_ref = Intersections.at(0).at( struct_index ).at( point_index ).column_intersections; - - - for(int i=0;i 0) + { + begin_ind = static_cast(floor(index_first_point.x)); + end_ind = static_cast(floor(index_second_point.x) + 1); - void Mask::UnifyRawAndColumn( LegacyWorldCoordinate3D the_firstPoint, std::vector& raw_intersections_ref , std::vector& column_intersections_ref , std::vector& intersections_raw_and_column_ref, int resolution_level ){ - - if( ( column_intersections_ref.size() > 0 ) && ( raw_intersections_ref.size() == 0 ) ){ - intersections_raw_and_column_ref = column_intersections_ref; - } - - if( ( raw_intersections_ref.size() > 0 ) && ( column_intersections_ref.size() == 0 ) ){ - intersections_raw_and_column_ref = raw_intersections_ref; - } - - - if( ( intersections_raw_and_column_ref.size() == 0 ) ){ // falls das nicht der Fall ist ist der Verlauf der Konturpunkte horizontal oder vertikal. Dann gibt es sowiso nur horizontale oder vertikale Schnittpunkte und die Vereinigung ist in GoIntersect... bereits geschehen. - - bool done = false; + } + else if (index_diff < 0) + { - int internal_counter = 0; - int counter = 0 ; + do_swap = 1; + begin_ind = static_cast(floor(index_second_point.x)); + end_ind = static_cast(floor(index_first_point.x) + 1); - LegacyWorldCoordinate2D rawPoint; - rawPoint.x = 0; - rawPoint.y = 0; - - LegacyWorldCoordinate2D columnPoint; - columnPoint.x = 0; - columnPoint.y = 0; - - - LegacyWorldCoordinate2D firstPoint = GetDoubleIndex2D( the_firstPoint.x , the_firstPoint.y, resolution_level ); - - - while( ! done ){ - - - if( counter < raw_intersections_ref.size() )rawPoint = raw_intersections_ref.at( counter ); - else if( raw_intersections_ref.size() > 0 ) rawPoint = raw_intersections_ref.at( raw_intersections_ref.size() - 1 ); - if( internal_counter < column_intersections_ref.size() )columnPoint = column_intersections_ref.at( internal_counter ); - else if( column_intersections_ref.size() > 0 ) columnPoint = column_intersections_ref.at( column_intersections_ref.size() - 1 ); - - double distance_raw = ( firstPoint.y - rawPoint.y ) * ( firstPoint.y - rawPoint.y ) + ( firstPoint.x - rawPoint.x ) * ( firstPoint.x - rawPoint.x ); - double distance_column = ( firstPoint.x - columnPoint.x ) * ( firstPoint.x - columnPoint.x ) + ( firstPoint.y - columnPoint.y ) * ( firstPoint.y - columnPoint.y ); - - - - - if( distance_raw == distance_column ){ - if( internal_counter >= column_intersections_ref.size() ){ - counter++; - } - else{ - intersections_raw_and_column_ref.push_back( columnPoint ); - internal_counter++; - counter++; - } - } - else if( ( ( distance_raw > distance_column ) && ( internal_counter < column_intersections_ref.size() ) ) || ( counter >= ( raw_intersections_ref.size() ) ) ){ - intersections_raw_and_column_ref.push_back( columnPoint ); - internal_counter++; - } - else if( ( distance_raw < distance_column ) || ( internal_counter >= column_intersections_ref.size() ) ){ - if( ( counter < ( raw_intersections_ref.size() ) ) ){ - intersections_raw_and_column_ref.push_back( rawPoint ); - counter++; - } - } - - if( ( internal_counter >= column_intersections_ref.size() ) && ( counter >= raw_intersections_ref.size() ) )done = true; - - - } - - - /* for( int i = 0 ; i < column_intersections_ref.size() ; i++ ){ - - LegacyWorldCoordinate2D Point = column_intersections_ref.at( i ); - std::cout<< " column_intersections_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!: " << Point.x < (GInf.at(resolution_level).getNumColumns() - 1)) + { + end_ind = GInf.at(resolution_level).getNumColumns() - 1; + } - for( int i = 0 ; i < intersections_raw_and_column_ref.size() ; i++ ){ - - LegacyWorldCoordinate2D Point = intersections_raw_and_column_ref.at( i ); - std::cout<< " intersections_raw_and_column_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : " << Point.x <& raw_intersections_ref, int resolution_level ){ + coord2D.y = the_index.y; + coord2D.x = column_index; + //alt + //double lambda = ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - 0.5 ) + GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); - if( ( secondPoint.y - firstPoint.y ) != 0 ){ - if( ( secondPoint.x - firstPoint.x ) != 0 ){ + //neu multi resolution + double lambda = (GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * + (column_index - multi_res_offset) + GInf.at(resolution_level).getImageOrientationColumn()( + 0) * GInf.at(resolution_level).getPixelSpacingColumn() * (the_index.y - multi_res_offset) - + firstPoint.x) / (secondPoint.x - firstPoint.x); + if ((lambda >= 0) && (lambda <= 1)) + { - /* - Siehe GoIntersectColumn (ist eigentlich das selbe) - Auf der einen Gerade liegt das Strutkur Segment und die andere Gerade ist die Spalte - Beziehungsweise die Zeile. - Zwei Geleichungen und zwei Unbekannte .... - */ + column_intersections_ref.push_back(coord2D); + } - /* - NEBENRECHNUNG : - linear connection between both points : + } - x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda - y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda + if (do_swap) + { - with lambda between zero and one representing the regarded structure segment + std::vector column_intersections_to_be_swaped; - equation raw : + for (int this_one = (column_intersections_ref.size() - 1) ; this_one >= 0 ; this_one--) + { - x = imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) - y = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) + column_intersections_to_be_swaped.push_back(column_intersections_ref.at(this_one)); - x_offset_raw gibt die rauemliche Verschiebung beim aendern des zeilen index an - raw_index repraesentiert den index der betrachteten Zeile also die y-Position innerhalb der Spalte + } - x_offset_raw = imageOrientationColumn.x*pixelSpacingColumn; - y_offset_raw = imageOrientationColumn.y*pixelSpacingColumn; + column_intersections_ref.swap(column_intersections_to_be_swaped); - unknown : lambda and the_index.x - the_index.x and raw_index represent the voxel - Solution : + } - First Equation: imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda - Second Equation: imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda + } + else + { + GoGetColumnIntersectionsAlongThisRaw(firstPoint , secondPoint , column_intersections_ref, + resolution_level); + } - Lambda from second equation: - ( imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) - firstPoint.y ) / ( secondPoint.y - firstPoint.y ) = lambda + } - First Equation: - ( imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) = lambda + } - First into Second Equation : - imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = - imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) ) + bool Mask::TestGoIntersectColumnByComparisonWithExpectedResult(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , + std::vector& column_intersections_ref, + std::vector& expected_intersections_ref) + { - First into Second Equation : - imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = (the_index.x-0.5) * ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) - First into SecondEquation : - (the_index.x-0.5) = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) / ( ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) ) + column_intersections_ref.clear(); - Der andere index ist raw_index und daher bereits bekannt. - Vorsicht, bevor ein Schnittpunkt als solcher akzeptiert werden kann muss untersucht werden - ob lambda zwischen null und eins liegt - da ansonsten Schnittpunkte der Segmentgeraden betrachtet werden, - die ausserhalb des eigentlichen Struktursegmentes liegen. + int resolution_level = 0; + GoIntersectColumn(firstPoint , secondPoint , column_intersections_ref, resolution_level); - */ + return IdenticalIntersectionsForTest(column_intersections_ref , expected_intersections_ref); + } - double x_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn(); - double y_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn(); - LegacyWorldCoordinate2D index_first_point; - index_first_point.x = 0; - index_first_point.y = 0; - LegacyWorldCoordinate2D index_second_point; - index_second_point.x = 0; - index_second_point.y = 0; + bool Mask::TestGoIntersectRawByComparisonWithExpectedResult(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, + std::vector& expected_intersections_ref) + { - // indicees der beiden uebergebenen Punkte bestimmen - index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); - index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); + raw_intersections_ref.clear(); - double index_diff = ( index_second_point.y - index_first_point.y ); + int resolution_level = 0; + GoIntersectRaw(firstPoint , secondPoint , raw_intersections_ref, resolution_level); + return IdenticalIntersectionsForTest(raw_intersections_ref , expected_intersections_ref); + } - int begin_ind = 0; - int end_ind = 0; - bool do_swap = 0; - if( index_diff > 0 ){ - begin_ind = static_cast( floor( index_first_point.y ) ); - end_ind = static_cast( floor( index_second_point.y ) + 1 ); - } - else if( index_diff < 0 ){ + bool Mask::IdenticalIntersectionsForTest(std::vector& + calculated_intersections_ref , std::vector& expected_intersections_ref) + { - do_swap = 1; - begin_ind = static_cast( floor( index_second_point.y ) ); - end_ind = static_cast( floor( index_first_point.y ) + 1 ); + if (calculated_intersections_ref.size() != expected_intersections_ref.size()) + { + std::cout << " Size Problem ! " << std::endl; + std::cout << " calculated_intersections_ref.size() : " << calculated_intersections_ref.size() + << std::endl; + std::cout << " expected_intersections_ref.size() : " << expected_intersections_ref.size() + << std::endl; - } - else{ + if (calculated_intersections_ref.size() < expected_intersections_ref.size()) + { + for (int counter = 0 ; counter < calculated_intersections_ref.size() ; counter++) + { + std::cout << " expected_intersections_ref.at( counter ).x : " << expected_intersections_ref.at( + counter).x << std::endl; + std::cout << " calculated_intersections_ref.at( counter ).x : " << calculated_intersections_ref.at( + counter).x << std::endl; + std::cout << " expected_intersections_ref.at( counter ).y : " << expected_intersections_ref.at( + counter).y << std::endl; + std::cout << " calculated_intersections_ref.at( counter ).y : " << + calculated_intersections_ref.at(counter).y << std::endl; + } + } + else + { + for (int counter = 0 ; counter < expected_intersections_ref.size() ; counter++) + { + std::cout << " expected_intersections_ref.at( counter ).x : " << expected_intersections_ref.at( + counter).x << std::endl; + std::cout << " calculated_intersections_ref.at( counter ).x : " << calculated_intersections_ref.at( + counter).x << std::endl; + std::cout << " expected_intersections_ref.at( counter ).y : " << expected_intersections_ref.at( + counter).y << std::endl; + std::cout << " calculated_intersections_ref.at( counter ).y : " << + calculated_intersections_ref.at(counter).y << std::endl; + } + } - begin_ind = 0; - end_ind = 0; + return false; + } - } + for (int counter = 0 ; counter < expected_intersections_ref.size() ; counter++) + { - if( begin_ind < 0 ) begin_ind = 0; - if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; + double diffa = ((expected_intersections_ref.at(counter).x - calculated_intersections_ref.at( + counter).x) * (expected_intersections_ref.at(counter).x - calculated_intersections_ref.at( + counter).x)); + double diffb = ((expected_intersections_ref.at(counter).y - calculated_intersections_ref.at( + counter).y) * (expected_intersections_ref.at(counter).y - calculated_intersections_ref.at( + counter).y)); - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; - LegacyWorldCoordinate3D the_index; - the_index.x = 0; - the_index.y = 0; - the_index.z = 0; + diffa = sqrt(diffa); + diffb = sqrt(diffb); - double multi_res_offset = GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); + if ((diffa > 0.001) || (diffb > 0.001)) + { - //std::cout <<"go intersection raw: "<= 0 ) && ( lambda <= 1 ) ){ - raw_intersections_ref.push_back( coord2D ); - //std::cout << coord2D.toString()<(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z) )}; - DoseVoxel voxel=DoseVoxel(index,GInf.at(resolution_level)); - std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); - this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(index, interPs));!!!Lanlan */ + } - /*std::cout << "intersections: "< vecW; - LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(end_ind-raw_index)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; - LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(end_ind-raw_index+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; - vecW.push_back(p1); - vecW.push_back(p2); - LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast( this->GetZIndex(firstPoint.z) )}; - this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW));*/ - } + void Mask::GoGetColumnIntersectionsAlongThisRaw(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , + std::vector& column_intersections_ref, int resolution_level) + { - } - if( do_swap ){ + LegacyWorldCoordinate2D index_first_point; + index_first_point.x = 0; + index_first_point.y = 0; + LegacyWorldCoordinate2D index_second_point; + index_second_point.x = 0; + index_second_point.y = 0; - std::vector raw_intersections_to_be_swaped; + if (firstPoint.y != secondPoint.y) + { + assert(0); + } - for( int this_one = ( raw_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ + // indicees der beiden uebergebenen Punkte bestimmen + index_first_point = GetDoubleIndex2D(firstPoint.x , firstPoint.y, resolution_level); + index_second_point = GetDoubleIndex2D(secondPoint.x , secondPoint.y, resolution_level); - raw_intersections_to_be_swaped.push_back( raw_intersections_ref.at( this_one ) ); + double index_diff = (index_second_point.x - index_first_point.x); - } + int begin_ind = 0; + int end_ind = 0; + bool do_swap = 0; - raw_intersections_ref.swap( raw_intersections_to_be_swaped ); + if (index_diff > 0) + { + begin_ind = static_cast(floor(index_first_point.x)); - } + if (floor(index_first_point.x) < index_first_point.x) + { + begin_ind += 1; + } - } - else{ - GoGetRawIntersectionsAlongThisColumn( firstPoint , secondPoint , raw_intersections_ref , resolution_level ); - } + end_ind = static_cast(floor(index_second_point.x)); + } + else if (index_diff < 0) + { - } - } + do_swap = 1; + begin_ind = static_cast(floor(index_second_point.x)); + if (floor(index_second_point.x) < index_second_point.x) + { + begin_ind += 1; + } + end_ind = static_cast(floor(index_first_point.x)); + } + else + { - void Mask::GoGetRawIntersectionsAlongThisColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, int resolution_level ){ + begin_ind = 0; + end_ind = 0; - LegacyWorldCoordinate2D index_first_point; - index_first_point.x = 0; - index_first_point.y = 0; - LegacyWorldCoordinate2D index_second_point; - index_second_point.x = 0; - index_second_point.y = 0; + } - if( firstPoint.x != secondPoint.x ) assert(0); + if (begin_ind < 0) + { + begin_ind = 0; + } - // indicees der beiden uebergebenen Punkte bestimmen - index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); - index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); + if (end_ind > (GInf.at(resolution_level).getNumRows() - 1)) + { + end_ind = GInf.at(resolution_level).getNumRows() - 1; + } - double index_diff = ( index_second_point.y - index_first_point.y ); + LegacyWorldCoordinate2D coord2D; + coord2D.x = 0; + coord2D.y = 0; - int begin_ind = 0; - int end_ind = 0; - bool do_swap = 0; + for (int column_index = begin_ind ; column_index <= end_ind ; column_index++) + { - if( index_diff > 0 ){ + coord2D.x = column_index; + coord2D.y = index_first_point.y; + column_intersections_ref.push_back(coord2D); - begin_ind = static_cast( floor( index_first_point.y ) ); - if( floor( index_first_point.y ) < index_first_point.y ) begin_ind += 1; - end_ind = static_cast( floor( index_second_point.y ) ); + } - } - else if( index_diff < 0 ){ + if (do_swap) + { - do_swap = 1; - begin_ind = static_cast( floor( index_second_point.y ) ); - if( floor( index_second_point.y ) < index_second_point.y ) begin_ind += 1; - end_ind = static_cast( floor( index_first_point.y ) ); + std::vector column_intersections_to_be_swaped; - } - else{ + for (int this_one = (column_intersections_ref.size() - 1) ; this_one >= 0 ; this_one--) + { - begin_ind = 0; - end_ind = 0; + column_intersections_to_be_swaped.push_back(column_intersections_ref.at(this_one)); - } + } - if( begin_ind < 0 ) begin_ind = 0; - if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; + column_intersections_ref.swap(column_intersections_to_be_swaped); - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; + } - //std::cout <<"go intersection raw along column: "< vecW; - //LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(raw_index-begin_ind)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; - //LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(raw_index-begin_ind+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; - //vecW.push_back(p1); - //vecW.push_back(p2); - //LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z))}; - //this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW)); - //core::LegacyDoseVoxelIndex3D index={static_cast(coord2D.x),static_cast(coord2D.y),0}; - /*DoseVoxel voxel=DoseVoxel(dosevoxel,GInf.at(resolution_level)); - std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); - this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, interPs));*/ + void Mask::ShowIntersections() + { - /*std::cout << "intersections: "< raw_intersections_to_be_swaped; + for (unsigned int resolution_level = 0 ; resolution_level < Intersections.size() ; + resolution_level++) + { - for( int this_one = ( raw_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ + std::cout << " resolution_level : " << resolution_level << std::endl; - raw_intersections_to_be_swaped.push_back( raw_intersections_ref.at( this_one ) ); + for (unsigned int struct_index = 0 ; struct_index < Intersections.at(resolution_level).size() ; + struct_index++) + { - } + std::cout << " struct_index : " << struct_index << std::endl; - raw_intersections_ref.swap( raw_intersections_to_be_swaped ); + for (unsigned int point_index = 0 ; + point_index < (Intersections.at(resolution_level).at(struct_index).size()); point_index++) + { + std::cout << " point_index : " << point_index << std::endl; - } - + for (unsigned int intersect_index = 0 ; + intersect_index < Intersections.at(resolution_level).at(struct_index).at( + point_index).intersections_raw_and_column.size() ; intersect_index++) + { - } + std::cout << " intersect_index : " << intersect_index << std::endl; + coord2D = Intersections.at(resolution_level).at(struct_index).at( + point_index).intersections_raw_and_column.at(intersect_index); + std::cout << " x : " << coord2D.x << std::endl; - void Mask::GoIntersectColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ){ - if( ( secondPoint.x - firstPoint.x ) != 0 ){ - if( ( secondPoint.y - firstPoint.y ) != 0 ){ + std::cout << " y : " << coord2D.y << std::endl; - /* - Siehe GoIntersectRaw (ist eigentlich das selbe) - Auf der einen Gerade liegt das Strutkur Segment und die andere Gerade ist die Spalte - Beziehungsweise die Zeile. - Zwei Geleichungen und zwei Unbekannte .... - */ - /* - NEBENRECHNUNG : - linear connection between the two points : + } - x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda - y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda + } - with lambda between zero and one representing the regarded structure segment + } - equation column : + } - x_offset_column gibt die rauemliche Verschiebung beim aendern des spalten index an - column_index repraesentiert den index der betrachteten Spalte also die x Position innerhalb der Zeile + //assert(0); - x = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y - y = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y + } - x_offset_column = imageOrientationRow.x * pixelSpacingRow; - y_offset_column = imageOrientationRow.y * pixelSpacingRow; - Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y - Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y + void Mask::MarkVoxelsTouchedByStructure(int resolution_level) + { - Erste Gleuchung aufloesen nach lambda : - Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - Lambda in zweite Gleichung einsetzen : - firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index = imageOrientationColumn.y * pixelSpacingColumn * the_index.y - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y ) = the_index.y * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) - Lambda in zweite Gleichung einsetzen : - the_index.y = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) + // In allen Slices die dem aktuellen Polygon zugeordnet sind muessen die zu den + // Schnittpunkten der Contour gehoerigen Voxel gesetzt werden. + // (siehe SliceStructureCorrespondency bzw. correspoinding_structure_vector unter correspoinding_structure ) + // Es muessen alle eintraege von SliceStructureCorrespondency durchsucht werden um festzustellen, + // ob es sich um ein slice des dose cubes handelt, das diesem Strukturelement zugeordnet ist. + // Dabei muss beachtet werden, dass eine Structurelement fuer mehrere verschiedene Slices + // das zugehoerige sein kann. - */ + LegacyWorldCoordinate2D coord2D; + coord2D.x = 0; + coord2D.y = 0; - /* - - Nach Koordinatentransformation nochmal ueberlegt: - + //if( resolution_level == 0 ) ShowIntersections(); - Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) - Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) + std::vector wich_slice; - Erste Gleuchung aufloesen nach lambda : - Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - Lambda in zweite Gleichung einsetzen : - firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) = imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y - 0.5 ) = ( the_index.y - 0.5 ) * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) - Lambda in zweite Gleichung einsetzen : - ( the_index.y - 0.5 ) = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) + for (unsigned int struct_index = 0 ; struct_index < Intersections.at(resolution_level).size() ; + struct_index++) + { - - - */ + correspoinding_structure_vector str_v; + wich_slice.clear(); + // die entsprechenden slices des dose cubes finden, die zu dieser Struktur gehoeren und die Voxel des MaskField belegen + for (unsigned int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++) + { - double x_offset_column = GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow(); - double y_offset_column = GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow(); + str_v = SliceStructureCorrespondency.at(index_z); - LegacyWorldCoordinate2D index_first_point; - index_first_point.x = 0; - index_first_point.y = 0; - LegacyWorldCoordinate2D index_second_point; - index_second_point.x = 0; - index_second_point.y = 0; + for (unsigned int count = 0 ; count < str_v.size() ; count++) + { + if (str_v.at(count) == struct_index) + { + wich_slice.push_back(index_z); + } - // indicees der beiden uebergebenen Punkte bestimmen - index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); - index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); + } - double index_diff = ( index_second_point.x - index_first_point.x ); + } - int begin_ind = 0; - int end_ind = 0; - bool do_swap = 0; + // iteration polygon + for (unsigned int point_index = 0 ; + point_index < (Intersections.at(resolution_level).at(struct_index).size()); point_index++) + { - if( index_diff > 0 ){ - begin_ind = static_cast( floor( index_first_point.x ) ); - end_ind = static_cast( floor( index_second_point.x ) + 1 ); + for (unsigned int intersect_index = 0 ; + intersect_index < Intersections.at(resolution_level).at(struct_index).at( + point_index).intersections_raw_and_column.size() ; intersect_index++) + { - } - else if( index_diff < 0 ){ + coord2D = Intersections.at(resolution_level).at(struct_index).at( + point_index).intersections_raw_and_column.at(intersect_index); - do_swap = 1; - begin_ind = static_cast( floor( index_second_point.x ) ); - end_ind = static_cast( floor( index_first_point.x ) + 1 ); - } - else{ + if ((coord2D.x >= 0) && (coord2D.y >= 0) && (coord2D.x < MaskField.at(resolution_level)->GetDimX()) + && (coord2D.y < MaskField.at(resolution_level)->GetDimY())) + { - begin_ind = 0; - end_ind = 0; - } + unsigned int index_x = static_cast(floor(coord2D.x)); + unsigned int index_y = static_cast(floor(coord2D.y)); - if( begin_ind < 0 ) begin_ind = 0; - if( end_ind > ( GInf.at(resolution_level).getNumColumns() - 1 ) ) end_ind = GInf.at(resolution_level).getNumColumns() - 1; + for (unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++) + { - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; - LegacyWorldCoordinate3D the_index; - the_index.x = 0; - the_index.y = 0; - the_index.z = 0; + unsigned int index_z = wich_slice.at(this_counter); + MaskField.at(resolution_level)->PutData(index_x , index_y , index_z , brightness_border); - double multi_res_offset = GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); + if ((floor(coord2D.x) == coord2D.x) && (index_x > 0)) + { - for( int column_index = begin_ind ; column_index <= end_ind ; column_index++ ){ + MaskField.at(resolution_level)->PutData((index_x - 1) , index_y , index_z , brightness_border); - //ganz alt - //the_index.y = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * column_index ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; - //alt - //the_index.y = 0.5 + ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * ( column_index - 0.5 ) ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; + } - //neu multi res - the_index.y = multi_res_offset + ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - multi_res_offset ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * ( column_index - multi_res_offset ) ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; - + if ((floor(coord2D.y) == coord2D.y) && (index_y > 0)) + { - coord2D.y = the_index.y; - coord2D.x = column_index; - - //alt - //double lambda = ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - 0.5 ) + GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); + MaskField.at(resolution_level)->PutData(index_x , (index_y - 1) , index_z , brightness_border); - //neu multi resolution - double lambda = ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - multi_res_offset ) + GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() * ( the_index.y - multi_res_offset ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); - - if( ( lambda >= 0 ) && ( lambda <= 1 ) ){ + } - column_intersections_ref.push_back( coord2D ); + if ((floor(coord2D.x) == coord2D.x) && (floor(coord2D.y) == coord2D.y) && (index_y > 0) + && (index_x > 0)) + { - } + MaskField.at(resolution_level)->PutData((index_x - 1) , (index_y - 1) , index_z , + brightness_border); + } - } - if( do_swap ){ + } - std::vector column_intersections_to_be_swaped; - for( int this_one = ( column_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ + } - column_intersections_to_be_swaped.push_back( column_intersections_ref.at( this_one ) ); + } - } + for (unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++) + { - column_intersections_ref.swap( column_intersections_to_be_swaped ); + unsigned int index_z = wich_slice.at(this_counter); + // Das Siemens Planunssystem schreibt aus ungeklaertem Gruend Daten raus, deren Voxelkoordinaten ausserhalb des Bildes zu liegen kommen. Eigentlich macht das keinen Sinn. Wir wissen, dass unsere Toolbox Welt-Voxel-Koordinaten Umrechnung DICOM conform ist. + int intx = floor(Intersections.at(resolution_level).at(struct_index).at( + point_index).contour_point_voxel_coord.x); + int inty = floor(Intersections.at(resolution_level).at(struct_index).at( + point_index).contour_point_voxel_coord.y); - } + if ((intx >= 0) && (inty >= 0) && (intx < MaskField.at(resolution_level)->GetDimX()) + && (inty < MaskField.at(resolution_level)->GetDimY())) + { - } - else{ - GoGetColumnIntersectionsAlongThisRaw( firstPoint , secondPoint , column_intersections_ref, resolution_level ); - } + Uint16 uintx = static_cast(intx); + Uint16 uinty = static_cast(inty); + MaskField.at(resolution_level)->PutData(uintx , uinty , index_z , brightness_border); - } + } + } - } + } // point index + } - bool Mask::TestGoIntersectColumnByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, std::vector& expected_intersections_ref ){ - column_intersections_ref.clear(); + } - int resolution_level = 0; - GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); - return IdenticalIntersectionsForTest( column_intersections_ref , expected_intersections_ref ); - } - bool Mask::TestGoIntersectRawByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, std::vector& expected_intersections_ref ){ + // like MarkVoxelsTouchedByStructure + void Mask::GetIntersectionInformationThisSlice(unsigned int index_z) + { - raw_intersections_ref.clear(); + // In allen Slices die dem aktuellen Polygon zugeordnet sind muessen die zu den + // Schnittpunkten der Contour gehoerigen Voxel gesetzt werden. + // (siehe SliceStructureCorrespondency bzw. correspoinding_structure_vector unter correspoinding_structure ) + // Es muessen alle eintraege von SliceStructureCorrespondency durchsucht werden um festzustellen, + // ob es sich um ein slice des dose cubes handelt, das diesem Strukturelement zugeordnet ist. + // Dabei muss beachtet werden, dass eine Structurelement fuer mehrere verschiedene Slices + // das zugehoerige sein kann. - int resolution_level = 0; - GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); + LegacyWorldCoordinate2D coord2D; + coord2D.x = 0; + coord2D.y = 0; - return IdenticalIntersectionsForTest( raw_intersections_ref , expected_intersections_ref ); + correspoinding_structure_vector str_v; + str_v = SliceStructureCorrespondency.at(index_z); - } + int resolution_level = 0; + for (unsigned int count = 0 ; count < str_v.size() ; count++) + { + unsigned int struct_index = str_v.at(count); + // iteration polygon + for (unsigned int point_index = 0 ; + point_index < (Intersections.at(resolution_level).at(struct_index).size()); point_index++) + { - bool Mask::IdenticalIntersectionsForTest( std::vector& calculated_intersections_ref , std::vector& expected_intersections_ref ){ - if( calculated_intersections_ref.size() != expected_intersections_ref.size() ){ - std::cout<< " Size Problem ! " <= 0) && (coord2D.y >= 0) && (coord2D.x < MaskField.at(resolution_level)->GetDimX()) + && (coord2D.y < MaskField.at(resolution_level)->GetDimY())) + { - if( ( diffa > 0.001 ) || ( diffb > 0.001 ) ) { - std::cout<< " Unexpectd coordinate ! " <(floor(coord2D.x)); + unsigned int index_y = static_cast(floor(coord2D.y)); - } - return true; + //MaskField.at( resolution_level )->PutData( index_x , index_y , index_z , brightness_border ); - } + if (FieldOfIntersections) + { + if (floor(coord2D.y) == coord2D.y) + { + unsigned int voxel_side = 0; + AddToFieldOfIntersections(index_x , index_y , 0 , struct_index , point_index , intersect_index , + coord2D, voxel_side); + } + else if (floor(coord2D.x) == coord2D.x) + { + unsigned int voxel_side = 3; + AddToFieldOfIntersections(index_x , index_y , 0 , struct_index , point_index , intersect_index , + coord2D, voxel_side); + } + } + if ((floor(coord2D.x) == coord2D.x) && (index_x > 0)) + { - void Mask::GoGetColumnIntersectionsAlongThisRaw( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ){ + //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , index_y , index_z , brightness_border ); - LegacyWorldCoordinate2D index_first_point; - index_first_point.x = 0; - index_first_point.y = 0; - LegacyWorldCoordinate2D index_second_point; - index_second_point.x = 0; - index_second_point.y = 0; - - if( firstPoint.y != secondPoint.y ) assert(0); + if (FieldOfIntersections) // Ecke wird gegebenenfalls mit angehaengt + { + unsigned int voxel_side = 1; - // indicees der beiden uebergebenen Punkte bestimmen - index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); - index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); - double index_diff = ( index_second_point.x - index_first_point.x ); + AddToFieldOfIntersections((index_x - 1) , index_y , 0 , struct_index , point_index , + intersect_index , coord2D, voxel_side); + } - int begin_ind = 0; - int end_ind = 0; - bool do_swap = 0; + } - if( index_diff > 0 ){ + if ((floor(coord2D.y) == coord2D.y) && (index_y > 0)) + { - begin_ind = static_cast( floor( index_first_point.x ) ); - if( floor( index_first_point.x ) < index_first_point.x ) begin_ind += 1; - end_ind = static_cast( floor( index_second_point.x ) ); - } - else if( index_diff < 0 ){ + //MaskField.at( resolution_level )->PutData( index_x , ( index_y - 1 ) , index_z , brightness_border ); - do_swap = 1; - begin_ind = static_cast( floor( index_second_point.x ) ); - if( floor( index_second_point.x ) < index_second_point.x ) begin_ind += 1; - end_ind = static_cast( floor( index_first_point.x ) ); + if (FieldOfIntersections) + { - } - else{ + if (floor(coord2D.x) == + coord2D.x) // Ecke wird gegebenenfalls nicht mit angehaengt, deshalb Fallunterscheidunn noetig, damit sie angehaengt wird ( Ecke wird nur an die Kante angehaengt an deren Anfang sie steht) + { + unsigned int voxel_side = 3; + AddToFieldOfIntersections(index_x , (index_y - 1) , 0 , struct_index , point_index , + intersect_index , coord2D, voxel_side); + } + else + { + unsigned int voxel_side = 2; + AddToFieldOfIntersections(index_x , (index_y - 1) , 0 , struct_index , point_index , + intersect_index , coord2D, voxel_side); + } - begin_ind = 0; - end_ind = 0; + } - } + } - if( begin_ind < 0 ) begin_ind = 0; - if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; + if ((floor(coord2D.x) == coord2D.x) && (floor(coord2D.y) == coord2D.y) && (index_y > 0) + && (index_x > 0)) + { - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; - for( int column_index = begin_ind ; column_index <= end_ind ; column_index++ ){ + //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , ( index_y - 1 ) , index_z , brightness_border ); - coord2D.x = column_index; - coord2D.y = index_first_point.y; - column_intersections_ref.push_back( coord2D ); + if (FieldOfIntersections) + { + unsigned int voxel_side = 2; - } - if( do_swap ){ + AddToFieldOfIntersections((index_x - 1) , (index_y - 1) , 0 , struct_index , point_index , + intersect_index , coord2D, voxel_side); + } - std::vector column_intersections_to_be_swaped; + } - for( int this_one = ( column_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ - column_intersections_to_be_swaped.push_back( column_intersections_ref.at( this_one ) ); + } - } + } - column_intersections_ref.swap( column_intersections_to_be_swaped ); - } - - } + } + } + } - void Mask::ShowIntersections(){ - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; - - for( unsigned int resolution_level = 0 ; resolution_level < Intersections.size() ; resolution_level++ ){ - - std::cout<< " resolution_level : " << resolution_level <GetData(index_x , index_y, index_z)->at(which_one)); + } + else + { + ExtendFieldOfIntersections(index_x , index_y , 0 , struct_index); - } - - } - - } - - } + int which_one = GetRespectiveIntersections(index_x , index_y , 0 , struct_index); - //assert(0); - - } + if (which_one == (-1)) + { + assert(0); + } - void Mask::MarkVoxelsTouchedByStructure( int resolution_level ){ + SetThisIntersectionToCornerOrEdge(index_x , index_y , which_intersection , coord2D , voxel_side, + FieldOfIntersections->GetData(index_x , index_y, index_z)->at(which_one)); - // In allen Slices die dem aktuellen Polygon zugeordnet sind muessen die zu den - // Schnittpunkten der Contour gehoerigen Voxel gesetzt werden. - // (siehe SliceStructureCorrespondency bzw. correspoinding_structure_vector unter correspoinding_structure ) - // Es muessen alle eintraege von SliceStructureCorrespondency durchsucht werden um festzustellen, - // ob es sich um ein slice des dose cubes handelt, das diesem Strukturelement zugeordnet ist. - // Dabei muss beachtet werden, dass eine Structurelement fuer mehrere verschiedene Slices - // das zugehoerige sein kann. - - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; - //if( resolution_level == 0 ) ShowIntersections(); - std::vector wich_slice; + } - for(unsigned int struct_index = 0 ; struct_index < Intersections.at(resolution_level).size() ; struct_index++ ){ + } - correspoinding_structure_vector str_v; - wich_slice.clear(); - // die entsprechenden slices des dose cubes finden, die zu dieser Struktur gehoeren und die Voxel des MaskField belegen - for(unsigned int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ + } - str_v = SliceStructureCorrespondency.at( index_z ); - for(unsigned int count = 0 ; count < str_v.size() ; count++ ){ - if( str_v.at( count ) == struct_index )wich_slice.push_back( index_z ); - - } - } - // iteration polygon - for(unsigned int point_index = 0 ; point_index < ( Intersections.at(resolution_level).at( struct_index ).size() ); point_index++ ){ + bool Mask::IsItToBeRegarded(unsigned int struct_index , unsigned int point_index , + unsigned int intersect_index , int index_x , int index_y) + { + // Muss betrachtet werden, falls der Konturpunkt sich in x oder durch y vom Schnittpunkt der zusaetzlich durch den intersect_index gegeben ist unterscheidet. + // Falls Schnittpunkt mit der Kante, der zusaetzlich durch intersect_index gegeben ist und der Konturpunkt nicht in x oder y unterscheiden, + // wird der vorherige Konturpunkt betrachtet. Und zwar der erste, der sich von dem intialen tatsaechlich unterscheidet. + // Wenn dieser Punkt in einer Richtung z.B. x auf der selben Kante liegt, sich aber in y Richtung unterscheidet, oder andersherum, + // dann muss der Schnittpunkt betrachtet werden, obwohl er mit einem Konturpunkt zusammenfaellt, weil der vorhergehende Konturpunkt auf der gleichen Kante liegt (eventuell in anderem Voxel, aber auf der selben Kante) - for(unsigned int intersect_index = 0 ; intersect_index < Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.size() ; intersect_index++ ){ + // Es ist nicht noetig die Selbe Stelle der Kante zweimal zu betrachten. Diese Stelle hier wird vom vorhergehenden Konturpunkt ausgehend als Schnittpunkt erkannt werden und wird deshalb hier nicht beruecksichtigt + if ((Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y != + Intersections.at(0).at(struct_index).at(point_index).intersections_raw_and_column.at( + intersect_index).y) || + (Intersections.at(0).at(struct_index).at(point_index).intersections_raw_and_column.at( + intersect_index).x != Intersections.at(0).at(struct_index).at( + point_index).contour_point_voxel_coord.x)) + { + return true; + } + else + { - coord2D = Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ); - - if( ( coord2D.x >= 0 ) && ( coord2D.y >= 0 ) && ( coord2D.x < MaskField.at( resolution_level )->GetDimX() ) && ( coord2D.y < MaskField.at( resolution_level )->GetDimY() ) ){ - - unsigned int index_x = static_cast( floor( coord2D.x ) ); - unsigned int index_y = static_cast( floor( coord2D.y ) ); + unsigned int struct_index_other = struct_index; + unsigned int point_index_other = point_index; + unsigned int intersect_index_other = intersect_index; - for(unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++ ){ + if (GetFirstDifferent(struct_index_other , point_index_other , + Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord)) + { - unsigned int index_z = wich_slice.at( this_counter ); - - MaskField.at( resolution_level )->PutData( index_x , index_y , index_z , brightness_border ); - - if( ( floor( coord2D.x ) == coord2D.x ) && ( index_x > 0 ) ){ - MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , index_y , index_z , brightness_border ); - - } - if( ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) ){ - - MaskField.at( resolution_level )->PutData( index_x , ( index_y - 1 ) , index_z , brightness_border ); - } - if( ( floor( coord2D.x ) == coord2D.x ) && ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) && ( index_x > 0 ) ){ + if ((floor(Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y / 1.0) + != Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y) + && (floor(Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x / 1.0) == + Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x)) + { - MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , ( index_y - 1 ) , index_z , brightness_border ); - - } + if (Intersections.at(0).at(struct_index_other).at(point_index_other).contour_point_voxel_coord.x == + Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x) + { + return true; + } + } + else if ((floor(Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y / + 1) == Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y) + && (floor(Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x / 1) != + Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x)) + { - } - + if (Intersections.at(0).at(struct_index_other).at(point_index_other).contour_point_voxel_coord.y == + Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y) + { + return true; + } - } + } - } - for(unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++ ){ + } + else + { + assert(0); + } - unsigned int index_z = wich_slice.at( this_counter ); - // Das Siemens Planunssystem schreibt aus ungeklaertem Gruend Daten raus, deren Voxelkoordinaten ausserhalb des Bildes zu liegen kommen. Eigentlich macht das keinen Sinn. Wir wissen, dass unsere Toolbox Welt-Voxel-Koordinaten Umrechnung DICOM conform ist. - int intx = floor( Intersections.at(resolution_level).at(struct_index).at( point_index ).contour_point_voxel_coord.x ); - int inty = floor( Intersections.at(resolution_level).at(struct_index).at( point_index ).contour_point_voxel_coord.y ); + } - - if( ( intx >= 0 ) && ( inty >= 0 ) && ( intx < MaskField.at( resolution_level )->GetDimX() ) && ( inty < MaskField.at( resolution_level )->GetDimY() ) ){ + return false; - Uint16 uintx = static_cast(intx); - Uint16 uinty = static_cast(inty); - MaskField.at( resolution_level )->PutData( uintx , uinty , index_z , brightness_border ); + } - } - } + bool Mask::GetFirstDifferent(unsigned int& struct_index , unsigned int& point_index , + LegacyWorldCoordinate3D compare_point) + { - } // point index + if (Intersections.at(0).at(struct_index).size() <= 1) + { + std::cerr << " Doesn't make sense to voxelize contour with less than two points ! " << + std::endl; + assert(0); // this should never happen. Doesn't make sense to voxelize contour with less than two points ! + } - } - - - } + bool docontinue = true; + int counter = 0; + while (docontinue) + { + if ((Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.x != + compare_point.x) + || (Intersections.at(0).at(struct_index).at(point_index).contour_point_voxel_coord.y != + compare_point.y)) + { + return true; + } + if (point_index > 0) + { + point_index--; + } + else + { + point_index = (Intersections.at(0).at(struct_index).size() - 1); + } + counter++; - // like MarkVoxelsTouchedByStructure - void Mask::GetIntersectionInformationThisSlice( unsigned int index_z ){ + if (counter > (Intersections.at(0).at(struct_index).size() * 2)) + { + break; + } - // In allen Slices die dem aktuellen Polygon zugeordnet sind muessen die zu den - // Schnittpunkten der Contour gehoerigen Voxel gesetzt werden. - // (siehe SliceStructureCorrespondency bzw. correspoinding_structure_vector unter correspoinding_structure ) - // Es muessen alle eintraege von SliceStructureCorrespondency durchsucht werden um festzustellen, - // ob es sich um ein slice des dose cubes handelt, das diesem Strukturelement zugeordnet ist. - // Dabei muss beachtet werden, dass eine Structurelement fuer mehrere verschiedene Slices - // das zugehoerige sein kann. + } - LegacyWorldCoordinate2D coord2D; - coord2D.x = 0; - coord2D.y = 0; + return false; - correspoinding_structure_vector str_v; - str_v = SliceStructureCorrespondency.at( index_z ); - - int resolution_level = 0; - - for(unsigned int count = 0 ; count < str_v.size() ; count++ ){ + } - unsigned int struct_index = str_v.at( count ); - // iteration polygon - for(unsigned int point_index = 0 ; point_index < ( Intersections.at(resolution_level).at( struct_index ).size() ); point_index++ ){ + void Mask::ExtendFieldOfIntersections(unsigned int index_x , unsigned int index_y , + unsigned int index_z , unsigned int struct_index) + { + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - for(unsigned int intersect_index = 0 ; intersect_index < Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.size() ; intersect_index++ ){ + LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); - coord2D = Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ); + PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( + struct_index); + LegacyDoseVoxelIndex3D aDoseIndex; + aDoseIndex.x = index_x; + aDoseIndex.y = index_y; + aDoseIndex.z = index_z; - if( ( coord2D.x >= 0 ) && ( coord2D.y >= 0 ) && ( coord2D.x < MaskField.at( resolution_level )->GetDimX() ) && ( coord2D.y < MaskField.at( resolution_level )->GetDimY() ) ){ + //PolygonInfo polInf = PolygonInfo( the_polygon_ref , struct_index , brightness_outside , brightness_inside , MaskField.at( resolution_level ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(resolution_level) ); - - unsigned int index_x = static_cast( floor( coord2D.x ) ); - unsigned int index_y = static_cast( floor( coord2D.y ) ); + VoxelIntersectionsVectorPointer pol_inf_pointer = new std::vector(); + FieldOfIntersections->PutData(index_x, index_y, index_z , pol_inf_pointer); - - //MaskField.at( resolution_level )->PutData( index_x , index_y , index_z , brightness_border ); - - if( FieldOfIntersections ){ - - if( floor( coord2D.y ) == coord2D.y ){ - unsigned int voxel_side = 0; - AddToFieldOfIntersections( index_x , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - else if( floor( coord2D.x ) == coord2D.x ){ - unsigned int voxel_side = 3; - AddToFieldOfIntersections( index_x , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - - } - - if( ( floor( coord2D.x ) == coord2D.x ) && ( index_x > 0 ) ){ + IntersectionsThisVoxel intersection_info; + intersection_info.SetPolygonNumber(struct_index); - //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , index_y , index_z , brightness_border ); - - if( FieldOfIntersections ){ // Ecke wird gegebenenfalls mit angehaengt - unsigned int voxel_side = 1; - - - AddToFieldOfIntersections( ( index_x - 1 ) , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - - } - if( ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) ){ + FieldOfIntersections->GetData(index_x , index_y, index_z)->push_back(intersection_info); - //MaskField.at( resolution_level )->PutData( index_x , ( index_y - 1 ) , index_z , brightness_border ); + } - if( FieldOfIntersections ){ - - if( floor( coord2D.x ) == coord2D.x ){ // Ecke wird gegebenenfalls nicht mit angehaengt, deshalb Fallunterscheidunn noetig, damit sie angehaengt wird ( Ecke wird nur an die Kante angehaengt an deren Anfang sie steht) - unsigned int voxel_side = 3; - AddToFieldOfIntersections( index_x , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - else{ - unsigned int voxel_side = 2; - AddToFieldOfIntersections( index_x , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - - } - } - if( ( floor( coord2D.x ) == coord2D.x ) && ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) && ( index_x > 0 ) ){ + int Mask::GetRespectiveIntersections(unsigned int index_x , unsigned int index_y , + unsigned int index_z , unsigned int struct_index) const + { - //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , ( index_y - 1 ) , index_z , brightness_border ); - if( FieldOfIntersections ){ - unsigned int voxel_side = 2; + if (FieldOfIntersections->GetData(index_x , index_y, index_z) != NULL) + { - AddToFieldOfIntersections( ( index_x - 1 ) , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); - } - - } + for (int i = 0 ; i < FieldOfIntersections->GetData(index_x , index_y, index_z)->size() ; i++) + { + if (FieldOfIntersections->GetData(index_x , index_y, + index_z)->at(i).GetPolygonNumber() == struct_index) + { + return i; + } + } + return (-1); - } + } + else + { + return (-1); + } - } + } + LegacyWorldCoordinate2D Mask::GetDoubleIndex2D(double x , double y, int resolution_level) + { - } + LegacyWorldCoordinate2D result; - } + // zunaechst + // x_world = imageOrientationRow.x*pixelSpacingRow*the_index.x+imageOrientationColumn.x*pixelSpacingColumn*the_index.y+imagePosition.x; + // y_world = imageOrientationRow.y*pixelSpacingRow*the_index.x+imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; + // mit x_world y_world ( Welt Koordinaten alles andere dcmtkrt Ausdruecke ) - } + // daraus folgt + // Gleichung a : ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.x ; + // Gleichung b : y_world = imageOrientationRow.y*pixelSpacingRow* ( ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; + // Gleichung b weiter aufgeloest nach the_index.y + // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn*the_index.y )/ ( imageOrientationRow.x*pixelSpacingRow ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y + // Gelichung b weiter umgeformt : + // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.y * ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) + // es ergibt sich + // aus Gleichung b : the_index.y = a / b + // wobei a = y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) + // und b = ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) + // Folglich erbibt sich aus Gleichung a : + // the_index.x = ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn* ( a / b ) ) ) / ( imageOrientationRow.x*pixelSpacingRow ) + // Uebersichtlicher : + // the_index.x = ( c - ( d * ( a / b ) ) ) / e + // c = ( x_world - imagePosition.x ) + // d = imageOrientationColumn.x*pixelSpacingColumn + // e = ( imageOrientationRow.x*pixelSpacingRow ) - void Mask::AddToFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , LegacyWorldCoordinate2D coord2D, unsigned int voxel_side ){ + // in anderen Worten : - int which_one = GetRespectiveIntersections( index_x , index_y , 0 , struct_index ); + double a = y - GInf.at(resolution_level).getImagePositionPatient()(1) - GInf.at( + resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow() * + (x - GInf.at(resolution_level).getImagePositionPatient()(0)) / (GInf.at( + resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow()) ; + double b = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at( + resolution_level).getPixelSpacingColumn() - GInf.at(resolution_level).getImageOrientationRow()( + 1) * GInf.at(resolution_level).getPixelSpacingRow() * (GInf.at( + resolution_level).getImageOrientationColumn()(0) * GInf.at( + resolution_level).getPixelSpacingColumn()) / (GInf.at(resolution_level).getImageOrientationRow()( + 0) * GInf.at(resolution_level).getPixelSpacingRow()) ; + double c = (x - GInf.at(resolution_level).getImagePositionPatient()(0)) ; + double d = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at( + resolution_level).getPixelSpacingColumn(); + double e = (GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at( + resolution_level).getPixelSpacingRow()); - IterativePolygonInTermsOfIntersections::WhichIntersection which_intersection; - which_intersection.point_index = point_index; - which_intersection.intersection_index = intersect_index; - which_intersection.column_raw_or_unified = 2; - - bool go = IsItToBeRegarded( struct_index , point_index , intersect_index, index_x , index_y ); + //alt + // folglich ergeben sich die voxel Koordinaten zu + //result.x = ( ( c - ( d * ( a / b ) ) ) / e ) ; + //result.y = ( a / b ) ; - if( go ){ - + // neu + // folglich ergeben sich die voxel Koordinaten zu - if( which_one != (-1) ){ - - SetThisIntersectionToCornerOrEdge( index_x , index_y , which_intersection , coord2D , voxel_side, FieldOfIntersections->GetData( index_x , index_y, index_z )->at(which_one) ); - - } - else{ + // Hier muss das resolution level beruecksichtigt werden. Aenderung vornehmen. Auch testen ! - ExtendFieldOfIntersections( index_x , index_y , 0 , struct_index ); + // result.x = ( ( c - ( d * ( a / b ) ) ) / e ) + 0.5; + // result.y = ( a / b ) + 0.5; - int which_one = GetRespectiveIntersections( index_x , index_y , 0 , struct_index ); + result.x = ((c - (d * (a / b))) / e) + GetWorldCoordinateOffsetThisResolutionLevel( + resolution_level); + result.y = (a / b) + GetWorldCoordinateOffsetThisResolutionLevel(resolution_level); - if( which_one == (-1) )assert( 0 ); - - - - SetThisIntersectionToCornerOrEdge( index_x , index_y , which_intersection , coord2D , voxel_side, FieldOfIntersections->GetData( index_x , index_y, index_z )->at(which_one) ); + return result; + } - } - - } + LegacyWorldCoordinate2D Mask::GetDoubleIndex2D(double x , double y) + { + return GetDoubleIndex2D(x , y, 0); - } + } + double Mask::GetWorldCoordinateOffsetThisResolutionLevel(int resolution_level) + { - bool Mask::IsItToBeRegarded( unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , int index_x , int index_y ){ - // Muss betrachtet werden, falls der Konturpunkt sich in x oder durch y vom Schnittpunkt der zusaetzlich durch den intersect_index gegeben ist unterscheidet. - // Falls Schnittpunkt mit der Kante, der zusaetzlich durch intersect_index gegeben ist und der Konturpunkt nicht in x oder y unterscheiden, - // wird der vorherige Konturpunkt betrachtet. Und zwar der erste, der sich von dem intialen tatsaechlich unterscheidet. - // Wenn dieser Punkt in einer Richtung z.B. x auf der selben Kante liegt, sich aber in y Richtung unterscheidet, oder andersherum, - // dann muss der Schnittpunkt betrachtet werden, obwohl er mit einem Konturpunkt zusammenfaellt, weil der vorhergehende Konturpunkt auf der gleichen Kante liegt (eventuell in anderem Voxel, aber auf der selben Kante) + double world_coord_offset = 1; + for (int i = 1 ; i <= resolution_level ; i++) + { + world_coord_offset *= 2; + } - // Es ist nicht noetig die Selbe Stelle der Kante zweimal zu betrachten. Diese Stelle hier wird vom vorhergehenden Konturpunkt ausgehend als Schnittpunkt erkannt werden und wird deshalb hier nicht beruecksichtigt - if( ( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y != Intersections.at(0).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ).y ) || - ( Intersections.at(0).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ).x != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) )return true; - else{ + world_coord_offset = (0.5 / world_coord_offset); + return world_coord_offset; - unsigned int struct_index_other = struct_index; - unsigned int point_index_other = point_index; - unsigned int intersect_index_other = intersect_index; + } - if( GetFirstDifferent( struct_index_other , point_index_other , Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord ) ){ - - - - if( ( floor(Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y / 1.0 ) != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ) && ( floor(Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x / 1.0 ) == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) ){ - - if( Intersections.at(0).at(struct_index_other).at( point_index_other ).contour_point_voxel_coord.x == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ){ - return true; - } - - } - else if( ( floor( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y / 1 ) == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ) && ( floor( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x / 1 ) != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) ){ - - if( Intersections.at(0).at(struct_index_other).at( point_index_other ).contour_point_voxel_coord.y == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ){ - return true; - } - - } - - - } - else assert( 0 ); - - } - - return false; - + double Mask::GetBlockLengthThisResolutionLevel(int resolution_level) + { - } - - - bool Mask::GetFirstDifferent( unsigned int& struct_index , unsigned int& point_index , LegacyWorldCoordinate3D compare_point ){ - - if( Intersections.at(0).at(struct_index).size() <= 1 ){ - std::cerr<< " Doesn't make sense to voxelize contour with less than two points ! " < 0 ) point_index--; - else point_index = ( Intersections.at(0).at(struct_index).size() - 1 ); - counter++; - if( counter > ( Intersections.at(0).at(struct_index).size() * 2 ) ) break; - - } - - return false; - - } - - - void Mask::ExtendFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ){ - - LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - - LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); - - PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); - - LegacyDoseVoxelIndex3D aDoseIndex; - aDoseIndex.x = index_x; - aDoseIndex.y = index_y; - aDoseIndex.z = index_z; - - //PolygonInfo polInf = PolygonInfo( the_polygon_ref , struct_index , brightness_outside , brightness_inside , MaskField.at( resolution_level ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(resolution_level) ); - - VoxelIntersectionsVectorPointer pol_inf_pointer = new std::vector(); - FieldOfIntersections->PutData( index_x, index_y, index_z , pol_inf_pointer ); - - IntersectionsThisVoxel intersection_info; - intersection_info.SetPolygonNumber( struct_index ); - - FieldOfIntersections->GetData( index_x , index_y, index_z )->push_back( intersection_info ); - - } - - - - int Mask::GetRespectiveIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ) const{ - - - if( FieldOfIntersections->GetData( index_x , index_y, index_z )!= NULL ){ - - for( int i = 0 ; i < FieldOfIntersections->GetData( index_x , index_y, index_z )->size() ; i++ ){ - if( FieldOfIntersections->GetData( index_x , index_y, index_z )->at(i).GetPolygonNumber() == struct_index )return i; - } - - return (-1); - - } - else return (-1); - - } - - - LegacyWorldCoordinate2D Mask::GetDoubleIndex2D( double x , double y, int resolution_level ){ - - LegacyWorldCoordinate2D result; - - // zunaechst - // x_world = imageOrientationRow.x*pixelSpacingRow*the_index.x+imageOrientationColumn.x*pixelSpacingColumn*the_index.y+imagePosition.x; - // y_world = imageOrientationRow.y*pixelSpacingRow*the_index.x+imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; - // mit x_world y_world ( Welt Koordinaten alles andere dcmtkrt Ausdruecke ) - - // daraus folgt - // Gleichung a : ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.x ; - // Gleichung b : y_world = imageOrientationRow.y*pixelSpacingRow* ( ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; - - // Gleichung b weiter aufgeloest nach the_index.y - // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn*the_index.y )/ ( imageOrientationRow.x*pixelSpacingRow ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y - // Gelichung b weiter umgeformt : - // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.y * ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) - // es ergibt sich - - // aus Gleichung b : the_index.y = a / b - // wobei a = y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) - // und b = ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) + double length = 1; - // Folglich erbibt sich aus Gleichung a : - // the_index.x = ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn* ( a / b ) ) ) / ( imageOrientationRow.x*pixelSpacingRow ) - // Uebersichtlicher : - // the_index.x = ( c - ( d * ( a / b ) ) ) / e - // c = ( x_world - imagePosition.x ) - // d = imageOrientationColumn.x*pixelSpacingColumn - // e = ( imageOrientationRow.x*pixelSpacingRow ) + for (int i = 1 ; i <= resolution_level ; i++) + { + length *= 2; + } - // in anderen Worten : + return length; - double a = y - GInf.at(resolution_level).getImagePositionPatient()(1) - GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow() * ( x - GInf.at(resolution_level).getImagePositionPatient()(0) ) / ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ) ; - double b = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow() * ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) / ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ) ; - double c = ( x - GInf.at(resolution_level).getImagePositionPatient()(0) ) ; - double d = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn(); - double e = ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ); + } - //alt - // folglich ergeben sich die voxel Koordinaten zu - //result.x = ( ( c - ( d * ( a / b ) ) ) / e ) ; - //result.y = ( a / b ) ; - // neu - // folglich ergeben sich die voxel Koordinaten zu + LegacyWorldCoordinate1D Mask::GetZIndex(LegacyWorldCoordinate1D z) + { + // alt + // return ( ( z - GInf.at(0).getImagePositionPatient()(2) ) / GInf.at(0).getSliceThickness() ); + //neu + LegacyWorldCoordinate1D result = ((z - GInf.at(0).getImagePositionPatient()(2)) / GInf.at( + 0).getSliceThickness()) + 0.5; + return result; + } - // Hier muss das resolution level beruecksichtigt werden. Aenderung vornehmen. Auch testen ! + bool Mask::GetSomeBorderVoxelXYZForTest(LegacyDoseVoxelIndex3D& aDoseIndex) + { - // result.x = ( ( c - ( d * ( a / b ) ) ) / e ) + 0.5; - // result.y = ( a / b ) + 0.5; + correspoinding_structure_vector str_v; - result.x = ( ( c - ( d * ( a / b ) ) ) / e ) + GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); - result.y = ( a / b ) + GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); + bool got_it = false; - return result; - - } + while ((got_it == false) && (aDoseIndex.z < (SliceStructureCorrespondency.size()))) + { + str_v = SliceStructureCorrespondency.at(aDoseIndex.z); - LegacyWorldCoordinate2D Mask::GetDoubleIndex2D( double x , double y ){ + if ((str_v.size() > 0) && (GetSomeBorderVoxelXYForTest(aDoseIndex))) + { - return GetDoubleIndex2D( x , y, 0 ); + got_it = true; + } + else + { + aDoseIndex.z++; + } - } - + } - double Mask::GetWorldCoordinateOffsetThisResolutionLevel( int resolution_level ){ + return got_it; - double world_coord_offset = 1; - - for( int i = 1 ; i <= resolution_level ; i++ )world_coord_offset *= 2; - - world_coord_offset = ( 0.5 / world_coord_offset ); - - return world_coord_offset; + } - } + bool Mask::GetSomeBorderVoxelXYForTest(LegacyDoseVoxelIndex3D& aDoseIndex) + { - double Mask::GetBlockLengthThisResolutionLevel( int resolution_level ){ + bool voxel_found = false; - double length = 1; - - for( int i = 1 ; i <= resolution_level ; i++ )length *= 2; - - return length; + unsigned int z = aDoseIndex.z; + int resolution_level = 0; - } + for (unsigned int x = 0 ; x < MaskField.at(resolution_level)->GetDimX() ; x++) + { + for (unsigned int y = 0 ; y < MaskField.at(resolution_level)->GetDimY() ; y++) + { - LegacyWorldCoordinate1D Mask::GetZIndex( LegacyWorldCoordinate1D z ){ - // alt - // return ( ( z - GInf.at(0).getImagePositionPatient()(2) ) / GInf.at(0).getSliceThickness() ); - //neu - LegacyWorldCoordinate1D result = ( ( z - GInf.at(0).getImagePositionPatient()(2) ) / GInf.at(0).getSliceThickness() ) + 0.5; - return result; - } - bool Mask::GetSomeBorderVoxelXYZForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ + if (MaskField.at(resolution_level)->GetData(x, y, z) == brightness_border) + { + voxel_found = true; + aDoseIndex.x = x; + aDoseIndex.y = y; + x = MaskField.at(resolution_level)->GetDimX(); + y = MaskField.at(resolution_level)->GetDimY(); + } + } + } - correspoinding_structure_vector str_v; - - bool got_it = false; + return voxel_found ; - while( ( got_it == false ) && ( aDoseIndex.z < ( SliceStructureCorrespondency.size() ) ) ){ - - str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); + } - if( ( str_v.size() > 0 ) && ( GetSomeBorderVoxelXYForTest( aDoseIndex ) ) ){ - - got_it = true; - } - else aDoseIndex.z++; - } + bool Mask::DoubleCheckIsOnBorderForTest(LegacyDoseVoxelIndex3D& aDoseIndex) + { + int resolution_level = 0; - return got_it; + if (MaskField.at(resolution_level)->GetData(aDoseIndex.x, aDoseIndex.y, + aDoseIndex.z) == brightness_border) + { + return true; + } + else + { + return false; + } + } - } + bool Mask::CheckFractionThisVoxelCorrectForTest(LegacyDoseVoxelIndex3D another_dose_index , + float the_correct_result) + { + if (GetFractionInside(another_dose_index) == the_correct_result) + { + return true; + } + else + { + return false; + } + } - bool Mask::GetSomeBorderVoxelXYForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ - bool voxel_found = false; + float Mask::GetFractionThisVoxelForTest(LegacyDoseVoxelIndex3D another_dose_index) + { + return GetFractionInside(another_dose_index); + } - unsigned int z = aDoseIndex.z; - int resolution_level = 0; - for( unsigned int x = 0 ; x < MaskField.at( resolution_level )->GetDimX() ; x++ ){ - for( unsigned int y = 0 ; y < MaskField.at( resolution_level )->GetDimY() ; y++ ){ + PolygonInfo* Mask::JustCreateAPolygonInfoForTest(LegacyDoseVoxelIndex3D aDoseIndex) + { - - - if( MaskField.at( resolution_level )->GetData( x, y, z ) == brightness_border ){ - voxel_found = true; - aDoseIndex.x = x; - aDoseIndex.y = y; - x = MaskField.at( resolution_level )->GetDimX(); - y = MaskField.at( resolution_level )->GetDimY(); - } - } - } + PolygonInfo* polInfTest = NULL; - return voxel_found ; - - } + if (do_detailed_subvox) + { + correspoinding_structure_vector str_v; + bool got_it = false; - bool Mask::DoubleCheckIsOnBorderForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ - int resolution_level = 0; - if( MaskField.at( resolution_level )->GetData( aDoseIndex.x, aDoseIndex.y, aDoseIndex.z ) == brightness_border ) return true; - else return false; - } + while ((got_it == false) && (aDoseIndex.z < (SliceStructureCorrespondency.size() - 1))) + { + str_v = SliceStructureCorrespondency.at(aDoseIndex.z); + if (str_v.size() > 0) + { + got_it = true; + } + else + { + aDoseIndex.z++; + } + } - bool Mask::CheckFractionThisVoxelCorrectForTest( LegacyDoseVoxelIndex3D another_dose_index , float the_correct_result ){ - if( GetFractionInside( another_dose_index ) == the_correct_result ) return true; - else return false; - } + // Nur der erste Polygonzug des entsprechenden slices wird betrachtet, daher keine Schleife ueber alle Strukturen dieses Slices noetig. + // Die Teststruktur die hier verwendetw wird besteht in diesem Slice nur aus einem Polygonzug. + // for( unsigned int count = 0 ; count < str_v.size() ; count++ ){ + if (got_it) + { - float Mask::GetFractionThisVoxelForTest( LegacyDoseVoxelIndex3D another_dose_index ){ - return GetFractionInside( another_dose_index ); - } + int struct_index = str_v.at(0); + LegacyPolygonSequenceType pol_seq; - PolygonInfo* Mask::JustCreateAPolygonInfoForTest( LegacyDoseVoxelIndex3D aDoseIndex ){ + PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( + struct_index); - PolygonInfo* polInfTest = NULL; + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); + LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); - if( do_detailed_subvox ){ + if (FieldOfIntersections) + { + FieldOfIntersections->SetZero(); + GetIntersectionInformationThisSlice(aDoseIndex.z); + } - correspoinding_structure_vector str_v; - bool got_it = false; + int which_one = GetRespectiveIntersections(aDoseIndex.x , aDoseIndex.y , 0 , struct_index); - while( ( got_it == false ) && ( aDoseIndex.z < ( SliceStructureCorrespondency.size() - 1 ) ) ){ - str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); - if( str_v.size() > 0 ) got_it = true; - else aDoseIndex.z++; - } + if (which_one != (-1)) + { - // Nur der erste Polygonzug des entsprechenden slices wird betrachtet, daher keine Schleife ueber alle Strukturen dieses Slices noetig. - // Die Teststruktur die hier verwendetw wird besteht in diesem Slice nur aus einem Polygonzug. - // for( unsigned int count = 0 ; count < str_v.size() ; count++ ){ + IntersectionsThisVoxel intersections_this_voxel = FieldOfIntersections->GetData(aDoseIndex.x , + aDoseIndex.y , 0)->at(which_one); + polInfTest = new PolygonInfo(the_polygon_ref, struct_index , brightness_outside , + brightness_inside , MaskField.at(0) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(0) , + intersections_this_voxel); - if( got_it ){ + } - int struct_index = str_v.at( 0 ); + } + else + { + return NULL; + } - LegacyPolygonSequenceType pol_seq; + } - PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); + return polInfTest; - LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); + } - if( FieldOfIntersections ){ - FieldOfIntersections->SetZero(); - GetIntersectionInformationThisSlice( aDoseIndex.z ); - } - int which_one = GetRespectiveIntersections( aDoseIndex.x , aDoseIndex.y , 0 , struct_index ); - - if( which_one != (-1) ){ - - IntersectionsThisVoxel intersections_this_voxel = FieldOfIntersections->GetData( aDoseIndex.x , aDoseIndex.y , 0 )->at( which_one ); - polInfTest = new PolygonInfo( the_polygon_ref, struct_index , brightness_outside , brightness_inside ,MaskField.at( 0 ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at( 0 ) , intersections_this_voxel ); - - } - - } - else return NULL; - } - return polInfTest; - } + bool Mask::GetIntersectionsOfSliceForTest(unsigned int position , + PolygonInTermsOfIntersections& Polygon_Intersections_Ref) + { + if (position < Intersections.at(0).size()) + { + Polygon_Intersections_Ref = Intersections.at(0).at(position); + return true; + } + else + { + return false; + } - bool Mask::GetIntersectionsOfSliceForTest( unsigned int position , PolygonInTermsOfIntersections& Polygon_Intersections_Ref ){ + } - if( position < Intersections.at(0).size() ){ - Polygon_Intersections_Ref = Intersections.at(0).at( position ); - return true; + bool Mask::ReturnFirstWithIntersectionsForTest(unsigned int& position) + { - } - else return false; + position = 0; - } + while (position < Intersections.at(0).size()) + { + if (Intersections.at(0).at(position).size() > 0) + { + return true; + } + else + { + position++; + } - bool Mask::ReturnFirstWithIntersectionsForTest( unsigned int& position ){ + } - position = 0; - - while( position < Intersections.at(0).size() ){ + position = 0; + return false; - if( Intersections.at(0).at( position ).size() > 0 )return true; - else position++; + } - } - - position = 0; - return false; - } + float Mask::GetFractionInside(const LegacyDoseVoxelIndex3D& aDoseIndex) + { + double fraction_total = 0; - float Mask::GetFractionInside( const LegacyDoseVoxelIndex3D& aDoseIndex ) { + correspoinding_structure_vector str_v; + str_v = SliceStructureCorrespondency.at(aDoseIndex.z); - double fraction_total = 0; + // Hier werden alle Polygone untersucht, die in diesem Slice liegen. + for (unsigned int count = 0 ; count < str_v.size() ; count++) + { - correspoinding_structure_vector str_v; - str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); + int struct_index = str_v.at(count); - // Hier werden alle Polygone untersucht, die in diesem Slice liegen. - for( unsigned int count = 0 ; count < str_v.size() ; count++ ){ + int which_one = GetRespectiveIntersections(aDoseIndex.x , aDoseIndex.y , 0 , struct_index); - int struct_index = str_v.at( count ); + //assert( which_one != (-1) ); // nein nicht assert, denn nicht jede Struktur die zu diesem Slice gehoert schneidet zwangslauefig dieses Voxel - int which_one = GetRespectiveIntersections( aDoseIndex.x , aDoseIndex.y , 0 , struct_index ); + if (which_one != (-1)) + { - //assert( which_one != (-1) ); // nein nicht assert, denn nicht jede Struktur die zu diesem Slice gehoert schneidet zwangslauefig dieses Voxel + LegacyPolygonSequenceType pol_seq; - if( which_one != (-1) ){ + assert(struct_index < Intersections.at(0).size()); - LegacyPolygonSequenceType pol_seq; + const PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( + struct_index); - assert( struct_index < Intersections.at(0).size() ); + LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); - const PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); + LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); - LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); + const IntersectionsThisVoxel& intersections_this_voxel = FieldOfIntersections->GetData( + aDoseIndex.x , aDoseIndex.y , 0)->at(which_one) ; - LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); - const IntersectionsThisVoxel& intersections_this_voxel = FieldOfIntersections->GetData( aDoseIndex.x , aDoseIndex.y , 0 )->at(which_one) ; + PolygonInfo polInf = PolygonInfo(the_polygon_ref , struct_index , brightness_outside , + brightness_inside , MaskField.at(0) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(0) , + intersections_this_voxel); + if (polInf.CreatePolygonSequence()) + { - PolygonInfo polInf = PolygonInfo( the_polygon_ref , struct_index , brightness_outside , brightness_inside , MaskField.at( 0 ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(0) , intersections_this_voxel ); + pol_seq = polInf.GetResultingSequence(); - if( polInf.CreatePolygonSequence() ){ + double fraction_this_polygon = 0; - pol_seq = polInf.GetResultingSequence(); + int numberOfContours = pol_seq.size(); - double fraction_this_polygon = 0; + for (int i = 0; i < numberOfContours ; i++) + { - int numberOfContours = pol_seq.size(); + Contour contour = Contour(pol_seq.at(i)); + double area = contour.getArea(); - for(int i=0; i= 0) ) std::cout<< " fraction_this_polygon : " << fraction_this_polygon <= 0 ); // that's essential since ResultingSequence is represented in Voxel coordinates + //assert( fraction_this_polygon <= 1 ); // that's essential since ResultingSequence is represented in Voxel coordinates - // if( ! (fraction_this_polygon >= 0) ) std::cout<< " fraction_this_polygon : " << fraction_this_polygon <= 0 ); // that's essential since ResultingSequence is represented in Voxel coordinates - //assert( fraction_this_polygon <= 1 ); // that's essential since ResultingSequence is represented in Voxel coordinates + //if( voxel_volume == 0 )assert(0); // this must never happen. Since depends on dataset : exception to be implemented ! - //double voxel_volume = GInf.at(resolution_level).getPixelSpacingRow() * GInf.at(resolution_level).getPixelSpacingColumn() * GInf.at(resolution_level).getSliceThickness(); + //fraction_this_polygon /= voxel_volume; - //if( voxel_volume == 0 )assert(0); // this must never happen. Since depends on dataset : exception to be implemented ! + } - //fraction_this_polygon /= voxel_volume; - } + fraction_total += fraction_this_polygon; + } - fraction_total += fraction_this_polygon; + } - } - - } - - } // Iteration ueber Polygone + } // Iteration ueber Polygone - return fraction_total; + return fraction_total; - } + } - }//namespace - }//namespace + }//namespace + }//namespace }//namespace diff --git a/code/masks/legacy/rttbMask.h b/code/masks/legacy/rttbMask.h index e37ddd4..f965b42 100644 --- a/code/masks/legacy/rttbMask.h +++ b/code/masks/legacy/rttbMask.h @@ -1,757 +1,816 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 __RT_MASK_H #define __RT_MASK_H #include "rttbBaseType_LEGACY.h" #include "rttbBaseType.h" #include "rttbStructure_LEGACY.h" #include "DoseVoxel_LEGACY.h" #include "DoseIteratorInterface_LEGACY.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" #include "rttbContour_LEGACY.h" #include "rttbPolygonInfo_LEGACY.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include #include -namespace rttb{ - namespace masks{ - namespace legacy{ - - /*! @class Mask - * @brief This class represents the Mask calculated using a dose iterator and a StructureLegacy/DoseVoxelVector. - The mask is first calculated with voxel accurracy. Those voxels that are touched by the structure are then further - regarded using PolygonInfo and IterativePolygonInTermsOfIntersections to find out the fraction that is - inside the structure. - The voxelization is done on several resultution levels, but the calculation on subvoxel accurracy, - that means the calculation of the fraction of the voxel that is inside the structure, is done solely on the finest resolution level. - And solely for those voxels that are touched by the structure - typically most voxels are not. - This multi resolution approach is much faster as compared to doing it on just one level, - because a voxel that is not touched by the structure and determinded to be inside the structure on a - croase resolution level does on all finer resolution level solely correspond to voxels that are inside, too. The same - goes for a voxel that was determined to be completely outside: All the voxels that are contained in this voxel - on each finer resolution level are colpletely outside, too. So the creation of the mask without subvoxel accurracy is - done on the croasest resolution level completely and for each voxel with clear affiliation inside/outside all the - respective voxels are set for all the finer resolution levels right away as they are determined on a croase level. - It is cumputational effort to create several masks - and it is effort to set the inside/outside affiliation of a voxel on all levels instead of just one. However, it saves - effort, because on each finer resolution level, only view voxels - need to be considered: Those that are close to the contour and were thus touched by the contour on the previous level - that was to croase to tell the inside/outside affiliation. Since there is a factor four in the number of voxels between two levels, - the multi resouluton calculation is fast, because view voxels need to be regarded. - Field.h has an efficient way of finding those voxels with unclear affiliation and of setting affiliation throughout resoltuion levels in blocks. - After reaching the finest resolution those voxels that are still in the border region - and thus just touched by the structure are then further examined with subvoxel accurracy, based on - PolygonInfo and IterativePolygonInTermsOfIntersections. - - - */ - class Mask{ - - public: - - - /*! @brief Constructor with a DoseIterator and a StructureLegacy - * The mask is calculated with sub voxel fraction info. - @pre The Structure must not intersect itself. It may touch itself. - @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about - the dose value associated with each voxel. - @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. - * @exception RTTBNullPointerException thrown if aDoseIter or aStructure is NULL - */ - Mask( DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure); - - /*! @brief Constructor with a DoseIterator and a vector of DoseVoxel inside a structure (with voxel proportion information) - @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about - the dose value associated with each voxel. - @param aDoseVoxelVector is a reference to a vector that holds values of the type DoseVoxel. Using this parameter it is possible - to accept a given "voxelization" created by Mevis for example. - * @exception RTTBNullPointerException thrown if aDoseIter is NULL - */ -// Mask( DoseIteratorInterface* aDoseIter , const std::vector& aDoseVoxelVector ); - - /*! @brief Constructor with a DoseIterator and a StructureLegacy - * The mask is calculated with sub voxel fraction info. - @pre The Structure must not intersect itself. It may touch itself. - @param aGeoInfo is a pointer to a GeometricInfo of the dose. - @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. - * @exception RTTBNullPointerException thrown if aDoseGeoInfo or aStructure is NULL - */ - Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure); - - - /*! @brief Destructor - */ - ~Mask(); - - /*! @brief Old Code!!! It is unnecessary now. The user should check the geometric information of the new dose iterator, if changed, - generate new mask using Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure)! - - *Old brief: Reset dose. If the geometric information has not changed, the _doseVoxelInStructure does not need to be recalculated, in case - other dose values are introduced for the same structure and geometry. Only doseData needs to be recalculated. - @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about - the dose value associated with each voxel. - * @exception RTTBNullPointerException Thrown if aDoseIter or aStructure is NULL - - */ - void resetDose(DoseIteratorInterface* aDoseIterator); - - - - /*! @brief Get the dose voxels which lie inside the structure - * @return Vector of DoseVoxel which are inside the structure (with voxel proportion information) - */ - const std::vector& getDoseVoxelInStructure() const; - - /*! @brief Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) - * @param aDoseVoxelVector Vector of RTDoseVoxels inside the structure to be set. - * @return - */ - void setDoseVoxelInStructure(std::vector aDoseVoxelVector); - - /*! @brief Get the dose iterator - * @return DoseIteratorInterface& returns the dose Iterator. - */ - const DoseIteratorInterface& getDoseIterator() const; - - /*! @brief Get the structure - * @return StructureLegacy& Returns the structure. - */ - const StructureLegacy& getRTStructure() const; - - /*! @brief Get absolute dose data of the voxels which are inside the structure. - @return Returns the dose values. - */ - //const std::vector getDoseData() const; - - - /*new...................*/ - - /*! @brief Calculates 2D voxel coordinates from 2D world coordinates. - @param x voxel coordinate x - @param y voxel coordinate y - @return Returns 2D world coordinates. - */ - LegacyWorldCoordinate2D GetDoubleIndex2D( double x , double y ); - /*! @brief Calculates 2D voxel coordinates from 2D world coordinates taking the current resolution level under consideration. - @param x voxel coordinate x - @param y voxel coordinate y - @param resolution_level current resolution - @return Returns 2D voxel coordinates. - */ - LegacyWorldCoordinate2D GetDoubleIndex2D( double x , double y, int resolution_level ); - - /*! @brief The offset between world and voxel coordinate system depends on the current resolution. This function calculates this offset. - @param resolution_level current resolution - @return Returns the offset between world and voxel coordinate system. - */ - double GetWorldCoordinateOffsetThisResolutionLevel( int resolution_level ); - - // Functions and other stuff needed for unit tests: - /*! @brief Needed for unit tests. Provides the Information about the Intersections of a specific polygon, - that is part of the structure, with the edges of the voxels. - @param position Index des polygon of interest. The structure consists of an entity of plygons. - @param Polygon_Intersections_Ref Refernce to an object of the Type PolygonInTermsOfIntersection. After running the function, this Reference holds the Information about - the intersections of the polygon of interest (specified by position) with the voxel edges. - @return This function returns false and does not do its job, in case "position" holds an unreasonalble value, e.g. refers to a - polygon that does not exist. - */ - bool GetIntersectionsOfSliceForTest( unsigned int position , PolygonInTermsOfIntersections& Polygon_Intersections_Ref ); - /*! @brief Needed for unit tests. Returns true in case there are any intersections of the structure with the voxel edges. - A reference to an integer is set to the index of the first polygon that intersects with voxel edges - in case there are intersections. Otherways the reference is set to zero and the function returns false. - @param position Some reference to some integer which is modified by this function. - In case there are any intersection this reference is set to the index of the first intersecting polygon. - Otherways it is set to zero. - @return Returns false in case there are no intersections and true in case there are intersections of the contour with the voxel edges. - */ - bool ReturnFirstWithIntersectionsForTest( unsigned int& position ); - /*! @brief Needed for unit tests. This function is made to test the function GoIntersectColumn which is private and therefore not - accessible for the testing unit. This function called TestGoIntersectColumnByComparisonWithExpectedResult - is provided with two 3D Points and with a vector called expected_intersections_ref that holds the information about - those intersections that are to be expected. These values are set by the one who wrote the unit test. Now these expected - values are compared with those that are calculated by the function GoIntersectColumn and in case there is any deviation - between acutal an expected result this function here returns false. Otherwise it returns true. - - @param firstPoint The first one of two points that specify a line which is to be checked for intersections with voxel edges. - @param secondPoint The second one of two points that specify a line which is to be checked for intersections with voxel edges. - @param column_intersections_ref After running this function this reference to a vector of objects of the type LegacyWorldCoordinate2D - holds the information about the calculated intersections. - @param expected_intersections_ref This is a reference to a vector of objects of the type LegacyWorldCoordinate2D which holds the - information about the expected intersections. These intersections are set by the programmer - who writes the unit test and who knows the correct intersections. - @return This funciton returns true in case the function GoIntersectColumn turned out to work properly. Otherwise it returns false. - */ - bool TestGoIntersectColumnByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, std::vector& expected_intersections_ref ); - /*! @brief Needed for unit tests. See TestGoIntersectColumnByComparisonWithExpectedResult for details since this function here is very similar. - The only difference is that this funciton is made to help with unit testing with respect to the funcion GoIntersectRaw - instead of GoIntersectColumn - despite that its just the same. - */ - bool TestGoIntersectRawByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, std::vector& expected_intersections_ref ); - /*! @brief Needed for unit tests. Checks whether two vectors of points that are passed to this function are identical. - @param calculated_intersections_ref First vector of points to be compared with the second one. - @param expected_intersections_ref Second vector of points to be compared with the first one. - @return Returns true in case the vectors are identical. - */ - bool IdenticalIntersectionsForTest( std::vector& calculated_intersections_ref , std::vector& expected_intersections_ref ); - /*! @brief Needed for unit tests. An object of the type PolygonInfo can only be created in an environment that has all the - incredients that are necessary. Since in Mask all the incredients are available and since there is no other environment, where this is the case, - since PolygonInfos are sofar not created anywhere else, this function was created, just in order to create and return a - PolygonInfo object for - test purposes. So this function creates an object of the type PolygonInfo and retunrns a pointer to it. - The PolygonInfo is created either for a voxel with cordinates aDoseIndex, given as a parameter - or alternatively for a voxel with greater - z-position in case there is no contour in the slice of the given location. In case there is no contour in any - slice with greater z-position either, the PolygonInfo can not be created. In that case a nullpointer is returned. - @param aDoseIndex Position for which the PolygonInfo object is to be created. - @return Returns an object of the type PolygonInfo in case a polygon of the structure can be found. Otherways it returns a NULL - pointer. - */ - PolygonInfo* JustCreateAPolygonInfoForTest( LegacyDoseVoxelIndex3D aDoseIndex ); - /*! @brief Needed for unit tests. Checks for a specific voxel, whether the correct fraction of this voxel was recognized to be - enclosed by the structure. - @param another_dose_index parameter of type LegacyDoseVoxelIndex3D which specifies the voxel coordinate of interest. - @param the_correct_result is a float that specifies the expected result. - @return Returns true in case Mask did well and the calculated fraction meets the expectation. - */ - bool CheckFractionThisVoxelCorrectForTest( LegacyDoseVoxelIndex3D another_dose_index , float the_correct_result ); - /*! @brief Needed for unit tests in order to access the fraction of a specific voxel that was determined to be enclosed by the structure. - @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. - @return Returns a float that holds the informaton about the portion of the voxel which is enclosed by the structure. - */ - float GetFractionThisVoxelForTest( LegacyDoseVoxelIndex3D another_dose_index ); - /*! @brief Needed for unit tests. Returns true in case the voxel specified by aDoseIndex is touched by the structure. - @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. - @return Returns true in case the voxel specified by aDoseIndex is touched by the structure. - */ - bool DoubleCheckIsOnBorderForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); - /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by the structure. - @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function. If things go well, - it is set to a voxelposition touched by the structure. In that case the function returns true. - @return Returns false in case no voxel is touched by the structure. Otherways returns true. - */ - bool GetSomeBorderVoxelXYZForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); - // End functions and other stuff needed for unit tests - - - - protected: - - typedef std::vector* VoxelIntersectionsVectorPointer; - - // @brief withSubVoxelFraction If true, the mask will be calculated with sub voxel fraction info; otherwise, without - // sub voxel fraction info, that means getDoseVoxelInStructure() returns the DoseVoxel with getProportionInStr()= 1. - // - //bool _withSubVoxelFraction; - - /// the dose iterator - DoseIteratorInterface* _doseIter; - /// the structure - StructureLegacy* _structure; - - /// vector of the RTDoseVoxels inside the structure - std::vector _doseVoxelInStructure; - - /// vector of the dose values corresponding to _doseVoxelInStructure, it has the same size as _doseVoxelInStructure - std::vector _doseData; - - /// geometric information about the dose distribution - std::vector< core::GeometricInfo > GInf; - - //VoxelIntersectionPointsMap voxel_intersectionPoints; - - /// Once they are determined to be inside voxels get this brightness. - field_content_type brightness_inside; - /// Once they are determined to be touched by the structure voxels get this brightness. - field_content_type brightness_border; - /// Once they are determined to be outside voxels get this brightness. - field_content_type brightness_outside; - /// Voxels that are yet not determinded to be inside the structure, outside the structure or touched by the structure are marked with this brightness. - field_content_type brightness_unknown; - - /// Calculates the mask. - void Calc(); - /// Just for test. Doublechecks and does assert(0) in case something has gone wrong. - void TestVoxelMaskUppward(); - - /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. - There are situations throughout the algorithm where it is known, that a specific affiliation of one voxel on one resolution - level does determine its affiliation on other resolution levels. The job of this function is to check that and to - assert, it terminates the program deliberately if something has happened, that definitely must never happen. - @param resolution_level_in Integer that species the current resolution level. - @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system - on the current resolution level that is to be checked throughout all finer levels. - @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. - */ - void CheckUppwardBlockSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); - /*! @brief This function sets a brightness of a voxel throughout resolution levels, since the Voxelisierung is done on - several resultution levels as explained above. - @param resolution_level_in Integer that species the current resolution level. - @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system - on the current resolution level that is to be set at first and then throughout all finer levels - adapted to the finer voxel coordinate sysetem. - @param brightness Integer that specifies the brightness that is to be set on the current and throughout all the finer resolution levels. - */ - void SetUppwardBlockThisIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); - /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. - There are situations where a specific affiliation of one voxel on one resolution - level does determine affiliation of at least one voxel on any finer resolution - level to the same intensity, within a specific block of voxels that corresponds to the voxel in position index_internal - on the croase level. - The job of this function is to check whether - there is any such voxel on every finer resolution level, within the respective block. - So this function terminates the program deliberately if something has happened, that definitely must never happen. - @param resolution_level_in Integer that species the current resolution level. - @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system - on the current resolution level that is to be checked throughout all finer levels. - @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. - */ - void CheckUppwardOneOutOfThisBlockHasSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); - /*! @brief Calculates for some resolution level the number of voxels of the finest resolution level, that fit into this - voxel one dimensionally. So this is a number of fine voxels that fit into this croase voxel along the length of this croase voxel. - @param resolution_level Integer that specifies the resolution level of the croase voxel. Whereas zero is the finest level, one the next - croase level with a total number of voxels of just one quater of the next finer level .... and so on .... - @return Returns a double that holds the information about the block length. Actually it should be an integer, but a double works, too ... - */ - double GetBlockLengthThisResolutionLevel( int resolution_level ); - /*! @brief Checks the structure, so checks all polygons of the structure, on intersections with themselves. - @return Returns true, if the structure does not contain self intersecting polygons and thus is fine. - */ - bool ContourFine(); - /*! @brief Checks two polygons for intersection with one another. Checks one polygon for intersection with itself, in case - struct_index_a and struct_index_b are the same. - @param struct_index_a Integer that specifies the index of the first polygon that is to be checked for intersections. - @param struct_index_b Integer that specifies the index of the second polygon that is to be checked for intersections. - @return Returns true if the polygons do intersect (or if the polygon does intersect in case of a check for self intersection). - */ - bool DoesIntersect( int struct_index_a , int struct_index_b ) const; - /*! @brief Checks two lines for intersection. - @param firstPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the first line. - @param secondPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the first line. - @param thirdPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the second line. - @param fourthPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the second line. - @return Returns true in case there is an intersection. - */ - bool HasIntersectionsThisPair( const LegacyWorldCoordinate3D& firstPoint , const LegacyWorldCoordinate3D& secondPoint, const LegacyWorldCoordinate3D& thirdPoint , const LegacyWorldCoordinate3D& fourthPoint ) const; - - /*! Holds the masks for different resolution levels. - To be initialized in Constructor by an initialization function. - */ - std::vector< rttb::masks::legacy::FieldOfScalar* > MaskField; - - /*! Two dimensional field. - Content of one element holds the information about the intersections of the structure with - the voxel edges of the corresponding voxel. The object, that holds this intersecton information - for the voxel in position x,y within the slice, is located in the position x,y within FieldOfIntersections. - FieldOfIntersections is created for just one slice - the slice which Mask is currently working on. - */ - rttb::masks::legacy::FieldOfPointer* FieldOfIntersections; - - bool do_detailed_subvox; /// If do_detailed_subvox is true, the Mask is calculated with sub-voxel accurracy. - - /*! To be initialized in Constructor by an initialization function. - Holds the information about the structure and its Intersections with the voxel edges. - */ - std::vector Intersections; ///Holds the information about the structure and its Intersections with the voxel edges. - - /*! @brief Fills _doseVoxelInStructure with DoseVoxel objects. Each of these DoseVoxel objects carries the information about the - portion of the voxel that is enclosed by the structure. The DoseVoxel objects are created based on the Mask - with the finest resolution. Based on this Mask field it is clear that the voxel is completely inside the structure or - completely outside in most of the cases. - SetDoseVoxelInStructureVector calls GetFractionInside() and thus determines the fraction - of the voxel that is enclosed by the structure in case the voxel is touched by the structure and thus - not yet determined to be completely inside or outside. - */ - void SetDoseVoxelInStructureVector(); - - - /*! @brief Old stuff. - */ - void SeperateRegions(); - - /*! @brief Old stuff. - */ - void SeperateRegionsQuick(); - - /*! @brief Old Stuff. - */ - void ConnectArea( field_content_type brightness_from , field_content_type brightness_to , LegacyUnsignedIndex3D start_index, LegacyDoseVoxelIndex2D index_begin, LegacyDoseVoxelIndex2D index_end ); // To be called by SetDoseVoxelInStructureVector - - /*! @brief To be initialized by an init function that is called by Constructor. Holds the information about how the polygons correspond to the slices. - */ - std::vector SliceStructureCorrespondency; - - - /*! @brief To be initialized by an init fuction which is called by Constructor. Contains the information about which area of the image is actually to be regarded. A large part of the image may be far off from any polygon. - */ - vector_of_area_vectors MarkInterestingArea; - - - /*! @brief Is called by the constructor and calls other initialization fucntions. - */ - void Init(); - - - /*! @brief Searches backward in Intersections until a point is reached that differs from compare_point. - point_index is set to the index of this point. - @param struct_index Reference to an integer that specifies the polygon of interest. - @param point_index Reference to an integer that is modified by this function. - First it specifies the index of the point where the function stearts searching. - It is decremented during the search and in the end it points to the first point within the search direction - that turned out to be different from compare_point. - @param compare_point Parameter of the type LegacyWorldCoordinate3D. Specifies a point. This function searches for a point - which differs from compare_point. - @return Returns true in case such a point was found and false in case it was not. - */ - bool GetFirstDifferent( unsigned int& struct_index , unsigned int& point_index , LegacyWorldCoordinate3D compare_point ); - - - - /*! @brief This function determines whether the intersection with struct_index, point_index and intersect_index - is to be set to the FieldOfIntersections. It is to be set in case the intersection with the voxeledge is either - not a point of the polygon, or in case it is ( that means the point of the polygon is on the edge of a voxel ) - and at the same time the previous point of the polygon has one identical coordinate in a way so that it is located on - the same edge, too (eventually alongside another voxel, so the same edge here means "same column seperating voxels"). - @param struct_index Index of the polygon. - @param point_index Index of the point within the polygon (last one between the intersection that is currently being processed). - @param intersect_index Index of the intersection that is currently being processed. - @param index_x X-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. - @param index_y Y-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. - @return Retruns true in case the intersection with struct_index, point_index and intersect_index is to be set to the - FieldOfIntersections. - */ - bool IsItToBeRegarded( unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , int index_x , int index_y ); - - - - /*! @brief This function calls SetThisIntersection with the respective parameters and therefore takes part in positioning the intersection characterized by the - parameter intersection within the FieldOfIntersections. - @param index_x X-position of the voxel. - @param index_y Y-position of the voxel. - @param intersection Specifies the intersection that is currently regarded (similar to an index, specifies location where the intersection can be found within the object Intersections). - @param coord2D Voxel coordinate of the intersection. - @param edge_number Denotes the edge which the intersection is on. - @param voxel_intersections The element within FieldOfIntersections that corresponds to this voxel and polygon. - */ - void SetThisIntersectionToCornerOrEdge(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D, unsigned int edge_number, IntersectionsThisVoxel& voxel_intersections ); - - - /*! @brief This function positions an intersection within voxel_intersections. Practically voxel_intersections is an element within FieldOfIntersections (generally it can be any reference to an IntersectionsThisVoxel ). - The voxel edge the intersection is placed to is given by edge_number. - @param corner_of_interest The corner at the beginning of the respective edge. Beginning means the point of the edge that is first passed while surrounding the voxel clockwise. - @param corner_next The corner at the end of the respective edge. That means the point along the edge that is passed last while surrounding the voxel clockwise. - @param corner_fixed Its the coordinate, which is the same all along the edge. - @param intersection Denotes the index of the regarded intersection in Intersections. - @param coord_of_interest The coordinate which is interesting, because it is responsible for the position of the intersection along the edge, while the other coordinate is just the same for the intersection as well as for all the points that belong to the edge. - @param coord_fixed This coordinate should equal to corner_fixed. The function asserts for that. Its the coordinate that all the points on the edge and the intersection point have in common. - @param voxel_intersections Practically its an element of FieldOfIntersections (although generally it can be any element of IntersectionsThisVoxel). - @param edge_number Number of the edge that is regarded. The edges are counted colckwise starting from upper left. - */ - void SetThisIntersection( unsigned int corner_of_interest, unsigned int corner_next , unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ); - - - /*! @brief This function checks whether value_to_compare is in between small_value_to_compare_with and big_value_to_compare_with. Practically value_to_compare is a coordinate of an intersection point. Practically big_value_to_compare_with is the end point of an edge. - In case value_to_compare is in between, the index of the intersection (that characterizes its location within Intersections (Intersections is a global variabele, a vector of StructureInTermsOfIntersections) ) and its coordinates are appended to the corresponding edge within voxel_intersections. - @param value_to_compare This value is to be compared with other values and inserted into voxel_intersections at the right place. - @param small_value_to_compare_with First value to compare with. - @param big_value_to_compare_with Second value to compare with. - @param edge_number Number of the edge. Edges are counted clockwise, starting from upper left. - @param intersection Index of the intersection within Intersections. - @param voxel_intersections Object of type IntersectionsThisVoxel that holds the information about all the intersections of the structure with this currently regarded voxel as well as the information where to find these intersection within Intersections - @return Retruns true in case insertation was successful. - */ - bool CompareIfBetweenAppend( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); - - - /*! @brief This function checks whether the intersection point is already known. - In case it is the index of the intersection within Intersections is appended to the already existing vector of points of the respective edge that all represent this specific intersection point (in case the structure goes through this point several times touching itself, otherways ist just one) - (Intersections is a global variable, a vector of StructureInTermsOfIntersections which contains the information about all the intersections with all the voxel edges on all resolutions). - In case it does not exist yet a new vector of indices as well as coordinates is created and inserted in the respective position. - In case the same intersection point will be found again later on it will be appended then. - @param value_to_compare Coordinate of the point to be inserted. - @param edge_number Number of the edge. The edges are counted clockwise, starting from upper left. - @param intersection Index of the intersectoin within Intersections. - @param voxel_intersections An object representing the information about the intersections of the structure with this voxel, including the information about coordinates of the intersection points as well as indicees that represent the information about where to find them within Intersections. - @return Returns true in case of a successful insertation. - */ - bool CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( double value_to_compare , unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); - - - /*! @brief See CompareIfBetweenAppend - the only difference is, that this function inserts the intersection at the beginning of the edge and that practically small_value_to_compare_with is the first point within the respective edge while big_value_to_compare_with is either the first intersection that has aleready been found, or the last point within the edge. - @return Returns true in case the intersection was inserted into voxel_intersections. - */ - bool CompareIfBetweenInsertAtBeginning( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); - - - /*! @brief Old stuff. - */ - void SetThisIntersectionXIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ); - /*! @brief Old stuff. - */ - void SetThisIntersectionYIncreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); - /*! @brief Old stuff. - */ - void SetThisIntersectionXDecreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); - /*! @brief Old stuff. - */ - void SetThisIntersectionYDecreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); - - - /*! @brief This function determines the area that contains voxels that need to be regarded. - For example voxels within x-coordinate lower than the contour pont with lowest x-coordinate do not need to be regarded, since they can - not be enclosed by the contor. Of course the same goes for other coordintates and ... - */ - void InitInterestingArea(); - /*! @brief Initializes MaskField which contains the masks fields for different resolution levels and the corresponding geometric infromation stored in GInf. - Different sizes are initialized, representing the different resolutions. Calls InitIntersections. - */ - void InitMultiResolution(); - /*! @brief Initializes Intersections which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. - This function just initializes, but yet does not calculate the intersections, so here Intersectons is created, but remains empty. - */ - void InitIntersections(); - - /*! @brief This function is called to calculate the intersections between structure and voxel edges and thus to fill - Intersections with intersecton values, which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. - @param resolution_level Specifies for which voxel grid the intersections are to be calculated. In case it is zero it is done for the - finest resolution and the values are filled into the first element of Intersections. - */ - void GetIntersections( int resolution_level ); - - /*! @brief This function fills intersections_raw_and_column_ref with intersection values. It operates on a segment of a polygon consisting of a line that connects a first and a second point. - The intersections of this polygon segment with the voxel edges on the resolution_level are already determined and stored in - raw_intersections_ref, which contains the intersections with raw-eges as well as - column_intersections_ref which holds the intersections with the voxel edges regarding columns. - In intersections_raw_and_column_ref they are sorted with respect to their distance - from firstPoint and in the end intersections_raw_and_column_ref contains all the intersections - colum and raw intersections. - @param firstPoint Starting point of the segment of the polygon. - @param raw_intersections_ref Contains the raw intersections sorted with resepect to their distance from firstPoint. - @param column_intersections_ref Contains the column intersections sorted with resepect to their distance from firstPoint. - @param intersections_raw_and_column_ref After running this function intersections_raw_and_column_ref contains all intersections sorted with resepect to their distance from firstPoint. - @param resolution_level The resolution level. Zero is finest. - */ - void UnifyRawAndColumn( LegacyWorldCoordinate3D firstPoint, std::vector& raw_intersections_ref , std::vector& column_intersections_ref , std::vector& intersections_raw_and_column_ref, int resolution_level ); - - - /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). - The line starts with firstPoint and ends with secondPoint. - @param firstPoint Point to start the line. - @param secondPoint point to end the line. - @param raw_intersections_ref The intersections are placed here. - @param resolution_level The current resolution. - */ - void GoIntersectRaw( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref , int resolution_level ); - - - /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). - The line starts with firstPoint and ends with secondPoint - @param firstPoint Point to start the line. - @param secondPoint point to end the line. - @param column_intersections_ref The intersections are placed here. - @param resolution_level The current resolution. - */ - void GoIntersectColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ); - - - /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). - The line starts with firstPoint and ends with secondPoint. - This function is called in case the x-position of firstPoint and secondPoint are identical. - @param firstPoint Point to start the line. - @param secondPoint point to end the line. - @param raw_intersections_ref The intersections are placed here. - @param resolution_level The current resolution. - */ - void GoGetRawIntersectionsAlongThisColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, int resolution_level ); - - - /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). - The line starts with firstPoint and ends with secondPoint. This function is called only in case the y-position of first and of - second point are identical. - @param firstPoint Point to start the line. - @param secondPoint point to end the line. - @param column_intersections_ref The intersections are placed here. - @param resolution_level The current resolution. - */ - void GoGetColumnIntersectionsAlongThisRaw( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ); - - - /*! @brief This function prints out all the intersections with cout. Normally its not called, but sometimes its needed for debugging. - */ - void ShowIntersections(); - - - /*! @brief Based on the global variable Intersections that holds the information about the intersections betweent the voxel edges and - the polygons this function determines all voxels that are touched by the structure on resolution_level. So this operation - is carried out for the mask field that belongs to resolution_level. For resolution_level equal to zero its the finest - resolution and so the resolution of the mask field is the resolution of the dose distribution. - */ - void MarkVoxelsTouchedByStructure( int resolution_level ); - - - /*! @brief Sets FieldOfIntersections for the current slice. This is done based on Intersections which stores the information about the - polygons and their intersections. - @param index_z Integer that represents the index of the slice which is to be regarded. - */ - void GetIntersectionInformationThisSlice( unsigned int index_z ); - - - /*! @brief The intersection with voxel coordinates coord2D is inserted into - the FieldOfIntersectons in position of voxel (index_x , index_y , index_z) and for the polygon with index struct_index - and for the side of the voxel denoted by voxel_side. - @param index_x X-position of the voxel. - @param index_y Y-position of the voxel. - @param index_z Z-position of the voxel. - @param struct_index Index of the polygon that is intersecting here. - @param point_index Index of the last polygon point before the intersection. - @param intersect_index Index of the intersection. By the way also represents the information about how many intersections with voxel edges are in between this intersection with voxel edge and the last polygon point. - @param coord2D Intersection in voxel coordinates. - @param voxel_side Side of the voxel which is intersected here. - */ - void AddToFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , LegacyWorldCoordinate2D coord2D, unsigned int voxel_side ); - - - /*! @brief A new element of the type VoxelIntersectionsVectorPointer is inserted into the FieldOfIntersections and a first element - of type IntersectionsThisVoxel is inserted. - @param index_x X-position of the voxel of interest, which needs specification of its intersections. - @param index_y Y-position of the voxel of interest, which needs specification of its intersections. - @param index_z Z-position of the voxel of interest, which needs specification of its intersections. - @param struct_index Specifies the specific polygon and its respective PolygonInTermsOfIntersections which intersects here. - */ - void ExtendFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ); - - - /*! @brief In case FieldOfIntersections does already have an element of type VoxelIntersectionsVectorPointer in the position that - corresponds to the voxel in index_x , index_y , index_z, - the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index is returned. - @param index_x X-position of the voxel of interest. - @param index_y Y-position of the voxel of interest. - @param index_z Z-position of the voxel of interest. - @param struct_index Index of the polygon of interest. - @return Returns the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index. - */ - int GetRespectiveIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ) const; - - - /*! @brief This function calculates and returns the fraction of the voxel with index aDoseIndex that is enclosed by the strucure. - This fraction is between zero and one. - @param aDoseIndex Index of the voxel of interest. - @return Returns a number between zero and one that specifies the fraction of the voxel that is enclosed by the structure. - */ - float GetFractionInside( const LegacyDoseVoxelIndex3D& aDoseIndex ) ; - - - /*! @brief Gets a number of voxels that are known to have oldcolor via indexList. Takes a voxel from this list. Lets call it THEVOXEL. - Checks the neighbours of THEVOXEL. Each neighbour that does have oldcolor is appended to the list for further - investigation. Afterwards THEVOXEL is set to newcolor and taken from the list. Now the next voxel of the list is regarded ... - ... so it is now THEVOXEL ... and so on ... until the list is empty. - @param indexList List of indicees that are known to have oldcolor. - @param oldcolor The old color. - @param newcolor The new color. - @param resolution_level The resolution level which is currently regarded. - */ - void FloodFill4( UnsignedIndexList indexList ,int oldcolor,int newcolor,int resolution_level); - - - /*! @brief Old stuff. - */ - void setInsideVoxelPreviousVersion(int resolution_level); - - - /*! @brief Goes through MaskField over all resolution levels and sets all the mask voxels to the brightness that characterizes - those voxel that are not known to be outside, inside or border. Those voxels that do already have the brightness that - characterizes them as border are not changed here. - */ - void SetContentUnknown(); - - - /*! @brief This function calls FloodFill4 for those voxels that are known to be inside or outside although yet not denoted so in the - mask field. FloodFill4 will first investigate the neighbourhood of these voxels and then set them to the correct value. - @param resolution_level The resolution that is currently regarded. - @param indexListInside Voxels known to be inside, but yet not denoted so in the mask field. - @param indexListOutside Voxels known to be outside, but yet not denoted so in the mask field. - */ - void setInsideVoxel( int resolution_level, std::vector< UnsignedIndexList > indexListInside, std::vector< UnsignedIndexList > indexListOutside ); - - - /*! @brief This function is just for debugging. It prints out the number of voxels with specific brightness. - @param resolution_level The resolution_level of interest. - */ - void CountThisColor( int resolution_level ); - - - /*! @brief First this function determines the voxels that are yet not denoted inside or outside in the mask field, - but are directly in touch with voxels which are already known to be inside/outside and thus their affiliation is clear. - This is done for the resolution resolution_level. GetBorderRegion of Field.h is called to do this job, - if the resolution is not croasest. In case the resolution is croasest, this step is omitted. - In case of the croasest resolution this step is not necessary and thus omitted since - on the croasest resolution no voxel is yet known to be inside or outside. - Afterwards setInsideVoxel is called by - this function. - @param resolution_level The resolution level which is supposed to be regarded here. - */ - void setInsideVoxelMultiRes( int resolution_level ); - - - /*! @brief Transforms world coordinate in voxel coordinate. - @param z The world coordinate to be tranformed. - @return Returns the resulting voxel coordinate. - */ - LegacyWorldCoordinate1D GetZIndex( LegacyWorldCoordinate1D z ); - - - /*! @brief Provides _doseData with the absolute dose data of the voxels which are inside the structure. - */ - void calcDoseData(); - - - // private stuff that is just for test: - /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by - the structure and which is located in the same slice that is given by the z-position of aDoseIndex, if possible. - @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function in x and y, but not in z. - If things go well, aDoseIndex is set to a voxelposition within the slice in position z that is touched - by the structure. In that case the function returns true. - @return Returns false in case no voxel is touched by the structure within this slice. Otherways returns true. - */ - bool GetSomeBorderVoxelXYForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); - // end private stuff just for test - - - private: - void clearMaskField(); - - - }; -} +namespace rttb +{ + namespace masks + { + namespace legacy + { + + /*! @class Mask + * @brief This class represents the Mask calculated using a dose iterator and a StructureLegacy/DoseVoxelVector. + The mask is first calculated with voxel accurracy. Those voxels that are touched by the structure are then further + regarded using PolygonInfo and IterativePolygonInTermsOfIntersections to find out the fraction that is + inside the structure. + The voxelization is done on several resultution levels, but the calculation on subvoxel accurracy, + that means the calculation of the fraction of the voxel that is inside the structure, is done solely on the finest resolution level. + And solely for those voxels that are touched by the structure - typically most voxels are not. + This multi resolution approach is much faster as compared to doing it on just one level, + because a voxel that is not touched by the structure and determinded to be inside the structure on a + croase resolution level does on all finer resolution level solely correspond to voxels that are inside, too. The same + goes for a voxel that was determined to be completely outside: All the voxels that are contained in this voxel + on each finer resolution level are colpletely outside, too. So the creation of the mask without subvoxel accurracy is + done on the croasest resolution level completely and for each voxel with clear affiliation inside/outside all the + respective voxels are set for all the finer resolution levels right away as they are determined on a croase level. + It is cumputational effort to create several masks + and it is effort to set the inside/outside affiliation of a voxel on all levels instead of just one. However, it saves + effort, because on each finer resolution level, only view voxels + need to be considered: Those that are close to the contour and were thus touched by the contour on the previous level + that was to croase to tell the inside/outside affiliation. Since there is a factor four in the number of voxels between two levels, + the multi resouluton calculation is fast, because view voxels need to be regarded. + Field.h has an efficient way of finding those voxels with unclear affiliation and of setting affiliation throughout resoltuion levels in blocks. + After reaching the finest resolution those voxels that are still in the border region + and thus just touched by the structure are then further examined with subvoxel accurracy, based on + PolygonInfo and IterativePolygonInTermsOfIntersections. + + + */ + class Mask + { + + public: + + + /*! @brief Constructor with a DoseIterator and a StructureLegacy + * The mask is calculated with sub voxel fraction info. + @pre The Structure must not intersect itself. It may touch itself. + @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about + the dose value associated with each voxel. + @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. + * @exception RTTBNullPointerException thrown if aDoseIter or aStructure is NULL + */ + Mask(DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure); + + /*! @brief Constructor with a DoseIterator and a vector of DoseVoxel inside a structure (with voxel proportion information) + @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about + the dose value associated with each voxel. + @param aDoseVoxelVector is a reference to a vector that holds values of the type DoseVoxel. Using this parameter it is possible + to accept a given "voxelization" created by Mevis for example. + * @exception RTTBNullPointerException thrown if aDoseIter is NULL + */ + // Mask( DoseIteratorInterface* aDoseIter , const std::vector& aDoseVoxelVector ); + + /*! @brief Constructor with a DoseIterator and a StructureLegacy + * The mask is calculated with sub voxel fraction info. + @pre The Structure must not intersect itself. It may touch itself. + @param aGeoInfo is a pointer to a GeometricInfo of the dose. + @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. + * @exception RTTBNullPointerException thrown if aDoseGeoInfo or aStructure is NULL + */ + Mask(core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure); + + + /*! @brief Destructor + */ + ~Mask(); + + /*! @brief Old Code!!! It is unnecessary now. The user should check the geometric information of the new dose iterator, if changed, + generate new mask using Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure)! + + *Old brief: Reset dose. If the geometric information has not changed, the _doseVoxelInStructure does not need to be recalculated, in case + other dose values are introduced for the same structure and geometry. Only doseData needs to be recalculated. + @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about + the dose value associated with each voxel. + * @exception RTTBNullPointerException Thrown if aDoseIter or aStructure is NULL + + */ + void resetDose(DoseIteratorInterface* aDoseIterator); + + + + /*! @brief Get the dose voxels which lie inside the structure + * @return Vector of DoseVoxel which are inside the structure (with voxel proportion information) + */ + const std::vector& getDoseVoxelInStructure() const; + + /*! @brief Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) + * @param aDoseVoxelVector Vector of RTDoseVoxels inside the structure to be set. + * @return + */ + void setDoseVoxelInStructure(std::vector aDoseVoxelVector); + + /*! @brief Get the dose iterator + * @return DoseIteratorInterface& returns the dose Iterator. + */ + const DoseIteratorInterface& getDoseIterator() const; + + /*! @brief Get the structure + * @return StructureLegacy& Returns the structure. + */ + const StructureLegacy& getRTStructure() const; + + /*! @brief Get absolute dose data of the voxels which are inside the structure. + @return Returns the dose values. + */ + //const std::vector getDoseData() const; + + + /*new...................*/ + + /*! @brief Calculates 2D voxel coordinates from 2D world coordinates. + @param x voxel coordinate x + @param y voxel coordinate y + @return Returns 2D world coordinates. + */ + LegacyWorldCoordinate2D GetDoubleIndex2D(double x , double y); + /*! @brief Calculates 2D voxel coordinates from 2D world coordinates taking the current resolution level under consideration. + @param x voxel coordinate x + @param y voxel coordinate y + @param resolution_level current resolution + @return Returns 2D voxel coordinates. + */ + LegacyWorldCoordinate2D GetDoubleIndex2D(double x , double y, int resolution_level); + + /*! @brief The offset between world and voxel coordinate system depends on the current resolution. This function calculates this offset. + @param resolution_level current resolution + @return Returns the offset between world and voxel coordinate system. + */ + double GetWorldCoordinateOffsetThisResolutionLevel(int resolution_level); + + // Functions and other stuff needed for unit tests: + /*! @brief Needed for unit tests. Provides the Information about the Intersections of a specific polygon, + that is part of the structure, with the edges of the voxels. + @param position Index des polygon of interest. The structure consists of an entity of plygons. + @param Polygon_Intersections_Ref Refernce to an object of the Type PolygonInTermsOfIntersection. After running the function, this Reference holds the Information about + the intersections of the polygon of interest (specified by position) with the voxel edges. + @return This function returns false and does not do its job, in case "position" holds an unreasonalble value, e.g. refers to a + polygon that does not exist. + */ + bool GetIntersectionsOfSliceForTest(unsigned int position , + PolygonInTermsOfIntersections& Polygon_Intersections_Ref); + /*! @brief Needed for unit tests. Returns true in case there are any intersections of the structure with the voxel edges. + A reference to an integer is set to the index of the first polygon that intersects with voxel edges + in case there are intersections. Otherways the reference is set to zero and the function returns false. + @param position Some reference to some integer which is modified by this function. + In case there are any intersection this reference is set to the index of the first intersecting polygon. + Otherways it is set to zero. + @return Returns false in case there are no intersections and true in case there are intersections of the contour with the voxel edges. + */ + bool ReturnFirstWithIntersectionsForTest(unsigned int& position); + /*! @brief Needed for unit tests. This function is made to test the function GoIntersectColumn which is private and therefore not + accessible for the testing unit. This function called TestGoIntersectColumnByComparisonWithExpectedResult + is provided with two 3D Points and with a vector called expected_intersections_ref that holds the information about + those intersections that are to be expected. These values are set by the one who wrote the unit test. Now these expected + values are compared with those that are calculated by the function GoIntersectColumn and in case there is any deviation + between acutal an expected result this function here returns false. Otherwise it returns true. + + @param firstPoint The first one of two points that specify a line which is to be checked for intersections with voxel edges. + @param secondPoint The second one of two points that specify a line which is to be checked for intersections with voxel edges. + @param column_intersections_ref After running this function this reference to a vector of objects of the type LegacyWorldCoordinate2D + holds the information about the calculated intersections. + @param expected_intersections_ref This is a reference to a vector of objects of the type LegacyWorldCoordinate2D which holds the + information about the expected intersections. These intersections are set by the programmer + who writes the unit test and who knows the correct intersections. + @return This funciton returns true in case the function GoIntersectColumn turned out to work properly. Otherwise it returns false. + */ + bool TestGoIntersectColumnByComparisonWithExpectedResult(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , + std::vector& column_intersections_ref, + std::vector& expected_intersections_ref); + /*! @brief Needed for unit tests. See TestGoIntersectColumnByComparisonWithExpectedResult for details since this function here is very similar. + The only difference is that this funciton is made to help with unit testing with respect to the funcion GoIntersectRaw + instead of GoIntersectColumn - despite that its just the same. + */ + bool TestGoIntersectRawByComparisonWithExpectedResult(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, + std::vector& expected_intersections_ref); + /*! @brief Needed for unit tests. Checks whether two vectors of points that are passed to this function are identical. + @param calculated_intersections_ref First vector of points to be compared with the second one. + @param expected_intersections_ref Second vector of points to be compared with the first one. + @return Returns true in case the vectors are identical. + */ + bool IdenticalIntersectionsForTest(std::vector& + calculated_intersections_ref , std::vector& expected_intersections_ref); + /*! @brief Needed for unit tests. An object of the type PolygonInfo can only be created in an environment that has all the + incredients that are necessary. Since in Mask all the incredients are available and since there is no other environment, where this is the case, + since PolygonInfos are sofar not created anywhere else, this function was created, just in order to create and return a + PolygonInfo object for + test purposes. So this function creates an object of the type PolygonInfo and retunrns a pointer to it. + The PolygonInfo is created either for a voxel with cordinates aDoseIndex, given as a parameter + or alternatively for a voxel with greater + z-position in case there is no contour in the slice of the given location. In case there is no contour in any + slice with greater z-position either, the PolygonInfo can not be created. In that case a nullpointer is returned. + @param aDoseIndex Position for which the PolygonInfo object is to be created. + @return Returns an object of the type PolygonInfo in case a polygon of the structure can be found. Otherways it returns a NULL + pointer. + */ + PolygonInfo* JustCreateAPolygonInfoForTest(LegacyDoseVoxelIndex3D aDoseIndex); + /*! @brief Needed for unit tests. Checks for a specific voxel, whether the correct fraction of this voxel was recognized to be + enclosed by the structure. + @param another_dose_index parameter of type LegacyDoseVoxelIndex3D which specifies the voxel coordinate of interest. + @param the_correct_result is a float that specifies the expected result. + @return Returns true in case Mask did well and the calculated fraction meets the expectation. + */ + bool CheckFractionThisVoxelCorrectForTest(LegacyDoseVoxelIndex3D another_dose_index , + float the_correct_result); + /*! @brief Needed for unit tests in order to access the fraction of a specific voxel that was determined to be enclosed by the structure. + @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. + @return Returns a float that holds the informaton about the portion of the voxel which is enclosed by the structure. + */ + float GetFractionThisVoxelForTest(LegacyDoseVoxelIndex3D another_dose_index); + /*! @brief Needed for unit tests. Returns true in case the voxel specified by aDoseIndex is touched by the structure. + @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. + @return Returns true in case the voxel specified by aDoseIndex is touched by the structure. + */ + bool DoubleCheckIsOnBorderForTest(LegacyDoseVoxelIndex3D& aDoseIndex); + /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by the structure. + @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function. If things go well, + it is set to a voxelposition touched by the structure. In that case the function returns true. + @return Returns false in case no voxel is touched by the structure. Otherways returns true. + */ + bool GetSomeBorderVoxelXYZForTest(LegacyDoseVoxelIndex3D& aDoseIndex); + // End functions and other stuff needed for unit tests + + + + protected: + + typedef std::vector* VoxelIntersectionsVectorPointer; + + // @brief withSubVoxelFraction If true, the mask will be calculated with sub voxel fraction info; otherwise, without + // sub voxel fraction info, that means getDoseVoxelInStructure() returns the DoseVoxel with getProportionInStr()= 1. + // + //bool _withSubVoxelFraction; + + /// the dose iterator + DoseIteratorInterface* _doseIter; + /// the structure + StructureLegacy* _structure; + + /// vector of the RTDoseVoxels inside the structure + std::vector _doseVoxelInStructure; + + /// vector of the dose values corresponding to _doseVoxelInStructure, it has the same size as _doseVoxelInStructure + std::vector _doseData; + + /// geometric information about the dose distribution + std::vector< core::GeometricInfo > GInf; + + //VoxelIntersectionPointsMap voxel_intersectionPoints; + + /// Once they are determined to be inside voxels get this brightness. + field_content_type brightness_inside; + /// Once they are determined to be touched by the structure voxels get this brightness. + field_content_type brightness_border; + /// Once they are determined to be outside voxels get this brightness. + field_content_type brightness_outside; + /// Voxels that are yet not determinded to be inside the structure, outside the structure or touched by the structure are marked with this brightness. + field_content_type brightness_unknown; + + /// Calculates the mask. + void Calc(); + /// Just for test. Doublechecks and does assert(0) in case something has gone wrong. + void TestVoxelMaskUppward(); + + /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. + There are situations throughout the algorithm where it is known, that a specific affiliation of one voxel on one resolution + level does determine its affiliation on other resolution levels. The job of this function is to check that and to + assert, it terminates the program deliberately if something has happened, that definitely must never happen. + @param resolution_level_in Integer that species the current resolution level. + @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system + on the current resolution level that is to be checked throughout all finer levels. + @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. + */ + void CheckUppwardBlockSameIntensity(int resolution_level_in , LegacyUnsignedIndex3D index_internal , + int brightness); + /*! @brief This function sets a brightness of a voxel throughout resolution levels, since the Voxelisierung is done on + several resultution levels as explained above. + @param resolution_level_in Integer that species the current resolution level. + @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system + on the current resolution level that is to be set at first and then throughout all finer levels + adapted to the finer voxel coordinate sysetem. + @param brightness Integer that specifies the brightness that is to be set on the current and throughout all the finer resolution levels. + */ + void SetUppwardBlockThisIntensity(int resolution_level_in , LegacyUnsignedIndex3D index_internal , + int brightness); + /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. + There are situations where a specific affiliation of one voxel on one resolution + level does determine affiliation of at least one voxel on any finer resolution + level to the same intensity, within a specific block of voxels that corresponds to the voxel in position index_internal + on the croase level. + The job of this function is to check whether + there is any such voxel on every finer resolution level, within the respective block. + So this function terminates the program deliberately if something has happened, that definitely must never happen. + @param resolution_level_in Integer that species the current resolution level. + @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system + on the current resolution level that is to be checked throughout all finer levels. + @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. + */ + void CheckUppwardOneOutOfThisBlockHasSameIntensity(int resolution_level_in , + LegacyUnsignedIndex3D index_internal , int brightness); + /*! @brief Calculates for some resolution level the number of voxels of the finest resolution level, that fit into this + voxel one dimensionally. So this is a number of fine voxels that fit into this croase voxel along the length of this croase voxel. + @param resolution_level Integer that specifies the resolution level of the croase voxel. Whereas zero is the finest level, one the next + croase level with a total number of voxels of just one quater of the next finer level .... and so on .... + @return Returns a double that holds the information about the block length. Actually it should be an integer, but a double works, too ... + */ + double GetBlockLengthThisResolutionLevel(int resolution_level); + /*! @brief Checks the structure, so checks all polygons of the structure, on intersections with themselves. + @return Returns true, if the structure does not contain self intersecting polygons and thus is fine. + */ + bool ContourFine(); + /*! @brief Checks two polygons for intersection with one another. Checks one polygon for intersection with itself, in case + struct_index_a and struct_index_b are the same. + @param struct_index_a Integer that specifies the index of the first polygon that is to be checked for intersections. + @param struct_index_b Integer that specifies the index of the second polygon that is to be checked for intersections. + @return Returns true if the polygons do intersect (or if the polygon does intersect in case of a check for self intersection). + */ + bool DoesIntersect(int struct_index_a , int struct_index_b) const; + /*! @brief Checks two lines for intersection. + @param firstPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the first line. + @param secondPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the first line. + @param thirdPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the second line. + @param fourthPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the second line. + @return Returns true in case there is an intersection. + */ + bool HasIntersectionsThisPair(const LegacyWorldCoordinate3D& firstPoint , + const LegacyWorldCoordinate3D& secondPoint, const LegacyWorldCoordinate3D& thirdPoint , + const LegacyWorldCoordinate3D& fourthPoint) const; + + /*! Holds the masks for different resolution levels. + To be initialized in Constructor by an initialization function. + */ + std::vector< rttb::masks::legacy::FieldOfScalar* > MaskField; + + /*! Two dimensional field. + Content of one element holds the information about the intersections of the structure with + the voxel edges of the corresponding voxel. The object, that holds this intersecton information + for the voxel in position x,y within the slice, is located in the position x,y within FieldOfIntersections. + FieldOfIntersections is created for just one slice - the slice which Mask is currently working on. + */ + rttb::masks::legacy::FieldOfPointer* FieldOfIntersections; + + bool do_detailed_subvox; /// If do_detailed_subvox is true, the Mask is calculated with sub-voxel accurracy. + + /*! To be initialized in Constructor by an initialization function. + Holds the information about the structure and its Intersections with the voxel edges. + */ + std::vector + Intersections; ///Holds the information about the structure and its Intersections with the voxel edges. + + /*! @brief Fills _doseVoxelInStructure with DoseVoxel objects. Each of these DoseVoxel objects carries the information about the + portion of the voxel that is enclosed by the structure. The DoseVoxel objects are created based on the Mask + with the finest resolution. Based on this Mask field it is clear that the voxel is completely inside the structure or + completely outside in most of the cases. + SetDoseVoxelInStructureVector calls GetFractionInside() and thus determines the fraction + of the voxel that is enclosed by the structure in case the voxel is touched by the structure and thus + not yet determined to be completely inside or outside. + */ + void SetDoseVoxelInStructureVector(); + + + /*! @brief Old stuff. + */ + void SeperateRegions(); + + /*! @brief Old stuff. + */ + void SeperateRegionsQuick(); + + /*! @brief Old Stuff. + */ + void ConnectArea(field_content_type brightness_from , field_content_type brightness_to , + LegacyUnsignedIndex3D start_index, LegacyDoseVoxelIndex2D index_begin, + LegacyDoseVoxelIndex2D index_end); // To be called by SetDoseVoxelInStructureVector + + /*! @brief To be initialized by an init function that is called by Constructor. Holds the information about how the polygons correspond to the slices. + */ + std::vector SliceStructureCorrespondency; + + + /*! @brief To be initialized by an init fuction which is called by Constructor. Contains the information about which area of the image is actually to be regarded. A large part of the image may be far off from any polygon. + */ + vector_of_area_vectors MarkInterestingArea; + + + /*! @brief Is called by the constructor and calls other initialization fucntions. + */ + void Init(); + + + /*! @brief Searches backward in Intersections until a point is reached that differs from compare_point. + point_index is set to the index of this point. + @param struct_index Reference to an integer that specifies the polygon of interest. + @param point_index Reference to an integer that is modified by this function. + First it specifies the index of the point where the function stearts searching. + It is decremented during the search and in the end it points to the first point within the search direction + that turned out to be different from compare_point. + @param compare_point Parameter of the type LegacyWorldCoordinate3D. Specifies a point. This function searches for a point + which differs from compare_point. + @return Returns true in case such a point was found and false in case it was not. + */ + bool GetFirstDifferent(unsigned int& struct_index , unsigned int& point_index , + LegacyWorldCoordinate3D compare_point); + + + + /*! @brief This function determines whether the intersection with struct_index, point_index and intersect_index + is to be set to the FieldOfIntersections. It is to be set in case the intersection with the voxeledge is either + not a point of the polygon, or in case it is ( that means the point of the polygon is on the edge of a voxel ) + and at the same time the previous point of the polygon has one identical coordinate in a way so that it is located on + the same edge, too (eventually alongside another voxel, so the same edge here means "same column seperating voxels"). + @param struct_index Index of the polygon. + @param point_index Index of the point within the polygon (last one between the intersection that is currently being processed). + @param intersect_index Index of the intersection that is currently being processed. + @param index_x X-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. + @param index_y Y-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. + @return Retruns true in case the intersection with struct_index, point_index and intersect_index is to be set to the + FieldOfIntersections. + */ + bool IsItToBeRegarded(unsigned int struct_index , unsigned int point_index , + unsigned int intersect_index , int index_x , int index_y); + + + + /*! @brief This function calls SetThisIntersection with the respective parameters and therefore takes part in positioning the intersection characterized by the + parameter intersection within the FieldOfIntersections. + @param index_x X-position of the voxel. + @param index_y Y-position of the voxel. + @param intersection Specifies the intersection that is currently regarded (similar to an index, specifies location where the intersection can be found within the object Intersections). + @param coord2D Voxel coordinate of the intersection. + @param edge_number Denotes the edge which the intersection is on. + @param voxel_intersections The element within FieldOfIntersections that corresponds to this voxel and polygon. + */ + void SetThisIntersectionToCornerOrEdge(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D, unsigned int edge_number, + IntersectionsThisVoxel& voxel_intersections); + + + /*! @brief This function positions an intersection within voxel_intersections. Practically voxel_intersections is an element within FieldOfIntersections (generally it can be any reference to an IntersectionsThisVoxel ). + The voxel edge the intersection is placed to is given by edge_number. + @param corner_of_interest The corner at the beginning of the respective edge. Beginning means the point of the edge that is first passed while surrounding the voxel clockwise. + @param corner_next The corner at the end of the respective edge. That means the point along the edge that is passed last while surrounding the voxel clockwise. + @param corner_fixed Its the coordinate, which is the same all along the edge. + @param intersection Denotes the index of the regarded intersection in Intersections. + @param coord_of_interest The coordinate which is interesting, because it is responsible for the position of the intersection along the edge, while the other coordinate is just the same for the intersection as well as for all the points that belong to the edge. + @param coord_fixed This coordinate should equal to corner_fixed. The function asserts for that. Its the coordinate that all the points on the edge and the intersection point have in common. + @param voxel_intersections Practically its an element of FieldOfIntersections (although generally it can be any element of IntersectionsThisVoxel). + @param edge_number Number of the edge that is regarded. The edges are counted colckwise starting from upper left. + */ + void SetThisIntersection(unsigned int corner_of_interest, unsigned int corner_next , + unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection + , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , + unsigned int edge_number); + + + /*! @brief This function checks whether value_to_compare is in between small_value_to_compare_with and big_value_to_compare_with. Practically value_to_compare is a coordinate of an intersection point. Practically big_value_to_compare_with is the end point of an edge. + In case value_to_compare is in between, the index of the intersection (that characterizes its location within Intersections (Intersections is a global variabele, a vector of StructureInTermsOfIntersections) ) and its coordinates are appended to the corresponding edge within voxel_intersections. + @param value_to_compare This value is to be compared with other values and inserted into voxel_intersections at the right place. + @param small_value_to_compare_with First value to compare with. + @param big_value_to_compare_with Second value to compare with. + @param edge_number Number of the edge. Edges are counted clockwise, starting from upper left. + @param intersection Index of the intersection within Intersections. + @param voxel_intersections Object of type IntersectionsThisVoxel that holds the information about all the intersections of the structure with this currently regarded voxel as well as the information where to find these intersection within Intersections + @return Retruns true in case insertation was successful. + */ + bool CompareIfBetweenAppend(double value_to_compare , double small_value_to_compare_with , + double big_value_to_compare_with, unsigned int edge_number, + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections); + + + /*! @brief This function checks whether the intersection point is already known. + In case it is the index of the intersection within Intersections is appended to the already existing vector of points of the respective edge that all represent this specific intersection point (in case the structure goes through this point several times touching itself, otherways ist just one) + (Intersections is a global variable, a vector of StructureInTermsOfIntersections which contains the information about all the intersections with all the voxel edges on all resolutions). + In case it does not exist yet a new vector of indices as well as coordinates is created and inserted in the respective position. + In case the same intersection point will be found again later on it will be appended then. + @param value_to_compare Coordinate of the point to be inserted. + @param edge_number Number of the edge. The edges are counted clockwise, starting from upper left. + @param intersection Index of the intersectoin within Intersections. + @param voxel_intersections An object representing the information about the intersections of the structure with this voxel, including the information about coordinates of the intersection points as well as indicees that represent the information about where to find them within Intersections. + @return Returns true in case of a successful insertation. + */ + bool CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert(double value_to_compare , + unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections); + + + /*! @brief See CompareIfBetweenAppend - the only difference is, that this function inserts the intersection at the beginning of the edge and that practically small_value_to_compare_with is the first point within the respective edge while big_value_to_compare_with is either the first intersection that has aleready been found, or the last point within the edge. + @return Returns true in case the intersection was inserted into voxel_intersections. + */ + bool CompareIfBetweenInsertAtBeginning(double value_to_compare , + double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + IntersectionsThisVoxel& voxel_intersections); + + + /*! @brief Old stuff. + */ + void SetThisIntersectionXIncreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , + unsigned int edge_number); + /*! @brief Old stuff. + */ + void SetThisIntersectionYIncreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections); + /*! @brief Old stuff. + */ + void SetThisIntersectionXDecreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections); + /*! @brief Old stuff. + */ + void SetThisIntersectionYDecreasing(unsigned int index_x , unsigned int index_y , + IterativePolygonInTermsOfIntersections::WhichIntersection intersection , + LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections); + + + /*! @brief This function determines the area that contains voxels that need to be regarded. + For example voxels within x-coordinate lower than the contour pont with lowest x-coordinate do not need to be regarded, since they can + not be enclosed by the contor. Of course the same goes for other coordintates and ... + */ + void InitInterestingArea(); + /*! @brief Initializes MaskField which contains the masks fields for different resolution levels and the corresponding geometric infromation stored in GInf. + Different sizes are initialized, representing the different resolutions. Calls InitIntersections. + */ + void InitMultiResolution(); + /*! @brief Initializes Intersections which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. + This function just initializes, but yet does not calculate the intersections, so here Intersectons is created, but remains empty. + */ + void InitIntersections(); + + /*! @brief This function is called to calculate the intersections between structure and voxel edges and thus to fill + Intersections with intersecton values, which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. + @param resolution_level Specifies for which voxel grid the intersections are to be calculated. In case it is zero it is done for the + finest resolution and the values are filled into the first element of Intersections. + */ + void GetIntersections(int resolution_level); + + /*! @brief This function fills intersections_raw_and_column_ref with intersection values. It operates on a segment of a polygon consisting of a line that connects a first and a second point. + The intersections of this polygon segment with the voxel edges on the resolution_level are already determined and stored in + raw_intersections_ref, which contains the intersections with raw-eges as well as + column_intersections_ref which holds the intersections with the voxel edges regarding columns. + In intersections_raw_and_column_ref they are sorted with respect to their distance + from firstPoint and in the end intersections_raw_and_column_ref contains all the intersections - colum and raw intersections. + @param firstPoint Starting point of the segment of the polygon. + @param raw_intersections_ref Contains the raw intersections sorted with resepect to their distance from firstPoint. + @param column_intersections_ref Contains the column intersections sorted with resepect to their distance from firstPoint. + @param intersections_raw_and_column_ref After running this function intersections_raw_and_column_ref contains all intersections sorted with resepect to their distance from firstPoint. + @param resolution_level The resolution level. Zero is finest. + */ + void UnifyRawAndColumn(LegacyWorldCoordinate3D firstPoint, + std::vector& raw_intersections_ref , + std::vector& column_intersections_ref , + std::vector& intersections_raw_and_column_ref, int resolution_level); + + + /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). + The line starts with firstPoint and ends with secondPoint. + @param firstPoint Point to start the line. + @param secondPoint point to end the line. + @param raw_intersections_ref The intersections are placed here. + @param resolution_level The current resolution. + */ + void GoIntersectRaw(LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , + std::vector& raw_intersections_ref , int resolution_level); + + + /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). + The line starts with firstPoint and ends with secondPoint + @param firstPoint Point to start the line. + @param secondPoint point to end the line. + @param column_intersections_ref The intersections are placed here. + @param resolution_level The current resolution. + */ + void GoIntersectColumn(LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , + std::vector& column_intersections_ref, int resolution_level); + + + /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). + The line starts with firstPoint and ends with secondPoint. + This function is called in case the x-position of firstPoint and secondPoint are identical. + @param firstPoint Point to start the line. + @param secondPoint point to end the line. + @param raw_intersections_ref The intersections are placed here. + @param resolution_level The current resolution. + */ + void GoGetRawIntersectionsAlongThisColumn(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, + int resolution_level); + + + /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). + The line starts with firstPoint and ends with secondPoint. This function is called only in case the y-position of first and of + second point are identical. + @param firstPoint Point to start the line. + @param secondPoint point to end the line. + @param column_intersections_ref The intersections are placed here. + @param resolution_level The current resolution. + */ + void GoGetColumnIntersectionsAlongThisRaw(LegacyWorldCoordinate3D firstPoint , + LegacyWorldCoordinate3D secondPoint , + std::vector& column_intersections_ref, int resolution_level); + + + /*! @brief This function prints out all the intersections with cout. Normally its not called, but sometimes its needed for debugging. + */ + void ShowIntersections(); + + + /*! @brief Based on the global variable Intersections that holds the information about the intersections betweent the voxel edges and + the polygons this function determines all voxels that are touched by the structure on resolution_level. So this operation + is carried out for the mask field that belongs to resolution_level. For resolution_level equal to zero its the finest + resolution and so the resolution of the mask field is the resolution of the dose distribution. + */ + void MarkVoxelsTouchedByStructure(int resolution_level); + + + /*! @brief Sets FieldOfIntersections for the current slice. This is done based on Intersections which stores the information about the + polygons and their intersections. + @param index_z Integer that represents the index of the slice which is to be regarded. + */ + void GetIntersectionInformationThisSlice(unsigned int index_z); + + + /*! @brief The intersection with voxel coordinates coord2D is inserted into + the FieldOfIntersectons in position of voxel (index_x , index_y , index_z) and for the polygon with index struct_index + and for the side of the voxel denoted by voxel_side. + @param index_x X-position of the voxel. + @param index_y Y-position of the voxel. + @param index_z Z-position of the voxel. + @param struct_index Index of the polygon that is intersecting here. + @param point_index Index of the last polygon point before the intersection. + @param intersect_index Index of the intersection. By the way also represents the information about how many intersections with voxel edges are in between this intersection with voxel edge and the last polygon point. + @param coord2D Intersection in voxel coordinates. + @param voxel_side Side of the voxel which is intersected here. + */ + void AddToFieldOfIntersections(unsigned int index_x , unsigned int index_y , unsigned int index_z , + unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , + LegacyWorldCoordinate2D coord2D, unsigned int voxel_side); + + + /*! @brief A new element of the type VoxelIntersectionsVectorPointer is inserted into the FieldOfIntersections and a first element + of type IntersectionsThisVoxel is inserted. + @param index_x X-position of the voxel of interest, which needs specification of its intersections. + @param index_y Y-position of the voxel of interest, which needs specification of its intersections. + @param index_z Z-position of the voxel of interest, which needs specification of its intersections. + @param struct_index Specifies the specific polygon and its respective PolygonInTermsOfIntersections which intersects here. + */ + void ExtendFieldOfIntersections(unsigned int index_x , unsigned int index_y , unsigned int index_z , + unsigned int struct_index); + + + /*! @brief In case FieldOfIntersections does already have an element of type VoxelIntersectionsVectorPointer in the position that + corresponds to the voxel in index_x , index_y , index_z, + the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index is returned. + @param index_x X-position of the voxel of interest. + @param index_y Y-position of the voxel of interest. + @param index_z Z-position of the voxel of interest. + @param struct_index Index of the polygon of interest. + @return Returns the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index. + */ + int GetRespectiveIntersections(unsigned int index_x , unsigned int index_y , unsigned int index_z , + unsigned int struct_index) const; + + + /*! @brief This function calculates and returns the fraction of the voxel with index aDoseIndex that is enclosed by the strucure. + This fraction is between zero and one. + @param aDoseIndex Index of the voxel of interest. + @return Returns a number between zero and one that specifies the fraction of the voxel that is enclosed by the structure. + */ + float GetFractionInside(const LegacyDoseVoxelIndex3D& aDoseIndex) ; + + + /*! @brief Gets a number of voxels that are known to have oldcolor via indexList. Takes a voxel from this list. Lets call it THEVOXEL. + Checks the neighbours of THEVOXEL. Each neighbour that does have oldcolor is appended to the list for further + investigation. Afterwards THEVOXEL is set to newcolor and taken from the list. Now the next voxel of the list is regarded ... + ... so it is now THEVOXEL ... and so on ... until the list is empty. + @param indexList List of indicees that are known to have oldcolor. + @param oldcolor The old color. + @param newcolor The new color. + @param resolution_level The resolution level which is currently regarded. + */ + void FloodFill4(UnsignedIndexList indexList , int oldcolor, int newcolor, int resolution_level); + + + /*! @brief Old stuff. + */ + void setInsideVoxelPreviousVersion(int resolution_level); + + + /*! @brief Goes through MaskField over all resolution levels and sets all the mask voxels to the brightness that characterizes + those voxel that are not known to be outside, inside or border. Those voxels that do already have the brightness that + characterizes them as border are not changed here. + */ + void SetContentUnknown(); + + + /*! @brief This function calls FloodFill4 for those voxels that are known to be inside or outside although yet not denoted so in the + mask field. FloodFill4 will first investigate the neighbourhood of these voxels and then set them to the correct value. + @param resolution_level The resolution that is currently regarded. + @param indexListInside Voxels known to be inside, but yet not denoted so in the mask field. + @param indexListOutside Voxels known to be outside, but yet not denoted so in the mask field. + */ + void setInsideVoxel(int resolution_level, std::vector< UnsignedIndexList > indexListInside, + std::vector< UnsignedIndexList > indexListOutside); + + + /*! @brief This function is just for debugging. It prints out the number of voxels with specific brightness. + @param resolution_level The resolution_level of interest. + */ + void CountThisColor(int resolution_level); + + + /*! @brief First this function determines the voxels that are yet not denoted inside or outside in the mask field, + but are directly in touch with voxels which are already known to be inside/outside and thus their affiliation is clear. + This is done for the resolution resolution_level. GetBorderRegion of Field.h is called to do this job, + if the resolution is not croasest. In case the resolution is croasest, this step is omitted. + In case of the croasest resolution this step is not necessary and thus omitted since + on the croasest resolution no voxel is yet known to be inside or outside. + Afterwards setInsideVoxel is called by + this function. + @param resolution_level The resolution level which is supposed to be regarded here. + */ + void setInsideVoxelMultiRes(int resolution_level); + + + /*! @brief Transforms world coordinate in voxel coordinate. + @param z The world coordinate to be tranformed. + @return Returns the resulting voxel coordinate. + */ + LegacyWorldCoordinate1D GetZIndex(LegacyWorldCoordinate1D z); + + + /*! @brief Provides _doseData with the absolute dose data of the voxels which are inside the structure. + */ + void calcDoseData(); + + + // private stuff that is just for test: + /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by + the structure and which is located in the same slice that is given by the z-position of aDoseIndex, if possible. + @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function in x and y, but not in z. + If things go well, aDoseIndex is set to a voxelposition within the slice in position z that is touched + by the structure. In that case the function returns true. + @return Returns false in case no voxel is touched by the structure within this slice. Otherways returns true. + */ + bool GetSomeBorderVoxelXYForTest(LegacyDoseVoxelIndex3D& aDoseIndex); + // end private stuff just for test + - } -} + private: + void clearMaskField(); + + + }; + } + + } +} -#endif \ No newline at end of file +#endif \ No newline at end of file diff --git a/code/masks/legacy/rttbMaskType_LEGACY.h b/code/masks/legacy/rttbMaskType_LEGACY.h index 20291af..2fef06a 100644 --- a/code/masks/legacy/rttbMaskType_LEGACY.h +++ b/code/masks/legacy/rttbMaskType_LEGACY.h @@ -1,117 +1,123 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MASK_TYPE_H #define __MASK_TYPE_H #include "rttbBaseType_LEGACY.h" #include -namespace rttb{ - namespace masks{ +namespace rttb +{ + namespace masks + { namespace legacy - { - - /*! @brief PointLevelVector - This structure represents one point of the structure and the intersections of the following - contour segment with the voxel edges. Contour segment, that is a line connecting this contour point and the next one. - contour_point_voxel_coord represents the contour point in voxel coordinates. - intersections_raw_and_column represents all the intersections with the voxel eges sorted in a way, - so that the one that is closest to the contour point represented by this PointLevelVector is the first one. - The one that is furthest from the contour point represented by this PointLevelVector is the last one - that appears in intersections_raw_and_column. - raw_intersections is just like intersections_raw_and_column, but represents the intersections with the voxel edges - that are parallel to the voxel raws. - column_intersections is like raw_intersections but represents the intersections with the voxel edges that - are parallel to the voxel columns. - */ - - struct PointLevelVector{ - - PointLevelVector(){ - to_be_Regarded = 1; - } - - ~PointLevelVector(){ - raw_intersections.clear(); - column_intersections.clear(); - intersections_raw_and_column.clear(); - } - - std::vector raw_intersections; - std::vector column_intersections; - std::vector intersections_raw_and_column; - LegacyWorldCoordinate3D contour_point_voxel_coord; - - bool to_be_Regarded; - }; - - /*! @typedef correspoinding_structure_vector - */ - typedef std::vector correspoinding_structure_vector; - - /*! @typedef PolygonLevelVector - */ - typedef std::vector PolygonLevelVector; - - /*! @typedef SliceLevelVector - */ - typedef std::vector SliceLevelVector; - - /*! @typedef field_content_type - */ - typedef int field_content_type; - - /*! @typedef VoxelIntersectionPointsMap - */ - typedef std::map< LegacyDoseVoxelIndex3D,std::vector > VoxelIntersectionPointsMap; - - /*! @brief Characterizes the relationship between the voxel edge (in this position that this CharacterizeIntersection object belongs to) - and the contour that is in touch with the edge right here. - real_intersection for example means that here the structure really intersects the voxel edge. - inside_to_edge means that the structure, coming from inside the voxel touches the voxel edge here and then runs along the voxel edge, touching rather than intersecting. - edge_to_edge means that the structure goes along the edge and has a contour point here. So it comes and goes along the edge and has a point here. - outside_to_edge means that here the contour comes from outside the voxel and continues to run along the edge. So here in this position represented by this CharacterizeIntersection the contour does not actually run into the voxel. - inside_inside_touches means that the contour comes from inside the voxel, does have a point here in this position right on the edge and continues its way going back into the voxel. So the contour just touches the voxel edge and does not really intersect here. - corner : this is just a corner. - unknown nobody knows what that is. - */ - enum CharacterizeIntersection{ unknown = -1 , real_intersection = 0 , edge_to_edge = 1 , inside_to_edge = 2 , edge_to_inside = 3 , outside_to_edge = 4 , edge_to_outside = 5 , inside_inside_touches = 6, outside_outside_touches = 7, corner = 8 }; - - typedef LegacyPolygonType::iterator LegacyPolygonTypeIterator; - - typedef std::vector PolygonInTermsOfIntersections; - - typedef std::vector StructureInTermsOfIntersections; - - typedef std::list UnsignedIndexList; + { + + /*! @brief PointLevelVector + This structure represents one point of the structure and the intersections of the following + contour segment with the voxel edges. Contour segment, that is a line connecting this contour point and the next one. + contour_point_voxel_coord represents the contour point in voxel coordinates. + intersections_raw_and_column represents all the intersections with the voxel eges sorted in a way, + so that the one that is closest to the contour point represented by this PointLevelVector is the first one. + The one that is furthest from the contour point represented by this PointLevelVector is the last one + that appears in intersections_raw_and_column. + raw_intersections is just like intersections_raw_and_column, but represents the intersections with the voxel edges + that are parallel to the voxel raws. + column_intersections is like raw_intersections but represents the intersections with the voxel edges that + are parallel to the voxel columns. + */ + + struct PointLevelVector + { + + PointLevelVector() + { + to_be_Regarded = 1; + } + + ~PointLevelVector() + { + raw_intersections.clear(); + column_intersections.clear(); + intersections_raw_and_column.clear(); + } + + std::vector raw_intersections; + std::vector column_intersections; + std::vector intersections_raw_and_column; + LegacyWorldCoordinate3D contour_point_voxel_coord; + + bool to_be_Regarded; + }; + + /*! @typedef correspoinding_structure_vector + */ + typedef std::vector correspoinding_structure_vector; + + /*! @typedef PolygonLevelVector + */ + typedef std::vector PolygonLevelVector; + + /*! @typedef SliceLevelVector + */ + typedef std::vector SliceLevelVector; + + /*! @typedef field_content_type + */ + typedef int field_content_type; + + /*! @typedef VoxelIntersectionPointsMap + */ + typedef std::map< LegacyDoseVoxelIndex3D, std::vector > + VoxelIntersectionPointsMap; + + /*! @brief Characterizes the relationship between the voxel edge (in this position that this CharacterizeIntersection object belongs to) + and the contour that is in touch with the edge right here. + real_intersection for example means that here the structure really intersects the voxel edge. + inside_to_edge means that the structure, coming from inside the voxel touches the voxel edge here and then runs along the voxel edge, touching rather than intersecting. + edge_to_edge means that the structure goes along the edge and has a contour point here. So it comes and goes along the edge and has a point here. + outside_to_edge means that here the contour comes from outside the voxel and continues to run along the edge. So here in this position represented by this CharacterizeIntersection the contour does not actually run into the voxel. + inside_inside_touches means that the contour comes from inside the voxel, does have a point here in this position right on the edge and continues its way going back into the voxel. So the contour just touches the voxel edge and does not really intersect here. + corner : this is just a corner. + unknown nobody knows what that is. + */ + enum CharacterizeIntersection { unknown = -1 , real_intersection = 0 , edge_to_edge = 1 , inside_to_edge = 2 , edge_to_inside = 3 , outside_to_edge = 4 , edge_to_outside = 5 , inside_inside_touches = 6, outside_outside_touches = 7, corner = 8 }; + + typedef LegacyPolygonType::iterator LegacyPolygonTypeIterator; + + typedef std::vector PolygonInTermsOfIntersections; + + typedef std::vector StructureInTermsOfIntersections; + + typedef std::list UnsignedIndexList; } - } -} + } +} -#endif \ No newline at end of file +#endif \ No newline at end of file diff --git a/code/masks/legacy/rttbOTBMaskAccessor.cpp b/code/masks/legacy/rttbOTBMaskAccessor.cpp index bb9c727..035c5e5 100644 --- a/code/masks/legacy/rttbOTBMaskAccessor.cpp +++ b/code/masks/legacy/rttbOTBMaskAccessor.cpp @@ -1,186 +1,186 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbOTBMaskAccessor.h" #include "rttbMappingOutsideOfImageException.h" #include #include #include #include namespace rttb { namespace masks { namespace legacy { OTBMaskAccessor::OTBMaskAccessor(StructTypePointer aStructurePointer, - const core::GeometricInfo& aGeometricInfo) + const core::GeometricInfo& aGeometricInfo) : _spStructure(aStructurePointer), _legacyStructure(*aStructurePointer) { _spRelevantVoxelVector = MaskVoxelListPointer(); _geoInfo = aGeometricInfo; //generate new structure set uid boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "OTBMask_" + ss.str(); } OTBMaskAccessor::~OTBMaskAccessor() { }; void OTBMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; // already calculated } legacy::Mask legacyMask(&_geoInfo , &_legacyStructure); //translate result to expected values const std::vector voxelsInStruct = legacyMask.getDoseVoxelInStructure(); for (std::vector::const_iterator it = voxelsInStruct.begin(); - it != voxelsInStruct.end(); ++it) + it != voxelsInStruct.end(); ++it) { rttb::VoxelGridID aVoxelGridID; rttb::VoxelGridIndex3D newIndex; legacy::LegacyDoseVoxelIndex3D oldIndex = it->getVoxelIndex3D(); newIndex(0) = oldIndex.x; newIndex(1) = oldIndex.y; newIndex(2) = oldIndex.z; // new architecture if (!_geoInfo.convert(newIndex, aVoxelGridID)) { throw core::MappingOutsideOfImageException("mapping outside of image occurred!"); } core::MaskVoxel newMaskVoxel(aVoxelGridID); newMaskVoxel.setRelevantVolumeFraction(it->getProportionInStr()); newRelevantVoxelVector.push_back(newMaskVoxel); } _spRelevantVoxelVector = boost::make_shared(newRelevantVoxelVector); return; } OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector() { // if not already generated start voxelization here updateMask(); return _spRelevantVoxelVector; } OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector(float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); // filter relevant voxels OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } bool OTBMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } //aID is not in mask voxel.setRelevantVolumeFraction(0); } // returns false if mask was not calculated without triggering calculation (otherwise not const!) else { return false; } return false; } bool OTBMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } } } } \ No newline at end of file diff --git a/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp b/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp index 2bcd98a..df95d5c 100644 --- a/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp +++ b/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp @@ -1,3966 +1,5034 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbMask.h" #include "rttbPolygonInfo_LEGACY.h" #include "rttbNullPointerException.h" -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { + + PolygonInfo::PolygonInfo(const LegacyPolygonType& the_polygon_in, int polygon_number_in, + field_content_type brightness_outside_in , field_content_type brightness_inside_in , + FieldOfScalar* MaskFieldReceived_in , + const PolygonInTermsOfIntersections& Polygon_Intersections_In , + const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn , + const IntersectionsThisVoxel& intersections_this_voxel_in): the_polygon(the_polygon_in) , + voxel_intersections(intersections_this_voxel_in) + { - PolygonInfo::PolygonInfo( const LegacyPolygonType& the_polygon_in, int polygon_number_in, field_content_type brightness_outside_in , field_content_type brightness_inside_in , FieldOfScalar* MaskFieldReceived_in , const PolygonInTermsOfIntersections& Polygon_Intersections_In , const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn , const IntersectionsThisVoxel& intersections_this_voxel_in ): the_polygon( the_polygon_in ) , voxel_intersections( intersections_this_voxel_in) { + if (MaskFieldReceived_in == NULL) + { + assert(0); + } + else + { + MaskFieldReceived = MaskFieldReceived_in; + } - if( MaskFieldReceived_in == NULL ){ - assert( 0 ); - } - else{ - MaskFieldReceived = MaskFieldReceived_in; - } - brightness_outside = brightness_outside_in; + brightness_outside = brightness_outside_in; - brightness_inside = brightness_inside_in; + brightness_inside = brightness_inside_in; - SetDoseIndex( aDoseIndex ); + SetDoseIndex(aDoseIndex); - pol_inf_vec.clear(); + pol_inf_vec.clear(); - PolygonInfoVectorOfEdges& pol_inf_vec_ref = pol_inf_vec; + PolygonInfoVectorOfEdges& pol_inf_vec_ref = pol_inf_vec; - GInformation = GInfIn; + GInformation = GInfIn; - SetCurrentPosition( aDoseIndex ); + SetCurrentPosition(aDoseIndex); - it_poly.SetIntersectionsAndResetIntersectionIndex( Polygon_Intersections_In ); - - voxel_intersections.SetPolygonNumber( polygon_number_in ); - } - - void PolygonInfo::CalcSnippetVectors(){ - VoxelIntersectionIndex next_voxel_intersection; + it_poly.SetIntersectionsAndResetIntersectionIndex(Polygon_Intersections_In); - pol_inf_vec.resize(0); + voxel_intersections.SetPolygonNumber(polygon_number_in); + } - for( int voxel_edge = 0 ; voxel_edge < 4 ; voxel_edge++ ){ + void PolygonInfo::CalcSnippetVectors() + { + VoxelIntersectionIndex next_voxel_intersection; - next_voxel_intersection.reset(); + pol_inf_vec.resize(0); - current_edge = voxel_edge; + for (int voxel_edge = 0 ; voxel_edge < 4 ; voxel_edge++) + { + + next_voxel_intersection.reset(); - snippet_vector snip_vec; + current_edge = voxel_edge; - snippet_vector& snip_vec_ref = snip_vec; + snippet_vector snip_vec; - SetCurrentPositionToEdge( voxel_edge ); - - std::vector snip_vec_local; - snippet_vector& snip_vec_ref_local = snip_vec_local; + snippet_vector& snip_vec_ref = snip_vec; - bool finished = false; + SetCurrentPositionToEdge(voxel_edge); - while( finished == false ){ - finished = AppendNextIntersectionAndCorrespoindingPolygonSnippets( snip_vec_ref_local, snip_vec_ref , voxel_edge, next_voxel_intersection ); - } + std::vector snip_vec_local; + snippet_vector& snip_vec_ref_local = snip_vec_local; - pol_inf_vec.push_back( snip_vec ); - } + bool finished = false; - AppendEdges( pol_inf_vec ); + while (finished == false) + { + finished = AppendNextIntersectionAndCorrespoindingPolygonSnippets(snip_vec_ref_local, snip_vec_ref , + voxel_edge, next_voxel_intersection); + } - it_poly.ResetIntersectionIndex(); - } + pol_inf_vec.push_back(snip_vec); + } - void PolygonInfo::ShowSnippet( PolygonSnippet a_snippet ){ - std::cout<< " a_snippet.i_have_been_processed : " << a_snippet.i_have_been_processed <GetData( 0, 0, 0 ) < 0 ) - { - gone_well = false; - std::cout<< " Mask field values must not be below zero ! " <( pol_snip_a.point_of_interest_start.x ) != static_cast( pol_snip_b.point_of_interest_start.x ) ) - { - return false; - } - if( static_cast( pol_snip_a.point_of_interest_start.y ) != static_cast( pol_snip_b.point_of_interest_start.y ) ) - { - return false; - } - if( static_cast( pol_snip_a.point_of_interest_end.y ) != static_cast( pol_snip_b.point_of_interest_end.y ) ) - { - return false; - } - if( static_cast( pol_snip_a.why_here.x ) != static_cast( pol_snip_b.why_here.x ) ) - { - return false; - } - if( static_cast( pol_snip_a.why_here.y ) != static_cast( pol_snip_b.why_here.y ) ) - { - return false; - } - if( pol_snip_a.snippet_intermediate_content.size() != pol_snip_b.snippet_intermediate_content.size() ) - { - return false; - } - - for( GridIndexType counter = 0 ; counter < pol_snip_a.snippet_intermediate_content.size() ; counter++ ){ - if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).x ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).x ) ) - { - return false; - } - if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).y ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).y ) ) - { - return false; - } - if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).z ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).z ) ) - { - return false; - } - } - return true; - } - - - bool PolygonInfo::CompareCalculatedAndExpectedResultingSequenceForTest( LegacyPolygonSequenceType& expected_resulting_sequence_ref ){ - if( expected_resulting_sequence_ref.size() > resulting_sequence.size() ) - { - std::cout<< " Size ! " <(the_dose_index.x); - current_position.y = static_cast(the_dose_index.y); - break; - case 1 : - current_position.x =static_cast(the_dose_index.x + 1); - current_position.y = static_cast(the_dose_index.y); - break; - case 2 : - current_position.x =static_cast(the_dose_index.x + 1); - current_position.y = static_cast(the_dose_index.y + 1); - break; - case 3 : - current_position.x =static_cast(the_dose_index.x); - current_position.y = static_cast(the_dose_index.y + 1); - break; - default : - assert( 0 ); - } - } - - void PolygonInfo::AppendEdges( PolygonInfoVectorOfEdges& pol_inf_vec_ref ){ - for( unsigned int voxel_edge = 0 ; voxel_edge < pol_inf_vec_ref.size() ; voxel_edge++ ){ - - assert( voxel_edge <= 3 ); - - PolygonSnippet pol_snip_front; - pol_snip_front.is_edge = 1; - pol_snip_front.characterize = corner; - - switch( voxel_edge ){ - case 0 : - pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x); - pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); - pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x); - pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); - pol_snip_front.why_here.x =static_cast(the_dose_index.x); - pol_snip_front.why_here.y = static_cast(the_dose_index.y); - break; - case 1 : - pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x + 1); - pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); - pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x + 1); - pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); - pol_snip_front.why_here.x =static_cast(the_dose_index.x + 1); - pol_snip_front.why_here.y = static_cast(the_dose_index.y); - break; - case 2 : - pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x + 1); - pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); - pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x + 1); - pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); - pol_snip_front.why_here.x =static_cast(the_dose_index.x + 1); - pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); - break; - case 3 : - pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x); - pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); - pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x); - pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); - pol_snip_front.why_here.x =static_cast(the_dose_index.x); - pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); - break; - default : - assert( 0 ); - } - - snippet_vector_iterator iter; - iter = pol_inf_vec_ref.at( voxel_edge ).begin(); - pol_inf_vec_ref.at( voxel_edge ).insert( iter , pol_snip_front ); - } - CheckEdgeIntersections(); - } - - void PolygonInfo::CheckEdgeIntersections(){ - SnippetIndex edge_index; - - edge_index.edge = 0; - edge_index.snip = 0; - current_edge = 0; - - CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); - - edge_index.edge = 1; - edge_index.snip = 0; - current_edge = 1; - - CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); - - edge_index.edge = 2; - edge_index.snip = 0; - current_edge = 2; - - CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); - - edge_index.edge = 3; - edge_index.snip = 0; - current_edge = 3; - CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); - } - - - bool PolygonInfo::GetCornerFromVoxelIntersections( unsigned int the_index, SnippetIndex edge_index , IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index ){ - if( voxel_intersections.corner_intersections_intersection_coord.at( edge_index.edge ).size() > the_index ) - { - intersect_index = voxel_intersections.corner_intersections_intersection_coord.at(edge_index.edge).at( the_index ); - return true; - } - else{ - return false; - } - } - - int PolygonInfo::GetNumberOfSnppetsThisEdge( SnippetIndex edge_index ){ - return voxel_intersections.corner_intersections_intersection_coord.at( edge_index.edge ).size(); - } - - - bool PolygonInfo::SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, VoxelIntersectionIndex next_voxel_intersection ){ - if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).size() > next_voxel_intersection.next_intersection ) - { - if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).at( next_voxel_intersection.next_intersection ).size() > next_voxel_intersection.intersection_douplication ) - { - IterativePolygonInTermsOfIntersections::WhichIntersection an_intersection_index = voxel_intersections.edge_intersections_intersection_coord.at(current_edge).at(next_voxel_intersection.next_intersection).at( next_voxel_intersection.intersection_douplication ); - - it_poly.SetCurrentIntersectionIndex( an_intersection_index ); - - it_poly.ThisIntersection( closest_local_current_position_ref ); - - if( !it_poly.CheckCurrentIntersectionIndexIdentical( an_intersection_index ) ) - { - assert(0); - } - return true; - } - else{ - return false; - } - } - else{ - return false; - } - } - - void PolygonInfo::CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( SnippetIndex edge_index ){ - - LegacyWorldCoordinate2D edge_coord = pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ).why_here; - - IterativePolygonInTermsOfIntersections::WhichIntersection the_intersection_index_from_voxel_intersections; - the_intersection_index_from_voxel_intersections.point_index = 0; - the_intersection_index_from_voxel_intersections.intersection_index = 0; - IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_from_voxel_intersections_ref = the_intersection_index_from_voxel_intersections; - - int number_of_snippets_this_edge = GetNumberOfSnppetsThisEdge( edge_index ); - - std::vector snip_vec_local; - - - if( number_of_snippets_this_edge > 0 ) - { - snip_vec_local = CreateSnippetVector( number_of_snippets_this_edge , pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ) ); - } - int erased = 0; - - for( int which_one = 0 ; which_one < number_of_snippets_this_edge ; which_one++ ){ - bool there_is_an_intersection = GetCornerFromVoxelIntersections( which_one, edge_index , the_intersection_index_from_voxel_intersections_ref ); - - if( there_is_an_intersection ) - { - it_poly.SetCurrentIntersectionIndex( the_intersection_index_from_voxel_intersections_ref ); - - LegacyWorldCoordinate3D contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinates( the_intersection_index_from_voxel_intersections_ref ); - - int back = 1; - - while( ( contour_point_one.x == edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ){ - contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinatesPrevious( the_intersection_index_from_voxel_intersections_ref , back ); - - back++; - } - - int ahead = 1; - - LegacyWorldCoordinate3D contour_point_two = it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( the_intersection_index_from_voxel_intersections_ref , ahead ); - - while( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ){ - ahead++; - - contour_point_two = it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( the_intersection_index_from_voxel_intersections_ref , ahead ); - } - - bool there_is_a_suitable_polygon_forward = false; - bool there_is_a_suitable_polygon_backward = false; - - PolygonSnippet forward_snippet; - PolygonSnippet& forward_snippet_ref = forward_snippet; - PolygonSnippet backward_snippet; - PolygonSnippet& backward_snippet_ref = backward_snippet; - - PolygonSnippet& edge_snippet_ref = snip_vec_local.at( ( which_one - erased ) ); - - float angle_charact_a = 0; - float angle_charact_b = 0; - - if( GoForwardAndCreatePolygonSnippet( forward_snippet_ref ) ) - { - there_is_a_suitable_polygon_forward = true; - } - - if( GoBackwardAndCreatePolygonSnippet( backward_snippet_ref ) ) - { - there_is_a_suitable_polygon_backward = true; - } - - if( there_is_a_suitable_polygon_forward ) - { - angle_charact_a = forward_snippet_ref.angle_charact; - } - if( there_is_a_suitable_polygon_backward ) - { - angle_charact_b = backward_snippet_ref.angle_charact; - } - if( ( ! there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ) - { - edge_snippet_ref.characterize = corner; - } - if( ( there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ) - { - WorkWithForwardAndBackwardEdgeSnippet( which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); - } - if( ( there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ) - { - WorkWithForwardEdgeSnippet( edge_coord, contour_point_one, which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); - } - if( ( ! there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ) - { - WorkWithBackwardEdgeSnippet( edge_coord, contour_point_two , which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); - } - } - } - - if( snip_vec_local.size() > 1 ) - { - snip_vec_local = SortClockwise( snip_vec_local ); - } - InsertToSnippetVectorFront( snip_vec_local, edge_index ); - } - - void PolygonInfo::WorkWithForwardAndBackwardEdgeSnippet( int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ - if( angle_charact_a < angle_charact_b ) - { - Switch( forward_snippet_ref , backward_snippet_ref ); - float keep_angle_charact_a = angle_charact_a; - float keep_angle_charact_b = angle_charact_b; - angle_charact_a = keep_angle_charact_b; - angle_charact_b = keep_angle_charact_a; - } - - if( ( angle_charact_a > 0 ) && ( angle_charact_a < 1.0 ) ) - { - if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) - { - forward_snippet_ref.characterize = inside_inside_touches; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - - backward_snippet_ref.characterize = inside_inside_touches; - backward_snippet_ref.why_here.x =backward_snippet_ref.point_of_interest_start.x; - backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; - backward_snippet_ref.is_edge = true; - - snippet_vector_iterator iter; - - iter = snip_vec_local.begin() + ( which_one - erased ) ; - snip_vec_local.insert( iter , backward_snippet_ref ); - } - else if( angle_charact_b == 0 ) - { - forward_snippet_ref.characterize = edge_to_inside; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - else if( angle_charact_b == 1.0 ) - { - assert(0); - } - else if( angle_charact_b < 0 ) - { - forward_snippet_ref.characterize = real_intersection; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - } - else if( angle_charact_a < 0 ) - { - assert( angle_charact_b < 0 ); - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_a == 1.0 ) - { - if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) - { - backward_snippet_ref.is_edge = true; - backward_snippet_ref.characterize = inside_to_edge; - backward_snippet_ref.why_here.x =backward_snippet_ref.point_of_interest_start.x; - backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , backward_snippet_ref ); - } - else if( angle_charact_b == 1.0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_b == 0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_b < 0 ) - { - forward_snippet_ref.characterize = outside_to_edge; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - } - } - - void PolygonInfo::WorkWithForwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ - float angle_charact = 0; - float& angle_charact_ref = angle_charact; - LegacyWorldCoordinate2D contour_point_one_2d; - contour_point_one_2d.x =contour_point_one.x; - contour_point_one_2d.y = contour_point_one.y; - - GetAngle( contour_point_one_2d , edge_coord , angle_charact_ref ); - - if( ( angle_charact_a > 0 ) && ( angle_charact_a < 1.0 ) ) - { - if( ( angle_charact_ref != 0 ) && ( angle_charact_ref != 1.0 ) ) - { - forward_snippet_ref.characterize = real_intersection; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - else if( angle_charact_ref == 0 ) - { - forward_snippet_ref.characterize = edge_to_inside; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - else if( angle_charact_ref == 1.0 ) - { - forward_snippet_ref.characterize = inside_to_edge ; - forward_snippet_ref.is_edge = true; - forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; - forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , forward_snippet_ref ); - } - } - else if( angle_charact_a == 0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_a == 1.0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_a < 0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - } - - void PolygonInfo::WorkWithBackwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ - float angle_charact = 0; - float& angle_charact_ref = angle_charact; - LegacyWorldCoordinate2D contour_point_two_2d; - contour_point_two_2d.x = contour_point_two.x; - contour_point_two_2d.y = contour_point_two.y; - - GetAngle( contour_point_two_2d , edge_coord , angle_charact_ref ); - - if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) - { - if( ( angle_charact_ref != 0 ) && ( angle_charact_ref != 1.0 ) ) - { - backward_snippet_ref.characterize = real_intersection; - backward_snippet_ref.is_edge = true; - backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; - backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , backward_snippet_ref ); - } - if( ( angle_charact_ref == 1.0 ) ) - { - backward_snippet_ref.characterize = inside_to_edge; - backward_snippet_ref.is_edge = true; - backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; - backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , backward_snippet_ref ); - } - if( ( angle_charact_ref == 0 ) ) - { - backward_snippet_ref.characterize = edge_to_inside; - backward_snippet_ref.is_edge = true; - backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; - backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; - - CopySnippet( edge_snippet_ref , backward_snippet_ref ); - } - - } - else if( angle_charact_b == 0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_b == 1.0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - else if( angle_charact_b < 0 ) - { - int position = ( which_one - erased ); - - RemoveFromLocalSnippetVector( snip_vec_local , position ); - - erased++; - } - } - - PolygonInfo::snippet_vector PolygonInfo::CreateSnippetVector( int number_of_snippets_this_edge , PolygonSnippet template_snip ){ - snippet_vector vector_local; - - PolygonSnippet pol_snip; - - for( int i = 0 ; i < number_of_snippets_this_edge ; i++ ){ - CopySnippet( pol_snip, template_snip ); - - vector_local.push_back( pol_snip ); - } - return vector_local; - } - - PolygonInfo::snippet_vector PolygonInfo::SortClockwise( snippet_vector snip_vec_local ){ - snippet_vector snip_vec_local_internal; - std::vector do_check; -do_check.clear(); - - for( GridIndexType i = 0 ; i < snip_vec_local.size() ; i++ ){ - - LegacyWorldCoordinate2D position_one = snip_vec_local.at( i ).point_of_interest_end; - - double distance_one = GetDistanceAlongEdge( the_dose_index , position_one ); - - LegacyWorldCoordinate2D position_for_reference = snip_vec_local.at( i ).why_here; - - double distance_for_reference = GetDistanceAlongEdge( the_dose_index , position_for_reference ); - - double rang_one = GetClockwiseDist( distance_for_reference , distance_one ); - - bool got_it = false; - - for( GridIndexType j = 0 ; j < snip_vec_local_internal.size() ; j++ ){ - - if( do_check.at(j) == true ) - { - LegacyWorldCoordinate2D position_two = snip_vec_local_internal.at( j ).point_of_interest_end; - - double distance_two = GetDistanceAlongEdge( the_dose_index , position_two ); - - double rang_two = GetClockwiseDist( distance_for_reference , distance_two ); - - if( rang_one < rang_two ) - { - snippet_vector_iterator iter; - iter = snip_vec_local_internal.begin(); - iter += j; - snip_vec_local_internal.insert( iter , snip_vec_local.at( i ) ); - got_it = true; - - bool check = true; - do_check.push_back( check ); - - if( ( snip_vec_local.at( i ).characterize == 6 ) && ( ( i + 1 ) < snip_vec_local.size() ) ) - { - if( snip_vec_local.at( i + 1 ).characterize == 6 ) - { - snippet_vector_iterator iter; - iter = snip_vec_local_internal.begin(); - iter += j; - snip_vec_local_internal.insert( iter , snip_vec_local.at( i + 1 ) ); - i++; - got_it = true; - - bool check = false; - do_check.push_back( check ); - } - } - j = snip_vec_local.size(); - } - } - } - if( got_it == false ) - { - snip_vec_local_internal.push_back( snip_vec_local.at( i ) ); - - bool check = true; - do_check.push_back( check ); - - if( ( snip_vec_local.at( i ).characterize == 6 ) && ( ( i + 1 ) < snip_vec_local.size() ) ) - { - if( snip_vec_local.at( i + 1 ).characterize == 6 ) - { - snip_vec_local_internal.push_back( snip_vec_local.at( i + 1 ) ); - i++; - got_it = true; - - bool check = false; - do_check.push_back( check ); - } - } - } - - } - return snip_vec_local_internal; - } - - void PolygonInfo::InsertToSnippetVectorFront( snippet_vector snip_vec_local , SnippetIndex edge_index ){ - snippet_vector_iterator iter; - - for( GridIndexType i = 0 ; i < snip_vec_local.size() ; i++ ){ - PolygonSnippet pol_snip_front = snip_vec_local.at( i ); - - iter = pol_inf_vec.at( edge_index.edge ).begin() + ( i + 1 ); - - pol_inf_vec.at( edge_index.edge ).insert( iter , pol_snip_front ); - } - - if( snip_vec_local.size() > 0 ) - { - iter = pol_inf_vec.at( edge_index.edge ).begin(); - pol_inf_vec.at( edge_index.edge ).erase( iter ); - } - } - - void PolygonInfo::RemoveFromLocalSnippetVector( snippet_vector& snip_vec_local , GridIndexType which_one ){ - snippet_vector_iterator iter; - - if( snip_vec_local.size() > which_one ) - { - iter = snip_vec_local.begin() + which_one; - snip_vec_local.erase( iter ); - } - } - - void PolygonInfo::GetSectorsAndSetCharacteristicsDoubleCheck( SnippetIndex edge_index, LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two ){ - PolygonSnippet& a_snippet_ref = pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ); - - WhichSector sector_first_point = not_known; - WhichSector sector_second_point = not_known; - - WhichSector& sector_first_point_ref = sector_first_point; - WhichSector& sector_second_point_ref = sector_second_point; - - GetSectors( edge_coord , contour_point_one , contour_point_two , sector_first_point_ref , sector_second_point_ref ); - - if( edge_index.edge == 0 ) - { - CharacterizeIntersection charact_double_check = GetCharacteristicFirstCorner( sector_first_point_ref , sector_second_point_ref ); - if( ( a_snippet_ref.characterize != charact_double_check ) && ( a_snippet_ref.characterize != corner ) ) - { - std::cout<< " Have double checked the characteristic of corner zero. It turned out not to be determined correctly ! " < edge_coord.x ) && ( contour_point_one.y < edge_coord.y ) ) - { - sector_first_point_ref = section_twelve_to_three_o_clock; - return; - } - if( ( contour_point_one.x > edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ) - { - sector_first_point_ref = on_edge_three_o_clock; - return; - } - if( ( contour_point_one.x > edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) - { - sector_first_point_ref = section_three_to_six_o_clock; - return; - } - if( ( contour_point_one.x == edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) - { - sector_first_point_ref = on_edge_six_o_clock; - return; - } - if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) - { - sector_first_point_ref = section_six_to_nine_o_clock; - return; - } - if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ) - { - sector_first_point_ref = on_edge_nine_o_clock; - return; - } - if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y < edge_coord.y ) ) - { - sector_first_point_ref = section_nine_to_twelve_o_clock; - return; - } - } - - void PolygonInfo::GetSectorSecondPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref ){ - if( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) - { - sector_second_point_ref = on_edge_twelve_o_clock; - return; - } - if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) - { - sector_second_point_ref = section_twelve_to_three_o_clock; - return; - } - if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ) - { - sector_second_point_ref = on_edge_three_o_clock; - return; - } - if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) - { - sector_second_point_ref = section_three_to_six_o_clock; - return; - } - if( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) - { - sector_second_point_ref = on_edge_six_o_clock; - return; - } - if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) - { - sector_second_point_ref = section_six_to_nine_o_clock; - return; - } - if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ) - { - sector_second_point_ref = on_edge_nine_o_clock; - return; - } - if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) - { - sector_second_point_ref = section_nine_to_twelve_o_clock; - return; - } - } - - CharacterizeIntersection PolygonInfo::GetCharacteristicFirstCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ - CharacterizeIntersection charact = unknown; - CharacterizeIntersection& charact_ref = charact; - - std::vector in_combination_vector; - std::vector& in_combination_vector_ref = in_combination_vector; - GetInCombinationFirstCorner( in_combination_vector_ref ); - - WhichSector inside; - WhichSector& inside_ref = inside; - GetInsideFirstCorner( inside_ref ); - - WhichSector preceding_edge; - WhichSector& preceding_edge_ref = preceding_edge; - GetPrecedingEdgeFirstCorner( preceding_edge_ref ); - - WhichSector following_edge; - WhichSector& following_edge_ref = following_edge; - GetFollowingEdgeFirstCorner( following_edge_ref ); - - DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); - - if( charact == unknown ) - { - assert( 0 ); - } - return charact; - } - - void PolygonInfo::DoCharacterize( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , CharacterizeIntersection& charact_ref , std::vector in_combination_vector , WhichSector& inside_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ){ - if( BothOnEdge( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , following_edge_ref ) ) - { - charact_ref = edge_to_edge;} - else if( FromEdgeIn( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , inside_ref ) ) - { - charact_ref = edge_to_inside; - } - else if( FromEdgeOut( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , in_combination_vector ) ) - { - charact_ref = edge_to_outside; - } - else if( OutToEdge( sector_first_point_ref , sector_second_point_ref , following_edge_ref , in_combination_vector ) ) - { - charact_ref = outside_to_edge; - } - else if( InToEdge( sector_first_point_ref , sector_second_point_ref , following_edge_ref , inside_ref ) ) - { - charact_ref = inside_to_edge; - } - else if( BothIn( sector_first_point_ref , sector_second_point_ref , inside_ref ) ) - { - charact_ref = inside_inside_touches; - } - else if( BothOut( sector_first_point_ref , sector_second_point_ref , in_combination_vector ) ) - { - charact_ref = outside_outside_touches; - } - else if( OneInOneOut( sector_first_point_ref , sector_second_point_ref , inside_ref , in_combination_vector ) ) charact_ref = real_intersection; - else assert( 0 ); - } + bool PolygonInfo::selfTest() + { + return CheckConstructurSuccessForTest(); + } + + IterativePolygonInTermsOfIntersections PolygonInfo::GetIterativePolygoneInTermsOfIntersections() + { + return it_poly; + } + + + bool PolygonInfo::CheckConstructurSuccessForTest() + { + bool gone_well = true; + + if (MaskFieldReceived == NULL) + { + gone_well = false; + std::cout << " Mask field must not be zero ! " << std::endl; + } + + if (MaskFieldReceived->GetData(0, 0, 0) < 0) + { + gone_well = false; + std::cout << " Mask field values must not be below zero ! " << std::endl; + } + + if (brightness_outside != 0) + { + gone_well = false; + std::cout << " Strange value for brightness_outside ! " << std::endl; + } + + if (it_poly.CheckCurrentIndexInitForTest() == false) + { + gone_well = false; + std::cout << " current_index_internal initialized incorrect ! " << std::endl; + } + + return gone_well; + } + + bool PolygonInfo::TestCreateUnifiedListOfRawAndColumnIntersections(PolygonInTermsOfIntersections + Expected_Unified_Polygon_Intersections) + { + return it_poly.ItIsAsExpected(Expected_Unified_Polygon_Intersections); + } + + bool PolygonInfo::CheckResultingPolygonInfoVectorOfEdgesForTestStructure( + PolygonInfoVectorOfEdges pol_inf_vec_expected) + { + if (pol_inf_vec.size() != pol_inf_vec_expected.size()) + { + std::cout << " incompatible size pol_inf_vec.size() " << pol_inf_vec.size() << std::endl; + std::cout << " incompatible size pol_inf_vec_expected.size() " << pol_inf_vec_expected.size() << + std::endl; + return false; + } + + for (GridIndexType counter = 0 ; counter < pol_inf_vec.size() ; counter++) + { + if (pol_inf_vec.at(counter).size() != pol_inf_vec_expected.at(counter).size()) + { + std::cout << " incompatible size pol_inf_vec.at( counter ).size() " << pol_inf_vec.at( + counter).size() << std::endl; + std::cout << " incompatible size pol_inf_vec_expected.at( counter ).size() " << + pol_inf_vec_expected.at(counter).size() << std::endl; + return false; + } + + for (GridIndexType internal_counter = 0 ; internal_counter < pol_inf_vec.at(counter).size() ; + internal_counter++) + { + PolygonSnippet pol_snip_a = pol_inf_vec.at(counter).at(internal_counter); + PolygonSnippet pol_snip_b = pol_inf_vec_expected.at(counter).at(internal_counter); + + if (! SameSnippet(pol_snip_a , pol_snip_b)) + { + std::cout << " Unexpected snippet das vorhandene ! " << std::endl; + ShowSnippet(pol_snip_a); + std::cout << " Unexpected snippet das erwartete ! " << std::endl; + ShowSnippet(pol_snip_b); + return false; + } + + } + + } + + return true; + } + + + bool PolygonInfo::SameSnippet(PolygonSnippet& pol_snip_a , PolygonSnippet& pol_snip_b) + { + + if (pol_snip_a.is_edge != pol_snip_b.is_edge) + { + return false; + } + + if (pol_snip_a.characterize != pol_snip_b.characterize) + { + return false; + } + + if (static_cast(pol_snip_a.point_of_interest_start.x) != static_cast + (pol_snip_b.point_of_interest_start.x)) + { + return false; + } + + if (static_cast(pol_snip_a.point_of_interest_start.y) != static_cast + (pol_snip_b.point_of_interest_start.y)) + { + return false; + } + + if (static_cast(pol_snip_a.point_of_interest_end.y) != static_cast + (pol_snip_b.point_of_interest_end.y)) + { + return false; + } + + if (static_cast(pol_snip_a.why_here.x) != static_cast(pol_snip_b.why_here.x)) + { + return false; + } + + if (static_cast(pol_snip_a.why_here.y) != static_cast(pol_snip_b.why_here.y)) + { + return false; + } + + if (pol_snip_a.snippet_intermediate_content.size() != + pol_snip_b.snippet_intermediate_content.size()) + { + return false; + } + + for (GridIndexType counter = 0 ; counter < pol_snip_a.snippet_intermediate_content.size() ; + counter++) + { + if (static_cast(pol_snip_a.snippet_intermediate_content.at(counter).x) != static_cast + (pol_snip_b.snippet_intermediate_content.at(counter).x)) + { + return false; + } + + if (static_cast(pol_snip_a.snippet_intermediate_content.at(counter).y) != static_cast + (pol_snip_b.snippet_intermediate_content.at(counter).y)) + { + return false; + } + + if (static_cast(pol_snip_a.snippet_intermediate_content.at(counter).z) != static_cast + (pol_snip_b.snippet_intermediate_content.at(counter).z)) + { + return false; + } + } + + return true; + } + + + bool PolygonInfo::CompareCalculatedAndExpectedResultingSequenceForTest( + LegacyPolygonSequenceType& expected_resulting_sequence_ref) + { + if (expected_resulting_sequence_ref.size() > resulting_sequence.size()) + { + std::cout << " Size ! " << std::endl; + std::cout << " expected_resulting_sequence_ref.size() " << expected_resulting_sequence_ref.size() + << std::endl; + std::cout << " resulting_sequence.size() " << resulting_sequence.size() << std::endl; + return false; + } + + for (GridIndexType counter = 0 ; counter < expected_resulting_sequence_ref.size() ; counter++) + { + if (expected_resulting_sequence_ref.at(counter).size() != resulting_sequence.at(counter).size()) + { + std::cout << " different size ! " << std::endl; + std::cout << " expected_resulting_sequence_ref.at( counter ).size() " << + expected_resulting_sequence_ref.at(counter).size() << std::endl; + std::cout << " resulting_sequence.at( counter ).size() " << resulting_sequence.at( + counter).size() << std::endl; + return false; + } + + for (GridIndexType counter_internal = 0 ; + counter_internal < expected_resulting_sequence_ref.at(counter).size() ; counter_internal++) + { + LegacyWorldCoordinate3D wc3d_a = expected_resulting_sequence_ref.at(counter).at(counter_internal); + LegacyWorldCoordinate3D wc3d_b = resulting_sequence.at(counter).at(counter_internal); + + if (wc3d_a.x != wc3d_b.x) + { + std::cout << " unexpected x ! " << std::endl; + return false; + } + + if (wc3d_a.y != wc3d_b.y) + { + std::cout << " unexpected y ! " << std::endl; + return false; + } + + if (wc3d_a.z != wc3d_b.z) + { + std::cout << " unexpected z ! " << std::endl; + return false; + } + } + } + + return true; + } + + void PolygonInfo::SetCurrentPositionToEdge(int voxel_edge) + { + switch (voxel_edge) + { + case 0 : + current_position.x = static_cast(the_dose_index.x); + current_position.y = static_cast(the_dose_index.y); + break; + + case 1 : + current_position.x = static_cast(the_dose_index.x + 1); + current_position.y = static_cast(the_dose_index.y); + break; + + case 2 : + current_position.x = static_cast(the_dose_index.x + 1); + current_position.y = static_cast(the_dose_index.y + 1); + break; + + case 3 : + current_position.x = static_cast(the_dose_index.x); + current_position.y = static_cast(the_dose_index.y + 1); + break; + + default : + assert(0); + } + } + + void PolygonInfo::AppendEdges(PolygonInfoVectorOfEdges& pol_inf_vec_ref) + { + for (unsigned int voxel_edge = 0 ; voxel_edge < pol_inf_vec_ref.size() ; voxel_edge++) + { + + assert(voxel_edge <= 3); + + PolygonSnippet pol_snip_front; + pol_snip_front.is_edge = 1; + pol_snip_front.characterize = corner; + + switch (voxel_edge) + { + case 0 : + pol_snip_front.point_of_interest_start.x = static_cast(the_dose_index.x); + pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); + pol_snip_front.point_of_interest_end.x = static_cast(the_dose_index.x); + pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); + pol_snip_front.why_here.x = static_cast(the_dose_index.x); + pol_snip_front.why_here.y = static_cast(the_dose_index.y); + break; + + case 1 : + pol_snip_front.point_of_interest_start.x = static_cast(the_dose_index.x + 1); + pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); + pol_snip_front.point_of_interest_end.x = static_cast(the_dose_index.x + 1); + pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); + pol_snip_front.why_here.x = static_cast(the_dose_index.x + 1); + pol_snip_front.why_here.y = static_cast(the_dose_index.y); + break; + + case 2 : + pol_snip_front.point_of_interest_start.x = static_cast(the_dose_index.x + 1); + pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); + pol_snip_front.point_of_interest_end.x = static_cast(the_dose_index.x + 1); + pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); + pol_snip_front.why_here.x = static_cast(the_dose_index.x + 1); + pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); + break; + + case 3 : + pol_snip_front.point_of_interest_start.x = static_cast(the_dose_index.x); + pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); + pol_snip_front.point_of_interest_end.x = static_cast(the_dose_index.x); + pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); + pol_snip_front.why_here.x = static_cast(the_dose_index.x); + pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); + break; + + default : + assert(0); + } + + snippet_vector_iterator iter; + iter = pol_inf_vec_ref.at(voxel_edge).begin(); + pol_inf_vec_ref.at(voxel_edge).insert(iter , pol_snip_front); + } + + CheckEdgeIntersections(); + } + + void PolygonInfo::CheckEdgeIntersections() + { + SnippetIndex edge_index; + + edge_index.edge = 0; + edge_index.snip = 0; + current_edge = 0; + + CheckEdegeTouchCharacteristicsAndAppendIntermediateContent(edge_index); + + edge_index.edge = 1; + edge_index.snip = 0; + current_edge = 1; + + CheckEdegeTouchCharacteristicsAndAppendIntermediateContent(edge_index); + + edge_index.edge = 2; + edge_index.snip = 0; + current_edge = 2; + + CheckEdegeTouchCharacteristicsAndAppendIntermediateContent(edge_index); + + edge_index.edge = 3; + edge_index.snip = 0; + current_edge = 3; + CheckEdegeTouchCharacteristicsAndAppendIntermediateContent(edge_index); + } + + + bool PolygonInfo::GetCornerFromVoxelIntersections(unsigned int the_index, SnippetIndex edge_index , + IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index) + { + if (voxel_intersections.corner_intersections_intersection_coord.at(edge_index.edge).size() > + the_index) + { + intersect_index = voxel_intersections.corner_intersections_intersection_coord.at( + edge_index.edge).at(the_index); + return true; + } + else + { + return false; + } + } + + int PolygonInfo::GetNumberOfSnppetsThisEdge(SnippetIndex edge_index) + { + return voxel_intersections.corner_intersections_intersection_coord.at(edge_index.edge).size(); + } + + + bool PolygonInfo::SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( + LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, + VoxelIntersectionIndex next_voxel_intersection) + { + if (voxel_intersections.edge_intersections_intersection_coord.at(current_edge).size() > + next_voxel_intersection.next_intersection) + { + if (voxel_intersections.edge_intersections_intersection_coord.at(current_edge).at( + next_voxel_intersection.next_intersection).size() > + next_voxel_intersection.intersection_douplication) + { + IterativePolygonInTermsOfIntersections::WhichIntersection an_intersection_index = + voxel_intersections.edge_intersections_intersection_coord.at(current_edge).at( + next_voxel_intersection.next_intersection).at(next_voxel_intersection.intersection_douplication); + + it_poly.SetCurrentIntersectionIndex(an_intersection_index); + + it_poly.ThisIntersection(closest_local_current_position_ref); + + if (!it_poly.CheckCurrentIntersectionIndexIdentical(an_intersection_index)) + { + assert(0); + } + + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } + + void PolygonInfo::CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( + SnippetIndex edge_index) + { + + LegacyWorldCoordinate2D edge_coord = pol_inf_vec.at(edge_index.edge).at(edge_index.snip).why_here; + + IterativePolygonInTermsOfIntersections::WhichIntersection + the_intersection_index_from_voxel_intersections; + the_intersection_index_from_voxel_intersections.point_index = 0; + the_intersection_index_from_voxel_intersections.intersection_index = 0; + IterativePolygonInTermsOfIntersections::WhichIntersection& + the_intersection_index_from_voxel_intersections_ref = + the_intersection_index_from_voxel_intersections; + + int number_of_snippets_this_edge = GetNumberOfSnppetsThisEdge(edge_index); + + std::vector snip_vec_local; + + + if (number_of_snippets_this_edge > 0) + { + snip_vec_local = CreateSnippetVector(number_of_snippets_this_edge , + pol_inf_vec.at(edge_index.edge).at(edge_index.snip)); + } + + int erased = 0; + + for (int which_one = 0 ; which_one < number_of_snippets_this_edge ; which_one++) + { + bool there_is_an_intersection = GetCornerFromVoxelIntersections(which_one, edge_index , + the_intersection_index_from_voxel_intersections_ref); + + if (there_is_an_intersection) + { + it_poly.SetCurrentIntersectionIndex(the_intersection_index_from_voxel_intersections_ref); + + LegacyWorldCoordinate3D contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinates( + the_intersection_index_from_voxel_intersections_ref); + + int back = 1; + + while ((contour_point_one.x == edge_coord.x) && (contour_point_one.y == edge_coord.y)) + { + contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinatesPrevious( + the_intersection_index_from_voxel_intersections_ref , back); + + back++; + } + + int ahead = 1; + + LegacyWorldCoordinate3D contour_point_two = + it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( + the_intersection_index_from_voxel_intersections_ref , ahead); + + while ((contour_point_two.x == edge_coord.x) && (contour_point_two.y == edge_coord.y)) + { + ahead++; + + contour_point_two = it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( + the_intersection_index_from_voxel_intersections_ref , ahead); + } + + bool there_is_a_suitable_polygon_forward = false; + bool there_is_a_suitable_polygon_backward = false; + + PolygonSnippet forward_snippet; + PolygonSnippet& forward_snippet_ref = forward_snippet; + PolygonSnippet backward_snippet; + PolygonSnippet& backward_snippet_ref = backward_snippet; + + PolygonSnippet& edge_snippet_ref = snip_vec_local.at((which_one - erased)); + + float angle_charact_a = 0; + float angle_charact_b = 0; + + if (GoForwardAndCreatePolygonSnippet(forward_snippet_ref)) + { + there_is_a_suitable_polygon_forward = true; + } + + if (GoBackwardAndCreatePolygonSnippet(backward_snippet_ref)) + { + there_is_a_suitable_polygon_backward = true; + } + + if (there_is_a_suitable_polygon_forward) + { + angle_charact_a = forward_snippet_ref.angle_charact; + } + + if (there_is_a_suitable_polygon_backward) + { + angle_charact_b = backward_snippet_ref.angle_charact; + } + + if ((! there_is_a_suitable_polygon_forward) && (! there_is_a_suitable_polygon_backward)) + { + edge_snippet_ref.characterize = corner; + } + + if ((there_is_a_suitable_polygon_forward) && (there_is_a_suitable_polygon_backward)) + { + WorkWithForwardAndBackwardEdgeSnippet(which_one, angle_charact_a , angle_charact_b , + forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased); + } + + if ((there_is_a_suitable_polygon_forward) && (! there_is_a_suitable_polygon_backward)) + { + WorkWithForwardEdgeSnippet(edge_coord, contour_point_one, which_one, angle_charact_a , + angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , + erased); + } + + if ((! there_is_a_suitable_polygon_forward) && (there_is_a_suitable_polygon_backward)) + { + WorkWithBackwardEdgeSnippet(edge_coord, contour_point_two , which_one, angle_charact_a , + angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , + erased); + } + } + } + + if (snip_vec_local.size() > 1) + { + snip_vec_local = SortClockwise(snip_vec_local); + } + + InsertToSnippetVectorFront(snip_vec_local, edge_index); + } + + void PolygonInfo::WorkWithForwardAndBackwardEdgeSnippet(int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased) + { + if (angle_charact_a < angle_charact_b) + { + Switch(forward_snippet_ref , backward_snippet_ref); + float keep_angle_charact_a = angle_charact_a; + float keep_angle_charact_b = angle_charact_b; + angle_charact_a = keep_angle_charact_b; + angle_charact_b = keep_angle_charact_a; + } + + if ((angle_charact_a > 0) && (angle_charact_a < 1.0)) + { + if ((angle_charact_b > 0) && (angle_charact_b < 1.0)) + { + forward_snippet_ref.characterize = inside_inside_touches; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + CopySnippet(edge_snippet_ref , forward_snippet_ref); + + backward_snippet_ref.characterize = inside_inside_touches; + backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; + backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; + backward_snippet_ref.is_edge = true; + + snippet_vector_iterator iter; + + iter = snip_vec_local.begin() + (which_one - erased) ; + snip_vec_local.insert(iter , backward_snippet_ref); + } + else if (angle_charact_b == 0) + { + forward_snippet_ref.characterize = edge_to_inside; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + else if (angle_charact_b == 1.0) + { + assert(0); + } + else if (angle_charact_b < 0) + { + forward_snippet_ref.characterize = real_intersection; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + } + else if (angle_charact_a < 0) + { + assert(angle_charact_b < 0); + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_a == 1.0) + { + if ((angle_charact_b > 0) && (angle_charact_b < 1.0)) + { + backward_snippet_ref.is_edge = true; + backward_snippet_ref.characterize = inside_to_edge; + backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; + backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , backward_snippet_ref); + } + else if (angle_charact_b == 1.0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_b == 0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_b < 0) + { + forward_snippet_ref.characterize = outside_to_edge; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + } + } + + void PolygonInfo::WorkWithForwardEdgeSnippet(LegacyWorldCoordinate2D edge_coord, + LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased) + { + float angle_charact = 0; + float& angle_charact_ref = angle_charact; + LegacyWorldCoordinate2D contour_point_one_2d; + contour_point_one_2d.x = contour_point_one.x; + contour_point_one_2d.y = contour_point_one.y; + + GetAngle(contour_point_one_2d , edge_coord , angle_charact_ref); + + if ((angle_charact_a > 0) && (angle_charact_a < 1.0)) + { + if ((angle_charact_ref != 0) && (angle_charact_ref != 1.0)) + { + forward_snippet_ref.characterize = real_intersection; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + else if (angle_charact_ref == 0) + { + forward_snippet_ref.characterize = edge_to_inside; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + else if (angle_charact_ref == 1.0) + { + forward_snippet_ref.characterize = inside_to_edge ; + forward_snippet_ref.is_edge = true; + forward_snippet_ref.why_here.x = forward_snippet_ref.point_of_interest_start.x; + forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , forward_snippet_ref); + } + } + else if (angle_charact_a == 0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_a == 1.0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_a < 0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + } + + void PolygonInfo::WorkWithBackwardEdgeSnippet(LegacyWorldCoordinate2D edge_coord, + LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased) + { + float angle_charact = 0; + float& angle_charact_ref = angle_charact; + LegacyWorldCoordinate2D contour_point_two_2d; + contour_point_two_2d.x = contour_point_two.x; + contour_point_two_2d.y = contour_point_two.y; + + GetAngle(contour_point_two_2d , edge_coord , angle_charact_ref); + + if ((angle_charact_b > 0) && (angle_charact_b < 1.0)) + { + if ((angle_charact_ref != 0) && (angle_charact_ref != 1.0)) + { + backward_snippet_ref.characterize = real_intersection; + backward_snippet_ref.is_edge = true; + backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; + backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , backward_snippet_ref); + } + + if ((angle_charact_ref == 1.0)) + { + backward_snippet_ref.characterize = inside_to_edge; + backward_snippet_ref.is_edge = true; + backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; + backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , backward_snippet_ref); + } + + if ((angle_charact_ref == 0)) + { + backward_snippet_ref.characterize = edge_to_inside; + backward_snippet_ref.is_edge = true; + backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; + backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; + + CopySnippet(edge_snippet_ref , backward_snippet_ref); + } + + } + else if (angle_charact_b == 0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_b == 1.0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + else if (angle_charact_b < 0) + { + int position = (which_one - erased); + + RemoveFromLocalSnippetVector(snip_vec_local , position); + + erased++; + } + } + + PolygonInfo::snippet_vector PolygonInfo::CreateSnippetVector(int number_of_snippets_this_edge , + PolygonSnippet template_snip) + { + snippet_vector vector_local; + + PolygonSnippet pol_snip; + + for (int i = 0 ; i < number_of_snippets_this_edge ; i++) + { + CopySnippet(pol_snip, template_snip); + + vector_local.push_back(pol_snip); + } + + return vector_local; + } + + PolygonInfo::snippet_vector PolygonInfo::SortClockwise(snippet_vector snip_vec_local) + { + snippet_vector snip_vec_local_internal; + std::vector do_check; + do_check.clear(); + + for (GridIndexType i = 0 ; i < snip_vec_local.size() ; i++) + { + + LegacyWorldCoordinate2D position_one = snip_vec_local.at(i).point_of_interest_end; + + double distance_one = GetDistanceAlongEdge(the_dose_index , position_one); + + LegacyWorldCoordinate2D position_for_reference = snip_vec_local.at(i).why_here; + + double distance_for_reference = GetDistanceAlongEdge(the_dose_index , position_for_reference); + + double rang_one = GetClockwiseDist(distance_for_reference , distance_one); + + bool got_it = false; + + for (GridIndexType j = 0 ; j < snip_vec_local_internal.size() ; j++) + { + + if (do_check.at(j) == true) + { + LegacyWorldCoordinate2D position_two = snip_vec_local_internal.at(j).point_of_interest_end; + + double distance_two = GetDistanceAlongEdge(the_dose_index , position_two); + + double rang_two = GetClockwiseDist(distance_for_reference , distance_two); + + if (rang_one < rang_two) + { + snippet_vector_iterator iter; + iter = snip_vec_local_internal.begin(); + iter += j; + snip_vec_local_internal.insert(iter , snip_vec_local.at(i)); + got_it = true; + + bool check = true; + do_check.push_back(check); + + if ((snip_vec_local.at(i).characterize == 6) && ((i + 1) < snip_vec_local.size())) + { + if (snip_vec_local.at(i + 1).characterize == 6) + { + snippet_vector_iterator iter; + iter = snip_vec_local_internal.begin(); + iter += j; + snip_vec_local_internal.insert(iter , snip_vec_local.at(i + 1)); + i++; + got_it = true; + + bool check = false; + do_check.push_back(check); + } + } + + j = snip_vec_local.size(); + } + } + } + + if (got_it == false) + { + snip_vec_local_internal.push_back(snip_vec_local.at(i)); + + bool check = true; + do_check.push_back(check); + + if ((snip_vec_local.at(i).characterize == 6) && ((i + 1) < snip_vec_local.size())) + { + if (snip_vec_local.at(i + 1).characterize == 6) + { + snip_vec_local_internal.push_back(snip_vec_local.at(i + 1)); + i++; + got_it = true; + + bool check = false; + do_check.push_back(check); + } + } + } + + } + + return snip_vec_local_internal; + } + + void PolygonInfo::InsertToSnippetVectorFront(snippet_vector snip_vec_local , + SnippetIndex edge_index) + { + snippet_vector_iterator iter; + + for (GridIndexType i = 0 ; i < snip_vec_local.size() ; i++) + { + PolygonSnippet pol_snip_front = snip_vec_local.at(i); + + iter = pol_inf_vec.at(edge_index.edge).begin() + (i + 1); + + pol_inf_vec.at(edge_index.edge).insert(iter , pol_snip_front); + } + + if (snip_vec_local.size() > 0) + { + iter = pol_inf_vec.at(edge_index.edge).begin(); + pol_inf_vec.at(edge_index.edge).erase(iter); + } + } + + void PolygonInfo::RemoveFromLocalSnippetVector(snippet_vector& snip_vec_local , + GridIndexType which_one) + { + snippet_vector_iterator iter; + + if (snip_vec_local.size() > which_one) + { + iter = snip_vec_local.begin() + which_one; + snip_vec_local.erase(iter); + } + } + + void PolygonInfo::GetSectorsAndSetCharacteristicsDoubleCheck(SnippetIndex edge_index, + LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , + LegacyWorldCoordinate3D& contour_point_two) + { + PolygonSnippet& a_snippet_ref = pol_inf_vec.at(edge_index.edge).at(edge_index.snip); + + WhichSector sector_first_point = not_known; + WhichSector sector_second_point = not_known; + + WhichSector& sector_first_point_ref = sector_first_point; + WhichSector& sector_second_point_ref = sector_second_point; + + GetSectors(edge_coord , contour_point_one , contour_point_two , sector_first_point_ref , + sector_second_point_ref); + + if (edge_index.edge == 0) + { + CharacterizeIntersection charact_double_check = GetCharacteristicFirstCorner( + sector_first_point_ref , sector_second_point_ref); + + if ((a_snippet_ref.characterize != charact_double_check) && (a_snippet_ref.characterize != corner)) + { + std::cout << + " Have double checked the characteristic of corner zero. It turned out not to be determined correctly ! " + << std::endl; + assert(0); + } + } + else if (edge_index.edge == 1) + { + CharacterizeIntersection charact_double_check = GetCharacteristicSecondCorner( + sector_first_point_ref , sector_second_point_ref); + + if ((a_snippet_ref.characterize != charact_double_check) && (a_snippet_ref.characterize != corner)) + { + std::cout << + " Have double checked the characteristic of corner one. It turned out not to be determined correctly ! " + << std::endl; + assert(0); + } + } + else if (edge_index.edge == 2) + { + CharacterizeIntersection charact_double_check = GetCharacteristicThirdCorner( + sector_first_point_ref , sector_second_point_ref); + + if ((a_snippet_ref.characterize != charact_double_check) && (a_snippet_ref.characterize != corner)) + { + std::cout << + " Have double checked the characteristic of corner two. It turned out not to be determined correctly ! " + << std::endl; + assert(0); + } + } + else if (edge_index.edge == 3) + { + CharacterizeIntersection charact_double_check = GetCharacteristicFourthCorner( + sector_first_point_ref , sector_second_point_ref); + + if ((a_snippet_ref.characterize != charact_double_check) && (a_snippet_ref.characterize != corner)) + { + std::cout << + " Have double checked the characteristic of corner three. It turned out not to be determined correctly ! " + << std::endl; + assert(0); + } + } + else + { + assert(0); + } + } + void PolygonInfo::GetSectors(LegacyWorldCoordinate2D edge_coord , + LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two, + WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref) + { + sector_first_point_ref = not_known; + sector_second_point_ref = not_known; - void PolygonInfo::GetInCombinationFirstCorner( std::vector& in_combination_vector_ref ){ + if ((contour_point_one.x == edge_coord.x) && (contour_point_one.y == edge_coord.y)) + { + assert(0); + } - WhichSector sec_three_to_six = section_three_to_six_o_clock; - in_combination_vector_ref.push_back( sec_three_to_six ); + if ((contour_point_two.x == edge_coord.x) && (contour_point_two.y == edge_coord.y)) + { + assert(0); + } - WhichSector sec_on_edge_six = on_edge_six_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_six ); + GetSectorFirstPoint(edge_coord , contour_point_one , sector_first_point_ref); + GetSectorSecondPoint(edge_coord , contour_point_two, sector_second_point_ref); - WhichSector sec_on_edge_three = on_edge_three_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_three ); + if ((sector_first_point_ref == not_known) || (sector_second_point_ref == not_known)) + { + assert(0); + } + } - } + void PolygonInfo::GetSectorFirstPoint(LegacyWorldCoordinate2D edge_coord , + LegacyWorldCoordinate3D& contour_point_one , WhichSector& sector_first_point_ref) + { + if ((contour_point_one.x == edge_coord.x) && (contour_point_one.y < edge_coord.y)) + { + sector_first_point_ref = on_edge_twelve_o_clock; + return; + } + if ((contour_point_one.x > edge_coord.x) && (contour_point_one.y < edge_coord.y)) + { + sector_first_point_ref = section_twelve_to_three_o_clock; + return; + } - void PolygonInfo::GetInsideFirstCorner( WhichSector& inside_ref ){ - inside_ref = section_three_to_six_o_clock; - } + if ((contour_point_one.x > edge_coord.x) && (contour_point_one.y == edge_coord.y)) + { + sector_first_point_ref = on_edge_three_o_clock; + return; + } + if ((contour_point_one.x > edge_coord.x) && (contour_point_one.y > edge_coord.y)) + { + sector_first_point_ref = section_three_to_six_o_clock; + return; + } - void PolygonInfo::GetPrecedingEdgeFirstCorner( WhichSector& preceding_edge_ref ){ - preceding_edge_ref = on_edge_six_o_clock; - } + if ((contour_point_one.x == edge_coord.x) && (contour_point_one.y > edge_coord.y)) + { + sector_first_point_ref = on_edge_six_o_clock; + return; + } + if ((contour_point_one.x < edge_coord.x) && (contour_point_one.y > edge_coord.y)) + { + sector_first_point_ref = section_six_to_nine_o_clock; + return; + } - void PolygonInfo::GetFollowingEdgeFirstCorner( WhichSector& following_edge_ref ){ - following_edge_ref = on_edge_three_o_clock; - } + if ((contour_point_one.x < edge_coord.x) && (contour_point_one.y == edge_coord.y)) + { + sector_first_point_ref = on_edge_nine_o_clock; + return; + } + if ((contour_point_one.x < edge_coord.x) && (contour_point_one.y < edge_coord.y)) + { + sector_first_point_ref = section_nine_to_twelve_o_clock; + return; + } + } + void PolygonInfo::GetSectorSecondPoint(LegacyWorldCoordinate2D edge_coord , + LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref) + { + if ((contour_point_two.x == edge_coord.x) && (contour_point_two.y < edge_coord.y)) + { + sector_second_point_ref = on_edge_twelve_o_clock; + return; + } - bool PolygonInfo::BothOnEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ){ + if ((contour_point_two.x > edge_coord.x) && (contour_point_two.y < edge_coord.y)) + { + sector_second_point_ref = section_twelve_to_three_o_clock; + return; + } - std::vector first_sector_vector; - WhichSector sec_following_edge = following_edge_ref; - first_sector_vector.push_back( sec_following_edge ); + if ((contour_point_two.x > edge_coord.x) && (contour_point_two.y == edge_coord.y)) + { + sector_second_point_ref = on_edge_three_o_clock; + return; + } - std::vector second_sector_vector; - WhichSector sec_preceding = preceding_edge_ref; - second_sector_vector.push_back( sec_preceding ); + if ((contour_point_two.x > edge_coord.x) && (contour_point_two.y > edge_coord.y)) + { + sector_second_point_ref = section_three_to_six_o_clock; + return; + } - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); + if ((contour_point_two.x == edge_coord.x) && (contour_point_two.y > edge_coord.y)) + { + sector_second_point_ref = on_edge_six_o_clock; + return; + } - if( it_is_a || it_is_b ) return true; - else return false; + if ((contour_point_two.x < edge_coord.x) && (contour_point_two.y > edge_coord.y)) + { + sector_second_point_ref = section_six_to_nine_o_clock; + return; + } - } + if ((contour_point_two.x < edge_coord.x) && (contour_point_two.y == edge_coord.y)) + { + sector_second_point_ref = on_edge_nine_o_clock; + return; + } + if ((contour_point_two.x < edge_coord.x) && (contour_point_two.y < edge_coord.y)) + { + sector_second_point_ref = section_nine_to_twelve_o_clock; + return; + } + } + + CharacterizeIntersection PolygonInfo::GetCharacteristicFirstCorner(WhichSector& + sector_first_point_ref , WhichSector& sector_second_point_ref) + { + CharacterizeIntersection charact = unknown; + CharacterizeIntersection& charact_ref = charact; - bool PolygonInfo::FromEdgeIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& inside_ref ){ + std::vector in_combination_vector; + std::vector& in_combination_vector_ref = in_combination_vector; + GetInCombinationFirstCorner(in_combination_vector_ref); - std::vector first_sector_vector; - WhichSector sec_preceding = preceding_edge_ref; - first_sector_vector.push_back( sec_preceding ); + WhichSector inside; + WhichSector& inside_ref = inside; + GetInsideFirstCorner(inside_ref); - std::vector second_sector_vector; - WhichSector sec_inside = inside_ref; - second_sector_vector.push_back( sec_inside ); + WhichSector preceding_edge; + WhichSector& preceding_edge_ref = preceding_edge; + GetPrecedingEdgeFirstCorner(preceding_edge_ref); - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); + WhichSector following_edge; + WhichSector& following_edge_ref = following_edge; + GetFollowingEdgeFirstCorner(following_edge_ref); + + DoCharacterize(sector_first_point_ref , sector_second_point_ref , charact_ref , + in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref); + + if (charact == unknown) + { + assert(0); + } + + return charact; + } + + void PolygonInfo::DoCharacterize(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , CharacterizeIntersection& charact_ref , + std::vector in_combination_vector , WhichSector& inside_ref , + WhichSector& preceding_edge_ref , WhichSector& following_edge_ref) + { + if (BothOnEdge(sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , + following_edge_ref)) + { + charact_ref = edge_to_edge; + } + else if (FromEdgeIn(sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , + inside_ref)) + { + charact_ref = edge_to_inside; + } + else if (FromEdgeOut(sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , + in_combination_vector)) + { + charact_ref = edge_to_outside; + } + else if (OutToEdge(sector_first_point_ref , sector_second_point_ref , following_edge_ref , + in_combination_vector)) + { + charact_ref = outside_to_edge; + } + else if (InToEdge(sector_first_point_ref , sector_second_point_ref , following_edge_ref , + inside_ref)) + { + charact_ref = inside_to_edge; + } + else if (BothIn(sector_first_point_ref , sector_second_point_ref , inside_ref)) + { + charact_ref = inside_inside_touches; + } + else if (BothOut(sector_first_point_ref , sector_second_point_ref , in_combination_vector)) + { + charact_ref = outside_outside_touches; + } + else if (OneInOneOut(sector_first_point_ref , sector_second_point_ref , inside_ref , + in_combination_vector)) + { + charact_ref = real_intersection; + } + else + { + assert(0); + } + } + + + void PolygonInfo::GetInCombinationFirstCorner(std::vector& in_combination_vector_ref) + { + + WhichSector sec_three_to_six = section_three_to_six_o_clock; + in_combination_vector_ref.push_back(sec_three_to_six); + + WhichSector sec_on_edge_six = on_edge_six_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_six); + + WhichSector sec_on_edge_three = on_edge_three_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_three); + + } + + + void PolygonInfo::GetInsideFirstCorner(WhichSector& inside_ref) + { + inside_ref = section_three_to_six_o_clock; + } + + + void PolygonInfo::GetPrecedingEdgeFirstCorner(WhichSector& preceding_edge_ref) + { + preceding_edge_ref = on_edge_six_o_clock; + } + + + void PolygonInfo::GetFollowingEdgeFirstCorner(WhichSector& following_edge_ref) + { + following_edge_ref = on_edge_three_o_clock; + } + + + + bool PolygonInfo::BothOnEdge(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , + WhichSector& following_edge_ref) + { + + std::vector first_sector_vector; + WhichSector sec_following_edge = following_edge_ref; + first_sector_vector.push_back(sec_following_edge); + + std::vector second_sector_vector; + WhichSector sec_preceding = preceding_edge_ref; + second_sector_vector.push_back(sec_preceding); + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_first_point_ref , + first_sector_vector , sector_second_point_ref , second_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_second_point_ref , + first_sector_vector , sector_first_point_ref , second_sector_vector); + + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + bool PolygonInfo::FromEdgeIn(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& inside_ref) + { + + std::vector first_sector_vector; + WhichSector sec_preceding = preceding_edge_ref; + first_sector_vector.push_back(sec_preceding); + + std::vector second_sector_vector; + WhichSector sec_inside = inside_ref; + second_sector_vector.push_back(sec_inside); + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_first_point_ref , + first_sector_vector , sector_second_point_ref , second_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_second_point_ref , + first_sector_vector , sector_first_point_ref , second_sector_vector); + + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + + bool PolygonInfo::FromEdgeOut(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , + std::vector second_sector_vector) + { - if( it_is_a || it_is_b ) return true; - else return false; + std::vector first_sector_vector; + WhichSector sec_preceding = preceding_edge_ref; + first_sector_vector.push_back(sec_preceding); - } + /*std::vector second_sector_vector; + WhichSector sec_three_to_six = section_three_to_six_o_clock; + second_sector_vector.push_back( sec_three_to_six ); + WhichSector sec_on_edge_six = on_edge_six_o_clock; + second_sector_vector.push_back( sec_on_edge_six ); + WhichSector sec_on_edge_three = on_edge_three_o_clock; + second_sector_vector.push_back( sec_on_edge_three );*/ - bool PolygonInfo::FromEdgeOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , std::vector second_sector_vector ){ - std::vector first_sector_vector; - WhichSector sec_preceding = preceding_edge_ref; - first_sector_vector.push_back( sec_preceding ); - /*std::vector second_sector_vector; - WhichSector sec_three_to_six = section_three_to_six_o_clock; - second_sector_vector.push_back( sec_three_to_six ); + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_first_point_ref , + first_sector_vector , sector_second_point_ref , second_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_second_point_ref , + first_sector_vector , sector_first_point_ref , second_sector_vector); - WhichSector sec_on_edge_six = on_edge_six_o_clock; - second_sector_vector.push_back( sec_on_edge_six ); + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::OutToEdge(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , + std::vector second_sector_vector) + { + + std::vector first_sector_vector; + WhichSector sec_following = following_edge_ref; + first_sector_vector.push_back(sec_following); + + /* std::vector second_sector_vector; + WhichSector sec_three_to_six = section_three_to_six_o_clock; + second_sector_vector.push_back( sec_three_to_six ); + + WhichSector sec_on_edge_six = on_edge_six_o_clock; + second_sector_vector.push_back( sec_on_edge_six ); + + WhichSector sec_on_edge_three = on_edge_three_o_clock; + second_sector_vector.push_back( sec_on_edge_three ); */ + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_first_point_ref , + first_sector_vector , sector_second_point_ref , second_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_second_point_ref , + first_sector_vector , sector_first_point_ref , second_sector_vector); + + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::InToEdge(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , WhichSector& inside_ref) + { + + std::vector first_sector_vector; + WhichSector sec_following_edge = following_edge_ref; + first_sector_vector.push_back(sec_following_edge); + + std::vector second_sector_vector; + WhichSector sec_inside = inside_ref; + second_sector_vector.push_back(sec_inside); + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_first_point_ref , + first_sector_vector , sector_second_point_ref , second_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_second_point_ref , + first_sector_vector , sector_first_point_ref , second_sector_vector); + + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::BothIn(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& inside_ref) + { + + std::vector sector_vector; + WhichSector sec_inside = inside_ref; + sector_vector.push_back(sec_inside); + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(sector_first_point_ref , + sector_vector , sector_second_point_ref , sector_vector); + + if (it_is_a) + { + return true; + } + else + { + return false; + } + + } + + + bool PolygonInfo::BothOut(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , std::vector sector_vector) + { + + /*std::vector sector_vector; + WhichSector sec_three_to_six = section_three_to_six_o_clock; + sector_vector.push_back( sec_three_to_six ); + + WhichSector sec_on_edge_six = on_edge_six_o_clock; + sector_vector.push_back( sec_on_edge_six ); + + WhichSector sec_on_edge_three = on_edge_three_o_clock; + sector_vector.push_back( sec_on_edge_three );*/ + + bool it_is_a = FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose(sector_first_point_ref , + sector_vector , sector_second_point_ref , sector_vector); + + if (it_is_a) + { + return true; + } + else + { + return false; + } + + + } + + + + bool PolygonInfo::OneInOneOut(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref , WhichSector& inside_ref , + std::vector first_sector_vector) + { + + /*std::vector first_sector_vector; + WhichSector sec_three_to_six = section_three_to_six_o_clock; + first_sector_vector.push_back( sec_three_to_six ); + + WhichSector sec_on_edge_six = on_edge_six_o_clock; + first_sector_vector.push_back( sec_on_edge_six ); + + WhichSector sec_on_edge_three = on_edge_three_o_clock; + first_sector_vector.push_back( sec_on_edge_three );*/ + + std::vector second_sector_vector; + WhichSector sec_inside = inside_ref; + second_sector_vector.push_back(sec_inside); + + bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_first_point_ref , + second_sector_vector , sector_second_point_ref , first_sector_vector); + bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(sector_second_point_ref , + second_sector_vector , sector_first_point_ref , first_sector_vector); + + if (it_is_a || it_is_b) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(WhichSector& + sector_first_point_ref , std::vector first_sector_vector , + WhichSector& sector_second_point_ref , std::vector second_sector_vector) + { + + bool first_one_of_these = false; + bool second_one_of_those = false; + + for (unsigned int index = 0 ; index < first_sector_vector.size() ; index++) + { + if (first_sector_vector.at(index) == sector_first_point_ref) + { + first_one_of_these = true; + } + } + + for (unsigned int index = 0 ; index < second_sector_vector.size() ; index++) + { + if (second_sector_vector.at(index) == sector_second_point_ref) + { + second_one_of_those = true; + } + } + + if (first_one_of_these && second_one_of_those) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( + WhichSector& sector_first_point_ref , std::vector first_sector_vector , + WhichSector& sector_second_point_ref , std::vector second_sector_vector) + { + + bool first_one_of_these = false; + bool second_none_of_those = true; + + for (unsigned int index = 0 ; index < first_sector_vector.size() ; index++) + { + if (first_sector_vector.at(index) == sector_first_point_ref) + { + first_one_of_these = true; + } + } + + for (unsigned int index = 0 ; index < second_sector_vector.size() ; index++) + { + if (second_sector_vector.at(index) == sector_second_point_ref) + { + second_none_of_those = false; + } + } + + if (first_one_of_these && second_none_of_those) + { + return true; + } + else + { + return false; + } + + } + + + + + bool PolygonInfo::FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( + WhichSector& sector_first_point_ref , std::vector first_sector_vector , + WhichSector& sector_second_point_ref , std::vector second_sector_vector) + { + + bool first_none_of_these = true; + bool second_none_of_those = true; + + for (unsigned int index = 0 ; index < first_sector_vector.size() ; index++) + { + if (first_sector_vector.at(index) == sector_first_point_ref) + { + first_none_of_these = false; + } + } - WhichSector sec_on_edge_three = on_edge_three_o_clock; - second_sector_vector.push_back( sec_on_edge_three );*/ + for (unsigned int index = 0 ; index < second_sector_vector.size() ; index++) + { + if (second_sector_vector.at(index) == sector_second_point_ref) + { + second_none_of_those = false; + } + } + if (first_none_of_these && second_none_of_those) + { + return true; + } + else + { + return false; + } + } - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); - if( it_is_a || it_is_b ) return true; - else return false; - } + CharacterizeIntersection PolygonInfo::GetCharacteristicSecondCorner(WhichSector& + sector_first_point_ref , WhichSector& sector_second_point_ref) + { + CharacterizeIntersection charact = unknown; + CharacterizeIntersection& charact_ref = charact; + std::vector in_combination_vector; + std::vector& in_combination_vector_ref = in_combination_vector; + GetInCombinationSecondCorner(in_combination_vector_ref); + WhichSector inside; + WhichSector& inside_ref = inside; + GetInsideSecondCorner(inside_ref); - bool PolygonInfo::OutToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , std::vector second_sector_vector ){ + WhichSector preceding_edge; + WhichSector& preceding_edge_ref = preceding_edge; + GetPrecedingEdgeSecondCorner(preceding_edge_ref); - std::vector first_sector_vector; - WhichSector sec_following = following_edge_ref; - first_sector_vector.push_back( sec_following ); + WhichSector following_edge; + WhichSector& following_edge_ref = following_edge; + GetFollowingEdgeSecondCorner(following_edge_ref); - /* std::vector second_sector_vector; - WhichSector sec_three_to_six = section_three_to_six_o_clock; - second_sector_vector.push_back( sec_three_to_six ); + DoCharacterize(sector_first_point_ref , sector_second_point_ref , charact_ref , + in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref); - WhichSector sec_on_edge_six = on_edge_six_o_clock; - second_sector_vector.push_back( sec_on_edge_six ); + if (charact == unknown) + { + assert(0); + } - WhichSector sec_on_edge_three = on_edge_three_o_clock; - second_sector_vector.push_back( sec_on_edge_three ); */ + return charact; - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); + } - if( it_is_a || it_is_b ) return true; - else return false; - } + void PolygonInfo::GetInCombinationSecondCorner(std::vector& in_combination_vector_ref) + { + WhichSector sec_six_to_nine = section_six_to_nine_o_clock; + in_combination_vector_ref.push_back(sec_six_to_nine); - bool PolygonInfo::InToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , WhichSector& inside_ref ){ + WhichSector sec_on_edge_nine = on_edge_nine_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_nine); - std::vector first_sector_vector; - WhichSector sec_following_edge = following_edge_ref; - first_sector_vector.push_back( sec_following_edge ); + WhichSector sec_on_edge_six = on_edge_six_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_six); - std::vector second_sector_vector; - WhichSector sec_inside = inside_ref; - second_sector_vector.push_back( sec_inside ); + } - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); - if( it_is_a || it_is_b ) return true; - else return false; - } + void PolygonInfo::GetInsideSecondCorner(WhichSector& inside_ref) + { + inside_ref = section_six_to_nine_o_clock; + } + void PolygonInfo::GetPrecedingEdgeSecondCorner(WhichSector& preceding_edge_ref) + { + preceding_edge_ref = on_edge_nine_o_clock; + } - bool PolygonInfo::BothIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref ){ - std::vector sector_vector; - WhichSector sec_inside = inside_ref; - sector_vector.push_back( sec_inside ); - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , sector_vector , sector_second_point_ref , sector_vector ); + void PolygonInfo::GetFollowingEdgeSecondCorner(WhichSector& following_edge_ref) + { + following_edge_ref = on_edge_six_o_clock; + } - if( it_is_a ) return true; - else return false; - } + CharacterizeIntersection PolygonInfo::GetCharacteristicThirdCorner(WhichSector& + sector_first_point_ref , WhichSector& sector_second_point_ref) + { - bool PolygonInfo::BothOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , std::vector sector_vector ){ + CharacterizeIntersection charact = unknown; + CharacterizeIntersection& charact_ref = charact; - /*std::vector sector_vector; - WhichSector sec_three_to_six = section_three_to_six_o_clock; - sector_vector.push_back( sec_three_to_six ); + std::vector in_combination_vector; + std::vector& in_combination_vector_ref = in_combination_vector; + GetInCombinationThirdCorner(in_combination_vector_ref); - WhichSector sec_on_edge_six = on_edge_six_o_clock; - sector_vector.push_back( sec_on_edge_six ); + WhichSector inside; + WhichSector& inside_ref = inside; + GetInsideThirdCorner(inside_ref); - WhichSector sec_on_edge_three = on_edge_three_o_clock; - sector_vector.push_back( sec_on_edge_three );*/ + WhichSector preceding_edge; + WhichSector& preceding_edge_ref = preceding_edge; + GetPrecedingEdgeThirdCorner(preceding_edge_ref); - bool it_is_a = FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , sector_vector , sector_second_point_ref , sector_vector ); + WhichSector following_edge; + WhichSector& following_edge_ref = following_edge; + GetFollowingEdgeThirdCorner(following_edge_ref); - if( it_is_a ) return true; - else return false; + DoCharacterize(sector_first_point_ref , sector_second_point_ref , charact_ref , + in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref); + if (charact == unknown) + { + assert(0); + } - } + return charact; + } - bool PolygonInfo::OneInOneOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref , std::vector first_sector_vector ){ - /*std::vector first_sector_vector; - WhichSector sec_three_to_six = section_three_to_six_o_clock; - first_sector_vector.push_back( sec_three_to_six ); + void PolygonInfo::GetInCombinationThirdCorner(std::vector& in_combination_vector_ref) + { - WhichSector sec_on_edge_six = on_edge_six_o_clock; - first_sector_vector.push_back( sec_on_edge_six ); + WhichSector sec_nine_to_twelve = section_nine_to_twelve_o_clock; + in_combination_vector_ref.push_back(sec_nine_to_twelve); - WhichSector sec_on_edge_three = on_edge_three_o_clock; - first_sector_vector.push_back( sec_on_edge_three );*/ + WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_twelve); - std::vector second_sector_vector; - WhichSector sec_inside = inside_ref; - second_sector_vector.push_back( sec_inside ); + WhichSector sec_on_edge_nine = on_edge_nine_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_nine); - bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , second_sector_vector , sector_second_point_ref , first_sector_vector ); - bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , second_sector_vector , sector_first_point_ref , first_sector_vector ); + } - if( it_is_a || it_is_b ) return true; - else return false; - } + void PolygonInfo::GetInsideThirdCorner(WhichSector& inside_ref) + { + inside_ref = section_nine_to_twelve_o_clock; + } + void PolygonInfo::GetPrecedingEdgeThirdCorner(WhichSector& preceding_edge_ref) + { + preceding_edge_ref = on_edge_twelve_o_clock; + } - bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ + void PolygonInfo::GetFollowingEdgeThirdCorner(WhichSector& following_edge_ref) + { + following_edge_ref = on_edge_nine_o_clock; + } - bool first_one_of_these = false; - bool second_one_of_those = false; - for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ - if( first_sector_vector.at( index ) == sector_first_point_ref ) first_one_of_these = true; - } - for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ - if( second_sector_vector.at( index ) == sector_second_point_ref ) second_one_of_those = true; - } + CharacterizeIntersection PolygonInfo::GetCharacteristicFourthCorner(WhichSector& + sector_first_point_ref , WhichSector& sector_second_point_ref) + { - if( first_one_of_these && second_one_of_those )return true; - else return false; + CharacterizeIntersection charact = unknown; + CharacterizeIntersection& charact_ref = charact; - } + std::vector in_combination_vector; + std::vector& in_combination_vector_ref = in_combination_vector; + GetInCombinationFourthCorner(in_combination_vector_ref); + WhichSector inside; + WhichSector& inside_ref = inside; + GetInsideFourthCorner(inside_ref); + WhichSector preceding_edge; + WhichSector& preceding_edge_ref = preceding_edge; + GetPrecedingEdgeFourthCorner(preceding_edge_ref); + WhichSector following_edge; + WhichSector& following_edge_ref = following_edge; + GetFollowingEdgeFourthCorner(following_edge_ref); - bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ + DoCharacterize(sector_first_point_ref , sector_second_point_ref , charact_ref , + in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref); - bool first_one_of_these = false; - bool second_none_of_those = true; + if (charact == unknown) + { + assert(0); + } - for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ - if( first_sector_vector.at( index ) == sector_first_point_ref ) first_one_of_these = true; - } + return charact; - for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ - if( second_sector_vector.at( index ) == sector_second_point_ref ) second_none_of_those = false; - } + } - if( first_one_of_these && second_none_of_those )return true; - else return false; - } + void PolygonInfo::GetInCombinationFourthCorner(std::vector& in_combination_vector_ref) + { + WhichSector sec_twelve_to_three = section_twelve_to_three_o_clock; + in_combination_vector_ref.push_back(sec_twelve_to_three); + WhichSector sec_on_edge_three = on_edge_three_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_three); + WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; + in_combination_vector_ref.push_back(sec_on_edge_twelve); - bool PolygonInfo::FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ + } - bool first_none_of_these = true; - bool second_none_of_those = true; - for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ - if( first_sector_vector.at( index ) == sector_first_point_ref ) first_none_of_these = false; - } + void PolygonInfo::GetInsideFourthCorner(WhichSector& inside_ref) + { + inside_ref = section_twelve_to_three_o_clock; + } - for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ - if( second_sector_vector.at( index ) == sector_second_point_ref ) second_none_of_those = false; - } - if( first_none_of_these && second_none_of_those )return true; - else return false; + void PolygonInfo::GetPrecedingEdgeFourthCorner(WhichSector& preceding_edge_ref) + { + preceding_edge_ref = on_edge_three_o_clock; + } - } + void PolygonInfo::GetFollowingEdgeFourthCorner(WhichSector& following_edge_ref) + { + following_edge_ref = on_edge_twelve_o_clock; + } - CharacterizeIntersection PolygonInfo::GetCharacteristicSecondCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ - CharacterizeIntersection charact = unknown; - CharacterizeIntersection& charact_ref = charact; + bool PolygonInfo::AppendNextIntersectionAndCorrespoindingPolygonSnippets( + snippet_vector& snip_vec_ref_local , snippet_vector& snip_vec_ref , int current_edge, + VoxelIntersectionIndex& next_voxel_intersection) + { - std::vector in_combination_vector; - std::vector& in_combination_vector_ref = in_combination_vector; - GetInCombinationSecondCorner( in_combination_vector_ref ); + bool finished = false; + bool im_done = false; - WhichSector inside; - WhichSector& inside_ref = inside; - GetInsideSecondCorner( inside_ref ); + LegacyWorldCoordinate2D closest_local_current_position; + LegacyWorldCoordinate2D& closest_local_current_position_ref = closest_local_current_position; + closest_local_current_position.x = current_position.x; + closest_local_current_position.y = current_position.y; - WhichSector preceding_edge; - WhichSector& preceding_edge_ref = preceding_edge; - GetPrecedingEdgeSecondCorner( preceding_edge_ref ); + while (im_done == false) + { - WhichSector following_edge; - WhichSector& following_edge_ref = following_edge; - GetFollowingEdgeSecondCorner( following_edge_ref ); + closest_local_current_position.x = current_position.x; + closest_local_current_position.y = current_position.y; - DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); + // double distance_current_position = GetDistanceAlongEdge( the_dose_index , current_position ); - if( charact == unknown ) assert( 0 ); + // die folgende Funktion macht den naechstliegenden Schnittpunkt ausfindig gespeichert in closest_local_current_position_ref + // the_intersection_index speichert die Information ueber seine Lage im Polygonzug + // hier wird untersucht, ob es einen naechsten Schnittpunkt gibt - return charact; + // float distance_next_intersection = SetToNextIntersectionAlongThisEdgeAndReturnDistance( closest_local_current_position_ref , distance_current_position , current_edge ); - } + unsigned int the_index = 0; + SnippetIndex edge_index; + edge_index.edge = 0; + edge_index.snip = 0; + bool got_one = 0; + got_one = SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( + closest_local_current_position_ref, current_edge, next_voxel_intersection); - void PolygonInfo::GetInCombinationSecondCorner( std::vector& in_combination_vector_ref ){ + //if( distance_next_intersection != ( 1000000 ) ){ // gibt es einen naechsten Schnittpunkt? + if (got_one) + { - WhichSector sec_six_to_nine = section_six_to_nine_o_clock; - in_combination_vector_ref.push_back( sec_six_to_nine ); + // Was der folgende Funktionsaufruf alles tut : + // Hier in AddSnippetsThisIntersection wird untersucht, ob zu dem gefundenen Schnittpunkt + // ein Polygon existiert das innerhalb des Voxels liegt, nur dann, wenn das der Fall ist, wird an snip_vec_ref angehaengt. + // Falls es einen geeigneten Schnittpunkt gibt, all die zugehoerigen + // Polygonsnippets anhaengen. + // Auch wird durch die Funktion AddSnippetsThisIntersection untersucht, ob man schon ausserhalb der betrachteten Kante ist. - WhichSector sec_on_edge_nine = on_edge_nine_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_nine ); + if (AddSnippetsThisIntersection(snip_vec_ref_local , closest_local_current_position)) + { - WhichSector sec_on_edge_six = on_edge_six_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_six ); + im_done = true; + finished = false; + // Falls Polygone gefunden im_done auf true und finished auf false setzen. + // Das bedeutet, an dieser Kante wird weitergearbeitet. Vielleicht gibt es noch mehr Schnittpunkte. - } + } + // falls kein drinnen liegendes Polygonstueck gefunden wurde, welches im Bereich der betrachteten Kante liegt + // bleibt im_done auf false und es wird weiter gesucht + // die current_position wird dann auf den zuletzt gefundenen Schnittpunkt gesetzt, zu dem es kein Polygonstueck gab + current_position.x = closest_local_current_position.x; + current_position.y = closest_local_current_position.y; - void PolygonInfo::GetInsideSecondCorner( WhichSector& inside_ref ){ - inside_ref = section_six_to_nine_o_clock; - } + } + else + { + // es gibt keinen weiteren Schnittpunkt mehr + im_done = true; + finished = true; + } - void PolygonInfo::GetPrecedingEdgeSecondCorner( WhichSector& preceding_edge_ref ){ - preceding_edge_ref = on_edge_nine_o_clock; - } + bool changed_loc = false; + IncrementVoxelIntersectionIndex(current_edge, next_voxel_intersection , changed_loc); + if (changed_loc) + { - void PolygonInfo::GetFollowingEdgeSecondCorner( WhichSector& following_edge_ref ){ - following_edge_ref = on_edge_six_o_clock; - } + if (snip_vec_ref_local.size() > 1) + { + snip_vec_ref_local = SortClockwise(snip_vec_ref_local); + } + for (GridIndexType counter = 0 ; counter < snip_vec_ref_local.size() ; counter++) + { + snip_vec_ref.push_back(snip_vec_ref_local.at(counter)); - CharacterizeIntersection PolygonInfo::GetCharacteristicThirdCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ + } - CharacterizeIntersection charact = unknown; - CharacterizeIntersection& charact_ref = charact; + snip_vec_ref_local.resize(0); - std::vector in_combination_vector; - std::vector& in_combination_vector_ref = in_combination_vector; - GetInCombinationThirdCorner( in_combination_vector_ref ); + } - WhichSector inside; - WhichSector& inside_ref = inside; - GetInsideThirdCorner( inside_ref ); + } - WhichSector preceding_edge; - WhichSector& preceding_edge_ref = preceding_edge; - GetPrecedingEdgeThirdCorner( preceding_edge_ref ); + return finished; - WhichSector following_edge; - WhichSector& following_edge_ref = following_edge; - GetFollowingEdgeThirdCorner( following_edge_ref ); + } - DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); - if( charact == unknown ) assert( 0 ); + void PolygonInfo::IncrementVoxelIntersectionIndex(int current_edge, + VoxelIntersectionIndex& vox_inters_index , bool& changed_location) + { - return charact; + if (voxel_intersections.edge_intersections_intersection_coord.at(current_edge).size() > + vox_inters_index.next_intersection) + { - } + if (voxel_intersections.edge_intersections_intersection_coord.at(current_edge).at( + vox_inters_index.next_intersection).size() > (vox_inters_index.intersection_douplication + 1)) + { + vox_inters_index.intersection_douplication++; + } + else + { - void PolygonInfo::GetInCombinationThirdCorner( std::vector& in_combination_vector_ref ){ + vox_inters_index.intersection_douplication = 0; + vox_inters_index.next_intersection++; + changed_location = true; - WhichSector sec_nine_to_twelve = section_nine_to_twelve_o_clock; - in_combination_vector_ref.push_back( sec_nine_to_twelve ); + } - WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_twelve ); + } - WhichSector sec_on_edge_nine = on_edge_nine_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_nine ); + } - } + // Achtung, bei der verallgemeinerung, die Beruehrpunkte erlaubt, muss hier eine Veraenderung vor werden. + // Es muessen auch naechste Punkte mit Abstand wie der bisherige erlaubt sien. + // Anmerkung : ist insofern erledigt, dass diese Funktion hier nicht mehr verwendet wird. + float PolygonInfo::SetToNextIntersectionAlongThisEdgeAndReturnDistance( + LegacyWorldCoordinate2D& closest_local_current_position_ref , float distance_current_position , + int current_edge) + { - void PolygonInfo::GetInsideThirdCorner( WhichSector& inside_ref ){ - inside_ref = section_nine_to_twelve_o_clock; - } + // Hier wird im Uhrzeigersinn vorwaerts gegangen um den Schnittpunkt zu finden, der dem aktuell betrachteten Schnittpunkt + // am naechsten liegt. Im Uhrzeigersinn zurueck liegende Punkte werden dabei ignoriert. + // Natuerlich ist jeder Punkt sich selbst der Naechste. Selbst wird daher ignoriert. + // diese Funktion gibt -1000000 zurueck, falls kein Punkt gefunden werden konnte. + // Die Distanz wird im Uhrzeigersinn der Voxelkante entlang gemessen. + // Erkannt und gesucht wird nur was auf der betrachteten Voxelkante liegt. + // Es wird der Abstand zu current_position, eindimensional entlang der + // Voxelkante zurueckgegeben. + float distance_current_position_local = 0; + double distance_next_edge = 0; + float min_local_distance = 1000000; + float min_local_distance_along_edge = 1000000; - void PolygonInfo::GetPrecedingEdgeThirdCorner( WhichSector& preceding_edge_ref ){ - preceding_edge_ref = on_edge_twelve_o_clock; - } + LegacyWorldCoordinate2D local_current_position; + local_current_position.x = current_position.x; + local_current_position.y = current_position.y; - void PolygonInfo::GetFollowingEdgeThirdCorner( WhichSector& following_edge_ref ){ - following_edge_ref = on_edge_nine_o_clock; - } + float local_distance; + local_distance = -1000000; + it_poly.RememberPosition(); - CharacterizeIntersection PolygonInfo::GetCharacteristicFourthCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ + it_poly.ResetIntersectionIndex(); - CharacterizeIntersection charact = unknown; - CharacterizeIntersection& charact_ref = charact; + bool was_able_to_increment = true; - std::vector in_combination_vector; - std::vector& in_combination_vector_ref = in_combination_vector; - GetInCombinationFourthCorner( in_combination_vector_ref ); - WhichSector inside; - WhichSector& inside_ref = inside; - GetInsideFourthCorner( inside_ref ); + while (was_able_to_increment == true) + { - WhichSector preceding_edge; - WhichSector& preceding_edge_ref = preceding_edge; - GetPrecedingEdgeFourthCorner( preceding_edge_ref ); + // if( it_poly.CheckToBeRegarded() ){ - WhichSector following_edge; - WhichSector& following_edge_ref = following_edge; - GetFollowingEdgeFourthCorner( following_edge_ref ); - DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); + if (it_poly.ThisIntersection(local_current_position)) + { - if( charact == unknown ) assert( 0 ); + if (IsTheSameEdgeButNoCorner(local_current_position , current_position , current_edge)) + { - return charact; - } + distance_current_position_local = GetDistanceAlongEdge(the_dose_index , local_current_position); + distance_next_edge = GetDistanceNextEdge(current_edge); - void PolygonInfo::GetInCombinationFourthCorner( std::vector& in_combination_vector_ref ){ - WhichSector sec_twelve_to_three = section_twelve_to_three_o_clock; - in_combination_vector_ref.push_back( sec_twelve_to_three ); + if ((static_cast(distance_current_position_local) > static_cast + (distance_current_position)) + && (static_cast(distance_next_edge) > static_cast + (distance_current_position_local))) // betrachtet werden nur die Schnittpunkte, die im Uhrzeigersinn + { + // entlanng der Voxelkante weiter entfernt sind + // echt groesser schliesst Detektion des betracteten Punktes selbst aus - WhichSector sec_on_edge_three = on_edge_three_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_three ); - WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; - in_combination_vector_ref.push_back( sec_on_edge_twelve ); + local_distance = GetPeriodicDist(distance_current_position_local , distance_current_position); - } + if (local_distance < min_local_distance) + { - void PolygonInfo::GetInsideFourthCorner( WhichSector& inside_ref ){ - inside_ref = section_twelve_to_three_o_clock; - } + min_local_distance = local_distance; + min_local_distance_along_edge = distance_current_position_local; + closest_local_current_position_ref.x = local_current_position.x; + closest_local_current_position_ref.y = local_current_position.y; - void PolygonInfo::GetPrecedingEdgeFourthCorner( WhichSector& preceding_edge_ref ){ - preceding_edge_ref = on_edge_three_o_clock; - } + it_poly.RememberPosition(); + } - void PolygonInfo::GetFollowingEdgeFourthCorner( WhichSector& following_edge_ref ){ - following_edge_ref = on_edge_twelve_o_clock; - } + } + } + // } // check to be regarded - bool PolygonInfo::AppendNextIntersectionAndCorrespoindingPolygonSnippets( snippet_vector& snip_vec_ref_local , snippet_vector& snip_vec_ref , int current_edge, VoxelIntersectionIndex& next_voxel_intersection ){ + } - bool finished = false; - bool im_done = false; + was_able_to_increment = it_poly.IncremtentIntersection(); - LegacyWorldCoordinate2D closest_local_current_position; - LegacyWorldCoordinate2D& closest_local_current_position_ref = closest_local_current_position; - closest_local_current_position.x = current_position.x; - closest_local_current_position.y = current_position.y; + } - while( im_done == false ){ + it_poly.JumpToRememberedPosition(); + return min_local_distance_along_edge; - closest_local_current_position.x = current_position.x; - closest_local_current_position.y = current_position.y; + } - // double distance_current_position = GetDistanceAlongEdge( the_dose_index , current_position ); - // die folgende Funktion macht den naechstliegenden Schnittpunkt ausfindig gespeichert in closest_local_current_position_ref - // the_intersection_index speichert die Information ueber seine Lage im Polygonzug - // hier wird untersucht, ob es einen naechsten Schnittpunkt gibt - // float distance_next_intersection = SetToNextIntersectionAlongThisEdgeAndReturnDistance( closest_local_current_position_ref , distance_current_position , current_edge ); - unsigned int the_index = 0; - SnippetIndex edge_index; - edge_index.edge = 0; - edge_index.snip = 0; - - bool got_one = 0; - - got_one = SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( closest_local_current_position_ref, current_edge, next_voxel_intersection ); + // Es ist noetig zu prufen, ob Ecke, wegen Rundungsfehlern. Hier muss auf genau die selbe Art festgestellt werden ob Ecke wie bei der unabhaengigen Betrachtung der Ecken. + // nein, das ist doch nicht noetig. Diese Funktion wird nicht mehr verwendet + bool PolygonInfo::IsTheSameEdgeButNoCorner(LegacyWorldCoordinate2D local_current_position , + LegacyWorldCoordinate2D current_position , int current_edge) + { + LegacyWorldCoordinate2D corner_coord; + corner_coord.x = static_cast(the_dose_index.x); + corner_coord.y = static_cast(the_dose_index.y); - //if( distance_next_intersection != ( 1000000 ) ){ // gibt es einen naechsten Schnittpunkt? - if( got_one ){ + switch (current_edge) + { - // Was der folgende Funktionsaufruf alles tut : - // Hier in AddSnippetsThisIntersection wird untersucht, ob zu dem gefundenen Schnittpunkt - // ein Polygon existiert das innerhalb des Voxels liegt, nur dann, wenn das der Fall ist, wird an snip_vec_ref angehaengt. - // Falls es einen geeigneten Schnittpunkt gibt, all die zugehoerigen - // Polygonsnippets anhaengen. - // Auch wird durch die Funktion AddSnippetsThisIntersection untersucht, ob man schon ausserhalb der betrachteten Kante ist. + case 0 : + + if ((local_current_position.y == current_position.y) + && (local_current_position.x <= (the_dose_index.x + 1)) + && (local_current_position.x >= the_dose_index.x) && (the_dose_index.y == local_current_position.y)) + { + + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } + + corner_coord.x += 1; + + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } + + return true; + + } + else + { + return false; + } + + break; + + case 1 : - if( AddSnippetsThisIntersection( snip_vec_ref_local , closest_local_current_position ) ){ + if ((local_current_position.x == current_position.x) + && (local_current_position.y <= (the_dose_index.y + 1)) + && (local_current_position.y >= the_dose_index.y) + && ((the_dose_index.x + 1) == local_current_position.x)) + { + corner_coord.x += 1; - im_done = true; - finished = false; - // Falls Polygone gefunden im_done auf true und finished auf false setzen. - // Das bedeutet, an dieser Kante wird weitergearbeitet. Vielleicht gibt es noch mehr Schnittpunkte. + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } - } + corner_coord.y += 1; - // falls kein drinnen liegendes Polygonstueck gefunden wurde, welches im Bereich der betrachteten Kante liegt - // bleibt im_done auf false und es wird weiter gesucht - // die current_position wird dann auf den zuletzt gefundenen Schnittpunkt gesetzt, zu dem es kein Polygonstueck gab - current_position.x = closest_local_current_position.x; - current_position.y = closest_local_current_position.y; + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } + return true; + } + else + { + return false; + } - } - else{ + break; - // es gibt keinen weiteren Schnittpunkt mehr - im_done = true; - finished = true; + case 2 : - } - - bool changed_loc = false; - - IncrementVoxelIntersectionIndex( current_edge, next_voxel_intersection , changed_loc ); - - if( changed_loc ){ + if ((local_current_position.y == current_position.y) + && (local_current_position.x <= (the_dose_index.x + 1)) + && (local_current_position.x >= the_dose_index.x) + && ((the_dose_index.y + 1) == local_current_position.y)) + { + corner_coord.x += 1; + corner_coord.y += 1; - if( snip_vec_ref_local.size() > 1 ) snip_vec_ref_local = SortClockwise( snip_vec_ref_local ); + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } - for( GridIndexType counter = 0 ; counter < snip_vec_ref_local.size() ; counter++ ){ - - snip_vec_ref.push_back( snip_vec_ref_local.at( counter ) ); - - } + corner_coord.x -= 1; - snip_vec_ref_local.resize( 0 ); - - } + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } - } + return true; + } + else + { + return false; + } - return finished; + break; - } - - - void PolygonInfo::IncrementVoxelIntersectionIndex( int current_edge, VoxelIntersectionIndex& vox_inters_index , bool& changed_location ){ + case 3 : - if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).size() > vox_inters_index.next_intersection ){ - - if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).at( vox_inters_index.next_intersection ).size() > ( vox_inters_index.intersection_douplication + 1 ) ){ - - vox_inters_index.intersection_douplication++; - - } - else{ - - vox_inters_index.intersection_douplication = 0; - vox_inters_index.next_intersection++; - changed_location = true; - - } - - } + if ((local_current_position.x == current_position.x) + && (local_current_position.y <= (the_dose_index.y + 1)) + && (local_current_position.y >= the_dose_index.y) && (the_dose_index.x == local_current_position.x)) + { + corner_coord.y += 1; - } + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } + corner_coord.y -= 1; - // Achtung, bei der verallgemeinerung, die Beruehrpunkte erlaubt, muss hier eine Veraenderung vor werden. - // Es muessen auch naechste Punkte mit Abstand wie der bisherige erlaubt sien. - // Anmerkung : ist insofern erledigt, dass diese Funktion hier nicht mehr verwendet wird. - float PolygonInfo::SetToNextIntersectionAlongThisEdgeAndReturnDistance( LegacyWorldCoordinate2D& closest_local_current_position_ref , float distance_current_position , int current_edge ){ + if ((static_cast(corner_coord.x) == static_cast(local_current_position.x)) + && (static_cast(corner_coord.y) == static_cast(local_current_position.y))) + { + return false; + } - // Hier wird im Uhrzeigersinn vorwaerts gegangen um den Schnittpunkt zu finden, der dem aktuell betrachteten Schnittpunkt - // am naechsten liegt. Im Uhrzeigersinn zurueck liegende Punkte werden dabei ignoriert. - // Natuerlich ist jeder Punkt sich selbst der Naechste. Selbst wird daher ignoriert. - // diese Funktion gibt -1000000 zurueck, falls kein Punkt gefunden werden konnte. - // Die Distanz wird im Uhrzeigersinn der Voxelkante entlang gemessen. - // Erkannt und gesucht wird nur was auf der betrachteten Voxelkante liegt. - // Es wird der Abstand zu current_position, eindimensional entlang der - // Voxelkante zurueckgegeben. + return true; + } + else + { + return false; + } - float distance_current_position_local = 0; - double distance_next_edge = 0; - float min_local_distance = 1000000; - float min_local_distance_along_edge = 1000000; + break; - LegacyWorldCoordinate2D local_current_position; - local_current_position.x = current_position.x; - local_current_position.y = current_position.y; + default : + assert(0); + } - float local_distance; - local_distance = -1000000; + return false; + } - it_poly.RememberPosition(); - it_poly.ResetIntersectionIndex(); - bool was_able_to_increment = true; - - while( was_able_to_increment == true ){ - // if( it_poly.CheckToBeRegarded() ){ + bool PolygonInfo::AddSnippetsThisIntersection(snippet_vector& snip_vec_ref , + LegacyWorldCoordinate2D closest_local_current_position) + { + bool there_is_a_suitable_polygon_forward = false; + bool there_is_a_suitable_polygon_backward = false; - if( it_poly.ThisIntersection( local_current_position ) ){ + PolygonSnippet forward_snippet; + PolygonSnippet& forward_snippet_ref = forward_snippet; + PolygonSnippet backward_snippet; + PolygonSnippet& backward_snippet_ref = backward_snippet; - if( IsTheSameEdgeButNoCorner( local_current_position , current_position , current_edge ) ){ + // ersten Punkt an beide Polygonschnipsel anhaengen + // Dann beide Schnittpunktelisten untersuchen um festzustellen, welche Punkte zuletzt noch aufgenommen + // werden muss in dieses Polygonstueck. Das geschieht in der Vorwaertsrichtung sowie in der rueckwaertigen Richtung + // durch die folgende Funktion - distance_current_position_local = GetDistanceAlongEdge( the_dose_index , local_current_position ); - distance_next_edge = GetDistanceNextEdge( current_edge ); + bool do_switch = false ; + float angle_charact_a = 0; + float angle_charact_b = 0; - if( ( static_cast( distance_current_position_local ) > static_cast( distance_current_position ) ) && ( static_cast( distance_next_edge ) > static_cast( distance_current_position_local ) ) ){ // betrachtet werden nur die Schnittpunkte, die im Uhrzeigersinn - // entlanng der Voxelkante weiter entfernt sind - // echt groesser schliesst Detektion des betracteten Punktes selbst aus + if (GoForwardAndCreatePolygonSnippet(forward_snippet_ref)) + { + there_is_a_suitable_polygon_forward = true; + } + if (GoBackwardAndCreatePolygonSnippet(backward_snippet_ref)) + { + there_is_a_suitable_polygon_backward = true; + } - local_distance = GetPeriodicDist( distance_current_position_local , distance_current_position ); + if (there_is_a_suitable_polygon_forward) + { + angle_charact_a = forward_snippet_ref.angle_charact; + } + if (there_is_a_suitable_polygon_backward) + { + angle_charact_b = backward_snippet_ref.angle_charact; + } - if( local_distance < min_local_distance ){ - min_local_distance = local_distance; - min_local_distance_along_edge = distance_current_position_local; + if (there_is_a_suitable_polygon_forward) + { + if (there_is_a_suitable_polygon_backward) + { - closest_local_current_position_ref.x = local_current_position.x; - closest_local_current_position_ref.y = local_current_position.y; - it_poly.RememberPosition(); + if (angle_charact_a < angle_charact_b) + { + Switch(forward_snippet_ref , backward_snippet_ref); + } + + //if( ( JustEdge( forward_snippet_ref ) ) && ( JustEdge( backward_snippet_ref ) ) ){ + // nothing happens + //} + + if ((JustEdge(forward_snippet_ref)) && (! JustEdge(backward_snippet_ref))) + { + backward_snippet_ref.characterize = inside_to_edge; + backward_snippet.why_here = closest_local_current_position; + snip_vec_ref.push_back(backward_snippet); + } + else if ((! JustEdge(forward_snippet_ref)) && (JustEdge(backward_snippet_ref))) + { + forward_snippet_ref.characterize = edge_to_inside; + forward_snippet.why_here = closest_local_current_position; + snip_vec_ref.push_back(forward_snippet); + } + else if ((! JustEdge(forward_snippet_ref)) && (! JustEdge(backward_snippet_ref))) + { + backward_snippet_ref.characterize = inside_inside_touches; + backward_snippet.why_here = closest_local_current_position; + snip_vec_ref.push_back(backward_snippet); + forward_snippet_ref.characterize = inside_inside_touches; + forward_snippet.why_here = closest_local_current_position; + snip_vec_ref.push_back(forward_snippet); + } + + } + + } + + + if ((there_is_a_suitable_polygon_forward) && (! there_is_a_suitable_polygon_backward)) + { - } + if (JustEdge(forward_snippet_ref)) + { - } + // nothing happens - } + } + else + { - // } // check to be regarded + forward_snippet_ref.characterize = real_intersection; + forward_snippet.why_here = closest_local_current_position; + snip_vec_ref.push_back(forward_snippet); - } + } - was_able_to_increment = it_poly.IncremtentIntersection(); + } - } - it_poly.JumpToRememberedPosition(); - return min_local_distance_along_edge; + if ((! there_is_a_suitable_polygon_forward) && (there_is_a_suitable_polygon_backward)) + { - } + if (JustEdge(backward_snippet_ref)) + { + } + else + { + backward_snippet_ref.characterize = real_intersection; + backward_snippet_ref.why_here = closest_local_current_position; + snip_vec_ref.push_back(backward_snippet); + } - // Es ist noetig zu prufen, ob Ecke, wegen Rundungsfehlern. Hier muss auf genau die selbe Art festgestellt werden ob Ecke wie bei der unabhaengigen Betrachtung der Ecken. - // nein, das ist doch nicht noetig. Diese Funktion wird nicht mehr verwendet - bool PolygonInfo::IsTheSameEdgeButNoCorner( LegacyWorldCoordinate2D local_current_position , LegacyWorldCoordinate2D current_position , int current_edge ){ + } - LegacyWorldCoordinate2D corner_coord; - corner_coord.x = static_cast( the_dose_index.x ); - corner_coord.y = static_cast( the_dose_index.y ); - switch( current_edge ){ - case 0 : + // Es ist zwar so, dass man das backward snippet, falls es nur ein snippet gibt nicht anhaengen muss, denn in diesem Fall + // ist das backward snippet bereits zum forward snippet geworden (und wird als forward snippet angehaengt). + // Falls es zwei snippets gibt wird nur das forward snippet angehaengt, und zwar das, das im Urzeigersinn richtig liegt. + // Im Zweifelsfall tauschen. + // Falls es nur ein forward snippet gibt wird es angehaengt, falls es im Urzeigersinn liegt. - if( ( local_current_position.y == current_position.y ) && ( local_current_position.x <= ( the_dose_index.x + 1 ) ) && ( local_current_position.x >= the_dose_index.x ) && ( the_dose_index.y == local_current_position.y ) ){ - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - corner_coord.x += 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - return true; - - } - else return false; - break; + // Dann muessen die Polygonstuecke an den snip_vec_ref dran gehaengt werden + // nur falls das Polygonstueck drin liegt anhaengen (GoForwardAndCreatePolygonSnippet GoBackwardAndCreatePolygonSnippet prueft das). - case 1 : + if ((there_is_a_suitable_polygon_forward) || (there_is_a_suitable_polygon_backward)) + { + return true; + } + else + { + return false; + } - if( ( local_current_position.x == current_position.x ) && ( local_current_position.y <= ( the_dose_index.y + 1 ) ) && ( local_current_position.y >= the_dose_index.y ) && ( ( the_dose_index.x + 1 ) == local_current_position.x ) ){ - corner_coord.x += 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - corner_coord.y += 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - return true; - } - else return false; - break; + } - case 2 : - if( ( local_current_position.y == current_position.y ) && ( local_current_position.x <= ( the_dose_index.x + 1 ) ) && ( local_current_position.x >= the_dose_index.x ) && ( ( the_dose_index.y + 1 ) == local_current_position.y ) ){ - corner_coord.x += 1; - corner_coord.y += 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - corner_coord.x -= 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - return true; - } - else return false; - break; - case 3 : + bool PolygonInfo::JustEdge(PolygonSnippet& snippet_ref) + { - if( ( local_current_position.x == current_position.x ) && ( local_current_position.y <= ( the_dose_index.y + 1 ) ) && ( local_current_position.y >= the_dose_index.y ) && ( the_dose_index.x == local_current_position.x ) ){ - corner_coord.y += 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - corner_coord.y -= 1; - if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; - return true; - } - else return false; - break; + bool just_edge = true; - default : + if ((current_edge == 0) || (current_edge == 2)) + { + for (unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; + position++) + { + LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at(position); - assert( 0 ); + if (static_cast(w_coord.y) != static_cast(snippet_ref.point_of_interest_start.y)) + { + just_edge = false; + } + } - } - return false; - } + if (static_cast(snippet_ref.point_of_interest_start.y) != static_cast + (snippet_ref.point_of_interest_end.y)) + { + just_edge = false; + } + } + else if ((current_edge == 1) || (current_edge == 3)) + { + if (static_cast(snippet_ref.point_of_interest_start.x) != static_cast + (snippet_ref.point_of_interest_end.x)) + { + just_edge = false; + } + for (unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; + position++) + { + LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at(position); + + if (static_cast(w_coord.x) != static_cast(snippet_ref.point_of_interest_start.x)) + { + just_edge = false; + } + } + } + else + { + assert(0); + } + return just_edge; + } - bool PolygonInfo::AddSnippetsThisIntersection( snippet_vector& snip_vec_ref , LegacyWorldCoordinate2D closest_local_current_position ){ - bool there_is_a_suitable_polygon_forward = false; - bool there_is_a_suitable_polygon_backward = false; + void PolygonInfo::Switch(PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref) + { - PolygonSnippet forward_snippet; - PolygonSnippet& forward_snippet_ref = forward_snippet; - PolygonSnippet backward_snippet; - PolygonSnippet& backward_snippet_ref = backward_snippet; + PolygonSnippet keep_snippet; + PolygonSnippet& keep_snippet_ref = keep_snippet; + CopySnippet(keep_snippet_ref , snippet_one_ref); + CopySnippet(snippet_one_ref, snippet_two_ref); + CopySnippet(snippet_two_ref, keep_snippet_ref); - // ersten Punkt an beide Polygonschnipsel anhaengen + } - // Dann beide Schnittpunktelisten untersuchen um festzustellen, welche Punkte zuletzt noch aufgenommen - // werden muss in dieses Polygonstueck. Das geschieht in der Vorwaertsrichtung sowie in der rueckwaertigen Richtung - // durch die folgende Funktion - bool do_switch = false ; - float angle_charact_a = 0; - float angle_charact_b = 0; - if( GoForwardAndCreatePolygonSnippet( forward_snippet_ref ) ){ - there_is_a_suitable_polygon_forward = true; - } - if( GoBackwardAndCreatePolygonSnippet( backward_snippet_ref ) ){ - there_is_a_suitable_polygon_backward = true; - } + void PolygonInfo::CopySnippet(PolygonSnippet& to_snippet, PolygonSnippet& snip_in) + { - if( there_is_a_suitable_polygon_forward ){ - angle_charact_a = forward_snippet_ref.angle_charact; - } - if( there_is_a_suitable_polygon_backward ){ - angle_charact_b = backward_snippet_ref.angle_charact; - } + to_snippet.characterize = snip_in.characterize; + to_snippet.is_edge = snip_in.is_edge; + to_snippet.why_here.x = snip_in.why_here.x; + to_snippet.why_here.y = snip_in.why_here.y; - if( there_is_a_suitable_polygon_forward ){ - if( there_is_a_suitable_polygon_backward ){ + to_snippet.point_of_interest_start.x = snip_in.point_of_interest_start.x; + to_snippet.point_of_interest_start.y = snip_in.point_of_interest_start.y; + to_snippet.point_of_interest_end.x = snip_in.point_of_interest_end.x; + to_snippet.point_of_interest_end.y = snip_in.point_of_interest_end.y; - if( angle_charact_a < angle_charact_b ){ - Switch( forward_snippet_ref , backward_snippet_ref ); - } + to_snippet.snippet_intermediate_content.clear(); - //if( ( JustEdge( forward_snippet_ref ) ) && ( JustEdge( backward_snippet_ref ) ) ){ - // nothing happens - //} + for (unsigned int counter = 0 ; counter < snip_in.snippet_intermediate_content.size() ; counter++) + { + to_snippet.snippet_intermediate_content.push_back(snip_in.snippet_intermediate_content.at(counter)); + } - if( ( JustEdge( forward_snippet_ref ) ) && ( ! JustEdge( backward_snippet_ref ) ) ){ - backward_snippet_ref.characterize = inside_to_edge; - backward_snippet.why_here = closest_local_current_position; - snip_vec_ref.push_back( backward_snippet ); - } - else if( ( ! JustEdge( forward_snippet_ref ) ) && ( JustEdge( backward_snippet_ref ) ) ){ - forward_snippet_ref.characterize = edge_to_inside; - forward_snippet.why_here = closest_local_current_position; - snip_vec_ref.push_back( forward_snippet ); - } - else if( ( ! JustEdge( forward_snippet_ref ) ) && ( ! JustEdge( backward_snippet_ref ) ) ){ - backward_snippet_ref.characterize = inside_inside_touches; - backward_snippet.why_here = closest_local_current_position; - snip_vec_ref.push_back( backward_snippet ); - forward_snippet_ref.characterize = inside_inside_touches; - forward_snippet.why_here = closest_local_current_position; - snip_vec_ref.push_back( forward_snippet ); - } - - } + } - } - if( ( there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ){ - if( JustEdge( forward_snippet_ref ) ){ + bool PolygonInfo::GoForwardAndCreatePolygonSnippet(PolygonSnippet& forward_snippet_ref) + { - // nothing happens + // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. + // Falls nein kann man alles folgende ueberspringen. - } - else{ + float& angle_charact_forward = forward_snippet_ref.angle_charact; - forward_snippet_ref.characterize = real_intersection; - forward_snippet.why_here = closest_local_current_position; - snip_vec_ref.push_back( forward_snippet ); - } - } + bool is_inside_valid = CheckPolygonIsInsideForward(angle_charact_forward); + if ((the_dose_index.x == 2) && (the_dose_index.y == 2)) + { + it_poly.PrintIntersectionIndex(); + } - if( ( ! there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ){ + if (is_inside_valid) + { - if( JustEdge( backward_snippet_ref ) ){ + LegacyWorldCoordinate2D& point_of_interest_start_ref = forward_snippet_ref.point_of_interest_start; + LegacyWorldCoordinate2D& point_of_interest_end_ref = forward_snippet_ref.point_of_interest_end; - } - else{ + std::vector& snippet_intermediate_content_ref = + forward_snippet_ref.snippet_intermediate_content; + it_poly.RunForwardToNextIntersection(point_of_interest_start_ref , point_of_interest_end_ref , + snippet_intermediate_content_ref , the_dose_index); - backward_snippet_ref.characterize = real_intersection; - backward_snippet_ref.why_here = closest_local_current_position; - snip_vec_ref.push_back( backward_snippet ); + } - } + return is_inside_valid; - } + } - // Es ist zwar so, dass man das backward snippet, falls es nur ein snippet gibt nicht anhaengen muss, denn in diesem Fall - // ist das backward snippet bereits zum forward snippet geworden (und wird als forward snippet angehaengt). - // Falls es zwei snippets gibt wird nur das forward snippet angehaengt, und zwar das, das im Urzeigersinn richtig liegt. - // Im Zweifelsfall tauschen. - // Falls es nur ein forward snippet gibt wird es angehaengt, falls es im Urzeigersinn liegt. + bool PolygonInfo::GoBackwardAndCreatePolygonSnippet(PolygonSnippet& backward_snippet_ref) + { + // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. + // Falls nein kann man alles folgende ueberspringen. - // Dann muessen die Polygonstuecke an den snip_vec_ref dran gehaengt werden - // nur falls das Polygonstueck drin liegt anhaengen (GoForwardAndCreatePolygonSnippet GoBackwardAndCreatePolygonSnippet prueft das). + float& angle_charact_backward = backward_snippet_ref.angle_charact; + bool is_inside_valid = CheckPolygonIsInsideBackward(angle_charact_backward); - if( ( there_is_a_suitable_polygon_forward ) || ( there_is_a_suitable_polygon_backward ) ) return true; - else return false; + if (is_inside_valid) + { - } + LegacyWorldCoordinate2D& point_of_interest_start_ref = backward_snippet_ref.point_of_interest_start; + LegacyWorldCoordinate2D& point_of_interest_end_ref = backward_snippet_ref.point_of_interest_end; + std::vector& snippet_intermediate_content_ref = + backward_snippet_ref.snippet_intermediate_content; + it_poly.RunBackwardToNextIntersection(point_of_interest_start_ref , point_of_interest_end_ref , + snippet_intermediate_content_ref); + } - bool PolygonInfo::JustEdge( PolygonSnippet& snippet_ref ){ + return is_inside_valid; - bool just_edge = true; + } - if( ( current_edge == 0 ) || ( current_edge == 2 ) ){ - for( unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; position++ ){ - LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at( position ); - if( static_cast( w_coord.y ) != static_cast( snippet_ref.point_of_interest_start.y ) ) just_edge = false; - } - if( static_cast( snippet_ref.point_of_interest_start.y ) != static_cast( snippet_ref.point_of_interest_end.y ) ) just_edge = false; - } - else if( ( current_edge == 1 ) || ( current_edge == 3 ) ){ - if( static_cast( snippet_ref.point_of_interest_start.x ) != static_cast( snippet_ref.point_of_interest_end.x ) ) just_edge = false; - for( unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; position++ ){ - LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at( position ); - if( static_cast( w_coord.x ) != static_cast( snippet_ref.point_of_interest_start.x ) ) just_edge = false; - } - } - else assert( 0 ); - return just_edge; - } + // To do : Sollte man it_poly.NextIntersection( the_next_point_ref ) besser als Funktions-Objekt-Dings uebergeben + // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? + // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Funktionen so verfahren und hat insgesamt weniger Funtionen. + // Das ist to do fuer spaeter. + bool PolygonInfo::CheckPolygonIsInsideForward(float& angle_charact_forward) + { + bool its_inside = false; + it_poly.RememberPosition(); - void PolygonInfo::Switch( PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref ){ + LegacyWorldCoordinate2D the_first_point; + the_first_point.x = 0; + the_first_point.y = 0; + LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; - PolygonSnippet keep_snippet; - PolygonSnippet& keep_snippet_ref = keep_snippet; - CopySnippet( keep_snippet_ref , snippet_one_ref ); + LegacyWorldCoordinate2D the_next_point; + the_next_point.x = 0; + the_next_point.y = 0; + LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; - CopySnippet( snippet_one_ref, snippet_two_ref ); - CopySnippet( snippet_two_ref, keep_snippet_ref ); + if (it_poly.ThisIntersection(the_first_point_ref)) + { - } + bool got_it = it_poly.NextPointOrIntersectionPeriodically(the_first_point_ref, the_next_point_ref, + the_dose_index); + int maxNum = it_poly.MaximumNumberOfElements(); + int stop_counter = -1; + while ((stop_counter < (maxNum + 2))) + { + stop_counter++; - void PolygonInfo::CopySnippet( PolygonSnippet& to_snippet, PolygonSnippet& snip_in ){ + /* + double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); + close_first = sqrt( close_first ); + if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich - to_snippet.characterize = snip_in.characterize; - to_snippet.is_edge = snip_in.is_edge; + double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); + close_second = sqrt( close_second ); + if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; + */ - to_snippet.why_here.x = snip_in.why_here.x; - to_snippet.why_here.y = snip_in.why_here.y; + if ((static_cast(the_next_point.x) != static_cast(the_first_point.x)) + || (static_cast(the_next_point.x) != static_cast(the_first_point.x))) + { + stop_counter = (maxNum + 2); + } - to_snippet.point_of_interest_start.x = snip_in.point_of_interest_start.x; - to_snippet.point_of_interest_start.y = snip_in.point_of_interest_start.y; + if ((static_cast(the_next_point.y) != static_cast(the_first_point.y)) + || (static_cast(the_next_point.y) != static_cast(the_first_point.y))) + { + stop_counter = (maxNum + 2); + } - to_snippet.point_of_interest_end.x = snip_in.point_of_interest_end.x; - to_snippet.point_of_interest_end.y = snip_in.point_of_interest_end.y; + if (stop_counter < (maxNum + 2)) + { + got_it = it_poly.NextPointOrIntersectionPeriodically(the_first_point_ref, the_next_point_ref, + the_dose_index); + } - to_snippet.snippet_intermediate_content.clear(); + } - for( unsigned int counter = 0 ; counter < snip_in.snippet_intermediate_content.size() ; counter++ ){ - to_snippet.snippet_intermediate_content.push_back( snip_in.snippet_intermediate_content.at( counter ) ); - } + if (got_it == false) + { + assert(0); + } - } + if ((got_it) && ((static_cast(the_next_point.x) != static_cast(the_first_point.x)) + || (static_cast(the_next_point.y) != static_cast(the_first_point.y)))) + { + LegacyWorldCoordinate2D an_intermediate_point; + an_intermediate_point.x = ((the_first_point.x + the_next_point.x) * 0.5) ; + an_intermediate_point.y = ((the_first_point.y + the_next_point.y) * 0.5) ; + GetAngle(the_next_point , the_first_point , angle_charact_forward); - bool PolygonInfo::GoForwardAndCreatePolygonSnippet( PolygonSnippet& forward_snippet_ref ){ + if (CheckPointInVoxelRegardingDoseIndex(an_intermediate_point)) + { + its_inside = true; + } - // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. - // Falls nein kann man alles folgende ueberspringen. + } + else + { + its_inside = false; + } - float& angle_charact_forward = forward_snippet_ref.angle_charact; + } + it_poly.JumpToRememberedPosition(); - bool is_inside_valid = CheckPolygonIsInsideForward( angle_charact_forward ); - - if( ( the_dose_index.x == 2 ) && ( the_dose_index.y == 2 ) ){ - it_poly.PrintIntersectionIndex(); - } - - if( is_inside_valid ){ + return its_inside; - LegacyWorldCoordinate2D& point_of_interest_start_ref = forward_snippet_ref.point_of_interest_start; - LegacyWorldCoordinate2D& point_of_interest_end_ref = forward_snippet_ref.point_of_interest_end; + } - std::vector& snippet_intermediate_content_ref = forward_snippet_ref.snippet_intermediate_content; - it_poly.RunForwardToNextIntersection( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref , the_dose_index ); - } - return is_inside_valid; - } + // Je kleiner der Winkel zwischen Kantenrichtung im Uhrzeigersinn und Strukturelement, desto groesser der Rueckgabewert. Der + // Rueckgabewert ist der Cosisnus dieses Winkels und ist daher 1, falls der Winkel null ist - minus eins ist er falls der + // Winkel 180 Grad gegen die Kante laueft. Da hier nur Strukturelemente betrachtet werden, die ins Voxel rein laufen, + // gibt es Winkel gruesser als 180 Grad nicht. + void PolygonInfo::GetAngle(LegacyWorldCoordinate2D the_next_point , + LegacyWorldCoordinate2D the_first_point , float& angle_charact) + { + double hypoten = (the_next_point.x - the_first_point.x) * (the_next_point.x - the_first_point.x) + + (the_next_point.y - the_first_point.y) * (the_next_point.y - the_first_point.y); - bool PolygonInfo::GoBackwardAndCreatePolygonSnippet( PolygonSnippet& backward_snippet_ref ){ + assert(hypoten > + 0); // This should never happen except in case of a structure consisting of one point only. However, that's not allowed in voxelisation. - // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. - // Falls nein kann man alles folgende ueberspringen. + if (current_edge == 0) + { + hypoten = sqrt(hypoten); + double gekat = (the_next_point.x - the_first_point.x); + angle_charact = static_cast((gekat / hypoten)); + } - float& angle_charact_backward = backward_snippet_ref.angle_charact; - bool is_inside_valid = CheckPolygonIsInsideBackward( angle_charact_backward ); + if (current_edge == 1) + { + hypoten = sqrt(hypoten); + double ankat = (the_next_point.y - the_first_point.y); + angle_charact = static_cast((ankat / hypoten)); + } - if( is_inside_valid ){ + if (current_edge == 2) + { + hypoten = sqrt(hypoten); + double gekat = (the_first_point.x - the_next_point.x); + angle_charact = static_cast((gekat / hypoten)); + } - LegacyWorldCoordinate2D& point_of_interest_start_ref = backward_snippet_ref.point_of_interest_start; - LegacyWorldCoordinate2D& point_of_interest_end_ref = backward_snippet_ref.point_of_interest_end; - std::vector& snippet_intermediate_content_ref = backward_snippet_ref.snippet_intermediate_content; + if (current_edge == 3) + { + hypoten = sqrt(hypoten); + double ankat = (the_first_point.y - the_next_point.y); + angle_charact = static_cast((ankat / hypoten)); + } - it_poly.RunBackwardToNextIntersection( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref ); + } - } - return is_inside_valid; - } + // To do : Kann man it_poly.NextIntersection( the_next_point_ref ) nicht als Funktions-Objekts-Dings uebergeben + // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? + // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Sachen so verfahren. + // Mache das spaeter. + bool PolygonInfo::CheckPolygonIsInsideBackward(float& angle_charact_backward) + { - // To do : Sollte man it_poly.NextIntersection( the_next_point_ref ) besser als Funktions-Objekt-Dings uebergeben - // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? - // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Funktionen so verfahren und hat insgesamt weniger Funtionen. - // Das ist to do fuer spaeter. - bool PolygonInfo::CheckPolygonIsInsideForward( float& angle_charact_forward ){ + bool its_inside = false; - bool its_inside = false; + it_poly.RememberPosition(); - it_poly.RememberPosition(); + LegacyWorldCoordinate2D the_first_point; + the_first_point.x = 0; + the_first_point.y = 0; + LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; - LegacyWorldCoordinate2D the_first_point; - the_first_point.x =0; - the_first_point.y = 0; - LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; + LegacyWorldCoordinate2D the_next_point; + the_next_point.x = 0; + the_next_point.y = 0; + LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; - LegacyWorldCoordinate2D the_next_point; - the_next_point.x =0; - the_next_point.y = 0; - LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; + if (it_poly.ThisIntersection(the_first_point_ref)) + { - if( it_poly.ThisIntersection( the_first_point_ref ) ){ + bool got_it = it_poly.PreviousPointOrIntersectionPeriodically(the_first_point_ref , + the_next_point_ref , the_dose_index); - bool got_it = it_poly.NextPointOrIntersectionPeriodically( the_first_point_ref, the_next_point_ref, the_dose_index ); + int stop_counter = -1; + int maxNum = it_poly.MaximumNumberOfElements(); - int maxNum = it_poly.MaximumNumberOfElements(); + while ((stop_counter < maxNum)) + { - int stop_counter = -1; + stop_counter++; - while( ( stop_counter < ( maxNum + 2 ) ) ){ + /*double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); + close_first = sqrt( close_first ); + if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich - stop_counter++; + double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); + close_second = sqrt( close_second ); + if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; */ - /* - double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); - close_first = sqrt( close_first ); - if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich - double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); - close_second = sqrt( close_second ); - if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; - */ - - if( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) ) stop_counter = ( maxNum + 2 ); - if( ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) stop_counter = ( maxNum + 2 ); + if ((static_cast(the_next_point.x) != static_cast(the_first_point.x)) + || (static_cast(the_next_point.x) != static_cast(the_first_point.x))) + { + stop_counter = maxNum; + } - if( stop_counter < ( maxNum + 2 ) ) got_it = it_poly.NextPointOrIntersectionPeriodically( the_first_point_ref, the_next_point_ref, the_dose_index ); + if ((static_cast(the_next_point.y) != static_cast(the_first_point.y)) + || (static_cast(the_next_point.y) != static_cast(the_first_point.y))) + { + stop_counter = maxNum; + } - } - if( got_it == false )assert( 0 ); + if (stop_counter < maxNum) + { + got_it = it_poly.PreviousPointOrIntersectionPeriodically(the_first_point_ref , the_next_point_ref , + the_dose_index); + } - if( ( got_it ) && ( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) ){ - LegacyWorldCoordinate2D an_intermediate_point; - an_intermediate_point.x =( ( the_first_point.x + the_next_point.x ) * 0.5) ; - an_intermediate_point.y = ( ( the_first_point.y + the_next_point.y ) * 0.5) ; + } - GetAngle( the_next_point , the_first_point , angle_charact_forward ); + if (got_it == false) + { + assert(0); + } - if( CheckPointInVoxelRegardingDoseIndex( an_intermediate_point ) ) its_inside = true; - } - else its_inside = false; + if ((got_it) && ((static_cast(the_next_point.x) != static_cast(the_first_point.x)) + || (static_cast(the_next_point.y) != static_cast(the_first_point.y)))) + { + LegacyWorldCoordinate2D an_intermediate_point; + an_intermediate_point.x = ((the_first_point.x + the_next_point.x) * 0.5); + an_intermediate_point.y = ((the_first_point.y + the_next_point.y) * 0.5); - } + GetAngle(the_next_point , the_first_point , angle_charact_backward); - it_poly.JumpToRememberedPosition(); + if (CheckPointInVoxelRegardingDoseIndex(an_intermediate_point)) + { + its_inside = true; + } - return its_inside; + } + else + { + its_inside = false; + } - } + } + else + { + assert(0); + } + it_poly.JumpToRememberedPosition(); + return its_inside; + } - // Je kleiner der Winkel zwischen Kantenrichtung im Uhrzeigersinn und Strukturelement, desto groesser der Rueckgabewert. Der - // Rueckgabewert ist der Cosisnus dieses Winkels und ist daher 1, falls der Winkel null ist - minus eins ist er falls der - // Winkel 180 Grad gegen die Kante laueft. Da hier nur Strukturelemente betrachtet werden, die ins Voxel rein laufen, - // gibt es Winkel gruesser als 180 Grad nicht. - void PolygonInfo::GetAngle( LegacyWorldCoordinate2D the_next_point , LegacyWorldCoordinate2D the_first_point , float& angle_charact ){ - double hypoten = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ) + ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); + bool PolygonInfo::CheckPointInVoxelRegardingDoseIndex(LegacyWorldCoordinate2D + voxel_coordinate_to_be_checked) + { - assert( hypoten > 0 ); // This should never happen except in case of a structure consisting of one point only. However, that's not allowed in voxelisation. + bool its_inside = false; - if( current_edge == 0 ){ - hypoten = sqrt( hypoten ); - double gekat = ( the_next_point.x - the_first_point.x ); - angle_charact = static_cast( ( gekat / hypoten ) ); - } - if( current_edge == 1 ){ - hypoten = sqrt( hypoten ); - double ankat = ( the_next_point.y - the_first_point.y ); - angle_charact = static_cast( ( ankat / hypoten ) ); - } - if( current_edge == 2 ){ - hypoten = sqrt( hypoten ); - double gekat = ( the_first_point.x - the_next_point.x ); - angle_charact = static_cast( ( gekat / hypoten ) ); - } - if( current_edge == 3 ){ - hypoten = sqrt( hypoten ); - double ankat = ( the_first_point.y - the_next_point.y ); - angle_charact = static_cast( ( ankat / hypoten ) ); - } + if ((voxel_coordinate_to_be_checked.x <= (the_dose_index.x + 1)) + && (voxel_coordinate_to_be_checked.x >= the_dose_index.x) + && (voxel_coordinate_to_be_checked.y <= (the_dose_index.y + 1)) + && (voxel_coordinate_to_be_checked.y >= the_dose_index.y)) + { + its_inside = true; + } - } + return its_inside; + } - // To do : Kann man it_poly.NextIntersection( the_next_point_ref ) nicht als Funktions-Objekts-Dings uebergeben - // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? - // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Sachen so verfahren. - // Mache das spaeter. - bool PolygonInfo::CheckPolygonIsInsideBackward( float& angle_charact_backward ){ + double PolygonInfo::GetDistanceNextEdge(int current_edge) + { - bool its_inside = false; + double return_distance; - it_poly.RememberPosition(); - LegacyWorldCoordinate2D the_first_point; - the_first_point.x =0; - the_first_point.y = 0; - LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; + switch (current_edge) + { - LegacyWorldCoordinate2D the_next_point; - the_next_point.x =0; - the_next_point.y = 0; - LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; - if( it_poly.ThisIntersection( the_first_point_ref ) ){ + case 0 : + return_distance = GInformation.getPixelSpacingRow(); + break; - bool got_it = it_poly.PreviousPointOrIntersectionPeriodically( the_first_point_ref , the_next_point_ref , the_dose_index ); - int stop_counter = -1; - int maxNum = it_poly.MaximumNumberOfElements(); + case 1 : + return_distance = GInformation.getPixelSpacingColumn(); + return_distance += GInformation.getPixelSpacingRow(); + break; - while( ( stop_counter < maxNum ) ){ + case 2 : + return_distance = GInformation.getPixelSpacingColumn(); + return_distance += 2 * GInformation.getPixelSpacingRow(); + break; - stop_counter++; + case 3 : + return_distance = 2 * GInformation.getPixelSpacingColumn(); + return_distance += 2 * GInformation.getPixelSpacingRow(); + break; - /*double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); - close_first = sqrt( close_first ); - if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich - double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); - close_second = sqrt( close_second ); - if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; */ + } - if( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) ) stop_counter = maxNum; + return return_distance; - if( ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) stop_counter = maxNum; + } - if( stop_counter < maxNum ) got_it = it_poly.PreviousPointOrIntersectionPeriodically( the_first_point_ref , the_next_point_ref , the_dose_index ); + float PolygonInfo::GetDistanceAlongEdge(LegacyDoseVoxelIndex3D edge_position , + LegacyWorldCoordinate2D local_position) + { + WorldCoordinate return_distance; - } + if (local_position.y == edge_position.y) + { + return_distance = (local_position.x - edge_position.x) * GInformation.getPixelSpacingRow(); + } + else if (local_position.y == (edge_position.y + 1)) + { + return_distance = GInformation.getPixelSpacingRow() - (local_position.x - edge_position.x) * + GInformation.getPixelSpacingRow(); + return_distance += GInformation.getPixelSpacingColumn(); + return_distance += GInformation.getPixelSpacingRow(); - if( got_it == false )assert( 0 ); + } + else if (local_position.x == edge_position.x) + { + return_distance = 2 * GInformation.getPixelSpacingRow(); + return_distance += GInformation.getPixelSpacingColumn(); + return_distance += GInformation.getPixelSpacingColumn() - (local_position.y - edge_position.y) * + GInformation.getPixelSpacingColumn(); - if( ( got_it ) && ( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) ){ + } + else if (local_position.x == (edge_position.x + 1)) + { + return_distance = GInformation.getPixelSpacingRow(); + return_distance += (local_position.y - edge_position.y) * GInformation.getPixelSpacingColumn(); - LegacyWorldCoordinate2D an_intermediate_point; - an_intermediate_point.x =( ( the_first_point.x + the_next_point.x ) * 0.5 ); - an_intermediate_point.y = ( ( the_first_point.y + the_next_point.y ) * 0.5 ); + } + else + { + // assert : Etwas ist schief gegangen. Wenn es sich wirklich um einen Schnittpunkt handelt, + // dann muesste einer der obigen Faelle eingetreten sein. + assert(0); + } - GetAngle( the_next_point , the_first_point , angle_charact_backward ); + return return_distance; - if( CheckPointInVoxelRegardingDoseIndex( an_intermediate_point ) ) its_inside = true; + } - } - else its_inside = false; - } - else assert(0); - it_poly.JumpToRememberedPosition(); + // Returns 1D distance of two Points along edge. + // Both Points are located on the edge of the voxel and the - return its_inside; + float PolygonInfo::GetPeriodicDist(float distance_current_position_local , + float distance_current_position) + { - } + float distance_oneD_return; + float max_distance = static_cast(2 * GInformation.getPixelSpacingRow() + 2 * + GInformation.getPixelSpacingColumn()); + if (distance_current_position_local >= distance_current_position) + { - bool PolygonInfo::CheckPointInVoxelRegardingDoseIndex( LegacyWorldCoordinate2D voxel_coordinate_to_be_checked ){ + distance_oneD_return = distance_current_position_local - distance_current_position; - bool its_inside = false; + float cross_edge_distance = (max_distance - distance_current_position_local) + + distance_current_position; - if( ( voxel_coordinate_to_be_checked.x <= ( the_dose_index.x + 1 ) ) && ( voxel_coordinate_to_be_checked.x >= the_dose_index.x ) && ( voxel_coordinate_to_be_checked.y <= ( the_dose_index.y + 1 ) ) && ( voxel_coordinate_to_be_checked.y >= the_dose_index.y ) ) its_inside = true; + if (cross_edge_distance < distance_oneD_return) + { + distance_oneD_return = cross_edge_distance; + } + } + else + { - return its_inside; + distance_oneD_return = distance_current_position - distance_current_position_local; - } + float cross_edge_distance = (max_distance - distance_current_position) + + distance_current_position_local; + if (cross_edge_distance < distance_oneD_return) + { + distance_oneD_return = cross_edge_distance; + } + } - double PolygonInfo::GetDistanceNextEdge( int current_edge ){ + return distance_oneD_return; - double return_distance; + } - switch( current_edge ){ + double PolygonInfo::GetClockwiseDist(double distance_refer_to , double distance_compare) + { - case 0 : - return_distance = GInformation.getPixelSpacingRow(); - break; + double distance_oneD_return; + double max_distance = static_cast(2 * GInformation.getPixelSpacingRow() + 2 * + GInformation.getPixelSpacingColumn()); - case 1 : - return_distance = GInformation.getPixelSpacingColumn(); - return_distance += GInformation.getPixelSpacingRow(); - break; + if (distance_compare >= distance_refer_to) + { - case 2 : - return_distance = GInformation.getPixelSpacingColumn(); - return_distance += 2*GInformation.getPixelSpacingRow(); - break; + distance_oneD_return = distance_compare - distance_refer_to; - case 3 : - return_distance = 2*GInformation.getPixelSpacingColumn(); - return_distance += 2*GInformation.getPixelSpacingRow(); - break; + } + else + { + distance_oneD_return = (max_distance - distance_refer_to) + distance_compare; - } + } + return distance_oneD_return; - return return_distance; + } - } + /* - float PolygonInfo::GetDistanceAlongEdge( LegacyDoseVoxelIndex3D edge_position , LegacyWorldCoordinate2D local_position ){ + // Es gibt einen current_static_index, der besagt welches Polygon gerade erzeugt wird. - WorldCoordinate return_distance; + // Und einen current_moving_index, der einmal ums Voxel laueft. + // Auserdem einen begin_index, der sagt, wo man mit der Erzeugung des umschliessenden Polygons angefangen hat + // und wider aufhoeren will. - if( local_position.y == edge_position.y ){ - return_distance = ( local_position.x - edge_position.x ) * GInformation.getPixelSpacingRow(); - } - else if( local_position.y == ( edge_position.y + 1 ) ){ - return_distance = GInformation.getPixelSpacingRow() - ( local_position.x - edge_position.x ) * GInformation.getPixelSpacingRow(); - return_distance += GInformation.getPixelSpacingColumn(); - return_distance += GInformation.getPixelSpacingRow(); - } - else if( local_position.x == edge_position.x ){ + current_static_index klappert jetzt die Voxelkante ab. + Fuer jeden zweiten drinnen-drausen-Wechsel (den gibt es bei echten Schnittpunkten und manchen Beruehrpunkten) + wird nun also ein innen-geschlossenes-Polygon berechnet. + Das geschieht indem fuer die entsprechende Position des current_static_index solange der current_moving_index + verschoben wird, bis man im Kreis rum ist. + Der current_moving_index wird dabei in doppleschritten verschoben: + Erst der Kante entlang zum naechsten echten Schnittpunkt oder Beruehrpunkt der zweiten Art. + Dann wird diesem Polygonsnippet zu sienem anderen + Schnittpunkt/Beruehrpunkt gefolgt. Das Polygonsnippet und die Randpunkte werden dabei an das derzeit zu erzeugende + Innenpolygon angehaengt. - return_distance = 2 * GInformation.getPixelSpacingRow(); - return_distance += GInformation.getPixelSpacingColumn(); - return_distance += GInformation.getPixelSpacingColumn() - ( local_position.y - edge_position.y ) * GInformation.getPixelSpacingColumn(); + Im Idealfall weiss man von einer Voxelecke anhand der Maske, dass sie draussen liegt. - }else if( local_position.x == ( edge_position.x + 1 ) ){ - return_distance = GInformation.getPixelSpacingRow(); - return_distance += ( local_position.y - edge_position.y ) * GInformation.getPixelSpacingColumn(); + Falls es keine Voxelecke gibt von der man eindeutig sagen kann dass sie draussen liegt und auf die man dann den begin_index setzen kann, + dann wird gesucht, ob es irgend eine Ecke gibt, die nicht Schnitt oder Beruehrpunkt ist. Per VoxelInStructure aus der Tooblox kann man sich in + diesem Fall behelfen. - } - else{ - // assert : Etwas ist schief gegangen. Wenn es sich wirklich um einen Schnittpunkt handelt, - // dann muesste einer der obigen Faelle eingetreten sein. - assert( 0 ); - } + Falls alle Ecken Beruehr oder Schnittpunkte sind, wird zunaechst geprueft, ob es nur Polygonsnippets gibt, die den Kanten entlang + laufen. Falls das so ist, wird VoxelInStructure der Toolbox fuer das Zentrum des Voxels aufgerufen. + Wenn das Zentrum drin ist, dann ist das ganze Voxel von der Kontur umschlossen. + Falls nicht liegt das ganze Voxel ausserhalb. - return return_distance; + Falls alle Voxelecken Schnitt/Beruehrpunkte sind und falls es sehr wohl echte Schnitte gibt: + Einen Punkt finden, der echter Schnittpunkt ist. Seine Nachbarschaft per VoxelInStructure aus der Tooblox untersuchen. - } + */ + // Anmerkung : Hier werden Aenderungen noetig sien, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. + // Die Aenderung wird darin bestehen, dass mehrere snippets mit dem selben why_here Wert existieren, die gleichberechtigt + // behandelt werden nach dem Winkel des sich nach innnen fortsetzenden Strukturelements geordnet sind. Diese werden dann + // behandelt wei ueblich (also keine echte Aenderung des Programmablaufs nur der Art der Polygon - Snippets ) - // Returns 1D distance of two Points along edge. - // Both Points are located on the edge of the voxel and the + // Polygon aufbauen: resulting_sequence wird hier belegt + bool PolygonInfo::CreatePolygonSequence() + { - float PolygonInfo::GetPeriodicDist( float distance_current_position_local , float distance_current_position ){ + CalcSnippetVectors(); - float distance_oneD_return; + SnippetIndex& current_static_index_ref = current_static_index; - float max_distance = static_cast( 2 * GInformation.getPixelSpacingRow() + 2 * GInformation.getPixelSpacingColumn() ); + // Es wird im idealfall in einer Ecke mit bekanntem drinnen /drausen begonnen. begin_index wird dort drauf gesetzt. + // current_static_index wird solange eins weiter gesetzt bis man wieder am Anfang ankommt. + // falls die Kontur gar nicht ins voxel rein laueft wird nothing_to_do auf true gesetzt - if( distance_current_position_local >= distance_current_position ){ + bool nothing_to_do = false; + bool& nothing_to_do_ref = nothing_to_do; - distance_oneD_return = distance_current_position_local - distance_current_position; - float cross_edge_distance = ( max_distance - distance_current_position_local ) + distance_current_position; + // SetCurrentStaticIndexKnownInsideOrOutside gibt zum einen ueber its_inside die information darueber zurueck, + // ob der Punkt auf den current_static_index gesetzt wurde im aussenbereich der Kontur liegt. + // Zum anderen enthaelt nothing_to_do_ref nach Aufruf von SetCurrentStaticIndexKnownInsideOrOutside die + // Information darueber, ob das Voxel ueberhaupt angeschnitten ist. Ist nothing_to_do_ref true, so ist das Voxel + // gar nicht angeschnitten. Ist dann auch noch its_inside true, dann liegt das ganze Voxel komplett im innern der Struktur. + // Ansonsten liegt das ganze Voxel komplett ausserhalb der Struktur. + bool its_inside = SetCurrentStaticIndexKnownInsideOrOutside(current_static_index_ref , + nothing_to_do_ref); // Falls es eine Ecke gibt, die draussen liegt wird hier false zurueckgegeben. + bool just_switched_inside = false; - if( cross_edge_distance < distance_oneD_return ) distance_oneD_return = cross_edge_distance; + if (its_inside) + { + just_switched_inside = true; + } - } - else{ - distance_oneD_return = distance_current_position - distance_current_position_local; + /* std::cout<< " the_dose_index.x : " << the_dose_index.x <( 2 * GInformation.getPixelSpacingRow() + 2 * GInformation.getPixelSpacingColumn() ); + }*/ - if( distance_compare >= distance_refer_to ){ - distance_oneD_return = distance_compare - distance_refer_to; + if (nothing_to_do == false) + { - } - else{ - distance_oneD_return = ( max_distance - distance_refer_to ) + distance_compare; - } + CopySnippetIndex(current_static_index , begin_index); + CopySnippetIndex(current_static_index , current_moving_index); - return distance_oneD_return; - - } + int max_num = GetMaxNumberSnippets(); + int& max_num_ref = max_num; + // auch wenn der status "falsch" gesetzt wurde, funktioniert doch das umschalten dennoch + // es ist also egal, ob man den ersten Schnitt als hinein, oder als hinauslaufend definiert, denn die Struktur ist ohnehin zyklisch + edge_status = edge_or_outside; + bool& its_inside_ref = its_inside; + bool next_is_edge = true; + bool& next_is_edge_ref = next_is_edge; + bool& just_switched_inside_ref = just_switched_inside; - /* + bool its_first_current_static = true; - // Es gibt einen current_static_index, der besagt welches Polygon gerade erzeugt wird. + while ((! SnippetIndexIdentical(begin_index , current_static_index)) + || (its_first_current_static == true)) + { - // Und einen current_moving_index, der einmal ums Voxel laueft. - // Auserdem einen begin_index, der sagt, wo man mit der Erzeugung des umschliessenden Polygons angefangen hat - // und wider aufhoeren will. + its_first_current_static = false; - current_static_index klappert jetzt die Voxelkante ab. - Fuer jeden zweiten drinnen-drausen-Wechsel (den gibt es bei echten Schnittpunkten und manchen Beruehrpunkten) - wird nun also ein innen-geschlossenes-Polygon berechnet. - Das geschieht indem fuer die entsprechende Position des current_static_index solange der current_moving_index - verschoben wird, bis man im Kreis rum ist. - Der current_moving_index wird dabei in doppleschritten verschoben: - Erst der Kante entlang zum naechsten echten Schnittpunkt oder Beruehrpunkt der zweiten Art. - Dann wird diesem Polygonsnippet zu sienem anderen - Schnittpunkt/Beruehrpunkt gefolgt. Das Polygonsnippet und die Randpunkte werden dabei an das derzeit zu erzeugende - Innenpolygon angehaengt. + CopySnippetIndex(current_static_index , current_moving_index); - Im Idealfall weiss man von einer Voxelecke anhand der Maske, dass sie draussen liegt. + CheckInside(current_moving_index , its_inside_ref , just_switched_inside_ref); - Falls es keine Voxelecke gibt von der man eindeutig sagen kann dass sie draussen liegt und auf die man dann den begin_index setzen kann, - dann wird gesucht, ob es irgend eine Ecke gibt, die nicht Schnitt oder Beruehrpunkt ist. Per VoxelInStructure aus der Tooblox kann man sich in - diesem Fall behelfen. + // Jedes zweite weitersetzen erzeugt ein innenpolygon. Eventuell jedes zweite ein Ausenbereichs polygon, das ein Stueck Ausenbereich + // des betrachteten Voxels umschliesst. - Falls alle Ecken Beruehr oder Schnittpunkte sind, wird zunaechst geprueft, ob es nur Polygonsnippets gibt, die den Kanten entlang - laufen. Falls das so ist, wird VoxelInStructure der Toolbox fuer das Zentrum des Voxels aufgerufen. - Wenn das Zentrum drin ist, dann ist das ganze Voxel von der Kontur umschlossen. - Falls nicht liegt das ganze Voxel ausserhalb. + next_is_edge = GetNextIsEdge(current_moving_index); - Falls alle Voxelecken Schnitt/Beruehrpunkte sind und falls es sehr wohl echte Schnitte gibt: - Einen Punkt finden, der echter Schnittpunkt ist. Seine Nachbarschaft per VoxelInStructure aus der Tooblox untersuchen. + if (! next_is_edge) // hier soll ein Snippet uebersprungen werden, weil das heran und das weglaufende vertreten sind. Verfolgt werden soll aber nur das weiterfuerende. Das heranfuehrende wird das snippet sein ueber das der Kreis am Ende geschlossen wird. Muss hier zunaechst nicht betrachtet werden. + { + IncrementSnippetIndex(current_static_index); + CopySnippetIndex(current_static_index , current_moving_index); + } + if ((((its_inside) && (just_switched_inside_ref)) || (next_is_edge == false)) + && (! CurrentSnippetIsProcessed())) + { - */ + AppendNewPolygonToResultingSequence(); - // Anmerkung : Hier werden Aenderungen noetig sien, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. - // Die Aenderung wird darin bestehen, dass mehrere snippets mit dem selben why_here Wert existieren, die gleichberechtigt - // behandelt werden nach dem Winkel des sich nach innnen fortsetzenden Strukturelements geordnet sind. Diese werden dann - // behandelt wei ueblich (also keine echte Aenderung des Programmablaufs nur der Art der Polygon - Snippets ) + bool do_continue = true; + bool& do_continue_ref = do_continue; - // Polygon aufbauen: resulting_sequence wird hier belegt - bool PolygonInfo::CreatePolygonSequence(){ + int continue_counter = 0; + int& continue_counter_ref = continue_counter; - CalcSnippetVectors(); - - SnippetIndex& current_static_index_ref = current_static_index; - // Es wird im idealfall in einer Ecke mit bekanntem drinnen /drausen begonnen. begin_index wird dort drauf gesetzt. - // current_static_index wird solange eins weiter gesetzt bis man wieder am Anfang ankommt. - // falls die Kontur gar nicht ins voxel rein laueft wird nothing_to_do auf true gesetzt + while (do_continue) + { - bool nothing_to_do = false; - bool& nothing_to_do_ref = nothing_to_do; + // Baustelle was mit ( !CurrentSnippetIsProcessed() ) und assert ! + GoGetPoly(do_continue_ref , next_is_edge_ref, continue_counter_ref , max_num_ref); - // SetCurrentStaticIndexKnownInsideOrOutside gibt zum einen ueber its_inside die information darueber zurueck, - // ob der Punkt auf den current_static_index gesetzt wurde im aussenbereich der Kontur liegt. - // Zum anderen enthaelt nothing_to_do_ref nach Aufruf von SetCurrentStaticIndexKnownInsideOrOutside die - // Information darueber, ob das Voxel ueberhaupt angeschnitten ist. Ist nothing_to_do_ref true, so ist das Voxel - // gar nicht angeschnitten. Ist dann auch noch its_inside true, dann liegt das ganze Voxel komplett im innern der Struktur. - // Ansonsten liegt das ganze Voxel komplett ausserhalb der Struktur. - bool its_inside = SetCurrentStaticIndexKnownInsideOrOutside( current_static_index_ref , nothing_to_do_ref ); // Falls es eine Ecke gibt, die draussen liegt wird hier false zurueckgegeben. - bool just_switched_inside = false; - if( its_inside ) just_switched_inside = true; - /* std::cout<< " the_dose_index.x : " << the_dose_index.x <(the_world_coordinate_3D.z) != 0) + { + the_z_value = the_world_coordinate_3D.z; + second_index = resulting_sequence.at(first_index).size(); + } - // Baustelle : soll false zureuckgeben, falls was schief geht. - return true; + } - } + for (unsigned int second_index = 0 ; second_index < resulting_sequence.at(first_index).size() ; + second_index++) + { + LegacyWorldCoordinate3D& the_world_coordinate_3D_ref = resulting_sequence.at(first_index).at( + second_index); + the_world_coordinate_3D_ref.z = the_z_value; + } - void PolygonInfo::AppendNewPolygonToResultingSequence(){ + if (resulting_sequence.at(first_index).size() > 0) + { + if (static_cast(resulting_sequence.at(first_index).at(resulting_sequence.at( + first_index).size() - 1).x) != static_cast(resulting_sequence.at(first_index).at(0).x)) + { + assert(0); // this must never happen. The countour must be of periodic nature. + } - LegacyPolygonType new_polygon; - resulting_sequence.push_back( new_polygon ); + if (static_cast(resulting_sequence.at(first_index).at(resulting_sequence.at( + first_index).size() - 1).y) != static_cast(resulting_sequence.at(first_index).at(0).y)) + { + assert(0); // this must never happen. The countour must be of periodic nature. + } - } + if (static_cast(resulting_sequence.at(first_index).at(resulting_sequence.at( + first_index).size() - 1).z) != static_cast(resulting_sequence.at(first_index).at(0).z)) + { + assert(0); // this must never happen. The countour must be of periodic nature. + } + } + } + } - void PolygonInfo::AppendVoxelContour(){ - AppendNewPolygonToResultingSequence(); - LegacyWorldCoordinate3D w_3_d; - w_3_d.x =the_dose_index.x; - w_3_d.y = the_dose_index.y; - w_3_d.z = the_dose_index.z; + int PolygonInfo::GetMaxNumberSnippets() + { - resulting_sequence.at( resulting_sequence.size() - 1 ).push_back( w_3_d ); + int nr = 0; - w_3_d.x =the_dose_index.x + 1; - w_3_d.y = the_dose_index.y; - w_3_d.z = the_dose_index.z; + for (int ind = 0 ; ind != 4 ; ind++) + { - resulting_sequence.at( resulting_sequence.size() - 1 ).push_back( w_3_d ); + nr += pol_inf_vec.at(ind).size(); - w_3_d.x =the_dose_index.x + 1; - w_3_d.y = the_dose_index.y + 1; - w_3_d.z = the_dose_index.z; + } - resulting_sequence.at( resulting_sequence.size() - 1 ).push_back( w_3_d ); + return nr; + } - w_3_d.x =the_dose_index.x; - w_3_d.y = the_dose_index.y + 1; - w_3_d.z = the_dose_index.z; - resulting_sequence.at( resulting_sequence.size() - 1 ).push_back( w_3_d ); - w_3_d.x =the_dose_index.x; - w_3_d.y = the_dose_index.y; - w_3_d.z = the_dose_index.z; + // Hier werden Aenderungen noetig sein, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. + // Ist erledigt. Die Beruehrpunkte sind jetzt erlaubt + void PolygonInfo::GoGetPoly(bool& do_continue_ref , bool& next_is_edge_ref, + int& continue_counter_ref , int& max_num_ref) + { - resulting_sequence.at( resulting_sequence.size() - 1 ).push_back( w_3_d ); - } + PolygonSnippet snipp; + PolygonSnippet& snipp_ref = snipp; + if (next_is_edge_ref) + { + bool interupt = false; + GetCurrentMovingSnippet(snipp_ref); - void PolygonInfo::SlicePositionUnifyAndCheckPeriodicSequence(){ + LegacyWorldCoordinate2D why_here = snipp_ref.why_here; + int the_previous_edge = current_moving_index.edge; + continue_counter_ref++; + IncrementSnippetIndex(current_moving_index); - for( unsigned int first_index = 0 ; first_index < resulting_sequence.size() ; first_index++ ){ + if (do_continue_ref) + { + do_continue_ref = DoContinue(max_num_ref , continue_counter_ref); + } - WorldCoordinate the_z_value = 0; + if (do_continue_ref == false) + { + interupt = true; + } - for( unsigned int second_index = 0 ; second_index < resulting_sequence.at( first_index ).size() ; second_index++ ){ + while (! interupt) + { + if (TryGetPolygonsnippetEdge(continue_counter_ref , + the_previous_edge)) // holt sich das Schnipsel, das zum moving index gehoert falls es Konturinhalt hat. Falls nicht wird der moving index weiter gesetzt. + { + interupt = true; + next_is_edge_ref = false; - LegacyWorldCoordinate3D the_world_coordinate_3D = resulting_sequence.at( first_index ).at( second_index ); - if( static_cast( the_world_coordinate_3D.z ) != 0 ){ - the_z_value = the_world_coordinate_3D.z; - second_index = resulting_sequence.at( first_index ).size(); - } + } - } - for( unsigned int second_index = 0 ; second_index < resulting_sequence.at( first_index ).size() ; second_index++ ){ - LegacyWorldCoordinate3D& the_world_coordinate_3D_ref = resulting_sequence.at( first_index ).at( second_index ); - the_world_coordinate_3D_ref.z = the_z_value; + if (do_continue_ref) + { + do_continue_ref = DoContinue(max_num_ref , continue_counter_ref); + } - } + if (do_continue_ref == false) + { + interupt = true; + } - if( resulting_sequence.at( first_index ).size() > 0 ){ - if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).x ) != static_cast( resulting_sequence.at( first_index ).at(0).x ) )assert(0); // this must never happen. The countour must be of periodic nature. - if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).y ) != static_cast( resulting_sequence.at( first_index ).at(0).y ) )assert(0); // this must never happen. The countour must be of periodic nature. - if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).z ) != static_cast( resulting_sequence.at( first_index ).at(0).z ) )assert(0); // this must never happen. The countour must be of periodic nature. - } - } + } - } + GetCurrentMovingSnippet(snipp_ref); - + DoAppendIntermediateEdgeUpToThisSnippet(snipp_ref , why_here , the_previous_edge , + current_moving_index.edge); + } + else + { - int PolygonInfo::GetMaxNumberSnippets(){ + if (GetCurrentMovingSnippet(snipp_ref)) + { - int nr = 0; + LegacyWorldCoordinate2D why_here = snipp_ref.why_here; - for( int ind = 0 ; ind != 4 ; ind++ ){ + SetCurrentMovingProcessed(); - nr += pol_inf_vec.at( ind ).size(); + GoAlongSnippetToNextIntersectionAndAppendToResultingSequence(snipp_ref , continue_counter_ref); - } + SetCurrentMovingProcessed(); - return nr; + if (do_continue_ref) + { - } + next_is_edge_ref = GetNextIsEdge(current_moving_index); + if (! next_is_edge_ref) + { + continue_counter_ref++; + IncrementSnippetIndex(current_moving_index); + } + } - // Hier werden Aenderungen noetig sein, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. - // Ist erledigt. Die Beruehrpunkte sind jetzt erlaubt - void PolygonInfo::GoGetPoly( bool& do_continue_ref , bool& next_is_edge_ref, int& continue_counter_ref , int& max_num_ref ){ + if (do_continue_ref) + { + do_continue_ref = DoContinue(max_num_ref , continue_counter_ref); + } - PolygonSnippet snipp; - PolygonSnippet& snipp_ref = snipp; + } + else + { + assert(0); //this should never happen + } - if( next_is_edge_ref ){ - bool interupt = false; + } - GetCurrentMovingSnippet( snipp_ref ); - LegacyWorldCoordinate2D why_here = snipp_ref.why_here; + } - int the_previous_edge = current_moving_index.edge; - continue_counter_ref++; - IncrementSnippetIndex( current_moving_index ); - if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); - if( do_continue_ref == false )interupt = true; - while( ! interupt ){ - if( TryGetPolygonsnippetEdge( continue_counter_ref , the_previous_edge ) ){ // holt sich das Schnipsel, das zum moving index gehoert falls es Konturinhalt hat. Falls nicht wird der moving index weiter gesetzt. - interupt = true; - next_is_edge_ref = false; + bool PolygonInfo::CurrentSnippetIsProcessed() + { + return pol_inf_vec.at(current_static_index.edge).at( + current_static_index.snip).i_have_been_processed; + } - } + void PolygonInfo::ShowPolygonInTermsOfIntersections() + { - if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); + it_poly.ShowSelf(); - if( do_continue_ref == false ){ + } - interupt = true; - } + void PolygonInfo::ShowResultingSequence() + { - } + for (GridIndexType counter = 0 ; counter < resulting_sequence.size() ; counter++) + { - GetCurrentMovingSnippet( snipp_ref ); + std::cout << " And this is countour number : " << counter << std::endl; - DoAppendIntermediateEdgeUpToThisSnippet( snipp_ref , why_here , the_previous_edge , current_moving_index.edge ); + for (GridIndexType counter_internal = 0 ; counter_internal < resulting_sequence.at(counter).size() ; + counter_internal++) + { - } - else{ + LegacyWorldCoordinate3D wc3d_b = resulting_sequence.at(counter).at(counter_internal); - if( GetCurrentMovingSnippet( snipp_ref ) ){ + std::cout << " wc3d_b.x : " << wc3d_b.x << std::endl; + std::cout << " wc3d_b.y : " << wc3d_b.y << std::endl; + std::cout << " wc3d_b.z : " << wc3d_b.z << std::endl; - LegacyWorldCoordinate2D why_here = snipp_ref.why_here; - SetCurrentMovingProcessed(); - - GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( snipp_ref , continue_counter_ref ); - - SetCurrentMovingProcessed(); + } - if( do_continue_ref ){ - - next_is_edge_ref = GetNextIsEdge( current_moving_index ); + } - if( ! next_is_edge_ref ){ - continue_counter_ref++; - IncrementSnippetIndex( current_moving_index ); - } - - } - if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); + } - } - else assert(0); //this should never happen + bool PolygonInfo::GetCurrentMovingSnippet(PolygonSnippet& snipp_ref) + { + if ((current_moving_index.edge < 4) + && (current_moving_index.snip < pol_inf_vec.at(current_moving_index.edge).size()) + && (current_moving_index.snip >= 0) && (current_moving_index.edge >= 0)) + { + snipp_ref = pol_inf_vec.at(current_moving_index.edge).at(current_moving_index.snip); - } + return true; + } + else + { + return false; + } + } - } + void PolygonInfo::SetCurrentMovingProcessed() + { + if ((current_moving_index.edge < 4) + && (current_moving_index.snip < pol_inf_vec.at(current_moving_index.edge).size()) + && (current_moving_index.snip >= 0) && (current_moving_index.edge >= 0)) + { + pol_inf_vec.at(current_moving_index.edge).at(current_moving_index.snip).i_have_been_processed = + true; + } + } - bool PolygonInfo::CurrentSnippetIsProcessed(){ - return pol_inf_vec.at( current_static_index.edge ).at( current_static_index.snip ).i_have_been_processed; - } + int PolygonInfo::EdgeDist(int edge_old , int the_current_edge) + { + int edge_internal = edge_old; - void PolygonInfo::ShowPolygonInTermsOfIntersections(){ + int counter = 0; - it_poly.ShowSelf(); + while (edge_internal != the_current_edge) + { + counter++; + IncrementEdge(edge_internal); + } - } + return counter; + } - void PolygonInfo::ShowResultingSequence(){ - for( GridIndexType counter = 0 ; counter < resulting_sequence.size() ; counter++ ){ + void PolygonInfo::IncrementEdge(int& edge_increment) + { - std::cout<< " And this is countour number : " << counter <& inter_content_ref = + snipp_internal.snippet_intermediate_content; + int edge_internal = the_previous_edge; - } + while (EdgeDist(edge_internal , the_current_edge) > 0) + { + edge_internal++; + if (edge_internal == 4) + { + edge_internal = 0; + } - bool PolygonInfo::GetCurrentMovingSnippet( PolygonSnippet& snipp_ref ){ + AppendEdgeToVector(inter_content_ref , edge_internal); + } - if( ( current_moving_index.edge < 4 ) && ( current_moving_index.snip < pol_inf_vec.at( current_moving_index.edge ).size() ) && ( current_moving_index.snip >= 0 ) && ( current_moving_index.edge >= 0 ) ){ - snipp_ref = pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ); + if (snipp_internal_ref.snippet_intermediate_content.size() > 0) + { + if ((snipp_internal_ref.snippet_intermediate_content.at(0).x == + snipp_internal_ref.point_of_interest_end.x) + && (snipp_internal_ref.snippet_intermediate_content.at(0).y == + snipp_internal_ref.point_of_interest_end.y)) + { + snipp_internal_ref.snippet_intermediate_content.clear(); + } + } - return true; - } - else return false; + if (snipp_internal_ref.snippet_intermediate_content.size() > 0) + { + std::vector::iterator iter; + + while ((snipp_internal_ref.snippet_intermediate_content.at( + snipp_internal_ref.snippet_intermediate_content.size() - 1).x == + snipp_internal_ref.point_of_interest_end.x) + && (snipp_internal_ref.snippet_intermediate_content.at( + snipp_internal_ref.snippet_intermediate_content.size() - 1).y == + snipp_internal_ref.point_of_interest_end.y)) + { + iter = snipp_internal_ref.snippet_intermediate_content.begin(); + iter += (snipp_internal_ref.snippet_intermediate_content.size() - 1); + snipp_internal_ref.snippet_intermediate_content.erase(iter); + } + } - } + AppendToResultingSequence(snipp_internal_ref); - void PolygonInfo::SetCurrentMovingProcessed(){ - if( ( current_moving_index.edge < 4 ) && ( current_moving_index.snip < pol_inf_vec.at( current_moving_index.edge ).size() ) && ( current_moving_index.snip >= 0 ) && ( current_moving_index.edge >= 0 ) ){ - pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ).i_have_been_processed = true; - } - } + } - int PolygonInfo::EdgeDist( int edge_old , int the_current_edge ){ - int edge_internal = edge_old; - int counter = 0; + void PolygonInfo::AppendEdgeToVector(std::vector& vector , + int edge_internal) + { - while( edge_internal != the_current_edge ){ - counter++; - IncrementEdge( edge_internal ); - } + LegacyWorldCoordinate3D world_coordinate; - return counter; + switch (edge_internal) + { - } + case 0 : + world_coordinate.x = the_dose_index.x; + world_coordinate.y = the_dose_index.y; + world_coordinate.z = 0; + break; - void PolygonInfo::IncrementEdge( int& edge_increment ){ - if( edge_increment == 3 ) edge_increment = 0; - else edge_increment++; + case 1 : - } + world_coordinate.x = the_dose_index.x + 1; + world_coordinate.y = the_dose_index.y; + world_coordinate.z = 0; + break; + case 2 : - void PolygonInfo::DoAppendIntermediateEdgeUpToThisSnippet( PolygonSnippet& snipp_ref , LegacyWorldCoordinate2D why_here , int the_previous_edge , int the_current_edge ){ + world_coordinate.x = the_dose_index.x + 1; + world_coordinate.y = the_dose_index.y + 1; + world_coordinate.z = 0; + break; - PolygonSnippet snipp_internal; - PolygonSnippet& snipp_internal_ref = snipp_internal; + case 3 : - snipp_internal_ref.why_here = why_here; - snipp_internal_ref.point_of_interest_start = why_here; - snipp_internal_ref.point_of_interest_end = snipp_ref.why_here; + world_coordinate.x = the_dose_index.x; + world_coordinate.y = the_dose_index.y + 1; + world_coordinate.z = 0; + break; - std::vector& inter_content_ref = snipp_internal.snippet_intermediate_content; + default : - int edge_internal = the_previous_edge; + assert(0); - while( EdgeDist( edge_internal , the_current_edge ) > 0 ){ - edge_internal++; - if( edge_internal == 4 ) edge_internal = 0; - AppendEdgeToVector( inter_content_ref , edge_internal ); - } + } - if( snipp_internal_ref.snippet_intermediate_content.size() > 0 ){ - if( ( snipp_internal_ref.snippet_intermediate_content.at( 0 ).x == snipp_internal_ref.point_of_interest_end.x ) && ( snipp_internal_ref.snippet_intermediate_content.at( 0 ).y == snipp_internal_ref.point_of_interest_end.y ) ) snipp_internal_ref.snippet_intermediate_content.clear(); - } + vector.push_back(world_coordinate); - if( snipp_internal_ref.snippet_intermediate_content.size() > 0 ){ - std::vector::iterator iter; - while( ( snipp_internal_ref.snippet_intermediate_content.at( snipp_internal_ref.snippet_intermediate_content.size() - 1 ).x == snipp_internal_ref.point_of_interest_end.x ) && ( snipp_internal_ref.snippet_intermediate_content.at( snipp_internal_ref.snippet_intermediate_content.size() - 1 ).y == snipp_internal_ref.point_of_interest_end.y ) ){ - iter = snipp_internal_ref.snippet_intermediate_content.begin(); - iter += ( snipp_internal_ref.snippet_intermediate_content.size() - 1 ); - snipp_internal_ref.snippet_intermediate_content.erase( iter ); - } - } - AppendToResultingSequence( snipp_internal_ref ); + } - } + void PolygonInfo::AppendToResultingSequence(PolygonSnippet& snipp_ref) + { + int which_polygon = (resulting_sequence.size() - 1); + if (resulting_sequence.at(which_polygon).size() > 0) + { - void PolygonInfo::AppendEdgeToVector( std::vector& vector , int edge_internal ){ + LegacyWorldCoordinate3D the_world_coordinate_3D = resulting_sequence.at(which_polygon).at( + resulting_sequence.at(which_polygon).size() - 1); - LegacyWorldCoordinate3D world_coordinate; + if ((snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x) + && (snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y)) + { - switch( edge_internal ){ + DoAppendForward(snipp_ref , which_polygon); - case 0 : + } + else if ((snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x) + && (snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y)) + { - world_coordinate.x =the_dose_index.x; - world_coordinate.y = the_dose_index.y; - world_coordinate.z = 0; - break; + DoAppendBackward(snipp_ref , which_polygon); + } + else + { - case 1 : + the_world_coordinate_3D = resulting_sequence.at(which_polygon).at(0); - world_coordinate.x =the_dose_index.x + 1; - world_coordinate.y = the_dose_index.y; - world_coordinate.z = 0; - break; + if ((snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x) + && (snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y)) + { - case 2 : + DoInsertForward(snipp_ref , which_polygon); - world_coordinate.x =the_dose_index.x + 1; - world_coordinate.y = the_dose_index.y + 1; - world_coordinate.z = 0; - break; + } + else if ((snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x) + && (snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y)) + { - case 3 : + DoInsertBackward(snipp_ref , which_polygon); - world_coordinate.x =the_dose_index.x; - world_coordinate.y = the_dose_index.y + 1; - world_coordinate.z = 0; - break; + } + else + { + assert(0); // this should never happen + } - default : + } - assert( 0 ); + } + else + { + AddFirstForward(snipp_ref , which_polygon); + } - } + } - vector.push_back( world_coordinate ); - } + void PolygonInfo::DoAppendForward(PolygonSnippet& snipp_ref , int which_polygon) + { + for (unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++) + { + resulting_sequence.at(which_polygon).push_back(snipp_ref.snippet_intermediate_content.at(counter)); + } + LegacyWorldCoordinate3D coord_3_d; + coord_3_d.x = snipp_ref.point_of_interest_end.x; + coord_3_d.y = snipp_ref.point_of_interest_end.y; + coord_3_d.z = 0; - void PolygonInfo::AppendToResultingSequence( PolygonSnippet& snipp_ref ){ + resulting_sequence.at(which_polygon).push_back(coord_3_d); - int which_polygon = ( resulting_sequence.size() - 1 ); + } - if( resulting_sequence.at( which_polygon ).size() > 0 ){ - LegacyWorldCoordinate3D the_world_coordinate_3D = resulting_sequence.at( which_polygon ).at( resulting_sequence.at( which_polygon ).size() - 1 ); - if( ( snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y ) ){ + void PolygonInfo::DoAppendBackward(PolygonSnippet& snipp_ref , int which_polygon) + { - DoAppendForward( snipp_ref , which_polygon ); + int index = 0; - } - else if( ( snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y ) ){ + for (unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++) + { - DoAppendBackward( snipp_ref , which_polygon ); + index = snipp_ref.snippet_intermediate_content.size() - counter - 1; - } - else{ + resulting_sequence.at(which_polygon).push_back(snipp_ref.snippet_intermediate_content.at(index)); - the_world_coordinate_3D = resulting_sequence.at( which_polygon ).at( 0 ); + } - if( ( snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y ) ){ + LegacyWorldCoordinate3D coord_3_d; + coord_3_d.x = snipp_ref.point_of_interest_start.x; + coord_3_d.y = snipp_ref.point_of_interest_start.y; + coord_3_d.z = 0; - DoInsertForward( snipp_ref , which_polygon ); + resulting_sequence.at(which_polygon).push_back(coord_3_d); - } - else if( ( snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y ) ){ + } - DoInsertBackward( snipp_ref , which_polygon ); - } - else{ - assert( 0 ); // this should never happen - } + void PolygonInfo::DoInsertForward(PolygonSnippet& snipp_ref , int which_polygon) + { - } + LegacyPolygonTypeIterator it; - } - else AddFirstForward( snipp_ref , which_polygon ); + for (unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++) + { + it = resulting_sequence.at(which_polygon).begin(); + resulting_sequence.at(which_polygon).insert(it , + snipp_ref.snippet_intermediate_content.at(counter)); + } - } + it = resulting_sequence.at(which_polygon).begin(); + LegacyWorldCoordinate3D coord_3_d; + coord_3_d.x = snipp_ref.point_of_interest_end.x; + coord_3_d.y = snipp_ref.point_of_interest_end.y; + coord_3_d.z = 0; + resulting_sequence.at(which_polygon).insert(it , coord_3_d); - void PolygonInfo::DoAppendForward( PolygonSnippet& snipp_ref , int which_polygon ){ + } - for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ - resulting_sequence.at( which_polygon ).push_back( snipp_ref.snippet_intermediate_content.at( counter ) ); - } - LegacyWorldCoordinate3D coord_3_d; - coord_3_d.x = snipp_ref.point_of_interest_end.x; - coord_3_d.y = snipp_ref.point_of_interest_end.y; - coord_3_d.z = 0; + void PolygonInfo::DoInsertBackward(PolygonSnippet& snipp_ref , int which_polygon) + { - resulting_sequence.at( which_polygon ).push_back( coord_3_d ); + int index = 0; - } + LegacyPolygonTypeIterator it; + for (unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++) + { + index = snipp_ref.snippet_intermediate_content.size() - counter - 1; - void PolygonInfo::DoAppendBackward( PolygonSnippet& snipp_ref , int which_polygon ){ + it = resulting_sequence.at(which_polygon).begin(); - int index = 0; + resulting_sequence.at(which_polygon).insert(it , snipp_ref.snippet_intermediate_content.at(index)); - for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ + } - index = snipp_ref.snippet_intermediate_content.size() - counter - 1; + it = resulting_sequence.at(which_polygon).begin(); - resulting_sequence.at( which_polygon ).push_back( snipp_ref.snippet_intermediate_content.at( index ) ); + LegacyWorldCoordinate3D coord_3_d; + coord_3_d.x = snipp_ref.point_of_interest_start.x; + coord_3_d.y = snipp_ref.point_of_interest_start.y; + coord_3_d.z = 0; - } + resulting_sequence.at(which_polygon).insert(it , coord_3_d); - LegacyWorldCoordinate3D coord_3_d; - coord_3_d.x = snipp_ref.point_of_interest_start.x; - coord_3_d.y = snipp_ref.point_of_interest_start.y; - coord_3_d.z = 0; + } - resulting_sequence.at( which_polygon ).push_back( coord_3_d ); - } + void PolygonInfo::AddFirstForward(PolygonSnippet& snipp_ref , int which_polygon) + { + LegacyWorldCoordinate3D coord_3_d; + coord_3_d.x = snipp_ref.point_of_interest_start.x; + coord_3_d.y = snipp_ref.point_of_interest_start.y; + coord_3_d.z = 0; - void PolygonInfo::DoInsertForward( PolygonSnippet& snipp_ref , int which_polygon ){ + resulting_sequence.at(which_polygon).push_back(coord_3_d); - LegacyPolygonTypeIterator it; + DoAppendForward(snipp_ref , which_polygon); - for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ - it = resulting_sequence.at( which_polygon ).begin(); - resulting_sequence.at( which_polygon ).insert( it , snipp_ref.snippet_intermediate_content.at( counter ) ); - } + } - it = resulting_sequence.at( which_polygon ).begin(); - LegacyWorldCoordinate3D coord_3_d; - coord_3_d.x = snipp_ref.point_of_interest_end.x; - coord_3_d.y = snipp_ref.point_of_interest_end.y; - coord_3_d.z = 0; - resulting_sequence.at( which_polygon ).insert( it , coord_3_d ); - } + void PolygonInfo::GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( + PolygonSnippet& snipp_ref , int& continue_counter_ref) + { + AppendToResultingSequence(snipp_ref); + FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter(snipp_ref , continue_counter_ref); - void PolygonInfo::DoInsertBackward( PolygonSnippet& snipp_ref , int which_polygon ){ + } - int index = 0; - LegacyPolygonTypeIterator it; - for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ - index = snipp_ref.snippet_intermediate_content.size() - counter - 1; - it = resulting_sequence.at( which_polygon ).begin(); + bool PolygonInfo::IsCorresponding(PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref) + { - resulting_sequence.at( which_polygon ).insert( it , snipp_ref.snippet_intermediate_content.at( index ) ); - } + if ((static_cast(snipp_ref_compare.why_here.x) == static_cast + (snipp_ref.point_of_interest_end.x)) + && (static_cast(snipp_ref_compare.why_here.y) == static_cast + (snipp_ref.point_of_interest_end.y))) + { - it = resulting_sequence.at( which_polygon ).begin(); + if (!((static_cast(snipp_ref_compare.point_of_interest_end.x) == static_cast + (snipp_ref.why_here.x)) + || (static_cast(snipp_ref_compare.point_of_interest_start.x) == static_cast + (snipp_ref.why_here.x))) + && ((static_cast(snipp_ref_compare.point_of_interest_end.y) == static_cast + (snipp_ref.why_here.y)) + || (static_cast(snipp_ref_compare.point_of_interest_start.y) == static_cast + (snipp_ref.why_here.y)))) + { + return false; + } - LegacyWorldCoordinate3D coord_3_d; - coord_3_d.x = snipp_ref.point_of_interest_start.x; - coord_3_d.y = snipp_ref.point_of_interest_start.y; - coord_3_d.z = 0; + if (snipp_ref_compare.snippet_intermediate_content.size() != + snipp_ref.snippet_intermediate_content.size()) + { + return false; + } - resulting_sequence.at( which_polygon ).insert( it , coord_3_d ); + for (GridIndexType counter = 0 ; counter < snipp_ref_compare.snippet_intermediate_content.size() ; + counter++) + { - } + if (static_cast(snipp_ref_compare.snippet_intermediate_content.at( + counter).x) != static_cast(snipp_ref.snippet_intermediate_content.at( + snipp_ref.snippet_intermediate_content.size() - (counter + 1)).x)) + { + return false; + } + if (static_cast(snipp_ref_compare.snippet_intermediate_content.at( + counter).y) != static_cast(snipp_ref.snippet_intermediate_content.at( + snipp_ref.snippet_intermediate_content.size() - (counter + 1)).y)) + { + return false; + } - void PolygonInfo::AddFirstForward( PolygonSnippet& snipp_ref , int which_polygon ){ + } - LegacyWorldCoordinate3D coord_3_d; - coord_3_d.x = snipp_ref.point_of_interest_start.x; - coord_3_d.y = snipp_ref.point_of_interest_start.y; - coord_3_d.z = 0; + return true; - resulting_sequence.at( which_polygon ).push_back( coord_3_d ); + } + else + { + return false; + } - DoAppendForward( snipp_ref , which_polygon ); + } - } + LegacyWorldCoordinate2D PolygonInfo::GetOtherEnd(PolygonSnippet& snipp_ref) + { + if ((snipp_ref.why_here.x == snipp_ref.point_of_interest_start.x) + && (snipp_ref.why_here.y == snipp_ref.point_of_interest_start.y)) + { + return snipp_ref.point_of_interest_end; + } + else if ((snipp_ref.why_here.x == snipp_ref.point_of_interest_end.x) + && (snipp_ref.why_here.y == snipp_ref.point_of_interest_end.y)) + { + return snipp_ref.point_of_interest_start; + } + else + { + assert(0); // this should never happen + } - void PolygonInfo::GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( PolygonSnippet& snipp_ref , int& continue_counter_ref ){ + return LegacyWorldCoordinate2D(); + } - AppendToResultingSequence( snipp_ref ); - FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( snipp_ref , continue_counter_ref ); - } + int PolygonInfo::GetSnippetIndexDistance(SnippetIndex behind_snip_index , + SnippetIndex front_snip_index) + { + int dist = 0; + while (!SnippetIndexIdentical(behind_snip_index , front_snip_index)) + { + dist++; + IncrementSnippetIndex(behind_snip_index); + } - bool PolygonInfo::IsCorresponding( PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref ){ + return dist; + } - if( ( static_cast( snipp_ref_compare.why_here.x ) == static_cast( snipp_ref.point_of_interest_end.x ) ) && ( static_cast( snipp_ref_compare.why_here.y ) == static_cast( snipp_ref.point_of_interest_end.y ) ) ){ + // returns true in case indicees are identical + bool PolygonInfo::SnippetIndexIdentical(SnippetIndex first , SnippetIndex second) + { + if ((first.edge == second.edge) && (first.snip == second.snip)) + { + return true; + } + else + { + return false; + } + } - if( ! ( ( static_cast( snipp_ref_compare.point_of_interest_end.x ) == static_cast( snipp_ref.why_here.x ) ) || ( static_cast( snipp_ref_compare.point_of_interest_start.x ) == static_cast( snipp_ref.why_here.x ) ) ) && ( ( static_cast( snipp_ref_compare.point_of_interest_end.y ) == static_cast( snipp_ref.why_here.y ) ) || ( static_cast( snipp_ref_compare.point_of_interest_start.y ) == static_cast( snipp_ref.why_here.y ) ) ) ) return false; - if( snipp_ref_compare.snippet_intermediate_content.size() != snipp_ref.snippet_intermediate_content.size() ) return false; - for( GridIndexType counter = 0 ; counter < snipp_ref_compare.snippet_intermediate_content.size() ; counter++ ){ + void PolygonInfo::FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( + PolygonSnippet& snipp_ref , int& continue_counter_ref) + { - if( static_cast( snipp_ref_compare.snippet_intermediate_content.at( counter ).x ) != static_cast( snipp_ref.snippet_intermediate_content.at( snipp_ref.snippet_intermediate_content.size() - ( counter + 1 ) ).x ) ) return false; - if( static_cast( snipp_ref_compare.snippet_intermediate_content.at( counter ).y ) != static_cast( snipp_ref.snippet_intermediate_content.at( snipp_ref.snippet_intermediate_content.size() - ( counter + 1 ) ).y ) ) return false; - } + SnippetIndex another_snip_index; + another_snip_index.edge = current_moving_index.edge; + another_snip_index.snip = current_moving_index.snip; - return true; + IncrementSnippetIndex(another_snip_index); - } - else return false; + bool there_is_one = false; - } + while ((!there_is_one) && ((another_snip_index.edge != current_moving_index.edge) + || (another_snip_index.snip != current_moving_index.snip))) + { + PolygonSnippet& snipp_ref_compare = pol_inf_vec.at(another_snip_index.edge).at( + another_snip_index.snip) ; + if (IsCorresponding(snipp_ref_compare , snipp_ref)) + { - LegacyWorldCoordinate2D PolygonInfo::GetOtherEnd( PolygonSnippet& snipp_ref ){ + continue_counter_ref += GetSnippetIndexDistance(current_moving_index , another_snip_index); + current_moving_index.edge = another_snip_index.edge; + current_moving_index.snip = another_snip_index.snip; + SetCurrentMovingProcessed(); + there_is_one = true; - if( ( snipp_ref.why_here.x == snipp_ref.point_of_interest_start.x ) && ( snipp_ref.why_here.y == snipp_ref.point_of_interest_start.y ) ){ - return snipp_ref.point_of_interest_end; - } - else if( ( snipp_ref.why_here.x == snipp_ref.point_of_interest_end.x ) && ( snipp_ref.why_here.y == snipp_ref.point_of_interest_end.y ) ){ - return snipp_ref.point_of_interest_start; - } - else assert( 0 ); // this should never happen - return LegacyWorldCoordinate2D(); - } + } + IncrementSnippetIndex(another_snip_index); - int PolygonInfo::GetSnippetIndexDistance( SnippetIndex behind_snip_index , SnippetIndex front_snip_index ){ + } - int dist = 0; - while( !SnippetIndexIdentical( behind_snip_index , front_snip_index ) ){ + assert(there_is_one); - dist++; - IncrementSnippetIndex( behind_snip_index ); + } - } - return dist; - } + bool PolygonInfo::IsOtherEdge(PolygonSnippet& snipp_ref , int the_previous_edge) + { - // returns true in case indicees are identical - bool PolygonInfo::SnippetIndexIdentical( SnippetIndex first , SnippetIndex second ){ - if( ( first.edge == second.edge ) && ( first.snip == second.snip ) )return true; - else return false; - } + if ((the_previous_edge == 0) || (the_previous_edge == 2)) + { + if (static_cast(snipp_ref.point_of_interest_start.y) != static_cast + (snipp_ref.point_of_interest_end.y)) + { + return true; + } + } + else if ((the_previous_edge == 1) || (the_previous_edge == 3)) + { - void PolygonInfo::FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( PolygonSnippet& snipp_ref , int& continue_counter_ref ){ + if (static_cast(snipp_ref.point_of_interest_start.x) != static_cast + (snipp_ref.point_of_interest_end.x)) + { + return true; + } + } + else + { + assert(0); + } - SnippetIndex another_snip_index; - another_snip_index.edge = current_moving_index.edge; - another_snip_index.snip = current_moving_index.snip; + return false; - IncrementSnippetIndex( another_snip_index ); + } - bool there_is_one = false; - - while( ( !there_is_one ) && ( ( another_snip_index.edge != current_moving_index.edge ) || ( another_snip_index.snip != current_moving_index.snip ) ) ){ - - PolygonSnippet& snipp_ref_compare = pol_inf_vec.at( another_snip_index.edge ).at( another_snip_index.snip ) ; - if( IsCorresponding( snipp_ref_compare , snipp_ref ) ){ - - continue_counter_ref += GetSnippetIndexDistance( current_moving_index , another_snip_index ); - current_moving_index.edge = another_snip_index.edge; - current_moving_index.snip = another_snip_index.snip; - SetCurrentMovingProcessed(); - there_is_one = true; - } - IncrementSnippetIndex( another_snip_index ); - - } + bool PolygonInfo::TryGetPolygonsnippetEdge(int& continue_counter_ref , int the_previous_edge) + { + if (pol_inf_vec.at(current_moving_index.edge).at( + current_moving_index.snip).snippet_intermediate_content.size() > 0) + { - assert( there_is_one ); + // ShowSnippet(pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip )); - } + return true; + } + else if (IsOtherEdge(pol_inf_vec.at(current_moving_index.edge).at(current_moving_index.snip) , + the_previous_edge)) + { + return true; - bool PolygonInfo::IsOtherEdge( PolygonSnippet& snipp_ref , int the_previous_edge ){ + } + else + { - if( ( the_previous_edge == 0 ) || ( the_previous_edge == 2 ) ){ + continue_counter_ref++; + IncrementSnippetIndex(current_moving_index); + return false; - if( static_cast( snipp_ref.point_of_interest_start.y ) != static_cast( snipp_ref.point_of_interest_end.y ) ) return true; + } - } - else if( ( the_previous_edge == 1 ) || ( the_previous_edge == 3 ) ){ + } - if( static_cast( snipp_ref.point_of_interest_start.x ) != static_cast( snipp_ref.point_of_interest_end.x ) ) return true; - } - else assert(0); + void PolygonInfo::IncrementSnippetIndex(SnippetIndex& the_snippet_index) + { - return false; + the_snippet_index.snip += 1; - } + if (the_snippet_index.snip >= pol_inf_vec.at(the_snippet_index.edge).size()) + { + the_snippet_index.snip = 0; + the_snippet_index.edge++; + if (the_snippet_index.edge > 3) + { + the_snippet_index.edge = 0; + } - bool PolygonInfo::TryGetPolygonsnippetEdge( int& continue_counter_ref , int the_previous_edge ){ + } - if( pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ).snippet_intermediate_content.size() > 0 ){ + } - // ShowSnippet(pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip )); - return true; + bool PolygonInfo::GetNextIsEdge(SnippetIndex snip_index) + { - } - else if( IsOtherEdge( pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ) , the_previous_edge ) ){ + CharacterizeIntersection characterize = pol_inf_vec.at(snip_index.edge).at( + snip_index.snip).characterize; - return true; + if (characterize == inside_inside_touches) + { + return false; + } + else + { + return true; + } - } - else{ + } - continue_counter_ref++; - IncrementSnippetIndex( current_moving_index ); - return false; - } - } + bool PolygonInfo::DoContinue(int& max_num , int& continue_counter_ref) + { + if (max_num > (continue_counter_ref)) + { + return true; + } + else if (max_num == (continue_counter_ref)) + { + return false; + } + else + { + //std::cout<< " the_dose_index.x : " << the_dose_index.x <= pol_inf_vec.at( the_snippet_index.edge ).size() ){ + void PolygonInfo::CopySnippetIndex(SnippetIndex snip_index_from , SnippetIndex& snip_index_to) + { - the_snippet_index.snip = 0; - the_snippet_index.edge++; - if( the_snippet_index.edge > 3 ) the_snippet_index.edge = 0; + snip_index_to.edge = snip_index_from.edge; + snip_index_to.snip = snip_index_from.snip; - } + } - } - bool PolygonInfo::GetNextIsEdge( SnippetIndex snip_index ){ + void PolygonInfo::ToZero(SnippetIndex snip_index) + { + snip_index.edge = 0; + snip_index.snip = 0; + } - CharacterizeIntersection characterize = pol_inf_vec.at( snip_index.edge ).at( snip_index.snip ).characterize; - if( characterize == inside_inside_touches ){ - return false; - } - else{ - return true; - } - } + // Der Rueckgabewert besagt, ob das was nach dem Schnittpunkt kommt drinnen oder drausen liegt. Also ob das folgende Segment + // innerhalb der VOI liegt. + // Ob drinen oder draussen wird anhand des Polygonsnippets in position current_moving_index und des + // bisherigen edge_status entschieden. edge_status wird dann entsprechend neu gesetzt. - bool PolygonInfo::DoContinue( int& max_num , int& continue_counter_ref ){ + // Der edge_status gibt an ob sich die Kontur an dieser Stelle innerhalb des Voxels oder ausserhalb des Voxels beziehungsweise + // auf dessen Kante befindet. Zwischen ausserhalb und Kante wird nicht unterschieden. - if( max_num > ( continue_counter_ref ) ) return true; - else if( max_num == ( continue_counter_ref ) )return false; - else{ - //std::cout<< " the_dose_index.x : " << the_dose_index.x <GetData(x, y, z) == brightness_outside) + { + assert(0); // this should never happen since we are dealing with a voxel that is touched by the structure. + } - return false; - } + //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. - // Gibt, falls es eine Ecke gibt, die drausen liegt true zurueck und setzt current_static_index_ref gegebenenfalls auf die entsprechende Ecke. - bool PolygonInfo::CheckCornersOutside( SnippetIndex& current_static_index_ref ){ + if ((CheckThereIsSuchNeighbour(x , y , z , -1 , -1 , 0, brightness_outside))) + { + current_static_index_ref.edge = 0; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , 1 , -1 , 0 , brightness_outside))) + { + current_static_index_ref.edge = 1; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , 1 , 1 , 0, brightness_outside))) + { + current_static_index_ref.edge = 2; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , -1 , 1 , 0, brightness_outside))) + { + current_static_index_ref.edge = 3; + current_static_index_ref.snip = 0; + return true; + } + return false; + } - Uint16 x = the_dose_index.x; - Uint16 y = the_dose_index.y; - Uint16 z = the_dose_index.z; - if( MaskFieldReceived->GetData( x, y, z ) == brightness_outside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. - //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. + // Gibt, falls es eine Ecke gibt, die drinnen liegt true zurueck und setzt current_static_index_ref gegebenenfalls auf die entsprechende Ecke. + bool PolygonInfo::CheckCornersInside(SnippetIndex& current_static_index_ref) + { - if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , -1 , 0, brightness_outside ) ) ){ - current_static_index_ref.edge = 0; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , -1 , 0 , brightness_outside ) ) ){ - current_static_index_ref.edge = 1; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , 1 , 0, brightness_outside ) ) ){ - current_static_index_ref.edge = 2; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , 1 , 0, brightness_outside ) ) ){ - current_static_index_ref.edge = 3; - current_static_index_ref.snip = 0; - return true; - } - return false; + Uint16 x = the_dose_index.x; + Uint16 y = the_dose_index.y; + Uint16 z = the_dose_index.z; - } + if (MaskFieldReceived->GetData(x, y, z) == brightness_outside) + { + assert(0); // this should never happen since we are dealing with a voxel that is touched by the structure. + } + //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); - // Gibt, falls es eine Ecke gibt, die drinnen liegt true zurueck und setzt current_static_index_ref gegebenenfalls auf die entsprechende Ecke. - bool PolygonInfo::CheckCornersInside( SnippetIndex& current_static_index_ref ){ + if ((CheckThereIsSuchNeighbour(x , y , z , -1 , -1 , 0, brightness_inside))) + { + current_static_index_ref.edge = 0; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , 1 , -1 , 0, brightness_inside))) + { + current_static_index_ref.edge = 1; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , 1 , 1 , 0, brightness_inside))) + { + current_static_index_ref.edge = 2; + current_static_index_ref.snip = 0; + return true; + } + else if ((CheckThereIsSuchNeighbour(x , y , z , -1 , 1 , 0, brightness_inside))) + { + current_static_index_ref.edge = 3; + current_static_index_ref.snip = 0; + return true; + } + return false; + } - Uint16 x = the_dose_index.x; - Uint16 y = the_dose_index.y; - Uint16 z = the_dose_index.z; + bool PolygonInfo::CheckThereIsSuchNeighbour(Uint16 x , Uint16 y , Uint16 z , int shift_x , + int shift_y , int shift_z, field_content_type brightness) + { - if( MaskFieldReceived->GetData( x, y, z ) == brightness_outside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. - //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); + Uint16 x_intern = x + shift_x; + Uint16 y_intern = y; - if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , -1 , 0, brightness_inside ) ) ){ - current_static_index_ref.edge = 0; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , -1 , 0, brightness_inside ) ) ){ - current_static_index_ref.edge = 1; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , 1 , 0, brightness_inside ) ) ){ - current_static_index_ref.edge = 2; - current_static_index_ref.snip = 0; - return true; - } - else if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , 1 , 0, brightness_inside ) ) ){ - current_static_index_ref.edge = 3; - current_static_index_ref.snip = 0; - return true; - } + if ((x_intern < MaskFieldReceived->GetDimX()) && (x_intern >= 0)) + { + if (MaskFieldReceived->GetData(x_intern, y_intern, z) == brightness) + { + return true; + } + } - return false; + x_intern = x + shift_x; + y_intern = y + shift_y; - } + if ((x_intern < MaskFieldReceived->GetDimX()) && (x_intern >= 0) + && (y_intern < MaskFieldReceived->GetDimY()) && (y_intern >= 0)) + { + if (MaskFieldReceived->GetData(x_intern, y_intern, z) == brightness) + { + return true; + } + } + x_intern = x; + y_intern = y + shift_y; - bool PolygonInfo::CheckThereIsSuchNeighbour( Uint16 x , Uint16 y , Uint16 z , int shift_x , int shift_y , int shift_z, field_content_type brightness ){ + if ((y_intern < MaskFieldReceived->GetDimY()) && (y_intern >= 0)) + { + if (MaskFieldReceived->GetData(x_intern, y_intern, z) == brightness) + { + return true; + } + } - Uint16 x_intern = x + shift_x; - Uint16 y_intern = y; + return false; - if( ( x_intern < MaskFieldReceived->GetDimX() ) && ( x_intern >= 0 ) ){ - if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; - } + } - x_intern = x + shift_x; - y_intern = y + shift_y; - if( ( x_intern < MaskFieldReceived->GetDimX() ) && ( x_intern >= 0 ) && ( y_intern < MaskFieldReceived->GetDimY() ) && ( y_intern >= 0 ) ){ - if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; - } - x_intern = x; - y_intern = y + shift_y; - if( ( y_intern < MaskFieldReceived->GetDimY() ) && ( y_intern >= 0 ) ){ - if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; - } + // Gibt true zurueck, falls das Voxel von der Kontur gar nicht angeschnitten wird. + bool PolygonInfo::CheckCenterSurroundingStructure(bool& inside) + { - return false; + bool no_intersections = true; - } + SnippetIndex a_snippet_index; + a_snippet_index.snip = 0; + a_snippet_index.edge = 0; + PolygonSnippet a_snippet; + for (a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++) + { + for (a_snippet_index.snip = 0 ; + a_snippet_index.snip < (pol_inf_vec.at(a_snippet_index.edge).size()) ; a_snippet_index.snip++) + { + a_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); - // Gibt true zurueck, falls das Voxel von der Kontur gar nicht angeschnitten wird. - bool PolygonInfo::CheckCenterSurroundingStructure( bool& inside ){ + if (!((a_snippet.characterize == outside_outside_touches) + || (a_snippet.characterize == edge_to_edge) || (a_snippet.characterize == corner) + || (a_snippet.characterize == outside_to_edge) || (a_snippet.characterize == edge_to_outside))) + { + no_intersections = false; + } - bool no_intersections = true; + } + } - SnippetIndex a_snippet_index; - a_snippet_index.snip = 0; - a_snippet_index.edge = 0; + if (no_intersections) + { - PolygonSnippet a_snippet; + LegacyWorldCoordinate3D a_voxel_coordinate; + a_voxel_coordinate.x = (the_dose_index.x + 0.5); + a_voxel_coordinate.y = (the_dose_index.y + 0.5); + a_voxel_coordinate.z = the_dose_index.z; - for( a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++ ){ - for( a_snippet_index.snip = 0 ; a_snippet_index.snip < ( pol_inf_vec.at( a_snippet_index.edge ).size() ) ; a_snippet_index.snip++ ){ - a_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); + LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate(a_voxel_coordinate); - if( !( ( a_snippet.characterize == outside_outside_touches ) || ( a_snippet.characterize == edge_to_edge ) || ( a_snippet.characterize == corner ) || (a_snippet.characterize == outside_to_edge ) || ( a_snippet.characterize == edge_to_outside ) ) ){ - no_intersections = false; - } + Contour contour(the_polygon); + inside = contour.pointInPolygon(a_world_coordinate); - } - } - if( no_intersections ){ + } - LegacyWorldCoordinate3D a_voxel_coordinate; - a_voxel_coordinate.x = (the_dose_index.x + 0.5); - a_voxel_coordinate.y = (the_dose_index.y + 0.5); - a_voxel_coordinate.z = the_dose_index.z; + return no_intersections; + } - LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); - Contour contour(the_polygon); - inside = contour.pointInPolygon(a_world_coordinate ); + // Die folgende Funktionalitaet ist in DoseVoxel im Prinziep bereits vorhanden. Daher Lanlan fragen, ob man sie dort + // zugaenglich machen kann, damit wir sie hier nicht verdoppeln muessen. Allerdings ist der Input hier . + LegacyWorldCoordinate3D PolygonInfo::GetWorldCoordinate(LegacyWorldCoordinate3D voxel_coordinate) + { - } + LegacyWorldCoordinate3D world_coordinate; + LegacyWorldCoordinate3D spacing; + spacing.x = GInformation.getPixelSpacingRow(); + spacing.y = GInformation.getPixelSpacingColumn(); + spacing.z = GInformation.getSliceThickness(); + OrientationMatrix orientation = GInformation.getOrientationMatrix(); + LegacyWorldCoordinate3D posPatient = GInformation.getImagePositionPatient(); - return no_intersections; + world_coordinate.x = (orientation(0, 0) * spacing.x * (voxel_coordinate.x - 0.5) + orientation(0, + 1) * spacing.y * (voxel_coordinate.y - 0.5) + posPatient.x); + world_coordinate.y = (orientation(1, 0) * spacing.x * (voxel_coordinate.x - 0.5) + orientation(1, + 1) * spacing.y * (voxel_coordinate.y - 0.5) + posPatient.y); + world_coordinate.z = (posPatient.z + spacing.z * (voxel_coordinate.z - 0.5)); - } + return world_coordinate; + } - // Die folgende Funktionalitaet ist in DoseVoxel im Prinziep bereits vorhanden. Daher Lanlan fragen, ob man sie dort - // zugaenglich machen kann, damit wir sie hier nicht verdoppeln muessen. Allerdings ist der Input hier . - LegacyWorldCoordinate3D PolygonInfo::GetWorldCoordinate( LegacyWorldCoordinate3D voxel_coordinate ){ + void PolygonInfo::SetCurrentPosition(const LegacyDoseVoxelIndex3D& aDoseIndex) + { + current_position.x = static_cast(aDoseIndex.x); + current_position.y = static_cast(aDoseIndex.y); + } - LegacyWorldCoordinate3D world_coordinate; - LegacyWorldCoordinate3D spacing; - spacing.x = GInformation.getPixelSpacingRow(); - spacing.y = GInformation.getPixelSpacingColumn(); - spacing.z = GInformation.getSliceThickness(); - OrientationMatrix orientation = GInformation.getOrientationMatrix(); - LegacyWorldCoordinate3D posPatient = GInformation.getImagePositionPatient(); - world_coordinate.x = (orientation(0,0)*spacing.x*(voxel_coordinate.x-0.5)+orientation(0,1)*spacing.y*(voxel_coordinate.y-0.5)+posPatient.x); - world_coordinate.y = (orientation(1,0)*spacing.x*(voxel_coordinate.x-0.5)+orientation(1,1)*spacing.y*(voxel_coordinate.y-0.5)+posPatient.y); - world_coordinate.z = (posPatient.z + spacing.z *(voxel_coordinate.z-0.5)); - return world_coordinate; + bool PolygonInfo::SnippetIndexIsIdentical(SnippetIndex first_index , SnippetIndex second_index) + { + if ((first_index.edge == second_index.edge) && (first_index.snip == second_index.snip)) + { + return true; + } + else + { + return false; + } + } - } - void PolygonInfo::SetCurrentPosition( const LegacyDoseVoxelIndex3D& aDoseIndex ){ - current_position.x = static_cast(aDoseIndex.x); - current_position.y = static_cast(aDoseIndex.y); - } + // Anpassung fuer beruehrende Strukturen noetig. Dann muss sichergestellt werdedn, dass current_static_index_ref nicht ein + // snippet repraesentiert das von einem anderen Snippet gefolgt wird fuer das .why_here identisch ist. + bool PolygonInfo::CheckPointOnEdgeOutside(SnippetIndex& current_static_index_ref , bool& inside) + { + bool got_it = false; + SnippetIndex a_snippet_index; + a_snippet_index.snip = 0; + a_snippet_index.edge = 0; - bool PolygonInfo::SnippetIndexIsIdentical( SnippetIndex first_index , SnippetIndex second_index ){ - if( ( first_index.edge == second_index.edge ) && ( first_index.snip == second_index.snip ) ) return true; - else return false; - } + PolygonSnippet a_snippet; + PolygonSnippet next_snippet; + for (a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++) + { + for (a_snippet_index.snip = 0 ; + a_snippet_index.snip < (pol_inf_vec.at(a_snippet_index.edge).size()) ; a_snippet_index.snip++) + { - // Anpassung fuer beruehrende Strukturen noetig. Dann muss sichergestellt werdedn, dass current_static_index_ref nicht ein - // snippet repraesentiert das von einem anderen Snippet gefolgt wird fuer das .why_here identisch ist. - bool PolygonInfo::CheckPointOnEdgeOutside( SnippetIndex& current_static_index_ref , bool& inside ){ + a_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); - bool got_it = false; + if ((a_snippet.characterize == real_intersection) || (a_snippet.characterize == edge_to_inside) + || (a_snippet.characterize == edge_to_outside) + || (a_snippet.characterize == inside_inside_touches)) + { - SnippetIndex a_snippet_index; - a_snippet_index.snip = 0; - a_snippet_index.edge = 0; + int at_begin = 0; - PolygonSnippet a_snippet; - PolygonSnippet next_snippet; + while ((got_it == false) && (at_begin < 2)) + { - for( a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++ ){ + // folgenden Teil auslagern als Funkton IncrementSnippetIndex() + if (pol_inf_vec.at(a_snippet_index.edge).size() > (a_snippet_index.snip + 1)) + { + a_snippet_index.snip += 1; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else if (a_snippet_index.edge < 3) + { + a_snippet_index.edge += 1; + a_snippet_index.snip = 0; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else + { + a_snippet_index.edge = 0; + a_snippet_index.snip = 0; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + at_begin++; + } - for( a_snippet_index.snip = 0 ; a_snippet_index.snip < ( pol_inf_vec.at( a_snippet_index.edge ).size() ) ; a_snippet_index.snip++ ){ + // ende auszulagern als Funkton IncrementSnippetIndex() - a_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); + if ((static_cast(a_snippet.why_here.x) != static_cast(next_snippet.why_here.x)) + || (static_cast(a_snippet.why_here.y) != static_cast(next_snippet.why_here.y))) + { - if( ( a_snippet.characterize == real_intersection ) || ( a_snippet.characterize == edge_to_inside ) || ( a_snippet.characterize == edge_to_outside ) || ( a_snippet.characterize == inside_inside_touches ) ){ + LegacyWorldCoordinate3D a_voxel_coordinate; + a_voxel_coordinate.x = ((a_snippet.why_here.x + next_snippet.why_here.x) * 0.5); + a_voxel_coordinate.y = ((a_snippet.why_here.y + next_snippet.why_here.y) * 0.5); + a_voxel_coordinate.z = the_dose_index.z; - int at_begin = 0; + LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate(a_voxel_coordinate); - while( ( got_it == false ) && ( at_begin < 2 ) ){ + /* + std::cout<< " a_voxel_coordinate.x : " << a_voxel_coordinate.x < ( a_snippet_index.snip + 1 ) ){ - a_snippet_index.snip += 1; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else if( a_snippet_index.edge < 3 ){ - a_snippet_index.edge += 1; - a_snippet_index.snip = 0; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else{ - a_snippet_index.edge = 0; - a_snippet_index.snip = 0; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - at_begin++; - } - // ende auszulagern als Funkton IncrementSnippetIndex() + std::cout<< " GInformation.getNumColumns(): " << GInformation.getNumColumns()<( a_snippet.why_here.x ) != static_cast( next_snippet.why_here.x ) ) || ( static_cast( a_snippet.why_here.y ) != static_cast( next_snippet.why_here.y ) ) ){ + */ - LegacyWorldCoordinate3D a_voxel_coordinate; - a_voxel_coordinate.x = (( a_snippet.why_here.x + next_snippet.why_here.x ) * 0.5); - a_voxel_coordinate.y = (( a_snippet.why_here.y + next_snippet.why_here.y ) * 0.5); - a_voxel_coordinate.z = the_dose_index.z; + Contour contour(the_polygon); + inside = contour.pointInPolygon(a_world_coordinate); - LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); - /* - std::cout<< " a_voxel_coordinate.x : " << a_voxel_coordinate.x < 0) + { + a_snippet_index.snip -= 1; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else if (a_snippet_index.edge > 0) + { + a_snippet_index.edge -= 1; + a_snippet_index.snip = pol_inf_vec.at(a_snippet_index.edge).size() - 1; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else + { + a_snippet_index.edge = 3; + a_snippet_index.snip = pol_inf_vec.at(a_snippet_index.edge).size() - 1; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + at_end++; + } - int at_end = 0; + // ende auszulagern als Funkton DecrementSnippetIndex() - while( ( got_it == false ) && ( at_end < 2 ) ){ - // Folgender Bereich is auszulagern als Funkton DecrementSnippetIndex() - if( a_snippet_index.snip > 0 ){ - a_snippet_index.snip -= 1; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else if( a_snippet_index.edge > 0 ){ - a_snippet_index.edge -= 1; - a_snippet_index.snip = pol_inf_vec.at( a_snippet_index.edge ).size() - 1; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else{ - a_snippet_index.edge = 3; - a_snippet_index.snip = pol_inf_vec.at( a_snippet_index.edge ).size() - 1; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - at_end++; - } - // ende auszulagern als Funkton DecrementSnippetIndex() + if ((static_cast(a_snippet.why_here.x) != static_cast(next_snippet.why_here.x)) + || (static_cast(a_snippet.why_here.y) != static_cast(next_snippet.why_here.y))) + { + LegacyWorldCoordinate3D a_voxel_coordinate; + a_voxel_coordinate.x = ((a_snippet.why_here.x + next_snippet.why_here.x) * 0.5); + a_voxel_coordinate.y = ((a_snippet.why_here.y + next_snippet.why_here.y) * 0.5); + a_voxel_coordinate.z = the_dose_index.z; - if( ( static_cast( a_snippet.why_here.x ) != static_cast( next_snippet.why_here.x ) ) || ( static_cast( a_snippet.why_here.y ) != static_cast( next_snippet.why_here.y ) ) ){ - LegacyWorldCoordinate3D a_voxel_coordinate; - a_voxel_coordinate.x = (( a_snippet.why_here.x + next_snippet.why_here.x ) * 0.5); - a_voxel_coordinate.y = (( a_snippet.why_here.y + next_snippet.why_here.y ) * 0.5); - a_voxel_coordinate.z = the_dose_index.z; + LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate(a_voxel_coordinate); + Contour contour(the_polygon); + inside = contour.pointInPolygon(a_world_coordinate); - LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); - Contour contour(the_polygon); - inside = contour.pointInPolygon( a_world_coordinate ); + // folgenden Teil auslagern als Funkton IncrementSnippetIndex() + if (pol_inf_vec.at(a_snippet_index.edge).size() > (a_snippet_index.snip + 1)) + { + a_snippet_index.snip += 1; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else if (a_snippet_index.edge < 3) + { + a_snippet_index.edge += 1; + a_snippet_index.snip = 0; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } + else + { + a_snippet_index.edge = 0; + a_snippet_index.snip = 0; + next_snippet = pol_inf_vec.at(a_snippet_index.edge).at(a_snippet_index.snip); + } - // folgenden Teil auslagern als Funkton IncrementSnippetIndex() - if( pol_inf_vec.at( a_snippet_index.edge ).size() > ( a_snippet_index.snip + 1 ) ){ - a_snippet_index.snip += 1; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else if( a_snippet_index.edge < 3 ){ - a_snippet_index.edge += 1; - a_snippet_index.snip = 0; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); - } - else{ - a_snippet_index.edge = 0; - a_snippet_index.snip = 0; - next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); + // ende auszulagern als Funkton IncrementSnippetIndex() - } - // ende auszulagern als Funkton IncrementSnippetIndex() + current_static_index_ref.snip = a_snippet_index.snip; + current_static_index_ref.edge = a_snippet_index.edge; - current_static_index_ref.snip = a_snippet_index.snip; - current_static_index_ref.edge = a_snippet_index.edge; + got_it = true; - got_it = true; + } - } + } + } - } - } + } + } - } - } + } - } + return got_it; - return got_it; + } - } + void PolygonInfo::ResetSnippetIndicees() + { - void PolygonInfo::ResetSnippetIndicees(){ + current_static_index.edge = 0; + current_static_index.snip = 0; + current_moving_index.edge = 0; + current_moving_index.snip = 0; + CopySnippetIndex(current_static_index , begin_index); - current_static_index.edge = 0; - current_static_index.snip = 0; - current_moving_index.edge = 0; - current_moving_index.snip = 0; - CopySnippetIndex( current_static_index , begin_index ); + } - } + void PolygonInfo::SetIndexIdentical(IterativePolygonInTermsOfIntersections::WhichIntersection& + intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& + intersection_index_from_ref) + { - void PolygonInfo::SetIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref ){ + intersection_index_to_ref.point_index = intersection_index_from_ref.point_index; + intersection_index_to_ref.intersection_index = intersection_index_from_ref.intersection_index; + intersection_index_to_ref.column_raw_or_unified = intersection_index_from_ref.column_raw_or_unified; - intersection_index_to_ref.point_index = intersection_index_from_ref.point_index; - intersection_index_to_ref.intersection_index = intersection_index_from_ref.intersection_index; - intersection_index_to_ref.column_raw_or_unified = intersection_index_from_ref.column_raw_or_unified; + } - } - -}//namespace - }//namespace + }//namespace + }//namespace }//namespace diff --git a/code/masks/legacy/rttbPolygonInfo_LEGACY.h b/code/masks/legacy/rttbPolygonInfo_LEGACY.h index 17b1d7c..166596b 100644 --- a/code/masks/legacy/rttbPolygonInfo_LEGACY.h +++ b/code/masks/legacy/rttbPolygonInfo_LEGACY.h @@ -1,449 +1,540 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 __PolygonInfo_H #define __PolygonInfo_H #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbStructure.h" #include "rttbDoseIteratorInterface.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" #include "rttbContour_LEGACY.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include #include -namespace rttb{ - namespace masks{ - namespace legacy{ +namespace rttb +{ + namespace masks + { + namespace legacy + { - typedef std::vector< std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > > edge_intersections_intersection_coord_type; - typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > intersection_coord_type; - typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > >::iterator intersection_coord_iterator_type; - - struct VoxelIntersectionIndex{ - - public: - - unsigned int next_intersection; - unsigned int intersection_douplication; - - VoxelIntersectionIndex(){ - next_intersection = 0; - intersection_douplication = 0; - } - - void reset(){ - next_intersection = 0; - intersection_douplication = 0; - } - - - }; - + typedef std::vector< std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > > + edge_intersections_intersection_coord_type; + typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > + intersection_coord_type; + typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > >::iterator + intersection_coord_iterator_type; - struct IntersectionsThisVoxel{ - - public: - - IntersectionsThisVoxel(){ - polygon_number = -1; - corner_intersections_intersection_coord.resize(4); - edge_intersections_intersection_coord.resize(4); - edge_intersections_vox_coord.resize(4); - } + struct VoxelIntersectionIndex + { - ~IntersectionsThisVoxel(){}; - - int GetPolygonNumber(){ - return polygon_number; - } + public: - void SetPolygonNumber( int polygon_number_in ){ - polygon_number = polygon_number_in; - } + unsigned int next_intersection; + unsigned int intersection_douplication; + VoxelIntersectionIndex() + { + next_intersection = 0; + intersection_douplication = 0; + } - std::vector< std::vector< std::vector< double > > > edge_intersections_vox_coord; - intersection_coord_type corner_intersections_intersection_coord; - edge_intersections_intersection_coord_type edge_intersections_intersection_coord; - - private: - - int polygon_number; - - }; + void reset() + { + next_intersection = 0; + intersection_douplication = 0; + } + }; + struct IntersectionsThisVoxel + { + public: + IntersectionsThisVoxel() + { + polygon_number = -1; + corner_intersections_intersection_coord.resize(4); + edge_intersections_intersection_coord.resize(4); + edge_intersections_vox_coord.resize(4); + } - // Die folgende Klasse handhabt die konkrete Speicherung der Schnittpunkte. - // Kennt sich also mit der Speicherung der Schnittpunkte der Konturen mit den Voxelkanten aus. - // Information auf Struktur-Polygonebene. - // Nimmt PolygonInfo den Zugriff auf diese Information ab. - - - - - - // PolygonInfo: Handhabung der Polygonschnipsel die ein Voxel anschneiden : - // Information auf Voxelebene. - // Speichert diese derart, dass die Schnittpunkte mit der Voxelkante in Uhrzeigersinn-Reihenfolge repraesentiert sind. - // Berechnet daraus dann den Anteil des Voxels, der Innerhalb der betrachteten Kontur liegt. - - // PolygonInfo ist ein Objekt, das alle noetigen Informationen zur Berechnung des Polygonsets enthaelt und sinnvoll - //strukturiert. Es berechnet dann anhand der Gesamtheit der schneidenden Polygonschnipsel den Innenanteil. - - class PolygonInfo{ - - - public: - - - - - PolygonInfo(){}; - PolygonInfo( const LegacyPolygonType& the_polygon_in, int polygon_number_in, field_content_type brightness_outside_in, field_content_type brightness_inside_in , FieldOfScalar* MaskFieldReceived_in , const PolygonInTermsOfIntersections& Polygon_Intersections_In , const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn, const IntersectionsThisVoxel& intersections_this_voxel_in ); - - ~PolygonInfo(){}; - LegacyPolygonSequenceType& GetResultingSequence() { return resulting_sequence; }; - bool CreatePolygonSequence(); - - - - struct PolygonSnippet{ - - PolygonSnippet(){ - why_here.x =0; - why_here.y = 0; - point_of_interest_start.x =0; - point_of_interest_start.y = 0; - point_of_interest_end.x =0; - point_of_interest_end.y = 0; - is_edge = 0; - characterize = unknown; - angle_charact = (-1); - i_have_been_processed = false; - } - - - //Wesentlicher Punkt: - //Verantwortlich fuer die Position dieses Snipplets an dieser Stelle Position der Kante - //(die Snipplets sollen anhand ihrer Schnittpositionen entlang der Kante eingeordnet werden und es soll - //hier gekennzeichnet werden, welcher der beiden Schnittpunkte oder Beruehrpunkte fuer die Einordnung and dieser Stelle wesentlich war. - //Ein Polygonsnippet kommt in den Kantenvektoren jeweils doppelt vor, denn es hat zwei Schnitt/Beruehrpunkte. - //Einer der beiden begrenzenden Schnittpunkte/Beruehrpunkte mit der Voxlekante kann auch der Eckpunkt sein. - //In vielen Faellen wird der Eckpunkt jedoch selbst kein Beruehr/Schnittpunkt sein. - LegacyWorldCoordinate2D why_here; - - // Anfangsschnittpunkt - LegacyWorldCoordinate2D point_of_interest_start; - - // Endschnittpunkt - LegacyWorldCoordinate2D point_of_interest_end; + ~IntersectionsThisVoxel() {}; - // Polygonstueckchen zwischen den Schnitt-/Beruehrpunkten - std::vector snippet_intermediate_content; + int GetPolygonNumber() + { + return polygon_number; + } - bool i_have_been_processed; + void SetPolygonNumber(int polygon_number_in) + { + polygon_number = polygon_number_in; + } - // handelt es sich um eine Ecke? - bool is_edge; - //characterize ist ein Integer: - //sagt, ob es sich hier + std::vector< std::vector< std::vector< double > > > edge_intersections_vox_coord; + intersection_coord_type corner_intersections_intersection_coord; + edge_intersections_intersection_coord_type edge_intersections_intersection_coord; - //a) um einen wahren Schnittpunkt handelt - // drinnen drausen Wechsel . - //Sein Wert ist dann 0. - //Drinnen Drausen Wechsel geschieht. + private: + + int polygon_number; + + }; + + + + + + + + // Die folgende Klasse handhabt die konkrete Speicherung der Schnittpunkte. + // Kennt sich also mit der Speicherung der Schnittpunkte der Konturen mit den Voxelkanten aus. + // Information auf Struktur-Polygonebene. + // Nimmt PolygonInfo den Zugriff auf diese Information ab. + + + + + + // PolygonInfo: Handhabung der Polygonschnipsel die ein Voxel anschneiden : + // Information auf Voxelebene. + // Speichert diese derart, dass die Schnittpunkte mit der Voxelkante in Uhrzeigersinn-Reihenfolge repraesentiert sind. + // Berechnet daraus dann den Anteil des Voxels, der Innerhalb der betrachteten Kontur liegt. + + // PolygonInfo ist ein Objekt, das alle noetigen Informationen zur Berechnung des Polygonsets enthaelt und sinnvoll + //strukturiert. Es berechnet dann anhand der Gesamtheit der schneidenden Polygonschnipsel den Innenanteil. + + class PolygonInfo + { + + + public: - //b) um einen Beruehrpunkt vom Typ 1 : - // Beide Snippets ganz auf der Kante kein Wechsel . - //Kontur und Voxelkante beider angrenzenden Polygonsnipplets parallell und deckungsgleich, die Voxelkante wird von beiden zugehoerigen - //Polygonsnippets nicht verlassen - //Sein Wert ist dann 1 - //Ein Drinnen Drausen Wechsel findet hier nicht statt. - //c) um einen Beruehrpunkt vom Typ 2: - //Polygon laueft halb raus. Wechsel je nachdem was folgt. - //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder - //ganzen Laenge auf der Kante. Es kommt von drinnen, aus dem Voxel heraus. - //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. - //Ein Wechsel von drausen nach drinnen findet nur statt, falls im Folgenden das an das zweite Snippet - //angrenzende nach drausen weiterverlaueft. - //Der Wert des integers ist 2 - - //d) Um einen Beruehrpunkt vom Typ 3: - //Polygon laueft halb rein. - //Wechsel nach drausen, je nachdem was folgt. - //Das zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder - //ganzen Laenge auf der Kante. Es Fuehrt nach drinnen ins voxel hinein. - //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. - //Ein wechsel von drinnen nach drausen findet nur statt, falls das Polygon zuletzt von drausen auf die Voxlekante zugelaufen ist. - //Der Wert des integers ist dann 3 - - //e) Um einen Beruehrpunkt vom Typ 4: - // Polygon laueft halb rein. - //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder - //ganzen Laenge auf der Kante. Es kommt von draussen auf das Voxel zu. - //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. - // Ein Wechsel findet dann statt, falls das Polygon im Folgenden nach drinnen weiter verlaueft. - //Der Wert des integers ist dann 4 - - //f) Um einen Beruehrpunkt vom Typ 5: - //Das Zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder - //ganzen Laenge auf der Kante. Es Fuehrt nach drausen aus dem Voxel heraus. - //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. - //Ein Wechsel findet dann statt, wenn das Polygon zuvor aus dem inneren des Voxels heraus kam. - //Der Wert des integers ist dann 5 - - - //g) Beruehrpunkte vom Typ 6 : - // Kein Wechsel aber eventuell ein Innenbereich zu erkennen und als Polygon anzuhaengen. - //(Beide angrenzenden Polygonsnipplets enden auf der Voxelkante und sind zur Voxelkante nicht paralell) - // Der Wert des integers ist dann 6. - // Falls der eine Schnipsel von drinnen kommt und der andere nach drinnen weiterlaueft, muss man einmal im Kreis rum fahren und - // das Polygon, das dabei eintsteht anhaengen. - - //h) Beruehrpunkte vom Typ 7 : - // Beruehrt, beide angrenzenden Polygonstuecke drausen - - // Ecke 8 - // Ecke darf nur dann gewaehlt werden, wenn die Ecke mit sicherheit kein Schittpunkt oder Beruherpunkt mit der Kontur ist - // CheckCornersOutside ist davon abhaengig. - - // Unklar -1. - - CharacterizeIntersection characterize; - - float angle_charact; - - }; - - typedef std::vector snippet_vector; - typedef std::vector PolygonInfoVectorOfEdges; - typedef snippet_vector::iterator snippet_vector_iterator; - - - enum WhichSector{ not_known = -1 , on_edge_twelve_o_clock = 0 , section_twelve_to_three_o_clock = 1 , on_edge_three_o_clock = 2 , section_three_to_six_o_clock = 3 , on_edge_six_o_clock = 4 , section_six_to_nine_o_clock = 5 , on_edge_nine_o_clock = 6, section_nine_to_twelve_o_clock = 7 }; - enum EdgeStatus{ unclear = -1 , inside = 0 , edge_or_outside = 1 }; - EdgeStatus edge_status; - - struct SnippetIndex{ - unsigned int edge; - unsigned int snip; - }; - - bool selfTest(); - IterativePolygonInTermsOfIntersections GetIterativePolygoneInTermsOfIntersections(); - - // Constructor of PolygonInfo calls function SetIntersectionsAndResetIntersectionIndex - // which calls function CreateUnifiedListOfRawAndColumnIntersections - // success of this function is checked here. Calculation of the intersection points is checked as well in this process. - bool TestCreateUnifiedListOfRawAndColumnIntersections( PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ); - bool CompareCalculatedAndExpectedResultingSequenceForTest( LegacyPolygonSequenceType& the_resulting_sequence_ref ); - - // Checks the member pol_inf_vec wihch is a vector that consists of four vectors of PolygonSnippets - // representing the voxel edges. - bool CheckResultingPolygonInfoVectorOfEdgesForTestStructure( PolygonInfoVectorOfEdges pol_inf_vec_expected ); - void ReferenceIterativePolygonForTest( IterativePolygonInTermsOfIntersections& it_poly_ref ){ it_poly_ref = it_poly; } - - - private: - - - void CalcSnippetVectors(); - void SetCurrentMovingProcessed(); - void AppendEdgeToVector( std::vector& vector , int edge_internal ); - bool GetCurrentMovingSnippet( PolygonSnippet& snipp_ref ); - bool CurrentSnippetIsProcessed(); - void ShowResultingSequence(); - void ShowPolygonInTermsOfIntersections(); - void ShowSnippet( PolygonSnippet a_snippet ); - void DoCharacterize( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , CharacterizeIntersection& charact_ref , std::vector anti_outside_combination_vector , WhichSector& inside_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ); - void SetDoseIndex( const LegacyDoseVoxelIndex3D& aDoseIndex ); - void AppendEdges( PolygonInfoVectorOfEdges& pol_inf_vec_ref ); - void CheckEdgeIntersections(); - void DoAppendIntermediateEdgeUpToThisSnippet( PolygonSnippet& snipp_ref , LegacyWorldCoordinate2D why_here , int the_previous_edge , int the_current_edge ); - int EdgeDist( int edge_old , int the_current_edge ); - void IncrementEdge( int& edge_increment ); - bool GetCornerFromVoxelIntersections( unsigned int the_index, SnippetIndex edge_index , IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index ); - int GetNumberOfSnppetsThisEdge( SnippetIndex edge_index ); - bool SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, VoxelIntersectionIndex next_voxel_intersection ); - snippet_vector CreateSnippetVector( int number_of_snippets_this_edge , PolygonSnippet template_snip ); - snippet_vector SortClockwise( snippet_vector snip_vec_local ); - void InsertToSnippetVectorFront( snippet_vector snip_vec_local , SnippetIndex edge_index ); - void RemoveFromLocalSnippetVector( snippet_vector& snip_vec_local , GridIndexType which_one ); - void CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( SnippetIndex edge_index ); - void WorkWithForwardAndBackwardEdgeSnippet( int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); - void WorkWithForwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); - void WorkWithBackwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); - - - - // The following function is just for test and easy debugging. - void GetSectorsAndSetCharacteristicsDoubleCheck( SnippetIndex edge_index, LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two ); - void GetSectors( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); - void GetSectorFirstPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , WhichSector& sector_first_point_ref ); - - // Anmerkung : Funktion verdoppelt die obige. Kann man loeschen und ihre Aufrufe durch GetSectorFirstPoint ersetzen, - // wobei GetSectorFirstPoint dann in GetSectorThisPoint umbenannt werden sollte. - void GetSectorSecondPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref ); - CharacterizeIntersection GetCharacteristicFirstCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); - void GetAntiOutsideCombinationFirstCorner( std::vector& anti_outside_combination_vector_ref ); - void GetInsideFirstCorner( WhichSector& inside_ref ); - void GetPrecedingEdgeFirstCorner( WhichSector& preceding_edge_ref ); - void GetFollowingEdgeFirstCorner( WhichSector& following_edge_ref ); - bool BothOnEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ); - bool FromEdgeIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& inside_ref ); - bool FromEdgeOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , std::vector second_sector_vector ); - bool OutToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , std::vector second_sector_vector ); - bool InToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , WhichSector& inside_ref ); - bool BothIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref ); - bool BothOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , std::vector sector_vector ); - bool OneInOneOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref , std::vector first_sector_vector ); - bool FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); - bool FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); - bool FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); - CharacterizeIntersection GetCharacteristicSecondCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); - void GetAntiOutsideCombinationSecondCorner( std::vector& anti_outside_combination_vector_ref ); - void GetInsideSecondCorner( WhichSector& inside_ref ); - void GetPrecedingEdgeSecondCorner( WhichSector& preceding_edge_ref ); - void GetFollowingEdgeSecondCorner( WhichSector& following_edge_ref ); - CharacterizeIntersection GetCharacteristicThirdCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); - void GetAntiOutsideCombinationThirdCorner( std::vector& anti_outside_combination_vector_ref ); - void GetInsideThirdCorner( WhichSector& inside_ref ); - void GetPrecedingEdgeThirdCorner( WhichSector& preceding_edge_ref ); - void GetFollowingEdgeThirdCorner( WhichSector& following_edge_ref ); - CharacterizeIntersection GetCharacteristicFourthCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); - void GetAntiOutsideCombinationFourthCorner( std::vector& anti_outside_combination_vector_ref ); - void GetInsideFourthCorner( WhichSector& inside_ref ); - void GetPrecedingEdgeFourthCorner( WhichSector& preceding_edge_ref ); - void GetFollowingEdgeFourthCorner( WhichSector& following_edge_ref ); - bool AppendNextIntersectionAndCorrespoindingPolygonSnippets( snippet_vector& snip_vec_ref_local , snippet_vector& snip_vec_ref , int current_edge, VoxelIntersectionIndex& next_voxel_intersection ); - float SetToNextIntersectionAlongThisEdgeAndReturnDistance( LegacyWorldCoordinate2D& closest_local_current_position_ref , float distance_current_position , int current_edge ); - bool IsTheSameEdgeButNoCorner( LegacyWorldCoordinate2D local_current_position , LegacyWorldCoordinate2D current_position , int current_edge ); - bool AddSnippetsThisIntersection( snippet_vector& snip_vec_ref , LegacyWorldCoordinate2D closest_local_current_position ); - bool JustEdge( PolygonSnippet& snippet_ref ); - void Switch( PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref ); - void CopySnippet( PolygonSnippet& to_snippet, PolygonSnippet& snip_in ); - bool GoForwardAndCreatePolygonSnippet( PolygonSnippet& forward_snippet_ref ); - bool GoBackwardAndCreatePolygonSnippet( PolygonSnippet& backward_snippet_ref); - bool CheckPolygonIsInsideForward( float& angle_charact_forward ); - void GetAngle( LegacyWorldCoordinate2D the_next_point , LegacyWorldCoordinate2D the_first_point , float& angle_charact ); - bool CheckPolygonIsInsideBackward( float& angle_charact_backward ); - bool CheckPointInVoxelRegardingDoseIndex( LegacyWorldCoordinate2D voxel_coordinate_to_be_checked ); - double GetDistanceNextEdge( int current_edge ); - float GetDistanceAlongEdge( LegacyDoseVoxelIndex3D edge_position , LegacyWorldCoordinate2D local_position ); - float GetPeriodicDist( float distance_current_position_local , float distance_current_position ); - double GetClockwiseDist( double distance_refer_to , double distance_compare ); - void AppendNewPolygonToResultingSequence(); - void AppendVoxelContour(); - void SlicePositionUnifyAndCheckPeriodicSequence(); - int GetMaxNumberSnippets(); - void GoGetPoly( bool& do_continue_ref , bool& next_is_edge_ref, int& continue_counter_ref , int& max_num ); - void AppendToResultingSequence( PolygonSnippet& snipp_ref ); - void DoAppendForward( PolygonSnippet& snipp_ref , int which_polygon ); - void DoAppendBackward( PolygonSnippet& snipp_ref , int which_polygon ); - void DoInsertForward( PolygonSnippet& snipp_ref , int which_polygon ); - void DoInsertBackward( PolygonSnippet& snipp_ref , int which_polygon ); - void AddFirstForward( PolygonSnippet& snipp_ref , int which_polygon ); - void GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( PolygonSnippet& snipp_ref , int& continue_counter_ref ); - bool IsCorresponding( PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref ); - LegacyWorldCoordinate2D GetOtherEnd( PolygonSnippet& snipp_ref ); - int GetSnippetIndexDistance( SnippetIndex behind_snip_index , SnippetIndex front_snip_index ); - bool SnippetIndexIdentical( SnippetIndex first , SnippetIndex second ); - void FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( PolygonSnippet& snipp_ref , int& continue_counter_ref ); - bool TryGetPolygonsnippetEdge( int& continue_counter_ref , int the_previous_edge ); - bool IsOtherEdge( PolygonSnippet& snipp_ref , int the_previous_edge ); - void IncrementSnippetIndex( SnippetIndex& the_snippet_index ); - bool GetNextIsEdge( SnippetIndex snip_index ); - bool DoContinue( int& max_num , int& continue_counter_ref ); - void CopySnippetIndex( SnippetIndex snip_index_from , SnippetIndex& snip_index_to ); - void ToZero( SnippetIndex snip_index ); - void CheckInside( SnippetIndex current_moving_index , bool& it_is_inside_ref , bool& inside_switch_ref ); - void SetEdgeStatus( CharacterizeIntersection characterize ); - bool SetCurrentStaticIndexKnownInsideOrOutside( SnippetIndex& current_static_index_ref , bool& nothing_to_do_ref ); - bool CheckCornersOutside( SnippetIndex& current_static_index_ref ); - bool CheckCornersInside( SnippetIndex& current_static_index_ref ); - bool CheckThereIsSuchNeighbour( Uint16 x , Uint16 y , Uint16 z , int shift_x , int shift_y , int shift_z , field_content_type brightness ); - bool CheckCenterSurroundingStructure( bool& inside ); - LegacyWorldCoordinate3D GetWorldCoordinate( LegacyWorldCoordinate3D actually_a_voxel_coordinate ); - void SetCurrentPosition( const LegacyDoseVoxelIndex3D& aDoseIndex ); - bool SnippetIndexIsIdentical( SnippetIndex first_index , SnippetIndex second_index ); - bool CheckPointOnEdgeOutside( SnippetIndex& current_static_index_ref , bool& inside ); - void ResetSnippetIndicees(); - void SetIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref ); - void SetCurrentPositionToEdge( int voxel_edge ); - bool SameSnippet( PolygonSnippet& pol_snip_a , PolygonSnippet& pol_snip_b ); - void GetInCombinationFirstCorner( std::vector& in_combination_vector_ref ); - void GetInCombinationSecondCorner( std::vector& in_combination_vector_ref ); - void GetInCombinationThirdCorner( std::vector& in_combination_vector_ref ); - void GetInCombinationFourthCorner( std::vector& in_combination_vector_ref ); - void IncrementVoxelIntersectionIndex( int current_edge, VoxelIntersectionIndex& vox_inters_index , bool& changed_location ); - - // begin some functions and stuff for test - bool CheckConstructurSuccessForTest(); - // end some functions and stuff for test - - PolygonInfoVectorOfEdges pol_inf_vec; - LegacyPolygonSequenceType resulting_sequence; - FieldOfScalar* MaskFieldReceived; - field_content_type brightness_outside; - field_content_type brightness_inside; - LegacyDoseVoxelIndex3D the_dose_index; - LegacyPolygonType the_polygon; - - IterativePolygonInTermsOfIntersections it_poly; - IntersectionsThisVoxel voxel_intersections; - - LegacyWorldCoordinate2D current_position; - - int current_edge; - - SnippetIndex current_static_index; - SnippetIndex current_moving_index; - SnippetIndex begin_index; - - core::GeometricInfo GInformation; - - }; -} - } -} + + PolygonInfo() {}; + PolygonInfo(const LegacyPolygonType& the_polygon_in, int polygon_number_in, + field_content_type brightness_outside_in, field_content_type brightness_inside_in , + FieldOfScalar* MaskFieldReceived_in , + const PolygonInTermsOfIntersections& Polygon_Intersections_In , + const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn, + const IntersectionsThisVoxel& intersections_this_voxel_in); + + ~PolygonInfo() {}; + LegacyPolygonSequenceType& GetResultingSequence() + { + return resulting_sequence; + }; + bool CreatePolygonSequence(); + + + + struct PolygonSnippet + { + + PolygonSnippet() + { + why_here.x = 0; + why_here.y = 0; + point_of_interest_start.x = 0; + point_of_interest_start.y = 0; + point_of_interest_end.x = 0; + point_of_interest_end.y = 0; + is_edge = 0; + characterize = unknown; + angle_charact = (-1); + i_have_been_processed = false; + } + + + //Wesentlicher Punkt: + //Verantwortlich fuer die Position dieses Snipplets an dieser Stelle Position der Kante + //(die Snipplets sollen anhand ihrer Schnittpositionen entlang der Kante eingeordnet werden und es soll + //hier gekennzeichnet werden, welcher der beiden Schnittpunkte oder Beruehrpunkte fuer die Einordnung and dieser Stelle wesentlich war. + //Ein Polygonsnippet kommt in den Kantenvektoren jeweils doppelt vor, denn es hat zwei Schnitt/Beruehrpunkte. + //Einer der beiden begrenzenden Schnittpunkte/Beruehrpunkte mit der Voxlekante kann auch der Eckpunkt sein. + //In vielen Faellen wird der Eckpunkt jedoch selbst kein Beruehr/Schnittpunkt sein. + LegacyWorldCoordinate2D why_here; + + // Anfangsschnittpunkt + LegacyWorldCoordinate2D point_of_interest_start; + + // Endschnittpunkt + LegacyWorldCoordinate2D point_of_interest_end; + + // Polygonstueckchen zwischen den Schnitt-/Beruehrpunkten + std::vector snippet_intermediate_content; + + bool i_have_been_processed; + + // handelt es sich um eine Ecke? + bool is_edge; + + //characterize ist ein Integer: + //sagt, ob es sich hier + + //a) um einen wahren Schnittpunkt handelt + // drinnen drausen Wechsel . + //Sein Wert ist dann 0. + //Drinnen Drausen Wechsel geschieht. + + //b) um einen Beruehrpunkt vom Typ 1 : + // Beide Snippets ganz auf der Kante kein Wechsel . + //Kontur und Voxelkante beider angrenzenden Polygonsnipplets parallell und deckungsgleich, die Voxelkante wird von beiden zugehoerigen + //Polygonsnippets nicht verlassen + //Sein Wert ist dann 1 + //Ein Drinnen Drausen Wechsel findet hier nicht statt. + + //c) um einen Beruehrpunkt vom Typ 2: + //Polygon laueft halb raus. Wechsel je nachdem was folgt. + //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder + //ganzen Laenge auf der Kante. Es kommt von drinnen, aus dem Voxel heraus. + //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. + //Ein Wechsel von drausen nach drinnen findet nur statt, falls im Folgenden das an das zweite Snippet + //angrenzende nach drausen weiterverlaueft. + //Der Wert des integers ist 2 + + //d) Um einen Beruehrpunkt vom Typ 3: + //Polygon laueft halb rein. + //Wechsel nach drausen, je nachdem was folgt. + //Das zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder + //ganzen Laenge auf der Kante. Es Fuehrt nach drinnen ins voxel hinein. + //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. + //Ein wechsel von drinnen nach drausen findet nur statt, falls das Polygon zuletzt von drausen auf die Voxlekante zugelaufen ist. + //Der Wert des integers ist dann 3 + + //e) Um einen Beruehrpunkt vom Typ 4: + // Polygon laueft halb rein. + //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder + //ganzen Laenge auf der Kante. Es kommt von draussen auf das Voxel zu. + //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. + // Ein Wechsel findet dann statt, falls das Polygon im Folgenden nach drinnen weiter verlaueft. + //Der Wert des integers ist dann 4 + + //f) Um einen Beruehrpunkt vom Typ 5: + //Das Zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder + //ganzen Laenge auf der Kante. Es Fuehrt nach drausen aus dem Voxel heraus. + //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. + //Ein Wechsel findet dann statt, wenn das Polygon zuvor aus dem inneren des Voxels heraus kam. + //Der Wert des integers ist dann 5 + + + //g) Beruehrpunkte vom Typ 6 : + // Kein Wechsel aber eventuell ein Innenbereich zu erkennen und als Polygon anzuhaengen. + //(Beide angrenzenden Polygonsnipplets enden auf der Voxelkante und sind zur Voxelkante nicht paralell) + // Der Wert des integers ist dann 6. + // Falls der eine Schnipsel von drinnen kommt und der andere nach drinnen weiterlaueft, muss man einmal im Kreis rum fahren und + // das Polygon, das dabei eintsteht anhaengen. + + //h) Beruehrpunkte vom Typ 7 : + // Beruehrt, beide angrenzenden Polygonstuecke drausen + + // Ecke 8 + // Ecke darf nur dann gewaehlt werden, wenn die Ecke mit sicherheit kein Schittpunkt oder Beruherpunkt mit der Kontur ist + // CheckCornersOutside ist davon abhaengig. + + // Unklar -1. + + CharacterizeIntersection characterize; + + float angle_charact; + + }; + + typedef std::vector snippet_vector; + typedef std::vector PolygonInfoVectorOfEdges; + typedef snippet_vector::iterator snippet_vector_iterator; + + + enum WhichSector { not_known = -1 , on_edge_twelve_o_clock = 0 , section_twelve_to_three_o_clock = 1 , on_edge_three_o_clock = 2 , section_three_to_six_o_clock = 3 , on_edge_six_o_clock = 4 , section_six_to_nine_o_clock = 5 , on_edge_nine_o_clock = 6, section_nine_to_twelve_o_clock = 7 }; + enum EdgeStatus { unclear = -1 , inside = 0 , edge_or_outside = 1 }; + EdgeStatus edge_status; + + struct SnippetIndex + { + unsigned int edge; + unsigned int snip; + }; + + bool selfTest(); + IterativePolygonInTermsOfIntersections GetIterativePolygoneInTermsOfIntersections(); + + // Constructor of PolygonInfo calls function SetIntersectionsAndResetIntersectionIndex + // which calls function CreateUnifiedListOfRawAndColumnIntersections + // success of this function is checked here. Calculation of the intersection points is checked as well in this process. + bool TestCreateUnifiedListOfRawAndColumnIntersections(PolygonInTermsOfIntersections + Expected_Unified_Polygon_Intersections); + bool CompareCalculatedAndExpectedResultingSequenceForTest(LegacyPolygonSequenceType& + the_resulting_sequence_ref); + + // Checks the member pol_inf_vec wihch is a vector that consists of four vectors of PolygonSnippets + // representing the voxel edges. + bool CheckResultingPolygonInfoVectorOfEdgesForTestStructure(PolygonInfoVectorOfEdges + pol_inf_vec_expected); + void ReferenceIterativePolygonForTest(IterativePolygonInTermsOfIntersections& it_poly_ref) + { + it_poly_ref = it_poly; + } + + + private: + + + void CalcSnippetVectors(); + void SetCurrentMovingProcessed(); + void AppendEdgeToVector(std::vector& vector , int edge_internal); + bool GetCurrentMovingSnippet(PolygonSnippet& snipp_ref); + bool CurrentSnippetIsProcessed(); + void ShowResultingSequence(); + void ShowPolygonInTermsOfIntersections(); + void ShowSnippet(PolygonSnippet a_snippet); + void DoCharacterize(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + CharacterizeIntersection& charact_ref , std::vector anti_outside_combination_vector , + WhichSector& inside_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref); + void SetDoseIndex(const LegacyDoseVoxelIndex3D& aDoseIndex); + void AppendEdges(PolygonInfoVectorOfEdges& pol_inf_vec_ref); + void CheckEdgeIntersections(); + void DoAppendIntermediateEdgeUpToThisSnippet(PolygonSnippet& snipp_ref , + LegacyWorldCoordinate2D why_here , int the_previous_edge , int the_current_edge); + int EdgeDist(int edge_old , int the_current_edge); + void IncrementEdge(int& edge_increment); + bool GetCornerFromVoxelIntersections(unsigned int the_index, SnippetIndex edge_index , + IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index); + int GetNumberOfSnppetsThisEdge(SnippetIndex edge_index); + bool SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( + LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, + VoxelIntersectionIndex next_voxel_intersection); + snippet_vector CreateSnippetVector(int number_of_snippets_this_edge , PolygonSnippet template_snip); + snippet_vector SortClockwise(snippet_vector snip_vec_local); + void InsertToSnippetVectorFront(snippet_vector snip_vec_local , SnippetIndex edge_index); + void RemoveFromLocalSnippetVector(snippet_vector& snip_vec_local , GridIndexType which_one); + void CheckEdegeTouchCharacteristicsAndAppendIntermediateContent(SnippetIndex edge_index); + void WorkWithForwardAndBackwardEdgeSnippet(int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased); + void WorkWithForwardEdgeSnippet(LegacyWorldCoordinate2D edge_coord, + LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased); + void WorkWithBackwardEdgeSnippet(LegacyWorldCoordinate2D edge_coord, + LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , + float& angle_charact_b , PolygonSnippet& forward_snippet_ref , + PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , + std::vector& snip_vec_local , int& erased); + + + + // The following function is just for test and easy debugging. + void GetSectorsAndSetCharacteristicsDoubleCheck(SnippetIndex edge_index, + LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , + LegacyWorldCoordinate3D& contour_point_two); + void GetSectors(LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , + LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref); + void GetSectorFirstPoint(LegacyWorldCoordinate2D edge_coord , + LegacyWorldCoordinate3D& contour_point_one , WhichSector& sector_first_point_ref); + + // Anmerkung : Funktion verdoppelt die obige. Kann man loeschen und ihre Aufrufe durch GetSectorFirstPoint ersetzen, + // wobei GetSectorFirstPoint dann in GetSectorThisPoint umbenannt werden sollte. + void GetSectorSecondPoint(LegacyWorldCoordinate2D edge_coord , + LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref); + CharacterizeIntersection GetCharacteristicFirstCorner(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref); + void GetAntiOutsideCombinationFirstCorner(std::vector& + anti_outside_combination_vector_ref); + void GetInsideFirstCorner(WhichSector& inside_ref); + void GetPrecedingEdgeFirstCorner(WhichSector& preceding_edge_ref); + void GetFollowingEdgeFirstCorner(WhichSector& following_edge_ref); + bool BothOnEdge(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& preceding_edge_ref , WhichSector& following_edge_ref); + bool FromEdgeIn(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& preceding_edge_ref , WhichSector& inside_ref); + bool FromEdgeOut(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& preceding_edge_ref , std::vector second_sector_vector); + bool OutToEdge(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& following_edge_ref , std::vector second_sector_vector); + bool InToEdge(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& following_edge_ref , WhichSector& inside_ref); + bool BothIn(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& inside_ref); + bool BothOut(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + std::vector sector_vector); + bool OneInOneOut(WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , + WhichSector& inside_ref , std::vector first_sector_vector); + bool FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose(WhichSector& sector_first_point_ref , + std::vector first_sector_vector , WhichSector& sector_second_point_ref , + std::vector second_sector_vector); + bool FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose(WhichSector& sector_first_point_ref , + std::vector first_sector_vector , WhichSector& sector_second_point_ref , + std::vector second_sector_vector); + bool FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose(WhichSector& sector_first_point_ref , + std::vector first_sector_vector , WhichSector& sector_second_point_ref , + std::vector second_sector_vector); + CharacterizeIntersection GetCharacteristicSecondCorner(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref); + void GetAntiOutsideCombinationSecondCorner(std::vector& + anti_outside_combination_vector_ref); + void GetInsideSecondCorner(WhichSector& inside_ref); + void GetPrecedingEdgeSecondCorner(WhichSector& preceding_edge_ref); + void GetFollowingEdgeSecondCorner(WhichSector& following_edge_ref); + CharacterizeIntersection GetCharacteristicThirdCorner(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref); + void GetAntiOutsideCombinationThirdCorner(std::vector& + anti_outside_combination_vector_ref); + void GetInsideThirdCorner(WhichSector& inside_ref); + void GetPrecedingEdgeThirdCorner(WhichSector& preceding_edge_ref); + void GetFollowingEdgeThirdCorner(WhichSector& following_edge_ref); + CharacterizeIntersection GetCharacteristicFourthCorner(WhichSector& sector_first_point_ref , + WhichSector& sector_second_point_ref); + void GetAntiOutsideCombinationFourthCorner(std::vector& + anti_outside_combination_vector_ref); + void GetInsideFourthCorner(WhichSector& inside_ref); + void GetPrecedingEdgeFourthCorner(WhichSector& preceding_edge_ref); + void GetFollowingEdgeFourthCorner(WhichSector& following_edge_ref); + bool AppendNextIntersectionAndCorrespoindingPolygonSnippets(snippet_vector& snip_vec_ref_local , + snippet_vector& snip_vec_ref , int current_edge, VoxelIntersectionIndex& next_voxel_intersection); + float SetToNextIntersectionAlongThisEdgeAndReturnDistance(LegacyWorldCoordinate2D& + closest_local_current_position_ref , float distance_current_position , int current_edge); + bool IsTheSameEdgeButNoCorner(LegacyWorldCoordinate2D local_current_position , + LegacyWorldCoordinate2D current_position , int current_edge); + bool AddSnippetsThisIntersection(snippet_vector& snip_vec_ref , + LegacyWorldCoordinate2D closest_local_current_position); + bool JustEdge(PolygonSnippet& snippet_ref); + void Switch(PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref); + void CopySnippet(PolygonSnippet& to_snippet, PolygonSnippet& snip_in); + bool GoForwardAndCreatePolygonSnippet(PolygonSnippet& forward_snippet_ref); + bool GoBackwardAndCreatePolygonSnippet(PolygonSnippet& backward_snippet_ref); + bool CheckPolygonIsInsideForward(float& angle_charact_forward); + void GetAngle(LegacyWorldCoordinate2D the_next_point , LegacyWorldCoordinate2D the_first_point , + float& angle_charact); + bool CheckPolygonIsInsideBackward(float& angle_charact_backward); + bool CheckPointInVoxelRegardingDoseIndex(LegacyWorldCoordinate2D voxel_coordinate_to_be_checked); + double GetDistanceNextEdge(int current_edge); + float GetDistanceAlongEdge(LegacyDoseVoxelIndex3D edge_position , + LegacyWorldCoordinate2D local_position); + float GetPeriodicDist(float distance_current_position_local , float distance_current_position); + double GetClockwiseDist(double distance_refer_to , double distance_compare); + void AppendNewPolygonToResultingSequence(); + void AppendVoxelContour(); + void SlicePositionUnifyAndCheckPeriodicSequence(); + int GetMaxNumberSnippets(); + void GoGetPoly(bool& do_continue_ref , bool& next_is_edge_ref, int& continue_counter_ref , + int& max_num); + void AppendToResultingSequence(PolygonSnippet& snipp_ref); + void DoAppendForward(PolygonSnippet& snipp_ref , int which_polygon); + void DoAppendBackward(PolygonSnippet& snipp_ref , int which_polygon); + void DoInsertForward(PolygonSnippet& snipp_ref , int which_polygon); + void DoInsertBackward(PolygonSnippet& snipp_ref , int which_polygon); + void AddFirstForward(PolygonSnippet& snipp_ref , int which_polygon); + void GoAlongSnippetToNextIntersectionAndAppendToResultingSequence(PolygonSnippet& snipp_ref , + int& continue_counter_ref); + bool IsCorresponding(PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref); + LegacyWorldCoordinate2D GetOtherEnd(PolygonSnippet& snipp_ref); + int GetSnippetIndexDistance(SnippetIndex behind_snip_index , SnippetIndex front_snip_index); + bool SnippetIndexIdentical(SnippetIndex first , SnippetIndex second); + void FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter(PolygonSnippet& snipp_ref , + int& continue_counter_ref); + bool TryGetPolygonsnippetEdge(int& continue_counter_ref , int the_previous_edge); + bool IsOtherEdge(PolygonSnippet& snipp_ref , int the_previous_edge); + void IncrementSnippetIndex(SnippetIndex& the_snippet_index); + bool GetNextIsEdge(SnippetIndex snip_index); + bool DoContinue(int& max_num , int& continue_counter_ref); + void CopySnippetIndex(SnippetIndex snip_index_from , SnippetIndex& snip_index_to); + void ToZero(SnippetIndex snip_index); + void CheckInside(SnippetIndex current_moving_index , bool& it_is_inside_ref , + bool& inside_switch_ref); + void SetEdgeStatus(CharacterizeIntersection characterize); + bool SetCurrentStaticIndexKnownInsideOrOutside(SnippetIndex& current_static_index_ref , + bool& nothing_to_do_ref); + bool CheckCornersOutside(SnippetIndex& current_static_index_ref); + bool CheckCornersInside(SnippetIndex& current_static_index_ref); + bool CheckThereIsSuchNeighbour(Uint16 x , Uint16 y , Uint16 z , int shift_x , int shift_y , + int shift_z , field_content_type brightness); + bool CheckCenterSurroundingStructure(bool& inside); + LegacyWorldCoordinate3D GetWorldCoordinate(LegacyWorldCoordinate3D actually_a_voxel_coordinate); + void SetCurrentPosition(const LegacyDoseVoxelIndex3D& aDoseIndex); + bool SnippetIndexIsIdentical(SnippetIndex first_index , SnippetIndex second_index); + bool CheckPointOnEdgeOutside(SnippetIndex& current_static_index_ref , bool& inside); + void ResetSnippetIndicees(); + void SetIndexIdentical(IterativePolygonInTermsOfIntersections::WhichIntersection& + intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& + intersection_index_from_ref); + void SetCurrentPositionToEdge(int voxel_edge); + bool SameSnippet(PolygonSnippet& pol_snip_a , PolygonSnippet& pol_snip_b); + void GetInCombinationFirstCorner(std::vector& in_combination_vector_ref); + void GetInCombinationSecondCorner(std::vector& in_combination_vector_ref); + void GetInCombinationThirdCorner(std::vector& in_combination_vector_ref); + void GetInCombinationFourthCorner(std::vector& in_combination_vector_ref); + void IncrementVoxelIntersectionIndex(int current_edge, VoxelIntersectionIndex& vox_inters_index , + bool& changed_location); + + // begin some functions and stuff for test + bool CheckConstructurSuccessForTest(); + // end some functions and stuff for test + + PolygonInfoVectorOfEdges pol_inf_vec; + LegacyPolygonSequenceType resulting_sequence; + FieldOfScalar* MaskFieldReceived; + field_content_type brightness_outside; + field_content_type brightness_inside; + LegacyDoseVoxelIndex3D the_dose_index; + LegacyPolygonType the_polygon; + + IterativePolygonInTermsOfIntersections it_poly; + IntersectionsThisVoxel voxel_intersections; + + LegacyWorldCoordinate2D current_position; + + int current_edge; + + SnippetIndex current_static_index; + SnippetIndex current_moving_index; + SnippetIndex begin_index; + + core::GeometricInfo GInformation; + + }; + } + + } +} -#endif +#endif diff --git a/code/masks/legacy/rttbSelfIntersectingStructureException.cpp b/code/masks/legacy/rttbSelfIntersectingStructureException.cpp index a747cc0..d5bef7b 100644 --- a/code/masks/legacy/rttbSelfIntersectingStructureException.cpp +++ b/code/masks/legacy/rttbSelfIntersectingStructureException.cpp @@ -1,39 +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 #include #include "rttbSelfIntersectingStructureException.h" -namespace rttb{ - namespace masks{ +namespace rttb +{ + namespace masks + { - const char* SelfIntersectingStructureException::what() const throw() { + const char* SelfIntersectingStructureException::what() const throw() + { return rttb_what.c_str(); - } + } - const char* SelfIntersectingStructureException::GetNameOfClass() const{ - return "SelfIntersectingStructureException"; - } - - }//end namespace masks - }//end namespace rttb + const char* SelfIntersectingStructureException::GetNameOfClass() const + { + return "SelfIntersectingStructureException"; + } + + }//end namespace masks +}//end namespace rttb diff --git a/code/masks/legacy/rttbSelfIntersectingStructureException.h b/code/masks/legacy/rttbSelfIntersectingStructureException.h index bdd8692..25917f0 100644 --- a/code/masks/legacy/rttbSelfIntersectingStructureException.h +++ b/code/masks/legacy/rttbSelfIntersectingStructureException.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H #define __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H #include #include #include "rttbException.h" -namespace rttb{ - namespace masks{ +namespace rttb +{ + namespace masks + { /*! @class SelfIntersectingStructureException - @brief This exception will be thrown in case a Structure intersects with itself in a context where + @brief This exception will be thrown in case a Structure intersects with itself in a context where this is not allowed. */ class SelfIntersectingStructureException: public core::Exception - { - public: - SelfIntersectingStructureException(const std::string& aWhat):Exception(aWhat){} + { + public: + SelfIntersectingStructureException(const std::string& aWhat): Exception(aWhat) {} - virtual ~SelfIntersectingStructureException() throw() {} + virtual ~SelfIntersectingStructureException() throw() {} - /*! @brief Get the exception description - */ - virtual const char * what() const throw(); + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); - /*! @brief Get the name of the exception class - */ - virtual const char* GetNameOfClass() const; - }; - } + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; } +} #endif diff --git a/code/masks/legacy/rttbStructure_LEGACY.cpp b/code/masks/legacy/rttbStructure_LEGACY.cpp index a45e02f..77b1c0e 100644 --- a/code/masks/legacy/rttbStructure_LEGACY.cpp +++ b/code/masks/legacy/rttbStructure_LEGACY.cpp @@ -1,256 +1,323 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbStructure_LEGACY.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbContour_LEGACY.h" //#include //#include #include #include #include #include #include -namespace rttb{ - namespace masks{ - namespace legacy{ - - StructureLegacy::StructureLegacy(const core::Structure& copy) { - this->_structureVector=copy.getStructureVector(); - this->_legacyStructureVector.clear(); - this->_strUID=copy.getUID(); - this->_label=copy.getLabel(); - - //initialize legacy structureVector - LegacyWorldCoordinate3D p; - if (!(_structureVector.size() == _legacyStructureVector.size())){ //needs to be converted - _legacyStructureVector.clear(); - PolygonSequenceType::const_iterator itVV=_structureVector.begin(); - for(;itVV!=_structureVector.end();itVV++){ - PolygonType v1=*itVV; - rttb::masks::legacy::LegacyPolygonType legacyPolygon; - for(PolygonType::const_iterator itPP=(*itVV).begin();itPP!=(*itVV).end();itPP++){ - p.x = itPP->x(); - p.y = itPP->y(); - p.z = itPP->z(); - legacyPolygon.push_back(p); +namespace rttb +{ + namespace masks + { + namespace legacy + { + + StructureLegacy::StructureLegacy(const core::Structure& copy) + { + this->_structureVector = copy.getStructureVector(); + this->_legacyStructureVector.clear(); + this->_strUID = copy.getUID(); + this->_label = copy.getLabel(); + + //initialize legacy structureVector + LegacyWorldCoordinate3D p; + + if (!(_structureVector.size() == _legacyStructureVector.size())) //needs to be converted + { + _legacyStructureVector.clear(); + PolygonSequenceType::const_iterator itVV = _structureVector.begin(); + + for (; itVV != _structureVector.end(); itVV++) + { + PolygonType v1 = *itVV; + rttb::masks::legacy::LegacyPolygonType legacyPolygon; + + for (PolygonType::const_iterator itPP = (*itVV).begin(); itPP != (*itVV).end(); itPP++) + { + p.x = itPP->x(); + p.y = itPP->y(); + p.z = itPP->z(); + legacyPolygon.push_back(p); + } + + _legacyStructureVector.push_back(legacyPolygon); } - _legacyStructureVector.push_back(legacyPolygon); } } - } - - StructureLegacy::~StructureLegacy(){ - } - const PolygonSequenceType& StructureLegacy::getStructureVector() const{ - return _structureVector; - } + StructureLegacy::~StructureLegacy() + { + } + const PolygonSequenceType& StructureLegacy::getStructureVector() const + { + return _structureVector; + } - const LegacyPolygonSequenceType& StructureLegacy::getLegacyStructureVector() const{ - return _legacyStructureVector; - } + const LegacyPolygonSequenceType& StructureLegacy::getLegacyStructureVector() const + { - VolumeType StructureLegacy::getVolume() const{ + return _legacyStructureVector; + } - /*check precondition: contourGeometricType must be closed planar! */ - for(int i=0;i_contourGeometricTypeVector.size();i++){ - std::cout << _contourGeometricTypeVector[i]<x<_contourGeometricTypeVector.size(); i++) + { + std::cout << _contourGeometricTypeVector[i] << std::endl; - int numberOfContours=this->_legacyStructureVector.size(); - std::cout <<"numberOfContours:"<x<_legacyStructureVector.size(); + std::cout << "numberOfContours:" << numberOfContours << std::endl; + double volume = 0; - } + for (int i = 0; i < numberOfContours - 1 ; i++) + { + Contour contour1 = Contour(_legacyStructureVector.at(i)); + double area1 = contour1.getArea(); + Contour contour2 = Contour(_legacyStructureVector.at(i + 1)); + double area2 = contour2.getArea(); + LegacyWorldCoordinate3D p2 = _legacyStructureVector.at(i + 1).at(0); + LegacyWorldCoordinate3D p1 = _legacyStructureVector.at(i).at(0); + double height = p2.z - p1.z; - //Using volume = 1/3 * h* (S1+S2+(S1*S2)^0,5) - volume+=(height*(area1+area2+pow(area1*area2, 0.5)))/3; + if (height == 0) + { + std::cout << "same slice!" << std::endl; + } - //std::cout << pow(area1*area2, 0.5) << std::endl; - //std::cout << "area1:"<getVolume() < str2.getVolume()){ - LegacyPolygonSequenceType::const_iterator itVV; - for(itVV=this->_legacyStructureVector.begin();itVV!=_legacyStructureVector.end();itVV++){ - LegacyPolygonType::iterator itV; - LegacyPolygonType vectorW=*itVV; - for(itV=vectorW.begin();itV!=vectorW.end();itV++){ - LegacyWorldCoordinate3D p=*itV; - if(str2.pointInStructure(p)){ - count++; - //std::cout << "p: "<getNumberOfEndpoints()); - } - //this structure bigger than str2 - else{ - LegacyPolygonSequenceType::const_iterator itVV; - const LegacyPolygonSequenceType& str2Vector = str2.getLegacyStructureVector(); - for(itVV=str2Vector.begin();itVV!=str2Vector.end();itVV++){ - LegacyPolygonType::iterator itV; - LegacyPolygonType vectorW=*itVV; - for(itV=vectorW.begin();itV!=vectorW.end();itV++){ - LegacyWorldCoordinate3D p=*itV; - if(this->pointInStructure(p)){ - count++; - } - /*else - std::cout << "p: "<= _legacyStructureVector.at(0).at(0).z && aPoint.z <=_legacyStructureVector.at(size-1).at(0).z){ - int polygonNr=0; - //get correspoinding slice - for(int i=0;igetVolume() < str2.getVolume()) + { + LegacyPolygonSequenceType::const_iterator itVV; - roiNext=_legacyStructureVector.at(i+1); + for (itVV = this->_legacyStructureVector.begin(); itVV != _legacyStructureVector.end(); itVV++) + { + LegacyPolygonType::iterator itV; + LegacyPolygonType vectorW = *itVV; - LegacyWorldCoordinate3D p1=roi[0]; - LegacyWorldCoordinate3D p2=roiNext[0]; + for (itV = vectorW.begin(); itV != vectorW.end(); itV++) + { + LegacyWorldCoordinate3D p = *itV; - //if roi and roiNext in the same slice - if(p1.z==p2.z){ - if(aPoint.z==p1.z){ - polygonNr=i; - break; + if (str2.pointInStructure(p)) + { + count++; + //std::cout << "p: "<= p1.z && aPoint.zgetNumberOfEndpoints()); + } + //this structure bigger than str2 + else + { + LegacyPolygonSequenceType::const_iterator itVV; + const LegacyPolygonSequenceType& str2Vector = str2.getLegacyStructureVector(); + + for (itVV = str2Vector.begin(); itVV != str2Vector.end(); itVV++) + { + LegacyPolygonType::iterator itV; + LegacyPolygonType vectorW = *itVV; + + for (itV = vectorW.begin(); itV != vectorW.end(); itV++) + { + LegacyWorldCoordinate3D p = *itV; + + if (this->pointInStructure(p)) + { + count++; } + + /*else + std::cout << "p: "<= _legacyStructureVector.at(0).at(0).z + && aPoint.z <= _legacyStructureVector.at(size - 1).at(0).z) + { + + int polygonNr = 0; + + //get correspoinding slice + for (int i = 0; i < size; i++) + { + LegacyPolygonType roi = _legacyStructureVector.at(i); + LegacyPolygonType roiNext; + + //if not the last polygon + if (i != size - 1) + { + + roiNext = _legacyStructureVector.at(i + 1); + + LegacyWorldCoordinate3D p1 = roi[0]; + LegacyWorldCoordinate3D p2 = roiNext[0]; + + //if roi and roiNext in the same slice + if (p1.z == p2.z) + { + if (aPoint.z == p1.z) + { + polygonNr = i; + break; + } + } + else + { + //if aPoint between roi i and roi i+1 + if (aPoint.z >= p1.z && aPoint.z < p2.z) + { + polygonNr = i; + break; + } + } + } + else + { + polygonNr = i; + } + } + + + for (int i = polygonNr; i < size; i++) + { + LegacyPolygonType roi = _legacyStructureVector.at(i); - for(int i=polygonNr;i #include #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" #include "rttbStructure.h" -namespace rttb{ +namespace rttb +{ - namespace masks{ - namespace legacy{ + namespace masks + { + namespace legacy + { - /*! @class Structure - @brief This is a class representing a RT Structure - */ - class StructureLegacy - { - private: - /*! @brief WorldCoordinate3D in mm - */ - PolygonSequenceType _structureVector; + /*! @class Structure + @brief This is a class representing a RT Structure + */ + class StructureLegacy + { + private: + /*! @brief WorldCoordinate3D in mm + */ + PolygonSequenceType _structureVector; - //legacy data structure for faster computation in original toolbox voxelization - LegacyPolygonSequenceType _legacyStructureVector; + //legacy data structure for faster computation in original toolbox voxelization + LegacyPolygonSequenceType _legacyStructureVector; - /*! @brief Contour Geometric Type using DICOM-RT definition (3006,0042). - * POINT: indicates that the contour is a single point, defining a specific location of significance. - * OPEN_PLANAR: indicates that the last vertex shall not be connected to the first point, and that all points - * in Contour Data (3006,0050) shall be coplanar. - * OPEN_NONPLANAR: indicates that the last vertex shall not be connected to the first point, and that the points - * in Contour Data(3006,0050) may be non-coplanar. - * CLOSED_PLANAR: indicates that the last point shall be connected to the first point, where the first point is - * not repeated in the Contour Data. All points in Contour Data (3006,0050) shall be coplanar. - */ + /*! @brief Contour Geometric Type using DICOM-RT definition (3006,0042). + * POINT: indicates that the contour is a single point, defining a specific location of significance. + * OPEN_PLANAR: indicates that the last vertex shall not be connected to the first point, and that all points + * in Contour Data (3006,0050) shall be coplanar. + * OPEN_NONPLANAR: indicates that the last vertex shall not be connected to the first point, and that the points + * in Contour Data(3006,0050) may be non-coplanar. + * CLOSED_PLANAR: indicates that the last point shall be connected to the first point, where the first point is + * not repeated in the Contour Data. All points in Contour Data (3006,0050) shall be coplanar. + */ - // wo und wie wird das Initialisier? Ist Vector die geeignete Datenstruktur? - std::vector _contourGeometricTypeVector; + // wo und wie wird das Initialisier? Ist Vector die geeignete Datenstruktur? + std::vector _contourGeometricTypeVector; - /*! @brief Structure UID*/ - IDType _strUID; + /*! @brief Structure UID*/ + IDType _strUID; - /*! @brief Structure Label*/ - StructureLabel _label; + /*! @brief Structure Label*/ + StructureLabel _label; - - public: - /** copy constructor - * @param copy Structure object to be copied - */ - StructureLegacy(const core::Structure& copy); + public: + /** copy constructor + * @param copy Structure object to be copied + */ + StructureLegacy(const core::Structure& copy); - /*! @brief Structure Destructor - */ - ~StructureLegacy(); - /*! @brief Get the structure vector - * @Return Return a LegacyPolygonSequenceType - */ - const LegacyPolygonSequenceType& getLegacyStructureVector()const; + /*! @brief Structure Destructor + */ + ~StructureLegacy(); - /*! @brief Get the structure vector - * @Return Return a PolygonSequenceType - */ - const PolygonSequenceType& getStructureVector() const; + /*! @brief Get the structure vector + * @Return Return a LegacyPolygonSequenceType + */ + const LegacyPolygonSequenceType& getLegacyStructureVector()const; + /*! @brief Get the structure vector + * @Return Return a PolygonSequenceType + */ + const PolygonSequenceType& getStructureVector() const; - /*! @brief Get the volume of this Structure. Calculation using volume = 1/3 * h* (S1+S2+(S1*S2)^0,5) - @return Return the absolute volume in mm3 - */ - VolumeType getVolume() const; - /*! @brief Structure operation: contain - @return Return the contain factor of str2 in this structure - @brief 0 non-copyable - GenericMutableMaskAccessor& operator=(const - GenericMutableMaskAccessor&);//not implemented on purpose -> non-copyable + GenericMutableMaskAccessor(const + GenericMutableMaskAccessor&); //not implemented on purpose -> non-copyable + GenericMutableMaskAccessor& operator=(const + GenericMutableMaskAccessor&);//not implemented on purpose -> non-copyable - public: - ~GenericMutableMaskAccessor(); + public: + ~GenericMutableMaskAccessor(); - GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo); + GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo); - /*! @brief initialize mask structure if _spRelevantVoxelVector was not previously initialized*/ - void updateMask(); + /*! @brief initialize mask structure if _spRelevantVoxelVector was not previously initialized*/ + void updateMask(); - /*! @brief get vector containing all relevant voxels that are inside the given structure*/ - MaskVoxelListPointer getRelevantVoxelVector(); - /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ - MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); + /*! @brief get vector containing all relevant voxels that are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(); + /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); - /*!@brief determine how a given voxel on the dose grid is masked - * @param aID ID of the voxel in grid. - * @param voxel Reference to the voxel. - * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. - * The relevant volume fraction will be set to zero. - * @return Indicates if the voxel exists and therefore if parameter voxel contains valid values.*/ - bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; + /*!@brief determine how a given voxel on the dose grid is masked + * @param aID ID of the voxel in grid. + * @param voxel Reference to the voxel. + * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. + * The relevant volume fraction will be set to zero. + * @return Indicates if the voxel exists and therefore if parameter voxel contains valid values.*/ + bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; - bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; + bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; - /* @ brief is true if dose is on a homogeneous grid */ - // Inhomogeneous grids are not supported at the moment, but if they will - // be supported in the future the interface does not need to change. - bool isGridHomogeneous() const - { - return true; - }; + /* @ brief is true if dose is on a homogeneous grid */ + // Inhomogeneous grids are not supported at the moment, but if they will + // be supported in the future the interface does not need to change. + bool isGridHomogeneous() const + { + return true; + }; - /*! @brief give access to GeometricInfo*/ - inline const core::GeometricInfo& getGeometricInfo() const - { - return _geoInfo; - }; + /*! @brief give access to GeometricInfo*/ + inline const core::GeometricInfo& getGeometricInfo() const + { + return _geoInfo; + }; - IDType getMaskUID() const - { - return _maskUID; - }; + IDType getMaskUID() const + { + return _maskUID; + }; - void setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel); + void setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel); - void setMaskAt(const VoxelGridIndex3D& gridIndex, const core::MaskVoxel& voxel); + void setMaskAt(const VoxelGridIndex3D& gridIndex, const core::MaskVoxel& voxel); - void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer); + void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer); - }; - } + }; + } } #endif \ No newline at end of file diff --git a/code/masks/rttbVOIindexIdentifier.cpp b/code/masks/rttbVOIindexIdentifier.cpp index ccb1f6c..5b9f874 100644 --- a/code/masks/rttbVOIindexIdentifier.cpp +++ b/code/masks/rttbVOIindexIdentifier.cpp @@ -1,101 +1,103 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: // @date $Date: // @author $Author: */ #include "rttbVOIindexIdentifier.h" #include #include "rttbExceptionMacros.h" namespace rttb { namespace masks { - const std::vector VOIindexIdentifier::getIndicesByVoiRegex(StructSetTypePointer spStructSet, - const std::string& nameAsRegEx) + const std::vector VOIindexIdentifier::getIndicesByVoiRegex( + StructSetTypePointer spStructSet, + const std::string& nameAsRegEx) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL"); } std::vector voiLabelList; std::vector resultVOiIndices; boost::regex e(nameAsRegEx); for (int i = 0; i < spStructSet->getNumberOfStructures(); i++) { voiLabelList.push_back(spStructSet->getStructure(i)->getLabel()); std::string s = spStructSet->getStructure(i)->getLabel(); if (boost::regex_match(s, e)) { resultVOiIndices.push_back(i); } } return resultVOiIndices; } - const unsigned int VOIindexIdentifier::getIndexByVoiName(StructSetTypePointer spStructSet, const std::string& name) + const unsigned int VOIindexIdentifier::getIndexByVoiName(StructSetTypePointer spStructSet, + const std::string& name) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL"); } for (unsigned int i = 0; i < spStructSet->getNumberOfStructures(); i++) { if (spStructSet->getStructure(i)->getLabel() == name) { return i; } } rttbDefaultExceptionStaticMacro("no VOI was found with the given name"); } const std::string VOIindexIdentifier::getVoiNameByIndex(StructSetTypePointer spStructSet, unsigned int index) { if (!spStructSet) { rttbDefaultExceptionStaticMacro("spStructSet is NULL!"); } if (index >= spStructSet->getNumberOfStructures()) { rttbDefaultExceptionStaticMacro("invalid index, voiLabelList out of range"); } return spStructSet->getStructure(index)->getLabel(); } } } diff --git a/code/masks/rttbVOIindexIdentifier.h b/code/masks/rttbVOIindexIdentifier.h index 59e70ba..e2f17b8 100644 --- a/code/masks/rttbVOIindexIdentifier.h +++ b/code/masks/rttbVOIindexIdentifier.h @@ -1,84 +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: // @date $Date: // @author $Author: */ #ifndef __VOI_INDEX_IDENTIFIER_H #define __VOI_INDEX_IDENTIFIER_H #include "rttbStructureSet.h" #include "rttbStructure.h" namespace rttb { namespace masks { class VOIindexIdentifier { public: typedef ::boost::shared_ptr Pointer; typedef ::rttb::core::StructureSet StructSetType; typedef ::boost::shared_ptr StructSetTypePointer; typedef ::rttb::core::Structure StructType; public: VOIindexIdentifier() {} virtual ~VOIindexIdentifier() {} /*!@brief get indices of all VOI that agree with the regex * @details if the regex does not agree with any VOI, the returning vector is empty. * @pre spStructSet must point to a valid structure set. * @param spStructSet Pointer to the structure set that should be checked for the named VOI. * @param name Regular expression of the VOI * @exception ::rttb::core::Exception on invalid spStructSet * @return a vector of all found indices */ static const std::vector getIndicesByVoiRegex(StructSetTypePointer spStructSet, const std::string& name); /*!@brief get the index of the corresponding VOI name * @details only if the exact name is found, the index will be given. * @pre name must contain a valid VOI name * @pre spStructSet must point to a valid structure set. * @param spStructSet Pointer to the structure set that should be checked for the named VOI. * @param name Name of the VOI * @exception ::rttb::core::Exception on invalid spStructSet * @exception ::rttb::core::Exception on invalid name (not found in structure set) * @return the index */ - static const unsigned int getIndexByVoiName(StructSetTypePointer spStructSet, const std::string& name); + static const unsigned int getIndexByVoiName(StructSetTypePointer spStructSet, + const std::string& name); /*!@brief get the VOI of the corresponding index * @pre index must specify a valid index value * @pre spStructSet must point to a valid structure set. * @param spStructSet Pointer to the structure set that should be checked for the named VOI. * @param name Index of the VOI * @exception ::rttb::core::Exception on invalid spStructSet or index>maxLabelIndex * @return voi name */ static const std::string getVoiNameByIndex(StructSetTypePointer spStructSet, unsigned int index); }; } } #endif diff --git a/code/models/rttbBaseTypeModels.h b/code/models/rttbBaseTypeModels.h index 5f06fd4..2625e82 100644 --- a/code/models/rttbBaseTypeModels.h +++ b/code/models/rttbBaseTypeModels.h @@ -1,49 +1,52 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __BASE_TYPE_MODEL_H #define __BASE_TYPE_MODEL_H #include #include "rttbBaseType.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { typedef double BioModelParamType; typedef double BioModelValueType; const double infinity = 1e30; - struct TcpParams { - double alphaMean; - double alphaVariance; - double rho; - std::vector volumeVector; - std::vector bedVector; - }; + struct TcpParams + { + double alphaMean; + double alphaVariance; + double rho; + std::vector volumeVector; + std::vector bedVector; + }; - } } +} #endif \ No newline at end of file diff --git a/code/models/rttbBioModel.cpp b/code/models/rttbBioModel.cpp index 91dcba9..4fa1c3f 100644 --- a/code/models/rttbBioModel.cpp +++ b/code/models/rttbBioModel.cpp @@ -1,48 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #define _USE_MATH_DEFINES #include #include #include "rttbBioModel.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { bool BioModel::init(const double doseFactor) + { + if (_dvh != NULL) { - if(_dvh!=NULL) - { - _value= this->calcModel(doseFactor); + _value = this->calcModel(doseFactor); return true; - } - return false; } - void BioModel::setDVH(const DVHPointer aDVH){_dvh=aDVH;} + return false; + } + + void BioModel::setDVH(const DVHPointer aDVH) + { + _dvh = aDVH; + } - const BioModel::DVHPointer BioModel::getDVH() const{return _dvh;} + const BioModel::DVHPointer BioModel::getDVH() const + { + return _dvh; + } - const BioModelValueType BioModel::getValue() const{ return _value; } + const BioModelValueType BioModel::getValue() const + { + return _value; + } - }//end namespace models - }//end namespace rttb + }//end namespace models +}//end namespace rttb diff --git a/code/models/rttbBioModelCurve.cpp b/code/models/rttbBioModelCurve.cpp index f1e593c..1010760 100644 --- a/code/models/rttbBioModelCurve.cpp +++ b/code/models/rttbBioModelCurve.cpp @@ -1,82 +1,92 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { CurveDataType getCurveDoseVSBioModel(BioModel& aModel, double normalisationDose, int aBin, - double minDose, double maxDose){ - CurveDataType _curveData; - - double minFactor=0, maxFactor=0; - - minFactor=minDose/normalisationDose; - maxFactor=maxDose/normalisationDose; - - double lastValue=0; - for(int i=0;igetDataDifferential(),_dvh->getDeltaD()*factor,_dvh->getDeltaV(), - "temporary","temporary"); + core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), _dvh->getDeltaD() * factor, + _dvh->getDeltaV(), + "temporary", "temporary"); - boost::shared_ptr spDVH = boost::make_shared(variantDVH); - double eud=getEUD(spDVH,aModel.getA()); + boost::shared_ptr spDVH = boost::make_shared(variantDVH); + double eud = getEUD(spDVH, aModel.getA()); - aModel.init(factor); - BioModelValueType value=aModel.getValue(); - _curveData.insert(CurvePointType(eud,value)); - } - return _curveData; + aModel.init(factor); + BioModelValueType value = aModel.getValue(); + _curveData.insert(CurvePointType(eud, value)); } + + return _curveData; } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/code/models/rttbBioModelCurve.h b/code/models/rttbBioModelCurve.h index f3275f4..f418e50 100644 --- a/code/models/rttbBioModelCurve.h +++ b/code/models/rttbBioModelCurve.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MODEL_CURVE_H #define __MODEL_CURVE_H #include "rttbBioModel.h" #include "rttbBaseType.h" #include "rttbNTCPLKBModel.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { //map of dose value and model value typedef std::map CurveDataType; //pair of dose value and model value typedef std::pair CurvePointType; - /*! @brief Get the curve TCP/NTCP Value vs normalisationDose, normalisationDose variant between minDose and + /*! @brief Get the curve TCP/NTCP Value vs normalisationDose, normalisationDose variant between minDose and maxDose. @param bin the size of the map @param minDose min value for x axis @param maxDose max value for x axis @param normalisationDose prescribed dose of the current _dvh or mean/maximum. */ - CurveDataType getCurveDoseVSBioModel(BioModel& aModel, double normalisationDose, int aBin=201, - double minDose=0.1, double maxDose=150); + CurveDataType getCurveDoseVSBioModel(BioModel& aModel, double normalisationDose, int aBin = 201, + double minDose = 0.1, double maxDose = 150); /*! @brief Get the curve NTCP Value vs EUD, dvh variant between minFactor*deltaD and maxFactor*deltaD. @param bin the size of the map @param minFactor min factor for dvh deltaD @param maxFactor max factor for dvh deltaD */ - CurveDataType getCurveEUDVSBioModel(NTCPLKBModel& aModel, DoseCalcType maxFactor=10, - DoseCalcType minFactor=0.1, int aBin=201); - } + CurveDataType getCurveEUDVSBioModel(NTCPLKBModel& aModel, DoseCalcType maxFactor = 10, + DoseCalcType minFactor = 0.1, int aBin = 201); } +} #endif \ No newline at end of file diff --git a/code/models/rttbBioModelScatterPlots.h b/code/models/rttbBioModelScatterPlots.h index 3c8dbea..dd247df 100644 --- a/code/models/rttbBioModelScatterPlots.h +++ b/code/models/rttbBioModelScatterPlots.h @@ -1,92 +1,94 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __MODEL_SCATTER_H #define __MODEL_SCATTER_H #include "rttbBioModel.h" namespace rttb { namespace models { // maps dose to a pair of model value and probability typedef std::multimap > ScatterPlotType; /*! @brief Get the points (TCP/NTCP Value, probability of the value) if 1 parameter vary from a normal- distribution with mean=aMean, variance=aVariance. @param aModel biological model for which the scatter plot will be generated @param aParamId ID of the parameter to be varied to generate the scatter plot @param aMean mean value for the distribution of the varied parameter @param aVariance variance of the varied parameter. The variance may not be exactly zero. If so, it is set to 1e-30 to avoid numerical instability. @param normalisationDose prescribed dose of the current _dvh @param numberOfPoints the size of the map, number of points to be calculated @param aMinDose dose will be randomly selected from [aMinDose] (uniform distribution). They will define the minvalue for x axis @param aMaxDose dose will be randomly selected from [aMaxDose] (uniform distribution). They will define the max value for x axis @return Map of scattered values. If all parameters are valid, this map contains numberOfPoints valid scatter values. If aMaxDose<=aMinDose, the scatter plot cannot be generated. The map will therefore be empty. @warning This method is slow, do not use with too many points. Because the scatter plot map must contain numberOfPoints the scatter plot generation may run more often (producing invalid values). In tests the generation process runs on average approximately 20% more often. @exception InvalidParameterException Thrown if aNormalisationDose<=0 or aMinDose<=aMaxiDose */ ScatterPlotType getScatterPlotVary1Parameter(BioModel& aModel, int aParamId, - BioModelParamType aMean, BioModelParamType aVariance, DoseTypeGy aNormalisationDose, int numberOfPoints = 100, + BioModelParamType aMean, BioModelParamType aVariance, DoseTypeGy aNormalisationDose, + int numberOfPoints = 100, DoseTypeGy aMinDose = 0, DoseTypeGy aMaxDose = 150); /*! @brief Get the points (TCP/NTCP Value, probability of the value) if >=1 parameter vary from a normal- distribution with mean of parameter aParamIdVec.at(i)=aMeanVec.at(i), variance of parameter aParamIdVec.at(i)= aVarianceVec.at(i). @param aModel biological model for which the scatter plot will be generated @param aParamIdVec a vector containing the IDs of the parameters to be varied to generate the scatter plot @param aMeanVec a vector of mean values for the distribution of individually the varied parameters @param aVarianceVec a vector of variance values of the individually varied parameter. The variance may not be exactly zero for any parameter. If so, it is set to 1e-30 to avoid numerical instability. @param normalisationDose prescribed dose of the current _dvh @param numberOfPoints the size of the map, number of points to be calculated @param aMinDose dose will be randomly selected from [aMinDose] (uniform distribution). They will define the min value for x axis @param aMaxDose dose will be randomly selected from [aMaxDose] (uniform distribution). They will define the max value for x axis @throw InvalidParameterException is thrown if the parameter vectors do not have the same size. @return Map of scattered values. If all parameters are valid, this map contains numberOfPoints valid scatter values. If aMaxDose<=aMinDose, the scatter plot cannot be generated. The map will therefore be empty. @warning This method is very slow do not use with too many points. Because the scatter plot map must contain numberOfPoints the scatter plot generation may run more often (producing invalid values). In tests the generation process runs on average approximately 20% more often. @exception InvalidParameterException Thrown if aNormalisationDose<=0 or aMinDose<=aMaxiDose */ ScatterPlotType getScatterPlotVaryParameters(BioModel& aModel, std::vector aParamIdVec, BioModel::ParamVectorType aMeanVec, BioModel::ParamVectorType aVarianceVec, - DoseTypeGy aNormalisationDose, int numberOfPoints = 50, DoseTypeGy aMinDose = 0, DoseTypeGy aMaxDose = 150); + DoseTypeGy aNormalisationDose, int numberOfPoints = 50, DoseTypeGy aMinDose = 0, + DoseTypeGy aMaxDose = 150); /*! Compute normal probability density function for zero mean at aValue with aVariance. */ double normal_pdf(double aValue, double aVariance); } } #endif \ No newline at end of file diff --git a/code/models/rttbDoseBasedModels.cpp b/code/models/rttbDoseBasedModels.cpp index 90147ce..c2559dc 100644 --- a/code/models/rttbDoseBasedModels.cpp +++ b/code/models/rttbDoseBasedModels.cpp @@ -1,41 +1,42 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include "rttbDoseBasedModels.h" #include "rttbInvalidParameterException.h" #include namespace rttb { namespace models { - rttb::models::BioModelValueType calcLQ(const DoseTypeGy dose, const DoseCalcType alpha, const DoseCalcType beta) + rttb::models::BioModelValueType calcLQ(const DoseTypeGy dose, const DoseCalcType alpha, + const DoseCalcType beta) { if (dose < 0 || alpha < 0 || beta < 0) { throw core::InvalidParameterException("Parameter invalid: dose, alpha, beta must be >=0!"); } return exp(-((alpha * dose) + (beta * dose * dose))); } } } \ No newline at end of file diff --git a/code/models/rttbDvhBasedModels.cpp b/code/models/rttbDvhBasedModels.cpp index 26e8dd3..185d8e3 100644 --- a/code/models/rttbDvhBasedModels.cpp +++ b/code/models/rttbDvhBasedModels.cpp @@ -1,173 +1,177 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace models { DoseStatisticType getEUD(const DVHPointer dvh, const DoseCalcType aA) { if (aA == 0) { throw core::InvalidParameterException("Parameter invalid: aA should not be zero!"); } DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } double eud = 0; DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); for (GridIndexType i = 0; i < dataDifferential.size(); i++) { double doseGyi = (i + 0.5) * deltaD; double relativeVolumei = dataDifferential[i] / numberOfVoxels; eud += pow((double)doseGyi, (double)aA) * relativeVolumei; } eud = pow((double)eud, (double)(1 / aA)); return eud; } - BEDDVHType calcBEDDVH(const DVHPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, + BEDDVHType calcBEDDVH(const DVHPointer dvh, const int numberOfFractions, + const DoseCalcType alpha_beta, const bool relativeVolume) { std::map dataBED; std::map dataBEDRelative; DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } if (alpha_beta <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha_beta must be >0!"); } if (numberOfFractions <= 0) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); std::deque::iterator it; int i = 0; for (it = dataDifferential.begin(); it != dataDifferential.end(); ++it) { DoseTypeGy doseGyi = ((i + 0.5) * deltaD); DoseTypeGy bedi = 0; bedi = (doseGyi * (1 + doseGyi / (numberOfFractions * alpha_beta))); if (!relativeVolume) { dataBED.insert(std::pair(bedi, (*it))); } else { - dataBEDRelative.insert(std::pair(bedi, (*it) / numberOfVoxels)); + dataBEDRelative.insert(std::pair(bedi, + (*it) / numberOfVoxels)); } i++; } if (!relativeVolume) { return dataBED; } else { return dataBEDRelative; } } - LQEDDVHType calcLQED2DVH(const DVHPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, + LQEDDVHType calcLQED2DVH(const DVHPointer dvh, const int numberOfFractions, + const DoseCalcType alpha_beta, const bool relativeVolume) { std::map dataLQED2; std::map dataLQED2Relative; DataDifferentialType dataDifferential = dvh->getDataDifferential(); if (dataDifferential.empty()) { throw core::InvalidParameterException("Parameter invalid: DVH data differential should not be empty!"); } if (alpha_beta <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha_beta must be >0!"); } if (numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } DoseTypeGy deltaD = dvh->getDeltaD(); DVHVoxelNumber numberOfVoxels = dvh->getNumberOfVoxels(); std::deque::iterator it; int i = 0; for (it = dataDifferential.begin(); it != dataDifferential.end(); ++it) { DoseTypeGy doseGyi = ((i + 0.5) * deltaD); DoseTypeGy lqed2i = 0; lqed2i = (doseGyi * ((alpha_beta + doseGyi / numberOfFractions) / (alpha_beta + 2))); if (!relativeVolume) { dataLQED2.insert(std::pair(lqed2i, *it)); } else { - dataLQED2Relative.insert(std::pair(lqed2i, (*it) / numberOfVoxels)); + dataLQED2Relative.insert(std::pair(lqed2i, + (*it) / numberOfVoxels)); } i++; } if (!relativeVolume) { return dataLQED2; } else { return dataLQED2Relative; } } } } \ No newline at end of file diff --git a/code/models/rttbDvhBasedModels.h b/code/models/rttbDvhBasedModels.h index d7c9d17..2ea7c76 100644 --- a/code/models/rttbDvhBasedModels.h +++ b/code/models/rttbDvhBasedModels.h @@ -1,49 +1,51 @@ #include #include "rttbDVH.h" #include "rttbBaseType.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { typedef core::DVH::DataDifferentialType DataDifferentialType; typedef core::DVH::DVHPointer DVHPointer; typedef std::map BEDDVHType; typedef std::map LQEDDVHType; - /*! @brief Get Equivalent Uniform Dose (EUD) - @pre dvh data differential is not empty, - @pre aA is not zero, - @return Return calculated EUD value, + /*! @brief Get Equivalent Uniform Dose (EUD) + @pre dvh data differential is not empty, + @pre aA is not zero, + @return Return calculated EUD value, @exception InvalidParameterException Thrown if parameters were not set correctly. */ DoseStatisticType getEUD(const DVHPointer dvh, const DoseCalcType aA); - /*! @brief Calculate Biological Effective/Equivalent Dose (BED) of dvh - @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; - if true-> the corresponding volume value is the relative volume % between 0 and 1, + /*! @brief Calculate Biological Effective/Equivalent Dose (BED) of dvh + @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; + if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 @return Return map: keys are BEDi in Gy, values are the volume of the dose bin @exception InvalidParameterException Thrown if parameters were not set correctly. */ - BEDDVHType calcBEDDVH(const DVHPointer dvh, const int numberOfFractions, - const DoseCalcType alpha_beta, const bool relativeVolume=false); + BEDDVHType calcBEDDVH(const DVHPointer dvh, const int numberOfFractions, + const DoseCalcType alpha_beta, const bool relativeVolume = false); - /*! @brief Calculate Linear-quadratic equivalent dose for 2-Gy (LQED2) of dvh - @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; - if true-> the corresponding volume value is the relative volume % between 0 and 1, + /*! @brief Calculate Linear-quadratic equivalent dose for 2-Gy (LQED2) of dvh + @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; + if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 - @return Return map: keys are LQED2 in Gy, values are the volume of the dose bin; return empty map if not initialized + @return Return map: keys are LQED2 in Gy, values are the volume of the dose bin; return empty map if not initialized @exception InvalidParameterException Thrown if parameters were not set correctly. */ - LQEDDVHType calcLQED2DVH(const DVHPointer dvh, const int numberOfFractions, - const DoseCalcType alpha_beta, const bool relativeVolume=false); + LQEDDVHType calcLQED2DVH(const DVHPointer dvh, const int numberOfFractions, + const DoseCalcType alpha_beta, const bool relativeVolume = false); } } \ No newline at end of file diff --git a/code/models/rttbIntegration.cpp b/code/models/rttbIntegration.cpp index b5ef825..52e780f 100644 --- a/code/models/rttbIntegration.cpp +++ b/code/models/rttbIntegration.cpp @@ -1,190 +1,192 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include #include #include "rttbIntegration.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace models { double tcpModelFunctor::calculate(double x) const { if (x == 0) { x = 1e-30; } return tcpFunction(a + (1 - x) / x, params) / (x * x); } double LkbModelFunctor::calculate(double x) const { if (x == 0) { x = 1e-30; } return lkbFunction(b - (1 - x) / x) / (x * x); } double tcpFunction(double x, const TcpParams& tcp_params) { double alphaVariance = tcp_params.alphaVariance; if (alphaVariance == 0) { alphaVariance = 1e-30; } double f = exp(-pow((x - tcp_params.alphaMean) / alphaVariance, 2) / 2); for (int i = 0; i < tcp_params.volumeVector.size(); ++i) { double tmp, tmp1, tmp2, tmp3; tmp1 = exp(-x * tcp_params.bedVector.at(i)); tmp2 = -(tcp_params.rho) * tcp_params.volumeVector.at(i); tmp3 = tmp2 * tmp1; tmp = exp(tmp3); if (tmp != 1) { f = f * tmp; } } return f; } double integrateTCP(double a, const TcpParams& params) { double aNew = 1e-30; double bNew = 1.0; tcpModelFunctor BMFunction; BMFunction.params = params; BMFunction.a = a; return iterativeIntegration(BMFunction, aNew, bNew); } double lkbFunction(double x) { double tmp = -pow(x, 2) / 2; double step = exp(tmp); return step; } double integrateLKB(double b) { double aNew = 1e-30; double bNew = 1.0; LkbModelFunctor BMFunction; BMFunction.b = b; return iterativeIntegration(BMFunction, aNew, bNew); } //returns the nth stage of refinement of the extended trapezoidal rule template - integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, int stepNum) + integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, + int stepNum) { static integrationType result; if (stepNum == 1) { result = 0.5 * (b - a) * (BMfunction.calculate(a) + BMfunction.calculate(b)); } else { integrationType x, tnm, sum, del; int it, j; for (it = 1, j = 1; j < stepNum - 1; j++) { it <<= 1; } tnm = it; del = (b - a) / tnm; x = a + 0.5 * del; for (sum = 0.0, j = 0; j < it; j++, x += del) { sum += BMfunction.calculate(x); } result = 0.5 * (result + (b - a) * sum / tnm); } return result; } template - integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, integrationType b) + integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, + integrationType b) { integrationType ost = 0.0; integrationType os = 0.0; int maxSteps = 50; double eps = 1e-6; int i = 1; for (; i <= maxSteps; ++i) { integrationType st = trapzd(BMfunction, a, b, i); integrationType s = (4.0 * st - ost) / 3.0; if (i > 5) { if (fabs(s - os) < eps * fabs(os) || (s == 0.0 && os == 0.0)) { return s; } } os = s; ost = st; } //too many iterations, this should never be reachable! throw rttb::core::InvalidParameterException("Integral calculation failed: too many iterations! "); } } } \ No newline at end of file diff --git a/code/models/rttbIntegration.h b/code/models/rttbIntegration.h index 89092bc..d9dc45b 100644 --- a/code/models/rttbIntegration.h +++ b/code/models/rttbIntegration.h @@ -1,113 +1,117 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __INTEGRATION_H #define __INTEGRATION_H #include "rttbBaseTypeModels.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { typedef float integrationType; - /*! @class LkbModelFunctor - @brief A FunctorType: calculate the transformed LKB-Model using the transformation x = b - (1-t)/t. - \int_{-\infty}^{b} dx f(x) = \int_0^1 dt f(b - (1-t)/t)/t^2 - */ - class LkbModelFunctor - { - public: - /*!b: upper bound of the lkb integration*/ - double b; - - /*! calculate the transformed LKB-Model using the transformation x = b - (1-t)/t.. - */ - double calculate(double x) const; - }; - - /*! @class tcpModelFunctor - @brief .A FunctorType: calculate the transformed TCP-LQ-Model using the transformation x = a + (1-t)/t. - \int_{a}^{+\infty} dx f(x) =\int_0^1 dt f(a + (1-t)/t)/t^2 - */ - class tcpModelFunctor - { - public: - - //TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector - TcpParams params; - - /*! a: lower bound of the tcp integration*/ - double a; - - /*! calculate the transformed TCP-LQ-Model using the transformation x = a + (1-t)/t. - */ - double calculate(double x) const; - }; + /*! @class LkbModelFunctor + @brief A FunctorType: calculate the transformed LKB-Model using the transformation x = b - (1-t)/t. + \int_{-\infty}^{b} dx f(x) = \int_0^1 dt f(b - (1-t)/t)/t^2 + */ + class LkbModelFunctor + { + public: + /*!b: upper bound of the lkb integration*/ + double b; + + /*! calculate the transformed LKB-Model using the transformation x = b - (1-t)/t.. + */ + double calculate(double x) const; + }; + + /*! @class tcpModelFunctor + @brief .A FunctorType: calculate the transformed TCP-LQ-Model using the transformation x = a + (1-t)/t. + \int_{a}^{+\infty} dx f(x) =\int_0^1 dt f(a + (1-t)/t)/t^2 + */ + class tcpModelFunctor + { + public: + + //TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector + TcpParams params; + + /*! a: lower bound of the tcp integration*/ + double a; + + /*! calculate the transformed TCP-LQ-Model using the transformation x = a + (1-t)/t. + */ + double calculate(double x) const; + }; /*! Function to be integrated for TCP LQ model. - @param x: variable of the TCP LQ model - @param params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector - @return Return the function value + @param x: variable of the TCP LQ model + @param params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector + @return Return the function value */ - double tcpFunction(double x, const TcpParams& tcp_params); + double tcpFunction(double x, const TcpParams& tcp_params); /*! Compute integration step for f(x) = exp(-pow(t,2)/2). - @param x: variable of the lkb function - @return Return the function value + @param x: variable of the lkb function + @return Return the function value */ double lkbFunction(double x); - /*! Calculate LKB Integration over(-infinity,b). The integral is mapped onto the semi-open interval (0,1] using the transformation x = b - (1-t)/t - @param b: upper bound of the lkb integration - */ + /*! Calculate LKB Integration over(-infinity,b). The integral is mapped onto the semi-open interval (0,1] using the transformation x = b - (1-t)/t + @param b: upper bound of the lkb integration + */ double integrateLKB(double b); - /*! Calculate TCP integration over (a, infinity). The integral is mapped onto the semi-open interval (0,1] using the transformation x = a + (1-t)/t - @param a: lower bound of the tcp integration - @param params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector - */ + /*! Calculate TCP integration over (a, infinity). The integral is mapped onto the semi-open interval (0,1] using the transformation x = a + (1-t)/t + @param a: lower bound of the tcp integration + @param params: TCP parameters including alpha mean, alpha variance, rho, volume vector and bed vector + */ double integrateTCP(double a, const TcpParams& params); - /*This function returns the nth stage of refinement of the extended trapezoidal rule. - @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor - @param a: lower bound of the integral - @param b: upper bound of the integral - @param stepNum: the nth stage - @param result: the current result - */ - template - integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, int stepNum); - - /*! Iterative integration routine - @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor - @param a: lower bound of the integral - @param b: upper bound of the integral - @exception throw InvalidParameterException if integral calculation failed. - */ - template - integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, integrationType b); + /*This function returns the nth stage of refinement of the extended trapezoidal rule. + @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor + @param a: lower bound of the integral + @param b: upper bound of the integral + @param stepNum: the nth stage + @param result: the current result + */ + template + integrationType trapzd(const FunctorType& BMfunction, integrationType a, integrationType b, + int stepNum); + + /*! Iterative integration routine + @param BMfunction: function to be integrated, for example a LkbModelFunctor or a tcpModelFunctor + @param a: lower bound of the integral + @param b: upper bound of the integral + @exception throw InvalidParameterException if integral calculation failed. + */ + template + integrationType iterativeIntegration(const FunctorType& BMfunction, integrationType a, + integrationType b); - } } +} #endif \ No newline at end of file diff --git a/code/models/rttbLQModelAccessor.cpp b/code/models/rttbLQModelAccessor.cpp index ee0b96a..65e3c33 100644 --- a/code/models/rttbLQModelAccessor.cpp +++ b/code/models/rttbLQModelAccessor.cpp @@ -1,72 +1,73 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbLQModelAccessor.h" #include "rttbDoseBasedModels.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace models { LQModelAccessor::~LQModelAccessor() { } - LQModelAccessor::LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta, + LQModelAccessor::LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, + BioModelParamType beta, double doseScaling) : _dose(dose), _alpha(alpha), _beta(beta), _doseScaling(doseScaling) { if (_dose == NULL) { throw core::InvalidDoseException("Dose is NULL"); } if (_doseScaling < 0) { throw core::InvalidParameterException("Dose Scaling must be >0"); } assembleGeometricInfo(); } GenericValueType LQModelAccessor::getValueAt(const VoxelGridID aID) const { return calcLQ(_dose->getValueAt(aID) * _doseScaling, _alpha, _beta); } GenericValueType LQModelAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { return calcLQ(_dose->getValueAt(aIndex) * _doseScaling, _alpha, _beta); } bool LQModelAccessor::assembleGeometricInfo() { _geoInfo = _dose->getGeometricInfo(); return true; } } } diff --git a/code/models/rttbLQModelAccessor.h b/code/models/rttbLQModelAccessor.h index 94456f0..a403ce5 100644 --- a/code/models/rttbLQModelAccessor.h +++ b/code/models/rttbLQModelAccessor.h @@ -1,81 +1,82 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __LQ_MODEL_ACCESSOR_H #define __LQ_MODEL_ACCESSOR_H #include "rttbAccessorWithGeoInfoBase.h" #include "rttbDoseAccessorInterface.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @class LQModelAccessor @brief This class gives access to the LQ Model information in an image */ class LQModelAccessor: public core::AccessorWithGeoInfoBase { public: typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; private: DoseAccessorPointer _dose; BioModelParamType _alpha; BioModelParamType _beta; double _doseScaling; IDType _bioModelUID; LQModelAccessor(); /*! @brief get all required data from the dose geometric info */ bool assembleGeometricInfo(); public: ~LQModelAccessor(); /*! @brief Constructor. @pre dose must be a valid instance (and not null) @exception InvalidDoseException if _dose is NULL */ - LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta, double doseScaling = 1.0); + LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta, + double doseScaling = 1.0); /*! @brief returns the LQ Model value for an id */ GenericValueType getValueAt(const VoxelGridID aID) const; /*! @brief returns the LQ Model value for an index */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const; const IDType getUID() const { return _bioModelUID; }; }; } } #endif diff --git a/code/models/rttbNTCPLKBModel.cpp b/code/models/rttbNTCPLKBModel.cpp index e44b2ce..412100a 100644 --- a/code/models/rttbNTCPLKBModel.cpp +++ b/code/models/rttbNTCPLKBModel.cpp @@ -1,161 +1,163 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include #include #define _USE_MATH_DEFINES #include #include "rttbIntegration.h" #include "rttbNTCPLKBModel.h" #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace models { NTCPLKBModel::NTCPLKBModel(): NTCPModel(), _m(0), _a(0) {} - NTCPLKBModel::NTCPLKBModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aM, BioModelParamType aA): + NTCPLKBModel::NTCPLKBModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aM, + BioModelParamType aA): NTCPModel(aDvh, aD50), _m(aM), _a(aA) {} void NTCPLKBModel::setA(const BioModelParamType aA) { _a = aA; } const BioModelParamType NTCPLKBModel::getA() { return _a; } void NTCPLKBModel::setM(const BioModelParamType aM) { _m = aM; } const BioModelParamType NTCPLKBModel::getM() { return _m; } void NTCPLKBModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 3! "); } else { _d50 = aParameterVector.at(0); _m = aParameterVector.at(1); _a = aParameterVector.at(2); } } void NTCPLKBModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _d50 = aValue; } else if (aParamId == 1) { _m = aValue; } else if (aParamId == 2) { _a = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(for d50) or 1(for m) or 2(for a)! "); } } const int NTCPLKBModel::getParameterID(const std::string& aParamName) const { if (aParamName == "d50") { return 0; } else if (aParamName == "m") { return 1; } else if (aParamName == "a") { return 2; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be d50 or m or a!"); } } BioModelValueType NTCPLKBModel::calcModel(const double doseFactor) { if (_a == 0) { throw core::InvalidParameterException("_a must not be zero"); } if (_m == 0) { throw core::InvalidParameterException("_m must not be zero"); } - core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), + core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), + (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), _dvh->getDeltaV(), "temporary", "temporary"); boost::shared_ptr spDVH = boost::make_shared(variantDVH); double eud = getEUD(spDVH, this->_a); //_m must not be zero double t = (eud - this->_d50) / (this->_m * this->_d50); double value = 1 / pow(2 * M_PI, 0.5); double result = integrateLKB(t); if (result != -100) { value *= result; return value; } else { return false; } } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbNTCPModel.h b/code/models/rttbNTCPModel.h index 559a39e..8d740f8 100644 --- a/code/models/rttbNTCPModel.h +++ b/code/models/rttbNTCPModel.h @@ -1,61 +1,69 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __NTCP_MODEL_H #define __NTCP_MODEL_H #include "rttbBaseType.h" #include "rttbBioModel.h" #include "rttbBaseTypeModels.h" -namespace rttb{ - namespace models{ +namespace rttb +{ + namespace models + { /*! @class NTCPModel @brief This is the interface class for NTCP(Normal Tissue Complication Probability) models */ class NTCPModel: public BioModel - { - public: - typedef BioModel::ParamVectorType ParamVectorType; - typedef BioModel::DVHPointer DVHPointer; + { + public: + typedef BioModel::ParamVectorType ParamVectorType; + typedef BioModel::DVHPointer DVHPointer; - protected: - BioModelParamType _d50; + protected: + BioModelParamType _d50; - public: - NTCPModel(): BioModel(), _d50(0){} - NTCPModel(const BioModelParamType aD50): BioModel(), _d50(aD50){} - NTCPModel(DVHPointer aDvh, const BioModelParamType aD50): BioModel(aDvh), _d50(aD50){} + public: + NTCPModel(): BioModel(), _d50(0) {} + NTCPModel(const BioModelParamType aD50): BioModel(), _d50(aD50) {} + NTCPModel(DVHPointer aDvh, const BioModelParamType aD50): BioModel(aDvh), _d50(aD50) {} - const BioModelParamType getD50(){return _d50;} + const BioModelParamType getD50() + { + return _d50; + } - void setD50(const BioModelParamType aD50){_d50=aD50;} - }; + void setD50(const BioModelParamType aD50) + { + _d50 = aD50; + } + }; - }//end namespace models - }//end namespace rttb + }//end namespace models +}//end namespace rttb #endif diff --git a/code/models/rttbNTCPRSModel.cpp b/code/models/rttbNTCPRSModel.cpp index 6d908ba..95c1c87 100644 --- a/code/models/rttbNTCPRSModel.cpp +++ b/code/models/rttbNTCPRSModel.cpp @@ -1,152 +1,153 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #define _USE_MATH_DEFINES #include #include "rttbNTCPRSModel.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace models { NTCPRSModel::NTCPRSModel(): NTCPModel(), _gamma(0), _s(0) {} - NTCPRSModel::NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, BioModelParamType aS): + NTCPRSModel::NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, + BioModelParamType aS): NTCPModel(aDvh, aD50), _gamma(aGamma), _s(aS) {} void NTCPRSModel::setGamma(const BioModelParamType aGamma) { _gamma = aGamma; } const BioModelParamType NTCPRSModel::getGamma() { return _gamma; } void NTCPRSModel::setS(const BioModelParamType aS) { _s = aS; } const BioModelParamType NTCPRSModel::getS() { return _s; } void NTCPRSModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 3! "); } else { _d50 = aParameterVector.at(0); _gamma = aParameterVector.at(1); _s = aParameterVector.at(2); } } void NTCPRSModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _d50 = aValue; } else if (aParamId == 1) { _gamma = aValue; } else if (aParamId == 2) { _s = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(for d50) or 1(for gamma) or 2(for s)! "); } } const int NTCPRSModel::getParameterID(const std::string& aParamName) const { if (aParamName == "d50") { return 0; } else if (aParamName == "gamma") { return 1; } else if (aParamName == "s") { return 2; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be d50 or gamma or s!"); } } const double NTCPRSModel::poissonModel(const double dose) { //_d50 must not be zero return pow(2, -exp(M_E * this->_gamma * (1 - dose / this->_d50))); } BioModelValueType NTCPRSModel::calcModel(double doseFactor) { if (_d50 == 0) { throw core::InvalidParameterException("d50 must not be zero"); } if (_s == 0) { throw core::InvalidParameterException("s must not be zero"); } std::deque dataDifferential = this->_dvh->getDataDifferential(); double ntcp = 1; for (GridIndexType i = 0; i < dataDifferential.size(); i++) { double pd = pow(this->poissonModel(i * this->_dvh->getDeltaD() * doseFactor), this->_s); double vi = dataDifferential[i] / this->_dvh->getNumberOfVoxels(); ntcp *= pow((1 - pd), vi); } //_s must not be zero return (BioModelValueType)(pow((1 - ntcp), 1 / this->_s)); } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbNTCPRSModel.h b/code/models/rttbNTCPRSModel.h index b0ab272..74f2f1a 100644 --- a/code/models/rttbNTCPRSModel.h +++ b/code/models/rttbNTCPRSModel.h @@ -1,106 +1,107 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __NTCP_RS_MODEL_H #define __NTCP_RS_MODEL_H #include #include #include "rttbBaseType.h" #include "rttbNTCPModel.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @class NTCPRSModel @brief This class represents a NTCP(Normal Tissue Complication Probability) relative seriality model (Källman 1992) @see NTCPModel */ class NTCPRSModel: public NTCPModel { public: typedef NTCPModel::ParamVectorType ParamVectorType; typedef NTCPModel::DVHPointer DVHPointer; private: /*! _gamma The normalised dose-response gradient, values between 1.7 and 2.0 are typical for human tumours. (Källman 1992) */ BioModelParamType _gamma; /*! _s The relative seriality factor, e.g. s=3.4 for the esophagus (highly serial structure) and s=0.0061 for the lung(highly parallel structure). Must not be zero on model evaluation. */ BioModelParamType _s; const double poissonModel(const double dose); protected: /*! @brief Calculate the model value @param doseFactor scaling factor for the dose. The model calculation will use the dvh with each di=old di*doseFactor. @throw if either _s or _d50 is zero for the model calculation. */ BioModelValueType calcModel(const double doseFactor = 1); public: NTCPRSModel(); /*!@brief Constructor initializing all member variables with given parameters. */ - NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, BioModelParamType aS); + NTCPRSModel(DVHPointer aDvh, BioModelParamType aD50, BioModelParamType aGamma, + BioModelParamType aS); void setGamma(const BioModelParamType aGamma); const BioModelParamType getGamma(); void setS(const BioModelParamType aS); const BioModelParamType getS(); /*! @brief Set parameter with ID. "d50":0,"gamma":1,"s":2 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2. */ virtual void setParameterByID(const int aParamId, const BioModelParamType aValue); /*! @brief Set parameter vector, where index of vector is the parameter Id. "d50":0,"gamma":1,"s":2 @exception InvalidParameterException Thrown if aParamterVector.size()!=3. */ virtual void setParameterVector(const ParamVectorType& aParameterVector); /*! @brief Get parameter ID. "d50":0,"gamma":1,"s":2 @return 0 for "d50", 1 for "gamma", 2 for "s" @exception InvalidParameterException Thrown if aParamName is not d50 or gamma or s. */ virtual const int getParameterID(const std::string& aParamName) const; }; } } #endif diff --git a/code/models/rttbTCPLQModel.cpp b/code/models/rttbTCPLQModel.cpp index 71ba16e..3df5ac9 100644 --- a/code/models/rttbTCPLQModel.cpp +++ b/code/models/rttbTCPLQModel.cpp @@ -1,273 +1,286 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #define _USE_MATH_DEFINES #include #include #include #include #include "rttbTCPLQModel.h" #include "rttbDvhBasedModels.h" #include "rttbBaseTypeModels.h" #include "rttbIntegration.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace models { TCPLQModel::TCPLQModel(): TCPModel(), _alphaMean(0), _alphaVariance(0), _alpha_beta(0), _rho(0) {} - TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, - int aNumberOfFractions): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(0), + TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, + BioModelParamType aRho, + int aNumberOfFractions): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), + _alphaVariance(0), _alpha_beta(aAlphaMean / aBeta), _rho(aRho) {} - TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, + TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, + BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(aAlphaVariance), _alpha_beta(aAlpha_Beta), _rho(aRho) {} - void TCPLQModel::setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, + void TCPLQModel::setParameters(const BioModelParamType aAlphaMean, + const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance) { _alphaMean = aAlphaMean; _alphaVariance = aAlphaVariance; _alpha_beta = aAlpha_Beta; _rho = aRho; //reset _value, because parameters have changed. _value = 0; } - void TCPLQModel::setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance) + void TCPLQModel::setAlpha(const BioModelParamType aAlphaMean, + const BioModelParamType aAlphaVariance) { _alphaVariance = aAlphaVariance; _alphaMean = aAlphaMean; } void TCPLQModel::setAlphaBeta(const BioModelParamType aAlpha_Beta) { _alpha_beta = aAlpha_Beta; } void TCPLQModel::setRho(const BioModelParamType aRho) { _rho = aRho; } const BioModelParamType TCPLQModel::getAlphaBeta() { return _alpha_beta; } const BioModelParamType TCPLQModel::getAlphaMean() { return _alphaMean; } const BioModelParamType TCPLQModel::getAlphaVariance() { return _alphaVariance; } const BioModelParamType TCPLQModel::getRho() { return _rho; } - long double TCPLQModel::calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj) + long double TCPLQModel::calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, + double bedj) { return exp(-aRho * vj * exp(-aAlphaMean * bedj)); } - long double TCPLQModel::calcTCP(std::map aBEDDVH, BioModelParamType aRho, + long double TCPLQModel::calcTCP(std::map aBEDDVH, + BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV) { std::map::iterator it; long double tcp = 1; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { long double tcpi = this->calcTCPi(aRho, aAlphaMean, (*it).second * aDeltaV, (*it).first); tcp = tcp * tcpi; } return tcp; } - long double TCPLQModel::calcTCPAlphaNormalDistribution(std::map aBEDDVH, - BioModelParamType aRho, BioModelParamType aAlphaMean, - BioModelParamType aAlphaVariance, double aDeltaV) + long double TCPLQModel::calcTCPAlphaNormalDistribution( + std::map aBEDDVH, + BioModelParamType aRho, BioModelParamType aAlphaMean, + BioModelParamType aAlphaVariance, double aDeltaV) { std::map::iterator it; std::vector volumeV2; std::vector bedV2; int i = 0; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { volumeV2.push_back((*it).second * aDeltaV); bedV2.push_back((*it).first); i++; } struct TcpParams params = {aAlphaMean, aAlphaVariance, aRho, volumeV2, bedV2}; double result = integrateTCP(0, params); if (result == -100) { std::cerr << "Integration error!\n"; return -1; } else { long double tcp = 1 / (pow(2 * M_PI, 0.5) * _alphaVariance) * result; return tcp; } } BioModelValueType TCPLQModel::calcModel(const double doseFactor) { - core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), + core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), + (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), _dvh->getDeltaV(), "temporary", "temporary"); boost::shared_ptr spDVH = boost::make_shared(variantDVH); BioModelValueType value = 0; if (_alphaVariance == 0) { if (_alphaMean <= 0 || _alpha_beta <= 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha, alpha/beta, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } - std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); + std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, + _alpha_beta); value = (BioModelValueType)this->calcTCP(dataBED, _rho, _alphaMean, variantDVH.getDeltaV()); return value; } //if alpha normal distribution else { if (this->_alpha_beta <= 0 || this->_alphaMean <= 0 || this->_alphaVariance < 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha/beta, alphaMean, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } - std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); - value = (BioModelValueType)(this->calcTCPAlphaNormalDistribution(dataBED, _rho, _alphaMean, _alphaVariance, + std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, + _alpha_beta); + value = (BioModelValueType)(this->calcTCPAlphaNormalDistribution(dataBED, _rho, _alphaMean, + _alphaVariance, variantDVH.getDeltaV())); return value; } } void TCPLQModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 4) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 4! "); } else { _alphaMean = aParameterVector.at(0); _alphaVariance = aParameterVector.at(1); _alpha_beta = aParameterVector.at(2); _rho = aParameterVector.at(3); } } void TCPLQModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _alphaMean = aValue; } else if (aParamId == 1) { _alphaVariance = aValue; } else if (aParamId == 2) { _alpha_beta = aValue; } else if (aParamId == 3) { _rho = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(alphaMean) or 1(alphaVariance) or 2(alpha_beta) or 3(rho)! "); } } const int TCPLQModel::getParameterID(const std::string& aParamName) const { if (aParamName == "alphaMean") { return 0; } else if (aParamName == "alphaVariance") { return 1; } else if (aParamName == "alpha_beta") { return 2; } else if (aParamName == "rho") { return 3; } else { rttbExceptionMacro(core::InvalidParameterException, - << "Parameter name " << aParamName << " invalid: it should be alphaMean or alphaVariance or alpha_beta or rho!"); + << "Parameter name " << aParamName << + " invalid: it should be alphaMean or alphaVariance or alpha_beta or rho!"); } } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbTCPLQModel.h b/code/models/rttbTCPLQModel.h index 560b33e..fbf95c5 100644 --- a/code/models/rttbTCPLQModel.h +++ b/code/models/rttbTCPLQModel.h @@ -1,163 +1,165 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __TCP_LQ_MODEL_H #define __TCP_LQ_MODEL_H #include #include #include #include "rttbBaseType.h" #include "rttbTCPModel.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @class TCPLQModel @brief This class represents a TCP(Tumor Control Probability) LQ model (Nahum and Sanchez-Nieto 2001, Hall and Giaccia 2006) @see TCPModel */ class TCPLQModel: public TCPModel { public: typedef TCPModel::ParamVectorType ParamVectorType; typedef TCPModel::DVHPointer DVHPointer; private: /*! @brief Calculate intermediate tcp using alpha constant. This is a helper function for calcTCP() @see calcTCP */ long double calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj); /*! @brief Calculate tcp using alpha constant. */ long double calcTCP(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV); /*! @brief Calculate tcp using a normal distribution for alpha. */ long double calcTCPAlphaNormalDistribution(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance, double aDeltaV); protected: BioModelParamType _alphaMean; BioModelParamType _alphaVariance; BioModelParamType _alpha_beta; /*! Roh is the initial clonogenic cell density */ BioModelParamType _rho; /*! @brief Calculate the model value @param doseFactor scaling factor for prescribed dose. The model calculation will use the dvh with each di=old di*doseFactor. @pre _alphaMean >0 @pre _alphaVariance >= 0 @pre _alpha_beta > 0 @pre _rho > 0 @pre _numberOfFractions > 1 @exception InvalidParameterException Thrown if parameters were not set correctly. */ BioModelValueType calcModel(const double doseFactor = 1); public: TCPLQModel(); /*! @brief Constructor initializes member variables with given parameters. @pre aAlphaMean >0 @pre aBeta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ - TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, + TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, + BioModelParamType aRho, int aNumberOfFractions); /*! @brief Constructor for alpha distribution initializes member variables with given parameters. @pre aAlphaMean >0 @pre aAlphaVariance >0 @pre aAlpha_Beta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ - TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, + TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, + BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance); const BioModelParamType getRho(); void setRho(const BioModelParamType aRho); const BioModelParamType getAlphaMean(); const BioModelParamType getAlphaVariance(); /*! @brief The distribution of the parameter alpha, which is characteristic for a population of cells, is described by the its mean and variance. If alpha is constant the variance is 0. @param aAlphaVariance The variance of alpha can be given, the default value is 0 resulting in constant alpha. */ void setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance = 0); const BioModelParamType getAlphaBeta(); void setAlphaBeta(const BioModelParamType aAlpha_Beta); /*! @brief Set parameters for the TCP model. _value will be reset to 0. @param aAlpha_Beta alpha/beta constant . @param aAlphaMean mean of alpha distribution. @param aAlphaVariance variance of alpha distribution. */ void setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance = 0); /*! @brief Set parameter with ID. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2 or 3. */ virtual void setParameterByID(const int aParamId, const BioModelParamType aValue); /*! @brief Set parameter vector, where index of vector is the parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamterVector.size()!=4. */ virtual void setParameterVector(const ParamVectorType& aParameterVector); /*! @brief Get parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @return 0 for "alphaMean", 1 for "alphaVariance", 2 for "alpha_beta", 3 for "rho" @exception InvalidParameterException Thrown if aParamName is not alphaMean or alphaVariance or alpha_beta or rho. */ virtual const int getParameterID(const std::string& aParamName) const; }; }//end algorithms }//end rttb #endif diff --git a/code/models/rttbTCPModel.cpp b/code/models/rttbTCPModel.cpp index fb3c157..6eb54d3 100644 --- a/code/models/rttbTCPModel.cpp +++ b/code/models/rttbTCPModel.cpp @@ -1,38 +1,42 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbTCPModel.h" -namespace rttb{ +namespace rttb +{ - namespace models{ + namespace models + { - void TCPModel::setNumberOfFractions(const int aNumberOfFractions){ - _numberOfFractions=aNumberOfFractions; - } + void TCPModel::setNumberOfFractions(const int aNumberOfFractions) + { + _numberOfFractions = aNumberOfFractions; + } - const int TCPModel::getNumberOfFractions(){ + const int TCPModel::getNumberOfFractions() + { return _numberOfFractions; - } - } + } +} diff --git a/code/models/rttbTCPModel.h b/code/models/rttbTCPModel.h index 8eef010..196774e 100644 --- a/code/models/rttbTCPModel.h +++ b/code/models/rttbTCPModel.h @@ -1,63 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __TCP_MODEL_H #define __TCP_MODEL_H #include "rttbBaseType.h" #include "rttbBioModel.h" #include "rttbBaseTypeModels.h" -namespace rttb{ +namespace rttb +{ - namespace models{ + namespace models + { /*! @class TCPModel @brief This is the interface class for TCP(Tumor Control Probability) models */ class TCPModel: public BioModel - { - public: - typedef BioModel::ParamVectorType ParamVectorType; - typedef BioModel::DVHPointer DVHPointer; + { + public: + typedef BioModel::ParamVectorType ParamVectorType; + typedef BioModel::DVHPointer DVHPointer; - protected: - int _numberOfFractions; + protected: + int _numberOfFractions; - public: + public: - TCPModel(): BioModel(), _numberOfFractions(0){}; + TCPModel(): BioModel(), _numberOfFractions(0) {}; - TCPModel(int aNum): BioModel(), _numberOfFractions(aNum){}; + TCPModel(int aNum): BioModel(), _numberOfFractions(aNum) {}; - TCPModel(DVHPointer aDvh, int aNum): BioModel(aDvh), _numberOfFractions(aNum){}; + TCPModel(DVHPointer aDvh, int aNum): BioModel(aDvh), _numberOfFractions(aNum) {}; - void setNumberOfFractions(const int aNumberOfFractions); + void setNumberOfFractions(const int aNumberOfFractions); - const int getNumberOfFractions(); + const int getNumberOfFractions(); - }; + }; - }//end namespace models - }//end namespace rttb + }//end namespace models +}//end namespace rttb #endif diff --git a/demoapps/BioModelCalc/BioModelCalc.cpp b/demoapps/BioModelCalc/BioModelCalc.cpp index 9d2b5a8..b05f4ae 100644 --- a/demoapps/BioModelCalc/BioModelCalc.cpp +++ b/demoapps/BioModelCalc/BioModelCalc.cpp @@ -1,131 +1,133 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "BioModelCalcApplicationData.h" #include "BioModelCalcHelper.h" #include "BioModelCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbException.h" rttb::apps::bioModelCalc::ApplicationData appData; int main(int argc, const char** argv) { int result = 0; boost::shared_ptr argParser; try { std::string appName = "BioModelCalc"; std::string appVersion = RTTB_FULL_VERSION_STRING; - argParser = boost::make_shared(argc, argv, appName, appVersion); + argParser = boost::make_shared(argc, argv, appName, + appVersion); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return -1; } // This is vital. The application needs to exit if the "help" or "version" parameter is set // because this means the other parameters won't be parsed. if (argParser->isSet(argParser->OPTION_HELP) || argParser->isSet(argParser->OPTION_VERSION)) { return 0; } rttb::apps::bioModelCalc::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose file: " << appData._doseFileName << std::endl; std::cout << "Bio model output file: " << appData._outputFileName << std::endl; std::cout << "Model: " << appData._model << std::endl; std::cout << "Model parameters: "; for (unsigned int i = 0; i < appData._modelParameters.size(); i++) { if (i != 0) { std::cout << ", "; } std::cout << appData._modelParameters.at(i); } std::cout << std::endl; std::cout << "Dose scaling: " << appData._doseScaling << std::endl; std::cout << std::endl; try { appData._dose = rttb::apps::bioModelCalc::loadDose(appData._doseFileName, appData._doseLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 1; } try { rttb::apps::bioModelCalc::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { - std::cerr << "Error!!! unknown error while calculating the bioModel or writing the image." << std::endl; + std::cerr << "Error!!! unknown error while calculating the bioModel or writing the image." << + std::endl; return 2; } return result; } diff --git a/demoapps/BioModelCalc/BioModelCalcHelper.cpp b/demoapps/BioModelCalc/BioModelCalcHelper.cpp index 979d839..990e9be 100644 --- a/demoapps/BioModelCalc/BioModelCalcHelper.cpp +++ b/demoapps/BioModelCalc/BioModelCalcHelper.cpp @@ -1,149 +1,152 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "BioModelCalcHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "rttbExceptionMacros.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbITKImageAccessorConverter.h" #include "rttbImageWriter.h" #include "rttbLQModelAccessor.h" rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::bioModelCalc::loadDose(const std::string& fileName, const rttb::apps::bioModelCalc::ApplicationData::LoadingStyleArgType& args) { rttb::core::DoseAccessorInterface::DoseAccessorPointer result; std::cout << std::endl << "read dose file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomDose(fileName); } else if (args[0] == "helax") { std::cout << "use RTTB Helax IO... "; result = loadHelaxDose(fileName); } else if (args[0] == "itk") { std::cout << "use RTTB itk IO... "; result = loadITKDose(fileName); } else if (args[0] == "virtuos") { if (args.size() < 2) { rttbDefaultExceptionStaticMacro( << "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); } std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos plan file: " << args[1] << " ... "; result = loadVirtuosDose(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::bioModelCalc::loadDicomDose(const std::string& fileName) { rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::bioModelCalc::loadHelaxDose(const std::string& path) { rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::bioModelCalc::loadITKDose(const std::string& fileName) { rttb::io::itk::ITKImageFileAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer -rttb::apps::bioModelCalc::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) +rttb::apps::bioModelCalc::loadVirtuosDose(const std::string& fileName, + const std::string& planFileName) { rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); return generator.generateDoseAccessor(); }; void rttb::apps::bioModelCalc::processData(rttb::apps::bioModelCalc::ApplicationData& appData) { rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor; std::cout << std::endl << "generate biomodel... "; - auto bioModelAccessor = generateBioModel(appData._dose, appData._model, appData._modelParameters, appData._doseScaling); + auto bioModelAccessor = generateBioModel(appData._dose, appData._model, appData._modelParameters, + appData._doseScaling); std::cout << "done." << std::endl; std::cout << std::endl << "generate output image... "; io::itk::ITKImageAccessorConverter converter(bioModelAccessor); converter.setFailOnInvalidIDs(true); converter.process(); io::itk::ITKImageAccessorConverter::ITKImageType::Pointer itkImage = converter.getITKImage(); std::cout << "done." << std::endl; std::cout << std::endl << "write output image... "; io::itk::ImageWriter writer(appData._outputFileName, itkImage); writer.writeFile(); std::cout << "done." << std::endl; }; rttb::core::AccessorInterface::AccessorPointer rttb::apps::bioModelCalc::generateBioModel( rttb::core::DoseAccessorInterface::DoseAccessorPointer dose, const std::string& model, const std::vector& modelParameters, double doseScaling) { if (model == "LQ") { - return boost::make_shared(dose, modelParameters.at(0), modelParameters.at(1), + return boost::make_shared(dose, modelParameters.at(0), + modelParameters.at(1), doseScaling); } else { rttbDefaultExceptionStaticMacro( << "Unknown model selected. Cannot load data. Selected model: " << model); } } diff --git a/demoapps/BioModelCalc/BioModelCmdLineParser.cpp b/demoapps/BioModelCalc/BioModelCmdLineParser.cpp index 7703b77..7287869 100644 --- a/demoapps/BioModelCalc/BioModelCmdLineParser.cpp +++ b/demoapps/BioModelCalc/BioModelCmdLineParser.cpp @@ -1,98 +1,100 @@ #include "BioModelCmdLineParser.h" namespace rttb { namespace apps { namespace bioModelCalc { BioModelCmdLineParser::BioModelCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version) : CmdLineParserBase(name, version) { addOption(OPTION_DOSE_FILE, OPTION_GROUP_REQUIRED, "The name of the dose file. Can be omitted if used as " "positional argument (see above).", 'd', true); addOption(OPTION_OUTPUT_FILE, OPTION_GROUP_REQUIRED, "The name of the output file. Can be omitted if used as " "positional argument (see above).", 'o', true); addPositionalOption(OPTION_DOSE_FILE, 1); addPositionalOption(OPTION_OUTPUT_FILE, 1); addOptionWithDefaultValue(OPTION_MODEL, OPTION_GROUP_REQUIRED, - "The used radiobiological model the dose should be analyzed with. Available models are:\n \"LQ\"", "LQ", "LQ", 'm'); + "The used radiobiological model the dose should be analyzed with. Available models are:\n \"LQ\"", + "LQ", "LQ", 'm'); addOption >(OPTION_MODEL_PARAMETERS, OPTION_GROUP_REQUIRED, "The parameters for the radiobiological model.", 'p', true, true); addOptionWithDefaultValue(OPTION_DOSE_SCALING, OPTION_GROUP_REQUIRED, "Dose scaling that should be applied.", 1.0, "1.0", 'c'); std::vector defaultLoadingStyle; defaultLoadingStyle.push_back("itk"); addOptionWithDefaultValue >(OPTION_LOAD_STYLE, OPTION_GROUP_REQUIRED, "The loading style for the dose. Available styles are:\n" "\"dicom\": normal dicom dose\n" "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle virtuos myFavorite.pln\")\n" "\"itk\": use itk image loading\n\"helax\": load a helax dose (choosing this style, the dose path should only be a directory).", defaultLoadingStyle, defaultLoadingStyle.at(0), 's', true, true); parse(argc, argv); } void BioModelCmdLineParser::validateInput() const { std::string model = get(OPTION_MODEL); if (model != "LQ") { throw cmdlineparsing::InvalidConstraintException("Unknown model: " + model + ".\nPlease refer to the help for valid models."); } else { if (get >(OPTION_MODEL_PARAMETERS).size() != 2) { throw cmdlineparsing::InvalidConstraintException("The LQ Model requires two parameters!"); } } std::vector loadStyle = get >(OPTION_LOAD_STYLE); std::string loadStyleAbbreviation = loadStyle.at(0); - if (loadStyleAbbreviation != "dicom" && loadStyleAbbreviation != "virtuos" && loadStyleAbbreviation != "itk" + if (loadStyleAbbreviation != "dicom" && loadStyleAbbreviation != "virtuos" + && loadStyleAbbreviation != "itk" && loadStyleAbbreviation != "helax") { throw cmdlineparsing::InvalidConstraintException("Unknown load style:" + loadStyleAbbreviation + ".\nPlease refer to the help for valid loading style settings."); } else if (loadStyleAbbreviation == "virtuos") { if (loadStyle.size() < 2) { throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io style argument."); } } double doseScaling = get(OPTION_DOSE_SCALING); if (doseScaling <= 0) { throw cmdlineparsing::InvalidConstraintException("Negative dose scaling is invalid. Dose scaling has to be >0."); } } void BioModelCmdLineParser::printHelp() const { cmdlineparsing::CmdLineParserBase::printHelp(); std::cout << "Example:" << std::endl << std::endl; std::cout << m_programName << " dose.mhd result.mhd -s itk -m LQ -p 0.2 0.02" << std::endl << std::endl; std::cout << "This will calculate the Linear quadratic (LQ) BioModel from \"dose.mhd\" and will write the result to \"result.mhd\". " "The alpha and beta parameters for the LQ model are 0.2 and 0.02, respectively." << std::endl; } } } } diff --git a/demoapps/BioModelCalc/BioModelCmdLineParser.h b/demoapps/BioModelCalc/BioModelCmdLineParser.h index 68e21f6..ad27d84 100644 --- a/demoapps/BioModelCalc/BioModelCmdLineParser.h +++ b/demoapps/BioModelCalc/BioModelCmdLineParser.h @@ -1,39 +1,40 @@ #ifndef __BIO_MODEL_CMD_LINE_PARSER #define __BIO_MODEL_CMD_LINE_PARSER #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace bioModelCalc { /*! @class BioModelCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class BioModelCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: - BioModelCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version); + BioModelCmdLineParser(int argc, const char** argv, const std::string& name, + const std::string& version); void validateInput() const; void printHelp() const; // Option groups const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; // Parameters const std::string OPTION_DOSE_FILE = "dose"; const std::string OPTION_OUTPUT_FILE = "outputFile"; const std::string OPTION_MODEL = "model"; const std::string OPTION_MODEL_PARAMETERS = "modelParameters"; const std::string OPTION_LOAD_STYLE = "loadStyle"; const std::string OPTION_DOSE_SCALING = "doseScaling"; }; } } } #endif \ No newline at end of file diff --git a/demoapps/DoseAcc/DoseAccHelper.h b/demoapps/DoseAcc/DoseAccHelper.h index cf51430..75e83b5 100644 --- a/demoapps/DoseAcc/DoseAccHelper.h +++ b/demoapps/DoseAcc/DoseAccHelper.h @@ -1,58 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACC_HELPER_H #define __DOSE_ACC_HELPER_H #include "DoseAccApplicationData.h" namespace rttb { - namespace apps - { - namespace doseAcc - { - /**loads the dose from a file. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, - const rttb::apps::doseAcc::ApplicationData::LoadingStyleArgType& args); - - /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); - /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); - /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); - /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, - const std::string& planFileName); - - ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); - - /**Containes the business logic for the accumulation of the doses and the storing of the result. - Uses appData for the input data and the correct configuration.*/ - void processData(ApplicationData& appData); - - } - } + namespace apps + { + namespace doseAcc + { + /**loads the dose from a file. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, + const rttb::apps::doseAcc::ApplicationData::LoadingStyleArgType& args); + + /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); + /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); + /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); + /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, + const std::string& planFileName); + + ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); + + /**Containes the business logic for the accumulation of the doses and the storing of the result. + Uses appData for the input data and the correct configuration.*/ + void processData(ApplicationData& appData); + + } + } } #endif diff --git a/demoapps/DoseMap/DoseMap.cpp b/demoapps/DoseMap/DoseMap.cpp index a770ff1..ec0218b 100644 --- a/demoapps/DoseMap/DoseMap.cpp +++ b/demoapps/DoseMap/DoseMap.cpp @@ -1,201 +1,201 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "DoseMapApplicationData.h" #include "DoseMapHelper.h" #include "mapDummyRegistrationAlgorithm.h" rttb::apps::doseMap::ApplicationData appData; /** Main function of dose mapper. @retval 0 normal program execution @retval 1 showed help or version (flag was set). @retval 2 not enough required input files. @retval 3 Argument parsing error @retval 4 Error loading input dose file @retval 5 Error loading reference dose file @retval 6 Error loading registration @retval 9 Error while mapping or storing result. */ int main(int argc, char** argv) { - int result = 0; - - std::cout << "DoseMap - RTTB demo app for simple dose mapping." << std::endl; - - switch (rttb::apps::doseMap::ParseArgumentsForAppData(argc, argv, appData)) - { - case 1: - { - //showed version or help info. Done. - return 1; - } - - case 2: - { - std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; - std::cerr << "-? or --help" << std::endl; - return 2; - } - - case 3: - { - //wrong option usage. - return 3; - } - } - - if (appData._fileCount < 2) - { - std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; - std::cerr << "-? or --help" << std::endl; - return 1; - } - - std::cout << std::endl << "*******************************************" << std::endl; - std::cout << "Input dose file: " << appData._inputDoseFileName << std::endl; - - if (!(appData._regFileName.empty())) - { - std::cout << "Registration file: " << appData._regFileName << std::endl; - } - - if (!(appData._refDoseFileName.empty())) - { - std::cout << "Reference dose file: " << appData._refDoseFileName << std::endl; - } - - try - { - appData._inputDose = rttb::apps::doseMap::loadDose(appData._inputDoseFileName, - appData._inputDoseLoadStyle); - } - catch (::itk::ExceptionObject& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e << std::endl; - return 4; - } - catch (std::exception& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e.what() << std::endl; - return 4; - } - catch (...) - { - std::cerr << "Error!!! unknown error while reading input image." << std::endl; - return 4; - } - - if (!(appData._refDoseFileName.empty())) - { - try - { - appData._refDose = rttb::apps::doseMap::loadDose(appData._refDoseFileName, - appData._refDoseLoadStyle); - } - catch (::itk::ExceptionObject& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e << std::endl; - return 5; - } - catch (std::exception& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e.what() << std::endl; - return 5; - } - catch (...) - { - std::cerr << "Error!!! unknown error while reading reference image." << std::endl; - return 5; - } - } - else - { - appData._refDose = appData._inputDose; - } - - if (!(appData._regFileName.empty())) - { - try - { - appData._spReg = rttb::apps::doseMap::loadRegistration(appData._regFileName); - } - catch (::itk::ExceptionObject& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e << std::endl; - return 6; - } - catch (std::exception& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e.what() << std::endl; - return 6; - } - catch (...) - { - std::cerr << "Error!!! unknown error while reading registration file." << std::endl; - return 6; - } - } - else - { - //generate dummy identity registration - typedef map::algorithm::DummyRegistrationAlgorithm<3> DummyRegType; - DummyRegType::Pointer regAlg = DummyRegType::New(); - - appData._spReg = regAlg->getRegistration(); - } - - try - { - rttb::apps::doseMap::processData(appData); - } - catch (::itk::ExceptionObject& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e << std::endl; - return 9; - } - catch (std::exception& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e.what() << std::endl; - return 9; - } - catch (...) - { - std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; - return 9; - } - - std::cout << std::endl; - - return result; + int result = 0; + + std::cout << "DoseMap - RTTB demo app for simple dose mapping." << std::endl; + + switch (rttb::apps::doseMap::ParseArgumentsForAppData(argc, argv, appData)) + { + case 1: + { + //showed version or help info. Done. + return 1; + } + + case 2: + { + std::cerr << "Missing Parameters. Use one of the following flags for more information:" << + std::endl; + std::cerr << "-? or --help" << std::endl; + return 2; + } + + case 3: + { + //wrong option usage. + return 3; + } + } + + if (appData._fileCount < 2) + { + std::cerr << "Missing Parameters. Use one of the following flags for more information:" << + std::endl; + std::cerr << "-? or --help" << std::endl; + return 1; + } + + std::cout << std::endl << "*******************************************" << std::endl; + std::cout << "Input dose file: " << appData._inputDoseFileName << std::endl; + + if (!(appData._regFileName.empty())) + { + std::cout << "Registration file: " << appData._regFileName << std::endl; + } + + if (!(appData._refDoseFileName.empty())) + { + std::cout << "Reference dose file: " << appData._refDoseFileName << std::endl; + } + + try + { + appData._inputDose = rttb::apps::doseMap::loadDose(appData._inputDoseFileName, + appData._inputDoseLoadStyle); + } + catch (::itk::ExceptionObject& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e << std::endl; + return 4; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 4; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading input image." << std::endl; + return 4; + } + + if (!(appData._refDoseFileName.empty())) + { + try + { + appData._refDose = rttb::apps::doseMap::loadDose(appData._refDoseFileName, + appData._refDoseLoadStyle); + } + catch (::itk::ExceptionObject& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e << std::endl; + return 5; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 5; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading reference image." << std::endl; + return 5; + } + } + else + { + appData._refDose = appData._inputDose; + } + + if (!(appData._regFileName.empty())) + { + try + { + appData._spReg = rttb::apps::doseMap::loadRegistration(appData._regFileName); + } + catch (::itk::ExceptionObject& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e << std::endl; + return 6; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 6; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading registration file." << std::endl; + return 6; + } + } + else + { + //generate dummy identity registration + typedef map::algorithm::DummyRegistrationAlgorithm<3> DummyRegType; + DummyRegType::Pointer regAlg = DummyRegType::New(); + + appData._spReg = regAlg->getRegistration(); + } + + try + { + rttb::apps::doseMap::processData(appData); + } + catch (::itk::ExceptionObject& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e << std::endl; + return 9; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 9; + } + catch (...) + { + std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; + return 9; + } + + std::cout << std::endl; + + return result; } diff --git a/demoapps/DoseMap/DoseMapApplicationData.h b/demoapps/DoseMap/DoseMapApplicationData.h index 53a6dec..20116be 100644 --- a/demoapps/DoseMap/DoseMapApplicationData.h +++ b/demoapps/DoseMap/DoseMapApplicationData.h @@ -1,87 +1,87 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_MAP_APPLICATION_DATA_H #define __DOSE_MAP_APPLICATION_DATA_H #include "mapRegistration.h" #include "rttbBaseType.h" #include "rttbDoseAccessorInterface.h" namespace rttb { - namespace apps - { - namespace doseMap - { + namespace apps + { + namespace doseMap + { - class ApplicationData - { - public: - typedef map::core::Registration<3, 3> RegistrationType; + class ApplicationData + { + public: + typedef map::core::Registration<3, 3> RegistrationType; - /**Vector of arguments used to specify the loading style (always the first argument) - * and, if needed, additional arguments for the specified loading style (e.g. location of the - * Virtuos plan file for the Virtuos IO style). - */ - typedef std::vector LoadingStyleArgType; - /** Loaded Dose.*/ - core::DoseAccessorInterface::DoseAccessorPointer _inputDose; - std::string _inputDoseFileName; - LoadingStyleArgType _inputDoseLoadStyle; - core::DoseAccessorInterface::DoseAccessorPointer _refDose; - std::string _refDoseFileName; - LoadingStyleArgType _refDoseLoadStyle; - RegistrationType::Pointer _spReg; - std::string _regFileName; + /**Vector of arguments used to specify the loading style (always the first argument) + * and, if needed, additional arguments for the specified loading style (e.g. location of the + * Virtuos plan file for the Virtuos IO style). + */ + typedef std::vector LoadingStyleArgType; + /** Loaded Dose.*/ + core::DoseAccessorInterface::DoseAccessorPointer _inputDose; + std::string _inputDoseFileName; + LoadingStyleArgType _inputDoseLoadStyle; + core::DoseAccessorInterface::DoseAccessorPointer _refDose; + std::string _refDoseFileName; + LoadingStyleArgType _refDoseLoadStyle; + RegistrationType::Pointer _spReg; + std::string _regFileName; - std::string _outputFileName; + std::string _outputFileName; - std::string _interpolatorName; + std::string _interpolatorName; - bool _showVersion; - bool _showHelp; + bool _showVersion; + bool _showHelp; - int _fileCount; + int _fileCount; - void Reset(); + void Reset(); - ApplicationData(); - }; + ApplicationData(); + }; - /** Parse the application argument passed when starting the application. - * If no error or special request occurred the return is 0. Otherwise the return values - * have the following meaning: \n - * 0: Normal parsing.\n - * 1: showed help or version (flag was set).\n - * 2: not enough required input files.\n - * 3: Parsing error.\n - * @param argc Number of parameter arguments - * @param argv Pointer to the passed arguments - * @return Result code of the parsing (see above).**/ - unsigned int ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData); + /** Parse the application argument passed when starting the application. + * If no error or special request occurred the return is 0. Otherwise the return values + * have the following meaning: \n + * 0: Normal parsing.\n + * 1: showed help or version (flag was set).\n + * 2: not enough required input files.\n + * 3: Parsing error.\n + * @param argc Number of parameter arguments + * @param argv Pointer to the passed arguments + * @return Result code of the parsing (see above).**/ + unsigned int ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData); - } - } + } + } } #endif diff --git a/demoapps/DoseMap/DoseMapHelper.h b/demoapps/DoseMap/DoseMapHelper.h index 7b1c73a..9ba6942 100644 --- a/demoapps/DoseMap/DoseMapHelper.h +++ b/demoapps/DoseMap/DoseMapHelper.h @@ -1,58 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_MAP_HELPER_H #define __DOSE_MAP_HELPER_H #include "DoseMapApplicationData.h" namespace rttb { - namespace apps - { - namespace doseMap - { - /**loads the dose from a file. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, - const rttb::apps::doseMap::ApplicationData::LoadingStyleArgType& args); - - /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); - /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); - /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); - /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, - const std::string& planFileName); - - ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); - - /**Containes the business logic for the accumulation of the doses and the storing of the result. - Uses appData for the input data and the correct configuration.*/ - void processData(ApplicationData& appData); - - } - } + namespace apps + { + namespace doseMap + { + /**loads the dose from a file. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, + const rttb::apps::doseMap::ApplicationData::LoadingStyleArgType& args); + + /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); + /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); + /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); + /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, + const std::string& planFileName); + + ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); + + /**Containes the business logic for the accumulation of the doses and the storing of the result. + Uses appData for the input data and the correct configuration.*/ + void processData(ApplicationData& appData); + + } + } } #endif diff --git a/demoapps/DoseTool/DoseTool.cpp b/demoapps/DoseTool/DoseTool.cpp index 69bf3d3..fe2131a 100644 --- a/demoapps/DoseTool/DoseTool.cpp +++ b/demoapps/DoseTool/DoseTool.cpp @@ -1,158 +1,160 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1066 $ (last changed revision) -// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "DoseToolApplicationData.h" #include "DoseToolHelper.h" #include "DoseToolCmdLineParser.h" #include "boost/shared_ptr.hpp" #include "boost/make_shared.hpp" #include "RTToolboxConfigure.h" #include "rttbException.h" rttb::apps::doseTool::ApplicationData appData; int main(int argc, const char** argv) { int result = 0; boost::shared_ptr argParser; try { std::string appName = "DoseTool"; std::string appVersion = RTTB_FULL_VERSION_STRING; - argParser = boost::make_shared(argc, argv, appName, appVersion); + argParser = boost::make_shared(argc, argv, appName, + appVersion); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return 5; } // This is vital. The application needs to exit if the "help" or "version" parameter is set // because this means the other parameters won't be parsed. if (argParser->isSet(argParser->OPTION_HELP) || argParser->isSet(argParser->OPTION_VERSION)) { return 0; } rttb::apps::doseTool::populateAppData(argParser, appData); std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose file: " << appData._doseFileName << std::endl; std::cout << "Struct file: " << appData._structFileName << std::endl; std::cout << "Struct name: " << appData._structNameRegex << std::endl; if (appData._computeDoseStatistics) { std::cout << "Dose statistic output file: " << appData._doseStatisticOutputFileName << std::endl; std::cout << "Compute complex statistics: " << appData._computeComplexDoseStatistics << std::endl; if (appData._computeComplexDoseStatistics) { std::cout << "Prescribed dose: " << appData._prescribedDose << std::endl; } std::cout << "Allow self intersections: " << appData._allowSelfIntersection << std::endl; } if (appData._computeDVH) { std::cout << "DVH output file: " << appData._dvhOutputFilename << std::endl; } try { appData._dose = rttb::apps::doseTool::loadDose(appData._doseFileName, appData._doseLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 1; } catch (...) { std::cerr << "Error!!! unknown error while reading dose image." << std::endl; return 1; } //loading of structure file not necessary in ITK case as it can be used directly as mask input. if (appData._structLoadStyle.front() != "itk") { try { - appData._struct = rttb::apps::doseTool::loadStruct(appData._structFileName, appData._structLoadStyle); + appData._struct = rttb::apps::doseTool::loadStruct(appData._structFileName, + appData._structLoadStyle); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while reading struct image." << std::endl; return 2; } } try { rttb::apps::doseTool::processData(appData); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (...) { std::cerr << "Error!!! unknown error while processing the data or writing the image." << std::endl; return 3; } return result; } diff --git a/demoapps/DoseTool/DoseToolApplicationData.cpp b/demoapps/DoseTool/DoseToolApplicationData.cpp index ffd75e9..4e6b40f 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.cpp +++ b/demoapps/DoseTool/DoseToolApplicationData.cpp @@ -1,87 +1,91 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1066 $ (last changed revision) -// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "DoseToolApplicationData.h" namespace rttb { namespace apps { namespace doseTool { ApplicationData:: ApplicationData() { this->reset(); } void ApplicationData:: reset() { _doseFileName = ""; _structFileName = ""; _structNameRegex = ""; _doseStatisticOutputFileName = ""; _computeComplexDoseStatistics = false; _allowSelfIntersection = false; _structIndices.clear(); _structNames.clear(); _prescribedDose = 1.0; _multipleStructsMode = false; _computeDVH = false; _computeDoseStatistics = false; } void populateAppData(boost::shared_ptr argParser, ApplicationData& appData) { appData._doseFileName = argParser->get(argParser->OPTION_DOSE_FILE); - appData._doseLoadStyle = argParser->get >(argParser->OPTION_DOSE_LOAD_STYLE); + appData._doseLoadStyle = argParser->get > + (argParser->OPTION_DOSE_LOAD_STYLE); appData._structFileName = argParser->get(argParser->OPTION_STRUCT_FILE); - appData._structLoadStyle = argParser->get >(argParser->OPTION_STRUCT_LOAD_STYLE); + appData._structLoadStyle = argParser->get > + (argParser->OPTION_STRUCT_LOAD_STYLE); appData._structNameRegex = argParser->get(argParser->OPTION_STRUCT_NAME); appData._multipleStructsMode = argParser->isSet(argParser->OPTION_MULTIPLE_STRUCTS_MODE); if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS)) { appData._computeDoseStatistics = true; - appData._doseStatisticOutputFileName = argParser->get(argParser->OPTION_DOSE_STATISTICS); - appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); - appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); - + appData._doseStatisticOutputFileName = argParser->get + (argParser->OPTION_DOSE_STATISTICS); + appData._computeComplexDoseStatistics = argParser->isSet(argParser->OPTION_COMPLEX_STATISTICS); + appData._allowSelfIntersection = argParser->isSet(argParser->OPTION_ALLOW_SELF_INTERSECTION_STRUCT); + } if (argParser->isSet(argParser->OPTION_DVH)) { appData._computeDVH = true; appData._dvhOutputFilename = argParser->get(argParser->OPTION_DVH); } - if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS) && argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) + if (argParser->isSet(argParser->OPTION_DOSE_STATISTICS) + && argParser->isSet(argParser->OPTION_PRESCRIBED_DOSE)) { appData._prescribedDose = argParser->get(argParser->OPTION_PRESCRIBED_DOSE); } } } } } diff --git a/demoapps/DoseTool/DoseToolApplicationData.h b/demoapps/DoseTool/DoseToolApplicationData.h index bc79970..6e44258 100644 --- a/demoapps/DoseTool/DoseToolApplicationData.h +++ b/demoapps/DoseTool/DoseToolApplicationData.h @@ -1,79 +1,79 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1070 $ (last changed revision) -// @date $Date: 2015-08-19 14:50:28 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __DOSETOOL_APPLICATION_DATA_H #define __DOSETOOL_APPLICATION_DATA_H #include #include "rttbDoseAccessorInterface.h" #include "rttbStructureSetGeneratorInterface.h" #include "DoseToolCmdLineParser.h" namespace rttb { namespace apps { namespace doseTool { /*! @class ApplicationData @brief Class for storing all relevant variables needed in DoseTool */ class ApplicationData { public: /**Vector of arguments used to specify the loading style (always the first argument) * and, if needed, additional arguments for the specified loading style (e.g. location of the * Virtuos plan file for the Virtuos IO style). */ typedef std::vector LoadingStyleArgType; core::DoseAccessorInterface::DoseAccessorPointer _dose; core::StructureSetGeneratorInterface::StructureSetPointer _struct; std::string _structNameRegex; std::vector _structIndices; std::vector _structNames; std::string _doseFileName; std::string _structFileName; LoadingStyleArgType _doseLoadStyle; LoadingStyleArgType _structLoadStyle; bool _computeComplexDoseStatistics; DoseTypeGy _prescribedDose; std::string _doseStatisticOutputFileName; bool _allowSelfIntersection; bool _multipleStructsMode; bool _computeDVH; bool _computeDoseStatistics; std::string _dvhOutputFilename; /*! @brief Resets the variables. _prescribedDose is set to 1.0 because it produces no exception then (as it is not needed). Consistency checks are done in DoseToolCmdLineParser::validateInput() */ void reset(); ApplicationData(); }; /*! @brief Reads the necessary arguments from the DoseToolCmdLineParser and writes them in the respective variables of ApplicationData. */ void populateAppData(boost::shared_ptr argParser, ApplicationData& appData); } } } #endif diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.cpp b/demoapps/DoseTool/DoseToolCmdLineParser.cpp index a13d78f..291301e 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.cpp +++ b/demoapps/DoseTool/DoseToolCmdLineParser.cpp @@ -1,177 +1,184 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1066 $ (last changed revision) -// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "DoseToolCmdLineParser.h" namespace rttb { namespace apps { namespace doseTool { DoseToolCmdLineParser::DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version) : CmdLineParserBase(name, version) { typedef double DoseTypeGy; addOption(OPTION_DOSE_FILE, OPTION_GROUP_REQUIRED, "The name of the dose file. Can be omitted if used as " "positional argument (see above).", 'd', true); addOption(OPTION_STRUCT_FILE, OPTION_GROUP_REQUIRED, "The name of the struct file. Can be omitted if used as " "positional argument (see above).", 's', true); addOptionWithDefaultValue(OPTION_STRUCT_NAME, OPTION_GROUP_REQUIRED, "The name of the struct as regular expression. Can be omitted if used as " "positional argument or with itk struct loadingStyle (see above).", "", "", 'n', true); addPositionalOption(OPTION_DOSE_FILE, 1); addPositionalOption(OPTION_STRUCT_FILE, 1); addPositionalOption(OPTION_STRUCT_NAME, 1); addPositionalOption(OPTION_DOSE_STATISTICS, 1); std::vector defaultLoadingStyle; defaultLoadingStyle.push_back("dicom"); addOptionWithDefaultValue >(OPTION_DOSE_LOAD_STYLE, OPTION_GROUP_REQUIRED, "The loading style for the dose. Available styles are:\n" "\"dicom\": normal dicom dose\n" "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--" + OPTION_DOSE_LOAD_STYLE + " virtuos myFavorite.pln\")\n" "\"itk\": use itk image loading\n\"helax\": load a helax dose (choosing this style, the dose path should only be a directory).", defaultLoadingStyle, defaultLoadingStyle.at(0), 't', true, true); - addOptionWithDefaultValue >(OPTION_STRUCT_LOAD_STYLE, OPTION_GROUP_REQUIRED, + addOptionWithDefaultValue >(OPTION_STRUCT_LOAD_STYLE, + OPTION_GROUP_REQUIRED, "The loading style for the dose. Available styles are:\n" "\"dicom\": normal dicom dose\n" "\"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--" + OPTION_DOSE_LOAD_STYLE + " virtuos myFavorite.pln\")\n" "\"itk\": use itk image loading.", defaultLoadingStyle, defaultLoadingStyle.at(0), 'u', true, true); addOption(OPTION_DOSE_STATISTICS, OPTION_GROUP_OPTIONAL, "If dose statistics should be computed. The argument is the output file. Can be omitted if used as " "positional argument (see above).", 'y'); addOption(OPTION_DVH, OPTION_GROUP_OPTIONAL, "If the DVH should be computed. The argument is the output file", 'z'); addOption(OPTION_COMPLEX_STATISTICS, OPTION_GROUP_OPTIONAL, "If the complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) should be computed.", 'x'); addOption(OPTION_PRESCRIBED_DOSE, OPTION_GROUP_OPTIONAL, "The prescribed dose in Gy.", 'p'); addOption(OPTION_ALLOW_SELF_INTERSECTION_STRUCT, OPTION_GROUP_OPTIONAL, "If a struct file contains self intersecting contours: Allow the processing of these structures and ignore potential problems." "WARNING: only use this parameter if you know what you are doing.", 'a'); addOption(OPTION_MULTIPLE_STRUCTS_MODE, OPTION_GROUP_OPTIONAL, "If the regex agrees with multiple structs: write a dose statistic for every struct file." "The struct name will be appended to the chosen output filename.", 'm'); parse(argc, argv); } void DoseToolCmdLineParser::validateInput() const { std::vector doseLoadStyle = get >(OPTION_DOSE_LOAD_STYLE); std::string doseLoadStyleAbbreviation = doseLoadStyle.at(0); - if (doseLoadStyleAbbreviation != "dicom" && doseLoadStyleAbbreviation != "virtuos" && doseLoadStyleAbbreviation != "itk" + if (doseLoadStyleAbbreviation != "dicom" && doseLoadStyleAbbreviation != "virtuos" + && doseLoadStyleAbbreviation != "itk" && doseLoadStyleAbbreviation != "helax") { - throw cmdlineparsing::InvalidConstraintException("Unknown load style for dose file:" + doseLoadStyleAbbreviation + + throw cmdlineparsing::InvalidConstraintException("Unknown load style for dose file:" + + doseLoadStyleAbbreviation + ".\nPlease refer to the help for valid loading style settings."); } if (doseLoadStyleAbbreviation == "virtuos") { if (doseLoadStyle.size() < 2) { throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io style argument."); } } std::vector structLoadStyle = get >(OPTION_STRUCT_LOAD_STYLE); std::string structLoadStyleAbbreviation = structLoadStyle.at(0); if (structLoadStyleAbbreviation != "dicom" && structLoadStyleAbbreviation != "virtuos" && structLoadStyleAbbreviation != "itk") { - throw cmdlineparsing::InvalidConstraintException("Unknown load style for struct file:" + structLoadStyleAbbreviation + + throw cmdlineparsing::InvalidConstraintException("Unknown load style for struct file:" + + structLoadStyleAbbreviation + ".\nPlease refer to the help for valid loading style settings."); } if (structLoadStyleAbbreviation == "dicom" || structLoadStyleAbbreviation == "virtuos" || structLoadStyleAbbreviation == "helax") { if (get(OPTION_STRUCT_NAME) == "") { throw cmdlineparsing::InvalidConstraintException("The struct name (--" + OPTION_STRUCT_NAME + ") has to be defined for dicom, virtuos or helax struct files."); } } if (structLoadStyleAbbreviation == "virtuos") { if (structLoadStyle.size() < 2) { throw cmdlineparsing::InvalidConstraintException("Cannot load virtuos struct file. CTX file is missing. Specify CTX file as 2nd io style argument."); } } if (!isSet(OPTION_DVH) && !isSet(OPTION_DOSE_STATISTICS)) { - throw cmdlineparsing::InvalidConstraintException("Neither the Dose statistics (--" + OPTION_DOSE_STATISTICS + + throw cmdlineparsing::InvalidConstraintException("Neither the Dose statistics (--" + + OPTION_DOSE_STATISTICS + "), nor the DVH (--" + OPTION_DVH + ") option was used."); } if (isSet(OPTION_DOSE_STATISTICS) && isSet(OPTION_COMPLEX_STATISTICS)) { if (!isSet(OPTION_PRESCRIBED_DOSE)) { - throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + ") has to be set for computation of complex dose statistics."); } else { if (get(OPTION_PRESCRIBED_DOSE) <= 0) { - throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + throw cmdlineparsing::InvalidConstraintException("The prescribed dose (--" + OPTION_PRESCRIBED_DOSE + + ") has to be >0!"); } } } } void DoseToolCmdLineParser::printHelp() const { cmdlineparsing::CmdLineParserBase::printHelp(); std::cout << "Example:" << std::endl << std::endl; std::cout << m_programName << " dose.dcm struct.dcm Liver result.xml --" + OPTION_DVH + " dvh.xml" << std::endl << std::endl; std::cout << "This will calculate the Dose statistic for liver using \"dose.dcm\" and the struct file \"struct.dcm\" and will write the dose statistics to \"result.xml\". " " The DVH is computed as well, its values are written to \"dvh.xml\". " << std::endl; } } } } diff --git a/demoapps/DoseTool/DoseToolCmdLineParser.h b/demoapps/DoseTool/DoseToolCmdLineParser.h index b7e86d9..b6804b6 100644 --- a/demoapps/DoseTool/DoseToolCmdLineParser.h +++ b/demoapps/DoseTool/DoseToolCmdLineParser.h @@ -1,65 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1066 $ (last changed revision) -// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __DOSETOOL_CMD_LINE_PARSER #define __DOSETOOL_CMD_LINE_PARSER #include "CmdLineParserBase.h" namespace rttb { namespace apps { namespace doseTool { /*! @class BioModelCmdLineParser @brief Argument parsing is parametrized here based on ArgParserLib @see cmdlineparsing::CmdLineParserBase */ class DoseToolCmdLineParser : public cmdlineparsing::CmdLineParserBase { public: - DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, const std::string& version); + DoseToolCmdLineParser(int argc, const char** argv, const std::string& name, + const std::string& version); void validateInput() const; void printHelp() const; // Option groups const std::string OPTION_GROUP_REQUIRED = "Required Arguments"; const std::string OPTION_GROUP_OPTIONAL = "Optional Arguments"; // Parameters const std::string OPTION_DOSE_FILE = "doseFile"; const std::string OPTION_STRUCT_FILE = "structFile"; const std::string OPTION_STRUCT_NAME = "structName"; const std::string OPTION_DOSE_STATISTICS = "doseStatistics"; const std::string OPTION_DVH = "DVH"; const std::string OPTION_DOSE_LOAD_STYLE = "doseLoadStyle"; const std::string OPTION_STRUCT_LOAD_STYLE = "structLoadStyle"; const std::string OPTION_COMPLEX_STATISTICS = "complexStatistics"; const std::string OPTION_PRESCRIBED_DOSE = "prescribedDose"; const std::string OPTION_ALLOW_SELF_INTERSECTION_STRUCT = "allowSelfIntersection"; const std::string OPTION_MULTIPLE_STRUCTS_MODE = "multipleStructsMode"; }; } } } #endif \ No newline at end of file diff --git a/demoapps/DoseTool/DoseToolHelper.cpp b/demoapps/DoseTool/DoseToolHelper.cpp index 66f5dc6..067e720 100644 --- a/demoapps/DoseTool/DoseToolHelper.cpp +++ b/demoapps/DoseTool/DoseToolHelper.cpp @@ -1,347 +1,363 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1095 $ (last changed revision) -// @date $Date: 2015-09-11 11:12:40 +0200 (Fr, 11 Sep 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "DoseToolHelper.h" #include "boost/make_shared.hpp" #include "boost/shared_ptr.hpp" #include "boost/property_tree/ptree.hpp" #include "boost/filesystem.hpp" #include "rttbExceptionMacros.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbStructureSetGeneratorInterface.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbDVHCalculator.h" #include "rttbDVHXMLFileWriter.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbVOIindexIdentifier.h" rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args) { rttb::core::DoseAccessorInterface::DoseAccessorPointer result; std::cout << std::endl << "read dose file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomDose(fileName); } else if (args[0] == "helax") { std::cout << "use RTTB Helax IO... "; result = loadHelaxDose(fileName); } else if (args[0] == "itk") { std::cout << "use RTTB itk IO... "; result = loadITKDose(fileName); } else if (args[0] == "virtuos") { if (args.size() < 2) { rttbDefaultExceptionStaticMacro( << "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); } std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos plan file: " << args[1] << " ... "; result = loadVirtuosDose(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadDicomDose(const std::string& fileName) { rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadHelaxDose(const std::string& path) { rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadITKDose(const std::string& fileName) { rttb::io::itk::ITKImageFileAccessorGenerator generator(fileName); return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseTool::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) { rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); return generator.generateDoseAccessor(); }; rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadStruct( const std::string& fileName, const ApplicationData::LoadingStyleArgType& args) { rttb::core::StructureSetGeneratorInterface::StructureSetPointer result; std::cout << std::endl << "read struct file... "; if (args.empty() || args[0] == "dicom") { std::cout << "use RTTB dicom IO... "; result = loadDicomStruct(fileName); } else if (args[0] == "virtuos") { std::cout << "use RTTB virtuos IO... " << std::endl; std::cout << " virtuos CTX file: " << args[1] << " ... "; result = loadVirtuosStruct(fileName, args[1]); } else { rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " << args[0]); } std::cout << "done." << std::endl; return result; } -rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadDicomStruct( +rttb::core::StructureSetGeneratorInterface::StructureSetPointer +rttb::apps::doseTool::loadDicomStruct( const std::string& fileName) { rttb::io::dicom::DicomFileStructureSetGenerator generator(fileName); return generator.generateStructureSet(); } -rttb::core::StructureSetGeneratorInterface::StructureSetPointer rttb::apps::doseTool::loadVirtuosStruct( +rttb::core::StructureSetGeneratorInterface::StructureSetPointer +rttb::apps::doseTool::loadVirtuosStruct( const std::string& fileName, const std::string& ctxFileName) { rttb::io::virtuos::VirtuosFileStructureSetGenerator generator(fileName, ctxFileName.c_str()); return generator.generateStructureSet(); } void rttb::apps::doseTool::processData(rttb::apps::doseTool::ApplicationData& appData) { std::cout << std::endl << "generating masks... "; - std::vector maskAccessorPtrVector = generateMasks(appData); + std::vector maskAccessorPtrVector = generateMasks( + appData); std::cout << "done." << std::endl; for (int i = 0; i < maskAccessorPtrVector.size(); i++) { - core::DoseIteratorInterface::DoseIteratorPointer spDoseIterator(generateMaskedDoseIterator(maskAccessorPtrVector.at(i), - appData._dose)); + 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); + 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)); + 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... "; - core::DVH::DVHPointer dvh = calculateDVH(spDoseIterator, appData._struct->getUID(), appData._dose->getUID()); + core::DVH::DVHPointer dvh = calculateDVH(spDoseIterator, appData._struct->getUID(), + appData._dose->getUID()); std::cout << "done." << std::endl; std::cout << std::endl << "writing DVH to file... "; std::string outputFilename; if (appData._multipleStructsMode) { outputFilename = assembleFilenameWithStruct(appData._dvhOutputFilename, appData._structNames.at(i)); } else { outputFilename = appData._dvhOutputFilename; } writeDVHFile(dvh, outputFilename); std::cout << "done." << std::endl; } } } -std::vector rttb::apps::doseTool::generateMasks( +std::vector +rttb::apps::doseTool::generateMasks( rttb::apps::doseTool::ApplicationData& appData) { std::vector maskAccessorPtrVector; if (appData._structLoadStyle.front() == "itk") { maskAccessorPtrVector.push_back(rttb::io::itk::ITKImageFileMaskAccessorGenerator( appData._structFileName).generateMaskAccessor()); } else { - std::vector foundIndices = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex(appData._struct, - appData._structNameRegex); + std::vector foundIndices = rttb::masks::VOIindexIdentifier::getIndicesByVoiRegex( + appData._struct, + appData._structNameRegex); std::vector relevantIndices; if (appData._multipleStructsMode) { relevantIndices = foundIndices; } else { if (!foundIndices.empty()) { relevantIndices.push_back(foundIndices.front()); } } appData._structIndices = relevantIndices; bool strict = !appData._allowSelfIntersection; for (int i = 0; i < appData._structIndices.size(); i++) { maskAccessorPtrVector.push_back( boost::make_shared - (appData._struct->getStructure(appData._structIndices.at(i)), appData._dose->getGeometricInfo(), strict)); + (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()); + appData._structNames.push_back(appData._struct->getStructure(appData._structIndices.at( + i))->getLabel()); } } return maskAccessorPtrVector; } -rttb::core::DoseIteratorInterface::DoseIteratorPointer rttb::apps::doseTool::generateMaskedDoseIterator( +rttb::core::DoseIteratorInterface::DoseIteratorPointer +rttb::apps::doseTool::generateMaskedDoseIterator( rttb::core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, rttb::core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr) { boost::shared_ptr maskedDoseIterator = boost::make_shared(maskAccessorPtr, doseAccessorPtr); rttb::core::DoseIteratorInterface::DoseIteratorPointer doseIterator(maskedDoseIterator); return doseIterator; } -rttb::algorithms::DoseStatistics::DoseStatisticsPointer rttb::apps::doseTool::calculateDoseStatistics( +rttb::algorithms::DoseStatistics::DoseStatisticsPointer +rttb::apps::doseTool::calculateDoseStatistics( core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, DoseTypeGy prescribedDose) { rttb::algorithms::DoseStatisticsCalculator doseStatsCalculator(doseIterator); if (calculateComplexDoseStatistics) { return doseStatsCalculator.calculateDoseStatistics(prescribedDose); } else { return doseStatsCalculator.calculateDoseStatistics(); } } -rttb::core::DVH::DVHPointer rttb::apps::doseTool::calculateDVH(core::DoseIteratorInterface::DoseIteratorPointer - doseIterator, IDType structUID, IDType doseUID) +rttb::core::DVH::DVHPointer rttb::apps::doseTool::calculateDVH( + core::DoseIteratorInterface::DoseIteratorPointer + doseIterator, IDType structUID, IDType doseUID) { rttb::core::DVHCalculator calc(doseIterator, structUID, doseUID); rttb::core::DVH::DVHPointer dvh = calc.generateDVH(); return dvh; } -void rttb::apps::doseTool::writeDoseStatisticsFile(rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, - const std::string& filename, const std::string& structName, - rttb::apps::doseTool::ApplicationData& appData) +void rttb::apps::doseTool::writeDoseStatisticsFile( + rttb::algorithms::DoseStatistics::DoseStatisticsPointer statistics, + const std::string& filename, const std::string& structName, + rttb::apps::doseTool::ApplicationData& appData) { boost::property_tree::ptree originalTree = rttb::io::other::writeDoseStatistics(statistics); //add config part to xml originalTree.add("statistics.config.requestedStructRegex", appData._structNameRegex); originalTree.add("statistics.config.structName", structName); originalTree.add("statistics.config.doseUID", appData._dose->getUID()); originalTree.add("statistics.config.doseFile", appData._doseFileName); originalTree.add("statistics.config.structFile", appData._structFileName); boost::property_tree::ptree reorderedTree, configTree, resultsTree; configTree = originalTree.get_child("statistics.config"); resultsTree = originalTree.get_child("statistics.results"); reorderedTree.add_child("statistics.config", configTree); reorderedTree.add_child("statistics.results", resultsTree); boost::property_tree::write_xml(filename, reorderedTree, std::locale(), boost::property_tree::xml_writer_make_settings('\t', 1)); } std::string rttb::apps::doseTool::assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName) { boost::filesystem::path originalFile(originalFilename); - std::string newFilename = originalFile.stem().string() + "_" + structName + originalFile.extension().string(); + std::string newFilename = originalFile.stem().string() + "_" + structName + + originalFile.extension().string(); boost::filesystem::path newFile(originalFile.parent_path() / newFilename); return newFile.string(); } void rttb::apps::doseTool::writeDVHFile(core::DVH::DVHPointer dvh, const std::string& filename) { DVHType typeCum = { DVHType::Cumulative }; rttb::io::other::DVHXMLFileWriter dvhWriter(filename, typeCum); dvhWriter.writeDVH(dvh); } diff --git a/demoapps/DoseTool/DoseToolHelper.h b/demoapps/DoseTool/DoseToolHelper.h index e5caf22..29d8c23 100644 --- a/demoapps/DoseTool/DoseToolHelper.h +++ b/demoapps/DoseTool/DoseToolHelper.h @@ -1,122 +1,128 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 1066 $ (last changed revision) -// @date $Date: 2015-08-19 11:47:07 +0200 (Mi, 19 Aug 2015) $ (last change date) -// @author $Author: floca $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __DOSETOOL_HELPER_H #define __DOSETOOL_HELPER_H #include "DoseToolApplicationData.h" #include "rttbDoseAccessorInterface.h" #include "rttbDoseIteratorInterface.h" #include "rttbMaskAccessorInterface.h" #include "rttbDoseStatistics.h" #include "rttbDVH.h" namespace rttb { namespace apps { namespace doseTool { /*! @brief loads a dose from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails */ core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); /*! @brief loads a helax dose from a file. @exception Throws an rttb::Exception if loading fails @sa DicomHelaxFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); /*! @brief loads an itk dose from a file. @exception Throws an rttb::Exception if loading fails. @details Might be of all formats that ITK know (*.mhd, *.nrrd, ...). The absolute image values are taken as dose. @sa ITKImageFileAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); /*! @brief loads a virtuos dose from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, const std::string& planFileName); /*! @brief loads a struct from a file based on the loadingStyle. @exception Throws an rttb::Exception if loading fails @details voxelized itk images are read in generateMask() directly */ core::StructureSetGeneratorInterface::StructureSetPointer loadStruct(const std::string& fileName, const rttb::apps::doseTool::ApplicationData::LoadingStyleArgType& args); /*! @brief loads a dicom struct from a file. @exception Throws an rttb::Exception if loading fails @sa DicomFileStructureSetGenerator */ - core::StructureSetGeneratorInterface::StructureSetPointer loadDicomStruct(const std::string& fileName); + core::StructureSetGeneratorInterface::StructureSetPointer loadDicomStruct( + const std::string& fileName); /*! @brief loads a virtuos struct from a file. @exception Throws an rttb::Exception if loading fails @sa VirtuosPlanFileDoseAccessorGenerator */ - core::StructureSetGeneratorInterface::StructureSetPointer loadVirtuosStruct(const std::string& fileName, - const std::string& ctxFileName); + core::StructureSetGeneratorInterface::StructureSetPointer loadVirtuosStruct( + const std::string& fileName, + const std::string& ctxFileName); /*! @brief Contains the business logic of processing all information to calculate the dose statistics and writing them to an xml file. @details Uses appData for the input data and the correct configuration. */ void processData(ApplicationData& appData); /*! @brief Generates a mask from the struct file by using the boostAccessor. In case of itk image, it directly loads the voxelized image. */ - std::vector generateMasks(ApplicationData& appData); + std::vector generateMasks( + ApplicationData& appData); algorithms::DoseStatistics::DoseStatisticsPointer calculateDoseStatistics( core::DoseIteratorInterface::DoseIteratorPointer doseIterator, bool calculateComplexDoseStatistics, DoseTypeGy prescribedDose); - core::DVH::DVHPointer calculateDVH(core::DoseIteratorInterface::DoseIteratorPointer doseIterator, IDType structUID, + core::DVH::DVHPointer calculateDVH(core::DoseIteratorInterface::DoseIteratorPointer doseIterator, + IDType structUID, IDType doseUID); /*! @brief Writes the dose statistics as XML to a file @details adds a .... part to the RTTB generated xml where the used files and struct names are stored. */ - void writeDoseStatisticsFile(algorithms::DoseStatistics::DoseStatisticsPointer statistics, const std::string& filename, + void writeDoseStatisticsFile(algorithms::DoseStatistics::DoseStatisticsPointer statistics, + const std::string& filename, const std::string& structName, rttb::apps::doseTool::ApplicationData& appData); void writeDVHFile(core::DVH::DVHPointer dvh, const std::string& filename); core::DoseIteratorInterface::DoseIteratorPointer generateMaskedDoseIterator( core::MaskAccessorInterface::MaskAccessorPointer maskAccessorPtr, core::DoseAccessorInterface::DoseAccessorPointer doseAccessorPtr); - std::string assembleFilenameWithStruct(const std::string& originalFilename, const std::string& structName); + std::string assembleFilenameWithStruct(const std::string& originalFilename, + const std::string& structName); } } } #endif diff --git a/demoapps/VoxelizerTool/rttbCommandOptions.cpp b/demoapps/VoxelizerTool/rttbCommandOptions.cpp index b80ddb3..ec7c13e 100644 --- a/demoapps/VoxelizerTool/rttbCommandOptions.cpp +++ b/demoapps/VoxelizerTool/rttbCommandOptions.cpp @@ -1,173 +1,181 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbCommandOptions.h" #include "rttbVoxelizerHelper.h" namespace rttb { namespace apps { namespace voxelizer { CommandOptions::CommandOptions(): PARAM_HELP("help"), PARAM_STRUCT_FILE("structFile"), PARAM_REFERENCE_FILE("referenceFile"), PARAM_OUT_FILE("output"), PARAM_REGEX("struct"), PARAM_MULTISTRUCT("multipleStructs"), PARAM_LEGACY_VOXELIZATION("legacyVoxelization"), PARAM_BOOST_VOXELIZATION("boostVoxelization"), PARAM_BOOLEAN_VOXELIZATION("booleanVoxelization"), PARAM_ADDSTRUCTURES("addStructures"), PARAM_ALLOW_SELF_INTERSECTIONS("selfIntersections"), _returnAfterHelp(false) { _params.multipleStructs = false; _params.legacyVoxelization = false; _params.booleanVoxelization = false; _params.addStructures = false; std::vector defaultRefLoadingStyle; defaultRefLoadingStyle.push_back("dicom"); po::options_description required("Required arguments"); addOption(required, PARAM_STRUCT_FILE, "s", po::value(&_params.structFile)->required(), "Filename of the structfile (*.dcm)"); - addOption(required, PARAM_REFERENCE_FILE, "r", po::value(&_params.referenceFile)->required(), + addOption(required, PARAM_REFERENCE_FILE, "r", + po::value(&_params.referenceFile)->required(), "Filename of the reference image (*.dcm)"); addOption(required, PARAM_REFERENCE_FILE_LOAD_STYLE, "y", po::value >(&_params.referenceFileLoadStyle)->required()->default_value( defaultRefLoadingStyle, "dicom"), "set the load style for the reference file. Available styles are:\n" "\"dicom\": normal dicom dose\n" "\"itk\": use itk image loading."); addOption(required, PARAM_REGEX, "e", po::value>(&_params.regEx)->multitoken()->required(), "set a regular expression describing the structs of interest"); addOption(required, PARAM_OUT_FILE, "o", po::value(&_params.outputFilename)->default_value("out.hdr"), "set output file name "); - addOption(required, PARAM_BOOST_VOXELIZATION, "b", po::bool_switch()->default_value(true), "to use boost voxelization"); + addOption(required, PARAM_BOOST_VOXELIZATION, "b", po::bool_switch()->default_value(true), + "to use boost voxelization"); po::options_description optional("Optional arguments"); addOption(optional, PARAM_HELP, "h", nullptr, "Display help message"); - addOption(optional, PARAM_MULTISTRUCT, "m", po::bool_switch(&_params.multipleStructs)->default_value(false), + addOption(optional, PARAM_MULTISTRUCT, "m", + po::bool_switch(&_params.multipleStructs)->default_value(false), "if multiple structs match the regular expression (--struct), save all in files"); - addOption(optional, PARAM_LEGACY_VOXELIZATION, "l", po::bool_switch(&_params.legacyVoxelization)->default_value(false), + addOption(optional, PARAM_LEGACY_VOXELIZATION, "l", + po::bool_switch(&_params.legacyVoxelization)->default_value(false), "to use legacy voxelization"); addOption(optional, PARAM_BOOLEAN_VOXELIZATION, "v", po::bool_switch(&_params.booleanVoxelization)->default_value(false), "Determines if the voxelization should be binarized (only values 0 or 1)"); - addOption(optional, PARAM_ADDSTRUCTURES, "a", nullptr, "Voxelizes multiple structs in one result file."); + addOption(optional, PARAM_ADDSTRUCTURES, "a", nullptr, + "Voxelizes multiple structs in one result file."); addOption(optional, PARAM_ALLOW_SELF_INTERSECTIONS, "i", po::bool_switch(&_params.allowSelfIntersections)->default_value(false), "If self intersections of polygons should be tolerated."); _description.add(required).add(optional); } void CommandOptions::addOption(po::options_description& o, const std::string& name, const std::string& shortcut, const po::value_semantic* valueSemantic, const std::string& description) { if (valueSemantic) { o.add_options()((name + std::string(",") + shortcut).c_str(), valueSemantic, description.c_str()); } else { o.add_options()((name + std::string(",") + shortcut).c_str(), description.c_str()); } } void CommandOptions::showHelp() const { std::cout << "Usage: VoxelizerTool [options] \n"; std::cout << _description << std::endl; - std::cout << "Example: VoxelizerTool -s structFile.dcm -r referenceFile.dcm -e Kidney -o outputFile.mhd -m" << + std::cout << + "Example: VoxelizerTool -s structFile.dcm -r referenceFile.dcm -e Kidney -o outputFile.mhd -m" << std::endl; std::cout << "Computes a voxelization file outputFile.mhd based on the DICOMRT-STRUCT structFile.dcm in the geometry of referenceFile.dcm where"; std::cout << "the name of the struct matches the regular expression 'Kidney'." << std::endl; std::cout << "If structures 'Kidney_left' and 'Kidney_right' are defined, "; std::cout << - "both are written under the names outputFile_Kidney_left.mhd and outputFile_Kidney_right.mhd (parameter -m)." << + "both are written under the names outputFile_Kidney_left.mhd and outputFile_Kidney_right.mhd (parameter -m)." + << std::endl; } bool CommandOptions::command(int argc, char* argv[]) { try { po::variables_map var; po::store(po::command_line_parser(argc, argv).options(_description).run(), var); if (var.count(PARAM_HELP)) { showHelp(); _returnAfterHelp = true; return true; } po::notify(var); if (var.count(PARAM_BOOST_VOXELIZATION)) { _params.legacyVoxelization = false; } if (_params.outputFilename.find('.') == std::string::npos) { - std::cout << "--output has to specify a file format (e.g. output.hdr). None is given: " << _params.outputFilename << + std::cout << "--output has to specify a file format (e.g. output.hdr). None is given: " << + _params.outputFilename << std::endl; return false; } if (_params.referenceFileLoadStyle.empty() || (_params.referenceFileLoadStyle.at(0) != "dicom" && _params.referenceFileLoadStyle.at(0) != "itk")) { std::cout << "Unknown load style:" + _params.referenceFileLoadStyle.at(0) + ".\nPlease refer to the help for valid loading style settings." << std::endl; return false; } if (var.count(PARAM_ADDSTRUCTURES)) { _params.addStructures = true; _params.multipleStructs = false; } } catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return false; } return true; } } } } \ No newline at end of file diff --git a/demoapps/VoxelizerTool/rttbMaskProcess.cpp b/demoapps/VoxelizerTool/rttbMaskProcess.cpp index d616879..058a1bb 100644 --- a/demoapps/VoxelizerTool/rttbMaskProcess.cpp +++ b/demoapps/VoxelizerTool/rttbMaskProcess.cpp @@ -1,64 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbMaskProcess.h" #include #include "rttbBoostMaskAccessor.h" namespace rttb { namespace apps { namespace voxelizer { MaskProcess::MaskProcess(StructureSetPointer rtStructureSet, DoseAccessorPointer doseAccessor, - bool legacy, bool allowSelfIntersection) : _rtStructureSet(rtStructureSet), _doseAccessor(doseAccessor), + bool legacy, bool allowSelfIntersection) : _rtStructureSet(rtStructureSet), + _doseAccessor(doseAccessor), _legacyVoxelization(legacy), _allowSelfIntersection(allowSelfIntersection) { } MaskProcess::MaskAccessorPointer MaskProcess::createMask(unsigned int indexOfStructure) const { MaskAccessorPointer maskAccessorPtr; if (_doseAccessor != NULL && _rtStructureSet != NULL) { if (_legacyVoxelization) { maskAccessorPtr = boost::make_shared (_rtStructureSet->getStructure(indexOfStructure), _doseAccessor->getGeometricInfo()); } else { maskAccessorPtr = boost::make_shared - (_rtStructureSet->getStructure(indexOfStructure), _doseAccessor->getGeometricInfo(), !_allowSelfIntersection); + (_rtStructureSet->getStructure(indexOfStructure), _doseAccessor->getGeometricInfo(), + !_allowSelfIntersection); } maskAccessorPtr->updateMask(); } return maskAccessorPtr; } } } } \ No newline at end of file diff --git a/demoapps/VoxelizerTool/rttbStructDataReader.cpp b/demoapps/VoxelizerTool/rttbStructDataReader.cpp index b7252af..0433868 100644 --- a/demoapps/VoxelizerTool/rttbStructDataReader.cpp +++ b/demoapps/VoxelizerTool/rttbStructDataReader.cpp @@ -1,114 +1,117 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbStructDataReader.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace apps { namespace voxelizer { - StructDataReader::StructDataReader(const std::string& structFileName, const std::string& referenceFileName, + StructDataReader::StructDataReader(const std::string& structFileName, + const std::string& referenceFileName, const std::vector& referenceFileLoadingStyle) : _referenceFilename(referenceFileName), _structFilename(structFileName), _referenceFileLoadingStyle(referenceFileLoadingStyle) { } void StructDataReader::read() { _doseAccessor = readReferenceFile(_referenceFilename, _referenceFileLoadingStyle); _rtStructureSet = readStructFile(_structFilename); } 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 NULL; } } - StructDataReader::DoseAccessorPointer StructDataReader::readDicomFile(const std::string& filename) const + 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 + 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 { StructureSetPointer rtStructureSet = rttb::io::dicom::DicomFileStructureSetGenerator( filename.c_str()).generateStructureSet(); return rtStructureSet; } } } } \ No newline at end of file diff --git a/demoapps/VoxelizerTool/rttbVoxelizerTool.cpp b/demoapps/VoxelizerTool/rttbVoxelizerTool.cpp index b7166b1..d4efc32 100644 --- a/demoapps/VoxelizerTool/rttbVoxelizerTool.cpp +++ b/demoapps/VoxelizerTool/rttbVoxelizerTool.cpp @@ -1,180 +1,181 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "itkMacro.h" #include "rttbVoxelizerHelper.h" #include "rttbMaskProcess.h" #include "rttbMaskWriter.h" #include "rttbStructDataReader.h" #include "rttbCommandOptions.h" int main(int argc, char* argv[]) { typedef rttb::core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; boost::shared_ptr co = boost::make_shared(); if (!co->command(argc, argv)) { return 1; } if (co->isReturnAfterHelp()) { return 0; } rttb::apps::voxelizer::Parameters params = co->getParameters(); boost::shared_ptr reader = boost::make_shared(params.structFile, params.referenceFile, params.referenceFileLoadStyle); std::cout << "reading reference and structure file..."; try { reader->read(); } catch (rttb::core::Exception& e) { std::cerr << "RTTB Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 2; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 2; } std::cout << "done." << std::endl; std::cout << "searching for structs..."; std::vector listOfCorrectElements; for (int i = 0; i < params.regEx.size(); i++) { std::vector indexOfCorrectElements; indexOfCorrectElements = rttb::apps::voxelizer::filterForExpression(reader->getAllLabels(), params.regEx.at(i)); - std::copy(indexOfCorrectElements.begin(), indexOfCorrectElements.end(), std::back_inserter(listOfCorrectElements)); + std::copy(indexOfCorrectElements.begin(), indexOfCorrectElements.end(), + std::back_inserter(listOfCorrectElements)); } std::cout << "done." << std::endl; boost::shared_ptr maskProcessor = boost::make_shared(reader->getStructureSetPointer(), reader->getDoseAccessorPointer(), params.legacyVoxelization, params.allowSelfIntersections); if (!listOfCorrectElements.empty()) { std::string fileName = rttb::apps::voxelizer::getFilenameWithoutEnding( params.outputFilename); std::string fileEnding = rttb::apps::voxelizer::getFileEnding(params.outputFilename); std::vector maskVector; if (params.addStructures) { std::string labelName; for (int i = 0; i < listOfCorrectElements.size(); i++) { int labelIndex = listOfCorrectElements.at(i); maskVector.push_back(maskProcessor->createMask(labelIndex)); std::vector labelVector = reader->getAllLabels(); std::string labelOfInterest = labelVector.at(labelIndex); rttb::apps::voxelizer::removeSpecialCharacters(labelOfInterest); labelName += "_" + labelOfInterest; } boost::shared_ptr writer = boost::make_shared(maskVector, params.booleanVoxelization); writer->writeMaskToFile(fileName + labelName + fileEnding); } else { unsigned int maxIterationCount = 1; if (params.multipleStructs) { maxIterationCount = listOfCorrectElements.size(); } for (unsigned int i = 0; i < maxIterationCount; i++) { std::cout << "creating mask..."; maskVector.push_back(maskProcessor->createMask(listOfCorrectElements.at(i))); std::cout << "done" << std::endl; int labelIndex = listOfCorrectElements.at(i); std::vector labelVector = reader->getAllLabels(); std::string labelOfInterest = labelVector.at(labelIndex); rttb::apps::voxelizer::removeSpecialCharacters(labelOfInterest); boost::shared_ptr MW = boost::make_shared(maskVector, params.booleanVoxelization); try { MW->writeMaskToFile(fileName + "_" + labelOfInterest + fileEnding); } catch (itk::ExceptionObject& err) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; return 3; } catch (const std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 3; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 3; } } } } else { std::cout << "No struct found" << std::endl; } return 0; } diff --git a/testing/algorithms/DoseStatisticsCalculatorTest.cpp b/testing/algorithms/DoseStatisticsCalculatorTest.cpp index 379bce9..0633fa8 100644 --- a/testing/algorithms/DoseStatisticsCalculatorTest.cpp +++ b/testing/algorithms/DoseStatisticsCalculatorTest.cpp @@ -1,315 +1,324 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" #include "../core/DummyDoseAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; typedef rttb::algorithms::DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; /*! @brief DoseStatisticsCalculatorTest - test the API of DoseStatisticsCalculator 1) test constructors 2) test setDoseIterator 3) test calculateDoseSatistics 4) get statistical values */ int DoseStatisticsCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); DoseIteratorPointer spDoseIteratorNull; //1) test constructors // the values cannot be accessed from outside, therefore correct default values are not tested - CHECK_THROW_EXPLICIT(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIteratorNull), + CHECK_THROW_EXPLICIT(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator( + spDoseIteratorNull), core::NullPointerException); CHECK_NO_THROW(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator)); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); //2) test setDoseIterator //3) test calculateDoseStatistics DoseStatisticsPointer theStatistics; //simple dose statistics CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics()); CHECK_EQUAL(theStatistics->getMinimumPositions()->empty(), false); CHECK_EQUAL(theStatistics->getMaximumPositions()->empty(), false); CHECK_EQUAL(theStatistics->getAllVx().empty(), true); CHECK_EQUAL(theStatistics->getAllDx().empty(), true); CHECK_EQUAL(theStatistics->getAllVx().empty(), true); CHECK_EQUAL(theStatistics->getAllMaxOHx().empty(), true); CHECK_EQUAL(theStatistics->getAllMOHx().empty(), true); CHECK_EQUAL(theStatistics->getAllMOCx().empty(), true); CHECK_EQUAL(theStatistics->getAllMinOCx().empty(), true); //check default values for computeComplexMeasures=true DoseStatisticsPointer theStatisticsDefault; CHECK_NO_THROW(theStatisticsDefault = myDoseStatsCalculator.calculateDoseStatistics(true)); CHECK_NO_THROW(theStatisticsDefault->getVx(0.02 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx(0.05 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx(0.1 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx(0.9 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx(0.95 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx(0.98 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.02 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.05 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.1 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.9 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.95 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx(0.98 * theStatisticsDefault->getVolume())); //check manually set reference dose and the default x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(100.0)); - CHECK_THROW_EXPLICIT(theStatistics->getVx(0.1 * theStatistics->getMaximum()), core::DataNotAvailableException); + CHECK_THROW_EXPLICIT(theStatistics->getVx(0.1 * theStatistics->getMaximum()), + core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx(0.1 * 100.0)); CHECK_NO_THROW(theStatistics->getDx(0.1 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOHx(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOCx(0.98 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //check manually set x values std::vector precomputeDoseValues, precomputeVolumeValues; precomputeDoseValues.push_back(0.01); precomputeDoseValues.push_back(0.02); precomputeDoseValues.push_back(0.05); precomputeVolumeValues.push_back(0.9); precomputeVolumeValues.push_back(0.95); precomputeVolumeValues.push_back(0.99); CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues)); CHECK_NO_THROW(theStatistics->getVx(0.01 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx(0.02 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx(0.05 * theStatistics->getMaximum())); - CHECK_THROW_EXPLICIT(theStatistics->getVx(0.03 * theStatistics->getMaximum()), core::DataNotAvailableException); + CHECK_THROW_EXPLICIT(theStatistics->getVx(0.03 * theStatistics->getMaximum()), + core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getDx(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx(0.99 * theStatistics->getVolume())); - CHECK_THROW_EXPLICIT(theStatistics->getDx(0.03 * theStatistics->getVolume()), core::DataNotAvailableException); + CHECK_THROW_EXPLICIT(theStatistics->getDx(0.03 * theStatistics->getVolume()), + core::DataNotAvailableException); CHECK_EQUAL(theStatistics->getVx(0.02 * theStatistics->getMaximum()), - theStatisticsDefault->getVx(0.02 * theStatistics->getMaximum())); + theStatisticsDefault->getVx(0.02 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getVx(0.05 * theStatistics->getMaximum()), - theStatisticsDefault->getVx(0.05 * theStatistics->getMaximum())); + theStatisticsDefault->getVx(0.05 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getDx(0.9 * theStatistics->getVolume()), - theStatisticsDefault->getDx(0.9 * theStatistics->getVolume())); + theStatisticsDefault->getDx(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getDx(0.95 * theStatistics->getVolume()), - theStatisticsDefault->getDx(0.95 * theStatistics->getVolume())); + theStatisticsDefault->getDx(0.95 * theStatistics->getVolume())); //check manually set reference dose and x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, - precomputeVolumeValues, 100.0)); - CHECK_THROW_EXPLICIT(theStatistics->getVx(0.01 * theStatistics->getMaximum()), core::DataNotAvailableException); + precomputeVolumeValues, 100.0)); + CHECK_THROW_EXPLICIT(theStatistics->getVx(0.01 * theStatistics->getMaximum()), + core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx(0.01 * 100.0)); CHECK_NO_THROW(theStatistics->getDx(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //MOHx, MOCx, MaxOHx and MinOCx are computed analogous to Dx, they will not be checked. //4) get statistical values CHECK_EQUAL(theStatistics->getNumberOfVoxels(), doseVals->size()); //compute simple statistical values (min, mean, max, stddev) for comparison DoseStatisticType maximum = 0; DoseStatisticType minimum = 1000000; DoseStatisticType mean = 0; DoseStatisticType variance = 0; std::vector::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } if (minimum > *doseIt) { minimum = *doseIt; } mean += *doseIt; ++doseIt; } mean /= doseVals->size(); DoseTypeGy compMean = (int(mean * 100)) / 100; doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { variance += pow(*doseIt - mean, 2); ++doseIt; } variance /= doseVals->size(); DoseStatisticType stdDev = pow(variance, 0.5); //we have some precision problems here... double errorConstantLarger = 1e-2; CHECK_EQUAL(theStatistics->getMaximum(), maximum); CHECK_EQUAL(theStatistics->getMinimum(), minimum); CHECK_CLOSE(theStatistics->getMean(), mean, errorConstantLarger); CHECK_CLOSE(theStatistics->getStdDeviation(), stdDev, errorConstantLarger); CHECK_CLOSE(theStatistics->getVariance(), variance, errorConstantLarger); //check for complex doseStatistics (maximumPositions, minimumPositions, Vx, Dx, MOHx, MOCx, MAXOHx, MinOCx) unsigned int nMax = 0, nMin = 0; doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (*doseIt == theStatistics->getMaximum()) { nMax++; } if (*doseIt == theStatistics->getMinimum()) { nMin++; } ++doseIt; } //only 100 positions are stored if (nMax > 100) { nMax = 100; } if (nMin > 100) { nMin = 100; } auto maximaPositions = theStatistics->getMaximumPositions(); auto minimaPositions = theStatistics->getMinimumPositions(); CHECK_EQUAL(maximaPositions->size(), nMax); CHECK_EQUAL(minimaPositions->size(), nMin); - for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); + for (auto maximaPositionsIterator = std::begin(*maximaPositions); + maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics->getMaximum()); } - for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); + for (auto minimaPositionsIterator = std::begin(*minimaPositions); + minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics->getMinimum()); } //generate specific example dose maximum = 9.5; minimum = 2.5; mean = 6; int sizeTemplate = 500; std::vector aDoseVector; for (int i = 0; i < sizeTemplate; i++) { aDoseVector.push_back(maximum); aDoseVector.push_back(minimum); } core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); geoInfo.setNumRows(20); geoInfo.setNumColumns(10); geoInfo.setNumSlices(5); boost::shared_ptr spTestDoseAccessor2 = boost::make_shared(aDoseVector, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); boost::shared_ptr spTestDoseIterator2 = boost::make_shared(spDoseAccessor2); DoseIteratorPointer spDoseIterator2(spTestDoseIterator2); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator2(spDoseIterator2); DoseStatisticsPointer theStatistics3 = myDoseStatsCalculator2.calculateDoseStatistics(); CHECK_EQUAL(theStatistics3->getMaximum(), maximum); CHECK_EQUAL(theStatistics3->getMinimum(), minimum); CHECK_EQUAL(theStatistics3->getMean(), mean); maximaPositions = theStatistics3->getMaximumPositions(); minimaPositions = theStatistics3->getMinimumPositions(); CHECK_EQUAL(maximaPositions->empty(), false); CHECK_EQUAL(minimaPositions->empty(), false); - for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); + for (auto maximaPositionsIterator = std::begin(*maximaPositions); + maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics3->getMaximum()); } - for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); + for (auto minimaPositionsIterator = std::begin(*minimaPositions); + minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics3->getMinimum()); } RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/algorithms/DoseStatisticsTest.cpp b/testing/algorithms/DoseStatisticsTest.cpp index 150a1a4..1184244 100644 --- a/testing/algorithms/DoseStatisticsTest.cpp +++ b/testing/algorithms/DoseStatisticsTest.cpp @@ -1,218 +1,227 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDoseStatistics.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace testing { typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; typedef rttb::algorithms::DoseStatistics::DoseToVolumeFunctionType DoseToVolumeFunctionType; typedef rttb::algorithms::DoseStatistics::VolumeToDoseFunctionType VolumeToDoseFunctionType; /*! @brief DoseStatisticsTest - test the API of DoseStatistics 1) test constructors 2) test setters 3) test getters of complex statistics (with stored key and without stored key) */ int DoseStatisticsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; DoseStatisticType minimum = 1.0; DoseStatisticType mean = 5.5; DoseStatisticType maximum = 108.2; DoseStatisticType stdDeviation = 10.1; unsigned int numVoxels = 100000; VolumeType volume = numVoxels * (0.5 * 0.5 * 0.5); std::vector > minVoxels; std::vector > maxVoxels; minVoxels.push_back(std::make_pair(1.0, 11)); minVoxels.push_back(std::make_pair(1.0, 22)); minVoxels.push_back(std::make_pair(1.0, 33)); minVoxels.push_back(std::make_pair(1.0, 44)); maxVoxels.push_back(std::make_pair(108.2, 5)); maxVoxels.push_back(std::make_pair(108.2, 6)); maxVoxels.push_back(std::make_pair(108.2, 7)); maxVoxels.push_back(std::make_pair(108.2, 8)); - ResultListPointer resultsMinVoxels = boost::make_shared > >(minVoxels); - ResultListPointer resultsMaxVoxels = boost::make_shared > >(maxVoxels); + ResultListPointer resultsMinVoxels = + boost::make_shared > >(minVoxels); + ResultListPointer resultsMaxVoxels = + boost::make_shared > >(maxVoxels); DoseToVolumeFunctionType Vx; Vx.insert(std::make_pair(1.1, 1000)); Vx.insert(std::make_pair(106.9, 99000)); VolumeToDoseFunctionType Dx; Dx.insert(std::make_pair(1000, 1.1)); Dx.insert(std::make_pair(99000, 106.9)); VolumeToDoseFunctionType MOHx; MOHx.insert(std::make_pair(1000, 5)); MOHx.insert(std::make_pair(99000, 105.5)); VolumeToDoseFunctionType MOCx; MOCx.insert(std::make_pair(1000, 10)); MOCx.insert(std::make_pair(99000, 99)); VolumeToDoseFunctionType MaxOHx; MaxOHx.insert(std::make_pair(1000, 40)); MaxOHx.insert(std::make_pair(99000, 98.3)); VolumeToDoseFunctionType MinOCx; MinOCx.insert(std::make_pair(1000, 25.5)); MinOCx.insert(std::make_pair(99000, 102.7)); //1) test constructors - CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, + CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, + numVoxels, volume)); - rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, volume); + rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, + volume); CHECK_EQUAL(aDoseStatistic.getMinimum(), minimum); CHECK_EQUAL(aDoseStatistic.getMaximum(), maximum); CHECK_EQUAL(aDoseStatistic.getMean(), mean); CHECK_EQUAL(aDoseStatistic.getStdDeviation(), stdDeviation); CHECK_EQUAL(aDoseStatistic.getVariance(), stdDeviation * stdDeviation); CHECK_EQUAL(aDoseStatistic.getNumberOfVoxels(), numVoxels); CHECK_EQUAL(aDoseStatistic.getVolume(), volume); //check default values for unset complex values CHECK_EQUAL(aDoseStatistic.getMaximumPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getMinimumPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getAllDx().empty(), true); CHECK_EQUAL(aDoseStatistic.getAllVx().empty(), true); CHECK_EQUAL(aDoseStatistic.getAllMOHx().empty(), true); CHECK_EQUAL(aDoseStatistic.getAllMOCx().empty(), true); CHECK_EQUAL(aDoseStatistic.getAllMaxOHx().empty(), true); CHECK_EQUAL(aDoseStatistic.getAllMinOCx().empty(), true); - CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, + CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, + stdDeviation, numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx)); - rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, volume, + rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, + numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx); CHECK_EQUAL(aDoseStatisticComplex.getMaximumPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatisticComplex.getMinimumPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatisticComplex.getAllDx() == Dx, true); CHECK_EQUAL(aDoseStatisticComplex.getAllVx() == Vx, true); CHECK_EQUAL(aDoseStatisticComplex.getAllMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getAllMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatisticComplex.getAllMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getAllMinOCx() == MinOCx, true); //2) test setters (only complex statistics have setters) CHECK_NO_THROW(aDoseStatistic.setMaximumVoxelPositions(resultsMaxVoxels)); CHECK_NO_THROW(aDoseStatistic.setMinimumVoxelPositions(resultsMinVoxels)); CHECK_NO_THROW(aDoseStatistic.setDx(Dx)); CHECK_NO_THROW(aDoseStatistic.setVx(Vx)); CHECK_NO_THROW(aDoseStatistic.setMOHx(MOHx)); CHECK_NO_THROW(aDoseStatistic.setMOCx(MOCx)); CHECK_NO_THROW(aDoseStatistic.setMaxOHx(MaxOHx)); CHECK_NO_THROW(aDoseStatistic.setMinOCx(MinOCx)); CHECK_EQUAL(aDoseStatistic.getMaximumPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatistic.getMinimumPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatistic.getAllDx() == Dx, true); CHECK_EQUAL(aDoseStatistic.getAllVx() == Vx, true); CHECK_EQUAL(aDoseStatistic.getAllMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatistic.getAllMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatistic.getAllMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatistic.getAllMinOCx() == MinOCx, true); //3) test getters of complex statistics(with stored key and without stored key) //getAll*() already tested in (2) Vx.clear(); Vx.insert(std::make_pair(1.1, 1000)); Vx.insert(std::make_pair(5.0, 2300)); Vx.insert(std::make_pair(90, 90500)); Vx.insert(std::make_pair(107, 99000)); Dx.clear(); Dx.insert(std::make_pair(1000, 1.1)); Dx.insert(std::make_pair(2000, 2.0)); Dx.insert(std::make_pair(5000, 10.8)); Dx.insert(std::make_pair(90000, 89.5)); Dx.insert(std::make_pair(98000, 104.4)); Dx.insert(std::make_pair(99000, 106.9)); - rttb::algorithms::DoseStatistics aDoseStatisticNewValues(minimum, maximum, mean, stdDeviation, numVoxels, volume); + rttb::algorithms::DoseStatistics aDoseStatisticNewValues(minimum, maximum, mean, stdDeviation, + numVoxels, volume); aDoseStatisticNewValues.setDx(Dx); aDoseStatisticNewValues.setVx(Vx); CHECK_NO_THROW(aDoseStatisticNewValues.getVx(1.1)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx(90)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx(1000)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx(98000)); CHECK_EQUAL(aDoseStatisticNewValues.getVx(1.1), Vx.find(1.1)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx(90), Vx.find(90)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx(1000), Dx.find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx(98000), Dx.find(98000)->second); //test if key-value combination NOT in map CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getDx(1001), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getVx(10), core::DataNotAvailableException); double closestDxKey, closestVxKey; CHECK_NO_THROW(aDoseStatisticNewValues.getDx(900, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx(99001, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx(10, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx(900, true, closestDxKey), Dx.find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx(99001, true, closestDxKey), Dx.find(99000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx(10, true, closestVxKey), Vx.find(5.0)->second); CHECK_EQUAL(closestDxKey, 99000); CHECK_EQUAL(closestVxKey, 5); //equal distance to two values. First value is returned. CHECK_NO_THROW(aDoseStatisticNewValues.getDx(1500, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx(98.5, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx(1500, true, closestDxKey), Dx.find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx(98.5, true, closestVxKey), Vx.find(90.0)->second); CHECK_EQUAL(closestDxKey, 1000); CHECK_EQUAL(closestVxKey, 90.0); double dummy; CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx(25), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx(9999), core::DataNotAvailableException); - CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx(25, true, dummy), core::DataNotAvailableException); - CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx(9999, true, dummy), core::DataNotAvailableException); + CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx(25, true, dummy), + core::DataNotAvailableException); + CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx(9999, true, dummy), + core::DataNotAvailableException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/CreateTestStructure.cpp b/testing/core/CreateTestStructure.cpp index c5b7f08..60ee7c1 100644 --- a/testing/core/CreateTestStructure.cpp +++ b/testing/core/CreateTestStructure.cpp @@ -1,614 +1,670 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "CreateTestStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbInvalidDoseException.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { - CreateTestStructure::~CreateTestStructure(){} + CreateTestStructure::~CreateTestStructure() {} - CreateTestStructure::CreateTestStructure(const core::GeometricInfo& aGeoInfo){ - _geoInfo = aGeoInfo; - } + CreateTestStructure::CreateTestStructure(const core::GeometricInfo& aGeoInfo) + { + _geoInfo = aGeoInfo; + } - PolygonType CreateTestStructure::createPolygonLeftUpper(std::vector aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonLeftUpper(std::vector aVoxelVector, + GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonCenter(std::vector aVoxelVector, + GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonBetweenUpperLeftAndCenter( + std::vector aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonBetweenLowerRightAndCenter( + std::vector aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonLeftEdgeMiddle(std::vector + aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonUpperCenter(std::vector + aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonIntermediatePoints(std::vector + aVoxelVector, GridIndexType sliceNumber) + { + + PolygonType polygon; - PolygonType polygon; - for(int i=0;i aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createPolygonCircle(std::vector aVoxelVector, + GridIndexType sliceNumber) + { PolygonType polygon; - if( aVoxelVector.size() > 0 ) - { - int i=0; + if (aVoxelVector.size() > 0) + { + int i = 0; VoxelGridIndex3D voxelIndex; - voxelIndex(0)=(aVoxelVector.at(i)).x(); - voxelIndex(1)=(aVoxelVector.at(i)).y(); - voxelIndex(2)=sliceNumber; + voxelIndex(0) = (aVoxelVector.at(i)).x(); + voxelIndex(1) = (aVoxelVector.at(i)).y(); + voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; - _geoInfo.indexToWorldCoordinate(voxelIndex,p1); - SpacingVectorType3D delta=_geoInfo.getSpacing(); + _geoInfo.indexToWorldCoordinate(voxelIndex, p1); + SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; - wp1(0)=p1.x(); - wp1(1)=p1.y(); - wp1(2)=p1.z(); + wp1(0) = p1.x(); + wp1(1) = p1.y(); + wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; - wp_intermediate(0)= 0; - wp_intermediate(1)= 0; - wp_intermediate(2)= p1.z(); + wp_intermediate(0) = 0; + wp_intermediate(1) = 0; + wp_intermediate(2) = p1.z(); - double radius = 2 * delta.x(); - double frac_radius = ( radius * 0.001 ); + double radius = 2 * delta.x(); + double frac_radius = (radius * 0.001); - double correct_y = ( delta.x() / delta.y() ); + double correct_y = (delta.x() / delta.y()); - for( int i = 0 ; i <= 1000 ; i++ ){ - double y_offset = sqrt( ( radius * radius ) - ( (frac_radius * i) * (frac_radius * i) ) ); + for (int i = 0 ; i <= 1000 ; i++) + { + double y_offset = sqrt((radius * radius) - ((frac_radius * i) * (frac_radius * i))); - wp_intermediate(0)= wp1.x() + frac_radius * i; - wp_intermediate(1)= wp1.y() - ( y_offset * correct_y ) ; + wp_intermediate(0) = wp1.x() + frac_radius * i; + wp_intermediate(1) = wp1.y() - (y_offset * correct_y) ; - polygon.push_back( wp_intermediate ); - } + polygon.push_back(wp_intermediate); + } - for( int i = 1000 ; i >= 0 ; i-- ){ + for (int i = 1000 ; i >= 0 ; i--) + { - double y_offset = sqrt( ( radius * radius ) - ( (frac_radius * i) * (frac_radius * i) ) ) ; + double y_offset = sqrt((radius * radius) - ((frac_radius * i) * (frac_radius * i))) ; - wp_intermediate(0)= wp1.x() + frac_radius * i; - wp_intermediate(1)= wp1.y() + ( y_offset * correct_y ); + wp_intermediate(0) = wp1.x() + frac_radius * i; + wp_intermediate(1) = wp1.y() + (y_offset * correct_y); - polygon.push_back( wp_intermediate ); - } + polygon.push_back(wp_intermediate); + } - for( int i = 0 ; i <= 1000 ; i++ ){ - double y_offset = sqrt( ( radius * radius ) - ( (frac_radius * i) * (frac_radius * i) ) ); + for (int i = 0 ; i <= 1000 ; i++) + { + double y_offset = sqrt((radius * radius) - ((frac_radius * i) * (frac_radius * i))); - wp_intermediate(0)= wp1.x() - frac_radius * i; - wp_intermediate(1)= wp1.y() + y_offset * correct_y ; + wp_intermediate(0) = wp1.x() - frac_radius * i; + wp_intermediate(1) = wp1.y() + y_offset * correct_y ; - polygon.push_back( wp_intermediate ); - } + polygon.push_back(wp_intermediate); + } - for( int i = 1000 ; i >= 0 ; i-- ){ - double y_offset = sqrt( ( radius * radius ) - ( (frac_radius * i) * (frac_radius * i) ) ); + for (int i = 1000 ; i >= 0 ; i--) + { + double y_offset = sqrt((radius * radius) - ((frac_radius * i) * (frac_radius * i))); - wp_intermediate(0)= wp1.x() - frac_radius * i ; - wp_intermediate(1)= wp1.y() - ( y_offset * correct_y ); + wp_intermediate(0) = wp1.x() - frac_radius * i ; + wp_intermediate(1) = wp1.y() - (y_offset * correct_y); - polygon.push_back( wp_intermediate ); - } + polygon.push_back(wp_intermediate); } + } + std::cout << std::endl; return polygon; - } + } - PolygonType CreateTestStructure::createStructureSeveralSectionsInsideOneVoxelA(std::vector aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createStructureSeveralSectionsInsideOneVoxelA( + std::vector aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - if( aVoxelVector.size() > 0 ) - { - int i=0; + if (aVoxelVector.size() > 0) + { + int i = 0; VoxelGridIndex3D voxelIndex; - voxelIndex(0)=(aVoxelVector.at(i)).x(); - voxelIndex(1)=(aVoxelVector.at(i)).y(); - voxelIndex(2)=sliceNumber; + voxelIndex(0) = (aVoxelVector.at(i)).x(); + voxelIndex(1) = (aVoxelVector.at(i)).y(); + voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; - _geoInfo.indexToWorldCoordinate(voxelIndex,p1); - SpacingVectorType3D delta=_geoInfo.getSpacing(); + _geoInfo.indexToWorldCoordinate(voxelIndex, p1); + SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; - wp1(0)=p1.x(); - wp1(1)=p1.y(); - wp1(2)=p1.z(); + wp1(0) = p1.x(); + wp1(1) = p1.y(); + wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; - wp_intermediate(0)= 0; - wp_intermediate(1)= 0; - wp_intermediate(2)= p1.z(); + wp_intermediate(0) = 0; + wp_intermediate(1) = 0; + wp_intermediate(2) = p1.z(); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.25 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.25); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.25 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.25); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.75 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.75); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.75 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.75); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.25 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.25); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.25 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.25); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 2.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 2.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.75 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.75); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.75 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 3.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.75); + wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() ; - wp_intermediate(1)= wp1.y() + ( delta.y() * 3.0 ); + wp_intermediate(0) = wp1.x() ; + wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() ; - wp_intermediate(1)= wp1.y() + ( delta.y() * 3.0 ); + wp_intermediate(0) = wp1.x() ; + wp_intermediate(1) = wp1.y() + (delta.y() * 3.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() ; - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.75 ); + wp_intermediate(0) = wp1.x() ; + wp_intermediate(1) = wp1.y() + (delta.y() * 0.75); + + polygon.push_back(wp_intermediate); + } - polygon.push_back( wp_intermediate ); - } std::cout << std::endl; return polygon; - } + } - PolygonType CreateTestStructure::createStructureSelfTouchingA(std::vector aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createStructureSelfTouchingA(std::vector + aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - if( aVoxelVector.size() > 0 ) - { - int i=0; + if (aVoxelVector.size() > 0) + { + int i = 0; VoxelGridIndex3D voxelIndex; - voxelIndex(0)=(aVoxelVector.at(i)).x(); - voxelIndex(1)=(aVoxelVector.at(i)).y(); - voxelIndex(2)=sliceNumber; + voxelIndex(0) = (aVoxelVector.at(i)).x(); + voxelIndex(1) = (aVoxelVector.at(i)).y(); + voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; - _geoInfo.indexToWorldCoordinate(voxelIndex,p1); - SpacingVectorType3D delta=_geoInfo.getSpacing(); + _geoInfo.indexToWorldCoordinate(voxelIndex, p1); + SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; - wp1(0)=p1.x(); - wp1(1)=p1.y(); - wp1(2)=p1.z(); + wp1(0) = p1.x(); + wp1(1) = p1.y(); + wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; - wp_intermediate(0)= 0; - wp_intermediate(1)= 0; - wp_intermediate(2)= p1.z(); + wp_intermediate(0) = 0; + wp_intermediate(1) = 0; + wp_intermediate(2) = p1.z(); - wp_intermediate(0)= wp1.x(); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x(); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y(); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y(); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() ; - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() ; + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); + + polygon.push_back(wp_intermediate); + } - polygon.push_back( wp_intermediate ); - } std::cout << std::endl; return polygon; - } + } - PolygonType CreateTestStructure::createStructureSelfTouchingB(std::vector aVoxelVector, GridIndexType sliceNumber){ + PolygonType CreateTestStructure::createStructureSelfTouchingB(std::vector + aVoxelVector, GridIndexType sliceNumber) + { PolygonType polygon; - if( aVoxelVector.size() > 0 ) - { - int i=0; + if (aVoxelVector.size() > 0) + { + int i = 0; VoxelGridIndex3D voxelIndex; - voxelIndex(0)=(aVoxelVector.at(i)).x(); - voxelIndex(1)=(aVoxelVector.at(i)).y(); - voxelIndex(2)=sliceNumber; + voxelIndex(0) = (aVoxelVector.at(i)).x(); + voxelIndex(1) = (aVoxelVector.at(i)).y(); + voxelIndex(2) = sliceNumber; WorldCoordinate3D p1; - _geoInfo.indexToWorldCoordinate(voxelIndex,p1); - SpacingVectorType3D delta=_geoInfo.getSpacing(); + _geoInfo.indexToWorldCoordinate(voxelIndex, p1); + SpacingVectorType3D delta = _geoInfo.getSpacing(); WorldCoordinate3D wp1; - wp1(0)=p1.x(); - wp1(1)=p1.y(); - wp1(2)=p1.z(); + wp1(0) = p1.x(); + wp1(1) = p1.y(); + wp1(2) = p1.z(); WorldCoordinate3D wp_intermediate; - wp_intermediate(0)= 0; - wp_intermediate(1)= 0; - wp_intermediate(2)= p1.z(); + wp_intermediate(0) = 0; + wp_intermediate(1) = 0; + wp_intermediate(2) = p1.z(); - wp_intermediate(0)= wp1.x(); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x(); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y(); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y(); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 1.0 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 1.0); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x(); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x(); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() + ( delta.x() * 0.5 ); - wp_intermediate(1)= wp1.y() + ( delta.y() * 1.0 ); + wp_intermediate(0) = wp1.x() + (delta.x() * 0.5); + wp_intermediate(1) = wp1.y() + (delta.y() * 1.0); - polygon.push_back( wp_intermediate ); + polygon.push_back(wp_intermediate); - wp_intermediate(0)= wp1.x() ; - wp_intermediate(1)= wp1.y() + ( delta.y() * 0.5 ); + wp_intermediate(0) = wp1.x() ; + wp_intermediate(1) = wp1.y() + (delta.y() * 0.5); + + polygon.push_back(wp_intermediate); + } - polygon.push_back( wp_intermediate ); - } std::cout << std::endl; return polygon; - } + } - }//testing - }//rttb + }//testing +}//rttb diff --git a/testing/core/CreateTestStructure.h b/testing/core/CreateTestStructure.h index 01daec3..e8deecf 100644 --- a/testing/core/CreateTestStructure.h +++ b/testing/core/CreateTestStructure.h @@ -1,60 +1,74 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbStructure.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { /*!@class CreateTestStructure - @brief Create dummy structures for testing. + @brief Create dummy structures for testing. */ - class CreateTestStructure{ + class CreateTestStructure + { private: core::GeometricInfo _geoInfo; - CreateTestStructure(){}; + CreateTestStructure() {}; public: ~CreateTestStructure(); CreateTestStructure(const core::GeometricInfo& aGeoInfo); - PolygonType createPolygonLeftUpper(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonCenter(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonBetweenUpperLeftAndCenter(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonBetweenLowerRightAndCenter(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonIntermediatePoints(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonUpperCenter(std::vector aVoxelVector, GridIndexType sliceNumber); - PolygonType createPolygonLeftEdgeMiddle(std::vector aVoxelVector, GridIndexType sliceNumber); + PolygonType createPolygonLeftUpper(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonCenter(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonBetweenUpperLeftAndCenter(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonBetweenLowerRightAndCenter(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonIntermediatePoints(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonUpperCenter(std::vector aVoxelVector, + GridIndexType sliceNumber); + PolygonType createPolygonLeftEdgeMiddle(std::vector aVoxelVector, + GridIndexType sliceNumber); - PolygonType createPolygonCircle(std::vector aVoxelVector, GridIndexType sliceNumber); + PolygonType createPolygonCircle(std::vector aVoxelVector, + GridIndexType sliceNumber); - PolygonType createStructureSeveralSectionsInsideOneVoxelA(std::vector aVoxelVector, GridIndexType sliceNumber); + PolygonType createStructureSeveralSectionsInsideOneVoxelA(std::vector + aVoxelVector, GridIndexType sliceNumber); - PolygonType createStructureSelfTouchingA(std::vector aVoxelVector, GridIndexType sliceNumber); + PolygonType createStructureSelfTouchingA(std::vector aVoxelVector, + GridIndexType sliceNumber); - PolygonType createStructureSelfTouchingB(std::vector aVoxelVector, GridIndexType sliceNumber); - }; - }//testing - }//rttb + PolygonType createStructureSelfTouchingB(std::vector aVoxelVector, + GridIndexType sliceNumber); + }; + }//testing +}//rttb diff --git a/testing/core/DVHCalculatorTest.cpp b/testing/core/DVHCalculatorTest.cpp index c772f62..8e8cc8d 100644 --- a/testing/core/DVHCalculatorTest.cpp +++ b/testing/core/DVHCalculatorTest.cpp @@ -1,127 +1,128 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "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_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! //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 myDVHCalc(spMaskedDoseIterator, structureID, doseID)); //actual calculation is still missing RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHSetTest.cpp b/testing/core/DVHSetTest.cpp index 4ad4577..157efa1 100644 --- a/testing/core/DVHSetTest.cpp +++ b/testing/core/DVHSetTest.cpp @@ -1,177 +1,183 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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)); + 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)); + 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)); + 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}; structureID = structureIDPrefix + "_TV_"; - core::DVH tv = dvhGenerator.generateDVH(structureID + boost::lexical_cast(tvSet.size()), doseID); + 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); DVHRole roleHT = {DVHRole::HealthyTissue}; structureID = structureIDPrefix + "_HT_"; - core::DVH ht = dvhGenerator.generateDVH(structureID + boost::lexical_cast(htSet.size()), doseID); + 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); + 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)); 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)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DVHTest.cpp b/testing/core/DVHTest.cpp index f972a80..a338d42 100644 --- a/testing/core/DVHTest.cpp +++ b/testing/core/DVHTest.cpp @@ -1,189 +1,191 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #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 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); } 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"; //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, + 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, + 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 core::DVH myTestDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID); CHECK_NO_THROW(core::DVH myOtherDVH = myTestDVH); const core::DVH myOtherDVH = myTestDVH; CHECK_NO_THROW(core::DVH aDVH(myOtherDVH)); //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); int percentage = 20; VolumeType absVol = VolumeType(percentage * numberOfVoxels * voxelVolume / 100.0); CHECK_EQUAL(myDVH.getAbsoluteVolume(percentage), absVol); //5) test equality core::DVH myDVH2(aDataDifferential2, binSize, voxelVolume, structureID, doseID); CHECK(!(myDVH == myDVH2)); CHECK_EQUAL(myDVH, myDVH); core::DVH aDVH(myOtherDVH); CHECK_EQUAL(aDVH, myOtherDVH); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/DummyDVHGenerator.h b/testing/core/DummyDVHGenerator.h index f95ba43..ebbfaf4 100644 --- a/testing/core/DummyDVHGenerator.h +++ b/testing/core/DummyDVHGenerator.h @@ -1,68 +1,71 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DUMMY_DVH_GENERATOR_H #define __DUMMY_DVH_GENERATOR_H #include #include "rttbDVH.h" #include "rttbBaseType.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { - /*! @class DummyDVHGenerator + /*! @class DummyDVHGenerator @brief generate DVHs for testing based on a randomly generated dose data vector. */ class DummyDVHGenerator - { - private: - DoseTypeGy _binSize; - DoseVoxelVolumeType _voxelVolume; - DoseCalcType _value; + { + private: + DoseTypeGy _binSize; + DoseVoxelVolumeType _voxelVolume; + DoseCalcType _value; - public: - ~DummyDVHGenerator(){}; + public: + ~DummyDVHGenerator() {}; - DummyDVHGenerator(); + DummyDVHGenerator(); - /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. - The values of the 100 bins are randomly generated [0,1000]. - */ - core::DVH generateDVH(IDType structureID, IDType doseID); + /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. + The values of the 100 bins are randomly generated [0,1000]. + */ + core::DVH generateDVH(IDType structureID, IDType doseID); - /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. - The values of the 100 bins all contain the given value. - */ - core::DVH generateDVH(IDType structureID, IDType doseID, DoseCalcType value); + /*! generate a dummy DVH with bin size = 0.1, voxel volume = 8 and 100 entries. + The values of the 100 bins all contain the given value. + */ + core::DVH generateDVH(IDType structureID, IDType doseID, DoseCalcType value); - /*! generate a dummy DVH with bin size = 0.1, voxel volume = 0.016 and 200 entries. - The values of the 200 bins are random values inside the interval defined by minValue and maxValue. - */ - core::DVH generateDVH(IDType structureID,IDType doseID, DoseCalcType minValue, DoseCalcType maxValue); + /*! generate a dummy DVH with bin size = 0.1, voxel volume = 0.016 and 200 entries. + The values of the 200 bins are random values inside the interval defined by minValue and maxValue. + */ + core::DVH generateDVH(IDType structureID, IDType doseID, DoseCalcType minValue, + DoseCalcType maxValue); - }; - } + }; } +} #endif diff --git a/testing/core/DummyStructure.cpp b/testing/core/DummyStructure.cpp index cd5c3e5..4fef460 100644 --- a/testing/core/DummyStructure.cpp +++ b/testing/core/DummyStructure.cpp @@ -1,635 +1,656 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "DummyStructure.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace testing { DummyStructure::~DummyStructure() {} DummyStructure::DummyStructure(const core::GeometricInfo& aGeoInfo) { _geoInfo = aGeoInfo; } core::Structure DummyStructure::CreateRectangularStructureCentered(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 1); VoxelGridIndex2D another_i2(5, 1); VoxelGridIndex2D another_i3(5, 5); VoxelGridIndex2D another_i4(2, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure_rectangular_centered = core::Structure(another_polySeq); return test_structure_rectangular_centered; } - core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacement(GridIndexType zPlane) + core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacement( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); - PolygonType another_polygon1 = another_cts.createPolygonBetweenUpperLeftAndCenter(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonBetweenUpperLeftAndCenter( + another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight( + core::Structure + DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonSequenceType another_polySeq; core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock( + core::Structure + DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(5, 7); VoxelGridIndex2D another_i3(8, 4); VoxelGridIndex2D another_i4(5, 1); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); - PolygonType another_polygon1 = another_cts.createPolygonBetweenLowerRightAndCenter(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonBetweenLowerRightAndCenter( + another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClockIntermediatePoints( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(5, 7); VoxelGridIndex2D another_i3(8, 4); VoxelGridIndex2D another_i4(5, 1); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); - PolygonType another_polygon1 = another_cts.createPolygonIntermediatePoints(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonIntermediatePoints(another_voxelVector , + zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureSeveralSeperateSectionsInsideOneVoxel(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureSeveralSeperateSectionsInsideOneVoxel( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); another_voxelVector.push_back(another_i1); - PolygonType another_polygon1 = another_cts.createStructureSeveralSectionsInsideOneVoxelA(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createStructureSeveralSectionsInsideOneVoxelA( + another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureSelfTouchingA(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); another_voxelVector.push_back(another_i1); - PolygonType another_polygon1 = another_cts.createStructureSelfTouchingA(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createStructureSelfTouchingA(another_voxelVector , + zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(GridIndexType zPlane1, - GridIndexType zPlane2) + core::Structure DummyStructure::CreateTestStructureIntersectingTwoPolygonsInDifferentSlices( + GridIndexType zPlane1, + GridIndexType zPlane2) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); CreateTestStructure one_more_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(8, 6); VoxelGridIndex2D another_i4(2, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane1); std::vector one_more_voxelVector; VoxelGridIndex2D one_more_i1(3, 5); VoxelGridIndex2D one_more_i2(9, 5); VoxelGridIndex2D one_more_i3(9, 7); VoxelGridIndex2D one_more_i4(3, 7); one_more_voxelVector.push_back(one_more_i1); one_more_voxelVector.push_back(one_more_i2); one_more_voxelVector.push_back(one_more_i3); one_more_voxelVector.push_back(one_more_i4); PolygonType another_polygon2 = one_more_cts.createPolygonCenter(one_more_voxelVector , zPlane2); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); another_polySeq.push_back(another_polygon2); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureIntersectingTwoPolygons(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); CreateTestStructure one_more_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(8, 6); VoxelGridIndex2D another_i4(2, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); std::vector one_more_voxelVector; VoxelGridIndex2D one_more_i1(3, 5); VoxelGridIndex2D one_more_i2(9, 5); VoxelGridIndex2D one_more_i3(9, 7); VoxelGridIndex2D one_more_i4(3, 7); one_more_voxelVector.push_back(one_more_i1); one_more_voxelVector.push_back(one_more_i2); one_more_voxelVector.push_back(one_more_i3); one_more_voxelVector.push_back(one_more_i4); PolygonType another_polygon2 = one_more_cts.createPolygonCenter(one_more_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); another_polySeq.push_back(another_polygon2); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureIntersecting(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(2, 6); VoxelGridIndex2D another_i4(8, 6); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureInsideInsideTouches(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i2(2, 8); VoxelGridIndex2D another_i3(4, 8); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); PolygonType another_polygon1 = another_cts.createPolygonUpperCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedPointDoubeled(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedPointDoubeled( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 4); VoxelGridIndex2D another_i4(2, 4); VoxelGridIndex2D another_i2(4, 4); VoxelGridIndex2D another_i3(3, 8); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); PolygonType another_polygon1 = another_cts.createPolygonUpperCenter(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi( + core::Structure + DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi( GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 5); VoxelGridIndex2D another_i2(3, 5); VoxelGridIndex2D another_i3(7, 6); VoxelGridIndex2D another_i4(7, 6); VoxelGridIndex2D another_i5(7, 4); VoxelGridIndex2D another_i6(7, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); - PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , + zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(7, 5); VoxelGridIndex2D another_i2(7, 5); VoxelGridIndex2D another_i3(3, 6); VoxelGridIndex2D another_i4(3, 6); VoxelGridIndex2D another_i5(3, 4); VoxelGridIndex2D another_i6(3, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); - PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , + zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedQuaterPi(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesRotatedQuaterPi( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i2(3, 4); VoxelGridIndex2D another_i3(3, 6); VoxelGridIndex2D another_i4(3, 6); VoxelGridIndex2D another_i5(7, 5); VoxelGridIndex2D another_i6(7, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); - PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , zPlane); + PolygonType another_polygon1 = another_cts.createPolygonLeftEdgeMiddle(another_voxelVector , + zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } core::Structure DummyStructure::CreateTestStructureCircle(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(4, 4); another_voxelVector.push_back(another_i1); PolygonType another_polygon1 = another_cts.createPolygonCircle(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperRight(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperRight( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 4); VoxelGridIndex2D another_i3(4, 5); VoxelGridIndex2D another_i5(5, 3); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i5); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerRight(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerRight( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(2, 2); VoxelGridIndex2D another_i2(2, 2); VoxelGridIndex2D another_i3(3, 1); VoxelGridIndex2D another_i4(3, 1); VoxelGridIndex2D another_i5(4, 3); VoxelGridIndex2D another_i6(4, 3); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerLeft(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesLowerLeft( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(3, 3); VoxelGridIndex2D another_i2(3, 3); VoxelGridIndex2D another_i3(4, 4); VoxelGridIndex2D another_i4(4, 4); VoxelGridIndex2D another_i5(2, 5); VoxelGridIndex2D another_i6(2, 5); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } - core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperLeft(GridIndexType zPlane) + core::Structure DummyStructure::CreateTestStructureInsideInsideTouchesUpperLeft( + GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 5); VoxelGridIndex2D another_i2(5, 5); VoxelGridIndex2D another_i3(4, 6); VoxelGridIndex2D another_i4(4, 6); VoxelGridIndex2D another_i5(3, 4); VoxelGridIndex2D another_i6(3, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); another_voxelVector.push_back(another_i5); another_voxelVector.push_back(another_i6); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } void DummyStructure::ShowTestStructure(core::Structure aStructure) { WorldCoordinate3D aPoint(0); PolygonSequenceType strVector = aStructure.getStructureVector(); for (unsigned int struct_index = 0 ; struct_index < strVector.size() ; struct_index++) { for (int point_index = 0 ; point_index < strVector.at(struct_index).size() ; point_index++) { aPoint = strVector.at(struct_index).at(point_index); std::cout << " aPoint.x " << aPoint.x() << std::endl; std::cout << " aPoint.y " << aPoint.y() << std::endl; std::cout << " aPoint.z " << aPoint.z() << std::endl; } } } core::Structure DummyStructure::CreateRectangularStructureUpperLeftRotated(GridIndexType zPlane) { CreateTestStructure another_cts = CreateTestStructure(_geoInfo); std::vector another_voxelVector; VoxelGridIndex2D another_i1(5, 1); VoxelGridIndex2D another_i2(8, 4); VoxelGridIndex2D another_i3(5, 7); VoxelGridIndex2D another_i4(2, 4); another_voxelVector.push_back(another_i1); another_voxelVector.push_back(another_i2); another_voxelVector.push_back(another_i3); another_voxelVector.push_back(another_i4); PolygonType another_polygon1 = another_cts.createPolygonLeftUpper(another_voxelVector , zPlane); PolygonSequenceType another_polySeq; another_polySeq.push_back(another_polygon1); core::Structure test_structure = core::Structure(another_polySeq); return test_structure; } }//testing }//rttb diff --git a/testing/core/DummyStructure.h b/testing/core/DummyStructure.h index b142aa8..bdc8894 100644 --- a/testing/core/DummyStructure.h +++ b/testing/core/DummyStructure.h @@ -1,88 +1,101 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "rttbStructure.h" #include "CreateTestStructure.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { /*! @class DummyStructure @brief generate simple geometric testing structures. The maximal x coordinate used is 9 and the maximal y coordinate is 8. Make sure the geometricInfo corresponds to a sufficiently large data grid. @see CreateTestStructures */ - class DummyStructure{ + class DummyStructure + { private: core::GeometricInfo _geoInfo; public: ~DummyStructure(); DummyStructure(const core::GeometricInfo& aGeoInfo); - const core::GeometricInfo& getGeometricInfo(){ + const core::GeometricInfo& getGeometricInfo() + { return _geoInfo; - }; + }; core::Structure CreateRectangularStructureCentered(GridIndexType zPlane); core::Structure CreateTestStructureCircle(GridIndexType zPlane); core::Structure CreateRectangularStructureUpperLeftRotated(GridIndexType zPlane); core::Structure CreateTestStructureSeveralSeperateSectionsInsideOneVoxel(GridIndexType zPlane); - core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacement(GridIndexType zPlane); - core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight(GridIndexType zPlane); - core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock(GridIndexType zPlane); - core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClockIntermediatePoints(GridIndexType zPlane); + core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacement( + GridIndexType zPlane); + core::Structure CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRight( + GridIndexType zPlane); + core::Structure + CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClock( + GridIndexType zPlane); + core::Structure + CreateRectangularStructureCenteredRotatedIntermediatePlacementLowerRightCounterClockIntermediatePoints( + GridIndexType zPlane); core::Structure CreateTestStructureSelfTouchingA(GridIndexType zPlane); core::Structure CreateTestStructureIntersecting(GridIndexType zPlane); core::Structure CreateTestStructureIntersectingTwoPolygons(GridIndexType zPlane); - core::Structure CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(GridIndexType zPlane1, GridIndexType zPlane2); + core::Structure CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(GridIndexType zPlane1, + GridIndexType zPlane2); core::Structure CreateTestStructureInsideInsideTouches(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesRotatedQuaterPi(GridIndexType zPlane); - core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi(GridIndexType zPlane); - core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi(GridIndexType zPlane); + core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedQuaterPi( + GridIndexType zPlane); + core::Structure CreateTestStructureInsideInsideTouchesCounterClockRotatedOnePointFivePi( + GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesRotatedPointDoubeled(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesUpperLeft(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesLowerLeft(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesLowerRight(GridIndexType zPlane); core::Structure CreateTestStructureInsideInsideTouchesUpperRight(GridIndexType zPlane); - void ShowTestStructure( core::Structure aStructure ); - }; - }//testing - }//rttb + void ShowTestStructure(core::Structure aStructure); + }; + }//testing +}//rttb diff --git a/testing/core/GenericDoseIteratorTest.cpp b/testing/core/GenericDoseIteratorTest.cpp index 92b7ef2..b373de6 100644 --- a/testing/core/GenericDoseIteratorTest.cpp +++ b/testing/core/GenericDoseIteratorTest.cpp @@ -1,88 +1,93 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "DummyDoseAccessor.h" -namespace rttb{ - namespace testing{ +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 */ - int GenericDoseIteratorTest(int argc, char* argv[] ) - { + int GenericDoseIteratorTest(int argc, char* argv[]) + { PREPARE_DEFAULT_TEST_REPORTING; //create dummy DoseAccessor boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); //1) test constructor (values as expected?) CHECK_NO_THROW(core::GenericDoseIterator genDoseIterator(spDoseAccessor)); core::GenericDoseIterator genDoseIterator(spDoseAccessor); - const VoxelGridID defaultDoseVoxelGridID = 0; + const VoxelGridID defaultDoseVoxelGridID = 0; const DoseVoxelVolumeType defaultVoxelVolume = 0; CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK_EQUAL(defaultVoxelVolume, genDoseIterator.getCurrentVoxelVolume()); //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_EQUAL(spacing(0)*spacing(1)*spacing(2) / 1000, genDoseIterator.getCurrentVoxelVolume()); //check if the correct voxels are accessed const std::vector* doseVals = spTestDoseAccessor->getDoseVector(); genDoseIterator.reset(); VoxelGridID position = 0; - while (genDoseIterator.isPositionValid()){ + + 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 isPositionValid() in invalid positions CHECK(!(genDoseIterator.isPositionValid())); //after end of dose genDoseIterator.reset(); CHECK_EQUAL(defaultDoseVoxelGridID, genDoseIterator.getCurrentVoxelGridID()); CHECK(genDoseIterator.isPositionValid());//before start of dose RETURN_AND_REPORT_TEST_SUCCESS; - } + } - }//end namespace testing - }//end namespace rttb + }//end namespace testing +}//end namespace rttb diff --git a/testing/core/GenericMaskedDoseIteratorTest.cpp b/testing/core/GenericMaskedDoseIteratorTest.cpp index 9326d1a..c3dd042 100644 --- a/testing/core/GenericMaskedDoseIteratorTest.cpp +++ b/testing/core/GenericMaskedDoseIteratorTest.cpp @@ -1,115 +1,129 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbException.h" #include "DummyDoseAccessor.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); - 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)); - core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor); - - //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 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 +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); + 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)); + core::GenericMaskedDoseIterator genMaskedDoseIterator(spMaskAccessor, spDoseAccessor); + + //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 if the correct voxels are accessed + genMaskedDoseIterator.reset(); + VoxelGridID defaultDoseVoxelGridID = genMaskedDoseIterator.getCurrentVoxelGridID(); + DoseTypeGy controlValue = 0; + VoxelGridID position = 0; + + while (genMaskedDoseIterator.isPositionValid()) + { + controlValue = doseVals->at((maskedVoxelListPtr->at(position)).getVoxelGridID()); + CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentDoseValue()); + controlValue = controlValue * (maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(); + CHECK_EQUAL(controlValue, genMaskedDoseIterator.getCurrentMaskedDoseValue()); + CHECK_EQUAL(homogeneousVoxelVolume, genMaskedDoseIterator.getCurrentVoxelVolume()); + CHECK_EQUAL((maskedVoxelListPtr->at(position)).getRelevantVolumeFraction(), + genMaskedDoseIterator.getCurrentRelevantVolumeFraction()); + CHECK_EQUAL((maskedVoxelListPtr->at(position)).getVoxelGridID(), + genMaskedDoseIterator.getCurrentVoxelGridID()); + CHECK(genMaskedDoseIterator.isPositionValid()); + + genMaskedDoseIterator.next(); + position++; + } + + //check isPositionValid() in invalid positions + CHECK(!(genMaskedDoseIterator.isPositionValid())); //after end of dose + genMaskedDoseIterator.reset(); + CHECK_EQUAL(defaultDoseVoxelGridID, genMaskedDoseIterator.getCurrentVoxelGridID()); + CHECK(genMaskedDoseIterator.isPositionValid());//at start of dose + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + + + }//testing }//rttb diff --git a/testing/core/GeometricInfoTest.cpp b/testing/core/GeometricInfoTest.cpp index 84d1019..f27ae3e 100644 --- a/testing/core/GeometricInfoTest.cpp +++ b/testing/core/GeometricInfoTest.cpp @@ -1,433 +1,434 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGeometricInfo.h" namespace rttb { namespace testing { /*!@brief GeometricInfoTest - test the API of GeometricInfo @note ITK pixel indexing: Index[0] = col, Index[1] = row, Index[2] = slice. 1) test default constructor (values as expected?) 2) test set/getImagePositionPatient 3) test set/getPixelSpacingColumn/Row/SliceThickness 4) test set/getSpacing 5) test set/getNumColumns/Rows/Slices 6) test get/setOrientationMatrix 7) test getImageOrientationRow/Column 8) test operators "==" 9) test equalsAlmost 10) test world to index coordinate conversion 11) test isInside and index to world coordinate conversion 12) test getNumberOfVoxels 13) Test convert, validID and validIndex */ int GeometricInfoTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test default constructor (values as expected?) CHECK_NO_THROW(core::GeometricInfo()); core::GeometricInfo geoInfo; SpacingVectorType3D testNullSV(0); WorldCoordinate3D testNullWC(0); OrientationMatrix testNullOM(0); CHECK_EQUAL(testNullSV, geoInfo.getSpacing()); CHECK_EQUAL(testNullWC, geoInfo.getImagePositionPatient()); CHECK_EQUAL(testNullOM, geoInfo.getOrientationMatrix()); //2) test set/getImagePositionPatient WorldCoordinate3D testIPP(1.2, 3.4, 5.6); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); geoInfo.setImagePositionPatient(testIPP); CHECK_EQUAL(testIPP, geoInfo.getImagePositionPatient()); //3) test set/getPixelSpacingColumn/Row/SliceThickness SpacingVectorType3D expectedSpacing(1, 2.2, 3.3); CHECK_NO_THROW(geoInfo.setPixelSpacingRow(expectedSpacing(0))); CHECK_EQUAL(expectedSpacing(0), geoInfo.getPixelSpacingRow()); CHECK_EQUAL(SpacingVectorType3D(expectedSpacing(0), 0, 0), geoInfo.getSpacing()); CHECK_EQUAL(geoInfo.getPixelSpacingRow(), geoInfo.getSpacing()(0)); CHECK_NO_THROW(geoInfo.setPixelSpacingColumn(expectedSpacing(1))); CHECK_EQUAL(expectedSpacing(1), geoInfo.getPixelSpacingColumn()); CHECK_EQUAL(SpacingVectorType3D(expectedSpacing(0), expectedSpacing(1), 0), geoInfo.getSpacing()); CHECK_EQUAL(geoInfo.getPixelSpacingColumn(), geoInfo.getSpacing()(1)); CHECK_NO_THROW(geoInfo.setSliceThickness(expectedSpacing(2))); CHECK_EQUAL(expectedSpacing(2), geoInfo.getSliceThickness()); CHECK_EQUAL(expectedSpacing, geoInfo.getSpacing()); CHECK_EQUAL(geoInfo.getSliceThickness(), geoInfo.getSpacing()(2)); //4) test set/getSpacing //negative spacing does not make sense! /*!@is related to #2028 Should SpacingTypeVector/GridVolumeType/OrientationMatrix be forced to be non-negative?*/ expectedSpacing(0) = 4.15; expectedSpacing(1) = 2.35; expectedSpacing(2) = 100; CHECK_NO_THROW(geoInfo.setSpacing(expectedSpacing)); geoInfo.setSpacing(expectedSpacing); CHECK_EQUAL(expectedSpacing, geoInfo.getSpacing()); //5) test set/getNumColumns/Rows/Slices const VoxelGridIndex3D expectedVoxelDims(10, 5, 3); //CHECK_THROW(geoInfo.setNumColumns(1.2)); -> implicit conversion will prevent exception CHECK_NO_THROW(geoInfo.setNumColumns(expectedVoxelDims(0))); geoInfo.setNumColumns(expectedVoxelDims(0)); CHECK_NO_THROW(geoInfo.setNumRows(expectedVoxelDims(1))); geoInfo.setNumRows(expectedVoxelDims(1)); //CHECK_THROW(geoInfo.setNumSlices(4.2)); -> implicit conversion will prevent exception CHECK_NO_THROW(geoInfo.setNumSlices(expectedVoxelDims(2))); geoInfo.setNumSlices(expectedVoxelDims(2)); ImageSize rttbSize = geoInfo.getImageSize(); CHECK_EQUAL(rttbSize(0), geoInfo.getNumColumns()); CHECK_EQUAL(rttbSize(1), geoInfo.getNumRows()); CHECK_EQUAL(rttbSize(2), geoInfo.getNumSlices()); rttbSize = ImageSize(11, 99, 6); core::GeometricInfo geoInfo3; geoInfo3.setImageSize(rttbSize); CHECK_EQUAL(rttbSize(0), geoInfo3.getNumColumns()); CHECK_EQUAL(rttbSize(1), geoInfo3.getNumRows()); CHECK_EQUAL(rttbSize(2), geoInfo3.getNumSlices()); //6) test get/setOrientationMatrix CHECK_EQUAL(testNullOM, geoInfo.getOrientationMatrix()); OrientationMatrix testOM(0); const WorldCoordinate3D testIORow(5.5, 4.7, 3.2); const WorldCoordinate3D testIOColumn(2.5, 1.8, 9.1); WorldCoordinate3D ortho = testIORow.cross(testIOColumn); testOM(0, 0) = testIORow(0); testOM(1, 0) = testIORow(1); testOM(2, 0) = testIORow(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); testOM(0, 1) = testIOColumn(0); testOM(1, 1) = testIOColumn(1); testOM(2, 1) = testIOColumn(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); testOM(0, 2) = ortho(0); testOM(1, 2) = ortho(1); testOM(2, 2) = ortho(2); CHECK_NO_THROW(geoInfo.setOrientationMatrix(testOM)); geoInfo.setOrientationMatrix(testOM); CHECK_EQUAL(testOM, geoInfo.getOrientationMatrix()); //7) test getImageOrientationRow/Column CHECK_EQUAL(testIORow, geoInfo.getImageOrientationRow()); CHECK_EQUAL(testIOColumn, geoInfo.getImageOrientationColumn()); //8) test operators "==" core::GeometricInfo geoInfo2; CHECK_EQUAL(geoInfo, geoInfo); CHECK(!(geoInfo == geoInfo2)); CHECK_EQUAL(geoInfo.getOrientationMatrix(), testOM); CHECK(!(geoInfo.getOrientationMatrix() == testNullOM)); //9) test equalsALmost OrientationMatrix testOM2 = testOM; SpacingVectorType3D testSPV2 = expectedSpacing; WorldCoordinate3D testIPP2 = testIPP; core::GeometricInfo testGI2, testGIEmpty; testGI2.setImagePositionPatient(testIPP2); testGI2.setOrientationMatrix(testOM2); testGI2.setSpacing(testSPV2); double smallValue = 0.000000001; testOM(0, 0) += smallValue; testSPV2(2) += smallValue; testIPP2(1) += smallValue; core::GeometricInfo testGI2similar; testGI2similar.setImagePositionPatient(testIPP2); testGI2similar.setOrientationMatrix(testOM2); testGI2similar.setSpacing(testSPV2); CHECK_EQUAL(testGI2.equalsAlmost(testGI2similar), true); CHECK_EQUAL(testGI2similar.equalsAlmost(testGI2), true); CHECK_EQUAL(testGI2.equalsAlmost(testGI2similar, smallValue * 0.001), false); CHECK_EQUAL(testGIEmpty.equalsAlmost(testGI2), false); CHECK_EQUAL(testGI2.equalsAlmost(testGIEmpty), false); //10) test world to index coordinate conversion //use unit matrix as orientation matrix CHECK_NO_THROW(geoInfo.setOrientationMatrix(OrientationMatrix())); //origin (inside) WorldCoordinate3D insideTestWC1 = geoInfo.getImagePositionPatient(); //inside const VoxelGridIndex3D expectedIndex(8, 3, 2); WorldCoordinate3D insideTestWC2(expectedIndex(0)*expectedSpacing(0) + testIPP(0), expectedIndex(1)*expectedSpacing(1) + testIPP(1), expectedIndex(2)*expectedSpacing(2) + testIPP(2)); //outside WorldCoordinate3D insideTestWC3(-33.12, 0, 14); // outside (dimension of grid) WorldCoordinate3D insideTestWC4(expectedVoxelDims(0)*expectedSpacing(0) + testIPP(0), expectedVoxelDims(1)*expectedSpacing(1) + testIPP(1), expectedVoxelDims(2)*expectedSpacing(2) + testIPP(2)); CHECK(geoInfo.isInside(insideTestWC1)); CHECK(geoInfo.isInside(insideTestWC2)); CHECK(!(geoInfo.isInside(insideTestWC3))); CHECK(!(geoInfo.isInside(insideTestWC4))); VoxelGridIndex3D testConvert(0); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC1, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(VoxelGridIndex3D(0), testConvert); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC2, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndex, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC3, testConvert))); //CHECK_EQUAL(VoxelGridIndex3D(0),testConvert); //if value is in a negative grid position it will be converted //to a very large unrelated number. CHECK(!(geoInfo.isInside(testConvert))); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC4, testConvert))); CHECK_EQUAL(expectedVoxelDims, testConvert); CHECK(!(geoInfo.isInside(testConvert))); //use a more complicated orientation matrix OrientationMatrix newOrientation(0); newOrientation(0, 0) = 0.5; newOrientation(1, 2) = -3; newOrientation(2, 1) = 1; CHECK_NO_THROW(geoInfo.setOrientationMatrix(newOrientation)); testIPP = WorldCoordinate3D(20, 100, -1000); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); CHECK_NO_THROW(geoInfo.setSpacing(SpacingVectorType3D(1))); //values for testing were generated with a dedicated MeVisLab routine insideTestWC1 = geoInfo.getImagePositionPatient(); //origin (inside) const VoxelGridIndex3D expectedIndexWC1(0, 0, 0); insideTestWC2 = WorldCoordinate3D(22.5, 97, -998); //inside const VoxelGridIndex3D expectedIndexWC2(5, 2, 1); insideTestWC3 = WorldCoordinate3D(26, 88, -996); //outside const VoxelGridIndex3D expectedIndexWC3(12, 4, 4); insideTestWC4 = WorldCoordinate3D(25, 91, -995); // outside: Grid dimension = [10,5,3] const VoxelGridIndex3D expectedIndexWC4(10, 5, 3); CHECK(geoInfo.isInside(insideTestWC1)); CHECK_EQUAL(geoInfo.isInside(insideTestWC1), geoInfo.isInside(expectedIndexWC1)); CHECK(geoInfo.isInside(insideTestWC2)); CHECK_EQUAL(geoInfo.isInside(insideTestWC2), geoInfo.isInside(expectedIndexWC2)); CHECK(!(geoInfo.isInside(insideTestWC3))); CHECK_EQUAL(geoInfo.isInside(insideTestWC3), geoInfo.isInside(expectedIndexWC3)); CHECK(!(geoInfo.isInside(insideTestWC4))); CHECK_EQUAL(geoInfo.isInside(insideTestWC4), geoInfo.isInside(expectedIndexWC4)); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC1, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndexWC1, testConvert); CHECK(geoInfo.worldCoordinateToIndex(insideTestWC2, testConvert)); CHECK(geoInfo.isInside(testConvert)); CHECK_EQUAL(expectedIndexWC2, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC3, testConvert))); CHECK(!(geoInfo.isInside(testConvert))); CHECK_EQUAL(expectedIndexWC3, testConvert); CHECK(!(geoInfo.worldCoordinateToIndex(insideTestWC4, testConvert))); CHECK(!(geoInfo.isInside(testConvert))); CHECK_EQUAL(expectedIndexWC4, testConvert); //11) test isInside and index to world coordinate conversion //use unit matrix as orientation matrix CHECK_NO_THROW(geoInfo.setOrientationMatrix(OrientationMatrix())); VoxelGridIndex3D insideTest1(0, 0, 0); //origin (inside) VoxelGridIndex3D insideTest2(2, 3, 1); //inside VoxelGridIndex3D insideTest3(0, 6, 14); //outside VoxelGridIndex3D insideTest4 = expectedVoxelDims; // outside CHECK(geoInfo.isInside(insideTest1)); CHECK(geoInfo.isInside(insideTest2)); CHECK(!(geoInfo.isInside(insideTest3))); CHECK(!(geoInfo.isInside(insideTest4))); WorldCoordinate3D testInside(0); CHECK(geoInfo.indexToWorldCoordinate(insideTest1, testInside)); CHECK(geoInfo.isInside(testInside)); //CHECK_EQUAL(geoInfo.getImagePositionPatient(),testInside); //half voxel shift prevents equality! CHECK(geoInfo.indexToWorldCoordinate(insideTest2, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest3, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest4, testInside))); CHECK(!(geoInfo.isInside(testInside))); - - DoubleVoxelGridIndex3D doubleIndex1 = DoubleVoxelGridIndex3D(0.1, 0, -0.3); + + DoubleVoxelGridIndex3D doubleIndex1 = DoubleVoxelGridIndex3D(0.1, 0, -0.3); const WorldCoordinate3D expectedDoubleIndex1(20.1, 100, -1000.3); DoubleVoxelGridIndex3D doubleIndex2 = DoubleVoxelGridIndex3D(11, 6, 15); //outside const WorldCoordinate3D expectedDoubleIndex2(31, 106, -985); - DoubleVoxelGridIndex3D doubleIndex3 = DoubleVoxelGridIndex3D(9.6, 5.0, 3.0); // outside: Grid dimension = [10,5,3] + DoubleVoxelGridIndex3D doubleIndex3 = DoubleVoxelGridIndex3D(9.6, 5.0, + 3.0); // outside: Grid dimension = [10,5,3] const WorldCoordinate3D expectedDoubleIndex3(29.6, 105, -997); - DoubleVoxelGridIndex3D doubleIndex4 = DoubleVoxelGridIndex3D(0.0, 0.0, 0.0); + DoubleVoxelGridIndex3D doubleIndex4 = DoubleVoxelGridIndex3D(0.0, 0.0, 0.0); const WorldCoordinate3D expectedDoubleIndex4 = geoInfo.getImagePositionPatient(); //test double index to world coordinate WorldCoordinate3D test; geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex1, test); CHECK_EQUAL(test, expectedDoubleIndex1); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex2, test); CHECK_EQUAL(test, expectedDoubleIndex2); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex3, test); CHECK_EQUAL(test, expectedDoubleIndex3); geoInfo.geometryCoordinateToWorldCoordinate(doubleIndex4, test); CHECK_EQUAL(test, expectedDoubleIndex4); DoubleVoxelGridIndex3D testDoubleIndex; geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex4, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndex4); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex3, testDoubleIndex); CHECK_CLOSE(testDoubleIndex(0), doubleIndex3(0), errorConstant); CHECK_CLOSE(testDoubleIndex(1), doubleIndex3(1), errorConstant); CHECK_CLOSE(testDoubleIndex(2), doubleIndex3(2), errorConstant); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex2, testDoubleIndex); CHECK_EQUAL(testDoubleIndex, doubleIndex2); geoInfo.worldCoordinateToGeometryCoordinate(expectedDoubleIndex1, testDoubleIndex); CHECK_CLOSE(testDoubleIndex(0), doubleIndex1(0), errorConstant); CHECK_CLOSE(testDoubleIndex(1), doubleIndex1(1), errorConstant); CHECK_CLOSE(testDoubleIndex(2), doubleIndex1(2), errorConstant); VoxelGridIndex3D testIntIndex; geoInfo.worldCoordinateToIndex(expectedDoubleIndex4, testIntIndex); CHECK_EQUAL(testIntIndex, insideTest1); geoInfo.worldCoordinateToIndex(expectedDoubleIndex1, testIntIndex); CHECK_EQUAL(testIntIndex, insideTest1); geoInfo.worldCoordinateToIndex(expectedDoubleIndex3, testIntIndex); CHECK_EQUAL(testIntIndex, expectedVoxelDims); //use a more complicated orientation matrix newOrientation = OrientationMatrix(0); newOrientation(0, 0) = 0.5; newOrientation(1, 2) = -3; newOrientation(2, 1) = 1; CHECK_NO_THROW(geoInfo.setOrientationMatrix(newOrientation)); testIPP = WorldCoordinate3D(20, 100, -1000); CHECK_NO_THROW(geoInfo.setImagePositionPatient(testIPP)); CHECK_NO_THROW(geoInfo.setSpacing(SpacingVectorType3D(1))); //values for testing were generated with a dedicated MeVisLab routine //expected world coordinates need to accommodate the half voxel shift //caused by the use of the central position in the voxel for conversion. insideTest1 = VoxelGridIndex3D(0, 0, 0); //origin (inside) const WorldCoordinate3D expectedIndex1(19.75, 101.5, -1000.5); insideTest2 = VoxelGridIndex3D(6, 0, 2); //inside const WorldCoordinate3D expectedIndex2(22.75, 95.5, -1000.5); insideTest3 = VoxelGridIndex3D(11, 6, 15); //outside const WorldCoordinate3D expectedIndex3(25.25, 56.5, -994.5); insideTest4 = VoxelGridIndex3D(10, 5, 3); // outside: Grid dimension = [10,5,3] const WorldCoordinate3D expectedIndex4(24.75, 92.5, -995.5); CHECK(geoInfo.isInside(insideTest1)); CHECK_EQUAL(geoInfo.isInside(insideTest1), geoInfo.isInside(expectedIndex1)); CHECK(geoInfo.isInside(insideTest2)); CHECK_EQUAL(geoInfo.isInside(insideTest2), geoInfo.isInside(expectedIndex2)); CHECK(!(geoInfo.isInside(insideTest3))); CHECK_EQUAL(geoInfo.isInside(insideTest3), geoInfo.isInside(expectedIndex3)); CHECK(!(geoInfo.isInside(insideTest4))); CHECK_EQUAL(geoInfo.isInside(insideTest4), geoInfo.isInside(expectedIndex4)); CHECK(geoInfo.indexToWorldCoordinate(insideTest1, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK_EQUAL(expectedIndex1, testInside); CHECK(geoInfo.indexToWorldCoordinate(insideTest2, testInside)); CHECK(geoInfo.isInside(testInside)); CHECK_EQUAL(expectedIndex2, testInside); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest3, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK_EQUAL(expectedIndex3, testInside); CHECK(!(geoInfo.indexToWorldCoordinate(insideTest4, testInside))); CHECK(!(geoInfo.isInside(testInside))); CHECK_EQUAL(expectedIndex4, testInside); - + //12) test getNumberOfVoxels CHECK_EQUAL(expectedVoxelDims(0)*expectedVoxelDims(1)*expectedVoxelDims(2), geoInfo.getNumberOfVoxels()); //13) Test convert, validID and validIndex geoInfo.setNumColumns(50); geoInfo.setNumRows(30); geoInfo.setNumSlices(40); VoxelGridIndex3D startIndex(0, 0, 0); VoxelGridID startId(0); VoxelGridIndex3D endIndex(geoInfo.getNumColumns() - 1, geoInfo.getNumRows() - 1, geoInfo.getNumSlices() - 1); VoxelGridID endId((geoInfo.getNumColumns()*geoInfo.getNumRows()*geoInfo.getNumSlices()) - 1); VoxelGridIndex3D indexInvalid(geoInfo.getNumColumns(), geoInfo.getNumRows(), geoInfo.getNumSlices()); VoxelGridID idInvalid(geoInfo.getNumColumns()*geoInfo.getNumRows()*geoInfo.getNumSlices()); CHECK(geoInfo.validID(startId)); CHECK(geoInfo.validIndex(startIndex)); VoxelGridIndex3D aIndex; VoxelGridID aId; CHECK(geoInfo.convert(startIndex, aId)); CHECK(geoInfo.convert(startId, aIndex)); CHECK_EQUAL(aId, startId); CHECK_EQUAL(aIndex, startIndex); CHECK(geoInfo.validID(endId)); CHECK(geoInfo.validIndex(endIndex)); CHECK(geoInfo.convert(endIndex, aId)); CHECK(geoInfo.convert(endId, aIndex)); CHECK_EQUAL(aId, endId); CHECK_EQUAL(aIndex, endIndex); CHECK(!geoInfo.validID(idInvalid)); CHECK(!geoInfo.validIndex(indexInvalid)); CHECK(!geoInfo.convert(idInvalid, aIndex)); CHECK(!geoInfo.convert(indexInvalid, aId)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/core/MaskVoxelTest.cpp b/testing/core/MaskVoxelTest.cpp index 7d35df4..ffc3b2d 100644 --- a/testing/core/MaskVoxelTest.cpp +++ b/testing/core/MaskVoxelTest.cpp @@ -1,102 +1,109 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (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{ +namespace rttb +{ + namespace testing + { /*! @brief MaskVoxelTest - test the API of MaskVoxel 1) test constructors (values as expected?) 2) test set/getRelevantVolumeFraction 3) test legacy access - 4) test operators "==" + 4) test operators "==" */ - int MaskVoxelTest(int argc, char* argv[] ) - { + 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); + 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 + //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); + 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()); + CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); //3) test legacy access aFraction = aMaskVoxel3.getRelevantVolumeFraction(); anID = aMaskVoxel3.getVoxelGridID(); CHECK_EQUAL(aFraction, aMaskVoxel3.getProportionInStr()); CHECK_EQUAL(aMaskVoxel3.getProportionInStr(), aMaskVoxel3.getRelevantVolumeFraction()); aFraction = 0.84; CHECK_NO_THROW(aMaskVoxel3.setProportionInStr(aFraction)); CHECK_THROW_EXPLICIT(aMaskVoxel3.setProportionInStr(-aFraction), core::InvalidParameterException); - CHECK_THROW_EXPLICIT(aMaskVoxel3.setProportionInStr(aFraction+2), core::InvalidParameterException); + CHECK_THROW_EXPLICIT(aMaskVoxel3.setProportionInStr(aFraction + 2), + core::InvalidParameterException); aMaskVoxel3.setProportionInStr(aFraction); CHECK_EQUAL(anID, aMaskVoxel3.getVoxelGridID()); - CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); + CHECK_EQUAL(aFraction, aMaskVoxel3.getRelevantVolumeFraction()); - //4) test operators "==" + //4) 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 RETURN_AND_REPORT_TEST_SUCCESS; - } + } - }//end namespace testing - }//end namespace rttb + }//end namespace testing +}//end namespace rttb diff --git a/testing/core/StrVectorStructureSetGeneratorTest.cpp b/testing/core/StrVectorStructureSetGeneratorTest.cpp index 765acf8..8ff82aa 100644 --- a/testing/core/StrVectorStructureSetGeneratorTest.cpp +++ b/testing/core/StrVectorStructureSetGeneratorTest.cpp @@ -1,80 +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) */ #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{ +namespace rttb +{ + namespace testing + { /*! @brief StructureTest - tests the API for Structure 1) constructors 2) get/setXX */ - int StrVectorStructureSetGeneratorTest(int argc, char* argv[] ) + 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); + 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(); + 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); + 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)); + CHECK_EQUAL(core::StrVectorStructureSetGenerator( + strVector).generateStructureSet()->getNumberOfStructures(), 1); + CHECK_NO_THROW(core::StrVectorStructureSetGenerator(strVector).generateStructureSet()->getStructure( + 0)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/core/StructureTest.cpp b/testing/core/StructureTest.cpp index b46361e..42b550a 100644 --- a/testing/core/StructureTest.cpp +++ b/testing/core/StructureTest.cpp @@ -1,129 +1,138 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbInvalidParameterException.h" #include "DummyStructure.h" #include "DummyDoseAccessor.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { /*! @brief StructureTest - tests the API for Structure 1) constructors 2) get/setXX */ - int StructureTest(int argc, char* argv[] ) - { + int StructureTest(int argc, char* argv[]) + { PREPARE_DEFAULT_TEST_REPORTING; - boost::shared_ptr spTestDoseAccessor = - boost::make_shared(); + boost::shared_ptr spTestDoseAccessor = + boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); //1) constructors CHECK_NO_THROW(core::Structure()); core::Structure emptyTestStruct; - CHECK_EQUAL("None",emptyTestStruct.getLabel()); + CHECK_EQUAL("None", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.getUID()); GridIndexType zPlane = 4; core::Structure rect = myStructGenerator.CreateRectangularStructureCentered(zPlane); CHECK_NO_THROW(core::Structure(rect.getStructureVector())); core::Structure rect2 = core::Structure(rect.getStructureVector()); - CHECK_EQUAL(rect.getLabel(),rect2.getLabel()); - CHECK(rect.getUID()!=rect2.getUID()); + CHECK_EQUAL(rect.getLabel(), rect2.getLabel()); + CHECK(rect.getUID() != rect2.getUID()); PolygonSequenceType rectVec = rect.getStructureVector(); PolygonSequenceType rect2Vec = rect2.getStructureVector(); - CHECK_EQUAL(rectVec.size(),rect2Vec.size()); + CHECK_EQUAL(rectVec.size(), rect2Vec.size()); PolygonSequenceType::iterator it = rectVec.begin(); PolygonSequenceType::iterator it2 = rect2Vec.begin(); - for (; it!=rectVec.end(); it++) - { - CHECK_EQUAL(it->size(),it2->size()); + + for (; it != rectVec.end(); it++) + { + CHECK_EQUAL(it->size(), it2->size()); PolygonType::iterator pit = it->begin(); PolygonType::iterator pit2 = it2->begin(); - for(;pit!=it->end();pit++) - { - CHECK_EQUAL(*(pit),*(pit2)); + + for (; pit != it->end(); pit++) + { + CHECK_EQUAL(*(pit), *(pit2)); pit2++; - } - it2++; } + it2++; + } + CHECK_NO_THROW(core::Structure rect3 = rect); core::Structure rect3 = rect; - CHECK_EQUAL(rect.getLabel(),rect3.getLabel()); - CHECK_EQUAL(rect.getUID(),rect3.getUID()); + CHECK_EQUAL(rect.getLabel(), rect3.getLabel()); + CHECK_EQUAL(rect.getUID(), rect3.getUID()); PolygonSequenceType rect3Vec = rect3.getStructureVector(); - CHECK_EQUAL(rectVec.size(),rect3Vec.size()); + CHECK_EQUAL(rectVec.size(), rect3Vec.size()); it = rectVec.begin(); PolygonSequenceType::iterator it3 = rect3Vec.begin(); - for (; it!=rectVec.end(); it++) - { - CHECK_EQUAL(it->size(),it3->size()); + + for (; it != rectVec.end(); it++) + { + CHECK_EQUAL(it->size(), it3->size()); PolygonType::iterator pit = it->begin(); PolygonType::iterator pit3 = it3->begin(); - for(;pit!=it->end();pit++) - { - CHECK_EQUAL(*(pit),*(pit3)); + + for (; pit != it->end(); pit++) + { + CHECK_EQUAL(*(pit), *(pit3)); pit3++; - } - it3++; } + it3++; + } + //2) get/setXX - CHECK_EQUAL("None",emptyTestStruct.getLabel()); + CHECK_EQUAL("None", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.setLabel("NEW Label")); - CHECK_EQUAL("NEW Label",emptyTestStruct.getLabel()); + CHECK_EQUAL("NEW Label", emptyTestStruct.getLabel()); CHECK_NO_THROW(emptyTestStruct.getUID()); CHECK_NO_THROW(emptyTestStruct.setUID("1.2.345.67.8.9")); - CHECK_EQUAL("1.2.345.67.8.9",emptyTestStruct.getUID()); + CHECK_EQUAL("1.2.345.67.8.9", emptyTestStruct.getUID()); CHECK((emptyTestStruct.getStructureVector()).empty()); - CHECK_EQUAL(0,emptyTestStruct.getNumberOfEndpoints()); + CHECK_EQUAL(0, emptyTestStruct.getNumberOfEndpoints()); - CHECK_EQUAL(4,rect.getNumberOfEndpoints()); - CHECK_EQUAL(rect.getNumberOfEndpoints(),rect2.getNumberOfEndpoints()); + CHECK_EQUAL(4, rect.getNumberOfEndpoints()); + CHECK_EQUAL(rect.getNumberOfEndpoints(), rect2.getNumberOfEndpoints()); core::Structure circ = myStructGenerator.CreateTestStructureCircle(zPlane); - CHECK_EQUAL(4004,circ.getNumberOfEndpoints()); + CHECK_EQUAL(4004, circ.getNumberOfEndpoints()); - core::Structure multiPoly = myStructGenerator.CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(zPlane, zPlane+1); - CHECK_EQUAL(8,multiPoly.getNumberOfEndpoints()); + core::Structure multiPoly = + myStructGenerator.CreateTestStructureIntersectingTwoPolygonsInDifferentSlices(zPlane, zPlane + 1); + CHECK_EQUAL(8, multiPoly.getNumberOfEndpoints()); RETURN_AND_REPORT_TEST_SUCCESS; - } + } - }//testing - }//rttb \ No newline at end of file + }//testing +}//rttb \ No newline at end of file diff --git a/testing/core/rttbCoreHeaderTest.cpp b/testing/core/rttbCoreHeaderTest.cpp index 5bfdd22..8f34c63 100644 --- a/testing/core/rttbCoreHeaderTest.cpp +++ b/testing/core/rttbCoreHeaderTest.cpp @@ -1,65 +1,65 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include #include "../../code/core/rttbBaseType_NEW.h" #include "../../code/core/rttbClinicalTrial.h" #include "../../code/core/rttbDoseAccessorInterface_NEW.h" #include "../../code/core/rttbDVH.h" #include "../../code/core/rttbDVHCalculator.h" #include "../../code/core/rttbDVHGeneratorInterface.h" #include "../../code/core/rttbDVHSet.h" #include "../../code/core/rttbException.h" #include "../../code/core/rttbField.h" #include "../../code/core/rttbFraction.h" #include "../../code/core/rttbFractionManager.h" #include "../../code/core/rttbGenericDoseIterator_NEW.h" #include "../../code/core/rttbGenericMaskedDoseIterator_NEW.h" #include "../../code/core/rttbGeometricInfo_NEW.h" #include "../../code/core/rttbImage.h" #include "../../code/core/rttbIndexConversionInterface_NEW.h" #include "../../code/core/rttbIndexOutOfBoundsException.h" #include "../../code/core/rttbInvalidDoseException.h" #include "../../code/core/rttbInvalidParameterException.h" #include "../../code/core/rttbMaskAccessorInterface_NEW.h" #include "../../code/core/rttbMaskedDoseIteratorInterface_NEW.h" #include "../../code/core/rttbMaskVoxel_NEW.h" #include "../../code/core/rttbNullPointerException.h" #include "../../code/core/rttbPatient.h" #include "../../code/core/rttbPhysicalInfo.h" #include "../../code/core/rttbPlan.h" #include "../../code/core/rttbSelfIntersectingStructureException.h" #include "../../code/core/rttbStructure.h" #include "../../code/core/rttbStructureSetInterface.h" #include "../../code/core/rttbTherapy.h" #include "../../code/core/rttbTreatmentCourse.h" -int main ( int , char* ) +int main(int , char*) { - - return EXIT_SUCCESS; + + return EXIT_SUCCESS; } diff --git a/testing/core/rttbCoreTests.cpp b/testing/core/rttbCoreTests.cpp index 78d20e6..7502b20 100644 --- a/testing/core/rttbCoreTests.cpp +++ b/testing/core/rttbCoreTests.cpp @@ -1,69 +1,71 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif -#include "litMultiTestsMain.h" +#include "litMultiTestsMain.h" -namespace rttb{ - namespace testing{ +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(StrVectorStructureSetGeneratorTest); } } +} int main(int argc, char* argv[]) - { +{ int result = 0; rttb::testing::registerTests(); try - { - result = lit::multiTestsMain(argc,argv); - } + { + result = lit::multiTestsMain(argc, argv); + } - catch(...) - { + catch (...) + { result = -1; - } + } return result; - } +} diff --git a/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp b/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp index d17a6ba..d439d8e 100644 --- a/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolBasicUsageTest.cpp @@ -1,75 +1,75 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseToolBasicUsageTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; if (argc > 1) { doseToolExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; //call without parameters std::cout << "Command line call: " + doseToolExeWithPath << std::endl; - CHECK_EQUAL(system(doseToolExeWithPath.c_str())!=0, true); + CHECK_EQUAL(system(doseToolExeWithPath.c_str()) != 0, true); //call with help parameters std::string helpCommandShort = doseToolExeWithPath + " -h"; std::string helpCommandLong = doseToolExeWithPath + " --help"; std::cout << "Command line call: " + helpCommandShort << std::endl; CHECK_EQUAL(system(helpCommandShort.c_str()), 0); std::cout << "Command line call: " + helpCommandLong << std::endl; CHECK_EQUAL(system(helpCommandLong.c_str()), 0); //call with version parameter std::string versionCommandShort = doseToolExeWithPath + " -v"; std::string versionCommandLong = doseToolExeWithPath + " --version"; std::cout << "Command line call: " + versionCommandShort << std::endl; CHECK_EQUAL(system(versionCommandShort.c_str()), 0); std::cout << "Command line call: " + versionCommandLong << std::endl; CHECK_EQUAL(system(versionCommandLong.c_str()), 0); //call with RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolDVHTest.cpp b/testing/demoapps/DoseTool/DoseToolDVHTest.cpp index d76702e..b5e9425 100644 --- a/testing/demoapps/DoseTool/DoseToolDVHTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDVHTest.cpp @@ -1,106 +1,107 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolDVHTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string planFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 5) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; } - std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; + std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + + doseToolExecutable; std::string defaultOutputFilename = "dicomDVHOutput.xml"; std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } std::string defaultDVHCommand = baseCommand + " -z " + defaultOutputFilename; std::cout << "Command line call: " + defaultDVHCommand << std::endl; CHECK_EQUAL(system(defaultDVHCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); CHECK_EQUAL(defaultAsIs, defaultExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp index e415bdc..7679251 100644 --- a/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolDicomDoseTest.cpp @@ -1,149 +1,150 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolDicomDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string referenceXMLFilename; std::string referenceDVHXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); if (argc > 7) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; structName = argv[4]; referenceXMLFilename = argv[5]; referenceDVHXMLFilename = argv[6]; referenceXMLComplexFilename = argv[7]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "dicomOutput.xml"; std::string defaultDVHOutputFilename = "dicomDVHOutput.xml"; std::string complexOutputFilename = "dicomOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; if (structName != "") { baseCommand += " -n " + structName; } else { baseCommand += " -u itk "; } std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); - std::string defaultDoseStatisticsAndDVHCommand = defaultDoseStatisticsCommand + " -z " + defaultDVHOutputFilename; + std::string defaultDoseStatisticsAndDVHCommand = defaultDoseStatisticsCommand + " -z " + + defaultDVHOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsAndDVHCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsAndDVHCommand.c_str()), 0); std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 14 Gy complexDoseStatisticsCommand += " -x -p 14"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(defaultDVHOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); std::string defaultDVHAsIs = readFile(defaultDVHOutputFilename); std::string defaultDVHExpected = readFile(referenceDVHXMLFilename); CHECK_EQUAL(defaultDVHAsIs, defaultDVHExpected); //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultDVHOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp index 5d379b3..277b002 100644 --- a/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolITKDoseTest.cpp @@ -1,143 +1,143 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolITKDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string structFilename; std::string structName; std::string ctxFilename; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); - + if (argc > 7) { doseToolExecutable = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; ctxFilename = argv[4]; structName = argv[5]; referenceXMLFilename = argv[6]; referenceXMLComplexFilename = argv[7]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "itkOutput.xml"; std::string complexOutputFilename = "itkOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -s " + structFilename; baseCommand += " -t itk "; if (structName != "") { baseCommand += " -n " + structName; if (ctxFilename != "") { baseCommand += " -u virtuos " + ctxFilename; } } else { baseCommand += " -u itk "; } std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 14 Gy complexDoseStatisticsCommand += " -x -p 14"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp index bec104f..106fcdd 100644 --- a/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolInvalidParametersTest.cpp @@ -1,109 +1,109 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int DoseToolInvalidParametersTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; if (argc > 1) { doseToolExecutable = argv[1]; } boost::filesystem::path callingPath(_callingAppPath); std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; //call with too few parameters std::string toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -s test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -s test"; toofewParametersCommand += " -n test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " test"; toofewParametersCommand += " test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); toofewParametersCommand = doseToolExeWithPath; toofewParametersCommand += " -d test"; toofewParametersCommand += " -s test"; toofewParametersCommand += " -n test"; std::cout << "Command line call: " + toofewParametersCommand << std::endl; CHECK_EQUAL(system(toofewParametersCommand.c_str()) != 0, true); //call with invalid dose load option std::string minimalCLI = doseToolExeWithPath + " test test test "; std::string invalidDoseLoadOption = minimalCLI; invalidDoseLoadOption += "-t wrongOption"; std::cout << "Command line call: " + invalidDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidDoseLoadOption.c_str()) != 0, true); //call with invalid struct load option std::string invalidStructLoadOption = minimalCLI; invalidStructLoadOption += "-u wrongOption"; std::cout << "Command line call: " + invalidStructLoadOption << std::endl; CHECK_EQUAL(system(invalidStructLoadOption.c_str()) != 0, true); //call with virtuos dose load option, but without plan/ctx std::string invalidVirtuosDoseLoadOption = minimalCLI; invalidVirtuosDoseLoadOption += "-u virtuos"; std::cout << "Command line call: " + invalidVirtuosDoseLoadOption << std::endl; CHECK_EQUAL(system(invalidVirtuosDoseLoadOption.c_str()) != 0, true); std::string invalidVirtuosStructLoadOption = minimalCLI; invalidVirtuosStructLoadOption += "-t virtuos"; std::cout << "Command line call: " + invalidVirtuosStructLoadOption << std::endl; CHECK_EQUAL(system(invalidVirtuosStructLoadOption.c_str()) != 0, true); //call with complex dose statistics, but without prescribed dose std::string complexDoseWithoutPrescribedDoseCommand = minimalCLI; complexDoseWithoutPrescribedDoseCommand += "-x"; std::cout << "Command line call: " + complexDoseWithoutPrescribedDoseCommand << std::endl; CHECK_EQUAL(system(complexDoseWithoutPrescribedDoseCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolRegexTest.cpp b/testing/demoapps/DoseTool/DoseToolRegexTest.cpp index 5226155..f76109c 100644 --- a/testing/demoapps/DoseTool/DoseToolRegexTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolRegexTest.cpp @@ -1,144 +1,144 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolRegexTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string doseLoadStyle; std::string structFilename; std::string structLoadStyle; std::string structName; std::string referenceXMLFilename; std::string referenceXMLFilename2; boost::filesystem::path callingPath(_callingAppPath); if (argc > 8) { doseToolExecutable = argv[1]; doseFilename = argv[2]; doseLoadStyle = argv[3]; structFilename = argv[4]; structLoadStyle = argv[5]; structName = argv[6]; referenceXMLFilename = argv[7]; referenceXMLFilename2 = argv[8]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "regexOutput.xml"; std::string defaultExpectedOutputFilename = "regexOutput_Nodes.xml"; std::string defaultExpectedOutputFilename2 = "regexOutput_Heart.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -t " + doseLoadStyle; baseCommand += " -s " + structFilename; baseCommand += " -u " + structLoadStyle; baseCommand += " -n \"" + structName + "\""; baseCommand += " -y " + defaultOutputFilename; std::cout << "Command line call: " + baseCommand << std::endl; CHECK_EQUAL(system(baseCommand.c_str()), 0); CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename), false); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename2), false); CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); std::string defaultDoseStatisticsCommand = baseCommand + " -m"; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); //check if two file were written CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(defaultExpectedOutputFilename2), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultExpectedOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); std::string requestedStructRegexTag = "Nodes"; std::string validStructRegexTag = "" + structName + ""; boost::replace_all(defaultExpected, requestedStructRegexTag, validStructRegexTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string default2AsIs = readFile(defaultExpectedOutputFilename2); std::string default2Expected = readFile(referenceXMLFilename2); boost::replace_all(default2Expected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(default2Expected, emptyStructFileTag, validStructFileTag); requestedStructRegexTag = "Heart"; validStructRegexTag = "" + structName + ""; boost::replace_all(default2Expected, requestedStructRegexTag, validStructRegexTag); CHECK_EQUAL(default2AsIs, default2Expected); //delete file again CHECK_EQUAL(std::remove(defaultExpectedOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(defaultExpectedOutputFilename2.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/DoseTool/DoseToolTests.cpp b/testing/demoapps/DoseTool/DoseToolTests.cpp index 18276bf..40003c8 100644 --- a/testing/demoapps/DoseTool/DoseToolTests.cpp +++ b/testing/demoapps/DoseTool/DoseToolTests.cpp @@ -1,73 +1,73 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @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 { const char* _callingAppPath = NULL; void registerTests() { LIT_REGISTER_TEST(DoseToolBasicUsageTest); LIT_REGISTER_TEST(DoseToolInvalidParametersTest); LIT_REGISTER_TEST(DoseToolVirtuosDoseTest); LIT_REGISTER_TEST(DoseToolDicomDoseTest); LIT_REGISTER_TEST(DoseToolITKDoseTest); LIT_REGISTER_TEST(DoseToolRegexTest); LIT_REGISTER_TEST(DoseToolDVHTest); } } //namespace testing } //namespace map int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); if (argc > 0) { rttb::testing::_callingAppPath = argv[0]; } try { result = lit::multiTestsMain(argc, argv); } catch (...) { result = -1; } return result; } diff --git a/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp index f339579..252f0ed 100644 --- a/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp +++ b/testing/demoapps/DoseTool/DoseToolVirtuosDoseTest.cpp @@ -1,133 +1,133 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 771 $ (last changed revision) -// @date $Date: 2014-09-25 14:41:34 +0200 (Do, 25 Sep 2014) $ (last change date) -// @author $Author: zhangl $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include #include #include #include "litCheckMacros.h" #include "boost/filesystem.hpp" #include "boost/algorithm/string.hpp" namespace rttb { namespace testing { //path to the current running directory. DoseTool is in the same directory (Debug/Release) extern const char* _callingAppPath; static std::string readFile(const std::string& filename); int DoseToolVirtuosDoseTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string doseToolExecutable; std::string doseFilename; std::string planFilename; std::string structFilename; std::string ctxFilename; std::string structName; std::string referenceXMLFilename; std::string referenceXMLComplexFilename; boost::filesystem::path callingPath(_callingAppPath); - + if (argc > 8) { doseToolExecutable = argv[1]; doseFilename = argv[2]; planFilename = argv[3]; structFilename = argv[4]; ctxFilename = argv[5]; structName = argv[6]; referenceXMLFilename = argv[7]; referenceXMLComplexFilename = argv[8]; } std::string doseToolExeWithPath = callingPath.parent_path().string() + "/" + doseToolExecutable; std::string defaultOutputFilename = "virtuosOutput.xml"; std::string complexOutputFilename = "virtuosOutputComplex.xml"; std::string baseCommand = doseToolExeWithPath; baseCommand += " -d " + doseFilename; baseCommand += " -t virtuos " + planFilename; baseCommand += " -s " + structFilename; baseCommand += " -u virtuos " + ctxFilename; baseCommand += " -n " + structName; std::string defaultDoseStatisticsCommand = baseCommand + " -y " + defaultOutputFilename; std::cout << "Command line call: " + defaultDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(defaultDoseStatisticsCommand.c_str()), 0); std::string complexDoseStatisticsCommand = baseCommand + " -y " + complexOutputFilename; //prescribed dose is 50 Gy complexDoseStatisticsCommand += " -x -p 50"; std::cout << "Command line call: " + complexDoseStatisticsCommand << std::endl; CHECK_EQUAL(system(complexDoseStatisticsCommand.c_str()), 0); //check if file exists CHECK_EQUAL(boost::filesystem::exists(defaultOutputFilename), true); CHECK_EQUAL(boost::filesystem::exists(complexOutputFilename), true); //check if file is the same than reference file std::string defaultAsIs = readFile(defaultOutputFilename); std::string defaultExpected = readFile(referenceXMLFilename); //add doseFile and structFile std::string emptyDoseFileTag = ""; std::string validDoseFileTag = "" + doseFilename + ""; boost::replace_all(defaultExpected, emptyDoseFileTag, validDoseFileTag); std::string emptyStructFileTag = ""; std::string validStructFileTag = "" + structFilename + ""; boost::replace_all(defaultExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(defaultAsIs, defaultExpected); //add doseFile and structFile std::string complexAsIs = readFile(complexOutputFilename); std::string complexExpected = readFile(referenceXMLComplexFilename); boost::replace_all(complexExpected, emptyDoseFileTag, validDoseFileTag); boost::replace_all(complexExpected, emptyStructFileTag, validStructFileTag); CHECK_EQUAL(complexAsIs, complexExpected); //delete file again CHECK_EQUAL(std::remove(defaultOutputFilename.c_str()), 0); CHECK_EQUAL(std::remove(complexOutputFilename.c_str()), 0); RETURN_AND_REPORT_TEST_SUCCESS; } std::string readFile(const std::string& filename) { std::ifstream fileStream(filename.c_str()); std::string content((std::istreambuf_iterator(fileStream)), (std::istreambuf_iterator())); return content; } } //namespace testing } //namespace rttb diff --git a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolIncorrectCommandsTest.cpp b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolIncorrectCommandsTest.cpp index 898ab14..b405efe 100644 --- a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolIncorrectCommandsTest.cpp +++ b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolIncorrectCommandsTest.cpp @@ -1,120 +1,120 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "litCheckMacros.h" #include /*! @brief VoxelizerToolTest4. Test incorrect commands with a wrong structfile, referencefile and a wrong struct. if the command return one, the program could not run to the end. return zero the command is correct */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolIncorrectCommandsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string voxelizerToolExe; std::string structFile; std::string invalidStructFile; std::string invalidReferenceFile; std::string referenceFile; std::string structureName; std::string invalidStructureName; if (argc > 7) { voxelizerToolExe = argv[1]; structFile = argv[2]; invalidStructFile = argv[3]; referenceFile = argv[4]; invalidReferenceFile = argv[5]; structureName = argv[6]; invalidStructureName = argv[7]; } boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::string tooFewArgumentsCommand = voxelizerToolExeWithPath; tooFewArgumentsCommand += " -s " + invalidStructFile; tooFewArgumentsCommand += " -r " + referenceFile; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; - CHECK_EQUAL(system(tooFewArgumentsCommand.c_str())!=0, true); + CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); tooFewArgumentsCommand = voxelizerToolExeWithPath; tooFewArgumentsCommand += " -s " + invalidStructFile; tooFewArgumentsCommand += " -e " + structureName; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; - CHECK_EQUAL(system(tooFewArgumentsCommand.c_str())!=0, true); + CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); tooFewArgumentsCommand = voxelizerToolExeWithPath; std::cout << "Command line call: " + tooFewArgumentsCommand << std::endl; - CHECK_EQUAL(system(tooFewArgumentsCommand.c_str())!=0, true); + CHECK_EQUAL(system(tooFewArgumentsCommand.c_str()) != 0, true); std::string noOutputEndingCommand = voxelizerToolExeWithPath; noOutputEndingCommand += " -s " + invalidStructFile; noOutputEndingCommand += " -r " + referenceFile; noOutputEndingCommand += " -e " + structureName; noOutputEndingCommand += " -o bla"; std::cout << "Command line call: " + noOutputEndingCommand << std::endl; - CHECK_EQUAL(system(noOutputEndingCommand.c_str())!=0, true); + CHECK_EQUAL(system(noOutputEndingCommand.c_str()) != 0, true); std::string structCommand = voxelizerToolExeWithPath; structCommand += " -s " + invalidStructFile; structCommand += " -r " + referenceFile; structCommand += " -e " + structureName; std::cout << "Command line call: " + structCommand << std::endl; - CHECK_EQUAL(system(structCommand.c_str())!=0, true); + CHECK_EQUAL(system(structCommand.c_str()) != 0, true); std::string referenceCommand = voxelizerToolExeWithPath; referenceCommand += " -s " + structFile; referenceCommand += " -r " + invalidReferenceFile; referenceCommand += " -e " + structureName; std::cout << "Command line call: " + referenceCommand << std::endl; - CHECK_EQUAL(system(referenceCommand.c_str())!=0, true); + CHECK_EQUAL(system(referenceCommand.c_str()) != 0, true); std::string structureNameCommand = voxelizerToolExeWithPath; structureNameCommand += " -s " + structFile; structureNameCommand += " -r " + referenceFile; structureNameCommand += +" -e " + invalidStructureName; std::cout << "Command line call: " + structureNameCommand << std::endl; CHECK_EQUAL(system(structureNameCommand.c_str()), 0); std::string referenceLoadingStyleCommand = voxelizerToolExeWithPath; referenceLoadingStyleCommand += " -s " + structFile; referenceLoadingStyleCommand += " -r " + referenceFile; referenceLoadingStyleCommand += +" -e " + invalidStructureName; referenceLoadingStyleCommand += +" -y nonsense"; std::cout << "Command line call: " + referenceLoadingStyleCommand << std::endl; - CHECK_EQUAL(system(referenceLoadingStyleCommand.c_str())!=0, true); + CHECK_EQUAL(system(referenceLoadingStyleCommand.c_str()) != 0, true); RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelValueTest.cpp b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelValueTest.cpp index 2abd905..c03d58a 100644 --- a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelValueTest.cpp +++ b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelValueTest.cpp @@ -1,132 +1,134 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include #include "itkImage.h" #include "itkImageFileReader.h" #include #include /*! @brief VoxelizerToolTest5. Search the coordinate at the Image and return the Voxel(Pixel) value. */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolVoxelValue(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef itk::Image< double, 3 > ImageType; typedef itk::ImageFileReader ReaderType; std::string voxelizerToolExe; std::string tempDirectory; std::string structFile; std::string referenceFile; std::string structName; if (argc > 5) { voxelizerToolExe = argv[1]; tempDirectory = argv[2]; structFile = argv[3]; referenceFile = argv[4]; structName = argv[5]; } boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::string command = voxelizerToolExeWithPath; command += " -s " + structFile; command += " -r " + referenceFile; command += " -e " + structName; int returnValue = system(command.c_str()); CHECK_EQUAL(returnValue, 0); //image values taken in Mevislab //Index inside ImageType::IndexType voxelInside1 = {{20, 30, 30}}; ImageType::IndexType voxelInside2 = {{30, 10, 40}}; //Outside index ImageType::IndexType voxelOutside1 = {{40, 30, 30}}; ImageType::IndexType voxelOutside2 = {{10, 40, 30}}; //Border index ImageType::IndexType voxelBorder1 = {{12, 23, 27}}; ImageType::IndexType voxelBorder2 = {{34, 21, 31}}; - std::vector voxelIndices = boost::assign::list_of(voxelInside1)(voxelInside2)(voxelOutside1)( + std::vector voxelIndices = boost::assign::list_of(voxelInside1)(voxelInside2)( + voxelOutside1)( voxelOutside2)(voxelBorder1)(voxelBorder2); - std::vector expectedVoxelValues = boost::assign::list_of(1.0)(1.0)(0.0)(0.0)(0.265865)(0.819613); + std::vector expectedVoxelValues = boost::assign::list_of(1.0)(1.0)(0.0)(0.0)( + 0.265865)(0.819613); std::string filenameHDRWithVoxelization = tempDirectory + "/out_" + structName + ".hdr"; std::string filenameIMGWithVoxelization = tempDirectory + "/out_" + structName + ".img"; CHECK(boost::filesystem::exists(filenameHDRWithVoxelization)); CHECK(boost::filesystem::exists(filenameIMGWithVoxelization)); if (boost::filesystem::exists(filenameHDRWithVoxelization)) { ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(filenameHDRWithVoxelization); reader->Update(); ReaderType::OutputImageType::ConstPointer image = reader->GetOutput(); for (int i = 0; i < voxelIndices.size(); i++) { ImageType::PixelType voxelValue = image->GetPixel(voxelIndices.at(i)); ImageType::PixelType expectedVoxelValue = expectedVoxelValues.at(i); if (expectedVoxelValue == 0.0 || expectedVoxelValue == 1.0) { CHECK_EQUAL(voxelValue, expectedVoxelValue); } else { CHECK_CLOSE(voxelValue, expectedVoxelValue, 1e-4); } } if (boost::filesystem::exists(filenameHDRWithVoxelization)) { boost::filesystem::remove(filenameHDRWithVoxelization); } if (boost::filesystem::exists(filenameIMGWithVoxelization)) { boost::filesystem::remove(filenameIMGWithVoxelization); } } RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelizerAllStructsTest.cpp b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelizerAllStructsTest.cpp index 56a9211..6ce2031 100644 --- a/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelizerAllStructsTest.cpp +++ b/testing/demoapps/VoxelizerTool/rttbVoxelizerToolVoxelizerAllStructsTest.cpp @@ -1,111 +1,111 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 #include /*! @brief VoxelizerToolTest. Tests a selection of structs. */ namespace rttb { namespace testing { //path to the current running directory. VoxelizerTool is in the same directory (Debug/Release) extern const char* _callingAppPath; int VoxelizerToolVoxelizerAllStructsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string voxelizerToolExe; std::string tempDirectory; std::string structFile; std::string referenceFile; if (argc > 4) { voxelizerToolExe = argv[1]; tempDirectory = argv[2]; structFile = argv[3]; referenceFile = argv[4]; } boost::filesystem::path callingPath(_callingAppPath); std::string voxelizerToolExeWithPath = callingPath.parent_path().string() + "/" + voxelizerToolExe; std::vector structNames; structNames.push_back("Niere.*"); structNames.push_back("Magen/DD"); structNames.push_back("PTV"); //structure names will be used for file naming, BUT '.' in the end will be cropped and '/' will be replaced by '_'. Thus, the different filenames. std::vector filenames; filenames.push_back("Niere re"); filenames.push_back("Magen_DD"); filenames.push_back("PTV"); std::string baseCommand = voxelizerToolExeWithPath; baseCommand += " -s " + structFile; baseCommand += " -r " + referenceFile; baseCommand += " -e \""; for (int i = 0; i < structNames.size(); i++) { std::string command = baseCommand + structNames.at(i) + "\""; std::cout << "Command line call: " + command << std::endl; int returnValue = system(command.c_str()); CHECK_EQUAL(returnValue, 0); const std::string HDRfileName = tempDirectory + "/out_" + filenames.at(i) + ".hdr"; boost::filesystem::path HDRFile(tempDirectory); - HDRFile/="out_" + filenames.at(i) + ".hdr"; + HDRFile /= "out_" + filenames.at(i) + ".hdr"; const std::string IMGfileName = tempDirectory + "/out_" + filenames.at(i) + ".img"; boost::filesystem::path IMGFile(tempDirectory); - IMGFile/="out_" + filenames.at(i) + ".img"; + IMGFile /= "out_" + filenames.at(i) + ".img"; CHECK_EQUAL( boost::filesystem::exists(HDRFile), true); CHECK_EQUAL( boost::filesystem::exists(IMGFile), true); if (boost::filesystem::exists(IMGFile)) { boost::filesystem::remove(IMGFile); } if (boost::filesystem::exists(HDRFile)) { boost::filesystem::remove(HDRFile); } } RETURN_AND_REPORT_TEST_SUCCESS; } } } diff --git a/testing/examples/DoseStatisticsIOVirtuosTest.cpp b/testing/examples/DoseStatisticsIOVirtuosTest.cpp index 79f4ac0..fe450bf 100644 --- a/testing/examples/DoseStatisticsIOVirtuosTest.cpp +++ b/testing/examples/DoseStatisticsIOVirtuosTest.cpp @@ -1,113 +1,115 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // 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 "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosDoseAccessor.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*! @brief OtherIOTest - test the IO for dose statistics 1) test exception 2) test writing statistics to xml file */ int DoseStatisticsIOVirtuosTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef boost::shared_ptr DoseStatisticsPtr; typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; typedef boost::shared_ptr GeometricInfoPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string Struct_FILENAME; std::string BPLCT_FILENAME; std::string Dose_FILENAME; std::string Plan_FILENAME; std::string Struct_NAME; if (argc > 5) { Struct_FILENAME = argv[1]; BPLCT_FILENAME = argv[2]; Dose_FILENAME = argv[3]; Plan_FILENAME = argv[4]; Struct_NAME = argv[5]; } else { std::cout << "at least 5 arguments are expected in DoseStatisticsIOVirtuosTest." << std::endl; } /* generate dummy dose */ - io::virtuos::VirtuosPlanFileDoseAccessorGenerator doseAccessorGenerator(Dose_FILENAME.c_str(), Plan_FILENAME.c_str()); + io::virtuos::VirtuosPlanFileDoseAccessorGenerator doseAccessorGenerator(Dose_FILENAME.c_str(), + Plan_FILENAME.c_str()); DoseAccessorPointer doseAccessor(doseAccessorGenerator.generateDoseAccessor()); StructureSetPointer rtStructureSet = io::virtuos::VirtuosFileStructureSetGenerator( Struct_FILENAME.c_str(), BPLCT_FILENAME.c_str()).generateStructureSet(); - GeometricInfoPointer geometricInfoPtr = boost::make_shared(doseAccessor->getGeometricInfo()); + GeometricInfoPointer geometricInfoPtr = boost::make_shared + (doseAccessor->getGeometricInfo()); MaskAccessorPointer maskAccessorPtr = boost::make_shared (rtStructureSet->getStructure(3), doseAccessor->getGeometricInfo()); maskAccessorPtr->updateMask(); boost::shared_ptr spTestDoseIterator = boost::make_shared(maskAccessorPtr, doseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = myDoseStatsCalculator.calculateDoseStatistics(true); /* test writing statistcs to xml file */ FileNameString fN = "doseStatisticsVirtuosComplex.xml"; CHECK_NO_THROW(io::other::writeDoseStatistics(doseStatistics, fN)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/RTBioModelExampleTest.cpp b/testing/examples/RTBioModelExampleTest.cpp index 8b03060..c292641 100644 --- a/testing/examples/RTBioModelExampleTest.cpp +++ b/testing/examples/RTBioModelExampleTest.cpp @@ -1,413 +1,416 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" #include "rttbDoseIteratorInterface.h" namespace rttb { namespace testing { /*! @brief RTBioModelTest. TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTBioModelExampleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef rttb::models::CurveDataType CurveDataType; typedef std::multimap > ScatterPlotType; typedef core::DVH::DVHPointer DVHPointer; //increased accuracy requires double values in the calculation (rttbBaseType.h) double toleranceEUD = 1e-5; double tolerance = 1e-7; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name //...........5: Virtuos MPM_LR_ah dvh lung file name //...........6: Virtuos MPM_LR_ah dvh target file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; std::string DVH_FILENAME_TV_TEST; std::string DVH_Virtuos_Target; std::string DVH_Virtuos_Lung; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } if (argc > 5) { DVH_FILENAME_TV_TEST = argv[5]; } if (argc > 6) { DVH_Virtuos_Lung = argv[6]; } if (argc > 7) { DVH_Virtuos_Target = argv[7]; } //DVH PTV rttb::io::other::DVHTxtFileReader dvhReader = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); DVHPointer dvhPtr = dvhReader.generateDVH(); CHECK_CLOSE(6.04759613161786830000e+001, models::getEUD(dvhPtr, 10), toleranceEUD); - rttb::io::other::DVHTxtFileReader dvhReader_test_tv = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_TV_TEST); + rttb::io::other::DVHTxtFileReader dvhReader_test_tv = rttb::io::other::DVHTxtFileReader( + DVH_FILENAME_TV_TEST); DVHPointer dvh_test_tv = dvhReader_test_tv.generateDVH(); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 2; DoseTypeGy normalizationDose = 68; rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_NO_THROW(tcplq.init()); if (tcplq.init()) { CHECK_CLOSE(1.00497232941856940000e-127, tcplq.getValue(), tolerance); } CurveDataType curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CurveDataType::iterator it; for (it = curve.begin(); it != curve.end(); it++) { if ((*it).first < 72) { CHECK_EQUAL(0, (*it).second); } else if ((*it).first > 150) { CHECK((*it).second > 0.9); } } models::BioModelParamType alphaBeta = 10; tcplq.setParameters(alpha, alphaBeta, roh, 0.08); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_CLOSE(1.84e-005, tcplq.getValue(), tolerance); } normalizationDose = 40; curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); alpha = 1; alphaBeta = 14.5; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_CLOSE(0.954885, tcplq.getValue(), toleranceEUD); } alpha = 0.9; alphaBeta = 1; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); if (tcplq.init()) { CHECK_EQUAL(1, tcplq.getValue()); } //TCP LQ Test alpha = 0.3; beta = 0.03; roh = 10000000; numFractions = 20; - rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, numFractions); + rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, + numFractions); CHECK_EQUAL(alpha, tcplq_test.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq_test.getAlphaBeta()); CHECK_EQUAL(roh, tcplq_test.getRho()); CHECK_NO_THROW(tcplq_test.init()); if (tcplq_test.init()) { CHECK_CLOSE(9.79050278878883180000e-001, tcplq_test.getValue(), tolerance); } normalizationDose = 60; curve = models::getCurveDoseVSBioModel(tcplq_test, normalizationDose); //DVH HT 1 rttb::io::other::DVHTxtFileReader dvhReader2 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); DVHPointer dvhPtr2 = dvhReader2.generateDVH(); CHECK_CLOSE(1.07920836034015810000e+001, models::getEUD(dvhPtr2, 10), toleranceEUD); //test RTNTCPLKBModel rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 55; CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr2); CHECK_EQUAL(dvhPtr2, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(lkb.init()); if (lkb.init()) { CHECK_CLOSE(2.53523522831366570000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr2); CHECK_EQUAL(dvhPtr2, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); CHECK_NO_THROW(rs.init()); if (rs.init()) { CHECK_CLOSE(3.70385888626145740000e-009, rs.getValue(), tolerance); } //DVH HT 2 rttb::io::other::DVHTxtFileReader dvhReader3 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT2); DVHPointer dvhPtr3 = dvhReader3.generateDVH(); CHECK_CLOSE(1.26287047025885110000e+001, models::getEUD(dvhPtr3, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr3); CHECK_EQUAL(dvhPtr3, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); if (lkb.init()) { CHECK_CLOSE(7.36294657754956700000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr3); CHECK_EQUAL(dvhPtr3, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); if (rs.init()) { CHECK_CLOSE(1.76778795490939440000e-007, rs.getValue(), tolerance); } //DVH HT 3 rttb::io::other::DVHTxtFileReader dvhReader4 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT3); DVHPointer dvhPtr4 = dvhReader4.generateDVH(); CHECK_CLOSE(2.18212982041056310000e+001, models::getEUD(dvhPtr4, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr4); CHECK_EQUAL(dvhPtr4, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); if (lkb.init()) { CHECK_CLOSE(8.15234192641929420000e-005, lkb.getValue(), tolerance); } //test RTNTCPRSModel rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr4); CHECK_EQUAL(dvhPtr4, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); if (rs.init()) { CHECK_CLOSE(2.02607985020919480000e-004, rs.getValue(), tolerance); } //test using Virtuos Pleuramesotheliom MPM_LR_ah //DVH PTV rttb::io::other::DVHTxtFileReader dR_Target = rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Target); DVHPointer dvhPtrTarget = dR_Target.generateDVH(); rttb::io::other::DVHTxtFileReader dR_Lung = rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Lung); DVHPointer dvhPtrLung = dR_Lung.generateDVH(); //test TCP LQ Model models::BioModelParamType alphaMean = 0.34; models::BioModelParamType alphaVarianz = 0.02; models::BioModelParamType alpha_beta = 28; models::BioModelParamType rho = 1200; int numFractionsVirtuos = 27; - rttb::models::TCPLQModel tcplqVirtuos = rttb::models::TCPLQModel(dvhPtrTarget, rho, numFractionsVirtuos, alpha_beta, + rttb::models::TCPLQModel tcplqVirtuos = rttb::models::TCPLQModel(dvhPtrTarget, rho, + numFractionsVirtuos, alpha_beta, alphaMean, alphaVarianz); if (tcplqVirtuos.init()) { CHECK_CLOSE(0.8894, tcplqVirtuos.getValue(), 1e-4); } models::BioModelParamType d50Mean = 20; models::BioModelParamType d50Varianz = 2; models::BioModelParamType m = 0.36; models::BioModelParamType a = 1.06; rttb::models::NTCPLKBModel lkbVirtuos = rttb::models::NTCPLKBModel(dvhPtrLung, d50Mean, m, a); if (lkbVirtuos.init()) { CHECK_CLOSE(0.0397, lkbVirtuos.getValue(), 1e-4); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTDVHCalculatorTest.cpp b/testing/examples/RTDVHCalculatorTest.cpp index 59ddd27..fe89538 100644 --- a/testing/examples/RTDVHCalculatorTest.cpp +++ b/testing/examples/RTDVHCalculatorTest.cpp @@ -1,252 +1,280 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // (c) Copyright 2007, DKFZ, Heidelberg, Germany // ALL RIGHTS RESERVED // // THIS FILE CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION OF DKFZ. // ANY DUPLICATION, MODIFICATION, DISTRIBUTION, OR // DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY PROHIBITED // WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF DKFZ. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author zhangl (last changed by) // @author *none* (Reviewer) // @author zhangl (Programmer) // // Subversion HeadURL: $HeadURL: http://sidt-hpc1/dkfz_repository/NotMeVisLab/SIDT/RTToolbox/branch/restructure/testing/core/DVHCalculatorTest.cpp $ */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "litCheckMacros.h" #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmrt/drtdose.h" #include "dcmtk/dcmrt/drtstruct.h" #include "../../code/core/rttbMaskedDoseIteratorInterface_NEW.h" #include "../../code/core/rttbGenericMaskedDoseIterator_NEW.h" #include "../../code/core/rttbGenericDoseIterator_NEW.h" #include "../../code/core/rttbDVHCalculator.h" #include "../../code/io/dicom/rttbDicomStructureSet.h" #include "../../code/core/rttbStructure.h" #include "../../code/core/rttbNullPointerException.h" #include "../../code/core/rttbInvalidParameterException.h" #include "../../code/core/rttbInvalidDoseException.h" #include "../../code/core/rttbException.h" #include "../../code/core/rttbBaseType_NEW.h" //#include "CreateTestStructure.h" - currently not used // sollen externe Methoden verwendet werden? #include "../../code/io/dicom/rttbDicomDoseAccessor.h" #include "../../code/masks/rttbOTBMaskAccessor.h" #include "../../code/algorithms/rttbDoseStatistics.h" #include -namespace rttb{ - - namespace testing{ - - - - /*! @brief DVHCalculatorTest. - 1. DVH calculator test: use MaskedDicomDoseIterator(&rtdose, &rtstr) -> now use rttbGenericMaskedDoseIterator_NEW.h - 2. DVH Calculator test: use cache of MaskedDicomDoseIterator resetDose -> obsolete - 3. DVH Calculator test: use MaskedDicomDoseIteratorRandomSampling ->obsolete use dummy mask? - 4. DVH Calculator test: use DicomDoseIteratorUseMask -> obsolete/ ../io/dicom? - 5. DVH Calculator test: use manually generated structure and Mask(DoseIteratorInterface*, Structure* ) -> check if this should be done here or in ../masks - 6. DVHCalculation Test using constructor Mask( DoseIteratorInterface* aDoseIter , std::vector aDoseVoxelVector ); -> mask generation should be tested in mask tests use default mask here - */ - - - /*static std::string MASK_FILENAME="../../../RTToolbox/testing/data/DICOM/TestDose/TestMask.dcm"; - static std::string HITDOSE_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTDOSE/HITDemoData_20100316T175500_RTDOSE_450.IMA"; - static std::string HITSTRUCT_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTSTRUCT/HITDemoData_20100407T152606_RTSTRUCT_0.IMA"; - static std::string HITBEAMDOSE_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTDOSE/HITDemoData_20100407T152314_RTDOSE_0.IMA"; - - static std::string DVH_FILENAME_WRITE="../../../RTToolbox/testing/data/TestDVH/dvh_write.txt"; - - static std::string DVH_FILENAME_PTV_HIT="../../../RTToolbox/testing/data/TestDVH/dvh_PTV_HIT.txt";*/ - - int RTDVHCalculatorTest(int argc, char* argv[] ) - { - typedef core::GenericDoseIterator::DoseAcessorPointer DoseAcessorPointer; - typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - typedef core::MaskedDoseIteratorInterface::MaskAcessorPointer MaskAcessorPointer; - typedef masks::OTBMaskAccessor::StructTypePointer StructTypePointer; - typedef algorithms::DoseStatistics::ResultListPointer ResultListPointer; - - - PREPARE_DEFAULT_TEST_REPORTING; - //ARGUMENTS: 1: structure file name - // 2: dose1 file name - // 3: dose2 file name - // 4: dose3 file name - - std::string STRUCT_FILENAME; - std::string DOSE_FILENAME; - std::string DOSE2_FILENAME; - std::string DOSE3_FILENAME; - - /*STRUCT_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTSTRUCT/H000090_20100610T144958_RTSTRUCT_479.IMA"; - DOSE_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_396.IMA"; - DOSE2_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_397.IMA"; - DOSE3_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_398.IMA";*/ - - - if (argc>1) - { - STRUCT_FILENAME = argv[1]; - } - if (argc>2) - { - DOSE_FILENAME = argv[2]; - } - if (argc>3) - { - DOSE2_FILENAME = argv[3]; - } - if (argc>4) - { - DOSE3_FILENAME = argv[4]; - } - - -// CHECK_THROW_EXPLICIT(core::DVHCalculator(NULL,"",""),core::NullPointerException); -> tested in individual test - - OFCondition status; - DcmFileFormat fileformat; - - /* read dicom-rt dose */ - ::DRTDoseIOD rtdose; -// rttb::core::Structure* rtstr; - double deltaD=0; - double deltaV=0.03; - // use new architecture accessor+iterator - // import dicom files - CHECK_NO_THROW(DoseAcessorPointer spDoseAccessor(new core::DicomDoseAccessor(DOSE_FILENAME.c_str()))); - DoseAcessorPointer spDoseAccessor(new core::DicomDoseAccessor(DOSE_FILENAME.c_str())); - std::cout <<"ProcessDose "<< DOSE_FILENAME.c_str()< mditVector; - ResultListPointer resultListMax; - ResultListPointer resultListMin; - if(rtstrset.getNumberOfStructures()>0){ - for(int j=0;j(*(rtstrset.getStructure(j))); - rttb::core::GeometricInfo geoInf = ddit.getGeometricInfo(); - - boost::shared_ptr pOTBMaskAccessor = boost::make_shared(spRtstr,geoInf, rtdose); - MaskAcessorPointer spMaskAccessor(pOTBMaskAccessor); - boost::shared_ptr spTestMaskedDoseIterator = boost::make_shared(spMaskAccessor, spDoseAccessor); //using Mask - DoseIteratorPointer mddit(spTestMaskedDoseIterator); - mddit->reset(); - std::cout << "Initialization time: "<<(clock()-startLoop)/1000<<" s"<getUID(),mddit->getDoseUID()); - rttb::core::DVH dvh=*(calc.getDVH()); - std::cout <<"DVH(mask) max: "<< dvh.getMaximum()<< "in "<getVolume()<<" cm^3"<0){ - for(int j=0;j(*(rtstrset.getStructure(j))); - rttb::core::GeometricInfo geoInf = ddit.getGeometricInfo(); - - boost::shared_ptr pOTBMaskAccessor = boost::make_shared(spRtstr,geoInf, rtdose); - MaskAcessorPointer spMaskAccessor(pOTBMaskAccessor); - boost::shared_ptr spTestMaskedDoseIterator = boost::make_shared(spMaskAccessor, spDoseAccessor2); //using Mask - DoseIteratorPointer mddit(spTestMaskedDoseIterator); - boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor2); - DoseIteratorPointer ddit2(spTestDoseIterator); - mddit->reset(); - std::cout << "Initialization time: "<<(clock()-startLoop)/1000<<" s"<getUID(),mddit->getDoseUID()); - rttb::core::DVH dvh2=*(calc2.getDVH()); - std::cout <<"DVH(mask) max: "<< dvh2.getMaximum()<< "in "<getVolume()<<" cm^3"<getUID(),ddit2->getDoseUID()); - rttb::core::DVH dvh=*(calc.getDVH()); - std::cout <<"DVH(dose) max: "<< dvh.getMaximum()< ../algorithms - clock_t startStats(clock()); - std::cout <<"Statistics: "< now use rttbGenericMaskedDoseIterator_NEW.h + 2. DVH Calculator test: use cache of MaskedDicomDoseIterator resetDose -> obsolete + 3. DVH Calculator test: use MaskedDicomDoseIteratorRandomSampling ->obsolete use dummy mask? + 4. DVH Calculator test: use DicomDoseIteratorUseMask -> obsolete/ ../io/dicom? + 5. DVH Calculator test: use manually generated structure and Mask(DoseIteratorInterface*, Structure* ) -> check if this should be done here or in ../masks + 6. DVHCalculation Test using constructor Mask( DoseIteratorInterface* aDoseIter , std::vector aDoseVoxelVector ); -> mask generation should be tested in mask tests use default mask here + */ + + + /*static std::string MASK_FILENAME="../../../RTToolbox/testing/data/DICOM/TestDose/TestMask.dcm"; + static std::string HITDOSE_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTDOSE/HITDemoData_20100316T175500_RTDOSE_450.IMA"; + static std::string HITSTRUCT_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTSTRUCT/HITDemoData_20100407T152606_RTSTRUCT_0.IMA"; + static std::string HITBEAMDOSE_FILENAME="d:/Dotmobi-SVN/rondo/RondoInterface/Resources/TestData/Dicom/HITDemoData/RTDOSE/HITDemoData_20100407T152314_RTDOSE_0.IMA"; + + static std::string DVH_FILENAME_WRITE="../../../RTToolbox/testing/data/TestDVH/dvh_write.txt"; + + static std::string DVH_FILENAME_PTV_HIT="../../../RTToolbox/testing/data/TestDVH/dvh_PTV_HIT.txt";*/ + + int RTDVHCalculatorTest(int argc, char* argv[]) + { + typedef core::GenericDoseIterator::DoseAcessorPointer DoseAcessorPointer; + typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; + typedef core::MaskedDoseIteratorInterface::MaskAcessorPointer MaskAcessorPointer; + typedef masks::OTBMaskAccessor::StructTypePointer StructTypePointer; + typedef algorithms::DoseStatistics::ResultListPointer ResultListPointer; + + + PREPARE_DEFAULT_TEST_REPORTING; + //ARGUMENTS: 1: structure file name + // 2: dose1 file name + // 3: dose2 file name + // 4: dose3 file name + + std::string STRUCT_FILENAME; + std::string DOSE_FILENAME; + std::string DOSE2_FILENAME; + std::string DOSE3_FILENAME; + + /*STRUCT_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTSTRUCT/H000090_20100610T144958_RTSTRUCT_479.IMA"; + DOSE_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_396.IMA"; + DOSE2_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_397.IMA"; + DOSE3_FILENAME="d:/RTToolboxProj/trunk/testing/data/DICOM/H000090/RTDOSE/H000090_20100610T144958_RTDOSE_398.IMA";*/ + + + if (argc > 1) + { + STRUCT_FILENAME = argv[1]; + } + + if (argc > 2) + { + DOSE_FILENAME = argv[2]; + } + + if (argc > 3) + { + DOSE2_FILENAME = argv[3]; + } + + if (argc > 4) + { + DOSE3_FILENAME = argv[4]; + } + + + // CHECK_THROW_EXPLICIT(core::DVHCalculator(NULL,"",""),core::NullPointerException); -> tested in individual test + + OFCondition status; + DcmFileFormat fileformat; + + /* read dicom-rt dose */ + ::DRTDoseIOD rtdose; + // rttb::core::Structure* rtstr; + double deltaD = 0; + double deltaV = 0.03; + // use new architecture accessor+iterator + // import dicom files + CHECK_NO_THROW(DoseAcessorPointer spDoseAccessor(new core::DicomDoseAccessor( + DOSE_FILENAME.c_str()))); + DoseAcessorPointer spDoseAccessor(new core::DicomDoseAccessor(DOSE_FILENAME.c_str())); + std::cout << "ProcessDose " << DOSE_FILENAME.c_str() << std::endl; + core::GenericDoseIterator ddit(spDoseAccessor); + + /* read dicom-rt structure set*/ + // use toolbox extensions from Andreas?!: DoseToolDCMStructLoader.h + ::DRTStructureSetIOD rtstruct; + status = fileformat.loadFile(STRUCT_FILENAME.c_str()); + CHECK(status.good()); + + if (!status.good()) + { + std::cerr << "Error: load rt structure set loadFile(STRUCT_FILENAME) failed!" << std::endl; + return -1; + } + + status = rtstruct.read(*fileformat.getDataset()); + + if (!status.good()) + { + std::cerr << "Error: read DRTStructureSetIOD failed!" << std::endl; + return -1; + } + + //get maximum of rtdose + + CHECK_NO_THROW(rttb::core::DicomStructureSet rtstrset = rttb::core::DicomStructureSet(&rtstruct)); + rttb::core::DicomStructureSet rtstrset = rttb::core::DicomStructureSet(&rtstruct); + + clock_t start(clock()); + //std::vector mditVector; + ResultListPointer resultListMax; + ResultListPointer resultListMin; + + if (rtstrset.getNumberOfStructures() > 0) + { + for (int j = 0; j < rtstrset.getNumberOfStructures(); j++) + { + clock_t startLoop(clock()); + StructTypePointer spRtstr = boost::make_shared(*(rtstrset.getStructure(j))); + rttb::core::GeometricInfo geoInf = ddit.getGeometricInfo(); + + boost::shared_ptr pOTBMaskAccessor = + boost::make_shared(spRtstr, geoInf, rtdose); + MaskAcessorPointer spMaskAccessor(pOTBMaskAccessor); + boost::shared_ptr spTestMaskedDoseIterator = + boost::make_shared(spMaskAccessor, + spDoseAccessor); //using Mask + DoseIteratorPointer mddit(spTestMaskedDoseIterator); + mddit->reset(); + std::cout << "Initialization time: " << (clock() - startLoop) / 1000 << " s" << std::endl; + + rttb::core::DVHCalculator calc(mddit, spRtstr->getUID(), mddit->getDoseUID()); + rttb::core::DVH dvh = *(calc.getDVH()); + std::cout << "DVH(mask) max: " << dvh.getMaximum() << "in " << spRtstr->getVolume() << " cm^3" << + std::endl; + } + } + + clock_t finish(clock()); + + std::cout << "DVH Calculation time: " << (finish - start) / 60000 << " min" << std::endl; + + DoseAcessorPointer spDoseAccessor2(new core::DicomDoseAccessor(DOSE2_FILENAME.c_str())); + std::cout << "ProcessDose " << DOSE2_FILENAME.c_str() << std::endl; + + start = clock(); + resultListMax.reset(); + resultListMin.reset(); + + if (rtstrset.getNumberOfStructures() > 0) + { + for (int j = 0; j < rtstrset.getNumberOfStructures(); j++) + { + clock_t startLoop(clock()); + StructTypePointer spRtstr = boost::make_shared(*(rtstrset.getStructure(j))); + rttb::core::GeometricInfo geoInf = ddit.getGeometricInfo(); + + boost::shared_ptr pOTBMaskAccessor = + boost::make_shared(spRtstr, geoInf, rtdose); + MaskAcessorPointer spMaskAccessor(pOTBMaskAccessor); + boost::shared_ptr spTestMaskedDoseIterator = + boost::make_shared(spMaskAccessor, + spDoseAccessor2); //using Mask + DoseIteratorPointer mddit(spTestMaskedDoseIterator); + boost::shared_ptr spTestDoseIterator = + boost::make_shared(spDoseAccessor2); + DoseIteratorPointer ddit2(spTestDoseIterator); + mddit->reset(); + std::cout << "Initialization time: " << (clock() - startLoop) / 1000 << " s" << std::endl; + + rttb::core::DVHCalculator calc2(mddit, spRtstr->getUID(), mddit->getDoseUID()); + rttb::core::DVH dvh2 = *(calc2.getDVH()); + std::cout << "DVH(mask) max: " << dvh2.getMaximum() << "in " << spRtstr->getVolume() << " cm^3" << + std::endl; + + rttb::core::DVHCalculator calc(ddit2, spRtstr->getUID(), ddit2->getDoseUID()); + rttb::core::DVH dvh = *(calc.getDVH()); + std::cout << "DVH(dose) max: " << dvh.getMaximum() << std::endl; + + + //test statistics here? -> ../algorithms + clock_t startStats(clock()); + std::cout << "Statistics: " << std::endl; + rttb::algorithms::DoseStatistics stat(mddit); + std::cout << "Statistics time: " << (clock() - startStats) << " s" << std::endl; + std::cout << "max: " << stat.getMaximum(resultListMax) << std::endl; + std::cout << "mean: " << stat.getMean() << std::endl; + std::cout << "min: " << stat.getMinimum(resultListMin) << std::endl; + std::cout << "std: " << stat.getStdDeviation() << std::endl; + std::cout << "var: " << stat.getVariance() << std::endl; + } + } + + finish = clock(); + + std::cout << "Calculation time: " << (finish - start) / 60000 << " min" << std::endl; + + + + + RETURN_AND_REPORT_TEST_SUCCESS; + + + } + + + + + }//testing }//rttb diff --git a/testing/examples/RTDoseIndexTest.cpp b/testing/examples/RTDoseIndexTest.cpp index 3b08dca..b8c142b 100644 --- a/testing/examples/RTDoseIndexTest.cpp +++ b/testing/examples/RTDoseIndexTest.cpp @@ -1,207 +1,209 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "litCheckMacros.h" #include "rttbDoseIndex.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbBaseType.h" #include "rttbNullPointerException.h" #include "rttbConformalIndex.h" #include "rttbConformationNumber.h" #include "rttbConformityIndex.h" #include "rttbCoverageIndex.h" #include "rttbHomogeneityIndex.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" #include #include #include namespace rttb { namespace testing { /*! @brief DoseIndexTest. ConformationNumber ConformalIndex ConformityIndex CoverageIndex HomogeneityIndex are tested. test dvh: deltaV 0.125, deltaD 0.5 1. dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133 2. dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40 3. dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50 4. dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70 Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTDoseIndexTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } /*test dvh: deltaV 0.125, deltaD 0.5*/ /*dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133*/ rttb::io::other::DVHTxtFileReader dvhReader = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); rttb::core::DVH dvhPTV = *(dvhReader.generateDVH()); /*dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40*/ rttb::io::other::DVHTxtFileReader dvhReader1 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); core::DVH dvhNT1 = *(dvhReader1.generateDVH()); /*dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50*/ rttb::io::other::DVHTxtFileReader dvhReader2 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT2); core::DVH dvhNT2 = *(dvhReader2.generateDVH()); /*dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70*/ rttb::io::other::DVHTxtFileReader dvhReader3 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT3); core::DVH dvhNT3 = *(dvhReader3.generateDVH()); std::vector dvhTVSet; std::vector dvhHTSet; dvhTVSet.push_back(dvhPTV); dvhHTSet.push_back(dvhNT1); dvhHTSet.push_back(dvhNT2); dvhHTSet.push_back(dvhNT3); - ::boost::shared_ptr dvhSetPtr = ::boost::make_shared(dvhTVSet, dvhHTSet, "testStrSet", dvhPTV.getDoseID()); - + ::boost::shared_ptr dvhSetPtr = ::boost::make_shared(dvhTVSet, dvhHTSet, + "testStrSet", dvhPTV.getDoseID()); + /*test exception*/ ::boost::shared_ptr dvhSetNullPtr; CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetNullPtr, 0), core::InvalidParameterException); - CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetNullPtr, 0), core::InvalidParameterException); + CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetNullPtr, 0), + core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::CoverageIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); /*test exception for invalid reference dose*/ CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetPtr, 0), core::InvalidParameterException); /*test index calculation*/ /*RTConformationNumber */ //PTV covered by reference dose 30 = the whole PTV =362.5; Volume of the referece 30=362.5+1.25 indices::ConformationNumber cn = indices::ConformationNumber(dvhSetPtr, 30); //check if values are close. Equality is only achieved with double precission. CHECK_CLOSE(362.5 / 363.75, cn.getValue(), errorConstant); //cn==1*TV0/V0=362.5/2466.25 cn.setDoseReference(0); CHECK_CLOSE(362.5 / 2466.25, cn.getValue(), errorConstant); cn.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, cn.getValue(), errorConstant); //ref dose: 65 -> TVref=Vref -> cn=TVref/TV=2300/2900 CHECK_EQUAL(cn.getValue(), cn.getValueAt(0)); CHECK_THROW_EXPLICIT(cn.getValueAt(1), core::InvalidParameterException); /*ConformalIndex */ //HT 1 covered by ref=HT2 covered by ref=0, HT3 covered by ref=1.25 indices::ConformalIndex coin = indices::ConformalIndex(dvhSetPtr, 30); CHECK_CLOSE((362.5 / 363.75) * (1 - 1.25 / 151.25), coin.getValue(), errorConstant); coin.setDoseReference(0); CHECK_EQUAL(0, coin.getValue()); coin.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coin.getValue(), errorConstant); //ref dose: 65 -> Vref=0 for all HT -> cn=cn*(1-0)=cn CHECK_EQUAL(coin.getValue(), coin.getValueAt(0)); CHECK_THROW_EXPLICIT(coin.getValueAt(1), core::InvalidParameterException); /*ConformityIndex */ indices::ConformityIndex ci = indices::ConformityIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 363.75, ci.getValue(), errorConstant); ci.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, ci.getValue(), errorConstant); //ref dose: 65->ci=2300/2900*1*1*1 CHECK_EQUAL(ci.getValue(), ci.getValueAt(0)); CHECK_THROW_EXPLICIT(ci.getValueAt(1), core::InvalidParameterException); /*CoverageIndex*/ indices::CoverageIndex coverageI = indices::CoverageIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 362.5, coverageI.getValue(), errorConstant); //ref dose: 30 -> coverage index=1 coverageI.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coverageI.getValue(), errorConstant); //ref dose: 65->coverage index=2300/2900 CHECK_EQUAL(coverageI.getValue(), coverageI.getValueAt(0)); CHECK_THROW_EXPLICIT(coverageI.getValueAt(1), core::InvalidParameterException); /*HomogeneityIndex TV max: 133*0.5=66.5, TV min: 127*0.5=63.5 -> hi=(66.5-63.5)/30*/ indices::HomogeneityIndex hi = indices::HomogeneityIndex(dvhSetPtr, 30); CHECK_CLOSE(3 / 30.0, hi.getValue(), errorConstant); hi.setDoseReference(65); CHECK_CLOSE(3 / 65.0, hi.getValue(), errorConstant); CHECK_EQUAL(hi.getValue(), hi.getValueAt(0)); CHECK_THROW_EXPLICIT(hi.getValueAt(1), core::InvalidParameterException); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTDoseStatisticsTest.cpp b/testing/examples/RTDoseStatisticsTest.cpp index 00e03ae..ecc3b28 100644 --- a/testing/examples/RTDoseStatisticsTest.cpp +++ b/testing/examples/RTDoseStatisticsTest.cpp @@ -1,201 +1,206 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbBaseType.h" namespace rttb { namespace testing { PREPARE_DEFAULT_TEST_REPORTING; /*! @brief RTDoseStatisticsTest. Max, min, mean, standard deviation, variance, Vx, Dx, MOHx, MOCx, MaxOHx, MinOCx are tested. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed!*/ const double reducedErrorConstant = 0.0001; const double expectedVal = 5.64477e-005; const double volume = 24120.; void testWithDummyDoseData(const std::string& doseFilename); - void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, const std::string& structFilename, + void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, + const std::string& structFilename, const std::string& planFilename, unsigned int structureNr); int RTDoseStatisticsTest(int argc, char* argv[]) { std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTSTRUCT_FILENAME; std::string RTPLAN_FILENAME; if (argc > 4) { RTDOSE_FILENAME = argv[1]; RTDOSE2_FILENAME = argv[2]; RTSTRUCT_FILENAME = argv[3]; RTPLAN_FILENAME = argv[4]; } else { std::cout << "at least four arguments required for RTDoseStatisticsTest" << std::endl; return -1; } testWithDummyDoseData(RTDOSE_FILENAME); //Structure 2 is RUECKENMARK testWithRealVirtuosDoseDataAndStructure(RTDOSE2_FILENAME, RTSTRUCT_FILENAME, RTPLAN_FILENAME, 2); RETURN_AND_REPORT_TEST_SUCCESS; } void testWithDummyDoseData(const std::string& doseFilename) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef algorithms::DoseStatisticsCalculator::ResultListPointer ResultListPointer; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(doseFilename.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create corresponding DoseIterator ::boost::shared_ptr spDoseIteratorTmp = ::boost::make_shared(doseAccessor1); DoseIteratorPointer spDoseIterator(spDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(spDoseIterator); std::vector precomputedDoseValues; precomputedDoseValues.push_back(0); precomputedDoseValues.push_back(0.5); precomputedDoseValues.push_back(1); std::vector precomputedVolumeValues; - precomputedVolumeValues.push_back(20000/volume); + precomputedVolumeValues.push_back(20000 / volume); precomputedVolumeValues.push_back(1); rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = doseStatisticsCalculator.calculateDoseStatistics(precomputedDoseValues, precomputedVolumeValues); CHECK_CLOSE(doseStatistics->getMean(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getStdDeviation(), 0, errorConstant); CHECK_CLOSE(doseStatistics->getVariance(), 0, errorConstant); double dummy; - DoseTypeGy vx = doseStatistics->getVx(expectedVal,true,dummy); + DoseTypeGy vx = doseStatistics->getVx(expectedVal, true, dummy); CHECK_EQUAL(vx, doseStatistics->getVx(0)); CHECK_CLOSE(expectedVal, doseStatistics->getDx(vx), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMaximum(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getMinimum(), expectedVal, errorConstant); ResultListPointer minListPtr = doseStatistics->getMinimumPositions(); ResultListPointer maxListPtr = doseStatistics->getMaximumPositions(); CHECK_EQUAL(maxListPtr->size(), 10); CHECK_EQUAL(minListPtr->size(), 10); CHECK_CLOSE(doseStatistics->getDx(24120), doseStatistics->getMinimum(), 0.001); CHECK_CLOSE(doseStatistics->getMOHx(24120), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMOCx(20000), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMinOCx(20000), doseStatistics->getMean(), reducedErrorConstant); } - void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, const std::string& structFilename, + void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, + const std::string& structFilename, const std::string& planFilename, unsigned int structureNr) { typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef rttb::algorithms::DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef algorithms::DoseStatisticsCalculator::ResultListPointer ResultListPointer; - DoseAccessorPointer virtuosDoseAccessor = io::virtuos::VirtuosPlanFileDoseAccessorGenerator(doseFilename.c_str(), - planFilename.c_str()).generateDoseAccessor(); + DoseAccessorPointer virtuosDoseAccessor = io::virtuos::VirtuosPlanFileDoseAccessorGenerator( + doseFilename.c_str(), + planFilename.c_str()).generateDoseAccessor(); StructureSetPointer virtuosStructureSet = io::virtuos::VirtuosFileStructureSetGenerator( - structFilename.c_str(), doseFilename.c_str()).generateStructureSet(); + structFilename.c_str(), doseFilename.c_str()).generateStructureSet(); boost::shared_ptr spOTBMaskAccessorVirtuos = boost::make_shared(virtuosStructureSet->getStructure(structureNr), virtuosDoseAccessor->getGeometricInfo()); spOTBMaskAccessorVirtuos->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessorVirtuos); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, virtuosDoseAccessor); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculatorVirtuos(spMaskedDoseIterator); - DoseStatisticsPointer doseStatisticsVirtuos = doseStatisticsCalculatorVirtuos.calculateDoseStatistics(true); + DoseStatisticsPointer doseStatisticsVirtuos = + doseStatisticsCalculatorVirtuos.calculateDoseStatistics(true); //comparison values computed with "old" DoseStatistics implementation CHECK_CLOSE(doseStatisticsVirtuos->getMinimum(), 6.4089, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMaximum(), 39.0734, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMean(), 22.5779, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getStdDeviation(), 6.28857, reducedErrorConstant); ResultListPointer maxPositions = doseStatisticsVirtuos->getMaximumPositions(); ResultListPointer minPositions = doseStatisticsVirtuos->getMinimumPositions(); CHECK_EQUAL(maxPositions->size(), 1); CHECK_EQUAL(minPositions->size(), 1); CHECK_EQUAL(maxPositions->begin()->first, doseStatisticsVirtuos->getMaximum()); CHECK_EQUAL(maxPositions->begin()->second, 3570772); CHECK_EQUAL(minPositions->begin()->first, doseStatisticsVirtuos->getMinimum()); CHECK_EQUAL(minPositions->begin()->second, 3571264); - CHECK_CLOSE(doseStatisticsVirtuos->getDx(0.02 * doseStatisticsVirtuos->getVolume()), 31.8358, reducedErrorConstant); + CHECK_CLOSE(doseStatisticsVirtuos->getDx(0.02 * doseStatisticsVirtuos->getVolume()), 31.8358, + reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getVx(0.9 * doseStatisticsVirtuos->getMaximum()), 0.471747, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOHx(0.1 * doseStatisticsVirtuos->getVolume()), 31.3266, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOCx(0.05 * doseStatisticsVirtuos->getVolume()), 9.01261, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMaxOHx(0.95 * doseStatisticsVirtuos->getVolume()), 10.3764, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMinOCx(0.98 * doseStatisticsVirtuos->getVolume()), 31.8373, reducedErrorConstant); } }//testing }//rttb diff --git a/testing/examples/VoxelizationValidationTest.cpp b/testing/examples/VoxelizationValidationTest.cpp index 95cdd92..8b33bb8 100644 --- a/testing/examples/VoxelizationValidationTest.cpp +++ b/testing/examples/VoxelizationValidationTest.cpp @@ -1,199 +1,201 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbOTBMaskAccessor.h" #include "rttbDVHTxtFileReader.h" #include "rttbBoostMaskAccessor.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbImageWriter.h" namespace rttb { namespace testing { /*! @brief VoxelizationValidationTest. Compare two differnt voxelizations: OTB and Boost. Check dvh maximum and minimum for each structure. Check write mask to itk file for further validation. */ int VoxelizationValidationTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: directory name to write boost mask of all structures // 4: directory name to write OTB mask of all structures std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string BoostMask_DIRNAME; std::string OTBMask_DIRNAME; if (argc > 4) { RTSTRUCT_FILENAME = argv[1]; RTDOSE_FILENAME = argv[2]; BoostMask_DIRNAME = argv[3]; OTBMask_DIRNAME = argv[4]; } OFCondition status; DcmFileFormat fileformat; /* read dicom-rt dose */ io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create a vector of MaskAccessors (one for each structure) StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); std::vector rtStructSetMaskAccessorVec; if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) { std::cout << j << ": " << rtStructureSet->getStructure(j)->getLabel() << std::endl; clock_t start(clock()); //create OTB MaskAccessor ::boost::shared_ptr spOTBMaskAccessor = ::boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); ::boost::shared_ptr spMaskedDoseIteratorTmp = ::boost::make_shared(spMaskAccessor, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getUID()); rttb::core::DVH dvh = *(calc.generateDVH()); clock_t finish(clock()); std::cout << "OTB Mask Calculation time: " << finish - start << " ms" << std::endl; //Write the mask image to a file. /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. To write all mask files, please use the outcommented code and call the .exe directly! */ /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter(spOTBMaskAccessor); CHECK(itkConverter.process()); std::stringstream fileNameSstr; fileNameSstr << OTBMask_DIRNAME << j << ".mhd"; rttb::io::itk::ImageWriter writer(fileNameSstr.str(), itkConverter.getITKImage()); CHECK(writer.writeFile());*/ clock_t start2(clock()); //create Boost MaskAccessor - MaskAccessorPointer boostMaskAccessorPtr = ::boost::make_shared - (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); + MaskAccessorPointer boostMaskAccessorPtr + = ::boost::make_shared + (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); CHECK_NO_THROW(boostMaskAccessorPtr->updateMask()); ::boost::shared_ptr spMaskedDoseIteratorTmp2 = ::boost::make_shared(boostMaskAccessorPtr, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator2(spMaskedDoseIteratorTmp2); rttb::core::DVHCalculator calc2(spMaskedDoseIterator2, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getUID()); rttb::core::DVH dvh2 = *(calc2.generateDVH()); clock_t finish2(clock()); - std::cout << "Boost Mask Calculation and write file time: " << finish2 - start2 << " ms" << std::endl; + std::cout << "Boost Mask Calculation and write file time: " << finish2 - start2 << " ms" << + std::endl; //Write the mask image to a file. /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. To write all mask files, please use the outcommented code and call the .exe directly! */ /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter2(boostMaskAccessorPtr); CHECK(itkConverter2.process()); std::stringstream fileNameSstr2; fileNameSstr2 << BoostMask_DIRNAME << j << ".mhd"; rttb::io::itk::ImageWriter writer2(fileNameSstr2.str(), itkConverter2.getITKImage()); CHECK(writer2.writeFile());*/ //check close of 2 voxelizatin: OTB and Boost CHECK_CLOSE(dvh.getMaximum(), dvh2.getMaximum(), 0.1); CHECK_CLOSE(dvh.getMinimum(), dvh2.getMinimum(), 0.1); if (j != 7) //7: Ref.Pkt, mean = -1.#IND { CHECK_CLOSE(dvh.getMean(), dvh2.getMean(), 0.1); } CHECK_CLOSE(dvh.getMedian(), dvh2.getMedian(), 0.1); CHECK_CLOSE(dvh.getModal(), dvh2.getModal(), 0.1); //0: Aussenkontur and 3: Niere li. failed. if (j != 0 && j != 3) { CHECK_CLOSE(dvh.getVx(0), dvh2.getVx(0), dvh.getVx(0) * 0.05); //check volume difference < 5% } } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp b/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp index 8e8a406..1de49a1 100644 --- a/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp +++ b/testing/interpolation/InterpolationITKTransformation/SimpleMappableDoseAccessorWithITKTest.cpp @@ -1,188 +1,192 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbTransformationInterface.h" #include "rttbITKTransformation.h" #include "rttbNullPointerException.h" #include "itkTranslationTransform.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::ITKTransformation ITKTransformation; typedef itk::TranslationTransform TranslationTransformType; /*! @brief SimpleMappableDoseAccessorWithITKTest - test the API of SimpleMappableDoseAccessor with ITK transformation 1) Test constructor 2) test getDoseAt() a) with Identity transform b) with translation transform */ int SimpleMappableDoseAccessorWithITKTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorWithITKTest are expected" << std::endl; return -1; } const double doseGridScaling = 2.822386e-005; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); NearestNeighborInterpolation::Pointer interpolationNN = NearestNeighborInterpolation::Pointer(new NearestNeighborInterpolation()); LinearInterpolation::Pointer interpolationLinear = LinearInterpolation::Pointer (new LinearInterpolation()); //auto transformITKIdentity = TransformationInterface::Pointer(new ITKTransformation( // IdentityTransformType::New())); TranslationTransformType::Pointer transformITKIdentityTemporary = TranslationTransformType::New(); TranslationTransformType::OutputVectorType translationIdentity; translationIdentity[0] = 0.0; translationIdentity[1] = 0.0; translationIdentity[2] = 0.0; transformITKIdentityTemporary->Translate(translationIdentity); - TransformationInterface::Pointer transformITKIdentity = TransformationInterface::Pointer(new ITKTransformation( - transformITKIdentityTemporary)); + TransformationInterface::Pointer transformITKIdentity = TransformationInterface::Pointer( + new ITKTransformation( + transformITKIdentityTemporary)); TranslationTransformType::Pointer transformITKTranslationTemporary = TranslationTransformType::New(); TranslationTransformType::OutputVectorType translation; translation[0] = 5.0; translation[1] = 5.0; translation[2] = 5.0; transformITKTranslationTemporary->Translate(translation); - TransformationInterface::Pointer transformITKTranslation = TransformationInterface::Pointer(new ITKTransformation( - transformITKTranslationTemporary)); - - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorITKIdentity = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1GeometricInfo, doseAccessor2, transformITKIdentity, interpolationLinear)); - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorITKTranslation = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1GeometricInfo, doseAccessor2, transformITKTranslation, interpolationLinear)); + TransformationInterface::Pointer transformITKTranslation = TransformationInterface::Pointer( + new ITKTransformation( + transformITKTranslationTemporary)); + + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorITKIdentity = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1GeometricInfo, doseAccessor2, transformITKIdentity, interpolationLinear)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorITKTranslation = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1GeometricInfo, doseAccessor2, transformITKTranslation, interpolationLinear)); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformITKIdentity, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformITKTranslation, interpolationLinear)); CHECK_NO_THROW(ITKTransformation(transformITKTranslationTemporary.GetPointer())); CHECK_THROW_EXPLICIT(ITKTransformation(NULL), core::NullPointerException); //2) test getDoseAt() // a) with Identity transform //test valid voxels std::vector voxelsAsIndexToTest; std::vector expectedValues; voxelsAsIndexToTest.push_back(VoxelGridIndex3D(5, 9, 8)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(22, 15, 10)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(30, 20, 7)); expectedValues.push_back(5.0 * doseGridScaling); expectedValues.push_back(22.0 * doseGridScaling); expectedValues.push_back(30.0 * doseGridScaling); //convert VoxelGridIndex3D to VoxelGridID for (int i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorITKIdentity->getValueAt(voxelsAsIndexToTest.at(i)), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorITKIdentity->getValueAt(voxelsAsIndexToTest.at(i)), aSimpleMappableDoseAccessorITKIdentity->getValueAt(currentId)); } //no tests with invalid IDs, this has been done already tested in SimpleMappableDoseAccessorTest //b) with translation transform //translation of one voxel in each direction expectedValues.clear(); expectedValues.push_back(6.0 * doseGridScaling); expectedValues.push_back(23.0 * doseGridScaling); expectedValues.push_back(31.0 * doseGridScaling); for (int i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorITKTranslation->getValueAt(voxelsAsIndexToTest.at(i)), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorITKTranslation->getValueAt(voxelsAsIndexToTest.at(i)), aSimpleMappableDoseAccessorITKTranslation->getValueAt(currentId)); } RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp b/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp index 446f5ef..f631d70 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/SimpleMappableDoseAccessorWithMatchPointTest.cpp @@ -1,252 +1,257 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbGeometricInfo.h" #include "rttbTransformationInterface.h" #include "rttbMatchPointTransformation.h" #include "rttbNullPointerException.h" #include "registrationTest.h" #include "simpleRegistrationWorkflow.h" namespace rttb { namespace testing { static const unsigned int TargetDimension3D = 3; static const unsigned int MovingDimension3D = 3; typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef map::core::RegistrationTest Registration3D3DTypeTest; typedef Registration3D3DTypeTest::Pointer Registration3D3DTypeTestPointer; typedef map::core::Registration Registration3D3DType; typedef Registration3D3DType::Pointer Registration3D3DPointer; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::MatchPointTransformation MatchPointTransformation; /*! @brief SimpleMappableDoseAccessorWithMatchPointTest - test the API of SimpleMappableDoseAccessor with MatchPoint transform 1) Test constructor 2) test getDoseAt() a) with Identity transform b) with translation transform [3) test with rigid registration optional (if filenames are given as argument)] */ int SimpleMappableDoseAccessorWithMatchPointTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; std::string RTDOSE_FILENAME_REALISTIC = ""; std::string CT_PLANNING = ""; std::string CT_FRACTION = ""; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorWithMatchPointTest are expected" << std::endl; return -1; } if (argc > 5) { RTDOSE_FILENAME_REALISTIC = argv[3]; CT_PLANNING = argv[4]; CT_FRACTION = argv[5]; } rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); DoseAccessorPointer doseAccessorNull; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); Registration3D3DTypeTestPointer registration = Registration3D3DTypeTest::New(); double translation[] = {0.0, 0.0, 0.0}; registration->_translation = translation; registration->_limitedTarget = false; NearestNeighborInterpolation::Pointer interpolationNN = NearestNeighborInterpolation::Pointer(new NearestNeighborInterpolation()); LinearInterpolation::Pointer interpolationLinear = LinearInterpolation::Pointer (new LinearInterpolation()); NearestNeighborInterpolation::Pointer interpolationNull; - TransformationInterface::Pointer transformMP = TransformationInterface::Pointer(new MatchPointTransformation( - registration.GetPointer())); + TransformationInterface::Pointer transformMP = TransformationInterface::Pointer( + new MatchPointTransformation( + registration.GetPointer())); - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPIdentityLinear = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear)); - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPIdentityNN = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPIdentityLinear = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPIdentityNN = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); CHECK_NO_THROW(MatchPointTransformation(registration.GetPointer())); CHECK_THROW_EXPLICIT(MatchPointTransformation(NULL), core::NullPointerException); //2) test getDoseAt() // a) with Identity transform double vectorDoseAccessorStartEnd = 0.0; while (vectorDoseAccessorStartEnd <= 1.0) { VoxelGridID runningID = (VoxelGridID)(vectorDoseAccessorStartEnd * (double)aSimpleMappableDoseAccessorMPIdentityLinear->getGridSize()); CHECK_EQUAL(aSimpleMappableDoseAccessorMPIdentityLinear->getValueAt(runningID), doseAccessor2->getValueAt(runningID)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPIdentityNN->getValueAt(runningID), doseAccessor2->getValueAt(runningID)); vectorDoseAccessorStartEnd += 0.1; } // b) with translation transform //Second: Translation (5mm/5mm/5mm) --> in voxel: (1/1/1) as pixelspacing = 5 mm translation[0] = translation[1] = translation[2] = 5.0; registration->_translation = translation; SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPTranslationLinear = SimpleMappableDoseAccessor::Pointer(new SimpleMappableDoseAccessor( doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationLinear)); - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPTranslationNN = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorMPTranslationNN = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1GeometricInfo, doseAccessor2, transformMP, interpolationNN)); rttb::VoxelGridIndex3D aIndexBeforeTransformation(0, 0, 0); rttb::VoxelGridIndex3D aIndexAfterTransformation(1, 1, 1); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation), doseAccessor2->getValueAt(aIndexAfterTransformation)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation), doseAccessor2->getValueAt(aIndexAfterTransformation)); rttb::VoxelGridIndex3D aIndexBeforeTransformation2(20, 10, 10); rttb::VoxelGridIndex3D aIndexAfterTransformation2(21, 11, 11); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation2), doseAccessor2->getValueAt(aIndexAfterTransformation2)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation2), doseAccessor2->getValueAt(aIndexAfterTransformation2)); rttb::VoxelGridIndex3D aIndexBeforeTransformation3( aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumColumns() - 2, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumRows() - 2, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumSlices() - 2); rttb::VoxelGridIndex3D aIndexAfterTransformation3( aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumColumns() - 1, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumRows() - 1, aSimpleMappableDoseAccessorMPTranslationLinear->getGeometricInfo().getNumSlices() - 1); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationLinear->getValueAt(aIndexBeforeTransformation3), doseAccessor2->getValueAt(aIndexAfterTransformation3)); CHECK_EQUAL(aSimpleMappableDoseAccessorMPTranslationNN->getValueAt(aIndexBeforeTransformation3), doseAccessor2->getValueAt(aIndexAfterTransformation3)); if (RTDOSE_FILENAME_REALISTIC != "" && CT_FRACTION != "" && CT_PLANNING != "") { //3) test with rigid registration //realistic background: registration from BP-CT to fraction CT, apply on planning dose that is based on BP-CT (proof of concept) //Target image: fraction CT, Moving image: planning CT simpleRegistrationWorkflow prepareRegistrationRealisticScenario(CT_FRACTION, CT_PLANNING, true); Registration3D3DPointer registrationRealisticScenario = prepareRegistrationRealisticScenario.getRegistration(); - TransformationInterface::Pointer transformRealistic = TransformationInterface::Pointer(new MatchPointTransformation( - registrationRealisticScenario)); + TransformationInterface::Pointer transformRealistic = TransformationInterface::Pointer( + new MatchPointTransformation( + registrationRealisticScenario)); io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE_FILENAME_REALISTIC.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); core::GeometricInfo geoInfoRealistic; geoInfoRealistic.setNumColumns( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[0]); geoInfoRealistic.setNumRows( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[1]); geoInfoRealistic.setNumSlices( prepareRegistrationRealisticScenario.getTargetImage()->GetLargestPossibleRegion().GetSize()[2]); //Dose is related to BP-CT, map dose to fraction CT geometry SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorRealisticScenarioLinear = SimpleMappableDoseAccessor::Pointer(new SimpleMappableDoseAccessor(geoInfoRealistic, doseAccessor3, transformRealistic, interpolationLinear)); //combination of 0, size/2 and size to check as coordinates std::vector coordinatesToCheckX, coordinatesToCheckY, coordinatesToCheckZ; coordinatesToCheckX.push_back(0); coordinatesToCheckX.push_back(geoInfoRealistic.getNumColumns() / 2); coordinatesToCheckX.push_back(geoInfoRealistic.getNumColumns() - 1); coordinatesToCheckY.push_back(0); coordinatesToCheckY.push_back(geoInfoRealistic.getNumRows() / 2); coordinatesToCheckY.push_back(geoInfoRealistic.getNumRows() - 1); coordinatesToCheckZ.push_back(0); coordinatesToCheckZ.push_back(geoInfoRealistic.getNumSlices() / 2); coordinatesToCheckZ.push_back(geoInfoRealistic.getNumSlices() - 1); //Pixels are inside the fraction CT image and mapping should work (even if they map outside of doseAccessor3) for (unsigned int i = 0; i < coordinatesToCheckX.size(); ++i) { for (unsigned int j = 0; j < coordinatesToCheckY.size(); ++j) { for (unsigned int k = 0; k < coordinatesToCheckZ.size(); ++k) { CHECK_NO_THROW(aSimpleMappableDoseAccessorRealisticScenarioLinear->getValueAt(VoxelGridIndex3D( coordinatesToCheckX.at(i), coordinatesToCheckY.at(j), coordinatesToCheckZ.at(k)))); } } } } RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp index 4aa1dd9..8a21f65 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.cpp @@ -1,88 +1,88 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "registrationHelper.h" #include "litTestImageIO.h" #include "litCheckMacros.h" #include "litImageTester.h" #include "litPointSetTester.h" #include int setImageFileNames(std::string targetImage, std::string movingImage, bool isDirectory, AppGlobals& globals) { globals.targetImageFileName = targetImage; globals.movingImageFileName = movingImage; globals.isDirectory = isDirectory; return EXIT_SUCCESS; } int loadData(AppGlobals& globals) { if (!globals.isDirectory) { globals.spTargetImage = lit::TestImageIO::InternalImageType>::readImage( globals.targetImageFileName); } else { globals.spTargetImage = map::io::readImage (globals.targetImageFileName, map::io::ImageSeriesReadStyle::Dicom); } if (globals.spTargetImage.IsNull()) { std::cerr << "Error. Cannot load target image: " << globals.targetImageFileName << std::endl; return EXIT_FAILURE; } if (!globals.isDirectory) { globals.spMovingImage = lit::TestImageIO::InternalImageType>::readImage( globals.movingImageFileName); } else { globals.spMovingImage = map::io::readImage (globals.movingImageFileName, map::io::ImageSeriesReadStyle::Dicom); } if (globals.spMovingImage.IsNull()) { std::cerr << "Error. Cannot load moving image: " << globals.movingImageFileName << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } AppGlobals::AppGlobals() { }; \ No newline at end of file diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h index dc788b3..ee79206 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationHelper.h @@ -1,56 +1,56 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #ifndef __REGISTRATION_HELPER_H #define __REGISTRATION_HELPER_H #include "mapContinuousElements.h" #include "mapDiscreteElements.h" #include "mapImageReader.h" typedef map::core::discrete::Elements<3>::InternalImageType ImageType; typedef map::core::continuous::Elements<3>::InternalPointSetType LandmarksType; struct AppGlobals { std::string targetImageFileName; std::string movingImageFileName; bool isDirectory; ImageType::Pointer spTargetImage; ImageType::Pointer spMovingImage; ImageType::Pointer spResultImage; AppGlobals(); }; int setImageFileNames(std::string targetImage, std::string movingImage, bool isDirectory, AppGlobals& globals); int loadData(AppGlobals& globals); #endif \ No newline at end of file diff --git a/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h b/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h index 131c9ff..ee23b74 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/registrationTest.h @@ -1,82 +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: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __REGISTRATION_TEST_H #define __REGISTRATION_TEST_H #include "mapRegistration.h" namespace map { namespace core { /*! @class TestRegistration @brief Simple implementation of MatchPoint Registration class with direct access to mapping. */ template class RegistrationTest: public Registration { public: typedef RegistrationTest Self; typedef RegistrationBase Superclass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; - typedef typename Registration::TargetPointType TargetPointType; - typedef typename Registration::MovingPointType MovingPointType; + typedef typename Registration::TargetPointType + TargetPointType; + typedef typename Registration::MovingPointType + MovingPointType; itkTypeMacro(RegistrationTest, Registration); itkNewMacro(Self); bool _limitedTarget; double* _translation; RegistrationTest() {}; ~RegistrationTest() { }; virtual bool mapPointInverse(const TargetPointType& inPoint, MovingPointType& outPoint) const { for (unsigned int i = 0; i < VTargetDimensions; i++) { outPoint[i] = inPoint[i] + _translation[i]; } return true; }; virtual bool hasLimitedTargetRepresentation() const { return _limitedTarget; } private: RegistrationTest(const Self& source); //purposely not implemented void operator=(const Self&); //purposely not implemented }; } } #endif diff --git a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp index b8810f4..e2c0502 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp +++ b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.cpp @@ -1,113 +1,113 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #undef MAP_SEAL_ALGORITHMS #include "simpleRegistrationWorkflow.h" #include "registrationHelper.h" simpleRegistrationWorkflow::simpleRegistrationWorkflow(std::string targetFilename, std::string movingFilename, bool isDirectory) { _targetFilename = targetFilename; _movingFilename = movingFilename; setImageFileNames(_targetFilename, _movingFilename, isDirectory, globals); loadData(globals); _spAlgorithmEuler = NULL; } vnl_vector simpleRegistrationWorkflow::getRegistrationParameters( Registration3D3DPointer reg) { typedef map::core::ModelBasedRegistrationKernel<3, 3> ModelBasedRegistrationKernel3D3D; const ModelBasedRegistrationKernel3D3D* pModelBasedDirectKernel3D3D = dynamic_cast(&(reg->getDirectMapping())); if (pModelBasedDirectKernel3D3D) { ModelBasedRegistrationKernel3D3D::ParametersType params = pModelBasedDirectKernel3D3D->getTransformModel()->GetParameters(); return params; } else { return vnl_vector(); } } void simpleRegistrationWorkflow::initializeAndPerformRegistration() { _spAlgorithmEuler = AlgorithmTypeEuler::New(); _spAlgorithmEuler->setProperty("PreinitTransform", map::core::MetaProperty::New(true)); _spAlgorithmEuler->setMovingImage(globals.spMovingImage); _spAlgorithmEuler->setTargetImage(globals.spTargetImage); AlgorithmTypeEuler::RegistrationType::Pointer spRegistration; try { spRegistration = _spAlgorithmEuler->getRegistration(); } catch (const map::core::ExceptionObject& e) { std::cerr << "caught an MatchPoint exception:\n"; e.Print(std::cerr); std::cerr << "\n"; } catch (const itk::ExceptionObject& e) { std::cerr << "caught an ITK exception:\n"; std::cerr << e.GetFile() << ":" << e.GetLine() << ":\n" << e.GetDescription() << "\n"; } catch (const std::exception& e) { std::cerr << "caught an exception:\n"; std::cerr << e.what() << "\n"; } catch (...) { std::cerr << "caught an unknown exception!!!\n"; } } map::core::Registration<3, 3>::Pointer simpleRegistrationWorkflow::getRegistration() { if (_spAlgorithmEuler.IsNull()) { initializeAndPerformRegistration(); } return _spAlgorithmEuler->getRegistration(); }; const itk::Image* simpleRegistrationWorkflow::getTargetImage() { if (_spAlgorithmEuler.IsNull()) { initializeAndPerformRegistration(); } return _spAlgorithmEuler->getTargetImage(); }; diff --git a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h index 71912da..75baffa 100644 --- a/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h +++ b/testing/interpolation/InterpolationMatchPointTransformation/simpleRegistrationWorkflow.h @@ -1,63 +1,63 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 741 $ (last changed revision) -// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ #ifndef __SIMPLE_REGISTRATION_WORKFLOW_H #define __SIMPLE_REGISTRATION_WORKFLOW_H #include #include "registrationHelper.h" #include "mapImageMappingTask.h" #include "mapITKEuler3DMattesMIRegistrationAlgorithmTemplate.h" #include "mapExceptionObject.h" /*! @class simpleRegistrationWorkflow @brief implements a concrete registration algorithm of MatchPoint */ class simpleRegistrationWorkflow { public: typedef map::core::Registration<3, 3> Registration3D3DType; typedef Registration3D3DType::Pointer Registration3D3DPointer; typedef map::algorithm::boxed::ITKEuler3DMattesMIRegistrationAlgorithm AlgorithmTypeEuler; private: std::string _targetFilename; std::string _movingFilename; std::string _targetDirectory; std::string _movingDirectory; AppGlobals globals; AlgorithmTypeEuler::Pointer _spAlgorithmEuler; public: /*! @brief Constructor */ simpleRegistrationWorkflow(std::string targetFilename, std::string movingFilename, bool isDirectory = false); map::core::Registration<3, 3>::Pointer getRegistration(); const itk::Image* getTargetImage(); vnl_vector getRegistrationParameters(Registration3D3DPointer reg); protected: void initializeAndPerformRegistration(); }; #endif \ No newline at end of file diff --git a/testing/interpolation/SimpleMappableDoseAccessorTest.cpp b/testing/interpolation/SimpleMappableDoseAccessorTest.cpp index 1ec7c42..af1bff7 100644 --- a/testing/interpolation/SimpleMappableDoseAccessorTest.cpp +++ b/testing/interpolation/SimpleMappableDoseAccessorTest.cpp @@ -1,166 +1,170 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbNearestNeighborInterpolation.h" #include "rttbLinearInterpolation.h" #include "rttbTransformationInterface.h" #include "DummyTransformation.h" #include "rttbNullPointerException.h" #include "rttbMappingOutsideOfImageException.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef rttb::interpolation::SimpleMappableDoseAccessor SimpleMappableDoseAccessor; typedef rttb::interpolation::TransformationInterface TransformationInterface; typedef rttb::interpolation::LinearInterpolation LinearInterpolation; typedef rttb::interpolation::NearestNeighborInterpolation NearestNeighborInterpolation; /*! @brief SimpleMappableDoseAccessorTest - test the API of SimpleMappableDoseAccessor 1) Test constructor 2) test getDoseAt() */ int SimpleMappableDoseAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for SimpleMappableDoseAccessorTest are expected" << std::endl; return -1; } const double doseGridScaling = 2.822386e-005; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); DoseAccessorPointer doseAccessorNull; - TransformationInterface::Pointer transformDummy = TransformationInterface::Pointer(new DummyTransformation()); + TransformationInterface::Pointer transformDummy = TransformationInterface::Pointer( + new DummyTransformation()); TransformationInterface::Pointer transformNull; NearestNeighborInterpolation::Pointer interpolationNN = NearestNeighborInterpolation::Pointer(new NearestNeighborInterpolation()); - LinearInterpolation::Pointer interpolationLinear = LinearInterpolation::Pointer(new LinearInterpolation()); + LinearInterpolation::Pointer interpolationLinear = LinearInterpolation::Pointer( + new LinearInterpolation()); boost::shared_ptr interpolationNull; - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorDefault = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear)); - SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorNoPadding = SimpleMappableDoseAccessor::Pointer( - new SimpleMappableDoseAccessor( - doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, false)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorDefault = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear)); + SimpleMappableDoseAccessor::Pointer aSimpleMappableDoseAccessorNoPadding = + SimpleMappableDoseAccessor::Pointer( + new SimpleMappableDoseAccessor( + doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, false)); //1) Test constructor CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear)); CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, false)); CHECK_NO_THROW(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformDummy, interpolationLinear, true, 5.0)); CHECK_NO_THROW(SimpleMappableDoseAccessor(doseAccessor1GeometricInfo, doseAccessor2, transformDummy, interpolationNN)); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformDummy, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessor2, transformNull, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor test(doseAccessor1->getGeometricInfo(), doseAccessorNull, transformNull, interpolationLinear), core::NullPointerException); CHECK_THROW_EXPLICIT(SimpleMappableDoseAccessor(doseAccessor1GeometricInfo, doseAccessor2, transformDummy, interpolationNull), core::NullPointerException); //2) test getGeometricInfo(), getGridSize(), getDoseUID() function CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getGeometricInfo(), doseAccessor1->getGeometricInfo()); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getGridSize(), doseAccessor1->getGeometricInfo().getNumberOfVoxels()); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getUID(), doseAccessor2->getUID()); //3) test getDoseAt() //test valid voxels std::vector voxelsAsIndexToTest; std::vector expectedValues; voxelsAsIndexToTest.push_back(VoxelGridIndex3D(5, 9, 8)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(22, 15, 10)); voxelsAsIndexToTest.push_back(VoxelGridIndex3D(30, 20, 7)); expectedValues.push_back(5.0 * doseGridScaling); expectedValues.push_back(22.0 * doseGridScaling); expectedValues.push_back(30.0 * doseGridScaling); for (int i = 0; i < voxelsAsIndexToTest.size(); i++) { VoxelGridID currentId; doseAccessor1GeometricInfo.convert(voxelsAsIndexToTest.at(i), currentId); //test if the expected interpolation values are computed CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(currentId), expectedValues.at(i)); //test if getDoseAt(VoxelGridIndex3D) and getDoseAt(VoxelGridD) lead to the same results CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(currentId), aSimpleMappableDoseAccessorDefault->getValueAt(voxelsAsIndexToTest.at(i))); } //test invalid voxels VoxelGridID invalidID(doseAccessor1GeometricInfo.getNumberOfVoxels() + 1); VoxelGridIndex3D invalidIndex(doseAccessor1GeometricInfo.getNumColumns() + 1, doseAccessor1GeometricInfo.getNumRows() + 1, doseAccessor1GeometricInfo.getNumSlices() + 1); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(invalidID), 0.0); CHECK_EQUAL(aSimpleMappableDoseAccessorDefault->getValueAt(invalidIndex), 0.0); CHECK_THROW_EXPLICIT(aSimpleMappableDoseAccessorNoPadding->getValueAt(invalidID), core::MappingOutsideOfImageException); CHECK_THROW_EXPLICIT(aSimpleMappableDoseAccessorNoPadding->getValueAt(invalidIndex), core::MappingOutsideOfImageException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/io/dicom/DicomDoseAccessorConverterTest.cpp b/testing/io/dicom/DicomDoseAccessorConverterTest.cpp index 3654154..8907aec 100644 --- a/testing/io/dicom/DicomDoseAccessorConverterTest.cpp +++ b/testing/io/dicom/DicomDoseAccessorConverterTest.cpp @@ -1,149 +1,158 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileDoseAccessorWriter.h" #include "rttbInvalidDoseException.h" #include "rttbDcmrtException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*!@brief DicomDoseAccessorGeneratorTest - test the generators for dicom data 1) test dicom file generator generateDoseAccessor() 2) test dicom IOD generator generateDoseAccessor() */ int DicomDoseAccessorConverterTest(int argc, char* argv[]) { typedef boost::shared_ptr DRTDoseIODPointer; typedef rttb::io::dicom::DicomDoseAccessor::DoseAccessorPointer DoseAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: the file name of the dose to read // 2: the file name of the dose to write std::string RTDOSE_FILENAME_R; std::string RTDOSE_FILENAME_W; if (argc > 2) { RTDOSE_FILENAME_R = argv[1]; RTDOSE_FILENAME_W = argv[2]; } double errorConstant = 1e-3; DoseAccessorPointer doseAccessor_r = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME_R.c_str()).generateDoseAccessor(); CHECK_NO_THROW(io::dicom::DicomFileDoseAccessorWriter()); io::dicom::DicomFileDoseAccessorWriter doseConverter; CHECK_NO_THROW(doseConverter.setDoseAccessor(doseAccessor_r)); CHECK_NO_THROW(doseConverter.setFileName(RTDOSE_FILENAME_W)); CHECK_EQUAL(doseConverter.process(), true); DoseAccessorPointer doseAccessor_w = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME_W).generateDoseAccessor(); //Check geometricinfo CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImagePositionPatient().x(), doseAccessor_w->getGeometricInfo().getImagePositionPatient().x(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImagePositionPatient().y(), doseAccessor_w->getGeometricInfo().getImagePositionPatient().y(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImagePositionPatient().z(), doseAccessor_w->getGeometricInfo().getImagePositionPatient().z(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationColumn().x(), doseAccessor_w->getGeometricInfo().getImageOrientationColumn().x(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationColumn().y(), doseAccessor_w->getGeometricInfo().getImageOrientationColumn().y(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationColumn().z(), doseAccessor_w->getGeometricInfo().getImageOrientationColumn().z(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationRow().x(), doseAccessor_w->getGeometricInfo().getImageOrientationRow().x(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationRow().y(), doseAccessor_w->getGeometricInfo().getImageOrientationRow().y(), errorConstant); CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getImageOrientationRow().z(), doseAccessor_w->getGeometricInfo().getImageOrientationRow().z(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().x(), doseAccessor_w->getGeometricInfo().getSpacing().x(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().x(), + doseAccessor_w->getGeometricInfo().getSpacing().x(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().y(), doseAccessor_w->getGeometricInfo().getSpacing().y(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().y(), + doseAccessor_w->getGeometricInfo().getSpacing().y(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().z(), doseAccessor_w->getGeometricInfo().getSpacing().z(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getSpacing().z(), + doseAccessor_w->getGeometricInfo().getSpacing().z(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumColumns(), doseAccessor_w->getGeometricInfo().getNumColumns(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumColumns(), + doseAccessor_w->getGeometricInfo().getNumColumns(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumRows(), doseAccessor_w->getGeometricInfo().getNumRows(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumRows(), + doseAccessor_w->getGeometricInfo().getNumRows(), errorConstant); - CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumSlices(), doseAccessor_w->getGeometricInfo().getNumSlices(), + CHECK_CLOSE(doseAccessor_r->getGeometricInfo().getNumSlices(), + doseAccessor_w->getGeometricInfo().getNumSlices(), errorConstant); //Check pixel data - int size = doseAccessor_r->getGeometricInfo().getNumColumns() * doseAccessor_r->getGeometricInfo().getNumRows() * + int size = doseAccessor_r->getGeometricInfo().getNumColumns() * + doseAccessor_r->getGeometricInfo().getNumRows() * doseAccessor_r->getGeometricInfo().getNumSlices() ; for (unsigned int index = 0; index < 30; index++) { CHECK_CLOSE(doseAccessor_r->getValueAt(index), doseAccessor_w->getValueAt(index), errorConstant); if (size / 2 - index >= 0 && size / 2 - index < size) { - CHECK_CLOSE(doseAccessor_r->getValueAt(size / 2 - index), doseAccessor_w->getValueAt(size / 2 - index), errorConstant); + CHECK_CLOSE(doseAccessor_r->getValueAt(size / 2 - index), + doseAccessor_w->getValueAt(size / 2 - index), errorConstant); } - CHECK_CLOSE(doseAccessor_r->getValueAt(size - index - 1), doseAccessor_w->getValueAt(size - index - 1), errorConstant); + CHECK_CLOSE(doseAccessor_r->getValueAt(size - index - 1), + doseAccessor_w->getValueAt(size - index - 1), errorConstant); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/dicom/DicomFileReaderHelperTest.cpp b/testing/io/dicom/DicomFileReaderHelperTest.cpp index a2dedf2..3ad5651 100644 --- a/testing/io/dicom/DicomFileReaderHelperTest.cpp +++ b/testing/io/dicom/DicomFileReaderHelperTest.cpp @@ -1,94 +1,98 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomFileReaderHelper.h" namespace rttb { namespace testing { /*!@brief DicomDoseAccessorGeneratorTest - test the generators for dicom data 1) test getFileNamesWithSameUID() with a directory name 2) test getFileNames() with a RTDOSE file name and check equal with getFileNamesWithSameUID() 3) test getFileNames() with a RTSTRUCT file name */ int DicomFileReaderHelperTest(int argc, char* argv[]) { typedef boost::shared_ptr DRTDoseIODPtr; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: helax directory name // 2: dose file name // 3: structure file name std::string RT_DIRNAME; std::string RTDOSE_FILENAME; std::string RTStr_FILENAME; if (argc > 3) { RT_DIRNAME = argv[1]; RTDOSE_FILENAME = argv[2]; RTStr_FILENAME = argv[3]; } - rttb::io::dicom::Modality doseModality= {rttb::io::dicom::Modality::RTDOSE}; - rttb::io::dicom::Modality strModality= {rttb::io::dicom::Modality::RTSTRUCT}; + + rttb::io::dicom::Modality doseModality = {rttb::io::dicom::Modality::RTDOSE}; + rttb::io::dicom::Modality strModality = {rttb::io::dicom::Modality::RTSTRUCT}; //1) test getFileNamesWithSameUID() with a directory name - std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(RT_DIRNAME, doseModality); + std::vector fileVector = rttb::io::dicom::getFileNamesWithSameUID(RT_DIRNAME, + doseModality); CHECK_EQUAL(fileVector.size(), 52); //2) test getFileNames() with a RTDOSE file name and check equal with getFileNamesWithSameUID() std::vector fileVector2 = rttb::io::dicom::getFileNames(RTDOSE_FILENAME); - for(int i=0; i #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbAccessorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbLQModelAccessor.h" #include "rttbITKImageAccessor.h" #include "rttbITKImageFileAccessorGenerator.h" #include "rttbITKImageAccessorGenerator.h" #include "rttbITKImageAccessorConverter.h" #include "rttbDoseAccessorProcessorBase.h" #include "rttbDoseAccessorConversionSettingInterface.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace testing { /*!@brief ITKBioModelAccessorConverterTest - test the conversion rttb BioModel accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) */ int ITKBioModelAccessorConverterTest(int argc, char* argv[]) { typedef core::AccessorInterface::AccessorPointer AccessorPointer; typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } //1) Read dicomFile and test process() and getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor(doseAccessorGenerator.generateDoseAccessor()); - AccessorPointer LQWithConstantDose = boost::make_shared(doseAccessor, 0.2, 0.02); + AccessorPointer LQWithConstantDose = boost::make_shared(doseAccessor, 0.2, + 0.02); io::itk::ITKImageAccessorConverter itkConverter(LQWithConstantDose); CHECK_NO_THROW(itkConverter.process()); CHECK_NO_THROW(itkConverter.getITKImage()); io::itk::ITKImageAccessor::ITKImageType::IndexType itkIndex; itkIndex[0] = itkIndex[1] = itkIndex[2] = 0; VoxelGridIndex3D rttbIndex(0, 0, 0); - CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); + CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), + LQWithConstantDose->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() / 2; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() / 2; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() / 2; - CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); + CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), + LQWithConstantDose->getValueAt(rttbIndex)); itkIndex[0] = rttbIndex[0] = doseAccessor->getGeometricInfo().getNumColumns() - 1; itkIndex[1] = rttbIndex[1] = doseAccessor->getGeometricInfo().getNumRows() - 1; itkIndex[2] = rttbIndex[2] = doseAccessor->getGeometricInfo().getNumSlices() - 1; - CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), LQWithConstantDose->getValueAt(rttbIndex)); + CHECK_EQUAL(itkConverter.getITKImage()->GetPixel(itkIndex), + LQWithConstantDose->getValueAt(rttbIndex)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKMaskAccessorConverterTest.cpp b/testing/io/itk/ITKMaskAccessorConverterTest.cpp index 4cfe546..dca4301 100644 --- a/testing/io/itk/ITKMaskAccessorConverterTest.cpp +++ b/testing/io/itk/ITKMaskAccessorConverterTest.cpp @@ -1,179 +1,180 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbOTBMaskAccessor.h" #include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*!@brief MaskAccessorConverterTest - test the conversion rttb dose accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) 2) test with mhd file (ITKImageFileDoseAccessorGenerator) */ int ITKMaskAccessorConverterTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; typedef io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer ITKImageTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: //ARGUMENTS: 1: structure file name // 2: dose1 file name std::string RTStr_FILENAME; std::string RTDose_FILENAME; std::string Mask_FILENAME; if (argc > 3) { RTStr_FILENAME = argv[1]; RTDose_FILENAME = argv[2]; Mask_FILENAME = argv[3]; } //1) Read dicomFile and test getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDose_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTStr_FILENAME.c_str()).generateStructureSet(); MaskAccessorPointer maskAccessorPtr = boost::make_shared (rtStructureSet->getStructure(9), doseAccessor1->getGeometricInfo()); maskAccessorPtr->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskAccessorPtr); CHECK_NO_THROW(maskAccessorConverter.process()); CHECK_NO_THROW(maskAccessorConverter.getITKImage()); //2) Read itk image, generate mask and convert it back to itk image, check equal MaskAccessorPointer maskAccessorPtr2 = io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor(); maskAccessorPtr2->updateMask();//!Important: Update the mask before conversion. io::itk::ITKImageMaskAccessorConverter maskAccessorConverter2(maskAccessorPtr2); maskAccessorConverter2.process(); typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; ITKImageTypePointer convertedImagePtr = maskAccessorConverter2.getITKImage(); io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer expectedImage = lit::TestImageIO::readImage( Mask_FILENAME); CHECK_EQUAL(convertedImagePtr->GetOrigin()[0], expectedImage->GetOrigin()[0]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[1], expectedImage->GetOrigin()[1]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[2], expectedImage->GetOrigin()[2]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[0], expectedImage->GetSpacing()[0]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[1], expectedImage->GetSpacing()[1]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[2], expectedImage->GetSpacing()[2]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[0], expectedImage->GetLargestPossibleRegion().GetSize()[0]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[1], expectedImage->GetLargestPossibleRegion().GetSize()[1]); CHECK_EQUAL(convertedImagePtr->GetLargestPossibleRegion().GetSize()[2], expectedImage->GetLargestPossibleRegion().GetSize()[2]); int sizeX = convertedImagePtr->GetLargestPossibleRegion().GetSize()[0]; int sizeY = convertedImagePtr->GetLargestPossibleRegion().GetSize()[1]; int sizeZ = convertedImagePtr->GetLargestPossibleRegion().GetSize()[2]; io::itk::ITKImageMaskAccessor::ITKMaskImageType::IndexType index; for (unsigned int i = 0; i < 20 && i < sizeX && i < sizeY && i < sizeZ; i++) { index[0] = i; index[1] = i; index[2] = i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for (unsigned int i = 0; i < 20; i++) { index[0] = sizeX - 1 - i; index[1] = sizeY - 1 - i; index[2] = sizeZ - 1 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } - for (unsigned int i = 0; i < 20 && (sizeX / 2 - i) < sizeX && (sizeY / 2 - i) < sizeY && (sizeZ / 2 - i) < sizeZ; i++) + for (unsigned int i = 0; i < 20 && (sizeX / 2 - i) < sizeX && (sizeY / 2 - i) < sizeY + && (sizeZ / 2 - i) < sizeZ; i++) { index[0] = sizeX / 2 - i; index[1] = sizeY / 2 - i; index[2] = sizeZ / 2 - i; if (expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index) <= 1) { CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp index 1511da8..fe97378 100644 --- a/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp +++ b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp @@ -1,97 +1,98 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbInvalidDoseException.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbITKImageMaskAccessorGenerator.h" namespace rttb { namespace testing { /*!@brief MaskAccessorGeneratorTest - test the generators for dicom data 1) test itk file generator generateDoseAccessor() 2) test itk generator generateDoseAccessor() */ int ITKMaskAccessorGeneratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: mhd/raw file name std::string Mask_FILENAME; if (argc > 1) { Mask_FILENAME = argv[1]; } - + /* test ITKImageFileMaskAccessorGenerator generateDoseAccessor()*/ CHECK_THROW_EXPLICIT(io::itk::ITKImageFileMaskAccessorGenerator("test.test").generateMaskAccessor(), core::InvalidDoseException); CHECK_NO_THROW(io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor()); /* test ITKImageMaskAccessorGenerator generateDoseAccessor()*/ typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; MaskImageType::Pointer invalidDose = MaskImageType::New(); ReaderType::Pointer reader = ReaderType::New(); CHECK_THROW_EXPLICIT(io::itk::ITKImageMaskAccessorGenerator( invalidDose.GetPointer()).generateMaskAccessor(), core::InvalidDoseException); reader->SetFileName(Mask_FILENAME); //important to update the reader (won't work without) reader->Update(); CHECK_NO_THROW(io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor()); - - io::itk::ITKImageMaskAccessorGenerator::MaskAccessorPointer maskAcc = io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor(); - CHECK_NO_THROW( maskAcc->getRelevantVoxelVector()); + io::itk::ITKImageMaskAccessorGenerator::MaskAccessorPointer maskAcc = + io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor(); + + CHECK_NO_THROW(maskAcc->getRelevantVoxelVector()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/CompareDVH.cpp b/testing/io/other/CompareDVH.cpp index 75381d7..be87039 100644 --- a/testing/io/other/CompareDVH.cpp +++ b/testing/io/other/CompareDVH.cpp @@ -1,53 +1,60 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "CompareDVH.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { - bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2){ + bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2) + { bool result; const double errorConstant = 1e-7; result = lit::AreClose(aDVH1->getDeltaD(), aDVH2->getDeltaD(), errorConstant); result = result && lit::AreClose(aDVH1->getDeltaV(), aDVH2->getDeltaV(), errorConstant); result = result && (aDVH1->getDoseID() == aDVH2->getDoseID()); result = result && (aDVH1->getStructureID() == aDVH2->getStructureID()); result = result && lit::AreClose(aDVH1->getMaximum(), aDVH2->getMaximum(), errorConstant); result = result && lit::AreClose(aDVH1->getMinimum(), aDVH2->getMinimum(), errorConstant); result = result && lit::AreClose(aDVH1->getMean(), aDVH2->getMean(), errorConstant); result = result && (aDVH1->getDataDifferential().size() == aDVH2->getDataDifferential().size()); - for(int i=0; igetDataDifferential().size(); i++){ - result = result && lit::AreClose(aDVH1->getDataDifferential().at(i), aDVH2->getDataDifferential().at(i), errorConstant); + + for (int i = 0; i < aDVH1->getDataDifferential().size(); i++) + { + result = result + && lit::AreClose(aDVH1->getDataDifferential().at(i), aDVH2->getDataDifferential().at(i), + errorConstant); } return result; } }//testing }//rttb diff --git a/testing/io/other/CompareDVH.h b/testing/io/other/CompareDVH.h index a1cba2b..d9c24eb 100644 --- a/testing/io/other/CompareDVH.h +++ b/testing/io/other/CompareDVH.h @@ -1,42 +1,44 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include "rttbDVH.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { typedef core::DVH::DVHPointer DVHPointer; /*! Compare 2 dvhs and return the results. @result Indicates if the test was successfull (true) or if it failed (false) */ bool checkEqualDVH(DVHPointer aDVH1, DVHPointer aDVH2); }//testing }//rttb diff --git a/testing/io/other/DVHTXTIOTest.cpp b/testing/io/other/DVHTXTIOTest.cpp index e6460a1..d7294fa 100644 --- a/testing/io/other/DVHTXTIOTest.cpp +++ b/testing/io/other/DVHTXTIOTest.cpp @@ -1,150 +1,153 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVHTxtFileWriter.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDVHGenerator.h" #include "CompareDVH.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { /*! @brief DVHTXTIOTest - test the IO for DVH txt data 1) test writing dvh to text file - 2) test reading DVH from text file + 2) test reading DVH from text file 3) test reading and writing the same dvh */ - int DVHTXTIOTest(int argc, char* argv[] ) + int DVHTXTIOTest(int argc, char* argv[]) { typedef core::DVHSet::DVHSetType DVHSetType; typedef core::DVH::DVHPointer DVHPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string DVHTXT_FILENAME; - if (argc>1) + if (argc > 1) { DVHTXT_FILENAME = argv[1]; } /* generate dummy DVH */ const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; - DummyDVHGenerator dvhGenerator; + DummyDVHGenerator dvhGenerator; - DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix,doseID)); + DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix, + doseID)); // 1) test writing DVH to text file DVHType typeCum = {DVHType::Cumulative}; DVHType typeDiff = {DVHType::Differential}; FileNameString fN1 = "test.txt"; CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeDiff)); CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeCum)); - io::other::DVHTxtFileWriter dvhWriter (fN1, typeCum); + io::other::DVHTxtFileWriter dvhWriter(fN1, typeCum); CHECK_EQUAL(fN1, dvhWriter.getFileName()); FileNameString fN2 = "otherFile.txt"; CHECK_NO_THROW(dvhWriter.setFileName(fN2)); CHECK_EQUAL(fN2, dvhWriter.getFileName()); CHECK_EQUAL(DVHType::Cumulative, dvhWriter.getDVHType().Type); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_EQUAL(DVHType::Differential, dvhWriter.getDVHType().Type); DVHPointer emptyDvh; - CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh),core::NullPointerException); + CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh), core::NullPointerException); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_NO_THROW(dvhWriter.writeDVH(spMyDVH)); - // 2) test reading DVH from text file + // 2) test reading DVH from text file CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN1)); io::other::DVHTxtFileReader dvhReaderTest(fN1); - CHECK_THROW_EXPLICIT(dvhReaderTest.generateDVH(),core::InvalidParameterException); + CHECK_THROW_EXPLICIT(dvhReaderTest.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN2)); io::other::DVHTxtFileReader dvhReader(fN2); CHECK_NO_THROW(dvhReader.resetFileName(fN1)); CHECK_THROW_EXPLICIT(dvhReader.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(dvhReader.resetFileName(fN2)); CHECK_NO_THROW(dvhReader.generateDVH()); - + DVHPointer importedDVH = dvhReader.generateDVH(); CHECK_EQUAL(*importedDVH, *spMyDVH); // 3) test reading and writing the same dvh //read dvh from a txt file io::other::DVHTxtFileReader dvhReader_R(DVHTXT_FILENAME); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_R = dvhReader_R.generateDVH(); - //write the dvh to another file as cumulative + //write the dvh to another file as cumulative io::other::DVHTxtFileWriter dvhWriter_R_Cum("test_Cum.txt", typeCum); dvhWriter_R_Cum.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Cum("test_Cum.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Cum = dvhReader_W_Cum.generateDVH(); //check equal CHECK(checkEqualDVH(dvhP_R, dvhP_W_Cum)); - //write the dvh to another file as differential + //write the dvh to another file as differential io::other::DVHTxtFileWriter dvhWriter_R_Diff("test_Diff.txt", typeDiff); dvhWriter_R_Diff.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Diff("test_Diff.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Diff = dvhReader_W_Diff.generateDVH(); //check equal CHECK(checkEqualDVH(dvhP_R, dvhP_W_Diff)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/DVHXMLIOTest.cpp b/testing/io/other/DVHXMLIOTest.cpp index 62eb112..31675ce 100644 --- a/testing/io/other/DVHXMLIOTest.cpp +++ b/testing/io/other/DVHXMLIOTest.cpp @@ -1,138 +1,141 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVHTxtFileWriter.h" #include "rttbDVHXMLFileReader.h" #include "rttbDVHXMLFileWriter.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDVHGenerator.h" #include "CompareDVH.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { /*! @brief DVHXMLIOTest - test the IO for DVH xml data 1) test writing dvh to xml file - 2) test reading DVH from xml file + 2) test reading DVH from xml file 3) test reading dvh from txt file and writing to xml, check equal */ - int DVHXMLIOTest(int argc, char* argv[] ) + int DVHXMLIOTest(int argc, char* argv[]) { typedef core::DVHSet::DVHSetType DVHSetType; typedef core::DVH::DVHPointer DVHPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string DVHTXT_FILENAME; - if (argc>1) + if (argc > 1) { DVHTXT_FILENAME = argv[1]; } /* generate dummy DVH */ const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; - DummyDVHGenerator dvhGenerator; + DummyDVHGenerator dvhGenerator; - DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix,doseID)); + DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix, + doseID)); // 1) test writing DVH to xml file DVHType typeCum = {DVHType::Cumulative}; DVHType typeDiff = {DVHType::Differential}; FileNameString fN1 = "test.xml"; CHECK_NO_THROW(io::other::DVHXMLFileWriter(fN1, typeDiff)); CHECK_NO_THROW(io::other::DVHXMLFileWriter(fN1, typeCum)); - io::other::DVHXMLFileWriter dvhWriter (fN1, typeCum); + io::other::DVHXMLFileWriter dvhWriter(fN1, typeCum); CHECK_EQUAL(fN1, dvhWriter.getFileName()); FileNameString fN2 = "otherFile.xml"; CHECK_NO_THROW(dvhWriter.setFileName(fN2)); CHECK_EQUAL(fN2, dvhWriter.getFileName()); CHECK_EQUAL(DVHType::Cumulative, dvhWriter.getDVHType().Type); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_EQUAL(DVHType::Differential, dvhWriter.getDVHType().Type); DVHPointer emptyDvh; CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh), core::NullPointerException); //CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(spMyDVH), core::InvalidParameterException); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_NO_THROW(dvhWriter.writeDVH(spMyDVH)); - // 2) test reading DVH from xml file + // 2) test reading DVH from xml file io::other::DVHXMLFileReader dvhReader(fN2); DVHPointer importedDVH = dvhReader.generateDVH(); CHECK_EQUAL(*importedDVH, *spMyDVH); - //3) test reading dvh from txt file and writing to xml + //3) test reading dvh from txt file and writing to xml io::other::DVHTxtFileReader dvhReader2(DVHTXT_FILENAME); DVHPointer importedDVH2 = dvhReader2.generateDVH(); //write dvh to a xml file as differential FileNameString toWrite_diff = "test_diff.xml"; io::other::DVHXMLFileWriter xmlWriter(toWrite_diff, typeDiff); xmlWriter.writeDVH(importedDVH2); io::other::DVHXMLFileReader xmlReader(toWrite_diff); DVHPointer readDVH = xmlReader.generateDVH(); CHECK(checkEqualDVH(importedDVH2, readDVH)); //write dvh to a xml file as cummulative FileNameString toWrite_cum = "test_cum.xml"; io::other::DVHXMLFileWriter xmlWriter_cum(toWrite_cum, typeCum); xmlWriter_cum.writeDVH(importedDVH2); io::other::DVHXMLFileReader xmlReader_cum(toWrite_cum); DVHPointer readDVH_cum = xmlReader_cum.generateDVH(); CHECK(checkEqualDVH(importedDVH2, readDVH_cum)); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/OtherIOTest.cpp b/testing/io/other/OtherIOTest.cpp index dc33b8e..72ebc75 100644 --- a/testing/io/other/OtherIOTest.cpp +++ b/testing/io/other/OtherIOTest.cpp @@ -1,174 +1,183 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // (c) Copyright 2007, DKFZ, Heidelberg, Germany // ALL RIGHTS RESERVED // // THIS FILE CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION OF DKFZ. // ANY DUPLICATION, MODIFICATION, DISTRIBUTION, OR // DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY PROHIBITED // WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF DKFZ. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author zhangl (last changed by) // @author *none* (Reviewer) // @author zhangl (Programmer) // // Subversion HeadURL: $HeadURL: http://sidt-hpc1/dkfz_repository/NotMeVisLab/SIDT/RTToolbox/trunk/testing/core/DVHCalculatorTest.cpp $ */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVH.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVHTxtFileWriter.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDVHGenerator.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { /*! @brief OtherIOTest - test the IO for DVH txt data 1) test writing dvh to text file - 2) test reading DVH from text file + 2) test reading DVH from text file 3) test reading and writing the same dvh */ - int OtherIOTest(int argc, char* argv[] ) + int OtherIOTest(int argc, char* argv[]) { typedef core::DVHSet::DVHSetType DVHSetType; typedef core::DVH::DVHPointer DVHPointer; PREPARE_DEFAULT_TEST_REPORTING; std::string DVHTXT_FILENAME; - if (argc>1) + if (argc > 1) { DVHTXT_FILENAME = argv[1]; } /* generate dummy DVH */ const IDType structureIDPrefix = "myStructure"; const IDType doseID = "myDose"; - DummyDVHGenerator dvhGenerator; + DummyDVHGenerator dvhGenerator; - DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix,doseID)); + DVHPointer spMyDVH = boost::make_shared(dvhGenerator.generateDVH(structureIDPrefix, + doseID)); // 1) test writing DVH to text file DVHType typeCum = {DVHType::Cumulative}; DVHType typeDiff = {DVHType::Differential}; FileNameString fN1 = "test.txt"; CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeDiff)); CHECK_NO_THROW(io::other::DVHTxtFileWriter(fN1, typeCum)); - io::other::DVHTxtFileWriter dvhWriter (fN1, typeCum); + io::other::DVHTxtFileWriter dvhWriter(fN1, typeCum); CHECK_EQUAL(fN1, dvhWriter.getFileName()); FileNameString fN2 = "otherFile.txt"; CHECK_NO_THROW(dvhWriter.setFileName(fN2)); CHECK_EQUAL(fN2, dvhWriter.getFileName()); CHECK_EQUAL(DVHType::Cumulative, dvhWriter.getDVHType().Type); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_EQUAL(DVHType::Differential, dvhWriter.getDVHType().Type); DVHPointer emptyDvh; - CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh),core::NullPointerException); + CHECK_THROW_EXPLICIT(dvhWriter.writeDVH(emptyDvh), core::NullPointerException); CHECK_NO_THROW(dvhWriter.setDVHType(typeDiff)); CHECK_NO_THROW(dvhWriter.writeDVH(spMyDVH)); - // 2) test reading DVH from text file + // 2) test reading DVH from text file CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN1)); io::other::DVHTxtFileReader dvhReaderTest(fN1); - CHECK_THROW_EXPLICIT(dvhReaderTest.generateDVH(),core::InvalidParameterException); + CHECK_THROW_EXPLICIT(dvhReaderTest.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(io::other::DVHTxtFileReader dvhReader(fN2)); io::other::DVHTxtFileReader dvhReader(fN2); CHECK_NO_THROW(dvhReader.resetFileName(fN1)); CHECK_THROW_EXPLICIT(dvhReader.generateDVH(), core::InvalidParameterException); CHECK_NO_THROW(dvhReader.resetFileName(fN2)); CHECK_NO_THROW(dvhReader.generateDVH()); - + DVHPointer importedDVH = dvhReader.generateDVH(); CHECK_EQUAL(*importedDVH, *spMyDVH); // 3) test reading and writing the same dvh //read dvh from a txt file io::other::DVHTxtFileReader dvhReader_R(DVHTXT_FILENAME); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_R = dvhReader_R.generateDVH(); - //write the dvh to another file as cumulative + //write the dvh to another file as cumulative io::other::DVHTxtFileWriter dvhWriter_R_Cum("test_Cum.txt", typeCum); dvhWriter_R_Cum.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Cum("test_Cum.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Cum = dvhReader_W_Cum.generateDVH(); //check equal const double errorConstant = 1e-7; CHECK_CLOSE(dvhP_R->getDeltaD(), dvhP_W_Cum->getDeltaD(), errorConstant); CHECK_CLOSE(dvhP_R->getDeltaV(), dvhP_W_Cum->getDeltaV(), errorConstant); CHECK(dvhP_R->getDoseID() == dvhP_W_Cum->getDoseID()); CHECK(dvhP_R->getStructureID() == dvhP_W_Cum->getStructureID()); CHECK_CLOSE(dvhP_R->getMaximum(), dvhP_W_Cum->getMaximum(), errorConstant); CHECK_CLOSE(dvhP_R->getMinimum(), dvhP_W_Cum->getMinimum(), errorConstant); CHECK_CLOSE(dvhP_R->getMean(), dvhP_W_Cum->getMean(), errorConstant); CHECK(dvhP_R->getDataDifferential().size() == dvhP_W_Cum->getDataDifferential().size()); - for(int i=0; igetDataDifferential().size(); i++){ - CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Cum->getDataDifferential().at(i), errorConstant); + + for (int i = 0; i < dvhP_R->getDataDifferential().size(); i++) + { + CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Cum->getDataDifferential().at(i), + errorConstant); } - //write the dvh to another file as differential + //write the dvh to another file as differential io::other::DVHTxtFileWriter dvhWriter_R_Diff("test_Diff.txt", typeDiff); dvhWriter_R_Diff.writeDVH(dvhP_R); //read the file io::other::DVHTxtFileReader dvhReader_W_Diff("test_Diff.txt"); rttb::core::DVHGeneratorInterface::DVHPointer dvhP_W_Diff = dvhReader_W_Diff.generateDVH(); //check equal CHECK_CLOSE(dvhP_R->getDeltaD(), dvhP_W_Diff->getDeltaD(), errorConstant); CHECK_CLOSE(dvhP_R->getDeltaV(), dvhP_W_Diff->getDeltaV(), errorConstant); CHECK(dvhP_R->getDoseID() == dvhP_W_Diff->getDoseID()); CHECK(dvhP_R->getStructureID() == dvhP_W_Diff->getStructureID()); CHECK_CLOSE(dvhP_R->getMaximum(), dvhP_W_Diff->getMaximum(), errorConstant); CHECK_CLOSE(dvhP_R->getMinimum(), dvhP_W_Diff->getMinimum(), errorConstant); CHECK_CLOSE(dvhP_R->getMean(), dvhP_W_Diff->getMean(), errorConstant); CHECK(dvhP_R->getDataDifferential().size() == dvhP_W_Diff->getDataDifferential().size()); - for(int i=0; igetDataDifferential().size(); i++){ - CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Diff->getDataDifferential().at(i), errorConstant); + + for (int i = 0; i < dvhP_R->getDataDifferential().size(); i++) + { + CHECK_CLOSE(dvhP_R->getDataDifferential().at(i), dvhP_W_Diff->getDataDifferential().at(i), + errorConstant); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/other/rttbIOTests.cpp b/testing/io/other/rttbIOTests.cpp index 7d012b6..30d557e 100644 --- a/testing/io/other/rttbIOTests.cpp +++ b/testing/io/other/rttbIOTests.cpp @@ -1,60 +1,62 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif -#include "litMultiTestsMain.h" +#include "litMultiTestsMain.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { void registerTests() { LIT_REGISTER_TEST(DoseStatisticsIOTest); LIT_REGISTER_TEST(DVHXMLIOTest); LIT_REGISTER_TEST(DVHTXTIOTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { - result = lit::multiTestsMain(argc,argv); + result = lit::multiTestsMain(argc, argv); } - catch(...) + catch (...) { result = -1; } return result; } diff --git a/testing/io/virtuos/rttbVirtuosIOTests.cpp b/testing/io/virtuos/rttbVirtuosIOTests.cpp index 90b1390..cc3a500 100644 --- a/testing/io/virtuos/rttbVirtuosIOTests.cpp +++ b/testing/io/virtuos/rttbVirtuosIOTests.cpp @@ -1,64 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif -#include "litMultiTestsMain.h" +#include "litMultiTestsMain.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { void registerTests() - { - LIT_REGISTER_TEST(VirtuosDoseAccessorGeneratorTest); - LIT_REGISTER_TEST(VirtuosDoseIOTest); - LIT_REGISTER_TEST(VirtuosStructureIOTest); + { + LIT_REGISTER_TEST(VirtuosDoseAccessorGeneratorTest); + LIT_REGISTER_TEST(VirtuosDoseIOTest); + LIT_REGISTER_TEST(VirtuosStructureIOTest); LIT_REGISTER_TEST(VirtuosStructureSetGeneratorTest); - LIT_REGISTER_TEST(TripStructureIOTest); - LIT_REGISTER_TEST(TripDoseIOTest); - LIT_REGISTER_TEST(VirtuosDVHCalculatorExampleTest); - } + LIT_REGISTER_TEST(TripStructureIOTest); + LIT_REGISTER_TEST(TripDoseIOTest); + LIT_REGISTER_TEST(VirtuosDVHCalculatorExampleTest); } } +} int main(int argc, char* argv[]) - { +{ int result = 0; rttb::testing::registerTests(); try - { - result = lit::multiTestsMain(argc,argv); - } + { + result = lit::multiTestsMain(argc, argv); + } - catch(...) - { + catch (...) + { result = -1; - } + } return result; - } +} diff --git a/testing/masks/VOIindexIdentifierTest.cpp b/testing/masks/VOIindexIdentifierTest.cpp index a6b1c6c..5a3f8b9 100644 --- a/testing/masks/VOIindexIdentifierTest.cpp +++ b/testing/masks/VOIindexIdentifierTest.cpp @@ -1,114 +1,116 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: // @date $Date: // @author $Author: */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbInvalidParameterException.h" #include "rttbVOIindexIdentifier.h" namespace rttb { namespace testing { int VOIindexIdentifierTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; //ARGUMENTS: 1: structure file name std::string RTSTRUCT_FILENAME; if (argc > 1) { RTSTRUCT_FILENAME = argv[1]; } StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); StructureSetPointer emptyPointer = StructureSetPointer(); - CHECK_NO_THROW(::rttb::masks::VOIindexIdentifier testVOIindexId = ::rttb::masks::VOIindexIdentifier()); + CHECK_NO_THROW(::rttb::masks::VOIindexIdentifier testVOIindexId + = ::rttb::masks::VOIindexIdentifier()); ::rttb::masks::VOIindexIdentifier testVOIindexId = ::rttb::masks::VOIindexIdentifier(); /* getIndexByVoiName */ CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(emptyPointer, "Leber"), ::rttb::core::Exception); - CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(rtStructureSet, "Invalid"), ::rttb::core::Exception); + CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(rtStructureSet, "Invalid"), + ::rttb::core::Exception); unsigned int indexActual; unsigned int indexExpected = 5; CHECK_NO_THROW(indexActual = testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber")); CHECK_EQUAL(indexActual, indexExpected); /*getIndicesByVoiRegex*/ CHECK_THROW_EXPLICIT(testVOIindexId.getIndicesByVoiRegex(emptyPointer, "Leber"), ::rttb::core::Exception); std::vector vectorActual; std::vector vectorExpected; vectorExpected.push_back(5); CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, "Leber")); CHECK_EQUAL(vectorActual.size(), vectorExpected.size()); CHECK_EQUAL(vectorActual.at(0), vectorExpected.at(0)); vectorExpected.clear(); vectorExpected.push_back(2); vectorExpected.push_back(3); CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, "Niere.*")); CHECK_EQUAL(vectorActual.size(), vectorExpected.size()); CHECK_EQUAL(vectorActual.at(0), vectorExpected.at(0)); CHECK_EQUAL(vectorActual.at(1), vectorExpected.at(1)); CHECK_NO_THROW(vectorActual = testVOIindexId.getIndicesByVoiRegex(rtStructureSet, ".*")); CHECK_EQUAL(vectorActual.size(), 10); for (unsigned int index = 0; index < vectorActual.size(); index++) { CHECK_EQUAL(vectorActual.at(index), index); } /* getVoiNameByIndex */ CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(emptyPointer, 5), ::rttb::core::Exception); CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(rtStructureSet, 20), ::rttb::core::Exception); CHECK_EQUAL(testVOIindexId.getVoiNameByIndex(rtStructureSet, 5), "Leber"); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/boost/BoostMaskAccessorTest.cpp b/testing/masks/boost/BoostMaskAccessorTest.cpp index ab1da25..caefd8b 100644 --- a/testing/masks/boost/BoostMaskAccessorTest.cpp +++ b/testing/masks/boost/BoostMaskAccessorTest.cpp @@ -1,128 +1,130 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" #include "../../core/DummyStructure.h" #include "../../core/DummyDoseAccessor.h" #include "rttbBoostMask.h" #include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*! @brief BoostMaskAccessorTest. 1) test constructors 2) test getRelevantVoxelVector 3) test getMaskAt */ int BoostMaskAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::Structure::StructTypePointer StructTypePointer; typedef masks::boost::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef masks::boost::BoostMaskAccessor::MaskVoxelList MaskVoxelList; // generate test structure set boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); boost::shared_ptr geometricPtr = boost::make_shared (spTestDoseAccessor->getGeometricInfo()); //1) test BoostMask and BoostMaskAccessor constructor CHECK_NO_THROW(rttb::masks::boost::BoostMask(geometricPtr, spMyStruct)); rttb::masks::boost::BoostMask boostMask = rttb::masks::boost::BoostMask(geometricPtr, spMyStruct); - CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); - rttb::masks::boost::BoostMaskAccessor boostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, + spTestDoseAccessor->getGeometricInfo())); + rttb::masks::boost::BoostMaskAccessor boostMaskAccessor(spMyStruct, + spTestDoseAccessor->getGeometricInfo()); //2) test getRelevantVoxelVector CHECK_NO_THROW(boostMask.getRelevantVoxelVector()); CHECK_NO_THROW(boostMaskAccessor.getRelevantVoxelVector()); //3) test getMaskAt const VoxelGridIndex3D inMask1(2, 1, 4); //corner -> volumeFraction = 0.25 const VoxelGridIndex3D inMask2(3, 4, 4); //inside ->volumeFraction = 1 const VoxelGridIndex3D inMask3(4, 5, 4); //side -> volumeFraction = 0.5 const VoxelGridIndex3D outMask1(7, 5, 4); const VoxelGridIndex3D outMask2(2, 1, 2); VoxelGridID testId; double errorConstant = 1e-7; core::MaskVoxel tmpMV1(0), tmpMV2(0); CHECK(boostMaskAccessor.getMaskAt(inMask1, tmpMV1)); geometricPtr->convert(inMask1, testId); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.25, tmpMV1.getRelevantVolumeFraction(), errorConstant); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask2, tmpMV1)); CHECK(geometricPtr->convert(inMask2, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(1, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask3, tmpMV1)); CHECK(geometricPtr->convert(inMask3, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.5, tmpMV1.getRelevantVolumeFraction(), errorConstant); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(!boostMaskAccessor.getMaskAt(outMask1, tmpMV1)); CHECK(geometricPtr->convert(outMask1, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask CHECK(!boostMaskAccessor.getMaskAt(outMask2, tmpMV1)); CHECK(geometricPtr->convert(outMask2, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/legacy/OTBMaskAccessorTest.cpp b/testing/masks/legacy/OTBMaskAccessorTest.cpp index 6784da4..4824ce6 100644 --- a/testing/masks/legacy/OTBMaskAccessorTest.cpp +++ b/testing/masks/legacy/OTBMaskAccessorTest.cpp @@ -1,197 +1,198 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. 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 "rttbOTBMaskAccessor.h" #include "rttbMaskVoxel.h" #include "rttbNullPointerException.h" #include "rttbException.h" #include "../../core/DummyStructure.h" #include "../../core/DummyDoseAccessor.h" #include "../rttbMaskVoxelListTester.h" #include "../rttbMaskRectStructTester.h" namespace rttb { namespace testing { /*! @brief GenericMaskedDoseIteratorTest. 1) test constructors 2) test updateMask (do relevant voxels match?) 3) test valid/convert 4) test getMaskAt 5) other interface functions (simple getters) */ int OTBMaskAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::Structure::StructTypePointer StructTypePointer; typedef masks::legacy::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef masks::legacy::OTBMaskAccessor::MaskVoxelList MaskVoxelList; // generate test structure set boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); //1) test constructors CHECK_NO_THROW(masks::legacy::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); masks::legacy::OTBMaskAccessor testOTB1(spMyStruct, spTestDoseAccessor->getGeometricInfo()); CHECK_EQUAL(spTestDoseAccessor->getGeometricInfo(), testOTB1.getGeometricInfo()); CHECK_NO_THROW(masks::legacy::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); masks::legacy::OTBMaskAccessor testOTB2(spMyStruct, spTestDoseAccessor->getGeometricInfo()); CHECK_EQUAL(spTestDoseAccessor->getGeometricInfo(), testOTB2.getGeometricInfo()); //2) test updateMask (do relevant voxels match?) CHECK_NO_THROW(testOTB1.updateMask()); CHECK_NO_THROW(testOTB1.getRelevantVoxelVector()); MaskVoxelListPointer relVoxelOTB1 = testOTB1.getRelevantVoxelVector(); boost::shared_ptr spMaskAccessor = - boost::make_shared(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + boost::make_shared(spMyStruct, + spTestDoseAccessor->getGeometricInfo()); MaskRectStructTester voxelizationTester(spMaskAccessor, zPlane); CHECK_TESTER(voxelizationTester); MaskVoxelListPointer relVoxelOTB2 = testOTB2.getRelevantVoxelVector(); MaskVoxelListTester listComp(relVoxelOTB1, relVoxelOTB2); CHECK_TESTER(listComp); //3) test valid/convert const VoxelGridIndex3D gridIndexIn1(0, 0, 0); const VoxelGridIndex3D gridIndexIn2(4, 3, 4); const VoxelGridIndex3D gridIndexIn3(testOTB2.getGeometricInfo().getNumColumns() - 1, testOTB2.getGeometricInfo().getNumRows() - 1, testOTB2.getGeometricInfo().getNumSlices() - 1); const VoxelGridIndex3D gridIndexOut1(testOTB2.getGeometricInfo().getNumColumns(), testOTB2.getGeometricInfo().getNumRows(), testOTB2.getGeometricInfo().getNumSlices()); const VoxelGridIndex3D gridIndexOut2(testOTB2.getGeometricInfo().getNumRows() * 2, testOTB2.getGeometricInfo().getNumRows() + 5, testOTB2.getGeometricInfo().getNumSlices() - 2); CHECK(testOTB2.getGeometricInfo().validIndex(gridIndexIn1)); CHECK(testOTB2.getGeometricInfo().validIndex(gridIndexIn2)); std::cout << gridIndexIn3 << std::endl; CHECK(testOTB2.getGeometricInfo().validIndex(gridIndexIn3)); CHECK(!testOTB2.getGeometricInfo().validIndex(gridIndexOut1)); CHECK(!testOTB2.getGeometricInfo().validIndex(gridIndexOut2)); const VoxelGridID gridIDIn1(0); int in2 = gridIndexIn2.z() * testOTB2.getGeometricInfo().getNumColumns() * testOTB2.getGeometricInfo().getNumRows() + gridIndexIn2.y() * testOTB2.getGeometricInfo().getNumColumns() + gridIndexIn2.x(); const VoxelGridID gridIDIn2(in2); const VoxelGridID gridIDIn3(testOTB2.getGeometricInfo().getNumberOfVoxels() - 1); //size-1 const VoxelGridID gridIDOut1(testOTB2.getGeometricInfo().getNumberOfVoxels()); //size const VoxelGridID gridIDOut2(testOTB2.getGeometricInfo().getNumberOfVoxels() + 10); CHECK(testOTB2.getGeometricInfo().validID(gridIDIn1)); CHECK(testOTB2.getGeometricInfo().validID(gridIDIn2)); CHECK(testOTB2.getGeometricInfo().validID(gridIDIn3)); CHECK(!testOTB2.getGeometricInfo().validID(gridIDOut1)); CHECK(!testOTB2.getGeometricInfo().validID(gridIDOut2)); VoxelGridIndex3D test; CHECK(testOTB2.getGeometricInfo().convert(gridIDIn1, test)); CHECK_EQUAL(gridIndexIn1, test); CHECK(testOTB2.getGeometricInfo().convert(gridIDIn2, test)); CHECK_EQUAL(gridIndexIn2, test); CHECK(!testOTB2.getGeometricInfo().convert(gridIDOut1, test)); //gridIndexOut1 is invalid, test is therefore not asigned, therefore testing is not necessary //CHECK_EQUAL(gridIndexOut1,test); VoxelGridID testId; CHECK(testOTB2.getGeometricInfo().convert(gridIndexIn1, testId)); CHECK_EQUAL(gridIDIn1, testId); CHECK(testOTB2.getGeometricInfo().convert(gridIndexIn2, testId)); CHECK_EQUAL(gridIDIn2, testId); CHECK(!testOTB2.getGeometricInfo().convert(gridIndexOut1, testId)); //gridIDOut1 is invalid, testId is therefore not asigned, therefore testing is not necessary //CHECK_EQUAL(exp,testId); //4) test getMaskAt const VoxelGridIndex3D inMask1(2, 1, 4); //corner -> volumeFraction = 0.25 const VoxelGridIndex3D inMask2(3, 4, 4); //inside ->volumeFraction = 1 const VoxelGridIndex3D inMask3(4, 5, 4); //side -> volumeFraction = 0.5 const VoxelGridIndex3D outMask1(7, 5, 4); const VoxelGridIndex3D outMask2(2, 1, 2); core::MaskVoxel tmpMV1(0), tmpMV2(0); CHECK(testOTB2.getMaskAt(inMask1, tmpMV1)); CHECK(testOTB2.getGeometricInfo().convert(inMask1, testId)); CHECK(testOTB2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0.25, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(testOTB2.getMaskAt(inMask2, tmpMV1)); CHECK(testOTB2.getGeometricInfo().convert(inMask2, testId)); CHECK(testOTB2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(1, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(testOTB2.getMaskAt(inMask3, tmpMV1)); CHECK(testOTB2.getGeometricInfo().convert(inMask3, testId)); CHECK(testOTB2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0.5, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(!testOTB2.getMaskAt(outMask1, tmpMV1)); CHECK(testOTB2.getGeometricInfo().convert(outMask1, testId)); CHECK(!testOTB2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask CHECK(!testOTB2.getMaskAt(outMask2, tmpMV1)); CHECK(testOTB2.getGeometricInfo().convert(outMask2, testId)); CHECK(!testOTB2.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask //5) other interface functions CHECK_EQUAL(true, testOTB1.isGridHomogeneous()); CHECK_NO_THROW(testOTB1.getMaskUID()); CHECK(testOTB1.getMaskUID() != testOTB2.getMaskUID()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/rttbMaskVoxelListTester.cpp b/testing/masks/rttbMaskVoxelListTester.cpp index 6ad0942..6534588 100644 --- a/testing/masks/rttbMaskVoxelListTester.cpp +++ b/testing/masks/rttbMaskVoxelListTester.cpp @@ -1,122 +1,153 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include #include "rttbMaskVoxelListTester.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { - MaskVoxelListTester::MaskVoxelListTester(MaskVoxelListPointer aReferenceList, MaskVoxelListPointer aCompareList){ + MaskVoxelListTester::MaskVoxelListTester(MaskVoxelListPointer aReferenceList, + MaskVoxelListPointer aCompareList) + { _referenceList = aReferenceList; _compareList = aCompareList; _sameSize = false; _masVoxelsDiffer = false; _numDifference = 0; } - void MaskVoxelListTester::setReferenceList(const MaskVoxelListPointer aReferenceList){ + void MaskVoxelListTester::setReferenceList(const MaskVoxelListPointer aReferenceList) + { _referenceList = aReferenceList; } - void MaskVoxelListTester::setCompareList(const MaskVoxelListPointer aCompareList){ + void MaskVoxelListTester::setCompareList(const MaskVoxelListPointer aCompareList) + { _compareList = aCompareList; } - lit::StringType MaskVoxelListTester::getTestDescription(void) const { + lit::StringType MaskVoxelListTester::getTestDescription(void) const + { return "Compare two MaskVoxelLists and determine if the contained content is equal."; }; - bool MaskVoxelListTester::doCheck(void) const{ + bool MaskVoxelListTester::doCheck(void) const + { _pResults->onTestStart(getCurrentTestLabel()); _masVoxelsDiffer = false; - if (_referenceList->size()==_compareList->size()){ + if (_referenceList->size() == _compareList->size()) + { _sameSize = true; } - else{ + else + { _sameSize = false; return false; } + _numDifference = 0; _maxDifference = 0; - MaskVoxelList::iterator iterR,iterC; + MaskVoxelList::iterator iterR, iterC; iterC = _compareList->begin(); - VoxelGridID index = 0; - for(iterR = _referenceList->begin(); iterR != _referenceList->end(); ++iterR,++iterC,++index){ - if(iterR->getVoxelGridID()==iterC->getVoxelGridID()){ - if (iterR->getRelevantVolumeFraction() == iterC->getRelevantVolumeFraction()){ + VoxelGridID index = 0; + + for (iterR = _referenceList->begin(); iterR != _referenceList->end(); ++iterR, ++iterC, ++index) + { + if (iterR->getVoxelGridID() == iterC->getVoxelGridID()) + { + if (iterR->getRelevantVolumeFraction() == iterC->getRelevantVolumeFraction()) + { continue; } - else{ - float diff = iterR->getRelevantVolumeFraction()-iterC->getRelevantVolumeFraction(); - if (diff > _maxDifference) { + else + { + float diff = iterR->getRelevantVolumeFraction() - iterC->getRelevantVolumeFraction(); + + if (diff > _maxDifference) + { _maxDifference = diff; } + /*if(diff > 0.001){ std::cout <getVoxelGridID()<< ": ("<< iterR->getRelevantVolumeFraction() << ","<getRelevantVolumeFraction()<<"); "; }*/ _numDifference++; } } - else{ + else + { _failedListIndex = index; _masVoxelsDiffer = true; return false; } }//end for(VoxelGridID id = 0; id < _referenceList->getGridSi... - if (_numDifference > 0){ + + if (_numDifference > 0) + { return false; } + return true; } - void MaskVoxelListTester::handleSuccess(void) const{ + void MaskVoxelListTester::handleSuccess(void) const + { std::ostringstream stream; - stream << "Both Lists are equal"<onTestSuccess(getCurrentTestLabel(), stream.str()); } - void MaskVoxelListTester::handleFailure(void) const{ + void MaskVoxelListTester::handleFailure(void) const + { std::ostringstream stream; - stream << "Lists were different"<< std::endl; + stream << "Lists were different" << std::endl; + + if (_sameSize) + { + stream << std::endl << "Error of volume fraction voxel count: " << _numDifference << std::endl; + stream << std::endl << "Maximum difference in volume fraction: " << _maxDifference << std::endl; - if(_sameSize){ - stream << std::endl << "Error of volume fraction voxel count: "<< _numDifference << std::endl; - stream << std::endl << "Maximum difference in volume fraction: "<< _maxDifference << std::endl; - if (_masVoxelsDiffer){ - stream << std::endl << "Mask points to different grid position in: "<< _failedListIndex << std::endl; + if (_masVoxelsDiffer) + { + stream << std::endl << "Mask points to different grid position in: " << _failedListIndex << + std::endl; } } - else{ - stream << "Lists have different size"<< std::endl; - stream << "Reference List is "<<_referenceList->size()<<" voxels long and comparison List "<< - _compareList->size()<< std::endl; + else + { + stream << "Lists have different size" << std::endl; + stream << "Reference List is " << _referenceList->size() << " voxels long and comparison List " << + _compareList->size() << std::endl; } + _pResults->onTestFailure(getCurrentTestLabel(), stream.str()); } } } \ No newline at end of file diff --git a/testing/models/BioModelScatterPlotTest.cpp b/testing/models/BioModelScatterPlotTest.cpp index 70efa07..d5ade24 100644 --- a/testing/models/BioModelScatterPlotTest.cpp +++ b/testing/models/BioModelScatterPlotTest.cpp @@ -1,216 +1,243 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" #include "rttbBioModelScatterPlots.h" #include "../core/DummyDVHGenerator.h" #include "DummyModel.h" #include "rttbIntegration.h" #include #include #include -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { typedef models::ScatterPlotType ScatterPlotType; /*! @brief BioModelScatterPlotTest. Test the scatterplot methods. 1) test if parameters are set correctly 2) test if scatterData contain each model value exactly once */ - int BioModelScatterPlotTest(int argc, char* argv[] ) + int BioModelScatterPlotTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DoseCalcType value = 1000; DummyDVHGenerator dummyDVH; const IDType structureID = "myStructure"; const IDType doseID = "myDose"; - core::DVH::DVHPointer dvhPtr = boost::make_shared(dummyDVH.generateDVH(structureID, doseID, 0,2000)); + core::DVH::DVHPointer dvhPtr = boost::make_shared(dummyDVH.generateDVH(structureID, + doseID, 0, 2000)); //test Dummy Model models::BioModelParamType param1 = 0.35; models::BioModelParamType param2 = 0.023333333333333; models::BioModelParamType param3 = 10000000; //model values will be dose/normalisationDose DoseTypeGy normalisationDose = 10; rttb::models::DummyModel model(dvhPtr); model.resetCounters(); - //default number of points is 100 + //default number of points is 100 CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 0, param1, 0.5, normalisationDose)); model.resetCounters(); - ScatterPlotType scatter = models::getScatterPlotVary1Parameter(model, 0, param1, 0.5, normalisationDose); + ScatterPlotType scatter = models::getScatterPlotVary1Parameter(model, 0, param1, 0.5, + normalisationDose); //only 1st parameter should gave been changed - CHECK_EQUAL(100,model.getSetParam1Count()); - CHECK_EQUAL(0,model.getSetParam2Count()); - CHECK_EQUAL(0,model.getSetParam3Count()); - CHECK_EQUAL(100,model.getCalcCount()); + CHECK_EQUAL(100, model.getSetParam1Count()); + CHECK_EQUAL(0, model.getSetParam2Count()); + CHECK_EQUAL(0, model.getSetParam3Count()); + CHECK_EQUAL(100, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose ScatterPlotType::iterator iter; - for (iter = scatter.begin(); iter != scatter.end(); ++iter){ + + for (iter = scatter.begin(); iter != scatter.end(); ++iter) + { double currentKey = iter->first; - if ((currentKey/normalisationDose) != iter->second.first){ - CHECK_EQUAL((currentKey/normalisationDose), iter->second.first); + + if ((currentKey / normalisationDose) != iter->second.first) + { + CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); - //number of points is 50 - CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose,50)); + //number of points is 50 + CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose, 50)); model.resetCounters(); - scatter = models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose,50); + scatter = models::getScatterPlotVary1Parameter(model, 1, param2, 0.25, normalisationDose, 50); //only 1st parameter should gave been changed - CHECK_EQUAL(0,model.getSetParam1Count()); - CHECK_EQUAL(50,model.getSetParam2Count()); - CHECK_EQUAL(0,model.getSetParam3Count()); - CHECK_EQUAL(50,model.getCalcCount()); + CHECK_EQUAL(0, model.getSetParam1Count()); + CHECK_EQUAL(50, model.getSetParam2Count()); + CHECK_EQUAL(0, model.getSetParam3Count()); + CHECK_EQUAL(50, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose - for (iter = scatter.begin(); iter != scatter.end(); ++iter){ + for (iter = scatter.begin(); iter != scatter.end(); ++iter) + { double currentKey = iter->first; - if ((currentKey/normalisationDose) != iter->second.first){ - CHECK_EQUAL((currentKey/normalisationDose), iter->second.first); + + if ((currentKey / normalisationDose) != iter->second.first) + { + CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); - //number of points is 150 - CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose,150)); + //number of points is 150 + CHECK_NO_THROW(models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose, + 150)); model.resetCounters(); - scatter = models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose,150); + scatter = models::getScatterPlotVary1Parameter(model, 2, param3, 0.75, normalisationDose, 150); //only 1st parameter should gave been changed - CHECK_EQUAL(0,model.getSetParam1Count()); - CHECK_EQUAL(0,model.getSetParam2Count()); - CHECK_EQUAL(150,model.getSetParam3Count()); - CHECK_EQUAL(150,model.getCalcCount()); + CHECK_EQUAL(0, model.getSetParam1Count()); + CHECK_EQUAL(0, model.getSetParam2Count()); + CHECK_EQUAL(150, model.getSetParam3Count()); + CHECK_EQUAL(150, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose - for (iter = scatter.begin(); iter != scatter.end(); ++iter){ + for (iter = scatter.begin(); iter != scatter.end(); ++iter) + { double currentKey = iter->first; - if ((currentKey/normalisationDose) != iter->second.first){ - CHECK_EQUAL((currentKey/normalisationDose), iter->second.first); + + if ((currentKey / normalisationDose) != iter->second.first) + { + CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); std::vector paramIDVec; models::BioModel::ParamVectorType meanVec; models::BioModel::ParamVectorType varianceVec; - paramIDVec.push_back(0); meanVec.push_back(1); varianceVec.push_back(0.6); - paramIDVec.push_back(1); meanVec.push_back(10); varianceVec.push_back(0.5); - paramIDVec.push_back(2); meanVec.push_back(100); varianceVec.push_back(0.4); - - //number of points is 50 - CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose,50)); + paramIDVec.push_back(0); + meanVec.push_back(1); + varianceVec.push_back(0.6); + paramIDVec.push_back(1); + meanVec.push_back(10); + varianceVec.push_back(0.5); + paramIDVec.push_back(2); + meanVec.push_back(100); + varianceVec.push_back(0.4); + + //number of points is 50 + CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, + normalisationDose, 50)); model.resetCounters(); - scatter = models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose,50); + scatter = models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, + normalisationDose, 50); //only 1st parameter should gave been changed - CHECK_EQUAL(50,model.getSetParam1Count()); - CHECK_EQUAL(50,model.getSetParam2Count()); - CHECK_EQUAL(50,model.getSetParam3Count()); - CHECK_EQUAL(50,model.getCalcCount()); + CHECK_EQUAL(50, model.getSetParam1Count()); + CHECK_EQUAL(50, model.getSetParam2Count()); + CHECK_EQUAL(50, model.getSetParam3Count()); + CHECK_EQUAL(50, model.getCalcCount()); // all model values should match the corresponding dose/normalizationDose - for (iter = scatter.begin(); iter != scatter.end(); ++iter){ + for (iter = scatter.begin(); iter != scatter.end(); ++iter) + { double currentKey = iter->first; - if ((currentKey/normalisationDose) != iter->second.first){ - CHECK_EQUAL((currentKey/normalisationDose), iter->second.first); + + if ((currentKey / normalisationDose) != iter->second.first) + { + CHECK_EQUAL((currentKey / normalisationDose), iter->second.first); } } model.resetCounters(); //test 2000 points - CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, normalisationDose,10000)); - + CHECK_NO_THROW(models::getScatterPlotVaryParameters(model, paramIDVec, meanVec, varianceVec, + normalisationDose, 10000)); + //test iterativeIntegration /*std::string bedFileName="d:/Temp/bed.txt"; std::ifstream dvh_ifstr(bedFileName,std::ios::in); std::vector volumeV2; std::vector bedV2; //std::cout << "iterative integration"<< std::endl; - if ( !dvh_ifstr.is_open() ) + if ( !dvh_ifstr.is_open() ) { std::cerr<< "DVH file name invalid: could not open the dvh file!"<> volume; volumeV2.push_back(volume); //std::cout << "("<< volume << ","; std::string lineSub2 = line.substr(found2+1,found3-found2-1); //std::cout << lineSub2 << std::endl; std::stringstream ss2(lineSub2); double bed; ss2 >> bed; bedV2.push_back(bed); //std::cout << bed << ");"; } } } struct rttb::models::TcpParams params={0.302101,0.08,10000000,volumeV2,bedV2}; double result = rttb::models::integrateTCP(0, params);*/ RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/BioModelTest.cpp b/testing/models/BioModelTest.cpp index c74d09a..40db317 100644 --- a/testing/models/BioModelTest.cpp +++ b/testing/models/BioModelTest.cpp @@ -1,299 +1,301 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBaseTypeModels.h" #include "rttbBioModelCurve.h" #include "rttbInvalidParameterException.h" #include "rttbBioModelScatterPlots.h" namespace rttb { namespace testing { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief RTBioModelTest. TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. TCPLQ: 1) test constructors (values as expected?) 2) test init (calcTCPxxx) 3) test set/get NTCP (LKB): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get NTCP (RS): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get */ int BioModelTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType aDataDifferential; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values for (int i = 0; i < 98; i++) { value = 0; numberOfVoxels += value; aDataDifferential.push_back(value); } aDataDifferential.push_back(10); aDataDifferential.push_back(20); const IDType structureID = "myStructure"; const IDType doseID = "myDose"; const IDType voxelizationID = "myVoxelization"; - core::DVH::DVHPointer dvhPtr = boost::make_shared(aDataDifferential, binSize, voxelVolume, structureID, + core::DVH::DVHPointer dvhPtr = boost::make_shared(aDataDifferential, binSize, + voxelVolume, structureID, doseID, voxelizationID); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 8; DoseTypeGy normalizationDose = 50; //1) test constructors (values as expected?) rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(0, tcplq.getAlphaBeta()); CHECK_EQUAL(0, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(dvhPtr, roh, numFractions, alpha / beta, alpha, 0.08); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(0, tcplq.getAlphaBeta()); CHECK_EQUAL(0, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_EQUAL(0, tcplq.getValue()); //2) test init (calcTCPxxx) CHECK_NO_THROW(tcplq.init(1)); //3) test set/get CHECK_EQUAL(0, tcplq.getValue()); CHECK_NO_THROW(tcplq.setParameters(alpha, 10, roh, 0.08)); CHECK_EQUAL(10, tcplq.getAlphaBeta()); CHECK_EQUAL(0.08, tcplq.getAlphaVariance()); CHECK_EQUAL(alpha, tcplq.getAlphaMean()); CHECK_EQUAL(roh, tcplq.getRho()); CHECK_NO_THROW(models::getCurveDoseVSBioModel(tcplq, normalizationDose)); std::vector aParameterVector; aParameterVector.push_back(alpha + 0.02); CHECK_THROW_EXPLICIT(tcplq.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(0.06); aParameterVector.push_back(8); aParameterVector.push_back(roh / 10); CHECK_NO_THROW(tcplq.setParameterVector(aParameterVector)); CHECK_EQUAL(8, tcplq.getAlphaBeta()); CHECK_EQUAL(0.06, tcplq.getAlphaVariance()); CHECK_EQUAL(alpha + 0.02, tcplq.getAlphaMean()); CHECK_EQUAL(roh / 10, tcplq.getRho()); for (int i = 0; i < 4; i++) { CHECK_NO_THROW(tcplq.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(tcplq.setParameterByID(4, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, tcplq.getParameterID("alphaMean")); CHECK_EQUAL(0, tcplq.getAlphaMean()); CHECK_EQUAL(1, tcplq.getParameterID("alphaVariance")); CHECK_EQUAL(1, tcplq.getAlphaVariance()); CHECK_EQUAL(2, tcplq.getParameterID("alpha_beta")); CHECK_EQUAL(2, tcplq.getAlphaBeta()); CHECK_EQUAL(3, tcplq.getParameterID("rho")); CHECK_EQUAL(3, tcplq.getRho()); //test NTCPLKBModel //1) test constructors (values as expected?) models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 35; CHECK_NO_THROW(rttb::models::NTCPLKBModel()); rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); CHECK_EQUAL(0, lkb.getValue()); CHECK_NO_THROW(rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal)); lkb = rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal); CHECK_EQUAL(0, lkb.getValue()); CHECK_EQUAL(dvhPtr, lkb.getDVH()); CHECK_EQUAL(aVal, lkb.getA()); CHECK_EQUAL(mVal, lkb.getM()); CHECK_EQUAL(d50Val, lkb.getD50()); //2) test init (calcxxx) CHECK_NO_THROW(lkb.init(1)); lkb.getValue(); //3) test set/get lkb = rttb::models::NTCPLKBModel(); CHECK_EQUAL(0, lkb.getA()); CHECK_EQUAL(0, lkb.getM()); CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr); CHECK_EQUAL(dvhPtr, lkb.getDVH()); lkb.setA(aVal); CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(models::getCurveEUDVSBioModel(lkb)); aParameterVector.clear(); aParameterVector.push_back(d50Val + 5); CHECK_THROW_EXPLICIT(lkb.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(mVal + 0.2); aParameterVector.push_back(aVal + 0.5); CHECK_NO_THROW(lkb.setParameterVector(aParameterVector)); CHECK_EQUAL(aVal + 0.5, lkb.getA()); CHECK_EQUAL(mVal + 0.2, lkb.getM()); CHECK_EQUAL(d50Val + 5, lkb.getD50()); for (int i = 0; i < 3; i++) { CHECK_NO_THROW(lkb.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(lkb.setParameterByID(3, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, lkb.getParameterID("d50")); CHECK_EQUAL(0, lkb.getD50()); CHECK_EQUAL(1, lkb.getParameterID("m")); CHECK_EQUAL(1, lkb.getM()); CHECK_EQUAL(2, lkb.getParameterID("a")); CHECK_EQUAL(2, lkb.getA()); //test NTCPRSModel //1) test constructors (values as expected?) CHECK_NO_THROW(rttb::models::NTCPRSModel()); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; CHECK_NO_THROW(rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal)); rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal); CHECK_EQUAL(dvhPtr, rs.getDVH()); CHECK_EQUAL(d50Val, rs.getD50()); CHECK_EQUAL(gammaVal, rs.getGamma()); CHECK_EQUAL(sVal, rs.getS()); rs = rttb::models::NTCPRSModel(); CHECK_EQUAL(0, rs.getGamma()); CHECK_EQUAL(0, rs.getS()); CHECK_EQUAL(0, rs.getD50()); //3) test set/get rs.setDVH(dvhPtr); CHECK_EQUAL(dvhPtr, rs.getDVH()); rs.setD50(d50Val); CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); CHECK_EQUAL(sVal, rs.getS()); //2) test init (calcxxx) CHECK_NO_THROW(rs.init(1)); //3) test set/get continued aParameterVector.clear(); aParameterVector.push_back(d50Val + 5); CHECK_THROW_EXPLICIT(rs.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(gammaVal + 0.2); aParameterVector.push_back(sVal + 0.5); CHECK_NO_THROW(rs.setParameterVector(aParameterVector)); CHECK_EQUAL(gammaVal + 0.2, rs.getGamma()); CHECK_EQUAL(sVal + 0.5, rs.getS()); CHECK_EQUAL(d50Val + 5, rs.getD50()); for (int i = 0; i < 3; i++) { CHECK_NO_THROW(rs.setParameterByID(i, models::BioModelParamType(i))); } CHECK_THROW_EXPLICIT(rs.setParameterByID(3, 4.0), core::InvalidParameterException); CHECK_EQUAL(0, rs.getParameterID("d50")); CHECK_EQUAL(0, rs.getD50()); CHECK_EQUAL(1, rs.getParameterID("gamma")); CHECK_EQUAL(1, rs.getGamma()); CHECK_EQUAL(2, rs.getParameterID("s")); CHECK_EQUAL(2, rs.getS()); //Scatter plot tests CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose)); //variance=0, will be set to 1e-30 CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, 0), core::InvalidParameterException);//normalisationdose=0 - CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, normalizationDose, 10000, 0, 0), + CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, + normalizationDose, 10000, 0, 0), core::InvalidParameterException);//maxDose-minDose=0 RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/DummyModel.cpp b/testing/models/DummyModel.cpp index e641f4b..ceed7b4 100644 --- a/testing/models/DummyModel.cpp +++ b/testing/models/DummyModel.cpp @@ -1,112 +1,114 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include "DummyModel.h" namespace rttb { namespace models { DummyModel::DummyModel(DVHPointer aDvh): BioModel(aDvh) { _calcCount = 0; _setParam1Count = 0; _setParam2Count = 0; _setParam3Count = 0; } BioModelValueType DummyModel::calcModel(const double doseFactor) { _calcCount++; _value = doseFactor; return _value; } void DummyModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 3) { std::cerr << "aParameterVector.size must be 3! Nothing will be done." << std::endl; } else { _param1 = aParameterVector.at(0); _setParam1Count++; _param2 = aParameterVector.at(1); _setParam2Count++; _param3 = aParameterVector.at(2); _setParam3Count++; } } void DummyModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _param1 = aValue; _setParam1Count++; } else if (aParamId == 1) { _param2 = aValue; _setParam2Count++; } else if (aParamId == 2) { _param3 = aValue; _setParam3Count++; } else { - std::cerr << "aParamID must be 0(DummyParam1) or 1(DummyParam2) or 2(DummyParam3)! Nothing will be done." << std::endl; + std::cerr << + "aParamID must be 0(DummyParam1) or 1(DummyParam2) or 2(DummyParam3)! Nothing will be done." << + std::endl; } } const int DummyModel::getParameterID(const std::string& aParamName) const { if (aParamName == "DummyParam1") { return 0; } else if (aParamName == "DummyParam2") { return 1; } else if (aParamName == "DummyParam3") { return 2; } else { std::cerr << "There is no parameter with the name " << aParamName << "!" << std::endl; return -1; } } void DummyModel::resetCounters() { _calcCount = 0; _setParam1Count = 0; _setParam2Count = 0; _setParam3Count = 0; } } } \ No newline at end of file diff --git a/testing/models/DvhBasedModelsTest.cpp b/testing/models/DvhBasedModelsTest.cpp index 9fe8321..347d252 100644 --- a/testing/models/DvhBasedModelsTest.cpp +++ b/testing/models/DvhBasedModelsTest.cpp @@ -1,100 +1,110 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbDVH.h" #include "rttbDvhBasedModels.h" #include "rttbInvalidParameterException.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { typedef core::DVH::DataDifferentialType DataDifferentialType; - /*! @brief DvhBasedModelsTest. + /*! @brief DvhBasedModelsTest. 1) Test bed und lqed2 */ - int DvhBasedModelsTest(int argc, char* argv[] ) + int DvhBasedModelsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //1) test calcBEDDVH and calcLQED2DVH //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; const IDType structureID = "myStructure"; const IDType doseID = "myDose"; - const IDType voxelizationID = "myVoxelization"; + const IDType voxelizationID = "myVoxelization"; DataDifferentialType aDataDifferential; std::vector bedVector; std::vector lqed2Vector; int numberOfFractions = 2; double alpha_beta = 10; - for(int i=0; i<100; i++){ - double volume = DoseCalcType((double(rand())/RAND_MAX)*1000); - double dose = (i+0.5)* binSize; - aDataDifferential.push_back( volume); + + for (int i = 0; i < 100; i++) + { + double volume = DoseCalcType((double(rand()) / RAND_MAX) * 1000); + double dose = (i + 0.5) * binSize; + aDataDifferential.push_back(volume); bedVector.push_back(dose * (1 + dose / (numberOfFractions * alpha_beta))); - lqed2Vector.push_back(dose * ((alpha_beta + (dose / numberOfFractions)) / (alpha_beta+2))); + lqed2Vector.push_back(dose * ((alpha_beta + (dose / numberOfFractions)) / (alpha_beta + 2))); } + core::DVH myDVH(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); core::DVH::DVHPointer dvhPtr = boost::make_shared(myDVH); CHECK_THROW_EXPLICIT(rttb::models::calcBEDDVH(dvhPtr, 0, 10), core::InvalidParameterException); - CHECK_THROW_EXPLICIT(rttb::models::calcBEDDVH(dvhPtr, 10,-1), core::InvalidParameterException); - CHECK_NO_THROW(rttb::models::calcBEDDVH(dvhPtr,10,10)); - CHECK_EQUAL(rttb::models::calcBEDDVH(dvhPtr,2,10).size(), myDVH.getDataDifferential().size()); - rttb::models::BEDDVHType bedDVH = rttb::models::calcBEDDVH(dvhPtr,numberOfFractions, alpha_beta); + CHECK_THROW_EXPLICIT(rttb::models::calcBEDDVH(dvhPtr, 10, -1), core::InvalidParameterException); + CHECK_NO_THROW(rttb::models::calcBEDDVH(dvhPtr, 10, 10)); + CHECK_EQUAL(rttb::models::calcBEDDVH(dvhPtr, 2, 10).size(), myDVH.getDataDifferential().size()); + rttb::models::BEDDVHType bedDVH = rttb::models::calcBEDDVH(dvhPtr, numberOfFractions, alpha_beta); - CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr,1,10), core::InvalidParameterException); - CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr,10,-1), core::InvalidParameterException); - CHECK_NO_THROW(rttb::models::calcLQED2DVH(dvhPtr,10,10,true)); - CHECK_EQUAL(rttb::models::calcLQED2DVH(dvhPtr,2,10).size(), myDVH.getDataDifferential().size()); - rttb::models::BEDDVHType lqed2DVH = rttb::models::calcLQED2DVH(dvhPtr,numberOfFractions, alpha_beta); + CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr, 1, 10), core::InvalidParameterException); + CHECK_THROW_EXPLICIT(rttb::models::calcLQED2DVH(dvhPtr, 10, -1), core::InvalidParameterException); + CHECK_NO_THROW(rttb::models::calcLQED2DVH(dvhPtr, 10, 10, true)); + CHECK_EQUAL(rttb::models::calcLQED2DVH(dvhPtr, 2, 10).size(), myDVH.getDataDifferential().size()); + rttb::models::BEDDVHType lqed2DVH = rttb::models::calcLQED2DVH(dvhPtr, numberOfFractions, + alpha_beta); //check the calculation rttb::models::BEDDVHType::iterator itBED, itLQED2; std::vector::iterator itBEDVec, itLQED2Vec; DataDifferentialType::iterator itDiff; - for(itBED = bedDVH.begin(), itLQED2 = lqed2DVH.begin(), itBEDVec = bedVector.begin(), itLQED2Vec = lqed2Vector.begin(), itDiff = aDataDifferential.begin(); - itBED != bedDVH.end(), itLQED2 != lqed2DVH.end(), itBEDVec != bedVector.end(), itLQED2Vec != lqed2Vector.end(), itDiff != aDataDifferential.end(); - ++itBED, ++itLQED2, ++itBEDVec, ++itLQED2Vec, ++itDiff){ - //check volume - CHECK_EQUAL(*itDiff, (*itBED).second); - CHECK_EQUAL((*itBED).second, (*itLQED2).second); + for (itBED = bedDVH.begin(), itLQED2 = lqed2DVH.begin(), itBEDVec = bedVector.begin(), + itLQED2Vec = lqed2Vector.begin(), itDiff = aDataDifferential.begin(); + itBED != bedDVH.end(), itLQED2 != lqed2DVH.end(), itBEDVec != bedVector.end(), + itLQED2Vec != lqed2Vector.end(), itDiff != aDataDifferential.end(); + ++itBED, ++itLQED2, ++itBEDVec, ++itLQED2Vec, ++itDiff) + { + + //check volume + CHECK_EQUAL(*itDiff, (*itBED).second); + CHECK_EQUAL((*itBED).second, (*itLQED2).second); - //check bed - CHECK_EQUAL(*itBEDVec, (*itBED).first); + //check bed + CHECK_EQUAL(*itBEDVec, (*itBED).first); - //check lqed2 - CHECK_EQUAL(*itLQED2Vec, (*itLQED2).first); + //check lqed2 + CHECK_EQUAL(*itLQED2Vec, (*itLQED2).first); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/LQModelAccessorTest.cpp b/testing/models/LQModelAccessorTest.cpp index 54a9302..5524047 100644 --- a/testing/models/LQModelAccessorTest.cpp +++ b/testing/models/LQModelAccessorTest.cpp @@ -1,130 +1,136 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "litCheckMacros.h" #include #include "rttbLQModelAccessor.h" #include "rttbGenericDoseIterator.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*! @brief LQModelAccessorTest. 1) Test constructor 2) Test getGeometricInfo() 3) Test getValueAt() */ int LQModelAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME_CONSTANT_TWO; std::string RTDOSE_FILENAME_INCREASE_X; if (argc > 2) { RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; RTDOSE_FILENAME_INCREASE_X = argv[2]; } else { std::cout << "at least two parameters for LQModelAccessorTest are expected" << std::endl; return -1; } typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( RTDOSE_FILENAME_CONSTANT_TWO.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( RTDOSE_FILENAME_INCREASE_X.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); core::GeometricInfo doseAccessor2GeometricInfo = doseAccessor2->getGeometricInfo(); DoseAccessorPointer doseAccessorNull; core::AccessorInterface::AccessorPointer LQWithConstantDose; core::AccessorInterface::AccessorPointer LQWithConstantDoseDoseScalingTwo; core::AccessorInterface::AccessorPointer LQWithIncreaseXDose; //1) test constructor CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessorNull, 0, 0), core::InvalidDoseException); - CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessor1, 0.2, 0.02, -1), core::InvalidParameterException); + CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessor1, 0.2, 0.02, -1), + core::InvalidParameterException); CHECK_NO_THROW(LQWithConstantDose = boost::make_shared(doseAccessor1, 0.2, 0.02)); - CHECK_NO_THROW(LQWithConstantDoseDoseScalingTwo = boost::make_shared(doseAccessor1, - 0.2, 0.02, 2.0)); + CHECK_NO_THROW(LQWithConstantDoseDoseScalingTwo = boost::make_shared + (doseAccessor1, + 0.2, 0.02, 2.0)); CHECK_NO_THROW(LQWithIncreaseXDose = boost::make_shared(doseAccessor2, 0.3, 0.01)); //2) Test getGeometricInfo() CHECK_EQUAL(LQWithConstantDose->getGeometricInfo(), doseAccessor1GeometricInfo); CHECK_EQUAL(LQWithIncreaseXDose->getGeometricInfo(), doseAccessor2GeometricInfo); //3) Test getValueAt() models::BioModelParamType expectedLQWithDoseTwo = exp(-(0.2 * 2 + (0.02 * 2 * 2))); CHECK_EQUAL(LQWithConstantDose->getValueAt(0), expectedLQWithDoseTwo); - CHECK_EQUAL(LQWithConstantDose->getValueAt(LQWithConstantDose->getGridSize() - 1), expectedLQWithDoseTwo); + CHECK_EQUAL(LQWithConstantDose->getValueAt(LQWithConstantDose->getGridSize() - 1), + expectedLQWithDoseTwo); CHECK_EQUAL(LQWithConstantDose->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseTwo); CHECK_EQUAL(LQWithConstantDose->getValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseTwo); models::BioModelParamType expectedLQWithDoseFour = exp(-(0.2 * 4 + (0.02 * 4 * 4))); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(0), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(LQWithConstantDose->getGridSize() - 1), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseFour); CHECK_EQUAL(LQWithConstantDoseDoseScalingTwo->getValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseFour); - models::BioModelParamType expectedLQWithIncreaseX = exp(-(0.3 * 66 * 2.822386e-5 + (0.01 * 66 * 2.822386e-5 * 66 * - 2.822386e-5))); + models::BioModelParamType expectedLQWithIncreaseX = exp(-(0.3 * 66 * 2.822386e-5 + + (0.01 * 66 * 2.822386e-5 * 66 * + 2.822386e-5))); CHECK_EQUAL(LQWithIncreaseXDose->getValueAt(0), 1); - CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(LQWithIncreaseXDose->getGridSize() - 1), expectedLQWithIncreaseX, + CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(LQWithIncreaseXDose->getGridSize() - 1), + expectedLQWithIncreaseX, errorConstant); expectedLQWithIncreaseX = exp(-(0.3 * 1 * 2.822386e-5 + (0.01 * 1 * 2.822386e-5 * 1 * 2.822386e-5))); - CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithIncreaseX, errorConstant); + CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithIncreaseX, + errorConstant); expectedLQWithIncreaseX = exp(-(0.3 * 45 * 2.822386e-5 + (0.01 * 45 * 2.822386e-5 * 45 * 2.822386e-5))); CHECK_CLOSE(LQWithIncreaseXDose->getValueAt(VoxelGridIndex3D(45, 40, 60)), expectedLQWithIncreaseX, errorConstant); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/rttbScatterTester.cpp b/testing/models/rttbScatterTester.cpp index 43fea9f..7977fbc 100644 --- a/testing/models/rttbScatterTester.cpp +++ b/testing/models/rttbScatterTester.cpp @@ -1,148 +1,199 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision $ (last changed revision) // @date $Date $ (last change date) // @author $Author $ (last changed by) */ #include #include "rttbScatterTester.h" -namespace rttb{ +namespace rttb +{ - namespace testing{ + namespace testing + { - ScatterTester::ScatterTester(models::CurveDataType aReferenceCurve, models::ScatterPlotType aCompareScatter, models::BioModelParamType aVariance){ + ScatterTester::ScatterTester(models::CurveDataType aReferenceCurve, + models::ScatterPlotType aCompareScatter, models::BioModelParamType aVariance) + { _referenceCurve = aReferenceCurve; _compareScatter = aCompareScatter; _variance = aVariance; _numDifference = 0; _allowExceptions = false; } - void ScatterTester::setReferenceCurve(const models::CurveDataType aReferenceCurve){ + void ScatterTester::setReferenceCurve(const models::CurveDataType aReferenceCurve) + { _referenceCurve = aReferenceCurve; } - void ScatterTester::setCompareScatter(const models::ScatterPlotType aCompareScatter){ + void ScatterTester::setCompareScatter(const models::ScatterPlotType aCompareScatter) + { _compareScatter = aCompareScatter; } - void ScatterTester::setVariance(const models::BioModelParamType aVariance){ + void ScatterTester::setVariance(const models::BioModelParamType aVariance) + { _variance = aVariance; } - void ScatterTester::setAllowExceptions(const bool allow){ + void ScatterTester::setAllowExceptions(const bool allow) + { _allowExceptions = allow; }; - lit::StringType ScatterTester::getTestDescription(void) const { + lit::StringType ScatterTester::getTestDescription(void) const + { return "Compare a model curve and the corresponding scatter plot. The values should be comparable."; }; - bool ScatterTester::doCheck(void) const{ + bool ScatterTester::doCheck(void) const + { _pResults->onTestStart(getCurrentTestLabel()); - const double scatterError = errorConstant*10+_variance; + const double scatterError = errorConstant * 10 + _variance; _numDifference = 0; _maxDifference = 0; _meanDifference = 0; - double lower,upper, difference,oldVal; + double lower, upper, difference, oldVal; models::CurveDataType::const_iterator iterC = _referenceCurve.begin(); oldVal = iterC->second; models::ScatterPlotType::const_iterator iter; - for (iter = _compareScatter.begin(); iter != _compareScatter.end(); ++iter){ + + for (iter = _compareScatter.begin(); iter != _compareScatter.end(); ++iter) + { double currentKey = iter->first; - //only set old value if the reference iterator iterC moves - if (currentKey > iterC->first){ + + //only set old value if the reference iterator iterC moves + if (currentKey > iterC->first) + { oldVal = iterC->second; - while(currentKey > iterC->first){ + + while (currentKey > iterC->first) + { ++iterC; } } - if (iterC != _referenceCurve.end()){ + + if (iterC != _referenceCurve.end()) + { //determine if curve is ascending or descending lower = oldVal; - upper = iterC->second; - if(upper < lower){ - lower = iterC->second; + upper = iterC->second; + + if (upper < lower) + { + lower = iterC->second; upper = oldVal; } + //check boundaries because no interpolation is done - if (upper<(iter->second).first) { - difference = abs(upper-(iter->second).first); - if (difference < scatterError){continue;} - else if (difference > _maxDifference){ + if (upper < (iter->second).first) + { + difference = abs(upper - (iter->second).first); + + if (difference < scatterError) + { + continue; + } + else if (difference > _maxDifference) + { _maxDifference = difference; } - _meanDifference+=difference; + + _meanDifference += difference; ++_numDifference; } - if(lower>(iter->second).first){ - difference = abs(upper-(iter->second).first); - if (difference < scatterError){continue;} - else if (difference > _maxDifference){ + + if (lower > (iter->second).first) + { + difference = abs(upper - (iter->second).first); + + if (difference < scatterError) + { + continue; + } + else if (difference > _maxDifference) + { _maxDifference = difference; } - _meanDifference+=difference; + + _meanDifference += difference; ++_numDifference; } - } + } }//end for(iter = _compareScatter.begin(); iter != _compareScatter.end(); ++iter) - if (_numDifference > 0){ - _meanDifference/=_numDifference; - if (!_allowExceptions){ + + if (_numDifference > 0) + { + _meanDifference /= _numDifference; + + if (!_allowExceptions) + { return false; } - else{ + else + { // allow up to 5% exceptions - if(_numDifference/_compareScatter.size() <= 0.05){ + if (_numDifference / _compareScatter.size() <= 0.05) + { return true; } + return false; } } + return true; } - void ScatterTester::handleSuccess(void) const{ + void ScatterTester::handleSuccess(void) const + { std::ostringstream stream; - if (!_allowExceptions){ - stream << "Curve and scatter plot are similar"<onTestSuccess(getCurrentTestLabel(), stream.str()); } - void ScatterTester::handleFailure(void) const{ + void ScatterTester::handleFailure(void) const + { std::ostringstream stream; - stream << "Curve and scatter plot do not correspond"<< std::endl; - stream << std::endl << "Error voxel count: "<< _numDifference << std::endl; - stream << std::endl << "Maximum difference: "<< _maxDifference << std::endl; - stream << std::endl << "Mean difference: "<< _meanDifference << ", variance was "<<_variance<onTestFailure(getCurrentTestLabel(), stream.str()); } } } \ No newline at end of file