diff --git a/code/io/mask/rttbBoostMask.cpp b/code/io/mask/rttbBoostMask.cpp index 7a81f6c..31963d1 100644 --- a/code/io/mask/rttbBoostMask.cpp +++ b/code/io/mask/rttbBoostMask.cpp @@ -1,267 +1,269 @@ #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()){ - + _isUpToDate = false; 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(); + if(!_isUpToDate){ + 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 index 4a4d33c..9da0da7 100644 --- a/code/io/mask/rttbBoostMask.h +++ b/code/io/mask/rttbBoostMask.h @@ -1,112 +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: 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 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*/ 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