diff --git a/code/core/rttbMaskVoxel.cpp b/code/core/rttbMaskVoxel.cpp index 4ab5ab5..079ec63 100644 --- a/code/core/rttbMaskVoxel.cpp +++ b/code/core/rttbMaskVoxel.cpp @@ -1,81 +1,85 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbMaskVoxel.h" #include "rttbInvalidParameterException.h" namespace rttb{ namespace core{ MaskVoxel::MaskVoxel(const rttb::VoxelGridID &aVoxelGridID){ if(aVoxelGridID<0) - { + { std::cout << aVoxelGridID<1) - { + { std::cout << aVolumeFraction<1) - { + { std::cout << aVolumeFraction< +#include +#include + +#include +#include +#include +#include +#include + +#include "rttbMaskBoost.h" +#include "rttbNullPointerException.h" +#include "rttbInvalidParameterException.h" + +namespace rttb{ + namespace masks{ + MaskBoost::MaskBoost(MaskBoost::GeometricInfoPtr aDoseGeoInfo, MaskBoost::StrPtr 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!"); + } + + if(hasSelfIntersections()){ + throw rttb::core::InvalidParameterException("Error: structure has self intersections!"); + } + + + for(unsigned int i=0; i< aDoseGeoInfo->getNumSlices(); i++){ + std::vector 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 MaskBoost::hasSelfIntersections(){ + bool hasSelfIntersection = false; + + for(unsigned int indexZ=0; indexZ< _geometricInfo->getNumSlices(); indexZ++){ + rttb::VoxelGridIndex3D currentIndex(0,0,indexZ); + + std::vector boostPolygons = getIntersectionSlicePolygons(currentIndex); + + for(unsigned int i =0; i intersection; + boost::geometry::intersection(boostPolygons.at(i), boostPolygons.at(j), intersection); + if(intersection.size()>0){ + hasSelfIntersection = true; + std::cout << "Has self intersection! Slice: "<< indexZ << ", polygon "< MaskBoost::getBoundingBox(unsigned int sliceNumber){ + if(sliceNumber<0 || sliceNumber >= _geometricInfo->getNumSlices()){ + throw rttb::core::InvalidParameterException(std::string("Error: slice number is invalid!")); + } + + rttb::VoxelGridIndex3D currentIndex(0,0,sliceNumber); + + std::vector 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); + + std::vector voxelList; + voxelList.push_back(index0); + voxelList.push_back(index1); + + return voxelList; + } + + + /*Get intersection polygons of the contour and a voxel polygon*/ + std::deque MaskBoost::getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D){ + std::deque polygonDeque; + + BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); + boost::geometry::correct(voxelPolygon); + + std::vector contourVector = getIntersectionSlicePolygons(aVoxelIndex3D); + for(unsigned int i=0; i intersection; + boost::geometry::intersection(voxelPolygon, contour, intersection); + + polygonDeque.insert(polygonDeque.end(), intersection.begin(), intersection.end()); + } + + return polygonDeque; + } + + + /*Calculate the intersection area*/ + double MaskBoost::calcArea(std::deque aPolygonDeque){ + double area = 0; + for(unsigned int i=0; iconvert(aMaskVoxel.getVoxelGridID(), gridIndex3D); + return gridIndex3D; + } + + MaskBoost::MaskVoxelListPointer MaskBoost::getRelevantVoxelVector(){ + return _voxelInStructure; + } + + MaskBoost::BoostRing2D MaskBoost::convert(const rttb::PolygonType& aRTTBPolygon){ + MaskBoost::BoostRing2D polygon2D; + BoostPoint2D firstPoint; + for(unsigned int i=0; i MaskBoost::getIntersectionSlicePolygons(const rttb::VoxelGridIndex3D& aVoxelGrid3D){ + std::vector boostPolygonVector; + + rttb::PolygonSequenceType polygonSequence = _structure->getStructureVector(); + + 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; + } + + MaskBoost::BoostRing2D MaskBoost::get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D){ + MaskBoost::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/rttbMaskBoost.h b/code/masks/rttbMaskBoost.h new file mode 100644 index 0000000..297cc65 --- /dev/null +++ b/code/masks/rttbMaskBoost.h @@ -0,0 +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: 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_MASK_BOOST_H +#define __RT_MASK_BOOST_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 MaskBoost{ + + public: + typedef boost::shared_ptr GeometricInfoPtr; + typedef core::Structure::StructTypePointer StrPtr; + typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; + typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; + typedef boost::geometry::model::d2::point_xy BoostPoint2D; + typedef boost::geometry::model::polygon > BoostPolygon2D; + typedef boost::geometry::model::ring > BoostRing2D; + + MaskBoost(GeometricInfoPtr aDoseGeoInfo, StrPtr aStructure); + + MaskVoxelListPointer getRelevantVoxelVector(); + + private: + + GeometricInfoPtr _geometricInfo; + + StrPtr _structure; + + //vector of the MaskVoxel inside the structure + MaskVoxelListPointer _voxelInStructure; + + /* Check if the structure has self intersections*/ + bool hasSelfIntersections(); + + + /*Get the min/max voxel index of the bounding box of the polygon in the slice with sliceNumber*/ + std::vector getBoundingBox(unsigned int sliceNumber); + + + /*Get intersection polygons of the contour and a voxel polygon*/ + std::deque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D); + + + /*Calculate the intersection area*/ + double calcArea(std::deque aPolygonDeque); + + VoxelGridIndex3D getGridIndex3D(const core::MaskVoxel& aMaskVoxel); + + + /*Convert RTTB polygon to boost polygon*/ + BoostRing2D convert(const rttb::PolygonType& aRTTBPolygon); + + /*Get the intersection slice of the voxel, return the polygons in the slice*/ + std::vector getIntersectionSlicePolygons(const rttb::VoxelGridIndex3D& aVoxelGrid3D); + + /*Get the voxel 2d contour polygon*/ + BoostRing2D get2DContour(const rttb::VoxelGridIndex3D& aVoxelGrid3D); + + }; + + } +} + +#endif \ No newline at end of file diff --git a/testing/examples/DVHCalculatorExampleTest.cpp b/testing/examples/DVHCalculatorExampleTest.cpp index 94abf88..a65046b 100644 --- a/testing/examples/DVHCalculatorExampleTest.cpp +++ b/testing/examples/DVHCalculatorExampleTest.cpp @@ -1,336 +1,356 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; 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 "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmrt/drtdose.h" #include "dcmtk/dcmrt/drtstrct.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 "rttbMaskBoost.h" +#include "../masks/rttbMaskVoxelListTester.h" + namespace rttb { namespace testing { /*! @brief DVHCalculatorTest. 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 DVHCalculatorExampleTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::DVHCalculator::MaskedDoseIteratorPointer MaskedDoseIteratorPointer; typedef masks::OTBMaskAccessor::StructTypePointer StructTypePointer; typedef core::DVH::DVHPointer DVHPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + typedef masks::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; + typedef masks::OTBMaskAccessor::MaskVoxelList MaskVoxelList; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; if (argc > 1) { RTSTRUCT_FILENAME = argv[1]; } if (argc > 2) { RTDOSE_FILENAME = argv[2]; } if (argc > 3) { RTDOSE2_FILENAME = argv[3]; } if (argc > 4) { RTDOSE3_FILENAME = argv[4]; } OFCondition status; DcmFileFormat fileformat; // read dicom-rt dose ::DRTDoseIOD rtdose1; 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(); //storeage for mask accessors to reduce time spent on voxelization (perform only once) std::vector rtStructSetMaskAccessorVec; ::DRTDoseIOD rtdose2; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2(RTDOSE2_FILENAME.c_str()); DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); ::DRTDoseIOD rtdose3; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator3(RTDOSE3_FILENAME.c_str()); DoseAccessorPointer doseAccessor3(doseAccessorGenerator3.generateDoseAccessor()); //start evaluation clock_t start(clock()); if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) { + std::cout << rtStructureSet->getStructure(j)->getLabel() << std::endl; + /**/ + boost::shared_ptr geometricPtr = boost::make_shared(doseAccessor1->getGeometricInfo()); + + rttb::masks::MaskBoost maskBoost = rttb::masks::MaskBoost(geometricPtr, rtStructureSet->getStructure(j)); + MaskVoxelListPointer voxelListBoost = maskBoost.getRelevantVoxelVector(); + + /**/ + //create MaskAccessor for each structure boost::shared_ptr spOTBMaskAccessor = boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); + + + MaskVoxelListPointer relVoxelOTB2 = spMaskAccessor->getRelevantVoxelVector(); + MaskVoxelListTester listComp(voxelListBoost, relVoxelOTB2); + CHECK_TESTER(listComp); + //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //store MaskAccessor for each structure (later reuse) rtStructSetMaskAccessorVec.push_back(spMaskAccessor); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); /*//DEBUG OUTPUT std::cout << "=== Dose 1 Structure "< spMaskedDoseIteratorTmp = boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor2); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor2->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); /*//DEBUG OUTPUT std::cout << "=== Dose 2 Structure "< spMaskedDoseIteratorTmp = boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor3); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //calculate DVH rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor3->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); /*//DEBUG OUTPUT std::cout << "=== Dose 3 Structure "< #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 "rttbMaskBoost.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); + //test maskBoost + boost::shared_ptr geometricPtr = boost::make_shared(spTestDoseAccessor->getGeometricInfo()); + + + rttb::masks::MaskBoost maskBoost = rttb::masks::MaskBoost(geometricPtr, spMyStruct); + MaskVoxelListPointer voxelListBoost = maskBoost.getRelevantVoxelVector(); + //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); + MaskVoxelListTester listComp2(relVoxelOTB1, voxelListBoost); + CHECK_TESTER(listComp2); + for(int i=0; isize(); i++){ + std::cout << relVoxelOTB1->at(i).getRelevantVolumeFraction() << ", "; + } + std::cout << std::endl; + for(int i=0; isize(); i++){ + std::cout << voxelListBoost->at(i).getRelevantVolumeFraction() << ", "; + } + std::cout << std::endl; + //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 f6a6978..6ad0942 100644 --- a/testing/masks/rttbMaskVoxelListTester.cpp +++ b/testing/masks/rttbMaskVoxelListTester.cpp @@ -1,119 +1,122 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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 testing{ MaskVoxelListTester::MaskVoxelListTester(MaskVoxelListPointer aReferenceList, MaskVoxelListPointer aCompareList){ _referenceList = aReferenceList; _compareList = aCompareList; _sameSize = false; _masVoxelsDiffer = false; _numDifference = 0; } void MaskVoxelListTester::setReferenceList(const MaskVoxelListPointer aReferenceList){ _referenceList = aReferenceList; } void MaskVoxelListTester::setCompareList(const MaskVoxelListPointer aCompareList){ _compareList = aCompareList; } lit::StringType MaskVoxelListTester::getTestDescription(void) const { return "Compare two MaskVoxelLists and determine if the contained content is equal."; }; bool MaskVoxelListTester::doCheck(void) const{ _pResults->onTestStart(getCurrentTestLabel()); _masVoxelsDiffer = false; if (_referenceList->size()==_compareList->size()){ _sameSize = true; } else{ _sameSize = false; return false; } _numDifference = 0; _maxDifference = 0; 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()){ continue; } else{ float diff = iterR->getRelevantVolumeFraction()-iterC->getRelevantVolumeFraction(); if (diff > _maxDifference) { _maxDifference = diff; } + /*if(diff > 0.001){ + std::cout <getVoxelGridID()<< ": ("<< iterR->getRelevantVolumeFraction() << ","<getRelevantVolumeFraction()<<"); "; + }*/ _numDifference++; } } else{ _failedListIndex = index; _masVoxelsDiffer = true; return false; } }//end for(VoxelGridID id = 0; id < _referenceList->getGridSi... if (_numDifference > 0){ return false; } return true; } void MaskVoxelListTester::handleSuccess(void) const{ std::ostringstream stream; stream << "Both Lists are equal"<onTestSuccess(getCurrentTestLabel(), stream.str()); } void MaskVoxelListTester::handleFailure(void) const{ std::ostringstream stream; 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 (_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; } _pResults->onTestFailure(getCurrentTestLabel(), stream.str()); } } } \ No newline at end of file