diff --git a/code/io/mask/files.cmake b/code/io/mask/files.cmake index d31bb1a..e1e9d23 100644 --- a/code/io/mask/files.cmake +++ b/code/io/mask/files.cmake @@ -1,19 +1,23 @@ SET(CPP_FILES + rttbBoostMask.cpp + rttbBoostMaskAccessor.cpp rttbITKImageFileMaskAccessorGenerator.cpp rttbITKImageMaskAccessor.cpp rttbITKImageMaskAccessorGenerator.cpp rttbITKImageMaskAccessorConverter.cpp ) SET(H_FILES + rttbBoostMask.h + rttbBoostMaskAccessor.h rttbITKImageFileMaskAccessorGenerator.h rttbITKImageMaskAccessor.h rttbITKImageMaskAccessorGenerator.h rttbITKImageMaskAccessorConverter.h rttbMaskAccessorProcessorBase.h rttbMaskAccessorProcessorInterface.h ../itk/rttbImageReader.h ../itk/rttbImageReader.tpp ../itk/rttbITKIOHelper.h ../itk/rttbITKIOHelper.tpp ) diff --git a/code/io/mask/rttbBoostMask.cpp b/code/io/mask/rttbBoostMask.cpp new file mode 100644 index 0000000..7a81f6c --- /dev/null +++ b/code/io/mask/rttbBoostMask.cpp @@ -0,0 +1,267 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rttbBoostMask.h" +#include "rttbNullPointerException.h" +#include "rttbInvalidParameterException.h" + +namespace rttb +{ + namespace io + { + namespace mask + { + BoostMask::BoostMask(BoostMask::GeometricInfoPointer aDoseGeoInfo, BoostMask::StructPointer aStructure) + :_geometricInfo(aDoseGeoInfo), _structure(aStructure), _voxelInStructure(boost::make_shared()){ + + + if(! _geometricInfo ){ + throw rttb::core::NullPointerException("Error: Geometric info is NULL!"); + } + else if(!_structure){ + throw rttb::core::NullPointerException("Error: Structure is NULL!"); + } + + } + + void BoostMask::calcMask(){ + if(hasSelfIntersections()){ + throw rttb::core::InvalidParameterException("Error: structure has self intersections!"); + } + + for(unsigned int i=0; i< _geometricInfo->getNumSlices(); i++){ + VoxelIndexVector voxelList = getBoundingBox(i); + 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 ++){ + rttb::VoxelGridIndex3D currentIndex; + currentIndex[0] = indexX; + currentIndex[1] = indexY; + currentIndex[2] = i; + + rttb::VoxelGridID gridID; + _geometricInfo->convert(currentIndex, gridID); + + std::deque polygons = getIntersections(currentIndex); + double intersectionArea = calcArea(polygons); + + double voxelSize = _geometricInfo->getSpacing()[0] * _geometricInfo->getSpacing()[1]; + + if(intersectionArea > 0) { + double volumeFraction = intersectionArea/voxelSize; + 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 hasSelfIntersection = false; + + for(unsigned int indexZ=0; indexZ< _geometricInfo->getNumSlices(); indexZ++){ + rttb::VoxelGridIndex3D currentIndex(0,0,indexZ); + + BoostMask::BoostRingVector boostPolygons = getIntersectionSlicePolygons(currentIndex); + + for(unsigned int i =0; i0){ + hasSelfIntersection = true; + std::cout << "Has self intersection! Slice: "<< indexZ << ", polygon "<= _geometricInfo->getNumSlices()){ + throw rttb::core::InvalidParameterException(std::string("Error: slice number is invalid!")); + } + + rttb::VoxelGridIndex3D currentIndex(0,0,sliceNumber); + + BoostRingVector boostPolygons = getIntersectionSlicePolygons(currentIndex); + + double xMin = 0; + double yMin = 0; + double xMax = 0; + double yMax = 0; + for(unsigned int i =0; i box; + boost::geometry::envelope(boostPolygons.at(i), box); + BoostPoint2D minPoint = box.min_corner(); + BoostPoint2D maxPoint = box.max_corner(); + if(i==0){ + 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){ + BoostMask::BoostPolygonDeque polygonDeque; + + BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); + boost::geometry::correct(voxelPolygon); + + BoostMask::BoostRingVector contourVector = getIntersectionSlicePolygons(aVoxelIndex3D); + for(unsigned int i=0; i aPolygonDeque){ + double area = 0; + for(unsigned int i=0; iconvert(aMaskVoxel.getVoxelGridID(), gridIndex3D); + return gridIndex3D; + } + + BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector(){ + calcMask(); + return _voxelInStructure; + } + + BoostMask::BoostRing2D BoostMask::convert(const rttb::PolygonType& aRTTBPolygon){ + BoostMask::BoostRing2D polygon2D; + BoostPoint2D firstPoint; + for(unsigned int i=0; igetStructureVector(); + + for(unsigned int i=0; i0){ + double polygonZCoor = rttbPolygon.at(0)[2]; + rttb::WorldCoordinate3D polygonPoint(0,0, polygonZCoor); + rttb::VoxelGridIndex3D polygonPointIndex3D; + _geometricInfo->worldCoordinateToIndex(polygonPoint, polygonPointIndex3D); + + //if the z + if(aVoxelGrid3D[2] == polygonPointIndex3D[2]){ + boostPolygonVector.push_back(convert(rttbPolygon)); + } + } + } + + return boostPolygonVector; + } + + 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; + + } + } + } +} \ No newline at end of file diff --git a/code/io/mask/rttbBoostMask.h b/code/io/mask/rttbBoostMask.h new file mode 100644 index 0000000..4a4d33c --- /dev/null +++ b/code/io/mask/rttbBoostMask.h @@ -0,0 +1,112 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 707 $ (last changed revision) +// @date $Date: 2014-09-04 16:37:24 +0200 (Do, 04 Sep 2014) $ (last change date) +// @author $Author: floca $ (last changed by) +*/ + + +#ifndef __RT_BOOST_MASK_H +#define __RT_BOOST_MASK_H + +#include "rttbBaseType.h" +#include "rttbStructure.h" +#include "rttbGeometricInfo.h" +#include "rttbMaskVoxel.h" +#include "rttbMaskAccessorInterface.h" + +#include +#include +#include +#include + +namespace rttb +{ + namespace io + { + namespace mask + { + 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 + */ + BoostMask(GeometricInfoPointer aDoseGeoInfo, StructPointer aStructure); + + /*! @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 > BoostPolygon2D; + typedef boost::geometry::model::ring > BoostRing2D; + typedef std::deque BoostPolygonDeque; + typedef std::vector BoostRingVector; + typedef std::vector VoxelIndexVector; + + GeometricInfoPointer _geometricInfo; + + StructPointer _structure; + + //vector of the MaskVoxel inside the structure + MaskVoxelListPointer _voxelInStructure; + + /*! @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*/ + VoxelIndexVector getBoundingBox(unsigned int sliceNumber); + + /*! @brief Get intersection polygons of the contour and a voxel polygon*/ + BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D); + + /*! @brief Calculate the intersection area*/ + double calcArea(BoostPolygonDeque aPolygonDeque); + + /*! @brief Get grid index of a 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 in the slice*/ + BoostRingVector getIntersectionSlicePolygons(const rttb::VoxelGridIndex3D& aVoxelGrid3D); + + /*! @brief Get the voxel 2d contour polygon*/ + BoostRing2D get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D); + + }; + + } + + + } +} + +#endif \ No newline at end of file diff --git a/code/io/mask/rttbBoostMaskAccessor.cpp b/code/io/mask/rttbBoostMaskAccessor.cpp new file mode 100644 index 0000000..e555263 --- /dev/null +++ b/code/io/mask/rttbBoostMaskAccessor.cpp @@ -0,0 +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: 484 $ (last changed revision) +// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +#include "rttbBoostMaskAccessor.h" +#include "rttbBoostMask.h" + +#include + +#include +#include +#include + +namespace rttb +{ + namespace io + { + namespace mask + { + + BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr) + : _spStructure(aStructurePointer), _spGeoInfo(aGeometricInfoPtr) + { + _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(_spGeoInfo , _spStructure); + + _spRelevantVoxelVector = mask.getRelevantVoxelVector(); + + return; + } + + BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() + { + // if not already generated start voxelization here + updateMask(); + return _spRelevantVoxelVector; + } + + 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 (!_spGeoInfo->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 (_spGeoInfo->convert(aIndex, aVoxelGridID)) + { + return getMaskAt(aVoxelGridID, voxel); + } + else + { + return false; + } + } + + const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const + { + return *_spGeoInfo; + }; + } + + } +} \ No newline at end of file diff --git a/code/io/mask/rttbBoostMaskAccessor.h b/code/io/mask/rttbBoostMaskAccessor.h new file mode 100644 index 0000000..85a4c4a --- /dev/null +++ b/code/io/mask/rttbBoostMaskAccessor.h @@ -0,0 +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: 484 $ (last changed revision) +// @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) +// @author $Author: zhangl $ (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 io + { + namespace mask + { + /*! @class BoostMaskAccessor + * @brief Implementation of the voxelization using boost + */ + class BoostMaskAccessor: public core::MaskAccessorInterface + { + public: + typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; + typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; + + typedef core::Structure::StructTypePointer StructTypePointer; + typedef boost::shared_ptr GeometricInfoPointer; + + private: + + GeometricInfoPointer _spGeoInfo; + + /*! vector containing list of mask voxels*/ + MaskVoxelListPointer _spRelevantVoxelVector; + + StructTypePointer _spStructure; + + IDType _maskUID; + + + 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 + */ + BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr); + + /*! @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/CMakeLists.txt b/code/masks/CMakeLists.txt index 024c513..b3802cc 100644 --- a/code/masks/CMakeLists.txt +++ b/code/masks/CMakeLists.txt @@ -1 +1 @@ -RTTB_CREATE_MODULE(RTTBMasks DEPENDS RTTBCore PACKAGE_DEPENDS Boost DCMTK) \ No newline at end of file +RTTB_CREATE_MODULE(RTTBMasks DEPENDS RTTBCore PACKAGE_DEPENDS DCMTK) \ No newline at end of file diff --git a/code/masks/files.cmake b/code/masks/files.cmake index 07d5621..14215d6 100644 --- a/code/masks/files.cmake +++ b/code/masks/files.cmake @@ -1,34 +1,30 @@ SET(CPP_FILES rttbOTBMaskAccessor.cpp rttbMask.cpp - rttbBoostMask.cpp - rttbBoostMaskAccessor.cpp DoseVoxel_LEGACY.cpp DoseIteratorInterface_LEGACY.cpp DoseIterator_LEGACY.cpp rttbContour_LEGACY.cpp rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp rttbPolygonInfo_LEGACY.cpp rttbSelfIntersectingStructureException.cpp rttbStructure_LEGACY.cpp rttbGenericMutableMaskAccessor.cpp ) SET(H_FILES rttbMaskType_LEGACY.h rttbMask.h - rttbBoostMask.h - rttbBoostMaskAccessor.h rttbOTBMaskAccessor.h DoseVoxel_LEGACY.h DoseIteratorInterface_LEGACY.h DoseIterator_LEGACY.h rttbContour_LEGACY.h rttbIterativePolygonInTermsOfIntersections_LEGACY.h rttbField_LEGACY.h rttbPolygonInfo_LEGACY.h rttbBaseType_LEGACY.h rttbSelfIntersectingStructureException.h rttbStructure_LEGACY.h rttbGenericMutableMaskAccessor.h ) diff --git a/code/masks/rttbBoostMask.cpp b/code/masks/rttbBoostMask.cpp deleted file mode 100644 index 2680d04..0000000 --- a/code/masks/rttbBoostMask.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "rttbBoostMask.h" -#include "rttbNullPointerException.h" -#include "rttbInvalidParameterException.h" - -namespace rttb{ - namespace masks{ - BoostMask::BoostMask(BoostMask::GeometricInfoPointer aDoseGeoInfo, BoostMask::StructPointer aStructure) - :_geometricInfo(aDoseGeoInfo), _structure(aStructure), _voxelInStructure(boost::make_shared()){ - - - if(! _geometricInfo ){ - throw rttb::core::NullPointerException("Error: Geometric info is NULL!"); - } - else if(!_structure){ - throw rttb::core::NullPointerException("Error: Structure is NULL!"); - } - - } - - void BoostMask::calcMask(){ - if(hasSelfIntersections()){ - throw rttb::core::InvalidParameterException("Error: structure has self intersections!"); - } - - for(unsigned int i=0; i< _geometricInfo->getNumSlices(); i++){ - VoxelIndexVector voxelList = getBoundingBox(i); - 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 ++){ - rttb::VoxelGridIndex3D currentIndex; - currentIndex[0] = indexX; - currentIndex[1] = indexY; - currentIndex[2] = i; - - rttb::VoxelGridID gridID; - _geometricInfo->convert(currentIndex, gridID); - - std::deque polygons = getIntersections(currentIndex); - double intersectionArea = calcArea(polygons); - - double voxelSize = _geometricInfo->getSpacing()[0] * _geometricInfo->getSpacing()[1]; - - if(intersectionArea > 0) { - double volumeFraction = intersectionArea/voxelSize; - 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 hasSelfIntersection = false; - - for(unsigned int indexZ=0; indexZ< _geometricInfo->getNumSlices(); indexZ++){ - rttb::VoxelGridIndex3D currentIndex(0,0,indexZ); - - BoostMask::BoostRingVector boostPolygons = getIntersectionSlicePolygons(currentIndex); - - for(unsigned int i =0; i0){ - hasSelfIntersection = true; - std::cout << "Has self intersection! Slice: "<< indexZ << ", polygon "<= _geometricInfo->getNumSlices()){ - throw rttb::core::InvalidParameterException(std::string("Error: slice number is invalid!")); - } - - rttb::VoxelGridIndex3D currentIndex(0,0,sliceNumber); - - BoostRingVector boostPolygons = getIntersectionSlicePolygons(currentIndex); - - double xMin = 0; - double yMin = 0; - double xMax = 0; - double yMax = 0; - for(unsigned int i =0; i box; - boost::geometry::envelope(boostPolygons.at(i), box); - BoostPoint2D minPoint = box.min_corner(); - BoostPoint2D maxPoint = box.max_corner(); - if(i==0){ - 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){ - BoostMask::BoostPolygonDeque polygonDeque; - - BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); - boost::geometry::correct(voxelPolygon); - - BoostMask::BoostRingVector contourVector = getIntersectionSlicePolygons(aVoxelIndex3D); - for(unsigned int i=0; i aPolygonDeque){ - double area = 0; - for(unsigned int i=0; iconvert(aMaskVoxel.getVoxelGridID(), gridIndex3D); - return gridIndex3D; - } - - BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector(){ - calcMask(); - return _voxelInStructure; - } - - BoostMask::BoostRing2D BoostMask::convert(const rttb::PolygonType& aRTTBPolygon){ - BoostMask::BoostRing2D polygon2D; - BoostPoint2D firstPoint; - for(unsigned int i=0; igetStructureVector(); - - for(unsigned int i=0; i0){ - double polygonZCoor = rttbPolygon.at(0)[2]; - rttb::WorldCoordinate3D polygonPoint(0,0, polygonZCoor); - rttb::VoxelGridIndex3D polygonPointIndex3D; - _geometricInfo->worldCoordinateToIndex(polygonPoint, polygonPointIndex3D); - - //if the z - if(aVoxelGrid3D[2] == polygonPointIndex3D[2]){ - boostPolygonVector.push_back(convert(rttbPolygon)); - } - } - } - - return boostPolygonVector; - } - - 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; - - } - } -} \ No newline at end of file diff --git a/code/masks/rttbBoostMask.h b/code/masks/rttbBoostMask.h deleted file mode 100644 index c0996cb..0000000 --- a/code/masks/rttbBoostMask.h +++ /dev/null @@ -1,106 +0,0 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notices for more information. -// -//------------------------------------------------------------------------ -/*! -// @file -// @version $Revision: 707 $ (last changed revision) -// @date $Date: 2014-09-04 16:37:24 +0200 (Do, 04 Sep 2014) $ (last change date) -// @author $Author: floca $ (last changed by) -*/ - - -#ifndef __RT_BOOST_MASK_H -#define __RT_BOOST_MASK_H - -#include "rttbBaseType.h" -#include "rttbStructure.h" -#include "rttbGeometricInfo.h" -#include "rttbMaskVoxel.h" -#include "rttbMaskAccessorInterface.h" - -#include -#include -#include -#include - -namespace rttb{ - namespace masks{ - - 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 - */ - BoostMask(GeometricInfoPointer aDoseGeoInfo, StructPointer aStructure); - - /*! @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 > BoostPolygon2D; - typedef boost::geometry::model::ring > BoostRing2D; - typedef std::deque BoostPolygonDeque; - typedef std::vector BoostRingVector; - typedef std::vector VoxelIndexVector; - - GeometricInfoPointer _geometricInfo; - - StructPointer _structure; - - //vector of the MaskVoxel inside the structure - MaskVoxelListPointer _voxelInStructure; - - /*! @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*/ - VoxelIndexVector getBoundingBox(unsigned int sliceNumber); - - /*! @brief Get intersection polygons of the contour and a voxel polygon*/ - BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D); - - /*! @brief Calculate the intersection area*/ - double calcArea(BoostPolygonDeque aPolygonDeque); - - /*! @brief Get grid index of a 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 in the slice*/ - BoostRingVector getIntersectionSlicePolygons(const rttb::VoxelGridIndex3D& aVoxelGrid3D); - - /*! @brief Get the voxel 2d contour polygon*/ - BoostRing2D get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D); - - }; - - } -} - -#endif \ No newline at end of file diff --git a/code/masks/rttbBoostMaskAccessor.cpp b/code/masks/rttbBoostMaskAccessor.cpp deleted file mode 100644 index 64be0e1..0000000 --- a/code/masks/rttbBoostMaskAccessor.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html -// -// This software is distributed WITHOUT ANY WARRANTY; 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: zhangl $ (last changed by) -*/ - -#include "rttbBoostMaskAccessor.h" -#include "rttbBoostMask.h" - -#include - -#include -#include -#include - -namespace rttb -{ - - namespace masks - { - - BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr) - : _spStructure(aStructurePointer), _spGeoInfo(aGeometricInfoPtr) - { - _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(_spGeoInfo , _spStructure); - - _spRelevantVoxelVector = mask.getRelevantVoxelVector(); - - return; - } - - BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() - { - // if not already generated start voxelization here - updateMask(); - return _spRelevantVoxelVector; - } - - 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 (!_spGeoInfo->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 (_spGeoInfo->convert(aIndex, aVoxelGridID)) - { - return getMaskAt(aVoxelGridID, voxel); - } - else - { - return false; - } - } - - const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const - { - return *_spGeoInfo; - }; - - } -} \ No newline at end of file diff --git a/code/masks/rttbBoostMaskAccessor.h b/code/masks/rttbBoostMaskAccessor.h deleted file mode 100644 index 2497a48..0000000 --- a/code/masks/rttbBoostMaskAccessor.h +++ /dev/null @@ -1,117 +0,0 @@ -// ----------------------------------------------------------------------- -// RTToolbox - DKFZ radiotherapy quantitative evaluation library -// -// Copyright (c) German Cancer Research Center (DKFZ), -// Software development for Integrated Diagnostics and Therapy (SIDT). -// ALL RIGHTS RESERVED. -// See rttbCopyright.txt or -// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html -// -// This software is distributed WITHOUT ANY WARRANTY; 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: zhangl $ (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 - { - /*! @class BoostMaskAccessor - * @brief Implementation of the voxelization using boost - */ - class BoostMaskAccessor: public core::MaskAccessorInterface - { - public: - typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; - typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; - - typedef core::Structure::StructTypePointer StructTypePointer; - typedef boost::shared_ptr GeometricInfoPointer; - - private: - - GeometricInfoPointer _spGeoInfo; - - /*! vector containing list of mask voxels*/ - MaskVoxelListPointer _spRelevantVoxelVector; - - StructTypePointer _spStructure; - - IDType _maskUID; - - - 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 - */ - BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr); - - /*! @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/testing/masks/BoostMaskAccessorTest.cpp b/testing/io/mask/BoostMaskAccessorTest.cpp similarity index 85% rename from testing/masks/BoostMaskAccessorTest.cpp rename to testing/io/mask/BoostMaskAccessorTest.cpp index a8c03cf..5c4211e 100644 --- a/testing/masks/BoostMaskAccessorTest.cpp +++ b/testing/io/mask/BoostMaskAccessorTest.cpp @@ -1,130 +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: 880 $ (last changed revision) // @date $Date: 2015-01-13 14:14:24 +0100 (Di, 13 Jan 2015) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" #include "rttbNullPointerException.h" #include "rttbException.h" -#include "../core/DummyStructure.h" -#include "../core/DummyDoseAccessor.h" -#include "rttbMaskVoxelListTester.h" -#include "rttbMaskRectStructTester.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::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; - typedef masks::BoostMaskAccessor::MaskVoxelList MaskVoxelList; + typedef io::mask::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; + typedef io::mask::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::BoostMask(geometricPtr, spMyStruct)); - rttb::masks::BoostMask boostMask = rttb::masks::BoostMask(geometricPtr, spMyStruct); - CHECK_NO_THROW(rttb::masks::BoostMaskAccessor(spMyStruct, geometricPtr)); - rttb::masks::BoostMaskAccessor boostMaskAccessor(spMyStruct, geometricPtr); + CHECK_NO_THROW( rttb::io::mask::BoostMask(geometricPtr, spMyStruct)); + rttb::io::mask::BoostMask boostMask = rttb::io::mask::BoostMask(geometricPtr, spMyStruct); + CHECK_NO_THROW(rttb::io::mask::BoostMaskAccessor(spMyStruct, geometricPtr)); + rttb::io::mask::BoostMaskAccessor boostMaskAccessor(spMyStruct, geometricPtr); //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/io/mask/CMakeLists.txt b/testing/io/mask/CMakeLists.txt index 9b2bda6..f366b1c 100644 --- a/testing/io/mask/CMakeLists.txt +++ b/testing/io/mask/CMakeLists.txt @@ -1,24 +1,27 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(MaskIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbMaskIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- +ADD_TEST(BoostMaskAccessorTest ${MaskIO_TEST} BoostMaskAccessorTest +) + ADD_TEST(MaskAccessorGeneratorTest ${MaskIO_TEST} MaskAccessorGeneratorTest "${TEST_DATA_ROOT}/MatchPointLogo.mhd") ADD_TEST(MaskAccessorConverterTest ${MaskIO_TEST} MaskAccessorConverterTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" "${TEST_DATA_ROOT}/MatchPointLogo.mhd") -RTTB_CREATE_TEST_MODULE(rttbMaskIO DEPENDS RTTBMaskIO RTTBDicomIO RTTBITKIO RTTBMasks PACKAGE_DEPENDS Boost Litmus MatchPoint ITK DCMTK) +RTTB_CREATE_TEST_MODULE(rttbMaskIO DEPENDS RTTBMaskIO RTTBDicomIO RTTBITKIO RTTBMasks PACKAGE_DEPENDS Boost BoostBinaries Litmus MatchPoint ITK DCMTK) diff --git a/testing/io/mask/files.cmake b/testing/io/mask/files.cmake index 3f345c4..af41734 100644 --- a/testing/io/mask/files.cmake +++ b/testing/io/mask/files.cmake @@ -1,8 +1,15 @@ SET(CPP_FILES + ../../core/DummyStructure.cpp + ../../core/CreateTestStructure.cpp + ../../core/DummyDoseAccessor.cpp + BoostMaskAccessorTest.cpp MaskAccessorGeneratorTest.cpp MaskAccessorConverterTest.cpp rttbMaskIOTests.cpp ) -SET(H_FILES +SET(H_FILES + ../../core/DummyStructure.h + ../../core/CreateTestStructure.h + ../../core/DummyDoseAccessor.h ) diff --git a/testing/io/mask/rttbMaskIOTests.cpp b/testing/io/mask/rttbMaskIOTests.cpp index 8a89504..52e3d82 100644 --- a/testing/io/mask/rttbMaskIOTests.cpp +++ b/testing/io/mask/rttbMaskIOTests.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: 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) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb{ namespace testing{ void registerTests() { + LIT_REGISTER_TEST(BoostMaskAccessorTest); LIT_REGISTER_TEST(MaskAccessorGeneratorTest); LIT_REGISTER_TEST(MaskAccessorConverterTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc,argv); } catch(...) { result = -1; } return result; } diff --git a/testing/masks/CMakeLists.txt b/testing/masks/CMakeLists.txt index 8c1c480..24b8248 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/CMakeLists.txt @@ -1,23 +1,20 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(MASKS_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbMasksTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- -ADD_TEST(BoostMaskAccessorTest ${MASKS_TESTS} BoostMaskAccessorTest -) - ADD_TEST(OTBMaskAccessorTest ${MASKS_TESTS} OTBMaskAccessorTest ) RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBMasks PACKAGE_DEPENDS BoostBinaries Litmus DCMTK) diff --git a/testing/masks/OTBMaskAccessorTest.cpp b/testing/masks/OTBMaskAccessorTest.cpp index 0096fce..cc1e5c8 100644 --- a/testing/masks/OTBMaskAccessorTest.cpp +++ b/testing/masks/OTBMaskAccessorTest.cpp @@ -1,198 +1,197 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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" -#include "rttbBoostMask.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::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef masks::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::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); masks::OTBMaskAccessor testOTB1(spMyStruct, spTestDoseAccessor->getGeometricInfo()); CHECK_EQUAL(spTestDoseAccessor->getGeometricInfo(), testOTB1.getGeometricInfo()); CHECK_NO_THROW(masks::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); masks::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()); 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/files.cmake b/testing/masks/files.cmake index a195a9e..fc32ea9 100644 --- a/testing/masks/files.cmake +++ b/testing/masks/files.cmake @@ -1,18 +1,17 @@ SET(CPP_FILES - BoostMaskAccessorTest.cpp ../core/DummyStructure.cpp ../core/CreateTestStructure.cpp ../core/DummyDoseAccessor.cpp OTBMaskAccessorTest.cpp rttbMaskVoxelListTester.cpp rttbMaskRectStructTester.cpp rttbMasksTests.cpp ) SET(H_FILES ../core/DummyStructure.h ../core/CreateTestStructure.h ../core/DummyDoseAccessor.h rttbMaskVoxelListTester.h rttbMaskRectStructTester.h ) diff --git a/testing/masks/rttbMasksTests.cpp b/testing/masks/rttbMasksTests.cpp index 40a46d0..c0a75a3 100644 --- a/testing/masks/rttbMasksTests.cpp +++ b/testing/masks/rttbMasksTests.cpp @@ -1,64 +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) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { void registerTests() { - LIT_REGISTER_TEST(BoostMaskAccessorTest); LIT_REGISTER_TEST(OTBMaskAccessorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; }