diff --git a/code/core/files.cmake b/code/core/files.cmake index 069db8c..60d2b55 100644 --- a/code/core/files.cmake +++ b/code/core/files.cmake @@ -1,58 +1,60 @@ SET(CPP_FILES rttbDoseIteratorInterface.cpp rttbDVH.cpp rttbDVHCalculator.cpp rttbDVHSet.cpp rttbException.cpp rttbGenericDoseIterator.cpp rttbGenericMaskedDoseIterator.cpp rttbGeometricInfo.cpp rttbIndexOutOfBoundsException.cpp rttbInvalidDoseException.cpp rttbInvalidParameterException.cpp rttbMappingOutsideOfImageException.cpp rttbMaskedDoseIteratorInterface.cpp rttbMaskVoxel.cpp rttbNullPointerException.cpp rttbPaddingException.cpp rttbPhysicalInfo.cpp rttbStructure.cpp rttbStructureSet.cpp rttbStrVectorStructureSetGenerator.cpp ) SET(H_FILES rttbBaseType.h rttbDoseAccessorGeneratorBase.h rttbDoseAccessorGeneratorInterface.h rttbDoseAccessorInterface.h rttbDoseIteratorInterface.h rttbDVH.h rttbDVHCalculator.h rttbDVHGeneratorInterface.h rttbDVHSet.h rttbException.h rttbExceptionMacros.h rttbGenericDoseIterator.h rttbGenericMaskedDoseIterator.h rttbGeometricInfo.h rttbIndexConversionInterface.h rttbIndexOutOfBoundsException.h rttbInvalidDoseException.h rttbInvalidParameterException.h rttbMappingOutsideOfImageException.h rttbMaskAccessorGeneratorBase.h rttbMaskAccessorGeneratorInterface.h rttbMaskAccessorInterface.h + rttbMaskAccessorProcessorBase.h + rttbMaskAccessorProcessorInterface.h rttbMaskedDoseIteratorInterface.h rttbMaskVoxel.h rttbMutableDoseAccessorInterface.h rttbMutableMaskAccessorInterface.h rttbNullPointerException.h rttbPaddingException.h rttbPhysicalInfo.h rttbStructure.h rttbStructureSet.h rttbStructureSetGeneratorInterface.h rttbStrVectorStructureSetGenerator.h ) diff --git a/code/io/mask/rttbMaskAccessorProcessorBase.h b/code/core/rttbMaskAccessorProcessorBase.h similarity index 100% rename from code/io/mask/rttbMaskAccessorProcessorBase.h rename to code/core/rttbMaskAccessorProcessorBase.h diff --git a/code/io/mask/rttbMaskAccessorProcessorInterface.h b/code/core/rttbMaskAccessorProcessorInterface.h similarity index 100% rename from code/io/mask/rttbMaskAccessorProcessorInterface.h rename to code/core/rttbMaskAccessorProcessorInterface.h diff --git a/code/io/CMakeLists.txt b/code/io/CMakeLists.txt index 612e52d..c2e03cb 100644 --- a/code/io/CMakeLists.txt +++ b/code/io/CMakeLists.txt @@ -1,27 +1,22 @@ MESSAGE (STATUS "processing RTToolbox io") ADD_SUBDIRECTORY (other) OPTION(BUILD_IO_Dicom "Determine if the IO class wrappers for DICOM format will be generated." OFF) IF(BUILD_IO_Dicom) ADD_SUBDIRECTORY(dicom) OPTION(BUILD_IO_HELAX "Determine if the IO class wrappers for HELAX format will be generated." OFF) IF(BUILD_IO_HELAX) ADD_SUBDIRECTORY(helax) ENDIF(BUILD_IO_HELAX) ENDIF(BUILD_IO_Dicom) OPTION(BUILD_IO_ITK "Determine if the IO class wrappers for ITK image formats will be generated." OFF) IF(BUILD_IO_ITK) ADD_SUBDIRECTORY(itk) ENDIF(BUILD_IO_ITK) OPTION(BUILD_IO_Virtuos "Determine if the IO class wrappers for Virtuos format will be generated." OFF) IF(BUILD_IO_Virtuos) ADD_SUBDIRECTORY(virtuos) ENDIF(BUILD_IO_Virtuos) -OPTION(BUILD_IO_Mask "Determine if the IO class wrappers for Mask Image will be generated." OFF) -IF(BUILD_IO_Mask) - ADD_SUBDIRECTORY(mask) -ENDIF(BUILD_IO_Mask) - diff --git a/code/io/itk/files.cmake b/code/io/itk/files.cmake index 5ef2044..6930adc 100644 --- a/code/io/itk/files.cmake +++ b/code/io/itk/files.cmake @@ -1,26 +1,38 @@ SET(CPP_FILES - rttbITKImageDoseAccessor.cpp - rttbITKImageFileDoseAccessorGenerator.cpp - rttbITKImageDoseAccessorGenerator.cpp - rttbGenericImageReader.cpp rttbFileDispatch.cpp + rttbGenericImageReader.cpp + rttbImageWriter.cpp + rttbITKException.cpp + rttbITKImageDoseAccessor.cpp rttbITKImageDoseAccessorConverter.cpp + rttbITKImageDoseAccessorGenerator.cpp + rttbITKImageFileDoseAccessorGenerator.cpp + rttbITKImageFileMaskAccessorGenerator.cpp + rttbITKImageMaskAccessor.cpp + rttbITKImageMaskAccessorGenerator.cpp + rttbITKImageMaskAccessorConverter.cpp rttbITKIOHelper.cpp ) SET(H_FILES - rttbITKImageDoseAccessor.h - rttbITKImageFileDoseAccessorGenerator.h - rttbITKImageDoseAccessorGenerator.h + rttbDoseAccessorConversionSettingInterface.h + rttbDoseAccessorProcessorBase.h + rttbDoseAccessorProcessorInterface.h + rttbFileDispatch.h rttbGenericImageReader.h rttbImageReader.h rttbImageReader.tpp - rttbFileDispatch.h + rttbImageWriter.h + rttbITKException.h + rttbITKImageDoseAccessor.h rttbITKImageDoseAccessorConverter.h - rttbDoseAccessorProcessorInterface.h - rttbDoseAccessorProcessorBase.h - rttbDoseAccessorConversionSettingInterface.h + rttbITKImageDoseAccessorGenerator.h + rttbITKImageFileDoseAccessorGenerator.h + rttbITKImageFileMaskAccessorGenerator.h + rttbITKImageMaskAccessor.h + rttbITKImageMaskAccessorConverter.h + rttbITKImageMaskAccessorGenerator.h rttbITKIOHelper.h rttbITKIOHelper.tpp ) diff --git a/code/masks/rttbSelfIntersectingStructureException.cpp b/code/io/itk/rttbITKException.cpp similarity index 57% copy from code/masks/rttbSelfIntersectingStructureException.cpp copy to code/io/itk/rttbITKException.cpp index a747cc0..f5449cc 100644 --- a/code/masks/rttbSelfIntersectingStructureException.cpp +++ b/code/io/itk/rttbITKException.cpp @@ -1,39 +1,39 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ -#include #include -#include "rttbSelfIntersectingStructureException.h" +#include "rttbITKException.h" namespace rttb{ - namespace masks{ - - const char* SelfIntersectingStructureException::what() const throw() { - return rttb_what.c_str(); + namespace io{ + namespace itk{ + const char* ITKException::what() const throw() { + return rttb_what.c_str(); } - const char* SelfIntersectingStructureException::GetNameOfClass() const{ - return "SelfIntersectingStructureException"; - } - - }//end namespace masks - }//end namespace rttb + const char* ITKException::GetNameOfClass() const{ + return "ITKException"; + } + } + + }//end namespace io +}//end namespace rttb diff --git a/code/masks/rttbSelfIntersectingStructureException.h b/code/io/itk/rttbITKException.h similarity index 51% copy from code/masks/rttbSelfIntersectingStructureException.h copy to code/io/itk/rttbITKException.h index bdd8692..92eceb4 100644 --- a/code/masks/rttbSelfIntersectingStructureException.h +++ b/code/io/itk/rttbITKException.h @@ -1,55 +1,57 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H -#define __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H +#ifndef __ITK_EXCEPTION_H +#define __ITK_EXCEPTION_H #include #include #include "rttbException.h" namespace rttb{ - namespace masks{ + namespace io{ + namespace itk{ - /*! @class SelfIntersectingStructureException - @brief This exception will be thrown in case a Structure intersects with itself in a context where - this is not allowed. - */ - class SelfIntersectingStructureException: public core::Exception + /*! @class ITKException + @brief This class represents a ITKException. Any itk error will throw this exception. + */ + class ITKException: public core::Exception { public: - SelfIntersectingStructureException(const std::string& aWhat):Exception(aWhat){} + ITKException(const std::string& aWhat):Exception(aWhat){} - virtual ~SelfIntersectingStructureException() throw() {} + virtual ~ITKException() throw() {} /*! @brief Get the exception description */ - virtual const char * what() const throw(); + const char * what() const throw(); - /*! @brief Get the name of the exception class + /*! @brief Get the name of the class that was thrown */ - virtual const char* GetNameOfClass() const; + const char* GetNameOfClass() const; }; } } +} + #endif diff --git a/code/io/mask/rttbITKImageFileMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp similarity index 95% rename from code/io/mask/rttbITKImageFileMaskAccessorGenerator.cpp rename to code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp index 6d00481..c9b7b30 100644 --- a/code/io/mask/rttbITKImageFileMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.cpp @@ -1,59 +1,59 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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) */ #include #include #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "../itk/rttbITKIOHelper.h" namespace rttb { namespace io { - namespace mask + namespace itk { ITKImageFileMaskAccessorGenerator::~ITKImageFileMaskAccessorGenerator() { } ITKImageFileMaskAccessorGenerator::ITKImageFileMaskAccessorGenerator(const FileNameType& fileName) { _itkMaskFileName = fileName; } rttb::core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageFileMaskAccessorGenerator::generateMaskAccessor() { _itkDoubleImage = rttb::io::itk::readITKDoubleImage(_itkMaskFileName); _maskAccessor = boost::make_shared(_itkDoubleImage.GetPointer()); return _maskAccessor; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/mask/rttbITKImageFileMaskAccessorGenerator.h b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h similarity index 96% rename from code/io/mask/rttbITKImageFileMaskAccessorGenerator.h rename to code/io/itk/rttbITKImageFileMaskAccessorGenerator.h index 9e12307..2569c2a 100644 --- a/code/io/mask/rttbITKImageFileMaskAccessorGenerator.h +++ b/code/io/itk/rttbITKImageFileMaskAccessorGenerator.h @@ -1,77 +1,77 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) */ #ifndef __ITK_IMAGE_MASK_FILE_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_MASK_FILE_ACCESSOR_GENERATOR_H #include "rttbMaskAccessorGeneratorBase.h" #include "rttbBaseType.h" #include "rttbITKImageMaskAccessor.h" #include "../itk/rttbGenericImageReader.h" #include "itkImage.h" #include "itkCastImageFilter.h" namespace rttb { namespace io { - namespace mask + namespace itk { /*! @class ITKImageFileMaskAccessorGenerator @brief Load 3D Mask data using the itk loading methods and wraps the resulting itk image in a ITKImageMaskAccessor. * this is normally used if Mask distributions are stored in formats like meta image, nrrd... */ class ITKImageFileMaskAccessorGenerator: public core::MaskAccessorGeneratorBase { public: typedef MaskAccessorGeneratorBase::MaskAccessorPointer MaskAccessorPointer; private: FileNameType _itkMaskFileName; /** @brief The mask as itkImage */ ITKImageMaskAccessor::ITKMaskImageType::Pointer _itkDoubleImage; ITKImageFileMaskAccessorGenerator(); public: ~ITKImageFileMaskAccessorGenerator(); ITKImageFileMaskAccessorGenerator(const FileNameType& fileName); /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. @exception InvalidDoseException Thrown if file could not be read @exception InvalidParameterException Thrown if file has imageDimension !=3 or image component type != SCALAR @details is always converted into a itkImage by using a CastImageFilter @sa doCasting, handleGenericImage */ MaskAccessorPointer generateMaskAccessor(); }; }//end namespace itk }//end namespace io }//end namespace rttb #endif diff --git a/code/io/mask/rttbITKImageMaskAccessor.cpp b/code/io/itk/rttbITKImageMaskAccessor.cpp similarity index 96% rename from code/io/mask/rttbITKImageMaskAccessor.cpp rename to code/io/itk/rttbITKImageMaskAccessor.cpp index 3951272..8f183a1 100644 --- a/code/io/mask/rttbITKImageMaskAccessor.cpp +++ b/code/io/itk/rttbITKImageMaskAccessor.cpp @@ -1,165 +1,165 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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) */ #include #include #include "rttbITKImageMaskAccessor.h" #include "rttbInvalidDoseException.h" namespace rttb { namespace io { - namespace mask + namespace itk { ITKImageMaskAccessor::ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage) : _mask(aMaskImage) { if (_mask.IsNull()) { throw core::InvalidDoseException("Mask image = 0!") ; } assembleGeometricInfo(); } ITKImageMaskAccessor::~ITKImageMaskAccessor() { }; bool ITKImageMaskAccessor::assembleGeometricInfo() { _geoInfo = boost::make_shared(); _geoInfo->setSpacing(SpacingVectorType3D(_mask->GetSpacing()[0], _mask->GetSpacing()[1], _mask->GetSpacing()[2])); if (_geoInfo->getSpacing()[0] == 0 || _geoInfo->getSpacing()[1] == 0 || _geoInfo->getSpacing()[2] == 0) { throw core::InvalidDoseException("Pixel spacing = 0!"); } _geoInfo->setImagePositionPatient(WorldCoordinate3D(_mask->GetOrigin()[0], _mask->GetOrigin()[1], _mask->GetOrigin()[2])); OrientationMatrix OM(0); for (int col = 0; col < 3; ++col) { for (int row = 0; row < 3; ++row) { OM(col, row) = _mask->GetDirection()(col, row); } } _geoInfo->setOrientationMatrix(OM); _geoInfo->setNumColumns(_mask->GetLargestPossibleRegion().GetSize()[0]); _geoInfo->setNumRows(_mask->GetLargestPossibleRegion().GetSize()[1]); _geoInfo->setNumSlices(_mask->GetLargestPossibleRegion().GetSize()[2]); if (_geoInfo->getNumColumns() == 0 || _geoInfo->getNumRows() == 0 || _geoInfo->getNumSlices() == 0) { throw core::InvalidDoseException("Empty mask!") ; } return true; } void ITKImageMaskAccessor::updateMask() { return; } ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector() { updateMask(); _relevantVoxelVector = getRelevantVoxelVector(0); return _relevantVoxelVector; } ITKImageMaskAccessor::MaskVoxelListPointer ITKImageMaskAccessor::getRelevantVoxelVector(float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); int size = _geoInfo->getNumColumns()*_geoInfo->getNumRows()*_geoInfo->getNumSlices(); filteredVoxelVectorPointer->reserve(size); for(int gridIndex =0 ; gridIndex < size; gridIndex++){ core::MaskVoxel currentVoxel = core::MaskVoxel(gridIndex); if(getMaskAt(gridIndex, currentVoxel)){ if(currentVoxel.getRelevantVolumeFraction() > lowerThreshold){ filteredVoxelVectorPointer->push_back(currentVoxel); } } } return filteredVoxelVectorPointer; } bool ITKImageMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { VoxelGridIndex3D aVoxelGridIndex; if (_geoInfo->convert(aID, aVoxelGridIndex)) { return getMaskAt(aVoxelGridIndex, voxel); } else { return false; } } bool ITKImageMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { voxel.setRelevantVolumeFraction(0); if (_geoInfo->validIndex(aIndex)) { const ITKMaskImageType::IndexType pixelIndex = {{aIndex[0], aIndex[1], aIndex[2]}}; double value = _mask->GetPixel(pixelIndex); VoxelGridID gridId; _geoInfo->convert(aIndex, gridId); if(value >= 0 && value <=1 ){ voxel.setRelevantVolumeFraction(value); } else{ std::cerr << "The pixel value of the mask should be >=0 and <=1!"< ITKMaskImageType; typedef ::itk::ImageBase<3> ITKImageBaseType; typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; typedef boost::shared_ptr GeometricInfoPointer; private: /** @brief The mask as itkImage */ ITKMaskImageType::ConstPointer _mask; IDType _maskUID; GeometricInfoPointer _geoInfo; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _relevantVoxelVector; /*! @brief get all required data from the itk image contained in _Mask @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. */ bool assembleGeometricInfo(); public: ~ITKImageMaskAccessor(); ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage); /*! @brief voxelization of the given structures according to the original RTToolbox algorithm*/ void updateMask(); /*! @brief get vector conatining al relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(); /*! @brief get vector conatining al 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; bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; /*! @brief give access to GeometricInfo*/ const core::GeometricInfo& getGeometricInfo() const; /* @ brief is true if Mask is on a homogeneous grid */ // Inhomogeneous grids are not supported at the moment, but if they will // be supported in the future the interface does not need to change. bool isGridHomogeneous() const { return true; }; IDType getMaskUID() const { return _maskUID; }; }; } } } #endif diff --git a/code/io/mask/rttbITKImageMaskAccessorConverter.cpp b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp similarity index 96% rename from code/io/mask/rttbITKImageMaskAccessorConverter.cpp rename to code/io/itk/rttbITKImageMaskAccessorConverter.cpp index 05d855c..169df98 100644 --- a/code/io/mask/rttbITKImageMaskAccessorConverter.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.cpp @@ -1,129 +1,129 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 747 $ (last changed revision) // @date $Date: 2014-09-17 12:01:00 +0200 (Mi, 17 Sep 2014) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include #include "rttbITKImageMaskAccessorConverter.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "itkImageRegionIterator.h" #include "rttbITKImageMaskAccessor.h" namespace rttb { namespace io { - namespace mask + namespace itk { ITKImageMaskAccessorConverter::ITKImageMaskAccessorConverter(MaskAccessorPointer accessor) { setMaskAccessor(accessor); } bool ITKImageMaskAccessorConverter::process() { //Transfer GeometricInfo to ITK Properties core::GeometricInfo geoInfo = _maskAccessor->getGeometricInfo(); ITKImageMaskAccessor::ITKMaskImageType::RegionType region; ITKImageMaskAccessor::ITKMaskImageType::IndexType start = {{0, 0, 0}}; ITKImageMaskAccessor::ITKMaskImageType::SizeType size = {{geoInfo.getNumColumns(), geoInfo.getNumRows(), geoInfo.getNumSlices()}}; ITKImageMaskAccessor::ITKMaskImageType::SpacingType spacing; for (unsigned int i = 0; i < 3; ++i) { spacing[i] = geoInfo.getSpacing()[i]; } ITKImageMaskAccessor::ITKMaskImageType::PointType origin; for (unsigned int i = 0; i < 3; ++i) { origin[i] = geoInfo.getImagePositionPatient()[i]; } ITKImageMaskAccessor::ITKMaskImageType::DirectionType direction; OrientationMatrix OM = geoInfo.getOrientationMatrix(); for (int col = 0; col < 3; ++col) { for (int row = 0; row < 3; ++row) { direction(col, row) = OM(col, row); } } //Create image, assign properties region.SetSize(size); region.SetIndex(start); _itkImage = ITKImageMaskAccessor::ITKMaskImageType::New(); _itkImage->SetRegions(region); _itkImage->SetSpacing(spacing); _itkImage->SetDirection(direction); _itkImage->SetOrigin(origin); _itkImage->Allocate(); ::itk::ImageRegionIterator imageIterator(_itkImage, region); VoxelGridID id = 0; //Transfer Mask values to itk image //Large advantage: rttbVoxelGridId ordering is the same as itk ordering while (!imageIterator.IsAtEnd()) { VoxelGridIndex3D aIndex; if (_maskAccessor->getGeometricInfo().validID(id)) { rttb::core::MaskVoxel maskVoxel = core::MaskVoxel(id);; _maskAccessor->getMaskAt(id, maskVoxel); // Set the current pixel imageIterator.Set(maskVoxel.getRelevantVolumeFraction()); } else { if (failsOnInvalidIDs()) { throw core::InvalidDoseException("invalid Mask id!"); return false; } else { imageIterator.Set(_invalidDoseValue); } } ++imageIterator; ++id; } return true; } }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/mask/rttbITKImageMaskAccessorConverter.h b/code/io/itk/rttbITKImageMaskAccessorConverter.h similarity index 96% rename from code/io/mask/rttbITKImageMaskAccessorConverter.h rename to code/io/itk/rttbITKImageMaskAccessorConverter.h index 31b7a81..8cf2cc8 100644 --- a/code/io/mask/rttbITKImageMaskAccessorConverter.h +++ b/code/io/itk/rttbITKImageMaskAccessorConverter.h @@ -1,68 +1,68 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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) */ #ifndef __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #define __ITK_IMAGE_MASK_ACCESSOR_CONVERTER_H #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorProcessorBase.h" #include "../itk/rttbDoseAccessorConversionSettingInterface.h" namespace rttb { namespace io { - namespace mask + namespace itk { /*! @class ITKImageMaskAccessorConverter @brief Class converts/dumps the processed accessor into an itk image @remark MaskAccessorConversionInterface defines how the converter should react on non valid Mask values. */ class ITKImageMaskAccessorConverter: public core::MaskAccessorProcessorBase, public rttb::core::DoseAccessorConversionSettingInterface { public: typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; bool process(); const ITKImageMaskAccessor::ITKMaskImageType::Pointer getITKImage() { return _itkImage; } ITKImageMaskAccessorConverter(MaskAccessorPointer accessor); virtual ~ITKImageMaskAccessorConverter() {}; private: ITKImageMaskAccessorConverter(const ITKImageMaskAccessorConverter&); //not implemented on purpose -> non-copyable ITKImageMaskAccessorConverter& operator=(const ITKImageMaskAccessorConverter&);//not implemented on purpose -> non-copyable ITKImageMaskAccessor::ITKMaskImageType::Pointer _itkImage; }; } } } #endif diff --git a/code/io/mask/rttbITKImageMaskAccessorGenerator.cpp b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp similarity index 95% copy from code/io/mask/rttbITKImageMaskAccessorGenerator.cpp copy to code/io/itk/rttbITKImageMaskAccessorGenerator.cpp index 0bf487d..fc7266c 100644 --- a/code/io/mask/rttbITKImageMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.cpp @@ -1,51 +1,51 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) */ #include #include #include "rttbITKImageMaskAccessorGenerator.h" #include "rttbException.h" #include "rttbInvalidDoseException.h" namespace rttb{ namespace io{ - namespace mask{ + namespace itk{ ITKImageMaskAccessorGenerator::ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage){ if (aMaskImage == NULL){ throw core::InvalidDoseException("MaskImage is NULL"); } _maskPtr = aMaskImage; } core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageMaskAccessorGenerator::generateMaskAccessor(){ _maskAccessor = boost::make_shared(_maskPtr); return _maskAccessor; } }//end namespace mask }//end namespace io }//end namespace rttb diff --git a/code/io/mask/rttbITKImageMaskAccessorGenerator.h b/code/io/itk/rttbITKImageMaskAccessorGenerator.h similarity index 95% rename from code/io/mask/rttbITKImageMaskAccessorGenerator.h rename to code/io/itk/rttbITKImageMaskAccessorGenerator.h index 21c959a..dce4fb5 100644 --- a/code/io/mask/rttbITKImageMaskAccessorGenerator.h +++ b/code/io/itk/rttbITKImageMaskAccessorGenerator.h @@ -1,67 +1,67 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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) */ #ifndef __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #define __ITK_IMAGE_MASK_ACCESSOR_GENERATOR_H #include "rttbBaseType.h" #include "rttbITKImageMaskAccessor.h" #include "rttbMaskAccessorGeneratorBase.h" #include "itkImage.h" namespace rttb { namespace io { - namespace mask + namespace itk { class ITKImageMaskAccessorGenerator: public core::MaskAccessorGeneratorBase { public: typedef MaskAccessorGeneratorBase::MaskAccessorPointer MaskAccessorPointer; private: /** @brief The Mask as itkImage */ ITKImageMaskAccessor::ITKMaskImageType::ConstPointer _maskPtr; ITKImageMaskAccessorGenerator(); public: virtual ~ITKImageMaskAccessorGenerator() {}; /*! @pre aMaskImage must point to a valid instance. @exception InvalidDoseException Thrown if aMaskImage is invalid. */ ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage); /*! @brief Generate MaskAccessor @return Return shared pointer of MaskAccessor. */ MaskAccessorPointer generateMaskAccessor() ; }; } } } #endif diff --git a/code/io/mask/rttbITKImageMaskAccessorGenerator.cpp b/code/io/itk/rttbImageWriter.cpp similarity index 51% rename from code/io/mask/rttbITKImageMaskAccessorGenerator.cpp rename to code/io/itk/rttbImageWriter.cpp index 0bf487d..f3e3246 100644 --- a/code/io/mask/rttbITKImageMaskAccessorGenerator.cpp +++ b/code/io/itk/rttbImageWriter.cpp @@ -1,51 +1,55 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @author $Author: lzhang $ (last changed by) */ +#include "rttbImageWriter.h" +#include "rttbITKException.h" -#include -#include - -#include "rttbITKImageMaskAccessorGenerator.h" -#include "rttbException.h" -#include "rttbInvalidDoseException.h" +namespace rttb +{ + namespace io + { + namespace itk { + ImageWriter::ImageWriter(FileNameString aFileName, ITKImageTypePointer aITKImage) + :_fileName(aFileName), _itkImage(aITKImage){ + } -namespace rttb{ - namespace io{ - namespace mask{ - ITKImageMaskAccessorGenerator::ITKImageMaskAccessorGenerator(const ITKImageMaskAccessor::ITKMaskImageType* aMaskImage){ - if (aMaskImage == NULL){ - throw core::InvalidDoseException("MaskImage is NULL"); + bool ImageWriter::writeFile(){ + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(_fileName); + writer->SetInput(_itkImage); + try{ + writer->Update(); + } + catch( ::itk::ExceptionObject & excp ) + { + std::cerr << "Error: ITK Exception caught " << excp << std::endl; + throw rttb::io::itk::ITKException("ITK Exception in writing image: writer->Update()!"); + return false; } - _maskPtr = aMaskImage; - } - - core::MaskAccessorGeneratorBase::MaskAccessorPointer ITKImageMaskAccessorGenerator::generateMaskAccessor(){ - _maskAccessor = boost::make_shared(_maskPtr); - return _maskAccessor; + return true; } - - - }//end namespace mask + }//end namespace itk }//end namespace io }//end namespace rttb + diff --git a/code/io/itk/rttbImageWriter.h b/code/io/itk/rttbImageWriter.h new file mode 100644 index 0000000..efbec7f --- /dev/null +++ b/code/io/itk/rttbImageWriter.h @@ -0,0 +1,70 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 793 $ (last changed revision) +// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) +// @author $Author: lzhang $ (last changed by) +*/ + +#ifndef __RTTB_IMAGE_WRITER_H +#define __RTTB_IMAGE_WRITER_H + +#include "itkImage.h" +#include "itkImageSource.h" +#include "itkImageFileWriter.h" +#include "rttbBaseType.h" +#include "rttbITKImageMaskAccessor.h" + +namespace rttb +{ + namespace io + { + namespace itk { + + + /** @class ImageWriter + * @brief Helper class writing 3D images to file ... + * + */ + class ImageWriter + { + typedef ::itk::Image ITKMaskImageType; + typedef ITKMaskImageType::Pointer ITKImageTypePointer; + typedef ::itk::ImageFileWriter WriterType; + + private: + FileNameString _fileName; + ITKImageTypePointer _itkImage; + + + public: + ImageWriter(FileNameString aFileName, ITKImageTypePointer aITKImage); + + /*! @brief Write itk image to file + @return Return true if successful. + @exception InvalidParameterException thrown if itk exception by writing the image + */ + bool writeFile(); + + + + }; + }//end namespace itk + }//end namespace io +}//end namespace rttb + + +#endif diff --git a/code/io/mask/CMakeLists.txt b/code/io/mask/CMakeLists.txt deleted file mode 100644 index 403a7de..0000000 --- a/code/io/mask/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -RTTB_CREATE_MODULE(RTTBMaskIO DEPENDS RTTBCore PACKAGE_DEPENDS Boost ITK) \ No newline at end of file diff --git a/code/io/mask/files.cmake b/code/io/mask/files.cmake deleted file mode 100644 index e1e9d23..0000000 --- a/code/io/mask/files.cmake +++ /dev/null @@ -1,23 +0,0 @@ -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/masks/CMakeLists.txt b/code/masks/CMakeLists.txt index b3802cc..f2c6473 100644 --- a/code/masks/CMakeLists.txt +++ b/code/masks/CMakeLists.txt @@ -1 +1,15 @@ -RTTB_CREATE_MODULE(RTTBMasks DEPENDS RTTBCore PACKAGE_DEPENDS DCMTK) \ No newline at end of file +MESSAGE (STATUS "processing RTToolbox mask") + +OPTION(BUILD_MASK_BOOST "Determine if the boost mask voxelization will be supported." ON) +IF(BUILD_MASK_BOOST) + ADD_SUBDIRECTORY(boost) +ENDIF(BUILD_MASK_BOOST) + +OPTION(BUILD_OTBMASK "Determine if the rttb OTB mask voxalization will be supported." ON) +IF(BUILD_OTBMASK) + ADD_SUBDIRECTORY(legacy) +ENDIF(BUILD_OTBMASK) + +RTTB_CREATE_MODULE(RTTBMasks DEPENDS RTTBCore PACKAGE_DEPENDS DCMTK) + + diff --git a/code/masks/boost/CMakeLists.txt b/code/masks/boost/CMakeLists.txt new file mode 100644 index 0000000..a5a057b --- /dev/null +++ b/code/masks/boost/CMakeLists.txt @@ -0,0 +1 @@ +RTTB_CREATE_MODULE(RTTBBoostMask DEPENDS RTTBCore RTTBMasks PACKAGE_DEPENDS Boost ITK) \ No newline at end of file diff --git a/code/masks/boost/files.cmake b/code/masks/boost/files.cmake new file mode 100644 index 0000000..616ac4e --- /dev/null +++ b/code/masks/boost/files.cmake @@ -0,0 +1,9 @@ +SET(CPP_FILES + rttbBoostMask.cpp + rttbBoostMaskAccessor.cpp +) + +SET(H_FILES + rttbBoostMask.h + rttbBoostMaskAccessor.h +) diff --git a/code/io/mask/rttbBoostMask.cpp b/code/masks/boost/rttbBoostMask.cpp similarity index 59% rename from code/io/mask/rttbBoostMask.cpp rename to code/masks/boost/rttbBoostMask.cpp index 31963d1..58be82e 100644 --- a/code/io/mask/rttbBoostMask.cpp +++ b/code/masks/boost/rttbBoostMask.cpp @@ -1,269 +1,300 @@ #include #include #include #include #include #include #include #include #include "rttbBoostMask.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" namespace rttb { - namespace io + namespace masks { - namespace mask + namespace boost { BoostMask::BoostMask(BoostMask::GeometricInfoPointer aDoseGeoInfo, BoostMask::StructPointer aStructure) - :_geometricInfo(aDoseGeoInfo), _structure(aStructure), _voxelInStructure(boost::make_shared()){ + :_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); + std::vector intersectionSlicePolygonsVector;//store the polygons of intersection slice of each index z + + //For each dose slice, get intersection structure slice and the contours on the structure slice + for(unsigned int indexZ=0; indexZ< _geometricInfo->getNumSlices(); indexZ++){ + BoostMask::BoostRingVector boostPolygons = getIntersectionSlicePolygons(indexZ); + BoostMask::BoostRingVector::iterator it; + for(it = boostPolygons.begin(); it != boostPolygons.end(); ++it){ + ::boost::geometry::correct(*it); + } + intersectionSlicePolygonsVector.push_back(boostPolygons); + } + + /* Use simple nearest neighbour interpolation (NNI) if dose and structure has different z spacing: + If dose slice (indexZ) has no intersection with structure slice, but the last and the next do, that means the dose + slice lies between two structure slices -> use the last slice intersection contours for this slice + */ + for(unsigned int indexZ=1; indexZ<_geometricInfo->getNumSlices()-1; indexZ++){ + if(intersectionSlicePolygonsVector.at(indexZ).size() == 0 && intersectionSlicePolygonsVector.at(indexZ-1).size() > 0 + && intersectionSlicePolygonsVector.at(indexZ+1).size() > 0) + intersectionSlicePolygonsVector.at(indexZ) = intersectionSlicePolygonsVector.at(indexZ-1); + } + + for(unsigned int indexZ=0; indexZ< _geometricInfo->getNumSlices(); indexZ++){ + BoostMask::BoostRingVector intersectionSlicePolygons = intersectionSlicePolygonsVector.at(indexZ); + + //Get bounding box of this dose slice + VoxelIndexVector voxelList = getBoundingBox(indexZ, intersectionSlicePolygons); rttb::VoxelGridIndex3D gridIndex3D0 = voxelList.at(0); rttb::VoxelGridIndex3D gridIndex3D1 = voxelList.at(1); - for(unsigned int indexX = gridIndex3D0[0] ; indexX <= gridIndex3D1[0]; indexX ++ ){ for(unsigned int indexY = gridIndex3D0[1]; indexY <= gridIndex3D1[1]; indexY ++){ rttb::VoxelGridIndex3D currentIndex; currentIndex[0] = indexX; currentIndex[1] = indexY; - currentIndex[2] = i; + currentIndex[2] = indexZ; rttb::VoxelGridID gridID; _geometricInfo->convert(currentIndex, gridID); - std::deque polygons = getIntersections(currentIndex); + //Get intersection polygons of the dose voxel and the structure + std::deque polygons = getIntersections(currentIndex, intersectionSlicePolygons); + + //Calc areas of all intersection polygons double intersectionArea = calcArea(polygons); double voxelSize = _geometricInfo->getSpacing()[0] * _geometricInfo->getSpacing()[1]; if(intersectionArea > 0) { 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); + BoostMask::BoostRingVector boostPolygons = getIntersectionSlicePolygons(currentIndex[2]); - 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); + + BoostRingVector::const_iterator it; + for(it = intersectionSlicePolygons.begin(); it != intersectionSlicePolygons.end(); ++it){ + ::boost::geometry::model::box box; + ::boost::geometry::envelope(*it, box); BoostPoint2D minPoint = box.min_corner(); BoostPoint2D maxPoint = box.max_corner(); - if(i==0){ + if(it == intersectionSlicePolygons.begin()){ xMin = minPoint.x(); yMin = minPoint.y(); xMax = maxPoint.x(); yMax = maxPoint.y(); } xMin = std::min(xMin, minPoint.x()); yMin = std::min(yMin, minPoint.y()); xMax = std::max(xMax, maxPoint.x()); yMax = std::max(yMax, maxPoint.y()); } rttb::WorldCoordinate3D nullWorldCoord; _geometricInfo->indexToWorldCoordinate(VoxelGridIndex3D(0,0,0),nullWorldCoord); rttb::WorldCoordinate3D minWorldCoord(xMin, yMin, nullWorldCoord.z()); rttb::WorldCoordinate3D maxWorldCoord(xMax, yMax, nullWorldCoord.z()); rttb::VoxelGridIndex3D index0; rttb::VoxelGridIndex3D index1; _geometricInfo->worldCoordinateToIndex(minWorldCoord, index0); _geometricInfo->worldCoordinateToIndex(maxWorldCoord, index1); VoxelIndexVector voxelList; voxelList.push_back(index0); voxelList.push_back(index1); return voxelList; - } + } /*Get intersection polygons of the contour and a voxel polygon*/ - BoostMask::BoostPolygonDeque BoostMask::getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D){ + BoostMask::BoostPolygonDeque BoostMask::getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D, const BoostRingVector& intersectionSlicePolygons){ BoostMask::BoostPolygonDeque polygonDeque; BoostRing2D voxelPolygon = get2DContour(aVoxelIndex3D); - boost::geometry::correct(voxelPolygon); + ::boost::geometry::correct(voxelPolygon); - BoostMask::BoostRingVector contourVector = getIntersectionSlicePolygons(aVoxelIndex3D); - for(unsigned int i=0; i aPolygonDeque){ + double BoostMask::calcArea(const BoostPolygonDeque& aPolygonDeque){ double area = 0; - for(unsigned int i=0; iconvert(aMaskVoxel.getVoxelGridID(), gridIndex3D); return gridIndex3D; } BoostMask::MaskVoxelListPointer BoostMask::getRelevantVoxelVector(){ 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){ + rttb::PolygonSequenceType::iterator it; + for(it = polygonSequence.begin(); it != polygonSequence.end(); ++it){ + PolygonType rttbPolygon = *it; + if(!rttbPolygon.empty()){ double polygonZCoor = rttbPolygon.at(0)[2]; rttb::WorldCoordinate3D polygonPoint(0,0, polygonZCoor); rttb::VoxelGridIndex3D polygonPointIndex3D; _geometricInfo->worldCoordinateToIndex(polygonPoint, polygonPointIndex3D); //if the z - if(aVoxelGrid3D[2] == polygonPointIndex3D[2]){ + if(aVoxelGridIndexZ == 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); + ::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); + ::boost::geometry::append(polygon, point2); BoostPoint2D point3(rttbPoint[0]+xSpacing, rttbPoint[1]+ySpacing); - boost::geometry::append(polygon, point3); + ::boost::geometry::append(polygon, point3); BoostPoint2D point4(rttbPoint[0], rttbPoint[1]+ySpacing); - boost::geometry::append(polygon, point4); + ::boost::geometry::append(polygon, point4); - boost::geometry::append(polygon, point1); + ::boost::geometry::append(polygon, point1); return polygon; } } } } \ No newline at end of file diff --git a/code/io/mask/rttbBoostMask.h b/code/masks/boost/rttbBoostMask.h similarity index 59% rename from code/io/mask/rttbBoostMask.h rename to code/masks/boost/rttbBoostMask.h index 9da0da7..d8cfa85 100644 --- a/code/io/mask/rttbBoostMask.h +++ b/code/masks/boost/rttbBoostMask.h @@ -1,116 +1,136 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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 +#ifndef __BOOST_MASK_H +#define __BOOST_MASK_H #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbGeometricInfo.h" #include "rttbMaskVoxel.h" #include "rttbMaskAccessorInterface.h" #include #include #include #include +#include namespace rttb { - namespace io + namespace masks { - namespace mask + namespace boost { - class BoostMask{ + class BoostMask + { public: - typedef boost::shared_ptr GeometricInfoPointer; + 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 ::boost::geometry::model::d2::point_xy BoostPoint2D; + typedef ::boost::geometry::model::polygon<::boost::geometry::model::d2::point_xy > BoostPolygon2D; + typedef ::boost::geometry::model::ring<::boost::geometry::model::d2::point_xy > BoostRing2D; typedef 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 the min/max voxel index of the bounding box of the polygon in the slice with sliceNumber + * @param sliceNumber slice number between 0 and _geometricInfo->getNumSlices() + * @param intersectionSlicePolygons Get the polygons intersecting the slice + * @exception InvalidParameterException thrown if sliceNumber < 0 or sliceNumber >= _geometricInfo->getNumSlices() + * @return Return the 4 voxel index of the bounding box + */ + VoxelIndexVector getBoundingBox(unsigned int sliceNumber, const BoostRingVector& intersectionSlicePolygons); - /*! @brief Get intersection polygons of the contour and a voxel polygon*/ - BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D); + /*! @brief Get intersection polygons of the contour and a voxel polygon + * @param aVoxelIndex3D The 3d grid index of the voxel + * @param intersectionSlicePolygons The polygons of the slice intersecting the voxel + * @return Return all intersetion polygons of the structure and the voxel + */ + BoostPolygonDeque getIntersections(const rttb::VoxelGridIndex3D& aVoxelIndex3D, const BoostRingVector& intersectionSlicePolygons); - /*! @brief Calculate the intersection area*/ - double calcArea(BoostPolygonDeque aPolygonDeque); + /*! @brief Calculate the area of all polygons + * @param aPolygonDeque The deque of polygons + * @return Return the area of all polygons + */ + double calcArea(const BoostPolygonDeque& aPolygonDeque); - /*! @brief Get grid index of a mask voxel*/ + /*! @brief Get grid index of a mask voxel + * @param aMaskVoxel A mask voxel + * @return Return the 3d grid index of the mask voxel + */ VoxelGridIndex3D getGridIndex3D(const core::MaskVoxel& aMaskVoxel); /*! @brief Convert RTTB polygon to boost polygon*/ BoostRing2D convert(const rttb::PolygonType& aRTTBPolygon); - /*! @brief Get the intersection slice of the voxel, return the polygons in the slice*/ - BoostRingVector getIntersectionSlicePolygons(const rttb::VoxelGridIndex3D& aVoxelGrid3D); + /*! @brief Get the intersection slice of the voxel, return the polygons in the slice + * @param aVoxelGridIndexZ The z grid index (slice number) of the voxel + * @return Return the structure polygons intersecting the slice + */ + BoostRingVector getIntersectionSlicePolygons(const rttb::GridIndexType aVoxelGridIndexZ); /*! @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/masks/boost/rttbBoostMaskAccessor.cpp similarity index 93% copy from code/io/mask/rttbBoostMaskAccessor.cpp copy to code/masks/boost/rttbBoostMaskAccessor.cpp index e555263..f8cd931 100644 --- a/code/io/mask/rttbBoostMaskAccessor.cpp +++ b/code/masks/boost/rttbBoostMaskAccessor.cpp @@ -1,162 +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 masks { - namespace mask + namespace boost { 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; + ::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/masks/boost/rttbBoostMaskAccessor.h similarity index 94% rename from code/io/mask/rttbBoostMaskAccessor.h rename to code/masks/boost/rttbBoostMaskAccessor.h index 85a4c4a..777dab2 100644 --- a/code/io/mask/rttbBoostMaskAccessor.h +++ b/code/masks/boost/rttbBoostMaskAccessor.h @@ -1,119 +1,119 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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 masks { - namespace mask + namespace boost { /*! @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; + 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/files.cmake b/code/masks/files.cmake index 14215d6..0cc43df 100644 --- a/code/masks/files.cmake +++ b/code/masks/files.cmake @@ -1,30 +1,7 @@ -SET(CPP_FILES - rttbOTBMaskAccessor.cpp - rttbMask.cpp - DoseVoxel_LEGACY.cpp - DoseIteratorInterface_LEGACY.cpp - DoseIterator_LEGACY.cpp - rttbContour_LEGACY.cpp - rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp - rttbPolygonInfo_LEGACY.cpp - rttbSelfIntersectingStructureException.cpp - rttbStructure_LEGACY.cpp +SET(CPP_FILES rttbGenericMutableMaskAccessor.cpp - ) +) -SET(H_FILES - rttbMaskType_LEGACY.h - rttbMask.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 +SET(H_FILES rttbGenericMutableMaskAccessor.h ) diff --git a/code/masks/legacy/CMakeLists.txt b/code/masks/legacy/CMakeLists.txt new file mode 100644 index 0000000..e8220b1 --- /dev/null +++ b/code/masks/legacy/CMakeLists.txt @@ -0,0 +1 @@ +RTTB_CREATE_MODULE(RTTBOTBMask DEPENDS RTTBCore RTTBMasks PACKAGE_DEPENDS DCMTK) \ No newline at end of file diff --git a/code/masks/DoseIteratorInterface_LEGACY.cpp b/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp similarity index 85% rename from code/masks/DoseIteratorInterface_LEGACY.cpp rename to code/masks/legacy/DoseIteratorInterface_LEGACY.cpp index 8b52e02..c8bb653 100644 --- a/code/masks/DoseIteratorInterface_LEGACY.cpp +++ b/code/masks/legacy/DoseIteratorInterface_LEGACY.cpp @@ -1,84 +1,84 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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) */ #include "DoseIteratorInterface_LEGACY.h" using namespace std; #include #include #include #include #include namespace rttb{ namespace masks{ namespace legacy{ IDType DoseIteratorInterface::getDoseUID(){ boost::uuids::uuid id; boost::uuids::random_generator generator; id=generator(); std::stringstream ss; ss << id; _doseUID=ss.str(); return _doseUID; } IDType DoseIteratorInterface::getPatientUID(){ boost::uuids::uuid id; boost::uuids::random_generator generator; id=generator(); std::stringstream ss; ss << id; _patientUID=ss.str(); return _patientUID; } int DoseIteratorInterface::size(){ this->start(); int size=0; while(this->hasNextVoxel()){ this->next(); size++; } return size; } } } } diff --git a/code/masks/DoseIteratorInterface_LEGACY.h b/code/masks/legacy/DoseIteratorInterface_LEGACY.h similarity index 91% rename from code/masks/DoseIteratorInterface_LEGACY.h rename to code/masks/legacy/DoseIteratorInterface_LEGACY.h index 17d9498..39da56a 100644 --- a/code/masks/DoseIteratorInterface_LEGACY.h +++ b/code/masks/legacy/DoseIteratorInterface_LEGACY.h @@ -1,115 +1,115 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __DOSE_ITERATOR_INTERFACE_H #define __DOSE_ITERATOR_INTERFACE_H #include #include #include #include "DoseVoxel_LEGACY.h" #include "rttbPhysicalInfo.h" namespace rttb{ namespace masks { namespace legacy { /*! @class DoseIteratorInterface * @brief This class represents the dose iterator interface. */ class DoseIteratorInterface: public core::PhysicalInfo { protected: /*! @brief Dose voxel index (x,y,z)*/ VoxelGridIndex3D _doseIndex; /*! @brief Dose UID*/ IDType _doseUID; /*! @brief Patient UID*/ IDType _patientUID; /*! @brief Current DoseVoxel*/ DoseVoxel _currentVoxel; /*! @brief Read dose and structure information * It will be called in constructor or if dose or structure is resetted */ virtual bool begin() = 0; public: /*! @brief Set the position before the first index. It must be called before hasNextVoxel() and next()! */ virtual void start()=0; /*! @brief Test if next voxel exists * @pre start() must be called before it is called! */ virtual bool hasNextVoxel() const = 0; /*! @brief Return dose value (in Gy) of the next index. After next() is called, current index of this iterator is at the next index. * @pre hasNextVoxel() must =true before it is called! */ virtual DoseTypeGy next() = 0; //RALF: man sollte zumindest so ein interface auch einbauen um einen viruellen Call zu sparen //virtual bool next(DoseTypeGy& nextValue) = 0; /*! @brief Return volume of one voxel (in cm3)*/ virtual DoseVoxelVolumeType getDeltaV() const = 0; /*! @brief Return geometric information*/ virtual core::GeometricInfo getGeometricInfo() const=0; /*! @brief If masked dose iterator, return the voxel proportion inside a given structure, value 0~1; Otherwise, 1*/ virtual double getCurrentVoxelProportion() const=0; /*! @brief Get dose uid. If there exists uuid for the dose, you should rewrite the method; otherwise, a uid will be * randomly generated using boost::uuid library. */ IDType getDoseUID(); /*! @brief Get patient uid. If there exists patient uuid for the dose, you should rewrite the method; otherwise, a uid will be * randomly generated using boost::uuid library. */ IDType getPatientUID(); /*! @brief Return the current RTVoxel Object*/ virtual const DoseVoxel& getCurrentRTVoxel()=0; /*! @brief Return the size of the dose iterator*/ virtual int size(); }; } } } #endif diff --git a/code/masks/DoseIterator_LEGACY.cpp b/code/masks/legacy/DoseIterator_LEGACY.cpp similarity index 93% rename from code/masks/DoseIterator_LEGACY.cpp rename to code/masks/legacy/DoseIterator_LEGACY.cpp index e4532b5..b774e91 100644 --- a/code/masks/DoseIterator_LEGACY.cpp +++ b/code/masks/legacy/DoseIterator_LEGACY.cpp @@ -1,163 +1,163 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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) */ #include "DoseIterator_LEGACY.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" using namespace std; namespace rttb{ namespace masks { namespace legacy { DoseIterator::~DoseIterator() { } DoseIterator::DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, DRTDoseIOD* maskIOD): doseData (aGeoInfo.getNumberOfVoxels(), 0){ this->count=-1; _dose = doseIOD; _mask = maskIOD; setDoseInfo(aGeoInfo); } void DoseIterator::start() { this->count=-1; } bool DoseIterator::setDoseInfo(core::GeometricInfo& aGeoInfo){ /* get Columns (0028,0011) of the dicom dose _dose*/ column = aGeoInfo.getNumColumns(); /*! get Rows (0028,0010) of the dicom dose _dose*/ row = aGeoInfo.getNumRows(); /* get NumberOfFrames (0028,0008) of the dicom dose _dose*/ numberOfFrames=aGeoInfo.getNumSlices(); //std::cout << "numberOfFrames: "<< numberOfFrames << std::endl; if(column==0 || row==0 || numberOfFrames==0){ throw rttb::core::InvalidDoseException("Empty dicom dose!"); } /* get DoseGridScaling (3004,000e) of the dicom dose _dose*/ OFString doseGridScalingStr; this->_dose->getDoseGridScaling(doseGridScalingStr); this->doseGridScaling=1; imagePositionPatient = aGeoInfo.getImagePositionPatient(); imageOrientationRow = aGeoInfo.getImageOrientationRow(); imageOrientationColumn = aGeoInfo.getImageOrientationColumn(); /* get PixelSpacing (0028,0030) of the dicom dose _dose*/ pixelSpacingRow=aGeoInfo.getPixelSpacingRow(); pixelSpacingColumn=aGeoInfo.getPixelSpacingColumn(); /* get SliceThickness (0018,0050) of the dicom dose _dose*/ sliceThickness=aGeoInfo.getSliceThickness(); return true; } DoseTypeGy DoseIterator::next(){ int size=this->pixelDataIndexInStructure.size(); if(count<(size-1)){ count++; DoseTypeGy dose; int i=pixelDataIndexInStructure[count]; dose=doseData.at(i)*this->doseGridScaling; return dose; } else{ throw core::IndexOutOfBoundsException("hasNextVoxel()==false!"); } } bool DoseIterator::hasNextVoxel() const{ int size=this->pixelDataIndexInStructure.size(); if(count<(size-1)){ return true; } else return false; } DoseVoxelVolumeType DoseIterator::getDeltaV() const{ return this->pixelSpacingColumn*this->pixelSpacingRow*this->sliceThickness/1000; } core::GeometricInfo DoseIterator::getGeometricInfo() const{ core::GeometricInfo ginfo; ginfo.setNumColumns(this->column); ginfo.setNumRows(this->row); OrientationMatrix orientation(0); orientation(0,0) = this->imageOrientationRow.x(); orientation(1,0) = this->imageOrientationRow.y(); orientation(2,0) = this->imageOrientationRow.z(); orientation(0,1) = this->imageOrientationColumn.x(); orientation(1,1) = this->imageOrientationColumn.y(); orientation(2,1) = this->imageOrientationColumn.z(); WorldCoordinate3D ortho = this->imageOrientationRow.cross(this->imageOrientationColumn); orientation(0,2) = ortho.x(); orientation(1,2) = ortho.y(); orientation(2,2) = ortho.z(); ginfo.setOrientationMatrix(orientation); ginfo.setImagePositionPatient(this->imagePositionPatient); ginfo.setNumSlices(this->numberOfFrames); ginfo.setPixelSpacingColumn(this->pixelSpacingColumn); ginfo.setPixelSpacingRow(this->pixelSpacingRow); ginfo.setSliceThickness(this->sliceThickness); return ginfo; } double DoseIterator::getCurrentVoxelProportion() const{ return 1; } const DoseVoxel& DoseIterator::getCurrentRTVoxel(){ return _currentVoxel; } } } } diff --git a/code/masks/DoseIterator_LEGACY.h b/code/masks/legacy/DoseIterator_LEGACY.h similarity index 93% rename from code/masks/DoseIterator_LEGACY.h rename to code/masks/legacy/DoseIterator_LEGACY.h index 82f976a..1fef018 100644 --- a/code/masks/DoseIterator_LEGACY.h +++ b/code/masks/legacy/DoseIterator_LEGACY.h @@ -1,156 +1,156 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __DICOM_DOSE_ITERATOR_USE_MASK_H #define __DICOM_DOSE_ITERATOR_USE_MASK_H #include #include #include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmrt/drtdose.h" #include "DoseIteratorInterface_LEGACY.h" #include "DoseVoxel_LEGACY.h" #include "rttbGeometricInfo.h" namespace rttb{ namespace masks{ namespace legacy { /*! @class DoseIterator * @brief This class represents the iterator of the dose voxels in a DRTDoseIOD Object within the >0 region of a image mask */ class DoseIterator: public DoseIteratorInterface { private: /*! DICOM-RT dose pointer*/ DRTDoseIOD* _dose; /*! DICOM-RT mask pointer. It must have the same image properties as _dose. The structure is masked with 1.*/ DRTDoseIOD* _mask; /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector doseData; /*! Columns (0028,0011) of the dicom dose _dose*/ Uint16 column; /*! Rows (0028,0010) of the dicom dose _dose*/ Uint16 row; /*! NumberOfFrames (0028,0008) of the dicom dose _dose*/ Uint16 numberOfFrames; /*! DoseGridScaling (3004,000e) of the dicom dose _dose*/ double doseGridScaling; /*! ImagePositionPatient (0020,0032) of the dicom dose _dose*/ WorldCoordinate3D imagePositionPatient; /*! ImageOrientationPatient (0020,0037) of the dicom dose _dose*/ ImageOrientation imageOrientationRow; ImageOrientation imageOrientationColumn; /*! PixelSpacing (0028,0030) of the dicom dose _dose*/ double pixelSpacingRow; double pixelSpacingColumn; /*! SliceThickness (0018,0050) of the dicom dose _dose*/ double sliceThickness; /*! The current position in pixelDataIndexInStructure*/ int count; /*! The vector stores all indices with pixel data >0 in the mask*/ std::vector pixelDataIndexInStructure; /*! @brief Get information from dose distribution:column, row, numberOfFramesdose, * GridScaling, imageOrientation, pixelSpacing, getSliceThickness() and absolute dose value in each voxel */ bool setDoseInfo(core::GeometricInfo& aGeoInfo); protected: /*! @brief Traverse dose distribution, get the dose voxels in the structure: doseVoxelInStructure. * It will be called in constructor or if structure is resetted. * @exception RTTBNullPointerException Thrown if _dose or _structure is NULL * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 * @exception RTTBDcmrtException Throw if dcmrt error */ bool begin() { start(); return true;}; public: /*! @brief Destructor*/ virtual ~DoseIterator(); /*! @brief Standard constructor * @exception RTTBNullPointerException Thrown if _dose or _mask is NULL * @exception RTTBInvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 * @exception RTTBDcmrtException Throw if dcmrt error */ DoseIterator(core::GeometricInfo& aGeoInfo, DRTDoseIOD* doseIOD, DRTDoseIOD* maskIOD); /*! @brief Set the position before the first index. * It must be called before hasNextVoxel() and next()! */ void start(); /*! @brief Test if next voxel existiert * @pre start() must be called before it is called! */ bool hasNextVoxel() const; /*! @brief Return dose value (in Gy) of the next index * @pre hasNextVoxel() must =true before it is called! * @exception RTTBIndexOutOfBoundsException Thrown if hasNextVoxel()==false */ DoseTypeGy next(); /*! @brief Volume of one voxel (in cm3)*/ DoseVoxelVolumeType getDeltaV() const; /*! @brief Return geometric information*/ core::GeometricInfo getGeometricInfo() const; /*! @brief Return 1? To be modified...*/ double getCurrentVoxelProportion() const; /*! @brief Return the current RTVoxel Object*/ const DoseVoxel& getCurrentRTVoxel(); }; } } } #endif diff --git a/code/masks/DoseVoxel_LEGACY.cpp b/code/masks/legacy/DoseVoxel_LEGACY.cpp similarity index 96% rename from code/masks/DoseVoxel_LEGACY.cpp rename to code/masks/legacy/DoseVoxel_LEGACY.cpp index 628255e..1f9ef85 100644 --- a/code/masks/DoseVoxel_LEGACY.cpp +++ b/code/masks/legacy/DoseVoxel_LEGACY.cpp @@ -1,867 +1,867 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include "DoseVoxel_LEGACY.h" #include "rttbInvalidParameterException.h" #include "rttbContour_LEGACY.h" using namespace std; namespace rttb{ namespace masks{ namespace legacy{ DoseVoxel::DoseVoxel(){ //default 1 _proportionInStr=1; } DoseVoxel::DoseVoxel(const VoxelGridIndex3D &aDoseIndex, const core::GeometricInfo* aGeometricInfo){ if(aDoseIndex(0)<0 || aDoseIndex(1)<0 || aDoseIndex(2)<0){ std::cout << aDoseIndex.toString()<getPixelSpacingRow()<=0 || aGeometricInfo->getPixelSpacingColumn()<=0 || aGeometricInfo->getSliceThickness() <=0) throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); else{ _voxelIndex3D.x=aDoseIndex(0); _voxelIndex3D.y=aDoseIndex(1); _voxelIndex3D.z=aDoseIndex(2); _geoInfo=aGeometricInfo; WorldCoordinate3D currentWorld(0); aGeometricInfo->indexToWorldCoordinate(aDoseIndex,currentWorld); _x=currentWorld(0); _y=currentWorld(1); _z=currentWorld(2); //std::cout << "zIndex:"<getPixelSpacingRow(); _deltaY=aGeometricInfo->getPixelSpacingColumn(); _deltaZ=aGeometricInfo->getSliceThickness(); } //default 1 _proportionInStr=1; } DoseVoxel::DoseVoxel(const LegacyDoseVoxelIndex3D &aDoseIndex, const rttb::core::GeometricInfo* aGeometricInfo){ if(aDoseIndex.x<0 || aDoseIndex.y<0 || aDoseIndex.z<0){ std::cout << aDoseIndex.toString()<getPixelSpacingRow()<=0 || aGeometricInfo->getPixelSpacingColumn()<=0 || aGeometricInfo->getSliceThickness() <=0) throw rttb::core::InvalidParameterException("Pixel spacing and slice thickness must not be zero! "); else{ _voxelIndex3D=aDoseIndex; _geoInfo=aGeometricInfo; // old //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.x; //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*(aDoseIndex.x)+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*(aDoseIndex.y)+aGeometricInfo->imagePositionPatient.y; //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z); //Martina WorldCoordinate3D currentWorld(0); VoxelGridIndex3D currentIndex(aDoseIndex.x,aDoseIndex.y,aDoseIndex.z); aGeometricInfo->indexToWorldCoordinate(currentIndex,currentWorld); _x=currentWorld(0); _y=currentWorld(1); _z=currentWorld(2); //Lanlan //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; //std::cout << "zIndex:"<getPixelSpacingRow(); _deltaY=aGeometricInfo->getPixelSpacingColumn(); _deltaZ=aGeometricInfo->getSliceThickness(); } //default 1 _proportionInStr=1; } bool DoseVoxel::operator==(const DoseVoxel& doseVoxel) const{ return (_x==doseVoxel._x)&& (_y==doseVoxel._y)&& (_z==doseVoxel._z) && (_deltaX==doseVoxel._deltaX) && (_deltaY==doseVoxel._deltaY)&& (_deltaZ==_deltaZ); } bool DoseVoxel::operator<(const DoseVoxel& doseVoxel) const{ WorldCoordinate3D leftP=doseVoxel.getLeftUpperPoint(); WorldCoordinate3D deltaP=doseVoxel.getDelta(); if(_zindexToWorldCoordinate(aDoseIndex , aWorldCoordinate)){ _x = aWorldCoordinate(0); _y = aWorldCoordinate(1); _z = aWorldCoordinate(2); } else{ //something went wrong! } /* //Martina _x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(0); _y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*(aDoseIndex(0)-0.5)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*(aDoseIndex(1)-0.5)+aGeometricInfo->getImagePositionPatient()(1); _z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2)-0.5); */ //Lanlan //_x=aGeometricInfo->getImageOrientationRow()(0)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(0)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(0)-0.5*aGeometricInfo->getPixelSpacingRow(); //_y=aGeometricInfo->getImageOrientationRow()(1)*aGeometricInfo->getPixelSpacingRow()*aDoseIndex(0)+aGeometricInfo->getImageOrientationColumn()(1)*aGeometricInfo->getPixelSpacingColumn()*aDoseIndex(1)+aGeometricInfo->getImagePositionPatient()(1)-0.5*aGeometricInfo->getPixelSpacingColumn(); //_z=aGeometricInfo->getImagePositionPatient()(2) + aGeometricInfo->getSliceThickness() *(aDoseIndex(2))-0.5*aGeometricInfo->getSliceThickness(); //std::cout << "zIndex:"<getPixelSpacingRow(); _deltaY=aGeometricInfo->getPixelSpacingColumn(); _deltaZ=aGeometricInfo->getSliceThickness(); } //default 1 _proportionInStr=1; } void DoseVoxel::setDoseVoxel(const LegacyDoseVoxelIndex3D &aDoseIndex, const rttb::core::GeometricInfo* aGeometricInfo) { if(aDoseIndex.x<0 || aDoseIndex.y<0 || aDoseIndex.z<0) throw rttb::core::InvalidParameterException("Invalid dose index!"); else{ _voxelIndex3D=aDoseIndex; _geoInfo=aGeometricInfo; //Martina WorldCoordinate3D aWorldCoordinate(0); VoxelGridIndex3D currentIndex(aDoseIndex.x,aDoseIndex.y,aDoseIndex.z); if(aGeometricInfo->indexToWorldCoordinate(currentIndex , aWorldCoordinate)){ _x = aWorldCoordinate(0); _y = aWorldCoordinate(1); _z = aWorldCoordinate(2); } //Lanlan //_x=aGeometricInfo->imageOrientationRow.x*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.x*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.x-0.5*aGeometricInfo->pixelSpacingRow; //_y=aGeometricInfo->imageOrientationRow.y*aGeometricInfo->pixelSpacingRow*aDoseIndex.x+aGeometricInfo->imageOrientationColumn.y*aGeometricInfo->pixelSpacingColumn*aDoseIndex.y+aGeometricInfo->imagePositionPatient.y-0.5*aGeometricInfo->pixelSpacingColumn; //_z=aGeometricInfo->imagePositionPatient.z + aGeometricInfo->sliceThickness *(aDoseIndex.z)-0.5*aGeometricInfo->sliceThickness; //std::cout << "zIndex:"<getPixelSpacingRow(); _deltaY=aGeometricInfo->getPixelSpacingColumn(); _deltaZ=aGeometricInfo->getSliceThickness(); } //default 1 _proportionInStr=1; } /*! @brief Set dose voxel with the left upper point and delta * */ void DoseVoxel::setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta){ _x=aWorldCoordinate(0); _y=aWorldCoordinate(1); _z=aWorldCoordinate(2); _deltaX=aVoxelDelta(0); _deltaY=aVoxelDelta(1); _deltaZ=aVoxelDelta(2); } void DoseVoxel::setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, LegacyWorldCoordinate3D aVoxelDelta){ _x=aWorldCoordinate.x; _y=aWorldCoordinate.y; _z=aWorldCoordinate.z; _deltaX=aVoxelDelta.x; _deltaY=aVoxelDelta.y; _deltaZ=aVoxelDelta.z; } /*! @brief Tests if a point is inside the voxel * */ bool DoseVoxel::pointInVoxel(const WorldCoordinate3D& aPoint) const { if ((aPoint(0) <=(_x+_deltaX) && aPoint(0) >=_x ) && (aPoint(1) <=(_y+_deltaY) && aPoint(1) >=_y ) && (aPoint(2) <=(_z+_deltaZ) && aPoint(2) >=_z )) return true; else return false; } bool DoseVoxel::pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const { if ((aPoint.x <=(_x+_deltaX) && aPoint.x >=_x ) && (aPoint.y <=(_y+_deltaY) && aPoint.y >=_y ) && (aPoint.z <=(_z+_deltaZ) && aPoint.z >=_z )) return true; else return false; } /*! @brief Calculates how many relative volume of the voxel inside the structure. * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error * @pre aRTStructure must not be NULL */ double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure) const{ //bool voxelInStr=false; const PolygonSequenceType& strVector=aRTStructure.getStructureVector(); int size=strVector.size(); if(size==0){ std::cerr << "Error: structure vector of aRTStructure is empty! "< roi=strVector[i]; vector roiNext; if(i==size-1) roiNext=strVector[0]; else roiNext=strVector[i+1]; WorldCoordinate3D* p1=roi[0]; WorldCoordinate3D* p2=roiNext[0]; if(_z>= p1->z && _zz) roiNumber[0]=i; else if(_z+_deltaZ/5 >= p1->z && _z+_deltaZ/5 z) roiNumber[1]=i; else if(_z+2*_deltaZ/5 >= p1->z && _z+2*_deltaZ/5 z) roiNumber[2]=i; else if(_z+3*_deltaZ/5 >= p1->z && _z+3*_deltaZ/5 z) roiNumber[3]=i; else if(_z+4*_deltaZ/5 >= p1->z && _z+4*_deltaZ/5 z) roiNumber[4]=i; } //get 5^3=125 points from the voxel for(int i=0; i<5; i++){ //std::cout <<"------------"< voxelPoints; //std::cout << "----------------------------Voxel Points: "<_x<x=(_x+k*_deltaX/5); p->y=(_y+j*_deltaY/5); p->z=(_z+i*_deltaZ/5); //std::cout << "("<x<<","<y<<","<z< roi=strVector[roiNumber[i]]; if(this->pointInPolygon(roi,voxelPoint)) voxelPointInStructure++; //} //~ vector::iterator it; for(it=voxelPoints.begin();it!=voxelPoints.end();it++){ delete (*it); } }*/ /*PolygonType roi=strVector[i]; if(roi.size()==0){ std::cerr << "Error: corresponding roi of aRTStructure is empty! "<pointInPolygon(roi,p)) voxelPointInStructure++;*/ //return voxelPointInStructure/125; //return voxelPointInStructure/1; std::vector sliceV=this->getZIntersectPolygonIndexVector(aRTStructure); for(int i=0;i0: voxel in structure, =0: voxel not in structure, <0: error * @pre aRTStructure must not be NULL */ double DoseVoxel::voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const{ const LegacyPolygonSequenceType& strVector=aRTStructure.getLegacyStructureVector(); int size=strVector.size(); if(size==0){ std::cerr << "Error: structure vector of aRTStructure is empty! "<size){ std::cerr << "Error: sliceNumber must between -1 and "<getArea(); }*/ //if the next contour not in the same slice, break if(isize){ std::cerr << "Error: polygonIndex must between -1 and "<getArea(); }*/ //std::cout << voxelPointInStructure/4.0<= last polygon //Reduce copying of values, since boost_vector constructors are expensive //Anmerkung fuer Lanlan zwecks mergen : Eine Kontur, die direkt in einem slice liegt sollte nicht in beiden angrenzenden Slices voxelisiert werden. if(_z<=strVector[i][0].z && _z+_deltaZ > strVector[i][0].z) return i; else return size;//out of structure and _z bigger than the last structure slice } //else else{ //if roi and roiNext in the same slice if(strVector[i][0].z==strVector[i+1][0].z){ //if voxel intersect the slice if(_z<=strVector[i][0].z && _z+_deltaZ>=strVector[i][0].z) return i; } else{ if(_z+_deltaZ>= strVector[i][0].z && _zz<<", p2(2):"<z<=roiNext, set i+1 } } } } return -1;//out of structure and _z smaller than the first structure slice } std::vector DoseVoxel::getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) const{ std::vector sliceNumberVector; const LegacyPolygonSequenceType& strVector=aRTStructure.getLegacyStructureVector();//strVector is ranked by _z of the contour int size=strVector.size(); if(size==0){ throw std::out_of_range( "Error: structure vector of aRTStructure is empty! "); } int firstSlice=this->getCorrespondingSlice(aRTStructure); if(firstSlice>=0 && firstSlice DoseVoxel::calcIntersectionPoints(WorldCoordinate3D firstPoint, WorldCoordinate3D secondPoint){ //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] //segment: (y-first(1))*(secont(0)-first(0))=(x-first(0))*(secont(1)-first(1)) int a=secondPoint(0)-firstPoint(0); int b=secondPoint(1)-firstPoint(1); std::vector intersectionPoints; if(a==0){ if(firstPoint(0)>=_x && firstPoint(0)<=(_x+_deltaX)){ if(min(firstPoint(1),secondPoint(1))<=_y && max(firstPoint(1), secondPoint(1))>=_y){ WorldCoordinate3D p; p(0) = firstPoint(0); p(1) = _y; p(2) = _z; intersectionPoints.push_back(p); } if(min(firstPoint(1),secondPoint(1))<=(_y+_deltaY) && max(firstPoint(1), secondPoint(1))>=(_y+_deltaY)){ WorldCoordinate3D p; p(0) = firstPoint(0); p(1) = _y+_deltaY; p(2) = _z; intersectionPoints.push_back(p); } } } else if(b==0){ if(firstPoint(1)>=_y && firstPoint(1)<=(_y+_deltaY)){ if(min(firstPoint(0),secondPoint(0))<=_x && max(firstPoint(0), secondPoint(0))>=_x){ WorldCoordinate3D p; p(0) = _x; p(1) = firstPoint(1); p(2) = _z; intersectionPoints.push_back(p); } if(min(firstPoint(0),secondPoint(0))<=(_x+_deltaX) && max(firstPoint(0), secondPoint(0))>=(_x+_deltaX)){ WorldCoordinate3D p; p(0) = _x+_deltaX; p(1) = firstPoint(1); p(2) = _z; intersectionPoints.push_back(p); } } } else{ //1.[(_x,_y),(_x+_deltaX,_y)] double interX=(_y-firstPoint(1))*a/b+firstPoint(0); if(interX>=_x && interX<=(_x+_deltaX)){ WorldCoordinate3D p; p(0) = interX; p(1) = _y; p(2) = _z; intersectionPoints.push_back(p); } //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] double interY=(_x+_deltaX-firstPoint(0))*b/a+firstPoint(1); if(interY>=_y && interY<=(_y+_deltaY)){ WorldCoordinate3D p; p(0) = _x+_deltaX; p(1) = interY; p(2) = _z; intersectionPoints.push_back(p); } //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] interX=(_y+_deltaY-firstPoint(1))*a/b+firstPoint(0); if(interX>=_x && interX<=(_x+_deltaX)){ WorldCoordinate3D p; p(0) = interX; p(1) = _y+_deltaY; p(2) = _z; intersectionPoints.push_back(p); } //4.[(_x,_y+_deltaY),(_x,_y)] interY=(_x-firstPoint(0))*b/a+firstPoint(1); if(interY>=_y && interY<=(_y+_deltaY)){ WorldCoordinate3D p; p(0) = _x; p(1) = interY; p(2) = _z; intersectionPoints.push_back(p); } } return intersectionPoints; } std::vector DoseVoxel::calcIntersectionPoints(LegacyWorldCoordinate3D firstPoint, LegacyWorldCoordinate3D secondPoint){ //4 Segment of the dose voxel:[(_x,_y),(_x+_deltaX,_y)],[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)],[(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)],[(_x,_y+_deltaY),(_x,_y)] //segment: (y-first.y)*(secont.x-first.x)=(x-first.x)*(secont.y-first.y) int a=secondPoint.x-firstPoint.x; int b=secondPoint.y-firstPoint.y; std::vector intersectionPoints; if(a==0){ if(firstPoint.x>=_x && firstPoint.x<=(_x+_deltaX)){ if(min(firstPoint.y,secondPoint.y)<=_y && max(firstPoint.y, secondPoint.y)>=_y){ LegacyWorldCoordinate3D p(firstPoint.x,_y,_z); intersectionPoints.push_back(p); } if(min(firstPoint.y,secondPoint.y)<=(_y+_deltaY) && max(firstPoint.y, secondPoint.y)>=(_y+_deltaY)){ LegacyWorldCoordinate3D p(firstPoint.x,_y+_deltaY,_z); intersectionPoints.push_back(p); } } } else if(b==0){ if(firstPoint.y>=_y && firstPoint.y<=(_y+_deltaY)){ if(min(firstPoint.x,secondPoint.x)<=_x && max(firstPoint.x, secondPoint.x)>=_x){ LegacyWorldCoordinate3D p(_x,firstPoint.y,_z); intersectionPoints.push_back(p); } if(min(firstPoint.x,secondPoint.x)<=(_x+_deltaX) && max(firstPoint.x, secondPoint.x)>=(_x+_deltaX)){ LegacyWorldCoordinate3D p(_x+_deltaX,firstPoint.y,_z); intersectionPoints.push_back(p); } } } else{ //1.[(_x,_y),(_x+_deltaX,_y)] double interX=(_y-firstPoint.y)*a/b+firstPoint.x; if(interX>=_x && interX<=(_x+_deltaX)){ LegacyWorldCoordinate3D p(interX,_y,_z); intersectionPoints.push_back(p); } //2.[(_x+_deltaX,_y),(_x+_deltaX,_y+_deltaY)] double interY=(_x+_deltaX-firstPoint.x)*b/a+firstPoint.y; if(interY>=_y && interY<=(_y+_deltaY)){ LegacyWorldCoordinate3D p(_x+_deltaX,interY,_z); intersectionPoints.push_back(p); } //3. [(_x+_deltaX,_y+_deltaY),(_x,_y+_deltaY)] interX=(_y+_deltaY-firstPoint.y)*a/b+firstPoint.x; if(interX>=_x && interX<=(_x+_deltaX)){ LegacyWorldCoordinate3D p(interX,_y+_deltaY,_z); intersectionPoints.push_back(p); } //4.[(_x,_y+_deltaY),(_x,_y)] interY=(_x-firstPoint.x)*b/a+firstPoint.y; if(interY>=_y && interY<=(_y+_deltaY)){ LegacyWorldCoordinate3D p(_x,interY,_z); intersectionPoints.push_back(p); } } return intersectionPoints; } /*! @brief Get the voxel index*/ const LegacyDoseVoxelIndex3D& DoseVoxel::getVoxelIndex3D() const{ return _voxelIndex3D; } /*! @brief Get the geometric information*/ const core::GeometricInfo* DoseVoxel::getGeometricInfo() const{ return _geoInfo; } void DoseVoxel::setProportionInStr(FractionType aProportionInStr){ _proportionInStr=aProportionInStr; } FractionType DoseVoxel::getProportionInStr() const{ return _proportionInStr; } } }//end namespace core }//end namespace rttb diff --git a/code/masks/DoseVoxel_LEGACY.h b/code/masks/legacy/DoseVoxel_LEGACY.h similarity index 95% rename from code/masks/DoseVoxel_LEGACY.h rename to code/masks/legacy/DoseVoxel_LEGACY.h index dda073e..1d45b83 100644 --- a/code/masks/DoseVoxel_LEGACY.h +++ b/code/masks/legacy/DoseVoxel_LEGACY.h @@ -1,210 +1,210 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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_DOSE_VOXEL_H #define __RT_DOSE_VOXEL_H //#include "rttbStructure.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" #include "rttbStructure_LEGACY.h" namespace rttb{ namespace masks { namespace legacy{ /*! @class DoseVoxel * @brief This is a class representing a DoseVoxel. */ class DoseVoxel { private: /*! @brief Voxel index */ LegacyDoseVoxelIndex3D _voxelIndex3D; /*! @brief WorldCoordinate (_x,_y,_z): the left upper point, the point in voxel with minimal x y and z coordinate*/ WorldCoordinate _x; WorldCoordinate _y; WorldCoordinate _z; /*! @brief(_x+_deltaX, _y+_deltaY,_z+_deltaZ): the point in voxel with maximal x y and z coordinate*/ WorldCoordinate _deltaX; WorldCoordinate _deltaY; WorldCoordinate _deltaZ; /*! @brief Geometric information*/ const core::GeometricInfo* _geoInfo; /*! @brief The proportion of voxel which is inside a given structure: 0~1 */ FractionType _proportionInStr; public: /* @brief Standard Constructor*/ DoseVoxel(); /*! @brief Constructor @param aDoseIndex: a dose voxel index, aGeometricInfo: the geometric information (imagePosition, ImageOrientation, pixelSpacing and getSliceThickness()) */ DoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); //same method with legacy data structures DoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); /*! @brief Operator = */ bool operator==(const DoseVoxel& doseVoxel) const; /*! @brief Operator < */ bool operator<(const DoseVoxel& doseVoxel) const; /*! @brief Initialisation of the dose voxel with dose voxel index and DICOM-RT information. Transform dose index to world coordinate * @param imagePosition: RT Image Position(3002,0012), * @param getImageOrientationRow(), getImageOrientationColumn(): Image Orientation (Patient) (0020,0037), * @param getPixelSpacingRow(), getPixelSpacingColumn(): Pixel Spacing (0028,0030) * @param getSliceThickness(): Slice Thickness (0018,0050). * @exception RTTBInvalidParameterException thrown if aDoseIndex /Pixel spacing/slice thickness invalid * */ //void setDoseIndex(const VoxelGridIndex3D& aDoseIndex, const WorldCoordinate3D& imagePosition, //const ImageOrientation& getImageOrientationRow(), const ImageOrientation& getImageOrientationColumn(), //double getPixelSpacingRow(), double getPixelSpacingColumn(), double getSliceThickness()); void setDoseVoxel(const VoxelGridIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); //same method with legacy data structures void setDoseVoxel(const LegacyDoseVoxelIndex3D& aDoseIndex, const core::GeometricInfo* aGeometricInfo); /*! @brief Initialisation of the dose voxel with world coordinate. Set dose voxel with the left upper point and delta * */ void setDoseVoxel(WorldCoordinate3D aWorldCoordinate, WorldCoordinate3D aVoxelDelta); //same method with legacy data structures void setDoseVoxel(LegacyWorldCoordinate3D aWorldCoordinate, LegacyWorldCoordinate3D aVoxelDelta); /*! @brief Tests if a point is inside the voxel * */ bool pointInVoxel(const WorldCoordinate3D& aPoint) const; //same method with legacy data structures bool pointInVoxel(const LegacyWorldCoordinate3D& aPoint) const; /*! @brief Calculates how many relative volume of the voxel inside the structure. * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error */ double voxelInStructure(const StructureLegacy& aRTStructure) const; /*! @brief Calculates how many relative volume of the voxel inside the structure, with the corresponding polygon index number. * It will be tested if the dose voxel in any Polygon with the same z coord.. * @param sliceNumber: fist index number of the polygon stored in strVector (ranked by z coord. of the polygon) if the z coord. * of the dose voxel between the last Polygon and this Polygon!!! * * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error * @pre aRTStructure must not be NULL */ double voxelInStructure(const StructureLegacy& aRTStructure, int sliceNumber) const; /*! @brief Calculates how many relative volume of the voxel inside the corresponding polygon with polygon index number. * * @param polygonIndex: the index number of the polygon stored in strVector (ranked by z coord. of the polygon) * * @return Return the relative volume. >0: voxel in structure, =0: voxel not in structure, <0: error * @pre aRTStructure must not be NULL */ double voxelInStructureAtIndex(const StructureLegacy& aRTStructure, int polygonIndex) const; /*! @brief Tests if a point is inside a polygon. * @return Return true if the point is inside the polygon or the point is on an edge of the polygon ! Make sure that the point and the list of positions lies both in the z-plane */ //bool pointInPolygon(const PolygonType& aPolygon, const WorldCoordinate3D& aPoint) const; /*! @brief Tests if the voxel intersect the polygon defined by the given list of positions. ! Make sure that the point and the list of positions lies both in the z-plane */ //public: bool voxelInROI(vector aRoi); /*! @brief get the first corresponding slice number: * !!!Important: not the actual slice number, but the index number of the polygon stored in the structure vector (ranked by z coord. of the polygon) if the z coord. of the dose voxel between the last Polygon and this Polygon!!! * @return i from (0~strVector.size()-1): voxel between the i-th and (i+1)-th polygon or _z on the i-th polygon; * -1: out of structure and _z smaller than z coordi.of the first polygon * strVector.size(): out of structure and _z bigger than z coordi.of the last polygon */ int getCorrespondingSlice(const StructureLegacy& aRTStructure) const; /*! @brief Get polygon indexs in the same contour-slice, which has intersection with this voxel. If the voxel intersect > 1 Slice, the slice with smallert * index will be used. * @return Return vector of index number of the polygons stored in the structure vector(ranked by z coord. of the polygon), if size=0: out of structure */ std::vector getZIntersectPolygonIndexVector(const StructureLegacy& aRTStructure) const; /*! @brief Get the left upper point of the dose voxel in world coordinate. * */ WorldCoordinate3D getLeftUpperPoint() const; LegacyWorldCoordinate3D getLeftUpperPointLegacy() const; /*! @brief Get (_deltaX, _deltaY, _deltaZ) of the dose voxel in world coordinate. * */ WorldCoordinate3D getDelta() const; LegacyWorldCoordinate3D getDeltaLegacy() const; /*! @brief Calculate the interseciton points with the segment [firstPoint, secontPoint]*/ std::vector calcIntersectionPoints(WorldCoordinate3D firstPoint, WorldCoordinate3D secondPoint); //same method with legacy data structures std::vector calcIntersectionPoints(LegacyWorldCoordinate3D firstPoint, LegacyWorldCoordinate3D secondPoint); /*! @brief Get the voxel index*/ const LegacyDoseVoxelIndex3D& getVoxelIndex3D() const; /*! @brief Get the geometric information*/ const core::GeometricInfo* getGeometricInfo() const; /*! @brief Set the voxel proportion inside a given structure*/ void setProportionInStr(FractionType aProportionInStr); /*! @brief Get the voxel proportion inside a given structure*/ FractionType getProportionInStr() const; }; } } } #endif diff --git a/code/masks/files.cmake b/code/masks/legacy/files.cmake similarity index 86% copy from code/masks/files.cmake copy to code/masks/legacy/files.cmake index 14215d6..51b0fbf 100644 --- a/code/masks/files.cmake +++ b/code/masks/legacy/files.cmake @@ -1,30 +1,28 @@ SET(CPP_FILES rttbOTBMaskAccessor.cpp rttbMask.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 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/rttbBaseType_LEGACY.h b/code/masks/legacy/rttbBaseType_LEGACY.h similarity index 92% rename from code/masks/rttbBaseType_LEGACY.h rename to code/masks/legacy/rttbBaseType_LEGACY.h index 16a7e01..f4157b9 100644 --- a/code/masks/rttbBaseType_LEGACY.h +++ b/code/masks/legacy/rttbBaseType_LEGACY.h @@ -1,254 +1,254 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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_BASE_TYPE_H #define __RT_BASE_TYPE_H #include #include #include #include #include #include #include "rttbBaseType.h" namespace rttb{ namespace masks{ namespace legacy{ typedef double LegacyWorldCoordinate1D; struct LegacyWorldCoordinate2D{ LegacyWorldCoordinate1D x; LegacyWorldCoordinate1D y; std::string toString() const{ std::stringstream sstr; sstr<<"("<x = 0; this->y = 0; this->z = 0; } LegacyWorldCoordinate3D( LegacyWorldCoordinate1D a, LegacyWorldCoordinate1D b, LegacyWorldCoordinate1D c){ this->x = a; this->y = b; this->z = c; } LegacyWorldCoordinate3D(rttb::WorldCoordinate3D aCoordinate){ this->x = aCoordinate.x(); this->y = aCoordinate.y(); this->z = aCoordinate.z(); } bool operator==(const LegacyWorldCoordinate3D& p) const { return(x==p.x && y==p.y && z==p.z); } /** assigment operator * @param copy LegacyWorldCoordinate3D object to be copied */ LegacyWorldCoordinate3D& operator=(const LegacyWorldCoordinate3D& copy){ if (this != ©) { x=copy.x; y=copy.y; z=copy.z; } return *this; } //vector cross product (not included in boost.ublas) LegacyWorldCoordinate3D cross(LegacyWorldCoordinate3D aVector) const{ LegacyWorldCoordinate3D result; LegacyWorldCoordinate1D x = this->x; LegacyWorldCoordinate1D y = this->y; LegacyWorldCoordinate1D z = this->z; result.x = y*aVector.z-z*aVector.y; result.y = z*aVector.x-x*aVector.z; result.z = x*aVector.y-y*aVector.x; return result; } }LegacyImageOrientation; typedef int LegacyDoseVoxelIndex1D; struct LegacyDoseVoxelIndex3D{ LegacyDoseVoxelIndex1D x; LegacyDoseVoxelIndex1D y; LegacyDoseVoxelIndex1D z; std::string toString() const{ std::stringstream sstr; sstr<<"("<index.z) return false; else{ if(yindex.y) return false; else{ if(x LegacyPolygonType; typedef std::vector LegacyPolygonSequenceType; typedef struct{ LegacyWorldCoordinate1D x_begin; LegacyWorldCoordinate1D x_end; LegacyWorldCoordinate1D y_begin; LegacyWorldCoordinate1D y_end; LegacyDoseVoxelIndex2D index_begin; LegacyDoseVoxelIndex2D index_end; void Init(){ x_begin = -1000000; x_end = -1000000; y_begin = -1000000; y_end = -1000000; index_begin.x = 0; index_begin.y = 0; index_end.x = 0; index_end.y = 0; } }LegacyArea2D; typedef struct{ LegacyWorldCoordinate2D begin; LegacyWorldCoordinate2D end; }LegacySegment2D; typedef struct{ LegacyWorldCoordinate3D begin; LegacyWorldCoordinate3D end; }LegacySegment3D; /*! @brief area_vector specifies an image region. So its a vector of 2d areas. That means it is a 3D area. */ typedef std::vector area_vector; typedef std::vector< std::vector > vector_of_area_vectors; } } } #endif diff --git a/code/masks/rttbContour_LEGACY.cpp b/code/masks/legacy/rttbContour_LEGACY.cpp similarity index 95% rename from code/masks/rttbContour_LEGACY.cpp rename to code/masks/legacy/rttbContour_LEGACY.cpp index 7ec0657..c5f593d 100644 --- a/code/masks/rttbContour_LEGACY.cpp +++ b/code/masks/legacy/rttbContour_LEGACY.cpp @@ -1,442 +1,442 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include "rttbContour_LEGACY.h" #include #include #include namespace rttb{ namespace masks{ namespace legacy{ Contour::Contour(LegacyPolygonType aPolygon) { _polygon=aPolygon; } /*Contour::Contour(int i){ }*/ Contour::~Contour(){ } const LegacyPolygonType& Contour::getPolygon() const{ return _polygon; } /*calculate contour area*/ double Contour::getArea() const{ double area=0; size_t numberOfPoints=_polygon.size(); for(int j1=0, j2=1; j1=std::min(q1.x,q2.x))&& (std::max(q1.x,q2.x)>=std::min(p1.x,p2.x))&& (std::max(p1.y,p2.y)>=std::min(q1.y,q2.y))&& (std::max(q1.y,q2.y)>=std::min(p1.y,p2.y))&& (multiply(q1,p2,p1)*multiply(p2,q2,p1)>=0)&& (multiply(p1,q2,q1)*multiply(q2,p2,q1)>=0)); //if(intersect) std::cout << "intersect: "<= pnt1.y ); GridIndexType i=0; do{ i++; if(i==_polygon.size()) pnt2=_polygon[0]; else pnt2 = _polygon[i]; //if the point lies on an edge of the polygon, return true if((pnt2.y-aPoint.y)*(pnt1.x-pnt2.x)==(pnt2.x-aPoint.x)*(pnt1.y-pnt2.y) && (aPoint.x>=std::min(pnt1.x,pnt2.x)) && (aPoint.x <=std::max(pnt1.x,pnt2.x)) && (aPoint.y>=std::min(pnt1.y,pnt2.y)) && (aPoint.y <=std::max(pnt1.y,pnt2.y))) return true; //else flag2=( aPoint.y >= pnt2.y ); if(flag1 != flag2) { if(((pnt2.y-aPoint.y)*(pnt1.x-pnt2.x)>=(pnt2.x-aPoint.x)*(pnt1.y-pnt2.y)) ==flag2) inside=!inside; } pnt1=pnt2; flag1=flag2; } while(i<_polygon.size()); //} return inside; } bool Contour::point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const{ if(this->_polygon.size()>0){ LegacyWorldCoordinate3D p; p.x = aPoint.x; p.y = aPoint.y; p.z = this->_polygon.at(0).z; return this->pointInPolygon(p); } else{ std::cerr << "_polygon is empty! "<< std::endl; return false; } } NumberOfEndpointsType Contour::getNumberOfEndpoints() const{ return _polygon.size(); } LegacyPolygonType Contour::getMinimalBox() const{ LegacyPolygonType box; WorldCoordinate maxX; WorldCoordinate maxY; WorldCoordinate minX; WorldCoordinate minY; WorldCoordinate z; for(GridIndexType i=0;i<_polygon.size();i++){ LegacyWorldCoordinate3D p=_polygon.at(i); z=p.z; if(i==0){ minX=p.x; minY=p.y; maxX=p.x; maxY=p.y; } if(p.xmaxX) maxX=p.x; if(p.ymaxY) maxY=p.y; } LegacyWorldCoordinate3D pLU; pLU.x = minX; pLU.y = minY; pLU.z = z; LegacyWorldCoordinate3D pRU; pRU.x = maxX; pRU.y = minY; pRU.z = z; LegacyWorldCoordinate3D pRB; pRB.x = maxX; pRB.y = maxY; pRB.z = z; LegacyWorldCoordinate3D pLB; pLB.x = minX; pLB.y = maxY; pLB.z = z; box.push_back(pLU); box.push_back(pRU); box.push_back(pRB); box.push_back(pLB); return box; } Contour* Contour::calcIntersection(Contour& contour2){ LegacyPolygonType box1=this->getMinimalBox(); LegacyWorldCoordinate3D box1P1=box1.at(0); LegacyWorldCoordinate3D box1P2=box1.at(1); LegacyWorldCoordinate3D box1P3=box1.at(2); LegacyWorldCoordinate3D box1P4=box1.at(3); LegacyPolygonType box2=contour2.getMinimalBox(); LegacyWorldCoordinate3D box2P1=box2.at(0); LegacyWorldCoordinate3D box2P2=box2.at(1); LegacyWorldCoordinate3D box2P3=box2.at(2); LegacyWorldCoordinate3D box2P4=box2.at(3); Contour box1Contour=Contour(box1); //if box1 and box2 have no intersection, that means no intersection between this contour and contour2 if(!box1Contour.pointInPolygon(box2P1) && !box1Contour.pointInPolygon(box2P2) && !box1Contour.pointInPolygon(box2P3) && !box1Contour.pointInPolygon(box2P4) ){ //std::cout << "No intersection!"< segments1InBox2; for(GridIndexType i=0;i<_polygon.size();i++){ LegacyWorldCoordinate3D segmentL=_polygon.at(i);//segment left corner LegacyWorldCoordinate3D segmentR;//segment right corner if(i==_polygon.size()-1) segmentR=_polygon.at(0); else segmentR=_polygon.at(i+1); //if this segment not inside box2 if(!(std::max(segmentL.x,segmentR.x)box2P2.x || (std::max(segmentL.y,segmentR.y)box2P3.y))){ LegacySegment3D segment; segment.begin=segmentL; segment.end=segmentR; segments1InBox2.push_back(segment); } } //Remove segments of contour2 which not inside box1 std::vector segments2InBox1; LegacyPolygonType polygon2=contour2.getPolygon(); for(GridIndexType i=0;ibox1P2.x || (std::max(segmentL.y,segmentR.y)box1P3.y))){ LegacySegment3D segment; segment.begin=segmentL; segment.end=segmentR; segments2InBox1.push_back(segment); } } //Get the points of this contour inside contour2 and all intersect points std::vector points1InContour2;//store points of this contour inside contour2 and all intersect points std::vector::iterator it; std::vector::iterator it2; for(it=segments1InBox2.begin();it!=segments1InBox2.end();it++){ LegacySegment3D segment=*it; if(contour2.pointInPolygon(segment.begin)) points1InContour2.push_back(segment.begin); //test: if segment has intersection with any segment in segments2InBox1 for(it2=segments2InBox1.begin();it2!=segments2InBox1.end();it2++){ if(Contour::intersect(segment.begin,segment.end,(*it2).begin,(*it2).end)){ LegacyWorldCoordinate3D interP=Contour::calcInterPoint(segment.begin,segment.end,(*it2).begin,(*it2).end); if(Contour(points1InContour2).contains(interP)) points1InContour2.push_back(interP); } } } //sort points1InContour2 clockwise Contour tempContour=Contour(points1InContour2); tempContour.sortClockwise(); points1InContour2=tempContour.getPolygon(); //Get the points of contour2 inside this contour and all intersect points std::vector points2InContour1;//store points of contour2 inside this contour and all intersect points for(it=segments2InBox1.begin();it!=segments2InBox1.end();it++){ LegacySegment3D segment=*it; if(pointInPolygon(segment.begin)) points2InContour1.push_back(segment.begin); //test: if segment has intersection with any segment in segments2InBox1 for(it2=segments1InBox2.begin();it2!=segments1InBox2.end();it2++){ if(Contour::intersect(segment.begin,segment.end,(*it2).begin,(*it2).end)){ LegacyWorldCoordinate3D interP=Contour::calcInterPoint(segment.begin,segment.end,(*it2).begin,(*it2).end); if(Contour(points2InContour1).contains(interP)) points2InContour1.push_back(interP); } } } //sort points1InContour2 clockwise tempContour=Contour(points2InContour1); tempContour.sortClockwise(); points2InContour1=tempContour.getPolygon(); LegacyPolygonType intersectionPolygon=points1InContour2; LegacyPolygonType::iterator itP; for(itP=points2InContour1.begin();itP!=points2InContour1.end();itP++){ if(!Contour(intersectionPolygon).contains((*itP))) intersectionPolygon.push_back((*itP)); } //sort intersectionPolygon Contour* intersection=new Contour(intersectionPolygon); intersection->sortClockwise(); return intersection; } /*! @brief Sort the points in _polygon in clockwise order*/ void Contour::sortClockwise(){ size_t numberOfP=_polygon.size(); if(numberOfP>=3){ LegacyWorldCoordinate3D p1=_polygon.at(0); LegacyWorldCoordinate3D p2=_polygon.at(1); LegacyWorldCoordinate3D p3=_polygon.at(2); LegacyWorldCoordinate2D pInPolygon = {(p1.x+p2.x+p3.x)/3,(p1.y+p2.y+p3.y)/3};//get a point inside the polygon std::map pointsI; std::map pointsII; std::map pointsIII; std::map pointsIV; for(int i=0;i=0 && dy>=0){ pointsI.insert(std::pair(sin*(-1.0),p)); } else if(dx>=0 && dy<0) pointsIV.insert(std::pair(sin*(-1.0),p)); else if(dx<0 && dy<0) pointsIII.insert(std::pair(sin,p)); else pointsII.insert(std::pair(sin,p)); } LegacyPolygonType sorted; std::map::iterator it; for(it=pointsII.begin();it!=pointsII.end();it++) sorted.push_back((*it).second); for(it=pointsI.begin();it!=pointsI.end();it++) sorted.push_back((*it).second); for(it=pointsIV.begin();it!=pointsIV.end();it++) sorted.push_back((*it).second); for(it=pointsIII.begin();it!=pointsIII.end();it++) sorted.push_back((*it).second); _polygon=sorted; } } std::string Contour::toString() const{ std::stringstream sstr; sstr<<"{"; for(GridIndexType i=0;i<_polygon.size();i++) sstr<<_polygon.at(i).toString()<<", "; sstr<<"}"; return sstr.str(); } bool Contour::contains(const LegacyWorldCoordinate3D& aPoint) const{ for(GridIndexType i=0;i<_polygon.size();i++){ if(aPoint==_polygon.at(i)) return true; } return false; } }//end namespace legacy }//end namespace masks }//end namespace rttb diff --git a/code/masks/rttbContour_LEGACY.h b/code/masks/legacy/rttbContour_LEGACY.h similarity index 93% rename from code/masks/rttbContour_LEGACY.h rename to code/masks/legacy/rttbContour_LEGACY.h index c7b67f3..f2384a4 100644 --- a/code/masks/rttbContour_LEGACY.h +++ b/code/masks/legacy/rttbContour_LEGACY.h @@ -1,129 +1,129 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __CONTOUR_H #define __CONTOUR_H #include #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" namespace rttb{ namespace masks{ namespace legacy{ typedef size_t NumberOfEndpointsType; /*! @class Contour * @brief This is a class representing a RT Contour. A RT contour is either a single point (for a point ROI) or more than * one point (representing an open or closed polygon). */ class Contour { private: /*! @brief WorldCoordinate3D in mm */ LegacyPolygonType _polygon; static double multiply(const LegacyWorldCoordinate3D& p1,const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& p0); static LegacyWorldCoordinate2D calcInterPoint2D(const LegacyWorldCoordinate2D& p1, const LegacyWorldCoordinate2D& p2, const LegacyWorldCoordinate2D& q1, const LegacyWorldCoordinate2D& q2); public: //Contour(int i); /*! @brief Contour Constructor @param aPolygon: a polygon used to generate the contour */ Contour(LegacyPolygonType aPolygon); /*! @brief Destructor */ ~Contour(); /*! @brief Calculate contour area using Formel 0.5*abs(x1*y2-y1*x2+x2*y3-y2*x3+...+xn*y1-yn*x1) @return Return a double value of contour area */ double getArea() const; /*! @brief Tests if a point is inside _polygon. If the point lies on an edge of the polygon, return true *! Make sure that the point and the list of positions lies both in the z-plane */ bool pointInPolygon(const LegacyWorldCoordinate3D& aPoint) const; /*! @brief Tests if a 2Dpoint is inside _polygon in 2D. If the point lies on an edge of the polygon, return true * */ bool point2DInPolygon(const LegacyWorldCoordinate2D& aPoint) const; /*! @brief Get the polygon */ const LegacyPolygonType& getPolygon() const; /*! @brief Tests if a point is inside the polygon defined by the given list of positions. ! Make sure that the point and the list of positions lies both in the z-plane */ //bool pointInStructure(const WorldCoordinate3D& aPoint) const; /*! @brief Get the number of end points of the polygon*/ NumberOfEndpointsType getNumberOfEndpoints() const; /*! @brief Get the minimal bounding box * @return Return Polygon{{minX,minY,z},{maxX,minY,z},{maxX,maxY,z},{minX,maxY,z}} */ LegacyPolygonType getMinimalBox() const; /*! @brief Get the intersection of this Contour and contour2 ! Make sure that the 2 Contours lies both in the z-plane * @return Return NULL if no intersection */ Contour* calcIntersection(Contour& contour2); /*! @brief Sort the points in _polygon in clockwise order*/ void sortClockwise(); /*! @brief Calculate the intersection between the two segments (p1,p2) and (q1,q2) * Make sure that the points lies in the same z-plane */ static LegacyWorldCoordinate3D calcInterPoint(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2); /*! @brief Tests if an intersection exists between two segments (p1, p2) and (q1, q2) */ static bool intersect(const LegacyWorldCoordinate3D& p1, const LegacyWorldCoordinate3D& p2, const LegacyWorldCoordinate3D& q1, const LegacyWorldCoordinate3D& q2); std::string toString() const; /*! @brief If aPoint stored in _polygon */ bool contains(const LegacyWorldCoordinate3D& aPoint) const; }; } } } #endif diff --git a/code/masks/rttbField_LEGACY.h b/code/masks/legacy/rttbField_LEGACY.h similarity index 95% rename from code/masks/rttbField_LEGACY.h rename to code/masks/legacy/rttbField_LEGACY.h index 63480b9..4623dd9 100644 --- a/code/masks/rttbField_LEGACY.h +++ b/code/masks/legacy/rttbField_LEGACY.h @@ -1,594 +1,594 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __FIELD_H #define __FIELD_H #include #include #include "rttbBaseType.h" #include "rttbMaskType_LEGACY.h" #include "rttbBaseType_LEGACY.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb{ namespace masks{ namespace legacy{ /*! @class BaseField @brief This is a class representing a field to be inherited. */ class BaseField { public: BaseField(){} BaseField( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ):dimx(dimx_in), dimy(dimy_in), dimz(dimz_in){} /*! @return extend of the field in x-direction. */ virtual Uint16 GetDimX(){ return dimx; } /*! @return extend of the field in y-direction. */ virtual Uint16 GetDimY(){ return dimy; } /*! @return extend of the field in z-direction. */ virtual Uint16 GetDimZ(){ return dimz; } protected: Uint16 dimx; Uint16 dimy; Uint16 dimz; }; /*! @class FieldOfScalar @brief This is a class representing a field of scalar values @todo uses UnsignedIndexList and other types from legacy code. Needs to be reimplemented. Close connection to legacy mask need to be resolved. */ template class FieldOfScalar : public BaseField { public: /*! @param dimx_in field extend in direction x. @param dimy_in field extend in direction y. @param dimz_in field extend in direction z. */ FieldOfScalar( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ): BaseField( dimx_in , dimy_in , dimz_in ) { create(); } ~FieldOfScalar(){ clear(); } typedef TYPE type; /*! @brief Get the data stored in this FieldOfScalar at index (x,y,z) @return value of interest @exception IndexOutOfBoundsException */ inline TYPE GetData( Uint16 x, Uint16 y, Uint16 z ); /*! @brief Set all values to zero. */ void SetZero(); /*! @brief Set value at index (x,y,z) to value. @exception IndexOutOfBoundsException */ inline void PutData( Uint16 x, Uint16 y, Uint16 z , TYPE value ); /*! @brief Check whether a 3D block of the length block_length with upper left corner (x,y,z) has the intensity of value. @return True if the entire block does have the value of interest. */ bool CheckBlockSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); /*! @brief Set 3D block of the length block_length with upper left corner (x,y,z) to the value of input parameter "value". */ void SetBlockThisIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); /*! @brief This function investigates a specific area of the field, given by the parameter av. Those voxels that are yet not clearly determined to be located inside or outside the contour and that are not part of the border region are of interest. Depending on the neighbours of these voxels they are now defined as inside or outside, if possible. @param av Specifies the region of interest within the field. @param indexListInside The function fills this list with voxels that are determined inside during this procedure. @param indexListOutside The function fills this list with voxels that are determined outside during this procedure. @param unclear_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes uncertainty with respect to association (inside/outside). @param inside_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes inside. @param outside_intensity Intensity or value (does not necessarily have to be an intensity) that characterizes outside. */ void GetBorderRegion( masks::legacy::area_vector av, std::vector< masks::legacy::UnsignedIndexList >& indexListInside , std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, TYPE inside_intensity , TYPE outside_intensity ); /*! @returns true in case one of the voxels within the regarded block does have the value "value". @param x x-position of the upper left corner of the block under investigation. @param y y-position of the upper left corner of the block under investigation. @param z z-position of the upper left corner of the block under investigation. @param block_length lenght of the block that is processed. */ bool CheckOneOutOfThisBlockHasSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ); private: /*! Return to initial state. */ void clear(); /*! Initialize all. */ void create(); TYPE* data; /*! Number of values within a slice. */ int slice_size; /*! Number of values within a raw. */ Uint16 raw_size; /*! Number of values within the field. */ int cube_size; }; template void FieldOfScalar::SetZero(){ int size = ( dimz * dimy * dimx ) * sizeof(TYPE); memset( data , 0 , size ); } template inline TYPE FieldOfScalar::GetData( Uint16 x, Uint16 y, Uint16 z ){ TYPE val; int offset; offset = ( z * slice_size + y * raw_size + x ) ; if(offset<0) { throw core::IndexOutOfBoundsException( " Out of range ! " ); } if( offset <= ( cube_size - 1 ) ) { val = *( (TYPE*) data + offset ); return val; } else{ throw core::IndexOutOfBoundsException( " Out of range ! " ); } } template inline void FieldOfScalar::PutData( Uint16 x, Uint16 y, Uint16 z, TYPE value ){ int offset; if( x >= dimx ) { throw core::IndexOutOfBoundsException( " Out of range ! " ); } if( y >= dimy ) { throw core::IndexOutOfBoundsException( " Out of range ! " ); } if( z >= dimz ) { throw core::IndexOutOfBoundsException( " Out of range ! " ); } offset = ( z * slice_size + y * raw_size + x ) ; if(offset<0) { throw core::IndexOutOfBoundsException( " Out of range ! " ); } if( offset <= ( cube_size - 1 ) ) { *( (TYPE*) data + offset ) = value; } else{ throw core::IndexOutOfBoundsException( " Out of range ! " ); } } template void FieldOfScalar::clear(){ free(data); } template void FieldOfScalar::create(){ int size = ( dimz * dimy * dimx ) * sizeof(TYPE); data = (type*) malloc( size ); slice_size = dimy * dimx; raw_size = dimx; cube_size = dimy * dimx * dimz; memset( data , 0, cube_size * sizeof(TYPE) ); } template bool FieldOfScalar::CheckBlockSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ){ if( x >= dimx ) { assert(0); } if( y >= dimy ) { assert(0); } if( z >= dimz ) { assert(0); } Uint16 x_block_length = block_length; if( ( (dimx-1) - x ) <= x_block_length ) { x_block_length = ( (dimx-1) - x ); } Uint16 y_block_length = block_length; if( ( (dimy-1) - y ) <= y_block_length ) { y_block_length = ( (dimy-1) - y ); } TYPE* local_data_pointer; for( int pos = 0 ; pos < y_block_length ; pos++ ){ int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; if( offset <= ( cube_size - 1 ) ) { local_data_pointer = (TYPE*) (data + offset); for( Uint16 counter = 0 ; counter < x_block_length ; counter++ ){ if( *(local_data_pointer) != value ) { return false; } local_data_pointer++; } } // if offset else{ assert(0); } } // for pos return true; } template void FieldOfScalar::SetBlockThisIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ){ if( x >= dimx ) { assert(0); } if( y >= dimy ) { assert(0); } if( z >= dimz ) { assert(0); } Uint16 x_block_length = block_length; if( ( (dimx-1) - x ) <= x_block_length ) { x_block_length = ( (dimx-1) - x ); } Uint16 y_block_length = block_length; if( ( (dimy-1) - y ) <= y_block_length ) { y_block_length = ( (dimy-1) - y ); } TYPE* local_data_pointer; for( int pos = 0 ; pos < y_block_length ; pos++ ){ int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; if( offset <= ( cube_size - 1 ) ) { local_data_pointer = (TYPE*) (data + offset); for( Uint16 counter = 0 ; counter < x_block_length ; counter++ ){ *(local_data_pointer) = value; local_data_pointer++; } } // if offset else{ assert(0); } } // for pos } template void FieldOfScalar::GetBorderRegion( masks::legacy::area_vector av, std::vector< masks::legacy::UnsignedIndexList >& indexListInside , std::vector< masks::legacy::UnsignedIndexList >& indexListOutside, TYPE unclear_intensity, TYPE inside_intensity , TYPE outside_intensity ){ for( GridIndexType z = 0 ; z < dimz ; z++ ){ for( GridIndexType y = av.at(z).index_begin.y ; y <= av.at(z).index_end.y ; y++ ){ for( GridIndexType x = av.at(z).index_begin.x ; x <= av.at(z).index_end.x ; x++ ){ TYPE* data_pointer; TYPE* data_pointer_check_neighbour; int offset = ( z * slice_size + y * raw_size + x ) ; data_pointer = (TYPE*) (data + offset); if( *data_pointer == unclear_intensity ) { bool its_inside = false; bool its_outside = false; if( x > av.at(z).index_begin.x ) { int offset_neighbour = ( z * slice_size + y * raw_size + (x-1) ) ; data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); if( *data_pointer_check_neighbour == inside_intensity )its_inside = true; if( *data_pointer_check_neighbour == outside_intensity)its_outside = true; } if( x < av.at(z).index_end.x ) { int offset_neighbour = ( z * slice_size + y * raw_size + (x+1) ) ; data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); if( *data_pointer_check_neighbour == inside_intensity ) its_inside = true; if( *data_pointer_check_neighbour == outside_intensity) its_outside = true; } if( y > av.at(z).index_begin.y ) { int offset_neighbour = ( z * slice_size + (y-1) * raw_size + x ) ; data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); if( *data_pointer_check_neighbour == inside_intensity )its_inside = true; if( *data_pointer_check_neighbour == outside_intensity)its_outside = true; } if( y < av.at(z).index_end.y ) { int offset_neighbour = ( z * slice_size + (y+1) * raw_size + x ) ; data_pointer_check_neighbour = (TYPE*) (data + offset_neighbour); if( *data_pointer_check_neighbour == inside_intensity ) its_inside = true; if( *data_pointer_check_neighbour == outside_intensity) its_outside = true; } if( its_inside && its_outside ) { assert(0); } if( its_inside || its_outside ) { masks::legacy::LegacyUnsignedIndex3D index = {x,y,z}; if( its_inside ) { indexListInside.at(z).push_back(index); } if( its_outside ) { indexListOutside.at(z).push_back(index); } } } } } } } template bool FieldOfScalar::CheckOneOutOfThisBlockHasSameIntensity( Uint16 x, Uint16 y, Uint16 z , Uint16 block_length , TYPE value ){ if( x >= dimx ) { assert(0); } if( y >= dimy ) { assert(0); } if( z >= dimz ) { assert(0); } bool its_fine = false; Uint16 x_block_length = block_length; if( ( (dimx-1) - x ) <= x_block_length ) { x_block_length = ( (dimx-1) - x ); } Uint16 y_block_length = block_length; if( ( (dimy-1) - y ) <= y_block_length ) { y_block_length = ( (dimy-1) - y ); } TYPE* local_data_pointer; for( int pos = 0 ; pos < y_block_length ; pos++ ){ int offset = ( z * slice_size + ( y + pos ) * raw_size + x ) ; if( offset <= ( cube_size - 1 ) ) { local_data_pointer = (TYPE*) data + offset; for( int counter = 0 ; counter < x_block_length ; counter++ ){ if( *local_data_pointer == value ) { its_fine = true; } local_data_pointer++; } } // if offset else{ assert(0); } } // for pos return its_fine; } /*! @class FieldOfPointer @brief This is a class representing a field of pointers to whatever. */ template class FieldOfPointer : public BaseField { public: FieldOfPointer( Uint16 dimx_in , Uint16 dimy_in, Uint16 dimz_in ): BaseField( dimx_in , dimy_in , dimz_in ) { create(); } ~FieldOfPointer(){ clear(); } typedef TYPE type; /*! @brief Get the data stored in this FieldOfPointer at index (x,y,z) @see FieldOfScalar. */ inline TYPE GetData( Uint16 x, Uint16 y, Uint16 z ); /*! @brief Set all entries to Null @see FieldOfScalar. Here zero is NULL. */ void SetZero(); /*! @brief Set value at index (x,y,z) @see FieldOfScalar. */ inline void PutData( Uint16 x, Uint16 y, Uint16 z , TYPE value ); private: void clear(); /*! Initialize all. */ void create(); TYPE* data; /*! Number of values within a slice. */ int slice_size; /*! Number of values in a raw. */ Uint16 raw_size; /*! Number of values within a cube. */ int cube_size; }; template void FieldOfPointer::SetZero(){ for( int offset = 0 ; offset < cube_size ; offset++ ){ delete *( (TYPE*) data + offset ); *( (TYPE*) data + offset ) = NULL; } } template inline TYPE FieldOfPointer::GetData( Uint16 x, Uint16 y, Uint16 z ){ TYPE val; int offset; offset = ( z * slice_size + y * raw_size + x ) ; if( offset <= ( cube_size - 1 ) ) { val = *( (TYPE*) data + offset ); return val; } else{ throw core::IndexOutOfBoundsException( " Out of range ! " ); } } template inline void FieldOfPointer::PutData( Uint16 x, Uint16 y, Uint16 z, TYPE value ){ int offset; offset = ( z * slice_size + y * raw_size + x ) ; if( offset <= ( cube_size - 1 ) ) { delete *( (TYPE*) data + offset ); *( (TYPE*) data + offset ) = value; } else{ throw core::IndexOutOfBoundsException( " Out of range ! " ); } } template void FieldOfPointer::clear(){ for( int offset = 0 ; offset < cube_size ; offset++ ) delete *( (TYPE*) data + offset ); free(data); } template void FieldOfPointer::create(){ int size = ( dimz * dimy * dimx ) * sizeof(TYPE); data = (type*) malloc( size ); slice_size = dimy * dimx; raw_size = dimx; cube_size = dimy * dimx * dimz; for( int offset = 0 ; offset < cube_size ; offset++ ){ *( (TYPE*) data + offset ) = NULL; } } } } } #endif diff --git a/code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp similarity index 97% rename from code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp rename to code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp index 4dcfb3a..a223464 100644 --- a/code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp +++ b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.cpp @@ -1,1525 +1,1525 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ //Relocate? #include "rttbMask.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include "rttbNullPointerException.h" #include #include #include #include #include // Generelle Anmerkung: // Koordinatensystem von Bild und Strukturen auf Kompatibilitaet pruefen! // Strukturen auf Gutartigkeit pruefen: // Ein Polygonzug darf sich nicht mit sich selbst schneiden. Ist eine Struktur innerhalb eines Slices durch // zwei Polygonzuege repraesentiert, so muessen diese distinkt sein, duerfen eineander also nicht ueberschneiden! namespace rttb{ namespace masks{ namespace legacy{ IterativePolygonInTermsOfIntersections::IterativePolygonInTermsOfIntersections(){ number_of_intersections = -1; } bool IterativePolygonInTermsOfIntersections::selfTest(){ std::cout<< " Hallo, ich bin die funktion selfTest von IterativePolygonInTermsOfIntersections und ich bin noch nicht implementiert. Trotzdem returne ich true. Das musst du aendern. " < ( the_intersection_index_ref.intersection_index + ahead ) ){ if( the_intersection_index_ref.column_raw_or_unified == 0 ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).column_intersections.at( the_intersection_index_ref.intersection_index + ahead ); } else if( the_intersection_index_ref.column_raw_or_unified == 1 ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).raw_intersections.at( the_intersection_index_ref.intersection_index + ahead ); } else{ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).intersections_raw_and_column.at( the_intersection_index_ref.intersection_index + ahead ); } } else{ if( GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) <= ( the_intersection_index_ref.intersection_index + ahead ) ){ GridIndexType control_index = ( ( the_intersection_index_ref.intersection_index + ahead ) - GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ); if( ( control_index >= 0 ) && ( control_index < GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ) ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).intersections_raw_and_column.at( ( ( the_intersection_index_ref.intersection_index + ahead ) - GetRestpectiveIntersectionVectorLength( the_intersection_index_ref ) ) ); } else assert(0); // the_intersection_index_ref and ahead have been initially unreasonalble } } return coordinates_return; } bool IterativePolygonInTermsOfIntersections::PointIndexIsFine( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ if( ( Polygon_Intersections.size() > ( the_intersection_index_ref.point_index ) ) && ( ( the_intersection_index_ref.point_index ) >= 0 ) ){ return true; } else return false; } LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinates( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ LegacyWorldCoordinate3D coordinates_return; if( PointIndexIsFine( the_intersection_index_ref ) ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index ).contour_point_voxel_coord; } else{ // exception to be implemented assert(0); } return coordinates_return; } LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinatesFurther( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , int ahead ){ // Baustelle zyklisch machen LegacyWorldCoordinate3D coordinates_return; if( Polygon_Intersections.size() > ( the_intersection_index_ref.point_index + ahead ) ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index + ahead ).contour_point_voxel_coord; } else{ if( ( ahead - ( Polygon_Intersections.size() - the_intersection_index_ref.point_index ) ) >= Polygon_Intersections.size() ) assert( 0 ); // this must never happen. Probably the contour consists of just one point. That does not make any sense in context of radiotherapy. coordinates_return = Polygon_Intersections.at( ahead - ( Polygon_Intersections.size() - the_intersection_index_ref.point_index ) ).contour_point_voxel_coord; } return coordinates_return; } LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetRestpectivePologonPointInVoxelCoordinatesPrevious( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref , unsigned int back ){ LegacyWorldCoordinate3D coordinates_return; if( ( ( the_intersection_index_ref.point_index ) >= back ) && ( ( the_intersection_index_ref.point_index ) < ( Polygon_Intersections.size() + back ) ) ){ coordinates_return = Polygon_Intersections.at( the_intersection_index_ref.point_index - back ).contour_point_voxel_coord; } else{ if( the_intersection_index_ref.point_index < back ){ int control_index = ( Polygon_Intersections.size() - ( back - the_intersection_index_ref.point_index ) ); if( control_index < 0 ){ assert(0); // This must never happen. Probably the contour consists of just one point. Each point has already been regarded. That does not make any sense in radiotherapy. } coordinates_return = Polygon_Intersections.at( Polygon_Intersections.size() - ( back - the_intersection_index_ref.point_index ) ).contour_point_voxel_coord; } if( ! ( ( the_intersection_index_ref.point_index ) < ( Polygon_Intersections.size() + back ) ) ){ assert(0); // that can't be right the_intersection_index_ref.point_index must have been initially unreasonable } } return coordinates_return; } LegacyWorldCoordinate3D IterativePolygonInTermsOfIntersections::GetFirstPointThisPolygon( IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ LegacyWorldCoordinate3D first_one_this_Polygon(0,0,0); if( Polygon_Intersections.size() > 0 ){ first_one_this_Polygon = Polygon_Intersections.at( 0 ).contour_point_voxel_coord; return first_one_this_Polygon; } else{ assert(0); // exception implementieren } return first_one_this_Polygon; } void IterativePolygonInTermsOfIntersections::ResetIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_set_to ){ current_index_internal.point_index = intersection_set_to.point_index ; current_index_internal.intersection_index = intersection_set_to.intersection_index ; current_index_internal.column_raw_or_unified = intersection_set_to.column_raw_or_unified ; } // index goes in for debug and will be removed later ... bool IterativePolygonInTermsOfIntersections::RunForwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref , LegacyDoseVoxelIndex3D the_dose_index ){ bool success = false; bool done = false; bool success_first_increment = false; RememberPosition(); if( ThisIntersection( point_of_interest_start_ref ) ){ snippet_intermediate_content_ref.clear(); if( ! CloseWithoutIncrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ) ){ PeriodicPolygonPointIncrement(); AppendThisIntermediatePoint( snippet_intermediate_content_ref ); while( !done ){ // done = AppendIntermediatePointOrCloseForward( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref ); done = CloseWithoutIncrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); if( !done ){ PeriodicPolygonPointIncrement(); AppendThisIntermediatePoint( snippet_intermediate_content_ref ); } } } } else assert(0); CleanOut( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); JumpToRememberedPosition(); return success; } void IterativePolygonInTermsOfIntersections::CleanOut( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ if( snippet_intermediate_content_ref.size() > 0 ){ bool im_done_a = false; while( (!im_done_a) && (snippet_intermediate_content_ref.size() > 0) ){ if( ( point_of_interest_start_ref.x == snippet_intermediate_content_ref.at( 0 ).x ) && ( point_of_interest_start_ref.y == snippet_intermediate_content_ref.at( 0 ).y ) )snippet_intermediate_content_ref.erase( snippet_intermediate_content_ref.begin() ); else im_done_a = true; } bool im_done_b = false; while( (!im_done_b) && (snippet_intermediate_content_ref.size() > 0) ){ if( ( point_of_interest_end_ref.x == snippet_intermediate_content_ref.at( snippet_intermediate_content_ref.size() - 1 ).x ) && ( point_of_interest_end_ref.y == snippet_intermediate_content_ref.at( snippet_intermediate_content_ref.size() - 1 ).y ) )snippet_intermediate_content_ref.pop_back(); else im_done_b = true; } } } bool IterativePolygonInTermsOfIntersections::RunBackwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ bool success = false; bool done = false; bool success_first_increment = false; RememberPosition(); if( ThisIntersection( point_of_interest_start_ref ) ){ snippet_intermediate_content_ref.clear(); if( ! CloseWithoutDecrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ) ){ AppendThisIntermediatePoint( snippet_intermediate_content_ref ); PeriodicPolygonPointDecrement(); while( ( !done ) ){ done = CloseWithoutDecrement( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); if( !done ){ AppendThisIntermediatePoint( snippet_intermediate_content_ref ); PeriodicPolygonPointDecrement(); } } } } else assert(0); // This must never happen ! CleanOut( point_of_interest_start_ref, point_of_interest_end_ref , snippet_intermediate_content_ref ); JumpToRememberedPosition(); return success; } bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseForward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ bool got_it = false; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() != 0 ){ while( current_index_internal.intersection_index < ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ){ current_index_internal.intersection_index++; LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); } if( ( static_cast( point_of_interest_start_ref.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at(0).x) ) || ( static_cast( point_of_interest_start_ref.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at(0).y ) ) ){ got_it = true; point_of_interest_end_ref = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( 0 ); snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); } else{ // Anmerkung : man kann die else Bedingung auch oben in die if Bedingung mit reinpacken, je nachdem, was der code-reviewer leserlicher findet // sie sind gleich. Die Frage ist nun, ob es Zwischenpunkte gab, ob die Punkte also noch, oder wieder gleich sind. if( snippet_intermediate_content_ref.size() > 0 ){ got_it = true; point_of_interest_end_ref = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( 0 ); snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); } } } else{ snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); } return got_it; } bool IterativePolygonInTermsOfIntersections::AppendIntermediatePointOrCloseBackward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ if( current_index_internal.intersection_index != ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ) assert(0); //this should not happen while( current_index_internal.intersection_index > 0 ){ current_index_internal.intersection_index--; LegacyWorldCoordinate2D point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) && ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ point_of_interest_end_ref = point_of_interest; return true; } } snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); return false; } void IterativePolygonInTermsOfIntersections::AppendThisIntermediatePoint( std::vector& snippet_intermediate_content_ref ){ snippet_intermediate_content_ref.push_back( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord ); } bool IterativePolygonInTermsOfIntersections::IncrementNeeded(){ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() <= ( current_index_internal.intersection_index + 1 ) ) return true; return false; } bool IterativePolygonInTermsOfIntersections::DecrementNeeded(){ bool is_needed = false; if( current_index_internal.intersection_index < 1 ) is_needed = true; return is_needed; } bool IterativePolygonInTermsOfIntersections::CloseWithoutIncrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ LegacyWorldCoordinate2D point_of_interest; if( CheckIndex() ){ point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ) || OneDiffers( snippet_intermediate_content_ref , point_of_interest_start_ref ) ){ point_of_interest_end_ref = point_of_interest; return true; } } if( ! IncrementNeeded() ){ while( current_index_internal.intersection_index < ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ) ){ current_index_internal.intersection_index++; point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ point_of_interest_end_ref = point_of_interest; return true; } } return false; } else return false; } bool IterativePolygonInTermsOfIntersections::OneDiffers( std::vector& snippet_intermediate_content_ref , LegacyWorldCoordinate2D& point_of_interest_start_ref ){ for( GridIndexType i = 0 ; i < snippet_intermediate_content_ref.size() ; i++ ){ LegacyWorldCoordinate3D a_point = snippet_intermediate_content_ref.at( i ); if( ( a_point.x != point_of_interest_start_ref.x ) || ( a_point.y != point_of_interest_start_ref.y ) )return true; } return false; } bool IterativePolygonInTermsOfIntersections::CloseWithoutDecrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ){ LegacyWorldCoordinate2D point_of_interest; if(CheckIndex()){ point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ) || OneDiffers( snippet_intermediate_content_ref , point_of_interest_start_ref ) ){ point_of_interest_end_ref = point_of_interest; return true; } } if( ! DecrementNeeded() ){ while( current_index_internal.intersection_index > 0 ){ current_index_internal.intersection_index--; point_of_interest = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( point_of_interest.x ) != static_cast( point_of_interest_start_ref.x ) ) || ( static_cast( point_of_interest.y ) != static_cast( point_of_interest_start_ref.y ) ) ){ point_of_interest_end_ref = point_of_interest; return true; } } return false; } else return false; } void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointIncrement(){ if( current_index_internal.point_index < ( Polygon_Intersections.size() - 1 ) ){ current_index_internal.point_index++; } else{ current_index_internal.point_index = 0; } current_index_internal.intersection_index = 0; } void IterativePolygonInTermsOfIntersections::PeriodicPolygonPointDecrement(){ if( current_index_internal.point_index > 0 ){ current_index_internal.point_index--; } else{ current_index_internal.point_index = ( Polygon_Intersections.size() - 1 ); } if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ; else current_index_internal.intersection_index = 0; } /// /// returns true, in case intersection /// bool IterativePolygonInTermsOfIntersections::CheckIsIntersection( LegacyWorldCoordinate2D& edge_coord , IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_ref ){ // Baustelle all control paths should return a value LegacyWorldCoordinate2D local_current_position = {0,0}; RememberPosition(); ResetIntersectionIndex(); bool was_able_to_increment = true; while( was_able_to_increment == true ){ // if( CheckToBeRegarded() ){ if( ThisIntersection( local_current_position ) ){ if( ( static_cast( edge_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( edge_coord.y ) == static_cast( local_current_position.y ) ) ){ IterativePolygonInTermsOfIntersections::WhichIntersection& current_index_internal_ref = current_index_internal; CopyIntersectionIndex( the_intersection_index_ref , current_index_internal_ref ); JumpToRememberedPosition(); return true; } } // } was_able_to_increment = IncremtentIntersection(); } JumpToRememberedPosition(); return false; } void IterativePolygonInTermsOfIntersections::CopyIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& from_ref ){ to_ref.point_index = from_ref.point_index; to_ref.intersection_index = from_ref.intersection_index; to_ref.column_raw_or_unified = from_ref.column_raw_or_unified; } bool IterativePolygonInTermsOfIntersections::IncremtentIntersection(){ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > ( current_index_internal.intersection_index + 1 ) ){ current_index_internal.intersection_index++; return true; } else{ bool success = false; while( success == false ){ if( Polygon_Intersections.size() > ( current_index_internal.point_index + 1 ) ){ current_index_internal.intersection_index = 0; current_index_internal.point_index++; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ return true; } } else return false; } } return false; } bool IterativePolygonInTermsOfIntersections::IncremtentIntersectionPeriodically(){ if( ( CheckIndex() ) && ( ThereAreIntersections() ) ){ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > ( current_index_internal.intersection_index + 1 ) ){ current_index_internal.intersection_index++; return true; } else{ bool success = false; while( success == false ){ if( Polygon_Intersections.size() > ( current_index_internal.point_index + 1 ) ){ current_index_internal.intersection_index = 0; current_index_internal.point_index++; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ return true; } } else{ current_index_internal.intersection_index = 0; current_index_internal.point_index = 0; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ return true; } } } } } else return false; return false; } bool IterativePolygonInTermsOfIntersections::CheckIndex(){ if( Polygon_Intersections.size() > current_index_internal.point_index ){ if( ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ) ){ return true; } else return false; } else return false; } // Caution : This function can end up with a bad intersedction index. bool IterativePolygonInTermsOfIntersections::DecrementPointOrIntersectionPeriodically(){ if( /*CheckIndex() &&*/ ( ThereAreIntersections() ) ){ if( 0 < ( current_index_internal.intersection_index ) ){ current_index_internal.intersection_index--; return true; } else{ if( ( 0 < ( current_index_internal.point_index ) ) ){ current_index_internal.point_index--; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; else current_index_internal.intersection_index = 0; return true; } else if( Polygon_Intersections.size() > 0 ){ current_index_internal.point_index = Polygon_Intersections.size() - 1; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ); else current_index_internal.intersection_index = 0; } else assert(0); // this should never happen since there are intersections, see ThereAreIntersections() } } else{ std::cout<< " could not decrement !!!!!!!" < 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; else current_index_internal.intersection_index = 0; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ return true; } } if( current_index_internal.point_index != 0 ){ assert(0); // This should never happen. } else if( Polygon_Intersections.size() > 0 ){ current_index_internal.point_index = Polygon_Intersections.size() - 1; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = ( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1 ); else{ while( ( 0 < ( current_index_internal.point_index ) ) ){ current_index_internal.point_index--; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ) current_index_internal.intersection_index = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() - 1; else current_index_internal.intersection_index = 0; if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > 0 ){ return true; } } assert(0); // should never get here, since there are interesections } } else assert(0); // this should never happen since there are intersections, see ThereAreIntersections() } } else return false; return false; } bool IterativePolygonInTermsOfIntersections::CheckToBeRegarded(){ return Polygon_Intersections.at( current_index_internal.point_index ).to_be_Regarded; } bool IterativePolygonInTermsOfIntersections::PreviousIntersectionPeriodically( LegacyWorldCoordinate2D& the_intersection ){ if( DecrementIntersectionPeriodically() ){ the_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); return true; } else{ the_intersection.x =0; the_intersection.y = 0; return false; } return false; } bool IterativePolygonInTermsOfIntersections::IsInside( LegacyWorldCoordinate3D& point_check , LegacyDoseVoxelIndex3D& the_dose_index ){ if( ( point_check.x > the_dose_index.x ) && ( point_check.x < ( the_dose_index.x + 1 ) ) && ( point_check.y > the_dose_index.y ) && ( point_check.y < ( the_dose_index.y + 1 ) ) ){ return true; } else return false; } bool IterativePolygonInTermsOfIntersections::ThisIntersection( LegacyWorldCoordinate2D& the_intersection ){ if( CheckIndex() ){ the_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); return true; } else{ the_intersection.x =0; the_intersection.y = 0; return false; } } void IterativePolygonInTermsOfIntersections::ShowSelf(){ if( Polygon_Intersections.size() > 0 ){ for( GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++ ){ std::cout<< " Polygon_Intersections.at( counter ).contour_point_voxel_coord.z : " << Polygon_Intersections.at( counter ).contour_point_voxel_coord.z <= 78 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.x <= 79 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.y >= 70 ) && ( Polygon_Intersections.at( counter ).contour_point_voxel_coord.y <= 71 ) ){ std::cout<< " Polygon_Intersections.at( counter ).contour_point_voxel_coord.x : " << Polygon_Intersections.at( counter ).contour_point_voxel_coord.x <= 78 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).x <= 79 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).y >= 70 ) && ( Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).y <= 71 ) ){ std::cout<< " Polygon bla ns_raw_and_column.at( internal_counter ).x : " << Polygon_Intersections.at( counter ).intersections_raw_and_column.at( internal_counter ).x <( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) ) ){ //Hier erst den Kontur-Punkt anschauen //erst wenn der nicht geht, dann schauen, ob es einen Schnittpunkt gibt und den Pruefen. //Dabei darauf achten, //dass der current_index_internal.intersection_index null sein kann, obwohl es kein nulltes Element gibt !! next_point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; next_point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; if( ( static_cast( previous_point_or_intersection.x ) != static_cast( next_point_or_intersection.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( next_point_or_intersection.y ) ) ) return true; } else{ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() <= current_index_internal.intersection_index ) assert(0); // this should never happen, since IncrementIntersection should not end up with a bad index next_point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( previous_point_or_intersection.x ) != static_cast( next_point_or_intersection.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( next_point_or_intersection.y ) ) ) return true; } } else{ assert(0); return false; } return false; } bool IterativePolygonInTermsOfIntersections::PreviousPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ){ if( /*( IsInside( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord , the_dose_index ) ) && */ ( current_index_internal.intersection_index == 0 ) && ( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) ) ){ point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; } else{ if( DecrementPointOrIntersectionPeriodically() ){ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ){ point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; } else{ point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; } } else{ bool decrement = true; while(decrement){ decrement = DecrementPointOrIntersectionPeriodically(); if( decrement ){ if( Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.size() > current_index_internal.intersection_index ){ point_or_intersection = Polygon_Intersections.at( current_index_internal.point_index ).intersections_raw_and_column.at( current_index_internal.intersection_index ); if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; } else{ point_or_intersection.x =Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x; point_or_intersection.y = Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y; if( ( static_cast( previous_point_or_intersection.x ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.x ) ) || ( static_cast( previous_point_or_intersection.y ) != static_cast( Polygon_Intersections.at( current_index_internal.point_index ).contour_point_voxel_coord.y ) ) )return true; } } } assert(0); // this must not happen } return false; } return false; } int IterativePolygonInTermsOfIntersections::MaximumNumberOfElements(){ if( number_of_intersections == (-1) ){ int resulting_number = 0; for( GridIndexType counter = 0 ; counter < Polygon_Intersections.size() ; counter++ ){ resulting_number += Polygon_Intersections.at( counter ).intersections_raw_and_column.size(); } number_of_intersections = resulting_number; return number_of_intersections; } else return number_of_intersections; } bool IterativePolygonInTermsOfIntersections::ThereAreIntersections(){ if( number_of_intersections == (-1) ) number_of_intersections = MaximumNumberOfElements(); if( number_of_intersections > 0 )return true; else return false; } void IterativePolygonInTermsOfIntersections::CreateUnifiedListOfRawAndColumnIntersections(){ // iteration along polygon for( unsigned int point_index = 0 ; point_index < ( Polygon_Intersections.size() ); point_index++ ){ if( Polygon_Intersections.at( point_index ).intersections_raw_and_column.size() == 0 ){ bool do_continue = true; Polygon_Intersections.at( point_index ).intersections_raw_and_column.clear(); unsigned int raw_index = 0; unsigned int column_index = 0; LegacyWorldCoordinate3D coordinates_return = Polygon_Intersections.at( point_index ).contour_point_voxel_coord; std::vector raw_intersections_work = Polygon_Intersections.at( point_index ).raw_intersections; std::vector& raw_intersections_work_ref = raw_intersections_work; std::vector column_intersections_work = Polygon_Intersections.at( point_index ).column_intersections; std::vector& column_intersections_work_ref = column_intersections_work; double last_distance = -1; while( do_continue ){ LegacyWorldCoordinate2D coordinates_raw_intersection; coordinates_raw_intersection.x =0; coordinates_raw_intersection.y = 0; LegacyWorldCoordinate2D coordinates_column_intersection; coordinates_column_intersection.x =0; coordinates_column_intersection.y = 0; LegacyWorldCoordinate2D coordinates_final_intersection; coordinates_final_intersection.x =0; coordinates_final_intersection.y = 0; double distance_raw = 1000000000; double distance_column = 1000000000; if( raw_intersections_work.size() > 0 ){ coordinates_raw_intersection = raw_intersections_work.at( 0 ); distance_raw = ( coordinates_raw_intersection.x - coordinates_return.x ) * ( coordinates_raw_intersection.x - coordinates_return.x ) + ( coordinates_raw_intersection.y - coordinates_return.y ) * ( coordinates_raw_intersection.y - coordinates_return.y ); distance_raw = sqrt( distance_raw ); if( distance_raw < last_distance )assert(0); // this must never happen } if( column_intersections_work.size() > 0 ){ coordinates_column_intersection = column_intersections_work.at( 0 ); distance_column = ( coordinates_column_intersection.x - coordinates_return.x ) * ( coordinates_column_intersection.x - coordinates_return.x ) + ( coordinates_column_intersection.y - coordinates_return.y ) * ( coordinates_column_intersection.y - coordinates_return.y ); distance_column = sqrt( distance_column ); if( distance_column < last_distance )assert(0); // this must never happen } if( ( distance_raw != 1000000000 ) && ( distance_column != 1000000000 ) ){ if( distance_raw < distance_column ){ coordinates_final_intersection = raw_intersections_work.at( raw_index ); Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); last_distance = distance_raw; } else if( distance_raw > distance_column ){ coordinates_final_intersection = column_intersections_work.at( column_index ); Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); last_distance = distance_column; } else if( distance_raw == distance_column ){ coordinates_final_intersection = column_intersections_work.at( column_index ); Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); // man muss diesen Punkt nicht zweimal beachten. // deshalb nicht : Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); last_distance = distance_column; } } else if( distance_raw != 1000000000 ){ coordinates_final_intersection = raw_intersections_work.at( raw_index ); Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_raw_intersection ); last_distance = distance_raw; } else if( distance_column != 1000000000 ){ coordinates_final_intersection = column_intersections_work.at( column_index ); Polygon_Intersections.at( point_index ).intersections_raw_and_column.push_back( coordinates_column_intersection ); last_distance = distance_column; } else{ do_continue = false; } /* std::cout << " Here are the values : " << std::endl; std::cout << " coordinates_return.x : " << coordinates_return.x << std::endl; std::cout << " coordinates_return.y : " << coordinates_return.y << std::endl; std::cout << " coordinates_final_intersection.x : " << coordinates_final_intersection.x << std::endl; std::cout << " coordinates_final_intersection.y : " << coordinates_final_intersection.y << std::endl; for( int counter = 0 ; counter < Polygon_Intersections.at( point_index ).intersections_raw_and_column.size() ; counter++ ){ std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).x << std::endl; std::cout << " Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y : " << Polygon_Intersections.at( point_index ).intersections_raw_and_column.at( counter ).y << std::endl; } for( int counter = 0 ; counter < raw_intersections_work.size() ; counter++ ){ std::cout << " raw_intersections_work.at( counter ).x : " << raw_intersections_work.at( counter ).x << std::endl; std::cout << " raw_intersections_work.at( counter ).y : " << raw_intersections_work.at( counter ).y << std::endl; } for( int counter = 0 ; counter < column_intersections_work.size() ; counter++ ){ std::cout << " column_intersections_work.at( counter ).x : " << column_intersections_work.at( counter ).x << std::endl; std::cout << " column_intersections_work.at( counter ).y : " << column_intersections_work.at( counter ).y << std::endl; } */ if( ( distance_raw != 1000000000 ) || ( distance_column != 1000000000 ) ) removeThisCoordinateFromBothLists( coordinates_final_intersection , raw_intersections_work_ref , column_intersections_work_ref ); } } } } void IterativePolygonInTermsOfIntersections::removeThisCoordinateFromBothLists( LegacyWorldCoordinate2D the_coordinate , std::vector& raw_intersections_work_ref , std::vector& column_intersections_work_ref ){ LegacyWorldCoordinate2D coordinates_this_intersection; coordinates_this_intersection.x =0; coordinates_this_intersection.y = 0; std::vector::iterator iter; for( GridIndexType counter = 0 ; counter < raw_intersections_work_ref.size() ; counter++ ){ coordinates_this_intersection = raw_intersections_work_ref.at( counter ); if( ( coordinates_this_intersection.x == the_coordinate.x ) && ( coordinates_this_intersection.y == the_coordinate.y ) ){ iter = raw_intersections_work_ref.begin(); raw_intersections_work_ref.erase( iter ); } else break; } for( GridIndexType counter = 0 ; counter < column_intersections_work_ref.size() ; counter++ ){ coordinates_this_intersection = column_intersections_work_ref.at( counter ); if( ( coordinates_this_intersection.x == the_coordinate.x ) && ( coordinates_this_intersection.y == the_coordinate.y ) ){ iter = column_intersections_work_ref.begin(); column_intersections_work_ref.erase( iter ); } else break; } } bool IterativePolygonInTermsOfIntersections::ItIsAsExpected( masks::legacy::PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ){ if( Expected_Unified_Polygon_Intersections.size() != Polygon_Intersections.size() ) return false; for( GridIndexType a_counter = 0 ; a_counter < Expected_Unified_Polygon_Intersections.size() ; a_counter++ ){ if( ! IdenticalUniList( Expected_Unified_Polygon_Intersections.at( a_counter ) , Polygon_Intersections.at( a_counter ) ) ) return false; } return true; } bool IterativePolygonInTermsOfIntersections::IdenticalUniList( masks::legacy::PointLevelVector plv_a , masks::legacy::PointLevelVector plv_b ){ if( plv_a.intersections_raw_and_column.size() != plv_b.intersections_raw_and_column.size() ) return false; LegacyWorldCoordinate2D wco2da; wco2da.x =0; wco2da.y = 0; LegacyWorldCoordinate2D wco2db; wco2db.x =0; wco2db.y = 0; for( GridIndexType this_counter = 0 ; this_counter < plv_a.intersections_raw_and_column.size() ; this_counter++ ){ wco2da = plv_a.intersections_raw_and_column.at( this_counter ); wco2db = plv_b.intersections_raw_and_column.at( this_counter ); if( ( static_cast( wco2da.x ) != static_cast( wco2db.x ) ) || ( static_cast( wco2da.y ) != static_cast( wco2db.y ) ) ) return false; } return true; } void IterativePolygonInTermsOfIntersections::RememberPosition(){ IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal_remember; IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = current_index_internal; CopyIntersectionIndex( intersection_index_to_ref , intersection_index_from_ref ); } void IterativePolygonInTermsOfIntersections::JumpToRememberedPosition(){ IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref = current_index_internal_remember; IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal; CopyIntersectionIndex( intersection_index_to_ref , intersection_index_from_ref ); } void IterativePolygonInTermsOfIntersections::SetCurrentIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_new_ref ){ IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref = current_index_internal; CopyIntersectionIndex( intersection_index_to_ref , intersection_index_new_ref ); } bool IterativePolygonInTermsOfIntersections::CheckCurrentIntersectionIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref ){ if( ( current_index_internal.point_index == intersection_index_compare_ref.point_index ) && ( current_index_internal.intersection_index == intersection_index_compare_ref.intersection_index ) ){ return true; } else{ return false; } } void IterativePolygonInTermsOfIntersections::MarkRelevantItems( LegacyDoseVoxelIndex3D aDoseIndex ){ WhichIntersection the_intersection_index; // the_intersection_index initialized to zero by constructor for( the_intersection_index.point_index = 0 ; the_intersection_index.point_index < ( Polygon_Intersections.size() ) ; the_intersection_index.point_index++ ){ Polygon_Intersections.at( the_intersection_index.point_index ).to_be_Regarded = false; } for( the_intersection_index.point_index = 0 ; the_intersection_index.point_index < ( Polygon_Intersections.size() - 1 ) ; the_intersection_index.point_index++ ){ LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at( the_intersection_index.point_index ).contour_point_voxel_coord; LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at( the_intersection_index.point_index + 1 ).contour_point_voxel_coord; if( VoxelInBetween( aDoseIndex , wc3da , wc3db ) ){ Polygon_Intersections.at( the_intersection_index.point_index ).to_be_Regarded = true; Polygon_Intersections.at( the_intersection_index.point_index + 1 ).to_be_Regarded = true; } } if( Polygon_Intersections.size() > 0 ){ LegacyWorldCoordinate3D wc3da = Polygon_Intersections.at( ( Polygon_Intersections.size() - 1 ) ).contour_point_voxel_coord; LegacyWorldCoordinate3D wc3db = Polygon_Intersections.at( 0 ).contour_point_voxel_coord; if( VoxelInBetween( aDoseIndex , wc3da , wc3db ) ){ Polygon_Intersections.at( ( Polygon_Intersections.size() - 1 ) ).to_be_Regarded = true; Polygon_Intersections.at( 0 ).to_be_Regarded = true; } } } bool IterativePolygonInTermsOfIntersections::VoxelInBetween( LegacyDoseVoxelIndex3D aDoseIndex , LegacyWorldCoordinate3D wc3da, LegacyWorldCoordinate3D wc3db ){ LegacyWorldCoordinate3D wc3dc_min; LegacyWorldCoordinate3D wc3dc_max; if( wc3da.x <= wc3db.x ){ wc3dc_min.x =wc3da.x; wc3dc_max.x =wc3db.x; } else{ wc3dc_min.x =wc3db.x; wc3dc_max.x =wc3da.x; } if( static_cast(wc3dc_min.x) > static_cast( aDoseIndex.x + 1.1 ) ) return false; if( static_cast(wc3dc_max.x) < static_cast( aDoseIndex.x - 0.1 ) ) return false; if( wc3da.y <= wc3db.y ){ wc3dc_min.y = wc3da.y; wc3dc_max.y = wc3db.y; } else{ wc3dc_min.y = wc3db.y; wc3dc_max.y = wc3da.y; } if( static_cast(wc3dc_min.y) > static_cast( aDoseIndex.y + 1.1 ) ) return false; if( static_cast(wc3dc_max.y) < static_cast( aDoseIndex.y - 0.1 ) ) return false; if( wc3da.z <= wc3db.z ){ wc3dc_min.z = wc3da.z; wc3dc_max.z = wc3db.z; } else{ wc3dc_min.z = wc3db.z; wc3dc_max.z = wc3da.z; } if( static_cast(wc3dc_min.z) > static_cast( aDoseIndex.z + 1.1 ) ) return false; // it can not be in between if( static_cast(wc3dc_max.z) < static_cast( aDoseIndex.z - 0.1 ) ) return false; return true; // can't be sure } }//namespace }//namespace }//namespace diff --git a/code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.h b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h similarity index 95% rename from code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.h rename to code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h index 3cc2c35..c37ce2a 100644 --- a/code/masks/rttbIterativePolygonInTermsOfIntersections_LEGACY.h +++ b/code/masks/legacy/rttbIterativePolygonInTermsOfIntersections_LEGACY.h @@ -1,151 +1,151 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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 __IterativePolygonInTermsOfIntersections_H #define __IterativePolygonInTermsOfIntersections_H #include "rttbBaseType.h" #include "rttbStructure.h" #include "rttbDoseIteratorInterface.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" // sollen Typen in Core neu definiert werden? #include "rttbContour_LEGACY.h" #include #include namespace rttb{ namespace masks{ namespace legacy{ // Die folgende Klasse handhabt die konkrete Speicherung der Schnittpunkte. // Kennt sich also mit der Speicherung der Schnittpunkte der Konturen mit den Voxelkanten aus. // Information auf Struktur-Polygonebene. // Nimmt PolygonInfo den Zugriff auf diese Information ab. class IterativePolygonInTermsOfIntersections{ public: IterativePolygonInTermsOfIntersections(); ~IterativePolygonInTermsOfIntersections(){}; void MarkRelevantItems( LegacyDoseVoxelIndex3D aDoseIndex ); bool ItIsAsExpected( masks::legacy::PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ); bool CheckToBeRegarded(); void ShowSelf(); class WhichIntersection{ public: WhichIntersection(){ point_index = 0; intersection_index = 0; column_raw_or_unified = 0; } ~WhichIntersection(){}; unsigned int point_index; unsigned int intersection_index; unsigned int column_raw_or_unified; // 0 bedeutet Spalte, 1 bedeutet Zeile und 2 bedeutet vereinheitlichte Liste der Zeilen uns Spaltenschnittpunkte }; void ResetIntersectionIndex(); bool ThisIntersection( LegacyWorldCoordinate2D& the_intersection ); void RememberPosition(); bool IncremtentIntersection(); bool IncremtentIntersectionPeriodically(); bool NextIntersectionPeriodically( LegacyWorldCoordinate2D& the_next_intersection ); bool NextPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& next_point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ); int MaximumNumberOfElements(); bool ThereAreIntersections(); void JumpToRememberedPosition(); bool RunForwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref , LegacyDoseVoxelIndex3D the_dose_index ); bool RunBackwardToNextIntersection( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); void CleanOut( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); bool NextIntersection( LegacyWorldCoordinate2D& the_next_intersection ); bool PreviousPointOrIntersectionPeriodically( LegacyWorldCoordinate2D& previous_point_or_intersection , LegacyWorldCoordinate2D& point_or_intersection , LegacyDoseVoxelIndex3D& the_dose_index ); bool PreviousIntersectionPeriodically( LegacyWorldCoordinate2D& the_intersection ); void ResetIntersectionIndex( WhichIntersection& intersection_set_to ); void SetIntersectionsAndResetIntersectionIndex( const masks::legacy::PolygonInTermsOfIntersections& Polygon_Intersections_In ); bool CheckIsIntersection( LegacyWorldCoordinate2D& edge_coord , WhichIntersection& the_intersection_index_ref ); LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinates( WhichIntersection& the_intersection_index_ref ); LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesFurther( WhichIntersection& the_intersection_index_ref , int ahead ); LegacyWorldCoordinate3D GetRestpectivePologonPointInVoxelCoordinatesPrevious( WhichIntersection& the_intersection_index_ref , unsigned int back ); bool selfTest(); bool CheckCurrentIndexInitForTest(); void SetCurrentIntersectionIndex( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_new_ref ); bool CheckCurrentIntersectionIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_compare_ref ); void PrintIntersectionIndex(); private: unsigned int GetRestpectiveIntersectionVectorLength( WhichIntersection& the_intersection_index_ref ); LegacyWorldCoordinate2D GetRestpectiveIntersection( WhichIntersection& the_intersection_index_ref ); LegacyWorldCoordinate2D GetRestpectiveIntersectionFurther( WhichIntersection& the_intersection_index_ref , int ahead ); bool PointIndexIsFine( WhichIntersection& the_intersection_index_ref ); LegacyWorldCoordinate3D GetFirstPointThisPolygon( WhichIntersection& the_intersection_index_ref ); bool AppendIntermediatePointOrCloseForward( LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); bool AppendIntermediatePointOrCloseBackward(LegacyWorldCoordinate2D& point_of_interest_start_ref , LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); void AppendThisIntermediatePoint( std::vector& snippet_intermediate_content_ref ); bool IncrementNeeded(); bool DecrementNeeded(); bool OneDiffers( std::vector& snippet_intermediate_content_ref , LegacyWorldCoordinate2D& point_of_interest_start_ref ); bool IdenticalUniList( masks::legacy::PointLevelVector plv_a , masks::legacy::PointLevelVector plv_b ); bool CloseWithoutIncrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); bool CloseWithoutDecrement( LegacyWorldCoordinate2D& point_of_interest_start_ref, LegacyWorldCoordinate2D& point_of_interest_end_ref , std::vector& snippet_intermediate_content_ref ); void PeriodicPolygonPointIncrement(); void PeriodicPolygonPointDecrement(); void CopyIntersectionIndex( WhichIntersection& to_ref , WhichIntersection& from_ref ); bool CheckIndex(); bool DecrementPointOrIntersectionPeriodically(); bool DecrementIntersectionPeriodically(); void CreateUnifiedListOfRawAndColumnIntersections(); void removeThisCoordinateFromBothLists( LegacyWorldCoordinate2D the_coordinate , std::vector& raw_intersections_work_ref , std::vector& column_intersections_work_ref ); bool VoxelInBetween( LegacyDoseVoxelIndex3D aDoseIndex , LegacyWorldCoordinate3D wc3da, LegacyWorldCoordinate3D wc3db ); bool IsInside( LegacyWorldCoordinate3D& point_check , LegacyDoseVoxelIndex3D& the_dose_index ); PolygonInTermsOfIntersections Polygon_Intersections; WhichIntersection current_index_internal; WhichIntersection current_index_internal_remember; int number_of_intersections; }; } } } #endif \ No newline at end of file diff --git a/code/masks/rttbMask.cpp b/code/masks/legacy/rttbMask.cpp similarity index 97% rename from code/masks/rttbMask.cpp rename to code/masks/legacy/rttbMask.cpp index bdeb4e2..6678759 100644 --- a/code/masks/rttbMask.cpp +++ b/code/masks/legacy/rttbMask.cpp @@ -1,3721 +1,3721 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include "rttbMask.h" #include "rttbNullPointerException.h" #include "rttbSelfIntersectingStructureException.h" #include #include #include #include #include using namespace std; namespace rttb{ namespace masks{ namespace legacy{ Mask::Mask( DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure ) { MaskField.resize(1); for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; FieldOfIntersections = NULL; do_detailed_subvox = false; this->_doseIter=aDoseIter; this->_structure=aStructure; //this->_withSubVoxelFraction=withSubVoxelFraction; if(!_doseIter) throw core::NullPointerException("aDoseIter must not be NULL!"); if(!_structure) throw core::NullPointerException("aStructure must not be NULL!"); this->_doseIter->start(); this->GInf.push_back( _doseIter->getGeometricInfo() ); //std::cout << "init begin"<~FieldOfScalar(); //MaskField.resize(0); sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); this->calcDoseData(); this->clearMaskField(); } Mask::Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure ) { if(!aDoseGeoInfo){ throw core::NullPointerException("aDoseGeoInfo must not be NULL!"); } MaskField.resize(1); for(int i = 0 ; i < MaskField.size() ; i++ ) { MaskField.at(i) = NULL; } FieldOfIntersections = NULL; do_detailed_subvox = false; if(!aStructure){ throw core::NullPointerException("aStructure must not be NULL!"); } this->_structure=aStructure; //this->_withSubVoxelFraction=withSubVoxelFraction; this->GInf.push_back( *aDoseGeoInfo ); //std::cout << "init begin"<~FieldOfScalar(); //MaskField.resize(0); sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); this->clearMaskField(); } /* Mask::Mask(rttb::core::DoseIteratorInterface *aDoseIter, const std::vector& aDoseVoxelVector){ _structure=NULL; FieldOfIntersections = NULL; do_detailed_subvox = false; MaskField.resize(1); for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; _doseIter=aDoseIter; if(!_doseIter) throw core::NullPointerException("aDoseIter must not be NULL!"); this->_doseIter->start(); this->GInf.push_back( _doseIter->getGeometricInfo() ); //Get valid DoseVoxel for(int i=0;icalcDoseData(); this->clearMaskField(); } */ Mask::~Mask(){ /*if( FieldOfIntersections != NULL )FieldOfIntersections->~FieldOfPointer(); for( int i = 0 ; i < MaskField.size() ; i++ ){ if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); } MaskField.resize(1); for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL;*/ } void Mask::clearMaskField(){ if( FieldOfIntersections != NULL )FieldOfIntersections->~FieldOfPointer(); for( int i = 0 ; i < MaskField.size() ; i++ ){ if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); } MaskField.resize(1); for(int i = 0 ; i < MaskField.size() ; i++ )MaskField.at(i) = NULL; } void Mask::resetDose(DoseIteratorInterface* aDoseIterator){ _doseIter=aDoseIterator; if(!_doseIter) throw core::NullPointerException("aDoseIter must not be NULL!"); this->_doseIter->start(); //if geometric info not changed or if the voxelization external if(_doseIter->getGeometricInfo()==this->GInf.at(0) || this->_structure==NULL){ //std::cout << "reset dose."<calcDoseData(); } else{ //std::cout << "recalculate mask"<GInf.push_back( _doseIter->getGeometricInfo() ); Init(); Calc(); sort(_doseVoxelInStructure.begin(),_doseVoxelInStructure.end()); this->calcDoseData(); this->clearMaskField(); } } /*const std::vector& Mask::getDoseVoxelIndexInStructure() const{ return doseVoxelIndexInStructure; }*/ /*! @brief Get the dose voxels which lie inside the structure * @return Return the vector of DoseVoxel which are inside the structure (with voxel proportion information) */ const std::vector& Mask::getDoseVoxelInStructure() const{ return this->_doseVoxelInStructure; } /*! @brief Set the dose voxels which lie inside the structure * @return Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) */ void Mask::setDoseVoxelInStructure(std::vector aDoseVoxelVector){ _doseVoxelInStructure=aDoseVoxelVector; } const DoseIteratorInterface& Mask::getDoseIterator() const{ return *_doseIter; } const StructureLegacy& Mask::getRTStructure() const{ return *_structure; } /*const std::vector Mask::getDoseData() const{ return _doseData; }*/ //get absolute dose data of the voxels which are inside the structure; void Mask::calcDoseData(){ _doseData.clear(); /*this->_doseIter->start(); std::vector doseDis;//dose distribution while(_doseIter->hasNextVoxel()){ doseDis.push_back(_doseIter->next()); }*/ _doseIter->start(); int count=0; std::vector::iterator it=_doseVoxelInStructure.begin(); while(_doseIter->hasNextVoxel() && it!=_doseVoxelInStructure.end()){ // Anmerkung von Martina fuer Lanlan: Eigentlich ist der Witz beim Iterator gerade, dass man sich ueber die // Innereien des Iterators als Programmierer, der ihn einsetzt keine Gedanken machen muss. Hier ist die fehlerfreie Funktion // des Codes jedoch von einigen Eigenschaften des Iterators, insbesondere von der Richtung in der iteriert wird, // abhaengig. Das kommt daher, dass der Programmierer den Iterator von innen kannte und Eigenschaften nutzt, die er eigentlich // nicht kennem wuerde, als Anwendungsprogrammierer des Iterators. Weil der Programmierer den Iterator aber selbst geschrieben hatte, // deshalb wuste er es hier ... // Das kann zur Folgen haben, dass nach einer Aenderung in Code des Iterators Mask nicht mehr korrekt // funktioniert (z.B. wenn die Richtung der iteration im Koordinatensystem sich umkehren wuerde) man kann darueber // nachdenken ob das problematisch ist .... // Es ist ja auch so, dass die RTToolbox dafuer gemacht ist erweitert zu werden. Es koennen andere Iteratoren dazu kommen. // Wollen wir hier spezifischer werden was den Typ des erlaubten Iterators betrifft? Das wuerde helfen. double doseValue=_doseIter->next(); LegacyDoseVoxelIndex3D doseVoxel=(*it).getVoxelIndex3D(); if(count==doseVoxel.z*GInf.at(0).getNumColumns()*GInf.at(0).getNumRows()+doseVoxel.y*GInf.at(0).getNumColumns()+doseVoxel.x){ _doseData.push_back(doseValue); it++; } count++; } } void Mask::Calc(){ //std::cout << "calc begin"<= 0 ; resolution_level-- ){ //std::cout << "GetIntersections"<= 0 ; resolution_level-- ){ for( int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ LegacyUnsignedIndex3D index_internal; index_internal.x = 0; index_internal.y = 0; index_internal.z = index_z; for( int resolution_level = ( GInf.size() - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ if( ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y != 0 ) ){ for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x ; index_internal.x++ ){ for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y ; index_internal.y++ ){ if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_inside ){ CheckUppwardBlockSameIntensity( resolution_level , index_internal, brightness_inside ); } if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_outside ){ CheckUppwardBlockSameIntensity( resolution_level , index_internal, brightness_outside ); } if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_border ){ CheckUppwardOneOutOfThisBlockHasSameIntensity( resolution_level , index_internal , brightness_border ); } if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) == brightness_unknown )assert(0); // This should not happen since each voxel must be regarded. } // for( index_internal.y } // for( index_internal.x } // if( ( MarkInterestingArea.at(resolution_level).at( index_z } // for( int resolution_level } } // resolution_level } void Mask::CheckUppwardBlockSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ if( resolution_level_in > 0 ){ for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ int resolution_difference = ( resolution_level_in - resolution_level ); double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); LegacyUnsignedIndex3D index_internal; index_internal.x = index_in.x * block_length; index_internal.y = index_in.y * block_length; index_internal.z = index_in.z; if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ bool its_fine = MaskField.at( resolution_level )->CheckBlockSameIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); assert( its_fine ); } } } } } void Mask::SetUppwardBlockThisIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ if( resolution_level_in > 0 ){ for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ int resolution_difference = ( resolution_level_in - resolution_level ); double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); LegacyUnsignedIndex3D index_internal; index_internal.x = index_in.x * block_length; index_internal.y = index_in.y * block_length; index_internal.z = index_in.z; if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ MaskField.at( resolution_level )->SetBlockThisIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); } } } } } void Mask::CheckUppwardOneOutOfThisBlockHasSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_in , int brightness ){ if( ( resolution_level_in > 0 ) && ( resolution_level_in < (MaskField.size()-1) ) ){ for( int resolution_level = ( resolution_level_in - 1 ) ; resolution_level >= 0 ; resolution_level-- ){ int resolution_difference = ( resolution_level_in - resolution_level ); double block_length = GetBlockLengthThisResolutionLevel( resolution_difference ); LegacyUnsignedIndex3D index_internal; index_internal.x = index_in.x * block_length; index_internal.y = index_in.y * block_length; index_internal.z = index_in.z; if( ( index_internal.x >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.x ) && ( index_internal.x <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.x - block_length ) ) && ( index_internal.y >= MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_begin.y ) && ( index_internal.y <= ( MarkInterestingArea.at(resolution_level).at( index_internal.z ).index_end.y - block_length ) ) ){ if( ( index_in.x >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.x ) && ( index_in.x <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.x - block_length ) ) && ( index_in.y >= MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_begin.y ) && ( index_in.y <= ( MarkInterestingArea.at(resolution_level_in).at( index_in.z ).index_end.y - block_length ) ) ){ bool its_fine = MaskField.at( resolution_level )->CheckOneOutOfThisBlockHasSameIntensity( index_internal.x , index_internal.y, index_internal.z , block_length , brightness ); assert( its_fine ); } } } } } bool Mask::ContourFine(){ //std::cout << "ContourFine begin"<getLegacyStructureVector(); LegacyPolygonSequenceType& strVector_ref = strVector; correspoinding_structure_vector str_v; std::vector wich_slice; for(unsigned int struct_index = 0 ; struct_index < Intersections.at(0).size() ; struct_index++ ){ wich_slice.clear(); /* if( strVector.at( struct_index ).size() < 2 ){ std::cerr<< " The Polygon consists of just one point ! That doesn't make sense in Radiotherapy. Program will be terminated. " < ( i+1 ) ) secondPoint = pitoiA.at( i+1 ).contour_point_voxel_coord; else secondPoint = pitoiA.at( 0 ).contour_point_voxel_coord; for( ; itB!=pitoiB.end() ;itB++ ){ //for( ; j ( j+1 ) ) fourthPoint = pitoiB.at( j+1 ).contour_point_voxel_coord; else fourthPoint = pitoiB.at( 0 ).contour_point_voxel_coord; //std::cout < firstPoint.x ){ x_min = firstPoint.x; x_max = secondPoint.x; } bool it_is_in_between = 1; if( (x < x_min) || (x > x_max) ) it_is_in_between = 0; if( (beta>0)&&(beta<1) && it_is_in_between ){ return true; } else return false; } else return false; } if( ( secondPoint.x - firstPoint.x ) == 0 ){ if( ( fourthPoint.x - thirdPoint.x ) != 0 ){ float beta = ( firstPoint.x - thirdPoint.x ) / ( fourthPoint.x - thirdPoint.x ); float y = ( fourthPoint.y - thirdPoint.y ) * beta + thirdPoint.y; float y_min = secondPoint.y; float y_max = firstPoint.y; if( secondPoint.y > firstPoint.y ){ y_min = firstPoint.y; y_max = secondPoint.y; } bool it_is_in_between = 1; if( (y < y_min) || (y > y_max) ) it_is_in_between = 0; if( (beta>0)&&(beta<1) && it_is_in_between ){ return true; } else return false; } else return false; } if( ( ( secondPoint.y - firstPoint.y ) == 0 ) || ( ( secondPoint.x - firstPoint.x ) == 0 ) ) assert(0); if( ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) == 0 ){ return false; // parallel, schneiden sich nicht ! } if( ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) == 0 ) assert( 0 ); float beta = ( ( ( thirdPoint.y - firstPoint.y ) / ( secondPoint.y - firstPoint.y ) ) - ( ( thirdPoint.x - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) ) ) / ( ( ( fourthPoint.x - thirdPoint.x ) / ( secondPoint.x - firstPoint.x ) ) - ( ( fourthPoint.y - thirdPoint.y ) / ( secondPoint.y - firstPoint.y ) ) ) ; float alpha = ( ( fourthPoint.x - thirdPoint.x ) * beta + thirdPoint.x - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); if( ( (beta>0)&&(beta<1) ) && ( (alpha>0) && (alpha<1) ) ){ // falls diese Bedingung nicht erfuellt ist, gibt es zwar einen Schnittpunkt der Geraden, aber nicht im relevanten Bereich return true; } return false; } void Mask::FloodFill4( UnsignedIndexList indexList,int oldcolor,int newcolor,int resolution_level) { LegacyUnsignedIndex3D index; index.x = 0; index.y = 0; index.z = 0; while(!indexList.empty()){ LegacyUnsignedIndex3D frontIndex=indexList.front(); index.z = frontIndex.z; if(MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y, frontIndex.z )==oldcolor){ //insert index if(frontIndex.y+1<=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_end.y && MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y+1, frontIndex.z )==oldcolor){ index.x=frontIndex.x; index.y=frontIndex.y+1; indexList.push_back(index); } if(frontIndex.y-1>=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_begin.y && MaskField.at( resolution_level )->GetData( frontIndex.x, frontIndex.y-1, frontIndex.z )==oldcolor ){ index.x=frontIndex.x; index.y=frontIndex.y-1; indexList.push_back(index); } if(frontIndex.x-1>=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_begin.x && MaskField.at( resolution_level )->GetData( frontIndex.x-1, frontIndex.y, frontIndex.z )==oldcolor){ index.x=frontIndex.x-1; index.y=frontIndex.y; indexList.push_back(index); } if(frontIndex.x+1<=MarkInterestingArea.at(resolution_level).at( frontIndex.z ).index_end.x && MaskField.at( resolution_level )->GetData( frontIndex.x+1, frontIndex.y, frontIndex.z )==oldcolor){ index.x=frontIndex.x+1; index.y=frontIndex.y; indexList.push_back(index); } //mark newcolor MaskField.at( resolution_level )->PutData( frontIndex.x, frontIndex.y, frontIndex.z, newcolor ); SetUppwardBlockThisIntensity( resolution_level , frontIndex , newcolor ); //delete front indexList.pop_front(); } else{ //delete front indexList.pop_front(); } } } void Mask::setInsideVoxelPreviousVersion(int resolution_level){ /* //doseVoxelIndexInStructure.clear(); _doseVoxelInStructure.clear(); LegacyUnsignedIndex3D index; index.x = 0; index.y = 0; index.z = 0; bool first=true; for( index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++ ){ LegacyUnsignedIndex3D index_internal; index_internal.x = 0; index_internal.y = 0; index_internal.z = index.z; /*First: Mark all voxels as unknown*/ /* if( ( MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y != 0 ) ){ for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index_internal.x++ ){ for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index_internal.y++ ){ //set all no border voxels as outside if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_unknown ); //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); }//end if else{ LegacyDoseVoxelIndex3D index2; index2.x = index_internal.x; index2.y = index_internal.y; index2.z = index_internal.z; DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); //std::cout <GInf.at(resolution_level)); if(doseVoxel.voxelInStructure(*_structure)==0){ //std::cout << "first outside voxel: "<FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); //get corresponding polygons DoseVoxel doseVoxelZPlane=DoseVoxel(index2,this->GInf.at(resolution_level)); std::vector sliceV=doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); for(int i=0;igetLegacyStructureVector().at(sliceV.at(i)); Contour contour=Contour(polygon);//get the contour in this slice LegacyPolygonType box=contour.getMinimalBox(); Contour boxContour=Contour(box); bool firstVoxelInStr=false; /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ /* for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelInStr ; index2.x++ ){ for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelInStr ; index2.y++ ){ if(MaskField.at( resolution_level )->GetData( index2.x, index2.y, index2.z )==brightness_unknown) { DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); //if doseVoxel inside the box LegacyWorldCoordinate2D luP={doseVoxel.getLeftUpperPoint().x,doseVoxel.getLeftUpperPoint().y}; //if left upper point of this voxel inside the box if(luP.x>=box.at(0).x && luP.y>=box.at(0).y && luP.x<=box.at(2).x && luP.y<=box.at(2).y){ if(doseVoxel.voxelInStructure(*_structure)==1){ //std::cout << "first inside voxel: "<FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); }//end for i //check unknown voxels int sizeUnknown=0; for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index2.x++ ){ for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index2.y++ ){ if(MaskField.at( resolution_level )->GetData(index2.x,index2.y,index2.z)==brightness_unknown){ //std::cout << index2.toString()<<"---"; //sizeUnknown++; DoseVoxel doseVoxel=DoseVoxel(index2,this->GInf.at(resolution_level)); double voxelInStr=doseVoxel.voxelInStructure(*_structure); if(voxelInStr>0){ this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown,brightness_inside,resolution_level); } else{ this->FloodFill4(index2.x,index2.y,index2.z,brightness_unknown, brightness_outside,resolution_level); } } } } /*if(sizeUnknown!=0) std::cout << "Unknown: "< indexListInside, std::vector< UnsignedIndexList > indexListOutside ){ _doseVoxelInStructure.clear(); LegacyUnsignedIndex3D index; index.x = 0; index.y = 0; index.z = 0; bool first=true; for( index.z = 0 ; index.z < GInf.at(resolution_level).getNumSlices() ; index.z++ ){ if( indexListOutside.at(index.z).size() == 0 ){ LegacyDoseVoxelIndex3D index2; index2.x = 0; index2.y = 0; index2.z = index.z; /*Mark all voxels outside the structure: using FloodFill4*/ bool firstVoxelOutStr=false; for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelOutStr ; index2.x++ ){ for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelOutStr ; index2.y++ ){ DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); if(doseVoxel.voxelInStructure(*_structure)==0){ LegacyUnsignedIndex3D indexUint; indexUint.x = static_cast(index2.x); indexUint.y = static_cast(index2.y); indexUint.z = static_cast(index2.z); indexListOutside.at(index.z).push_back( indexUint ); firstVoxelOutStr=true; break; }//end if }//end for index2.y if(firstVoxelOutStr) break; }//end for index2.x } if( indexListOutside.at(index.z).size() > 0 ) this->FloodFill4(indexListOutside.at(index.z),brightness_unknown, brightness_outside,resolution_level); if( indexListInside.at(index.z).size() == 0 ){ LegacyDoseVoxelIndex3D index2; index2.x = 0; index2.y = 0; index2.z = index.z; //get corresponding polygons DoseVoxel doseVoxelZPlane=DoseVoxel(index2,&(this->GInf.at(resolution_level))); std::vector sliceV=doseVoxelZPlane.getZIntersectPolygonIndexVector(*_structure); for(int i=0;igetLegacyStructureVector().at(sliceV.at(i)); Contour contour=Contour(polygon);//get the contour in this slice LegacyPolygonType box=contour.getMinimalBox(); Contour boxContour=Contour(box); bool firstVoxelInStr=false; /*Mark all voxels inside a polygon of the structure: using FloodFill4*/ for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x && !firstVoxelInStr ; index2.x++ ){ for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y && !firstVoxelInStr ; index2.y++ ){ if(MaskField.at( resolution_level )->GetData( index2.x, index2.y, index2.z )==brightness_unknown) { DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); //if doseVoxel inside the box LegacyWorldCoordinate2D luP={doseVoxel.getLeftUpperPoint().x(),doseVoxel.getLeftUpperPoint().y()}; //if left upper point of this voxel inside the box if(luP.x>=box.at(0).x && luP.y>=box.at(0).y && luP.x<=box.at(2).x && luP.y<=box.at(2).y){ if(doseVoxel.voxelInStructure(*_structure)==1){ //std::cout << "first inside voxel: "<(index2.x); indexUint.y = static_cast(index2.y); indexUint.z = static_cast(index2.z); indexListInside.at(index.z).push_back(indexUint); } }//end for i } if(indexListInside.at(index.z).size() > 0)this->FloodFill4(indexListInside.at(index.z),brightness_unknown,brightness_inside,resolution_level); //check unknown voxels int sizeUnknown=0; LegacyDoseVoxelIndex3D index2; index2.x = 0; index2.y = 0; index2.z = index.z; for( index2.x = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.x ; index2.x <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.x ; index2.x++ ){ for( index2.y = MarkInterestingArea.at(resolution_level).at( index.z ).index_begin.y ; index2.y <= MarkInterestingArea.at(resolution_level).at( index.z ).index_end.y ; index2.y++ ){ if(MaskField.at( resolution_level )->GetData(index2.x,index2.y,index2.z)==brightness_unknown){ //std::cout << index2.toString()<<"---"; //sizeUnknown++; DoseVoxel doseVoxel=DoseVoxel(index2,&(this->GInf.at(resolution_level))); double voxelInStr=doseVoxel.voxelInStructure(*_structure); if(voxelInStr>0){ indexListInside.at(index.z).resize(0); LegacyUnsignedIndex3D indexUint; indexUint.x = static_cast(index2.x); indexUint.y = static_cast(index2.y); indexUint.z = static_cast(index2.z); indexListInside.at(index.z).push_back(indexUint); this->FloodFill4(indexListInside.at(index.z),brightness_unknown,brightness_inside,resolution_level); } else{ indexListOutside.at(index.z).resize(0); LegacyUnsignedIndex3D indexUint; indexUint.x = static_cast(index2.x); indexUint.y = static_cast(index2.y); indexUint.z = static_cast(index2.z); indexListOutside.at(index.z).push_back(indexUint); this->FloodFill4(indexListOutside.at(index.z),brightness_unknown, brightness_outside,resolution_level); } } } } /*if(sizeUnknown!=0) std::cout << "Unknown: "<GetDimX() ; x++ ){ for( int y = 0 ; y < MaskField.at( resolution_level )->GetDimY() ; y++ ){ for( int z = 0 ; z < MaskField.at( resolution_level )->GetDimZ() ; z++ ){ if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_inside ) counter_inside++; if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_outside ) counter_outside++; if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_border ) counter_border++; if( MaskField.at( resolution_level )->GetData(x,y,z) == brightness_unknown ) counter_unknown++; } } } std::cout<< " counter_inside : " << counter_inside < indexListInside; std::vector< UnsignedIndexList > indexListOutside; for( int z = 0 ; z < GInf.at(resolution_level).getNumSlices() ; z++ ){ UnsignedIndexList a_list; a_list.resize(0); indexListInside.push_back(a_list); indexListOutside.push_back(a_list); } if( resolution_level < ( MaskField.size() - 1 ) )MaskField.at( resolution_level )->GetBorderRegion( MarkInterestingArea.at(resolution_level), indexListInside , indexListOutside, brightness_unknown, brightness_inside, brightness_outside ); setInsideVoxel( resolution_level , indexListInside, indexListOutside ); } void Mask::SetContentUnknown(){ for( int resolution_level = 0 ; resolution_level < GInf.size() ; resolution_level++ ){ for( int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ LegacyUnsignedIndex3D index_internal; index_internal.x = 0; index_internal.y = 0; index_internal.z = index_z; /*First: Mark all voxels as unknown*/ if( ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x != 0 ) && ( MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y != 0 ) ){ for( index_internal.x = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.x ; index_internal.x++ ){ for( index_internal.y = MarkInterestingArea.at(resolution_level).at( index_z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(resolution_level).at( index_z ).index_end.y ; index_internal.y++ ){ //set all no border voxels as outside if( MaskField.at( resolution_level )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_unknown ); //MaskField.at( resolution_level )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); }//end if }//end for index_internal.y }//end for index_internal.x //std::cout << std::endl; }//end if } } } void Mask::SeperateRegionsQuick(){ //doseVoxelIndexInStructure.clear(); _doseVoxelInStructure.clear(); LegacyUnsignedIndex3D index; index.x = 0; index.y = 0; index.z = 0; for( index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++ ){ LegacyUnsignedIndex3D index_internal; index_internal.x = 0; index_internal.y = 0; index_internal.z = index.z; if( ( MarkInterestingArea.at(0).at( index.z ).index_end.x != 0 ) && ( MarkInterestingArea.at(0).at( index.z ).index_end.y != 0 ) ){ for( index_internal.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index_internal.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index_internal.x++ ){ for( index_internal.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y ; index_internal.y <= MarkInterestingArea.at(0).at( index.z ).index_end.y ; index_internal.y++ ){ if( MaskField.at( 0 )->GetData( index_internal.x, index_internal.y, index_internal.z ) != brightness_border ){ MaskField.at( 0 )->PutData( index_internal.x, index_internal.y, index_internal.z, brightness_inside ); } } } } index.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y; for( index.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index.x++ ){ if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); } } index.y = MarkInterestingArea.at(0).at( index.z ).index_end.y; for( index.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x ; index.x <= MarkInterestingArea.at(0).at( index.z ).index_end.x ; index.x++ ){ if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); } } index.x = MarkInterestingArea.at(0).at( index.z ).index_begin.x; for( index.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y ; index.y <= MarkInterestingArea.at(0).at( index.z ).index_end.y ; index.y++ ){ if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); } } index.x = MarkInterestingArea.at(0).at( index.z ).index_end.x; for( index.y = MarkInterestingArea.at(0).at( index.z ).index_begin.y ; index.y <= MarkInterestingArea.at(0).at( index.z ).index_end.y ; index.y++ ){ if( MaskField.at( 0 )->GetData( index.x, index.y, index.z ) == brightness_inside ){ MaskField.at( 0 )->PutData( index.x, index.y, index.z, brightness_outside ); ConnectArea( brightness_inside , brightness_outside , index , MarkInterestingArea.at(0).at( index.z ).index_begin , MarkInterestingArea.at(0).at( index.z ).index_end ); } } } } void Mask::SetDoseVoxelInStructureVector(){ _doseVoxelInStructure.clear(); DoseVoxel aDoseVoxel; LegacyUnsignedIndex3D index; index.x = 0; index.y = 0; index.z = 0; LegacyDoseVoxelIndex3D aDoseIndex; aDoseIndex.x = 0; aDoseIndex.y = 0; aDoseIndex.z = 0; double fraction = 0; for( index.z = 0 ; index.z < GInf.at(0).getNumSlices() ; index.z++ ){ if( FieldOfIntersections ){ FieldOfIntersections->SetZero(); GetIntersectionInformationThisSlice( index.z ); } for( index.x = 0 ; index.x < GInf.at(0).getNumColumns() ; index.x++ ){ for( index.y = 0 ; index.y < GInf.at(0).getNumRows() ; index.y++ ){ aDoseIndex.x = index.x; aDoseIndex.y = index.y; aDoseIndex.z = index.z; if( brightness_inside == MaskField.at( 0 )->GetData( index.x, index.y, index.z ) ){ //doseVoxelIndexInStructure.push_back( aDoseIndex ); fraction = 1.0; DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); doseVoxel.setProportionInStr(fraction); this->_doseVoxelInStructure.push_back(doseVoxel); // und jetzt fraction irgendwie anhaengen an geeignete Struktur und dann raus damit //std::cout << "inside: "<GetData( index.x, index.y, index.z ) ){ if( !do_detailed_subvox ){ /*Lanlan*/ DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); fraction=doseVoxel.voxelInStructure(*_structure);//simple test if(fraction>0){ //doseVoxelIndexInStructure.push_back( aDoseIndex ); doseVoxel.setProportionInStr(fraction); this->_doseVoxelInStructure.push_back(doseVoxel); } } else{ /*Martina..............*/ //doseVoxelIndexInStructure.push_back( aDoseIndex ); fraction = 1.0; fraction = GetFractionInside( aDoseIndex ); if( ( fraction < 0 ) || ( fraction > 1.0 ) ) assert(0); DoseVoxel doseVoxel=DoseVoxel(aDoseIndex,&(GInf.at(0))); doseVoxel.setProportionInStr( fraction ); _doseVoxelInStructure.push_back( doseVoxel ); } } } } } double total_volume = 0; for( int counter = 0 ; counter < _doseVoxelInStructure.size() ; counter++ ){ total_volume += _doseVoxelInStructure.at( counter ).getProportionInStr(); } //std::cout<< " total_volume : " << total_volume <= index_begin.x ) && ( start_index.y >= index_begin.y ) && ( start_index.x <= index_end.x ) && ( start_index.y <= index_end.y ) ){ std::deque index_list; LegacyUnsignedIndex2D this_index; this_index.x = start_index.x; this_index.y = start_index.y; LegacyUnsignedIndex2D another_index; another_index.x = 0; another_index.y = 0; MaskField.at( 0 )->PutData( start_index.x, start_index.y, start_index.z, brightness_to ); index_list.push_back( this_index ); int counter = 1; while( index_list.size() > 0 ){ // std::cout<< " counter " << counter < index_begin.x ){ another_index.x = this_index.x - 1; another_index.y = this_index.y; if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ index_list.push_back( another_index ); counter++; MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); } } if( this_index.y > index_begin.y ){ another_index.x = this_index.x; another_index.y = this_index.y - 1; if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ index_list.push_back( another_index ); counter++; MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); } } if( this_index.x < index_end.x ){ another_index.x = this_index.x + 1; another_index.y = this_index.y; if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ index_list.push_back( another_index ); counter++; MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); } } if( this_index.y < index_end.y ){ another_index.x = this_index.x; another_index.y = this_index.y + 1; if( MaskField.at( 0 )->GetData( another_index.x , another_index.y , start_index.z ) == brightness_from ){ index_list.push_back( another_index ); counter++; MaskField.at( 0 )->PutData( another_index.x, another_index.y, start_index.z, brightness_to ); } } } } } // die folgende Funktion prueft immer erst, ob es sich um einen Schnittpunkt mit der Ecke handelt. Falls nicht wird er in die Reihe der Kantenschnittpunkte einsortiert. Betrachtet wird lediglich die erste Ecke. void Mask::SetThisIntersectionToCornerOrEdge( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D, unsigned int edge_number, IntersectionsThisVoxel& voxel_intersections ){ if(edge_number==0){ SetThisIntersection( index_x , (index_x+1) , index_y , intersection , coord2D.x, coord2D.y , voxel_intersections, edge_number ); } else if(edge_number==1){ SetThisIntersection( index_y , (index_y+1) , ( index_x + 1 ) , intersection , coord2D.y, coord2D.x , voxel_intersections, edge_number ); //SetThisIntersectionYIncreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); } else if(edge_number==2){ SetThisIntersection( ( index_x + 1 ) , index_x , ( index_y + 1 ) , intersection , coord2D.x, coord2D.y , voxel_intersections, edge_number ); //SetThisIntersectionXDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); } else if(edge_number==3){ SetThisIntersection( ( index_y + 1 ) , index_y , index_x , intersection , coord2D.y, coord2D.x , voxel_intersections, edge_number ); //SetThisIntersectionYDecreasing( index_x , index_y , intersection , coord2D , voxel_intersections ); } else assert(0); } void Mask::SetThisIntersection( unsigned int corner_of_interest , unsigned int corner_next, unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ){ if( coord_fixed != static_cast(corner_fixed) ) assert(0); // this should never happen since coord_fixed is the coordinate which is the same all along the edge that starts with corner_fixed if( coord_of_interest == static_cast(corner_of_interest) ){ // falls der Schnittpunkt direkt am Anfang der Kante liegt also der Anfangspunkt der Kante ist voxel_intersections.corner_intersections_intersection_coord.at(edge_number).push_back( intersection ); // dann haenge den Schnittpunkt an die Liste der Schnittpunkte mit eben diesem Anfangspunkt der Kante an return; } else{ if( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() > 0 ){ // falls die Kante schon Schnittpunkte hat double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(0).at(0); // In der naechsten Zeile wird geprueft, ob der Schnittpunkt zwischen dem Anfang der Kante und dem ersten bereits bekannten Schnittpunkt liegt. Falls ja, wird er entsprechend eingefuegt. if( CompareIfBetweenInsertAtBeginning( coord_of_interest , static_cast(corner_of_interest) , first_coord_double , edge_number, intersection , voxel_intersections ) ) return; } // naechste Zeile: Pruefe, ob der Schnittpunkt in der Liste der Schnittpunkte mit dieser Kante schon vorhanden ist und falls ja, verlaengere die Liste der Punkte, die eben in diesem Punkt schneiden um den neuen Schnittpunkt. // Puntemaessig ist das zwar der selbe, der schon mindestens einmal da ist, aber intersection ist ja eine Art Index im PolygonOfIntersections // und muss dann hier einsortiert werden. Denn das Polygon kann tatsaechlich mehrfach durch den selben Punkt laufen. // Falls der Schnittpunkt noch nicht vorkommt, aber zwischen zweien ist, die bereits vorkommen, wird er entsprechend eingefuegt. if( CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( coord_of_interest , edge_number, intersection , voxel_intersections ) ) return; double that_coord_double = 0; // Die folgenden beiden Zeilen sind dafuer zustaendig that_coord_double mit entweder dem letzten bereits bekannten Schnittpunkt dieser Kante, // oder alternativ mit dem Anfangspunkt der Kante zu belegen. if( voxel_intersections.edge_intersections_vox_coord.at(edge_number).size() > 0 ) that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).at(0) ; else that_coord_double = static_cast( corner_of_interest ); if( that_coord_double == coord_of_interest ){ if( coord_of_interest == static_cast( corner_of_interest ) ) assert( 0 ); // Das kann nicht sein, denn falls der Schnittpunkt wirklich der erste Punkt der Kante waere, muesste das ganz zu Beginn dieser Funktion bereits erkannt worden sein und die Funktion haette dann bereits returned. Falls that_coord_double also coord_of_interest (eizusortierender Punk) ist, kann dieser nicht der Anfangspunkt der Kante sein. // der einzusortierende Punkt coord_of_interest ist gerade gleich dem letzten bereits gefundenen Schnittpunkt that_coord_double und wird der Liste seinder Vorkommnisse entsprechend hinzugefuegt. voxel_intersections.edge_intersections_vox_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).push_back( coord_of_interest ); voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at( ( voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size() - 1 ) ).push_back( intersection ); return; } else{ // Hier wird geprueft, ob der betrachtete Punkt zwischen dem letzten bereits gefundenen Schnittpunkt und dem Ende der Kante liegt. Falls ja, wird er vor dem Kantenende entsprechend eingefuegt. if( CompareIfBetweenAppend( coord_of_interest , that_coord_double, static_cast( corner_next ), edge_number, intersection , voxel_intersections ) ){ return; } if( coord_of_interest == static_cast( corner_next ) ) assert(0); // this case is not supposed to be considered here. Its the next edge and should have gone elsewhere. Das Ende der Kante ist der Anfang der naechsten Kante uns haette daher bei dieser naechsten Kante landen muessen. } assert( 0 ); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be considered here. } } void Mask::SetThisIntersectionXIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ){ if( coord2D.y != static_cast(index_y) ) assert(0); // this should never happen if( coord2D.x == static_cast(index_x) ){ voxel_intersections.corner_intersections_intersection_coord.at(0).push_back( intersection ); return; } else{ if( voxel_intersections.edge_intersections_intersection_coord.at(0).size() > 0 ){ double first_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at(0).at(0); if( CompareIfBetweenInsertAtBeginning( coord2D.x , static_cast(index_x) , first_coord_double , edge_number, intersection , voxel_intersections ) ) return; } if( CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( coord2D.x , edge_number, intersection , voxel_intersections ) ) return; double that_coord_double = 0; if( voxel_intersections.edge_intersections_vox_coord.at(0).size() > 0 ) that_coord_double = voxel_intersections.edge_intersections_vox_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).at(0) ; else that_coord_double = static_cast( index_x ); if( that_coord_double == coord2D.x ){ if( coord2D.x == static_cast( index_x ) ) assert( 0 ); voxel_intersections.edge_intersections_vox_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).push_back( coord2D.x ); voxel_intersections.edge_intersections_intersection_coord.at(0).at( ( voxel_intersections.edge_intersections_intersection_coord.at(0).size() - 1 ) ).push_back( intersection ); return; } else{ if( CompareIfBetweenAppend( coord2D.x , that_coord_double, static_cast( index_x + 1 ), edge_number, intersection , voxel_intersections ) ) return; if( coord2D.x == static_cast( index_x + 1 ) ) assert(0); // this case is not supposed to be treated here. } assert( 0 ); // assigned to the wrong edge by programmer. It may be the second corner attachted to this edge, however, it is not supposed to be treated here. } } bool Mask::CompareIfBetweenAppend( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ if( ( ( value_to_compare < big_value_to_compare_with ) && ( value_to_compare > small_value_to_compare_with ) ) || ( ( value_to_compare > big_value_to_compare_with ) && ( value_to_compare < small_value_to_compare_with ) ) ){ std::vector< double > double_vec; double_vec.push_back(value_to_compare) ; std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; intersection_vec.push_back( intersection ); voxel_intersections.edge_intersections_vox_coord.at(edge_number).push_back( double_vec ); voxel_intersections.edge_intersections_intersection_coord.at(edge_number).push_back( intersection_vec ); return true; } else return false; } bool Mask::CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( double value_to_compare , unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ for( int i = 0 ; i < ( static_cast(voxel_intersections.edge_intersections_intersection_coord.at(edge_number).size()) - 1 ) ; i++ ){ double the_coord_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).at(0) ; if( value_to_compare == the_coord_double ){ voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i).push_back( value_to_compare ); voxel_intersections.edge_intersections_intersection_coord.at(edge_number).at(i).push_back( intersection ); return true; } else{ double another_double = voxel_intersections.edge_intersections_vox_coord.at(edge_number).at(i+1).at(0) ; if( ( ( another_double > value_to_compare ) && ( the_coord_double < value_to_compare ) ) || ( ( another_double < value_to_compare ) && ( the_coord_double > value_to_compare ) ) ){ std::vector< double > double_vec; double_vec.push_back( value_to_compare ) ; std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; intersection_vec.push_back( intersection ); intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at(edge_number).begin() + ( i + 1 ); voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert( ( voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin() + ( i + 1 ) ) , double_vec ); voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert( it , intersection_vec ); return true; } } } return false; } bool Mask::CompareIfBetweenInsertAtBeginning( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ){ if( ( ( value_to_compare > small_value_to_compare_with ) && ( value_to_compare < big_value_to_compare_with ) ) || ( ( value_to_compare < small_value_to_compare_with ) && ( value_to_compare > big_value_to_compare_with ) ) ){ std::vector< double > double_vec; double_vec.push_back(value_to_compare) ; std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > intersection_vec; intersection_vec.push_back( intersection ); intersection_coord_iterator_type it = voxel_intersections.edge_intersections_intersection_coord.at(edge_number).begin(); voxel_intersections.edge_intersections_vox_coord.at(edge_number).insert( voxel_intersections.edge_intersections_vox_coord.at(edge_number).begin(), double_vec ); voxel_intersections.edge_intersections_intersection_coord.at(edge_number).insert( it , intersection_vec ); return true; } return false; } void Mask::SetThisIntersectionYIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ if( coord2D.x != static_cast(index_x+1) ) assert(0); // this should never happen // to be implemented } void Mask::SetThisIntersectionXDecreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ if( coord2D.y != static_cast(index_y+1) ) assert(0); // this should never happen // to be implemented } void Mask::SetThisIntersectionYDecreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ){ if( coord2D.x != static_cast(index_x) ) assert(0); // this should never happen // to be implemented } void Mask::Init(){ SliceStructureCorrespondency.clear(); do_detailed_subvox = true; if( do_detailed_subvox ){ FieldOfIntersections = new rttb::masks::legacy::FieldOfPointer( GInf.at(0).getNumColumns() , GInf.at(0).getNumRows() , 1 ); } for( int i = 0 ; i < MaskField.size() ; i++ ){ if(MaskField.at(i)!=NULL)MaskField.at(i)->~FieldOfScalar(); } MaskField.resize(0); rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new rttb::masks::legacy::FieldOfScalar( GInf.at(0).getNumColumns() , GInf.at(0).getNumRows() , GInf.at(0).getNumSlices() ); MaskField.push_back( a_field_of_scalar ); brightness_inside = 50; brightness_border = 10; brightness_outside = 0; brightness_unknown = -10; LegacyDoseVoxelIndex3D doseVoxelIndex; doseVoxelIndex.x = 0; doseVoxelIndex.y = 0; doseVoxelIndex.z = 0 ; int currentSliceNumber=0; LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); LegacyPolygonSequenceType& strVector_ref = strVector; StructureInTermsOfIntersections inters; inters.resize( strVector.size() ); Intersections.push_back( inters ); StructureInTermsOfIntersections sitoi=Intersections.at(0); //StructureInTermsOfIntersections:: for(unsigned int i = 0 ; i < strVector.size() ; i++ ){ Intersections.at(0).at( i ).resize( strVector.at( i ).size() ); LegacyWorldCoordinate2D index_coord; index_coord.x = 0; index_coord.y = 0; LegacyWorldCoordinate3D contour_point_world; contour_point_world.x = 0; contour_point_world.y = 0; contour_point_world.z = 0; for(unsigned int j = 0 ; j < strVector.at( i ).size() ; j++ ){ contour_point_world = strVector.at( i ).at( j ); index_coord = GetDoubleIndex2D( contour_point_world.x , contour_point_world.y ); Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.x = index_coord.x; Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.y = index_coord.y; Intersections.at(0).at( i ).at( j ).contour_point_voxel_coord.z = GetZIndex(contour_point_world.z); } } // iteration slices for( doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++ ){ correspoinding_structure_vector str_v; LegacyWorldCoordinate2D the_index; the_index.x = 0; the_index.y = 0; DoseVoxel doseVoxel; //from dose index to worldcoordinate doseVoxel.setDoseVoxel( doseVoxelIndex , &(GInf.at(0)) ); str_v=doseVoxel.getZIntersectPolygonIndexVector(*_structure ); //Lanlan SliceStructureCorrespondency.push_back( str_v ); } InitInterestingArea(); InitMultiResolution(); } void Mask::InitInterestingArea(){ MarkInterestingArea.clear(); std::vector interesting_area_this_resolution; LegacyDoseVoxelIndex3D doseVoxelIndex; doseVoxelIndex.x = 0; doseVoxelIndex.y = 0; doseVoxelIndex.z = 0 ; int currentSliceNumber=0; LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); LegacyPolygonSequenceType& strVector_ref = strVector; // iteration slices for( doseVoxelIndex.z = 0 ; doseVoxelIndex.z < GInf.at(0).getNumSlices() ; doseVoxelIndex.z++ ){ LegacyWorldCoordinate1D x_min = 1000000000; LegacyWorldCoordinate1D x_max = -1000000000; LegacyWorldCoordinate1D y_min = 1000000000; LegacyWorldCoordinate1D y_max = -1000000000; LegacyWorldCoordinate1D x_index_min = 1000000000; LegacyWorldCoordinate1D x_index_max = -1000000000; LegacyWorldCoordinate1D y_index_min = 1000000000; LegacyWorldCoordinate1D y_index_max = -1000000000; LegacyWorldCoordinate2D the_index; the_index.x = 0; the_index.y = 0; DoseVoxel doseVoxel; //from dose index to worldcoordinate doseVoxel.setDoseVoxel( doseVoxelIndex ,&( GInf.at(0)) ); std::vector sliceV = doseVoxel.getZIntersectPolygonIndexVector( *_structure ); //if( ( strVector.size() != currentSliceNumber ) && ( currentSliceNumber != (-1) ) ){ for(int indexV=0; indexV x_max ){ x_max = firstPoint.x; } if( firstPoint.y > y_max ){ y_max = firstPoint.y; } the_index = GetDoubleIndex2D( firstPoint.x , firstPoint.y ); if( the_index.x < x_index_min ){ x_index_min = the_index.x; } if( the_index.y < y_index_min ){ y_index_min = the_index.y; } if( the_index.x > x_index_max ){ x_index_max = the_index.x; } if( the_index.y > y_index_max ){ y_index_max = the_index.y; } } }//end for indexV if(sliceV.size()>0){ LegacyArea2D area_2d; area_2d.x_begin = x_min; area_2d.x_end = x_max; area_2d.y_begin = y_min; area_2d.y_end = y_max; int small_enough_x = static_cast(floor( x_index_min ) - 1); if( small_enough_x < 0 ) small_enough_x = 0; area_2d.index_begin.x = small_enough_x; int small_enough_y = static_cast(floor( y_index_min ) - 1); if( small_enough_y < 0 ) small_enough_y = 0; area_2d.index_begin.y = small_enough_y; int large_enough_x = static_cast(floor( x_index_max ) + 1); if( large_enough_x >= GInf.at(0).getNumColumns() ) large_enough_x = ( GInf.at(0).getNumColumns() - 1 ); area_2d.index_end.x = large_enough_x; int large_enough_y = static_cast(floor( y_index_max ) + 1); if( large_enough_y >= GInf.at(0).getNumRows() ) large_enough_y = ( GInf.at(0).getNumRows() - 1 ); area_2d.index_end.y = large_enough_y; interesting_area_this_resolution.push_back( area_2d ); // std::vector } else{ LegacyArea2D area_2d; area_2d.Init(); interesting_area_this_resolution.push_back( area_2d ); } } MarkInterestingArea.push_back( interesting_area_this_resolution ); } void Mask::InitMultiResolution(){ bool done = false; while( done == false ){ int new_dim_x = MaskField.at( 0 )->GetDimX() / static_cast( GetBlockLengthThisResolutionLevel( MaskField.size() ) ) + 1; int new_dim_y = MaskField.at( 0 )->GetDimY() / static_cast( GetBlockLengthThisResolutionLevel( MaskField.size() ) ) + 1; if( new_dim_x > 20 && new_dim_y > 20 ){ core::GeometricInfo NewGeomInf; NewGeomInf.setImagePositionPatient(GInf.at( GInf.size() - 1 ).getImagePositionPatient()); NewGeomInf.setOrientationMatrix(GInf.at( GInf.size() - 1 ).getOrientationMatrix()); NewGeomInf.setSliceThickness(GInf.at( GInf.size() - 1 ).getSliceThickness()); NewGeomInf.setNumSlices(GInf.at( GInf.size() - 1 ).getNumSlices()); NewGeomInf.setNumColumns(new_dim_x); NewGeomInf.setNumRows(new_dim_y); double power = 1; for( int i = 0 ; i < GInf.size() ; i++ ){ power *= 2; } NewGeomInf.setPixelSpacingRow(GInf.at( 0 ).getPixelSpacingRow() * power); NewGeomInf.setPixelSpacingColumn(GInf.at( 0 ).getPixelSpacingColumn() * power); GInf.push_back( NewGeomInf ); rttb::masks::legacy::FieldOfScalar* a_field_of_scalar = new rttb::masks::legacy::FieldOfScalar( GInf.at( GInf.size() - 1 ).getNumColumns() , GInf.at( GInf.size() - 1 ).getNumRows() , GInf.at( GInf.size() - 1 ).getNumSlices() ); MaskField.push_back( a_field_of_scalar ); std::vector interesting_area_this_resolution; for( int z = 0 ; z < MarkInterestingArea.at( 0 ).size() ; z++ ){ LegacyArea2D NewArea; NewArea.x_begin = MarkInterestingArea.at( 0 ).at( z ).x_begin; NewArea.x_end = MarkInterestingArea.at( 0 ).at( z ).x_end; NewArea.y_begin = MarkInterestingArea.at( 0 ).at( z ).y_begin; NewArea.y_end = MarkInterestingArea.at( 0 ).at( z ).y_end; NewArea.index_begin.x = ( MarkInterestingArea.at( 0 ).at( z ).index_begin.x / power ); if( NewArea.index_begin.x > 0 ) NewArea.index_begin.x -= 1; NewArea.index_begin.y = ( MarkInterestingArea.at( 0 ).at( z ).index_begin.y / power ); if( NewArea.index_begin.y > 0 ) NewArea.index_begin.y -= 1; NewArea.index_end.x = ( MarkInterestingArea.at( 0 ).at( z ).index_end.x / power ); NewArea.index_end.x += 1; if( NewArea.index_end.x >= MaskField.at( MaskField.size() - 1 )->GetDimX() ) NewArea.index_end.x = ( MaskField.at( MaskField.size() - 1 )->GetDimX() - 1 ); NewArea.index_end.y = ( MarkInterestingArea.at( 0 ).at( z ).index_end.y / power ); NewArea.index_end.y += 1; if( NewArea.index_end.y >= MaskField.at( MaskField.size() - 1 )->GetDimY() ) NewArea.index_end.y = ( MaskField.at( MaskField.size() - 1 )->GetDimY() - 1 ); interesting_area_this_resolution.push_back( NewArea ); } MarkInterestingArea.push_back( interesting_area_this_resolution ); } else done = true; } /* std::cout<< " MaskField.size() " << MaskField.size() <GetDimX() : " << MaskField.at( i )->GetDimX() <GetDimY() : " << MaskField.at( i )->GetDimY() <pixelSpacingColumn : " << GInf.at( i ).getPixelSpacingColumn() <sliceThickness : " << GInf.at( i ).getSliceThickness() <column : " << GInf.at( i )getNumColumns() <row : " << GInf.at( i )getNumRows() <numberOfFrames : " << GInf.at( i ).getNumSlices() < 1 ) || ( MarkInterestingArea.at( i ).at( z ).index_end.y > 1 ) ){ std::cout<< " z : " << z <getLegacyStructureVector(); LegacyPolygonSequenceType& strVector_ref = strVector; StructureInTermsOfIntersections inters; inters.resize( strVector.size() ); Intersections.push_back( inters ); for(unsigned int i = 0 ; i < strVector.size() ; i++ ){ Intersections.at(counter).at( i ).resize( strVector.at( i ).size() ); LegacyWorldCoordinate2D index_coord; index_coord.x = 0; index_coord.y = 0; LegacyWorldCoordinate3D contour_point_world; contour_point_world.x = 0; contour_point_world.y = 0; contour_point_world.z = 0; for(unsigned int j = 0 ; j < strVector.at( i ).size() ; j++ ){ contour_point_world = strVector.at( i ).at( j ); index_coord = GetDoubleIndex2D( contour_point_world.x , contour_point_world.y , counter ); Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.x = index_coord.x; Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.y = index_coord.y; Intersections.at(counter).at( i ).at( j ).contour_point_voxel_coord.z = GetZIndex(contour_point_world.z); } } } if( Intersections.size() != GInf.size() ) assert(0); /* for( int counter = 0 ; counter < GInf.size() ; counter++ ){ std::cout<< " next resolution level " << counter <getLegacyStructureVector(); LegacyPolygonSequenceType& strVector_ref = strVector; LegacyWorldCoordinate3D firstPoint; firstPoint.x = 0; firstPoint.y = 0; firstPoint.z = 0; LegacyWorldCoordinate3D secondPoint; secondPoint.x = 0; secondPoint.y = 0; secondPoint.z = 0; // iteration z direction for(unsigned int struct_index = 0 ; struct_index < strVector.size() ; struct_index++ ){ // iteration polygon for( int point_index = 0 ; point_index < ( strVector.at(struct_index).size() - 1 ); point_index++ ){ firstPoint = strVector.at(struct_index).at( point_index ); secondPoint = strVector.at(struct_index).at( point_index + 1 ); std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).raw_intersections; std::vector& column_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).column_intersections; std::vector& intersections_raw_and_column_ref = Intersections.at(resolution_level).at( struct_index ).at( point_index ).intersections_raw_and_column; GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); UnifyRawAndColumn( firstPoint , raw_intersections_ref , column_intersections_ref , intersections_raw_and_column_ref, resolution_level ); } // the connection between the last and the first Point of the Polygon needs to be checked as well if( strVector.at(struct_index).size() > 0 ){ firstPoint = strVector.at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ); secondPoint = strVector.at( struct_index ).at( 0 ); std::vector& raw_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).raw_intersections; std::vector& column_intersections_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).column_intersections; std::vector& intersections_raw_and_column_ref = Intersections.at(resolution_level).at( struct_index ).at( ( strVector.at(struct_index).size() - 1 ) ).intersections_raw_and_column; GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); UnifyRawAndColumn( firstPoint, raw_intersections_ref , column_intersections_ref, intersections_raw_and_column_ref, resolution_level ); } } /*for( int struct_index = 0 ; struct_index < strVector.size() ; struct_index++ ){ // iteration polygon for( int point_index = 0 ; point_index < ( strVector.at(struct_index).size() - 1 ); point_index++ ){ std::vector& raw_intersections_ref = Intersections.at(0).at(0).at( struct_index ).at( point_index ).raw_intersections; std::vector& column_intersections_ref = Intersections.at(0).at( struct_index ).at( point_index ).column_intersections; for(int i=0;i& raw_intersections_ref , std::vector& column_intersections_ref , std::vector& intersections_raw_and_column_ref, int resolution_level ){ if( ( column_intersections_ref.size() > 0 ) && ( raw_intersections_ref.size() == 0 ) ){ intersections_raw_and_column_ref = column_intersections_ref; } if( ( raw_intersections_ref.size() > 0 ) && ( column_intersections_ref.size() == 0 ) ){ intersections_raw_and_column_ref = raw_intersections_ref; } if( ( intersections_raw_and_column_ref.size() == 0 ) ){ // falls das nicht der Fall ist ist der Verlauf der Konturpunkte horizontal oder vertikal. Dann gibt es sowiso nur horizontale oder vertikale Schnittpunkte und die Vereinigung ist in GoIntersect... bereits geschehen. bool done = false; int internal_counter = 0; int counter = 0 ; LegacyWorldCoordinate2D rawPoint; rawPoint.x = 0; rawPoint.y = 0; LegacyWorldCoordinate2D columnPoint; columnPoint.x = 0; columnPoint.y = 0; LegacyWorldCoordinate2D firstPoint = GetDoubleIndex2D( the_firstPoint.x , the_firstPoint.y, resolution_level ); while( ! done ){ if( counter < raw_intersections_ref.size() )rawPoint = raw_intersections_ref.at( counter ); else if( raw_intersections_ref.size() > 0 ) rawPoint = raw_intersections_ref.at( raw_intersections_ref.size() - 1 ); if( internal_counter < column_intersections_ref.size() )columnPoint = column_intersections_ref.at( internal_counter ); else if( column_intersections_ref.size() > 0 ) columnPoint = column_intersections_ref.at( column_intersections_ref.size() - 1 ); double distance_raw = ( firstPoint.y - rawPoint.y ) * ( firstPoint.y - rawPoint.y ) + ( firstPoint.x - rawPoint.x ) * ( firstPoint.x - rawPoint.x ); double distance_column = ( firstPoint.x - columnPoint.x ) * ( firstPoint.x - columnPoint.x ) + ( firstPoint.y - columnPoint.y ) * ( firstPoint.y - columnPoint.y ); if( distance_raw == distance_column ){ if( internal_counter >= column_intersections_ref.size() ){ counter++; } else{ intersections_raw_and_column_ref.push_back( columnPoint ); internal_counter++; counter++; } } else if( ( ( distance_raw > distance_column ) && ( internal_counter < column_intersections_ref.size() ) ) || ( counter >= ( raw_intersections_ref.size() ) ) ){ intersections_raw_and_column_ref.push_back( columnPoint ); internal_counter++; } else if( ( distance_raw < distance_column ) || ( internal_counter >= column_intersections_ref.size() ) ){ if( ( counter < ( raw_intersections_ref.size() ) ) ){ intersections_raw_and_column_ref.push_back( rawPoint ); counter++; } } if( ( internal_counter >= column_intersections_ref.size() ) && ( counter >= raw_intersections_ref.size() ) )done = true; } /* for( int i = 0 ; i < column_intersections_ref.size() ; i++ ){ LegacyWorldCoordinate2D Point = column_intersections_ref.at( i ); std::cout<< " column_intersections_ref.at( i ) Point.x !!!!!!!!!!!!!!!!!!!!!!!!!!!!: " << Point.x <& raw_intersections_ref, int resolution_level ){ if( ( secondPoint.y - firstPoint.y ) != 0 ){ if( ( secondPoint.x - firstPoint.x ) != 0 ){ /* Siehe GoIntersectColumn (ist eigentlich das selbe) Auf der einen Gerade liegt das Strutkur Segment und die andere Gerade ist die Spalte Beziehungsweise die Zeile. Zwei Geleichungen und zwei Unbekannte .... */ /* NEBENRECHNUNG : linear connection between both points : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda with lambda between zero and one representing the regarded structure segment equation raw : x = imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) y = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) x_offset_raw gibt die rauemliche Verschiebung beim aendern des zeilen index an raw_index repraesentiert den index der betrachteten Zeile also die y-Position innerhalb der Spalte x_offset_raw = imageOrientationColumn.x*pixelSpacingColumn; y_offset_raw = imageOrientationColumn.y*pixelSpacingColumn; unknown : lambda and the_index.x the_index.x and raw_index represent the voxel Solution : First Equation: imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda Second Equation: imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda Lambda from second equation: ( imagePositionPatient.y + y_offset_raw * (raw_index-0.5) + imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) - firstPoint.y ) / ( secondPoint.y - firstPoint.y ) = lambda First Equation: ( imagePositionPatient.x + x_offset_raw * (raw_index-0.5) + imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) = lambda First into Second Equation : imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = - imageOrientationRow.y * pixelSpacingRow * (the_index.x-0.5) + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow * (the_index.x-0.5) ) First into Second Equation : imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) = (the_index.x-0.5) * ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) First into SecondEquation : (the_index.x-0.5) = imagePositionPatient.y + y_offset_raw * (raw_index-0.5) - firstPoint.y - ( imagePositionPatient.x - firstPoint.x + x_offset_raw * (raw_index-0.5) ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) / ( ( - imageOrientationRow.y * pixelSpacingRow + ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x )* ( imageOrientationRow.x * pixelSpacingRow ) ) ) Der andere index ist raw_index und daher bereits bekannt. Vorsicht, bevor ein Schnittpunkt als solcher akzeptiert werden kann muss untersucht werden ob lambda zwischen null und eins liegt da ansonsten Schnittpunkte der Segmentgeraden betrachtet werden, die ausserhalb des eigentlichen Struktursegmentes liegen. */ double x_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn(); double y_offset_raw = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn(); LegacyWorldCoordinate2D index_first_point; index_first_point.x = 0; index_first_point.y = 0; LegacyWorldCoordinate2D index_second_point; index_second_point.x = 0; index_second_point.y = 0; // indicees der beiden uebergebenen Punkte bestimmen index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); double index_diff = ( index_second_point.y - index_first_point.y ); int begin_ind = 0; int end_ind = 0; bool do_swap = 0; if( index_diff > 0 ){ begin_ind = static_cast( floor( index_first_point.y ) ); end_ind = static_cast( floor( index_second_point.y ) + 1 ); } else if( index_diff < 0 ){ do_swap = 1; begin_ind = static_cast( floor( index_second_point.y ) ); end_ind = static_cast( floor( index_first_point.y ) + 1 ); } else{ begin_ind = 0; end_ind = 0; } if( begin_ind < 0 ) begin_ind = 0; if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; LegacyWorldCoordinate3D the_index; the_index.x = 0; the_index.y = 0; the_index.z = 0; double multi_res_offset = GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); //std::cout <<"go intersection raw: "<= 0 ) && ( lambda <= 1 ) ){ raw_intersections_ref.push_back( coord2D ); //std::cout << coord2D.toString()<(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z) )}; DoseVoxel voxel=DoseVoxel(index,GInf.at(resolution_level)); std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(index, interPs));!!!Lanlan */ /*std::cout << "intersections: "< vecW; LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(end_ind-raw_index)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(end_ind-raw_index+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; vecW.push_back(p1); vecW.push_back(p2); LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast( this->GetZIndex(firstPoint.z) )}; this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW));*/ } } if( do_swap ){ std::vector raw_intersections_to_be_swaped; for( int this_one = ( raw_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ raw_intersections_to_be_swaped.push_back( raw_intersections_ref.at( this_one ) ); } raw_intersections_ref.swap( raw_intersections_to_be_swaped ); } } else{ GoGetRawIntersectionsAlongThisColumn( firstPoint , secondPoint , raw_intersections_ref , resolution_level ); } } } void Mask::GoGetRawIntersectionsAlongThisColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, int resolution_level ){ LegacyWorldCoordinate2D index_first_point; index_first_point.x = 0; index_first_point.y = 0; LegacyWorldCoordinate2D index_second_point; index_second_point.x = 0; index_second_point.y = 0; if( firstPoint.x != secondPoint.x ) assert(0); // indicees der beiden uebergebenen Punkte bestimmen index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); double index_diff = ( index_second_point.y - index_first_point.y ); int begin_ind = 0; int end_ind = 0; bool do_swap = 0; if( index_diff > 0 ){ begin_ind = static_cast( floor( index_first_point.y ) ); if( floor( index_first_point.y ) < index_first_point.y ) begin_ind += 1; end_ind = static_cast( floor( index_second_point.y ) ); } else if( index_diff < 0 ){ do_swap = 1; begin_ind = static_cast( floor( index_second_point.y ) ); if( floor( index_second_point.y ) < index_second_point.y ) begin_ind += 1; end_ind = static_cast( floor( index_first_point.y ) ); } else{ begin_ind = 0; end_ind = 0; } if( begin_ind < 0 ) begin_ind = 0; if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; //std::cout <<"go intersection raw along column: "< vecW; //LegacyWorldCoordinate3D p1={firstPoint.x, (firstPoint.y+(raw_index-begin_ind)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; //LegacyWorldCoordinate3D p2={firstPoint.x, (firstPoint.y+(raw_index-begin_ind+1)*GInf.at(resolution_level).getPixelSpacingRow()), firstPoint.z}; //vecW.push_back(p1); //vecW.push_back(p2); //LegacyDoseVoxelIndex3D dosevoxel={static_cast(coord2D.x),static_cast(coord2D.y),static_cast(this->GetZIndex(firstPoint.z))}; //this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, vecW)); //core::LegacyDoseVoxelIndex3D index={static_cast(coord2D.x),static_cast(coord2D.y),0}; /*DoseVoxel voxel=DoseVoxel(dosevoxel,GInf.at(resolution_level)); std::vector interPs=voxel.calcIntersectionPoints(firstPoint, secondPoint); this->voxel_intersectionPoints.insert(VoxelIntersectionPointsMap::value_type(dosevoxel, interPs));*/ /*std::cout << "intersections: "< raw_intersections_to_be_swaped; for( int this_one = ( raw_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ raw_intersections_to_be_swaped.push_back( raw_intersections_ref.at( this_one ) ); } raw_intersections_ref.swap( raw_intersections_to_be_swaped ); } } void Mask::GoIntersectColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ){ if( ( secondPoint.x - firstPoint.x ) != 0 ){ if( ( secondPoint.y - firstPoint.y ) != 0 ){ /* Siehe GoIntersectRaw (ist eigentlich das selbe) Auf der einen Gerade liegt das Strutkur Segment und die andere Gerade ist die Spalte Beziehungsweise die Zeile. Zwei Geleichungen und zwei Unbekannte .... */ /* NEBENRECHNUNG : linear connection between the two points : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda with lambda between zero and one representing the regarded structure segment equation column : x_offset_column gibt die rauemliche Verschiebung beim aendern des spalten index an column_index repraesentiert den index der betrachteten Spalte also die x Position innerhalb der Zeile x = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y y = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y x_offset_column = imageOrientationRow.x * pixelSpacingRow; y_offset_column = imageOrientationRow.y * pixelSpacingRow; Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * column_index + imageOrientationColumn.y * pixelSpacingColumn * the_index.y Erste Gleuchung aufloesen nach lambda : Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * column_index + imageOrientationColumn.x * pixelSpacingColumn * the_index.y - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) Lambda in zweite Gleichung einsetzen : firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index = imageOrientationColumn.y * pixelSpacingColumn * the_index.y - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y ) = the_index.y * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) Lambda in zweite Gleichung einsetzen : the_index.y = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * column_index ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) */ /* Nach Koordinatentransformation nochmal ueberlegt: Erste Geleuchung : x = firstPoint.x + ( secondPoint.x - firstPoint.x ) * lambda = imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) Zweite Geleuchung : y = firstPoint.y + ( secondPoint.y - firstPoint.y ) * lambda = imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) Erste Gleuchung aufloesen nach lambda : Erste Geleuchung : lambda = ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) + imageOrientationColumn.x * pixelSpacingColumn * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) Lambda in zweite Gleichung einsetzen : firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) = imageOrientationColumn.y * pixelSpacingColumn * ( the_index.y - 0.5 ) - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) * ( the_index.y - 0.5 ) = ( the_index.y - 0.5 ) * ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) Lambda in zweite Gleichung einsetzen : ( the_index.y - 0.5 ) = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( imagePositionPatient.x + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - imagePositionPatient.y + y_offset_column * ( column_index - 0.5 ) ) / ( imageOrientationColumn.y * pixelSpacingColumn - ( imageOrientationColumn.x * pixelSpacingColumn ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) */ double x_offset_column = GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow(); double y_offset_column = GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow(); LegacyWorldCoordinate2D index_first_point; index_first_point.x = 0; index_first_point.y = 0; LegacyWorldCoordinate2D index_second_point; index_second_point.x = 0; index_second_point.y = 0; // indicees der beiden uebergebenen Punkte bestimmen index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); double index_diff = ( index_second_point.x - index_first_point.x ); int begin_ind = 0; int end_ind = 0; bool do_swap = 0; if( index_diff > 0 ){ begin_ind = static_cast( floor( index_first_point.x ) ); end_ind = static_cast( floor( index_second_point.x ) + 1 ); } else if( index_diff < 0 ){ do_swap = 1; begin_ind = static_cast( floor( index_second_point.x ) ); end_ind = static_cast( floor( index_first_point.x ) + 1 ); } else{ begin_ind = 0; end_ind = 0; } if( begin_ind < 0 ) begin_ind = 0; if( end_ind > ( GInf.at(resolution_level).getNumColumns() - 1 ) ) end_ind = GInf.at(resolution_level).getNumColumns() - 1; LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; LegacyWorldCoordinate3D the_index; the_index.x = 0; the_index.y = 0; the_index.z = 0; double multi_res_offset = GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); for( int column_index = begin_ind ; column_index <= end_ind ; column_index++ ){ //ganz alt //the_index.y = ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * column_index - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * column_index ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; //alt //the_index.y = 0.5 + ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * ( column_index - 0.5 ) ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; //neu multi res the_index.y = multi_res_offset + ( firstPoint.y + ( secondPoint.y - firstPoint.y ) * ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - multi_res_offset ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ) - GInf.at(resolution_level).getImagePositionPatient()(1) + y_offset_column * ( column_index - multi_res_offset ) ) / ( GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) * ( secondPoint.y - firstPoint.y ) / ( secondPoint.x - firstPoint.x ) ) ; coord2D.y = the_index.y; coord2D.x = column_index; //alt //double lambda = ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - 0.5 ) + GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() * ( the_index.y - 0.5 ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); //neu multi resolution double lambda = ( GInf.at(resolution_level).getImagePositionPatient()(0) + x_offset_column * ( column_index - multi_res_offset ) + GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() * ( the_index.y - multi_res_offset ) - firstPoint.x ) / ( secondPoint.x - firstPoint.x ); if( ( lambda >= 0 ) && ( lambda <= 1 ) ){ column_intersections_ref.push_back( coord2D ); } } if( do_swap ){ std::vector column_intersections_to_be_swaped; for( int this_one = ( column_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ column_intersections_to_be_swaped.push_back( column_intersections_ref.at( this_one ) ); } column_intersections_ref.swap( column_intersections_to_be_swaped ); } } else{ GoGetColumnIntersectionsAlongThisRaw( firstPoint , secondPoint , column_intersections_ref, resolution_level ); } } } bool Mask::TestGoIntersectColumnByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, std::vector& expected_intersections_ref ){ column_intersections_ref.clear(); int resolution_level = 0; GoIntersectColumn( firstPoint , secondPoint , column_intersections_ref, resolution_level ); return IdenticalIntersectionsForTest( column_intersections_ref , expected_intersections_ref ); } bool Mask::TestGoIntersectRawByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, std::vector& expected_intersections_ref ){ raw_intersections_ref.clear(); int resolution_level = 0; GoIntersectRaw( firstPoint , secondPoint , raw_intersections_ref, resolution_level ); return IdenticalIntersectionsForTest( raw_intersections_ref , expected_intersections_ref ); } bool Mask::IdenticalIntersectionsForTest( std::vector& calculated_intersections_ref , std::vector& expected_intersections_ref ){ if( calculated_intersections_ref.size() != expected_intersections_ref.size() ){ std::cout<< " Size Problem ! " < 0.001 ) || ( diffb > 0.001 ) ) { std::cout<< " Unexpectd coordinate ! " <& column_intersections_ref, int resolution_level ){ LegacyWorldCoordinate2D index_first_point; index_first_point.x = 0; index_first_point.y = 0; LegacyWorldCoordinate2D index_second_point; index_second_point.x = 0; index_second_point.y = 0; if( firstPoint.y != secondPoint.y ) assert(0); // indicees der beiden uebergebenen Punkte bestimmen index_first_point = GetDoubleIndex2D( firstPoint.x , firstPoint.y, resolution_level ); index_second_point = GetDoubleIndex2D( secondPoint.x , secondPoint.y, resolution_level ); double index_diff = ( index_second_point.x - index_first_point.x ); int begin_ind = 0; int end_ind = 0; bool do_swap = 0; if( index_diff > 0 ){ begin_ind = static_cast( floor( index_first_point.x ) ); if( floor( index_first_point.x ) < index_first_point.x ) begin_ind += 1; end_ind = static_cast( floor( index_second_point.x ) ); } else if( index_diff < 0 ){ do_swap = 1; begin_ind = static_cast( floor( index_second_point.x ) ); if( floor( index_second_point.x ) < index_second_point.x ) begin_ind += 1; end_ind = static_cast( floor( index_first_point.x ) ); } else{ begin_ind = 0; end_ind = 0; } if( begin_ind < 0 ) begin_ind = 0; if( end_ind > ( GInf.at(resolution_level).getNumRows() - 1 ) ) end_ind = GInf.at(resolution_level).getNumRows() - 1; LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; for( int column_index = begin_ind ; column_index <= end_ind ; column_index++ ){ coord2D.x = column_index; coord2D.y = index_first_point.y; column_intersections_ref.push_back( coord2D ); } if( do_swap ){ std::vector column_intersections_to_be_swaped; for( int this_one = ( column_intersections_ref.size() - 1 ) ; this_one >= 0 ; this_one-- ){ column_intersections_to_be_swaped.push_back( column_intersections_ref.at( this_one ) ); } column_intersections_ref.swap( column_intersections_to_be_swaped ); } } void Mask::ShowIntersections(){ LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; for( unsigned int resolution_level = 0 ; resolution_level < Intersections.size() ; resolution_level++ ){ std::cout<< " resolution_level : " << resolution_level < wich_slice; for(unsigned int struct_index = 0 ; struct_index < Intersections.at(resolution_level).size() ; struct_index++ ){ correspoinding_structure_vector str_v; wich_slice.clear(); // die entsprechenden slices des dose cubes finden, die zu dieser Struktur gehoeren und die Voxel des MaskField belegen for(unsigned int index_z = 0 ; index_z < GInf.at(resolution_level).getNumSlices() ; index_z++ ){ str_v = SliceStructureCorrespondency.at( index_z ); for(unsigned int count = 0 ; count < str_v.size() ; count++ ){ if( str_v.at( count ) == struct_index )wich_slice.push_back( index_z ); } } // iteration polygon for(unsigned int point_index = 0 ; point_index < ( Intersections.at(resolution_level).at( struct_index ).size() ); point_index++ ){ for(unsigned int intersect_index = 0 ; intersect_index < Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.size() ; intersect_index++ ){ coord2D = Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ); if( ( coord2D.x >= 0 ) && ( coord2D.y >= 0 ) && ( coord2D.x < MaskField.at( resolution_level )->GetDimX() ) && ( coord2D.y < MaskField.at( resolution_level )->GetDimY() ) ){ unsigned int index_x = static_cast( floor( coord2D.x ) ); unsigned int index_y = static_cast( floor( coord2D.y ) ); for(unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++ ){ unsigned int index_z = wich_slice.at( this_counter ); MaskField.at( resolution_level )->PutData( index_x , index_y , index_z , brightness_border ); if( ( floor( coord2D.x ) == coord2D.x ) && ( index_x > 0 ) ){ MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , index_y , index_z , brightness_border ); } if( ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) ){ MaskField.at( resolution_level )->PutData( index_x , ( index_y - 1 ) , index_z , brightness_border ); } if( ( floor( coord2D.x ) == coord2D.x ) && ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) && ( index_x > 0 ) ){ MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , ( index_y - 1 ) , index_z , brightness_border ); } } } } for(unsigned int this_counter = 0 ; this_counter < wich_slice.size() ; this_counter++ ){ unsigned int index_z = wich_slice.at( this_counter ); // Das Siemens Planunssystem schreibt aus ungeklaertem Gruend Daten raus, deren Voxelkoordinaten ausserhalb des Bildes zu liegen kommen. Eigentlich macht das keinen Sinn. Wir wissen, dass unsere Toolbox Welt-Voxel-Koordinaten Umrechnung DICOM conform ist. int intx = floor( Intersections.at(resolution_level).at(struct_index).at( point_index ).contour_point_voxel_coord.x ); int inty = floor( Intersections.at(resolution_level).at(struct_index).at( point_index ).contour_point_voxel_coord.y ); if( ( intx >= 0 ) && ( inty >= 0 ) && ( intx < MaskField.at( resolution_level )->GetDimX() ) && ( inty < MaskField.at( resolution_level )->GetDimY() ) ){ Uint16 uintx = static_cast(intx); Uint16 uinty = static_cast(inty); MaskField.at( resolution_level )->PutData( uintx , uinty , index_z , brightness_border ); } } } // point index } } // like MarkVoxelsTouchedByStructure void Mask::GetIntersectionInformationThisSlice( unsigned int index_z ){ // In allen Slices die dem aktuellen Polygon zugeordnet sind muessen die zu den // Schnittpunkten der Contour gehoerigen Voxel gesetzt werden. // (siehe SliceStructureCorrespondency bzw. correspoinding_structure_vector unter correspoinding_structure ) // Es muessen alle eintraege von SliceStructureCorrespondency durchsucht werden um festzustellen, // ob es sich um ein slice des dose cubes handelt, das diesem Strukturelement zugeordnet ist. // Dabei muss beachtet werden, dass eine Structurelement fuer mehrere verschiedene Slices // das zugehoerige sein kann. LegacyWorldCoordinate2D coord2D; coord2D.x = 0; coord2D.y = 0; correspoinding_structure_vector str_v; str_v = SliceStructureCorrespondency.at( index_z ); int resolution_level = 0; for(unsigned int count = 0 ; count < str_v.size() ; count++ ){ unsigned int struct_index = str_v.at( count ); // iteration polygon for(unsigned int point_index = 0 ; point_index < ( Intersections.at(resolution_level).at( struct_index ).size() ); point_index++ ){ for(unsigned int intersect_index = 0 ; intersect_index < Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.size() ; intersect_index++ ){ coord2D = Intersections.at(resolution_level).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ); if( ( coord2D.x >= 0 ) && ( coord2D.y >= 0 ) && ( coord2D.x < MaskField.at( resolution_level )->GetDimX() ) && ( coord2D.y < MaskField.at( resolution_level )->GetDimY() ) ){ unsigned int index_x = static_cast( floor( coord2D.x ) ); unsigned int index_y = static_cast( floor( coord2D.y ) ); //MaskField.at( resolution_level )->PutData( index_x , index_y , index_z , brightness_border ); if( FieldOfIntersections ){ if( floor( coord2D.y ) == coord2D.y ){ unsigned int voxel_side = 0; AddToFieldOfIntersections( index_x , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } else if( floor( coord2D.x ) == coord2D.x ){ unsigned int voxel_side = 3; AddToFieldOfIntersections( index_x , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } } if( ( floor( coord2D.x ) == coord2D.x ) && ( index_x > 0 ) ){ //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , index_y , index_z , brightness_border ); if( FieldOfIntersections ){ // Ecke wird gegebenenfalls mit angehaengt unsigned int voxel_side = 1; AddToFieldOfIntersections( ( index_x - 1 ) , index_y , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } } if( ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) ){ //MaskField.at( resolution_level )->PutData( index_x , ( index_y - 1 ) , index_z , brightness_border ); if( FieldOfIntersections ){ if( floor( coord2D.x ) == coord2D.x ){ // Ecke wird gegebenenfalls nicht mit angehaengt, deshalb Fallunterscheidunn noetig, damit sie angehaengt wird ( Ecke wird nur an die Kante angehaengt an deren Anfang sie steht) unsigned int voxel_side = 3; AddToFieldOfIntersections( index_x , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } else{ unsigned int voxel_side = 2; AddToFieldOfIntersections( index_x , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } } } if( ( floor( coord2D.x ) == coord2D.x ) && ( floor( coord2D.y ) == coord2D.y ) && ( index_y > 0 ) && ( index_x > 0 ) ){ //MaskField.at( resolution_level )->PutData( ( index_x - 1 ) , ( index_y - 1 ) , index_z , brightness_border ); if( FieldOfIntersections ){ unsigned int voxel_side = 2; AddToFieldOfIntersections( ( index_x - 1 ) , ( index_y - 1 ) , 0 , struct_index , point_index , intersect_index , coord2D, voxel_side ); } } } } } } } void Mask::AddToFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , LegacyWorldCoordinate2D coord2D, unsigned int voxel_side ){ int which_one = GetRespectiveIntersections( index_x , index_y , 0 , struct_index ); IterativePolygonInTermsOfIntersections::WhichIntersection which_intersection; which_intersection.point_index = point_index; which_intersection.intersection_index = intersect_index; which_intersection.column_raw_or_unified = 2; bool go = IsItToBeRegarded( struct_index , point_index , intersect_index, index_x , index_y ); if( go ){ if( which_one != (-1) ){ SetThisIntersectionToCornerOrEdge( index_x , index_y , which_intersection , coord2D , voxel_side, FieldOfIntersections->GetData( index_x , index_y, index_z )->at(which_one) ); } else{ ExtendFieldOfIntersections( index_x , index_y , 0 , struct_index ); int which_one = GetRespectiveIntersections( index_x , index_y , 0 , struct_index ); if( which_one == (-1) )assert( 0 ); SetThisIntersectionToCornerOrEdge( index_x , index_y , which_intersection , coord2D , voxel_side, FieldOfIntersections->GetData( index_x , index_y, index_z )->at(which_one) ); } } } bool Mask::IsItToBeRegarded( unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , int index_x , int index_y ){ // Muss betrachtet werden, falls der Konturpunkt sich in x oder durch y vom Schnittpunkt der zusaetzlich durch den intersect_index gegeben ist unterscheidet. // Falls Schnittpunkt mit der Kante, der zusaetzlich durch intersect_index gegeben ist und der Konturpunkt nicht in x oder y unterscheiden, // wird der vorherige Konturpunkt betrachtet. Und zwar der erste, der sich von dem intialen tatsaechlich unterscheidet. // Wenn dieser Punkt in einer Richtung z.B. x auf der selben Kante liegt, sich aber in y Richtung unterscheidet, oder andersherum, // dann muss der Schnittpunkt betrachtet werden, obwohl er mit einem Konturpunkt zusammenfaellt, weil der vorhergehende Konturpunkt auf der gleichen Kante liegt (eventuell in anderem Voxel, aber auf der selben Kante) // Es ist nicht noetig die Selbe Stelle der Kante zweimal zu betrachten. Diese Stelle hier wird vom vorhergehenden Konturpunkt ausgehend als Schnittpunkt erkannt werden und wird deshalb hier nicht beruecksichtigt if( ( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y != Intersections.at(0).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ).y ) || ( Intersections.at(0).at(struct_index).at( point_index ).intersections_raw_and_column.at( intersect_index ).x != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) )return true; else{ unsigned int struct_index_other = struct_index; unsigned int point_index_other = point_index; unsigned int intersect_index_other = intersect_index; if( GetFirstDifferent( struct_index_other , point_index_other , Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord ) ){ if( ( floor(Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y / 1.0 ) != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ) && ( floor(Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x / 1.0 ) == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) ){ if( Intersections.at(0).at(struct_index_other).at( point_index_other ).contour_point_voxel_coord.x == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ){ return true; } } else if( ( floor( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y / 1 ) == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ) && ( floor( Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x / 1 ) != Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.x ) ){ if( Intersections.at(0).at(struct_index_other).at( point_index_other ).contour_point_voxel_coord.y == Intersections.at(0).at(struct_index).at( point_index ).contour_point_voxel_coord.y ){ return true; } } } else assert( 0 ); } return false; } bool Mask::GetFirstDifferent( unsigned int& struct_index , unsigned int& point_index , LegacyWorldCoordinate3D compare_point ){ if( Intersections.at(0).at(struct_index).size() <= 1 ){ std::cerr<< " Doesn't make sense to voxelize contour with less than two points ! " < 0 ) point_index--; else point_index = ( Intersections.at(0).at(struct_index).size() - 1 ); counter++; if( counter > ( Intersections.at(0).at(struct_index).size() * 2 ) ) break; } return false; } void Mask::ExtendFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ){ LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); LegacyDoseVoxelIndex3D aDoseIndex; aDoseIndex.x = index_x; aDoseIndex.y = index_y; aDoseIndex.z = index_z; //PolygonInfo polInf = PolygonInfo( the_polygon_ref , struct_index , brightness_outside , brightness_inside , MaskField.at( resolution_level ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(resolution_level) ); VoxelIntersectionsVectorPointer pol_inf_pointer = new std::vector(); FieldOfIntersections->PutData( index_x, index_y, index_z , pol_inf_pointer ); IntersectionsThisVoxel intersection_info; intersection_info.SetPolygonNumber( struct_index ); FieldOfIntersections->GetData( index_x , index_y, index_z )->push_back( intersection_info ); } int Mask::GetRespectiveIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ) const{ if( FieldOfIntersections->GetData( index_x , index_y, index_z )!= NULL ){ for( int i = 0 ; i < FieldOfIntersections->GetData( index_x , index_y, index_z )->size() ; i++ ){ if( FieldOfIntersections->GetData( index_x , index_y, index_z )->at(i).GetPolygonNumber() == struct_index )return i; } return (-1); } else return (-1); } LegacyWorldCoordinate2D Mask::GetDoubleIndex2D( double x , double y, int resolution_level ){ LegacyWorldCoordinate2D result; // zunaechst // x_world = imageOrientationRow.x*pixelSpacingRow*the_index.x+imageOrientationColumn.x*pixelSpacingColumn*the_index.y+imagePosition.x; // y_world = imageOrientationRow.y*pixelSpacingRow*the_index.x+imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; // mit x_world y_world ( Welt Koordinaten alles andere dcmtkrt Ausdruecke ) // daraus folgt // Gleichung a : ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.x ; // Gleichung b : y_world = imageOrientationRow.y*pixelSpacingRow* ( ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn*the_index.y ) ) / ( imageOrientationRow.x*pixelSpacingRow ) ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y+imagePosition.y; // Gleichung b weiter aufgeloest nach the_index.y // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn*the_index.y )/ ( imageOrientationRow.x*pixelSpacingRow ) +imageOrientationColumn.y*pixelSpacingColumn*the_index.y // Gelichung b weiter umgeformt : // y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) = the_index.y * ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) // es ergibt sich // aus Gleichung b : the_index.y = a / b // wobei a = y_world - imagePosition.y - imageOrientationRow.y*pixelSpacingRow*( x_world - imagePosition.x ) / ( imageOrientationRow.x*pixelSpacingRow ) // und b = ( imageOrientationColumn.y*pixelSpacingColumn - imageOrientationRow.y*pixelSpacingRow*( imageOrientationColumn.x*pixelSpacingColumn )/ ( imageOrientationRow.x*pixelSpacingRow ) ) // Folglich erbibt sich aus Gleichung a : // the_index.x = ( ( x_world - imagePosition.x ) - ( imageOrientationColumn.x*pixelSpacingColumn* ( a / b ) ) ) / ( imageOrientationRow.x*pixelSpacingRow ) // Uebersichtlicher : // the_index.x = ( c - ( d * ( a / b ) ) ) / e // c = ( x_world - imagePosition.x ) // d = imageOrientationColumn.x*pixelSpacingColumn // e = ( imageOrientationRow.x*pixelSpacingRow ) // in anderen Worten : double a = y - GInf.at(resolution_level).getImagePositionPatient()(1) - GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow() * ( x - GInf.at(resolution_level).getImagePositionPatient()(0) ) / ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ) ; double b = GInf.at(resolution_level).getImageOrientationColumn()(1) * GInf.at(resolution_level).getPixelSpacingColumn() - GInf.at(resolution_level).getImageOrientationRow()(1) * GInf.at(resolution_level).getPixelSpacingRow() * ( GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn() ) / ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ) ; double c = ( x - GInf.at(resolution_level).getImagePositionPatient()(0) ) ; double d = GInf.at(resolution_level).getImageOrientationColumn()(0) * GInf.at(resolution_level).getPixelSpacingColumn(); double e = ( GInf.at(resolution_level).getImageOrientationRow()(0) * GInf.at(resolution_level).getPixelSpacingRow() ); //alt // folglich ergeben sich die voxel Koordinaten zu //result.x = ( ( c - ( d * ( a / b ) ) ) / e ) ; //result.y = ( a / b ) ; // neu // folglich ergeben sich die voxel Koordinaten zu // Hier muss das resolution level beruecksichtigt werden. Aenderung vornehmen. Auch testen ! // result.x = ( ( c - ( d * ( a / b ) ) ) / e ) + 0.5; // result.y = ( a / b ) + 0.5; result.x = ( ( c - ( d * ( a / b ) ) ) / e ) + GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); result.y = ( a / b ) + GetWorldCoordinateOffsetThisResolutionLevel( resolution_level ); return result; } LegacyWorldCoordinate2D Mask::GetDoubleIndex2D( double x , double y ){ return GetDoubleIndex2D( x , y, 0 ); } double Mask::GetWorldCoordinateOffsetThisResolutionLevel( int resolution_level ){ double world_coord_offset = 1; for( int i = 1 ; i <= resolution_level ; i++ )world_coord_offset *= 2; world_coord_offset = ( 0.5 / world_coord_offset ); return world_coord_offset; } double Mask::GetBlockLengthThisResolutionLevel( int resolution_level ){ double length = 1; for( int i = 1 ; i <= resolution_level ; i++ )length *= 2; return length; } LegacyWorldCoordinate1D Mask::GetZIndex( LegacyWorldCoordinate1D z ){ // alt // return ( ( z - GInf.at(0).getImagePositionPatient()(2) ) / GInf.at(0).getSliceThickness() ); //neu LegacyWorldCoordinate1D result = ( ( z - GInf.at(0).getImagePositionPatient()(2) ) / GInf.at(0).getSliceThickness() ) + 0.5; return result; } bool Mask::GetSomeBorderVoxelXYZForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ correspoinding_structure_vector str_v; bool got_it = false; while( ( got_it == false ) && ( aDoseIndex.z < ( SliceStructureCorrespondency.size() ) ) ){ str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); if( ( str_v.size() > 0 ) && ( GetSomeBorderVoxelXYForTest( aDoseIndex ) ) ){ got_it = true; } else aDoseIndex.z++; } return got_it; } bool Mask::GetSomeBorderVoxelXYForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ bool voxel_found = false; unsigned int z = aDoseIndex.z; int resolution_level = 0; for( unsigned int x = 0 ; x < MaskField.at( resolution_level )->GetDimX() ; x++ ){ for( unsigned int y = 0 ; y < MaskField.at( resolution_level )->GetDimY() ; y++ ){ if( MaskField.at( resolution_level )->GetData( x, y, z ) == brightness_border ){ voxel_found = true; aDoseIndex.x = x; aDoseIndex.y = y; x = MaskField.at( resolution_level )->GetDimX(); y = MaskField.at( resolution_level )->GetDimY(); } } } return voxel_found ; } bool Mask::DoubleCheckIsOnBorderForTest( LegacyDoseVoxelIndex3D& aDoseIndex ){ int resolution_level = 0; if( MaskField.at( resolution_level )->GetData( aDoseIndex.x, aDoseIndex.y, aDoseIndex.z ) == brightness_border ) return true; else return false; } bool Mask::CheckFractionThisVoxelCorrectForTest( LegacyDoseVoxelIndex3D another_dose_index , float the_correct_result ){ if( GetFractionInside( another_dose_index ) == the_correct_result ) return true; else return false; } float Mask::GetFractionThisVoxelForTest( LegacyDoseVoxelIndex3D another_dose_index ){ return GetFractionInside( another_dose_index ); } PolygonInfo* Mask::JustCreateAPolygonInfoForTest( LegacyDoseVoxelIndex3D aDoseIndex ){ PolygonInfo* polInfTest = NULL; if( do_detailed_subvox ){ correspoinding_structure_vector str_v; bool got_it = false; while( ( got_it == false ) && ( aDoseIndex.z < ( SliceStructureCorrespondency.size() - 1 ) ) ){ str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); if( str_v.size() > 0 ) got_it = true; else aDoseIndex.z++; } // Nur der erste Polygonzug des entsprechenden slices wird betrachtet, daher keine Schleife ueber alle Strukturen dieses Slices noetig. // Die Teststruktur die hier verwendetw wird besteht in diesem Slice nur aus einem Polygonzug. // for( unsigned int count = 0 ; count < str_v.size() ; count++ ){ if( got_it ){ int struct_index = str_v.at( 0 ); LegacyPolygonSequenceType pol_seq; PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); if( FieldOfIntersections ){ FieldOfIntersections->SetZero(); GetIntersectionInformationThisSlice( aDoseIndex.z ); } int which_one = GetRespectiveIntersections( aDoseIndex.x , aDoseIndex.y , 0 , struct_index ); if( which_one != (-1) ){ IntersectionsThisVoxel intersections_this_voxel = FieldOfIntersections->GetData( aDoseIndex.x , aDoseIndex.y , 0 )->at( which_one ); polInfTest = new PolygonInfo( the_polygon_ref, struct_index , brightness_outside , brightness_inside ,MaskField.at( 0 ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at( 0 ) , intersections_this_voxel ); } } else return NULL; } return polInfTest; } bool Mask::GetIntersectionsOfSliceForTest( unsigned int position , PolygonInTermsOfIntersections& Polygon_Intersections_Ref ){ if( position < Intersections.at(0).size() ){ Polygon_Intersections_Ref = Intersections.at(0).at( position ); return true; } else return false; } bool Mask::ReturnFirstWithIntersectionsForTest( unsigned int& position ){ position = 0; while( position < Intersections.at(0).size() ){ if( Intersections.at(0).at( position ).size() > 0 )return true; else position++; } position = 0; return false; } float Mask::GetFractionInside( const LegacyDoseVoxelIndex3D& aDoseIndex ) { double fraction_total = 0; correspoinding_structure_vector str_v; str_v = SliceStructureCorrespondency.at( aDoseIndex.z ); // Hier werden alle Polygone untersucht, die in diesem Slice liegen. for( unsigned int count = 0 ; count < str_v.size() ; count++ ){ int struct_index = str_v.at( count ); int which_one = GetRespectiveIntersections( aDoseIndex.x , aDoseIndex.y , 0 , struct_index ); //assert( which_one != (-1) ); // nein nicht assert, denn nicht jede Struktur die zu diesem Slice gehoert schneidet zwangslauefig dieses Voxel if( which_one != (-1) ){ LegacyPolygonSequenceType pol_seq; assert( struct_index < Intersections.at(0).size() ); const PolygonInTermsOfIntersections& Polygon_Intersections_Input_Ref = Intersections.at(0).at( struct_index ); LegacyPolygonSequenceType strVector = _structure->getLegacyStructureVector(); LegacyPolygonType& the_polygon_ref = strVector.at(struct_index); const IntersectionsThisVoxel& intersections_this_voxel = FieldOfIntersections->GetData( aDoseIndex.x , aDoseIndex.y , 0 )->at(which_one) ; PolygonInfo polInf = PolygonInfo( the_polygon_ref , struct_index , brightness_outside , brightness_inside , MaskField.at( 0 ) , Polygon_Intersections_Input_Ref , aDoseIndex , GInf.at(0) , intersections_this_voxel ); if( polInf.CreatePolygonSequence() ){ pol_seq = polInf.GetResultingSequence(); double fraction_this_polygon = 0; int numberOfContours = pol_seq.size(); for(int i=0; i= 0) ) std::cout<< " fraction_this_polygon : " << fraction_this_polygon <= 0 ); // that's essential since ResultingSequence is represented in Voxel coordinates //assert( fraction_this_polygon <= 1 ); // that's essential since ResultingSequence is represented in Voxel coordinates //double voxel_volume = GInf.at(resolution_level).getPixelSpacingRow() * GInf.at(resolution_level).getPixelSpacingColumn() * GInf.at(resolution_level).getSliceThickness(); //if( voxel_volume == 0 )assert(0); // this must never happen. Since depends on dataset : exception to be implemented ! //fraction_this_polygon /= voxel_volume; } fraction_total += fraction_this_polygon; } } } // Iteration ueber Polygone return fraction_total; } }//namespace }//namespace }//namespace diff --git a/code/masks/rttbMask.h b/code/masks/legacy/rttbMask.h similarity index 98% rename from code/masks/rttbMask.h rename to code/masks/legacy/rttbMask.h index e37ddd4..d8d52b5 100644 --- a/code/masks/rttbMask.h +++ b/code/masks/legacy/rttbMask.h @@ -1,757 +1,757 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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_H #define __RT_MASK_H #include "rttbBaseType_LEGACY.h" #include "rttbBaseType.h" #include "rttbStructure_LEGACY.h" #include "DoseVoxel_LEGACY.h" #include "DoseIteratorInterface_LEGACY.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" #include "rttbContour_LEGACY.h" #include "rttbPolygonInfo_LEGACY.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include #include namespace rttb{ namespace masks{ namespace legacy{ /*! @class Mask * @brief This class represents the Mask calculated using a dose iterator and a StructureLegacy/DoseVoxelVector. The mask is first calculated with voxel accurracy. Those voxels that are touched by the structure are then further regarded using PolygonInfo and IterativePolygonInTermsOfIntersections to find out the fraction that is inside the structure. The voxelization is done on several resultution levels, but the calculation on subvoxel accurracy, that means the calculation of the fraction of the voxel that is inside the structure, is done solely on the finest resolution level. And solely for those voxels that are touched by the structure - typically most voxels are not. This multi resolution approach is much faster as compared to doing it on just one level, because a voxel that is not touched by the structure and determinded to be inside the structure on a croase resolution level does on all finer resolution level solely correspond to voxels that are inside, too. The same goes for a voxel that was determined to be completely outside: All the voxels that are contained in this voxel on each finer resolution level are colpletely outside, too. So the creation of the mask without subvoxel accurracy is done on the croasest resolution level completely and for each voxel with clear affiliation inside/outside all the respective voxels are set for all the finer resolution levels right away as they are determined on a croase level. It is cumputational effort to create several masks and it is effort to set the inside/outside affiliation of a voxel on all levels instead of just one. However, it saves effort, because on each finer resolution level, only view voxels need to be considered: Those that are close to the contour and were thus touched by the contour on the previous level that was to croase to tell the inside/outside affiliation. Since there is a factor four in the number of voxels between two levels, the multi resouluton calculation is fast, because view voxels need to be regarded. Field.h has an efficient way of finding those voxels with unclear affiliation and of setting affiliation throughout resoltuion levels in blocks. After reaching the finest resolution those voxels that are still in the border region and thus just touched by the structure are then further examined with subvoxel accurracy, based on PolygonInfo and IterativePolygonInTermsOfIntersections. */ class Mask{ public: /*! @brief Constructor with a DoseIterator and a StructureLegacy * The mask is calculated with sub voxel fraction info. @pre The Structure must not intersect itself. It may touch itself. @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about the dose value associated with each voxel. @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. * @exception RTTBNullPointerException thrown if aDoseIter or aStructure is NULL */ Mask( DoseIteratorInterface* aDoseIter , StructureLegacy* aStructure); /*! @brief Constructor with a DoseIterator and a vector of DoseVoxel inside a structure (with voxel proportion information) @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about the dose value associated with each voxel. @param aDoseVoxelVector is a reference to a vector that holds values of the type DoseVoxel. Using this parameter it is possible to accept a given "voxelization" created by Mevis for example. * @exception RTTBNullPointerException thrown if aDoseIter is NULL */ // Mask( DoseIteratorInterface* aDoseIter , const std::vector& aDoseVoxelVector ); /*! @brief Constructor with a DoseIterator and a StructureLegacy * The mask is calculated with sub voxel fraction info. @pre The Structure must not intersect itself. It may touch itself. @param aGeoInfo is a pointer to a GeometricInfo of the dose. @param aStructure is a Pointer to the StructureLegacy which holds the contour the mask shall be based on. * @exception RTTBNullPointerException thrown if aDoseGeoInfo or aStructure is NULL */ Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure); /*! @brief Destructor */ ~Mask(); /*! @brief Old Code!!! It is unnecessary now. The user should check the geometric information of the new dose iterator, if changed, generate new mask using Mask( core::GeometricInfo* aDoseGeoInfo , StructureLegacy* aStructure)! *Old brief: Reset dose. If the geometric information has not changed, the _doseVoxelInStructure does not need to be recalculated, in case other dose values are introduced for the same structure and geometry. Only doseData needs to be recalculated. @param aDoseIter is a pointer to a DoseIteratorInterface. It is supposed to contain the information about the dose value associated with each voxel. * @exception RTTBNullPointerException Thrown if aDoseIter or aStructure is NULL */ void resetDose(DoseIteratorInterface* aDoseIterator); /*! @brief Get the dose voxels which lie inside the structure * @return Vector of DoseVoxel which are inside the structure (with voxel proportion information) */ const std::vector& getDoseVoxelInStructure() const; /*! @brief Set the vector of DoseVoxel which are inside the structure (with voxel proportion information) * @param aDoseVoxelVector Vector of RTDoseVoxels inside the structure to be set. * @return */ void setDoseVoxelInStructure(std::vector aDoseVoxelVector); /*! @brief Get the dose iterator * @return DoseIteratorInterface& returns the dose Iterator. */ const DoseIteratorInterface& getDoseIterator() const; /*! @brief Get the structure * @return StructureLegacy& Returns the structure. */ const StructureLegacy& getRTStructure() const; /*! @brief Get absolute dose data of the voxels which are inside the structure. @return Returns the dose values. */ //const std::vector getDoseData() const; /*new...................*/ /*! @brief Calculates 2D voxel coordinates from 2D world coordinates. @param x voxel coordinate x @param y voxel coordinate y @return Returns 2D world coordinates. */ LegacyWorldCoordinate2D GetDoubleIndex2D( double x , double y ); /*! @brief Calculates 2D voxel coordinates from 2D world coordinates taking the current resolution level under consideration. @param x voxel coordinate x @param y voxel coordinate y @param resolution_level current resolution @return Returns 2D voxel coordinates. */ LegacyWorldCoordinate2D GetDoubleIndex2D( double x , double y, int resolution_level ); /*! @brief The offset between world and voxel coordinate system depends on the current resolution. This function calculates this offset. @param resolution_level current resolution @return Returns the offset between world and voxel coordinate system. */ double GetWorldCoordinateOffsetThisResolutionLevel( int resolution_level ); // Functions and other stuff needed for unit tests: /*! @brief Needed for unit tests. Provides the Information about the Intersections of a specific polygon, that is part of the structure, with the edges of the voxels. @param position Index des polygon of interest. The structure consists of an entity of plygons. @param Polygon_Intersections_Ref Refernce to an object of the Type PolygonInTermsOfIntersection. After running the function, this Reference holds the Information about the intersections of the polygon of interest (specified by position) with the voxel edges. @return This function returns false and does not do its job, in case "position" holds an unreasonalble value, e.g. refers to a polygon that does not exist. */ bool GetIntersectionsOfSliceForTest( unsigned int position , PolygonInTermsOfIntersections& Polygon_Intersections_Ref ); /*! @brief Needed for unit tests. Returns true in case there are any intersections of the structure with the voxel edges. A reference to an integer is set to the index of the first polygon that intersects with voxel edges in case there are intersections. Otherways the reference is set to zero and the function returns false. @param position Some reference to some integer which is modified by this function. In case there are any intersection this reference is set to the index of the first intersecting polygon. Otherways it is set to zero. @return Returns false in case there are no intersections and true in case there are intersections of the contour with the voxel edges. */ bool ReturnFirstWithIntersectionsForTest( unsigned int& position ); /*! @brief Needed for unit tests. This function is made to test the function GoIntersectColumn which is private and therefore not accessible for the testing unit. This function called TestGoIntersectColumnByComparisonWithExpectedResult is provided with two 3D Points and with a vector called expected_intersections_ref that holds the information about those intersections that are to be expected. These values are set by the one who wrote the unit test. Now these expected values are compared with those that are calculated by the function GoIntersectColumn and in case there is any deviation between acutal an expected result this function here returns false. Otherwise it returns true. @param firstPoint The first one of two points that specify a line which is to be checked for intersections with voxel edges. @param secondPoint The second one of two points that specify a line which is to be checked for intersections with voxel edges. @param column_intersections_ref After running this function this reference to a vector of objects of the type LegacyWorldCoordinate2D holds the information about the calculated intersections. @param expected_intersections_ref This is a reference to a vector of objects of the type LegacyWorldCoordinate2D which holds the information about the expected intersections. These intersections are set by the programmer who writes the unit test and who knows the correct intersections. @return This funciton returns true in case the function GoIntersectColumn turned out to work properly. Otherwise it returns false. */ bool TestGoIntersectColumnByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, std::vector& expected_intersections_ref ); /*! @brief Needed for unit tests. See TestGoIntersectColumnByComparisonWithExpectedResult for details since this function here is very similar. The only difference is that this funciton is made to help with unit testing with respect to the funcion GoIntersectRaw instead of GoIntersectColumn - despite that its just the same. */ bool TestGoIntersectRawByComparisonWithExpectedResult( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, std::vector& expected_intersections_ref ); /*! @brief Needed for unit tests. Checks whether two vectors of points that are passed to this function are identical. @param calculated_intersections_ref First vector of points to be compared with the second one. @param expected_intersections_ref Second vector of points to be compared with the first one. @return Returns true in case the vectors are identical. */ bool IdenticalIntersectionsForTest( std::vector& calculated_intersections_ref , std::vector& expected_intersections_ref ); /*! @brief Needed for unit tests. An object of the type PolygonInfo can only be created in an environment that has all the incredients that are necessary. Since in Mask all the incredients are available and since there is no other environment, where this is the case, since PolygonInfos are sofar not created anywhere else, this function was created, just in order to create and return a PolygonInfo object for test purposes. So this function creates an object of the type PolygonInfo and retunrns a pointer to it. The PolygonInfo is created either for a voxel with cordinates aDoseIndex, given as a parameter or alternatively for a voxel with greater z-position in case there is no contour in the slice of the given location. In case there is no contour in any slice with greater z-position either, the PolygonInfo can not be created. In that case a nullpointer is returned. @param aDoseIndex Position for which the PolygonInfo object is to be created. @return Returns an object of the type PolygonInfo in case a polygon of the structure can be found. Otherways it returns a NULL pointer. */ PolygonInfo* JustCreateAPolygonInfoForTest( LegacyDoseVoxelIndex3D aDoseIndex ); /*! @brief Needed for unit tests. Checks for a specific voxel, whether the correct fraction of this voxel was recognized to be enclosed by the structure. @param another_dose_index parameter of type LegacyDoseVoxelIndex3D which specifies the voxel coordinate of interest. @param the_correct_result is a float that specifies the expected result. @return Returns true in case Mask did well and the calculated fraction meets the expectation. */ bool CheckFractionThisVoxelCorrectForTest( LegacyDoseVoxelIndex3D another_dose_index , float the_correct_result ); /*! @brief Needed for unit tests in order to access the fraction of a specific voxel that was determined to be enclosed by the structure. @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. @return Returns a float that holds the informaton about the portion of the voxel which is enclosed by the structure. */ float GetFractionThisVoxelForTest( LegacyDoseVoxelIndex3D another_dose_index ); /*! @brief Needed for unit tests. Returns true in case the voxel specified by aDoseIndex is touched by the structure. @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which specifies the voxel position of interest. @return Returns true in case the voxel specified by aDoseIndex is touched by the structure. */ bool DoubleCheckIsOnBorderForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by the structure. @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function. If things go well, it is set to a voxelposition touched by the structure. In that case the function returns true. @return Returns false in case no voxel is touched by the structure. Otherways returns true. */ bool GetSomeBorderVoxelXYZForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); // End functions and other stuff needed for unit tests protected: typedef std::vector* VoxelIntersectionsVectorPointer; // @brief withSubVoxelFraction If true, the mask will be calculated with sub voxel fraction info; otherwise, without // sub voxel fraction info, that means getDoseVoxelInStructure() returns the DoseVoxel with getProportionInStr()= 1. // //bool _withSubVoxelFraction; /// the dose iterator DoseIteratorInterface* _doseIter; /// the structure StructureLegacy* _structure; /// vector of the RTDoseVoxels inside the structure std::vector _doseVoxelInStructure; /// vector of the dose values corresponding to _doseVoxelInStructure, it has the same size as _doseVoxelInStructure std::vector _doseData; /// geometric information about the dose distribution std::vector< core::GeometricInfo > GInf; //VoxelIntersectionPointsMap voxel_intersectionPoints; /// Once they are determined to be inside voxels get this brightness. field_content_type brightness_inside; /// Once they are determined to be touched by the structure voxels get this brightness. field_content_type brightness_border; /// Once they are determined to be outside voxels get this brightness. field_content_type brightness_outside; /// Voxels that are yet not determinded to be inside the structure, outside the structure or touched by the structure are marked with this brightness. field_content_type brightness_unknown; /// Calculates the mask. void Calc(); /// Just for test. Doublechecks and does assert(0) in case something has gone wrong. void TestVoxelMaskUppward(); /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. There are situations throughout the algorithm where it is known, that a specific affiliation of one voxel on one resolution level does determine its affiliation on other resolution levels. The job of this function is to check that and to assert, it terminates the program deliberately if something has happened, that definitely must never happen. @param resolution_level_in Integer that species the current resolution level. @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system on the current resolution level that is to be checked throughout all finer levels. @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. */ void CheckUppwardBlockSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); /*! @brief This function sets a brightness of a voxel throughout resolution levels, since the Voxelisierung is done on several resultution levels as explained above. @param resolution_level_in Integer that species the current resolution level. @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system on the current resolution level that is to be set at first and then throughout all finer levels adapted to the finer voxel coordinate sysetem. @param brightness Integer that specifies the brightness that is to be set on the current and throughout all the finer resolution levels. */ void SetUppwardBlockThisIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); /*! @brief This function is made for assertation. The voxelization is done on several resultution levels as explained above. There are situations where a specific affiliation of one voxel on one resolution level does determine affiliation of at least one voxel on any finer resolution level to the same intensity, within a specific block of voxels that corresponds to the voxel in position index_internal on the croase level. The job of this function is to check whether there is any such voxel on every finer resolution level, within the respective block. So this function terminates the program deliberately if something has happened, that definitely must never happen. @param resolution_level_in Integer that species the current resolution level. @param index_internal Parameter of the type LegacyUnsignedIndex3D which specifies the position in the voxel coordinate system on the current resolution level that is to be checked throughout all finer levels. @param brightness Integer that specifies the brightness that is expected throughout all the finer resolution levels. */ void CheckUppwardOneOutOfThisBlockHasSameIntensity( int resolution_level_in , LegacyUnsignedIndex3D index_internal , int brightness ); /*! @brief Calculates for some resolution level the number of voxels of the finest resolution level, that fit into this voxel one dimensionally. So this is a number of fine voxels that fit into this croase voxel along the length of this croase voxel. @param resolution_level Integer that specifies the resolution level of the croase voxel. Whereas zero is the finest level, one the next croase level with a total number of voxels of just one quater of the next finer level .... and so on .... @return Returns a double that holds the information about the block length. Actually it should be an integer, but a double works, too ... */ double GetBlockLengthThisResolutionLevel( int resolution_level ); /*! @brief Checks the structure, so checks all polygons of the structure, on intersections with themselves. @return Returns true, if the structure does not contain self intersecting polygons and thus is fine. */ bool ContourFine(); /*! @brief Checks two polygons for intersection with one another. Checks one polygon for intersection with itself, in case struct_index_a and struct_index_b are the same. @param struct_index_a Integer that specifies the index of the first polygon that is to be checked for intersections. @param struct_index_b Integer that specifies the index of the second polygon that is to be checked for intersections. @return Returns true if the polygons do intersect (or if the polygon does intersect in case of a check for self intersection). */ bool DoesIntersect( int struct_index_a , int struct_index_b ) const; /*! @brief Checks two lines for intersection. @param firstPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the first line. @param secondPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the first line. @param thirdPoint Paramter of type LegacyWorldCoordinate3D that specifies the beginning of the second line. @param fourthPoint Paramter of type LegacyWorldCoordinate3D that specifies the end of the second line. @return Returns true in case there is an intersection. */ bool HasIntersectionsThisPair( const LegacyWorldCoordinate3D& firstPoint , const LegacyWorldCoordinate3D& secondPoint, const LegacyWorldCoordinate3D& thirdPoint , const LegacyWorldCoordinate3D& fourthPoint ) const; /*! Holds the masks for different resolution levels. To be initialized in Constructor by an initialization function. */ std::vector< rttb::masks::legacy::FieldOfScalar* > MaskField; /*! Two dimensional field. Content of one element holds the information about the intersections of the structure with the voxel edges of the corresponding voxel. The object, that holds this intersecton information for the voxel in position x,y within the slice, is located in the position x,y within FieldOfIntersections. FieldOfIntersections is created for just one slice - the slice which Mask is currently working on. */ rttb::masks::legacy::FieldOfPointer* FieldOfIntersections; bool do_detailed_subvox; /// If do_detailed_subvox is true, the Mask is calculated with sub-voxel accurracy. /*! To be initialized in Constructor by an initialization function. Holds the information about the structure and its Intersections with the voxel edges. */ std::vector Intersections; ///Holds the information about the structure and its Intersections with the voxel edges. /*! @brief Fills _doseVoxelInStructure with DoseVoxel objects. Each of these DoseVoxel objects carries the information about the portion of the voxel that is enclosed by the structure. The DoseVoxel objects are created based on the Mask with the finest resolution. Based on this Mask field it is clear that the voxel is completely inside the structure or completely outside in most of the cases. SetDoseVoxelInStructureVector calls GetFractionInside() and thus determines the fraction of the voxel that is enclosed by the structure in case the voxel is touched by the structure and thus not yet determined to be completely inside or outside. */ void SetDoseVoxelInStructureVector(); /*! @brief Old stuff. */ void SeperateRegions(); /*! @brief Old stuff. */ void SeperateRegionsQuick(); /*! @brief Old Stuff. */ void ConnectArea( field_content_type brightness_from , field_content_type brightness_to , LegacyUnsignedIndex3D start_index, LegacyDoseVoxelIndex2D index_begin, LegacyDoseVoxelIndex2D index_end ); // To be called by SetDoseVoxelInStructureVector /*! @brief To be initialized by an init function that is called by Constructor. Holds the information about how the polygons correspond to the slices. */ std::vector SliceStructureCorrespondency; /*! @brief To be initialized by an init fuction which is called by Constructor. Contains the information about which area of the image is actually to be regarded. A large part of the image may be far off from any polygon. */ vector_of_area_vectors MarkInterestingArea; /*! @brief Is called by the constructor and calls other initialization fucntions. */ void Init(); /*! @brief Searches backward in Intersections until a point is reached that differs from compare_point. point_index is set to the index of this point. @param struct_index Reference to an integer that specifies the polygon of interest. @param point_index Reference to an integer that is modified by this function. First it specifies the index of the point where the function stearts searching. It is decremented during the search and in the end it points to the first point within the search direction that turned out to be different from compare_point. @param compare_point Parameter of the type LegacyWorldCoordinate3D. Specifies a point. This function searches for a point which differs from compare_point. @return Returns true in case such a point was found and false in case it was not. */ bool GetFirstDifferent( unsigned int& struct_index , unsigned int& point_index , LegacyWorldCoordinate3D compare_point ); /*! @brief This function determines whether the intersection with struct_index, point_index and intersect_index is to be set to the FieldOfIntersections. It is to be set in case the intersection with the voxeledge is either not a point of the polygon, or in case it is ( that means the point of the polygon is on the edge of a voxel ) and at the same time the previous point of the polygon has one identical coordinate in a way so that it is located on the same edge, too (eventually alongside another voxel, so the same edge here means "same column seperating voxels"). @param struct_index Index of the polygon. @param point_index Index of the point within the polygon (last one between the intersection that is currently being processed). @param intersect_index Index of the intersection that is currently being processed. @param index_x X-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. @param index_y Y-position of the voxel. The element of FieldOfIntersectons that belongs to this voxel is calculated right now. @return Retruns true in case the intersection with struct_index, point_index and intersect_index is to be set to the FieldOfIntersections. */ bool IsItToBeRegarded( unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , int index_x , int index_y ); /*! @brief This function calls SetThisIntersection with the respective parameters and therefore takes part in positioning the intersection characterized by the parameter intersection within the FieldOfIntersections. @param index_x X-position of the voxel. @param index_y Y-position of the voxel. @param intersection Specifies the intersection that is currently regarded (similar to an index, specifies location where the intersection can be found within the object Intersections). @param coord2D Voxel coordinate of the intersection. @param edge_number Denotes the edge which the intersection is on. @param voxel_intersections The element within FieldOfIntersections that corresponds to this voxel and polygon. */ void SetThisIntersectionToCornerOrEdge(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D, unsigned int edge_number, IntersectionsThisVoxel& voxel_intersections ); /*! @brief This function positions an intersection within voxel_intersections. Practically voxel_intersections is an element within FieldOfIntersections (generally it can be any reference to an IntersectionsThisVoxel ). The voxel edge the intersection is placed to is given by edge_number. @param corner_of_interest The corner at the beginning of the respective edge. Beginning means the point of the edge that is first passed while surrounding the voxel clockwise. @param corner_next The corner at the end of the respective edge. That means the point along the edge that is passed last while surrounding the voxel clockwise. @param corner_fixed Its the coordinate, which is the same all along the edge. @param intersection Denotes the index of the regarded intersection in Intersections. @param coord_of_interest The coordinate which is interesting, because it is responsible for the position of the intersection along the edge, while the other coordinate is just the same for the intersection as well as for all the points that belong to the edge. @param coord_fixed This coordinate should equal to corner_fixed. The function asserts for that. Its the coordinate that all the points on the edge and the intersection point have in common. @param voxel_intersections Practically its an element of FieldOfIntersections (although generally it can be any element of IntersectionsThisVoxel). @param edge_number Number of the edge that is regarded. The edges are counted colckwise starting from upper left. */ void SetThisIntersection( unsigned int corner_of_interest, unsigned int corner_next , unsigned int corner_fixed , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , double coord_of_interest , double coord_fixed, IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ); /*! @brief This function checks whether value_to_compare is in between small_value_to_compare_with and big_value_to_compare_with. Practically value_to_compare is a coordinate of an intersection point. Practically big_value_to_compare_with is the end point of an edge. In case value_to_compare is in between, the index of the intersection (that characterizes its location within Intersections (Intersections is a global variabele, a vector of StructureInTermsOfIntersections) ) and its coordinates are appended to the corresponding edge within voxel_intersections. @param value_to_compare This value is to be compared with other values and inserted into voxel_intersections at the right place. @param small_value_to_compare_with First value to compare with. @param big_value_to_compare_with Second value to compare with. @param edge_number Number of the edge. Edges are counted clockwise, starting from upper left. @param intersection Index of the intersection within Intersections. @param voxel_intersections Object of type IntersectionsThisVoxel that holds the information about all the intersections of the structure with this currently regarded voxel as well as the information where to find these intersection within Intersections @return Retruns true in case insertation was successful. */ bool CompareIfBetweenAppend( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); /*! @brief This function checks whether the intersection point is already known. In case it is the index of the intersection within Intersections is appended to the already existing vector of points of the respective edge that all represent this specific intersection point (in case the structure goes through this point several times touching itself, otherways ist just one) (Intersections is a global variable, a vector of StructureInTermsOfIntersections which contains the information about all the intersections with all the voxel edges on all resolutions). In case it does not exist yet a new vector of indices as well as coordinates is created and inserted in the respective position. In case the same intersection point will be found again later on it will be appended then. @param value_to_compare Coordinate of the point to be inserted. @param edge_number Number of the edge. The edges are counted clockwise, starting from upper left. @param intersection Index of the intersectoin within Intersections. @param voxel_intersections An object representing the information about the intersections of the structure with this voxel, including the information about coordinates of the intersection points as well as indicees that represent the information about where to find them within Intersections. @return Returns true in case of a successful insertation. */ bool CheckIfIndenticalOrBetweenRespectiveVectorElementsAndDoInsert( double value_to_compare , unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); /*! @brief See CompareIfBetweenAppend - the only difference is, that this function inserts the intersection at the beginning of the edge and that practically small_value_to_compare_with is the first point within the respective edge while big_value_to_compare_with is either the first intersection that has aleready been found, or the last point within the edge. @return Returns true in case the intersection was inserted into voxel_intersections. */ bool CompareIfBetweenInsertAtBeginning( double value_to_compare , double small_value_to_compare_with , double big_value_to_compare_with, unsigned int edge_number, IterativePolygonInTermsOfIntersections::WhichIntersection intersection , IntersectionsThisVoxel& voxel_intersections ); /*! @brief Old stuff. */ void SetThisIntersectionXIncreasing( unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections , unsigned int edge_number ); /*! @brief Old stuff. */ void SetThisIntersectionYIncreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); /*! @brief Old stuff. */ void SetThisIntersectionXDecreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); /*! @brief Old stuff. */ void SetThisIntersectionYDecreasing(unsigned int index_x , unsigned int index_y , IterativePolygonInTermsOfIntersections::WhichIntersection intersection , LegacyWorldCoordinate2D coord2D , IntersectionsThisVoxel& voxel_intersections ); /*! @brief This function determines the area that contains voxels that need to be regarded. For example voxels within x-coordinate lower than the contour pont with lowest x-coordinate do not need to be regarded, since they can not be enclosed by the contor. Of course the same goes for other coordintates and ... */ void InitInterestingArea(); /*! @brief Initializes MaskField which contains the masks fields for different resolution levels and the corresponding geometric infromation stored in GInf. Different sizes are initialized, representing the different resolutions. Calls InitIntersections. */ void InitMultiResolution(); /*! @brief Initializes Intersections which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. This function just initializes, but yet does not calculate the intersections, so here Intersectons is created, but remains empty. */ void InitIntersections(); /*! @brief This function is called to calculate the intersections between structure and voxel edges and thus to fill Intersections with intersecton values, which is a vector of StructureInTermsOfIntersections and holds the information about the intersections between voxel grid and structure for different resolution levels. @param resolution_level Specifies for which voxel grid the intersections are to be calculated. In case it is zero it is done for the finest resolution and the values are filled into the first element of Intersections. */ void GetIntersections( int resolution_level ); /*! @brief This function fills intersections_raw_and_column_ref with intersection values. It operates on a segment of a polygon consisting of a line that connects a first and a second point. The intersections of this polygon segment with the voxel edges on the resolution_level are already determined and stored in raw_intersections_ref, which contains the intersections with raw-eges as well as column_intersections_ref which holds the intersections with the voxel edges regarding columns. In intersections_raw_and_column_ref they are sorted with respect to their distance from firstPoint and in the end intersections_raw_and_column_ref contains all the intersections - colum and raw intersections. @param firstPoint Starting point of the segment of the polygon. @param raw_intersections_ref Contains the raw intersections sorted with resepect to their distance from firstPoint. @param column_intersections_ref Contains the column intersections sorted with resepect to their distance from firstPoint. @param intersections_raw_and_column_ref After running this function intersections_raw_and_column_ref contains all intersections sorted with resepect to their distance from firstPoint. @param resolution_level The resolution level. Zero is finest. */ void UnifyRawAndColumn( LegacyWorldCoordinate3D firstPoint, std::vector& raw_intersections_ref , std::vector& column_intersections_ref , std::vector& intersections_raw_and_column_ref, int resolution_level ); /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). The line starts with firstPoint and ends with secondPoint. @param firstPoint Point to start the line. @param secondPoint point to end the line. @param raw_intersections_ref The intersections are placed here. @param resolution_level The current resolution. */ void GoIntersectRaw( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref , int resolution_level ); /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). The line starts with firstPoint and ends with secondPoint @param firstPoint Point to start the line. @param secondPoint point to end the line. @param column_intersections_ref The intersections are placed here. @param resolution_level The current resolution. */ void GoIntersectColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ); /*! @brief This function calculates the intersections between a line and the horizontal voxel edges (voxel edges in raw direction). The line starts with firstPoint and ends with secondPoint. This function is called in case the x-position of firstPoint and secondPoint are identical. @param firstPoint Point to start the line. @param secondPoint point to end the line. @param raw_intersections_ref The intersections are placed here. @param resolution_level The current resolution. */ void GoGetRawIntersectionsAlongThisColumn( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& raw_intersections_ref, int resolution_level ); /*! @brief This function calculates the intersections between a line and the vertical voxel edges (voxel edges in column direction). The line starts with firstPoint and ends with secondPoint. This function is called only in case the y-position of first and of second point are identical. @param firstPoint Point to start the line. @param secondPoint point to end the line. @param column_intersections_ref The intersections are placed here. @param resolution_level The current resolution. */ void GoGetColumnIntersectionsAlongThisRaw( LegacyWorldCoordinate3D firstPoint , LegacyWorldCoordinate3D secondPoint , std::vector& column_intersections_ref, int resolution_level ); /*! @brief This function prints out all the intersections with cout. Normally its not called, but sometimes its needed for debugging. */ void ShowIntersections(); /*! @brief Based on the global variable Intersections that holds the information about the intersections betweent the voxel edges and the polygons this function determines all voxels that are touched by the structure on resolution_level. So this operation is carried out for the mask field that belongs to resolution_level. For resolution_level equal to zero its the finest resolution and so the resolution of the mask field is the resolution of the dose distribution. */ void MarkVoxelsTouchedByStructure( int resolution_level ); /*! @brief Sets FieldOfIntersections for the current slice. This is done based on Intersections which stores the information about the polygons and their intersections. @param index_z Integer that represents the index of the slice which is to be regarded. */ void GetIntersectionInformationThisSlice( unsigned int index_z ); /*! @brief The intersection with voxel coordinates coord2D is inserted into the FieldOfIntersectons in position of voxel (index_x , index_y , index_z) and for the polygon with index struct_index and for the side of the voxel denoted by voxel_side. @param index_x X-position of the voxel. @param index_y Y-position of the voxel. @param index_z Z-position of the voxel. @param struct_index Index of the polygon that is intersecting here. @param point_index Index of the last polygon point before the intersection. @param intersect_index Index of the intersection. By the way also represents the information about how many intersections with voxel edges are in between this intersection with voxel edge and the last polygon point. @param coord2D Intersection in voxel coordinates. @param voxel_side Side of the voxel which is intersected here. */ void AddToFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index , unsigned int point_index , unsigned int intersect_index , LegacyWorldCoordinate2D coord2D, unsigned int voxel_side ); /*! @brief A new element of the type VoxelIntersectionsVectorPointer is inserted into the FieldOfIntersections and a first element of type IntersectionsThisVoxel is inserted. @param index_x X-position of the voxel of interest, which needs specification of its intersections. @param index_y Y-position of the voxel of interest, which needs specification of its intersections. @param index_z Z-position of the voxel of interest, which needs specification of its intersections. @param struct_index Specifies the specific polygon and its respective PolygonInTermsOfIntersections which intersects here. */ void ExtendFieldOfIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ); /*! @brief In case FieldOfIntersections does already have an element of type VoxelIntersectionsVectorPointer in the position that corresponds to the voxel in index_x , index_y , index_z, the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index is returned. @param index_x X-position of the voxel of interest. @param index_y Y-position of the voxel of interest. @param index_z Z-position of the voxel of interest. @param struct_index Index of the polygon of interest. @return Returns the index of the IntersectionsThisVoxel element that corresponds to the polygon with index struct_index. */ int GetRespectiveIntersections( unsigned int index_x , unsigned int index_y , unsigned int index_z , unsigned int struct_index ) const; /*! @brief This function calculates and returns the fraction of the voxel with index aDoseIndex that is enclosed by the strucure. This fraction is between zero and one. @param aDoseIndex Index of the voxel of interest. @return Returns a number between zero and one that specifies the fraction of the voxel that is enclosed by the structure. */ float GetFractionInside( const LegacyDoseVoxelIndex3D& aDoseIndex ) ; /*! @brief Gets a number of voxels that are known to have oldcolor via indexList. Takes a voxel from this list. Lets call it THEVOXEL. Checks the neighbours of THEVOXEL. Each neighbour that does have oldcolor is appended to the list for further investigation. Afterwards THEVOXEL is set to newcolor and taken from the list. Now the next voxel of the list is regarded ... ... so it is now THEVOXEL ... and so on ... until the list is empty. @param indexList List of indicees that are known to have oldcolor. @param oldcolor The old color. @param newcolor The new color. @param resolution_level The resolution level which is currently regarded. */ void FloodFill4( UnsignedIndexList indexList ,int oldcolor,int newcolor,int resolution_level); /*! @brief Old stuff. */ void setInsideVoxelPreviousVersion(int resolution_level); /*! @brief Goes through MaskField over all resolution levels and sets all the mask voxels to the brightness that characterizes those voxel that are not known to be outside, inside or border. Those voxels that do already have the brightness that characterizes them as border are not changed here. */ void SetContentUnknown(); /*! @brief This function calls FloodFill4 for those voxels that are known to be inside or outside although yet not denoted so in the mask field. FloodFill4 will first investigate the neighbourhood of these voxels and then set them to the correct value. @param resolution_level The resolution that is currently regarded. @param indexListInside Voxels known to be inside, but yet not denoted so in the mask field. @param indexListOutside Voxels known to be outside, but yet not denoted so in the mask field. */ void setInsideVoxel( int resolution_level, std::vector< UnsignedIndexList > indexListInside, std::vector< UnsignedIndexList > indexListOutside ); /*! @brief This function is just for debugging. It prints out the number of voxels with specific brightness. @param resolution_level The resolution_level of interest. */ void CountThisColor( int resolution_level ); /*! @brief First this function determines the voxels that are yet not denoted inside or outside in the mask field, but are directly in touch with voxels which are already known to be inside/outside and thus their affiliation is clear. This is done for the resolution resolution_level. GetBorderRegion of Field.h is called to do this job, if the resolution is not croasest. In case the resolution is croasest, this step is omitted. In case of the croasest resolution this step is not necessary and thus omitted since on the croasest resolution no voxel is yet known to be inside or outside. Afterwards setInsideVoxel is called by this function. @param resolution_level The resolution level which is supposed to be regarded here. */ void setInsideVoxelMultiRes( int resolution_level ); /*! @brief Transforms world coordinate in voxel coordinate. @param z The world coordinate to be tranformed. @return Returns the resulting voxel coordinate. */ LegacyWorldCoordinate1D GetZIndex( LegacyWorldCoordinate1D z ); /*! @brief Provides _doseData with the absolute dose data of the voxels which are inside the structure. */ void calcDoseData(); // private stuff that is just for test: /*! @brief Needed for unit tests. The parameter aDoseIndex is set to a voxel that is touched by the structure and which is located in the same slice that is given by the z-position of aDoseIndex, if possible. @param aDoseIndex is a reference to a LegacyDoseVoxelIndex3D which is modified by this function in x and y, but not in z. If things go well, aDoseIndex is set to a voxelposition within the slice in position z that is touched by the structure. In that case the function returns true. @return Returns false in case no voxel is touched by the structure within this slice. Otherways returns true. */ bool GetSomeBorderVoxelXYForTest( LegacyDoseVoxelIndex3D& aDoseIndex ); // end private stuff just for test private: void clearMaskField(); }; } } } #endif \ No newline at end of file diff --git a/code/masks/rttbMaskType_LEGACY.h b/code/masks/legacy/rttbMaskType_LEGACY.h similarity index 94% rename from code/masks/rttbMaskType_LEGACY.h rename to code/masks/legacy/rttbMaskType_LEGACY.h index 20291af..9b19ba1 100644 --- a/code/masks/rttbMaskType_LEGACY.h +++ b/code/masks/legacy/rttbMaskType_LEGACY.h @@ -1,117 +1,117 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @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 __MASK_TYPE_H #define __MASK_TYPE_H #include "rttbBaseType_LEGACY.h" #include namespace rttb{ namespace masks{ namespace legacy { /*! @brief PointLevelVector This structure represents one point of the structure and the intersections of the following contour segment with the voxel edges. Contour segment, that is a line connecting this contour point and the next one. contour_point_voxel_coord represents the contour point in voxel coordinates. intersections_raw_and_column represents all the intersections with the voxel eges sorted in a way, so that the one that is closest to the contour point represented by this PointLevelVector is the first one. The one that is furthest from the contour point represented by this PointLevelVector is the last one that appears in intersections_raw_and_column. raw_intersections is just like intersections_raw_and_column, but represents the intersections with the voxel edges that are parallel to the voxel raws. column_intersections is like raw_intersections but represents the intersections with the voxel edges that are parallel to the voxel columns. */ struct PointLevelVector{ PointLevelVector(){ to_be_Regarded = 1; } ~PointLevelVector(){ raw_intersections.clear(); column_intersections.clear(); intersections_raw_and_column.clear(); } std::vector raw_intersections; std::vector column_intersections; std::vector intersections_raw_and_column; LegacyWorldCoordinate3D contour_point_voxel_coord; bool to_be_Regarded; }; /*! @typedef correspoinding_structure_vector */ typedef std::vector correspoinding_structure_vector; /*! @typedef PolygonLevelVector */ typedef std::vector PolygonLevelVector; /*! @typedef SliceLevelVector */ typedef std::vector SliceLevelVector; /*! @typedef field_content_type */ typedef int field_content_type; /*! @typedef VoxelIntersectionPointsMap */ typedef std::map< LegacyDoseVoxelIndex3D,std::vector > VoxelIntersectionPointsMap; /*! @brief Characterizes the relationship between the voxel edge (in this position that this CharacterizeIntersection object belongs to) and the contour that is in touch with the edge right here. real_intersection for example means that here the structure really intersects the voxel edge. inside_to_edge means that the structure, coming from inside the voxel touches the voxel edge here and then runs along the voxel edge, touching rather than intersecting. edge_to_edge means that the structure goes along the edge and has a contour point here. So it comes and goes along the edge and has a point here. outside_to_edge means that here the contour comes from outside the voxel and continues to run along the edge. So here in this position represented by this CharacterizeIntersection the contour does not actually run into the voxel. inside_inside_touches means that the contour comes from inside the voxel, does have a point here in this position right on the edge and continues its way going back into the voxel. So the contour just touches the voxel edge and does not really intersect here. corner : this is just a corner. unknown nobody knows what that is. */ enum CharacterizeIntersection{ unknown = -1 , real_intersection = 0 , edge_to_edge = 1 , inside_to_edge = 2 , edge_to_inside = 3 , outside_to_edge = 4 , edge_to_outside = 5 , inside_inside_touches = 6, outside_outside_touches = 7, corner = 8 }; typedef LegacyPolygonType::iterator LegacyPolygonTypeIterator; typedef std::vector PolygonInTermsOfIntersections; typedef std::vector StructureInTermsOfIntersections; typedef std::list UnsignedIndexList; } } } #endif \ No newline at end of file diff --git a/code/io/mask/rttbBoostMaskAccessor.cpp b/code/masks/legacy/rttbOTBMaskAccessor.cpp similarity index 50% rename from code/io/mask/rttbBoostMaskAccessor.cpp rename to code/masks/legacy/rttbOTBMaskAccessor.cpp index e555263..021c27b 100644 --- a/code/io/mask/rttbBoostMaskAccessor.cpp +++ b/code/masks/legacy/rttbOTBMaskAccessor.cpp @@ -1,162 +1,186 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 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) +// @version $Revision: 747 $ (last changed revision) +// @date $Date: 2014-09-17 12:01:00 +0200 (Mi, 17 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) */ -#include "rttbBoostMaskAccessor.h" -#include "rttbBoostMask.h" +#include "rttbOTBMaskAccessor.h" +#include "rttbMappingOutsideOfImageException.h" #include #include #include #include namespace rttb { - namespace io + + namespace masks { - namespace mask + namespace legacy { - BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr) - : _spStructure(aStructurePointer), _spGeoInfo(aGeometricInfoPtr) + OTBMaskAccessor::OTBMaskAccessor(StructTypePointer aStructurePointer, + const core::GeometricInfo& aGeometricInfo) + : _spStructure(aStructurePointer), _legacyStructure(*aStructurePointer) { _spRelevantVoxelVector = MaskVoxelListPointer(); + _geoInfo = aGeometricInfo; //generate new structure set uid boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; - _maskUID = "BoostMask_" + ss.str(); + _maskUID = "OTBMask_" + ss.str(); } - BoostMaskAccessor::~BoostMaskAccessor() + OTBMaskAccessor::~OTBMaskAccessor() { }; - void BoostMaskAccessor::updateMask() + void OTBMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; // already calculated } - BoostMask mask(_spGeoInfo , _spStructure); + legacy::Mask legacyMask(&_geoInfo , &_legacyStructure); + + //translate result to expected values + const std::vector voxelsInStruct = legacyMask.getDoseVoxelInStructure(); + + for (std::vector::const_iterator it = voxelsInStruct.begin(); + it != voxelsInStruct.end(); ++it) + { + rttb::VoxelGridID aVoxelGridID; + rttb::VoxelGridIndex3D newIndex; + + legacy::LegacyDoseVoxelIndex3D oldIndex = it->getVoxelIndex3D(); + newIndex(0) = oldIndex.x; + newIndex(1) = oldIndex.y; + newIndex(2) = oldIndex.z; + + // new architecture + if (!_geoInfo.convert(newIndex, aVoxelGridID)) + { + throw core::MappingOutsideOfImageException("mapping outside of image occurred!"); + } + + core::MaskVoxel newMaskVoxel(aVoxelGridID); + newMaskVoxel.setRelevantVolumeFraction(it->getProportionInStr()); - _spRelevantVoxelVector = mask.getRelevantVoxelVector(); + newRelevantVoxelVector.push_back(newMaskVoxel); + } + _spRelevantVoxelVector = boost::make_shared(newRelevantVoxelVector); return; } - BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() + OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector() { // if not already generated start voxelization here updateMask(); return _spRelevantVoxelVector; } - BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector(float lowerThreshold) + OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector(float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); // filter relevant voxels - BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); + OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } - bool BoostMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const + bool OTBMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid - if (!_spGeoInfo->validID(aID)) + if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { - BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); + OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } + //aID is not in mask + voxel.setRelevantVolumeFraction(0); } // returns false if mask was not calculated without triggering calculation (otherwise not const!) else { return false; } return false; } - bool BoostMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const + bool OTBMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; - if (_spGeoInfo->convert(aIndex, aVoxelGridID)) + if (_geoInfo.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/rttbITKImageMaskAccessor.h b/code/masks/legacy/rttbOTBMaskAccessor.h similarity index 62% rename from code/io/mask/rttbITKImageMaskAccessor.h rename to code/masks/legacy/rttbOTBMaskAccessor.h index cccd822..df1df86 100644 --- a/code/io/mask/rttbITKImageMaskAccessor.h +++ b/code/masks/legacy/rttbOTBMaskAccessor.h @@ -1,114 +1,124 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision: 793 $ (last changed revision) -// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) +// @version $Revision: 747 $ (last changed revision) +// @date $Date: 2014-09-17 12:01:00 +0200 (Mi, 17 Sep 2014) $ (last change date) // @author $Author: hentsch $ (last changed by) */ -#ifndef __ITK_IMAGE_MASK_ACCESSOR_H -#define __ITK_IMAGE_MASK_ACCESSOR_H +#ifndef __MASK_ACCESSOR_OTB_NEW_H +#define __MASK_ACCESSOR_OTB_NEW_H -#include "rttbMaskAccessorInterface.h" -#include "rttbGeometricInfo.h" #include "rttbBaseType.h" +#include "rttbGeometricInfo.h" +#include "rttbMaskVoxel.h" +#include "rttbMaskType_LEGACY.h" +#include "rttbBaseType_LEGACY.h" +#include "rttbStructure_LEGACY.h" +#include "rttbMask.h" +#include "rttbContour_LEGACY.h" +#include "rttbPolygonInfo_LEGACY.h" +#include "DoseIteratorInterface_LEGACY.h" +#include "DoseIterator_LEGACY.h" +#include "rttbMaskAccessorInterface.h" +#include "rttbGenericDoseIterator.h" +#include "rttbStructure.h" + +#include -#include "itkImage.h" namespace rttb { - namespace io + + namespace masks { - namespace mask + namespace legacy { - - /*! @class ITKImageMaskAccessor - @brief This class gives access to mask information stored in an itk image + /*! @class OTBMaskAccessor + * @brief Implementation of original toolbox voxelization by M. Hub. */ - class ITKImageMaskAccessor: public core::MaskAccessorInterface + class OTBMaskAccessor: public core::MaskAccessorInterface { public: - typedef ::itk::Image ITKMaskImageType; - typedef ::itk::ImageBase<3> ITKImageBaseType; typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; - typedef boost::shared_ptr GeometricInfoPointer; + typedef core::Structure::StructTypePointer StructTypePointer; private: - /** @brief The mask as itkImage */ - ITKMaskImageType::ConstPointer _mask; + core::GeometricInfo _geoInfo; - IDType _maskUID; + /*! vector containing list of mask voxels*/ + MaskVoxelListPointer _spRelevantVoxelVector; - GeometricInfoPointer _geoInfo; + StructTypePointer _spStructure; - /*! vector containing list of mask voxels*/ - MaskVoxelListPointer _relevantVoxelVector; + legacy::StructureLegacy _legacyStructure; - /*! @brief get all required data from the itk image contained in _Mask - @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. - */ - bool assembleGeometricInfo(); + IDType _maskUID; public: - ~ITKImageMaskAccessor(); + ~OTBMaskAccessor(); - ITKImageMaskAccessor(ITKMaskImageType::ConstPointer aMaskImage); + // import of structure sets (loading from data) is done elsewhere. Structures are only voxelized here. + // here the original RTToolbox voxelization shall be implemented + OTBMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo); /*! @brief voxelization of the given structures according to the original RTToolbox algorithm*/ void updateMask(); /*! @brief get vector conatining al relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(); /*! @brief get vector conatining al 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; bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; - /*! @brief give access to GeometricInfo*/ - const core::GeometricInfo& getGeometricInfo() const; - - /* @ brief is true if Mask is on a homogeneous grid */ + /* @ brief is true if dose is on a homogeneous grid */ // Inhomogeneous grids are not supported at the moment, but if they will // be supported in the future the interface does not need to change. bool isGridHomogeneous() const { return true; }; + /*! @brief give access to GeometricInfo*/ + inline const core::GeometricInfo& getGeometricInfo() const + { + return _geoInfo; + }; + IDType getMaskUID() const { return _maskUID; }; }; - } } } #endif diff --git a/code/masks/rttbPolygonInfo_LEGACY.cpp b/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp similarity index 97% rename from code/masks/rttbPolygonInfo_LEGACY.cpp rename to code/masks/legacy/rttbPolygonInfo_LEGACY.cpp index 2bcd98a..9628c3c 100644 --- a/code/masks/rttbPolygonInfo_LEGACY.cpp +++ b/code/masks/legacy/rttbPolygonInfo_LEGACY.cpp @@ -1,3966 +1,3966 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include #include #include #include #include #include "rttbMask.h" #include "rttbPolygonInfo_LEGACY.h" #include "rttbNullPointerException.h" namespace rttb{ namespace masks{ namespace legacy{ PolygonInfo::PolygonInfo( const LegacyPolygonType& the_polygon_in, int polygon_number_in, field_content_type brightness_outside_in , field_content_type brightness_inside_in , FieldOfScalar* MaskFieldReceived_in , const PolygonInTermsOfIntersections& Polygon_Intersections_In , const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn , const IntersectionsThisVoxel& intersections_this_voxel_in ): the_polygon( the_polygon_in ) , voxel_intersections( intersections_this_voxel_in) { if( MaskFieldReceived_in == NULL ){ assert( 0 ); } else{ MaskFieldReceived = MaskFieldReceived_in; } brightness_outside = brightness_outside_in; brightness_inside = brightness_inside_in; SetDoseIndex( aDoseIndex ); pol_inf_vec.clear(); PolygonInfoVectorOfEdges& pol_inf_vec_ref = pol_inf_vec; GInformation = GInfIn; SetCurrentPosition( aDoseIndex ); it_poly.SetIntersectionsAndResetIntersectionIndex( Polygon_Intersections_In ); voxel_intersections.SetPolygonNumber( polygon_number_in ); } void PolygonInfo::CalcSnippetVectors(){ VoxelIntersectionIndex next_voxel_intersection; pol_inf_vec.resize(0); for( int voxel_edge = 0 ; voxel_edge < 4 ; voxel_edge++ ){ next_voxel_intersection.reset(); current_edge = voxel_edge; snippet_vector snip_vec; snippet_vector& snip_vec_ref = snip_vec; SetCurrentPositionToEdge( voxel_edge ); std::vector snip_vec_local; snippet_vector& snip_vec_ref_local = snip_vec_local; bool finished = false; while( finished == false ){ finished = AppendNextIntersectionAndCorrespoindingPolygonSnippets( snip_vec_ref_local, snip_vec_ref , voxel_edge, next_voxel_intersection ); } pol_inf_vec.push_back( snip_vec ); } AppendEdges( pol_inf_vec ); it_poly.ResetIntersectionIndex(); } void PolygonInfo::ShowSnippet( PolygonSnippet a_snippet ){ std::cout<< " a_snippet.i_have_been_processed : " << a_snippet.i_have_been_processed <GetData( 0, 0, 0 ) < 0 ) { gone_well = false; std::cout<< " Mask field values must not be below zero ! " <( pol_snip_a.point_of_interest_start.x ) != static_cast( pol_snip_b.point_of_interest_start.x ) ) { return false; } if( static_cast( pol_snip_a.point_of_interest_start.y ) != static_cast( pol_snip_b.point_of_interest_start.y ) ) { return false; } if( static_cast( pol_snip_a.point_of_interest_end.y ) != static_cast( pol_snip_b.point_of_interest_end.y ) ) { return false; } if( static_cast( pol_snip_a.why_here.x ) != static_cast( pol_snip_b.why_here.x ) ) { return false; } if( static_cast( pol_snip_a.why_here.y ) != static_cast( pol_snip_b.why_here.y ) ) { return false; } if( pol_snip_a.snippet_intermediate_content.size() != pol_snip_b.snippet_intermediate_content.size() ) { return false; } for( GridIndexType counter = 0 ; counter < pol_snip_a.snippet_intermediate_content.size() ; counter++ ){ if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).x ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).x ) ) { return false; } if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).y ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).y ) ) { return false; } if( static_cast( pol_snip_a.snippet_intermediate_content.at(counter).z ) != static_cast( pol_snip_b.snippet_intermediate_content.at(counter).z ) ) { return false; } } return true; } bool PolygonInfo::CompareCalculatedAndExpectedResultingSequenceForTest( LegacyPolygonSequenceType& expected_resulting_sequence_ref ){ if( expected_resulting_sequence_ref.size() > resulting_sequence.size() ) { std::cout<< " Size ! " <(the_dose_index.x); current_position.y = static_cast(the_dose_index.y); break; case 1 : current_position.x =static_cast(the_dose_index.x + 1); current_position.y = static_cast(the_dose_index.y); break; case 2 : current_position.x =static_cast(the_dose_index.x + 1); current_position.y = static_cast(the_dose_index.y + 1); break; case 3 : current_position.x =static_cast(the_dose_index.x); current_position.y = static_cast(the_dose_index.y + 1); break; default : assert( 0 ); } } void PolygonInfo::AppendEdges( PolygonInfoVectorOfEdges& pol_inf_vec_ref ){ for( unsigned int voxel_edge = 0 ; voxel_edge < pol_inf_vec_ref.size() ; voxel_edge++ ){ assert( voxel_edge <= 3 ); PolygonSnippet pol_snip_front; pol_snip_front.is_edge = 1; pol_snip_front.characterize = corner; switch( voxel_edge ){ case 0 : pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x); pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x); pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); pol_snip_front.why_here.x =static_cast(the_dose_index.x); pol_snip_front.why_here.y = static_cast(the_dose_index.y); break; case 1 : pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x + 1); pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y); pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x + 1); pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y); pol_snip_front.why_here.x =static_cast(the_dose_index.x + 1); pol_snip_front.why_here.y = static_cast(the_dose_index.y); break; case 2 : pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x + 1); pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x + 1); pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); pol_snip_front.why_here.x =static_cast(the_dose_index.x + 1); pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); break; case 3 : pol_snip_front.point_of_interest_start.x =static_cast(the_dose_index.x); pol_snip_front.point_of_interest_start.y = static_cast(the_dose_index.y + 1); pol_snip_front.point_of_interest_end.x =static_cast(the_dose_index.x); pol_snip_front.point_of_interest_end.y = static_cast(the_dose_index.y + 1); pol_snip_front.why_here.x =static_cast(the_dose_index.x); pol_snip_front.why_here.y = static_cast(the_dose_index.y + 1); break; default : assert( 0 ); } snippet_vector_iterator iter; iter = pol_inf_vec_ref.at( voxel_edge ).begin(); pol_inf_vec_ref.at( voxel_edge ).insert( iter , pol_snip_front ); } CheckEdgeIntersections(); } void PolygonInfo::CheckEdgeIntersections(){ SnippetIndex edge_index; edge_index.edge = 0; edge_index.snip = 0; current_edge = 0; CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); edge_index.edge = 1; edge_index.snip = 0; current_edge = 1; CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); edge_index.edge = 2; edge_index.snip = 0; current_edge = 2; CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); edge_index.edge = 3; edge_index.snip = 0; current_edge = 3; CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( edge_index ); } bool PolygonInfo::GetCornerFromVoxelIntersections( unsigned int the_index, SnippetIndex edge_index , IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index ){ if( voxel_intersections.corner_intersections_intersection_coord.at( edge_index.edge ).size() > the_index ) { intersect_index = voxel_intersections.corner_intersections_intersection_coord.at(edge_index.edge).at( the_index ); return true; } else{ return false; } } int PolygonInfo::GetNumberOfSnppetsThisEdge( SnippetIndex edge_index ){ return voxel_intersections.corner_intersections_intersection_coord.at( edge_index.edge ).size(); } bool PolygonInfo::SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, VoxelIntersectionIndex next_voxel_intersection ){ if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).size() > next_voxel_intersection.next_intersection ) { if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).at( next_voxel_intersection.next_intersection ).size() > next_voxel_intersection.intersection_douplication ) { IterativePolygonInTermsOfIntersections::WhichIntersection an_intersection_index = voxel_intersections.edge_intersections_intersection_coord.at(current_edge).at(next_voxel_intersection.next_intersection).at( next_voxel_intersection.intersection_douplication ); it_poly.SetCurrentIntersectionIndex( an_intersection_index ); it_poly.ThisIntersection( closest_local_current_position_ref ); if( !it_poly.CheckCurrentIntersectionIndexIdentical( an_intersection_index ) ) { assert(0); } return true; } else{ return false; } } else{ return false; } } void PolygonInfo::CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( SnippetIndex edge_index ){ LegacyWorldCoordinate2D edge_coord = pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ).why_here; IterativePolygonInTermsOfIntersections::WhichIntersection the_intersection_index_from_voxel_intersections; the_intersection_index_from_voxel_intersections.point_index = 0; the_intersection_index_from_voxel_intersections.intersection_index = 0; IterativePolygonInTermsOfIntersections::WhichIntersection& the_intersection_index_from_voxel_intersections_ref = the_intersection_index_from_voxel_intersections; int number_of_snippets_this_edge = GetNumberOfSnppetsThisEdge( edge_index ); std::vector snip_vec_local; if( number_of_snippets_this_edge > 0 ) { snip_vec_local = CreateSnippetVector( number_of_snippets_this_edge , pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ) ); } int erased = 0; for( int which_one = 0 ; which_one < number_of_snippets_this_edge ; which_one++ ){ bool there_is_an_intersection = GetCornerFromVoxelIntersections( which_one, edge_index , the_intersection_index_from_voxel_intersections_ref ); if( there_is_an_intersection ) { it_poly.SetCurrentIntersectionIndex( the_intersection_index_from_voxel_intersections_ref ); LegacyWorldCoordinate3D contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinates( the_intersection_index_from_voxel_intersections_ref ); int back = 1; while( ( contour_point_one.x == edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ){ contour_point_one = it_poly.GetRestpectivePologonPointInVoxelCoordinatesPrevious( the_intersection_index_from_voxel_intersections_ref , back ); back++; } int ahead = 1; LegacyWorldCoordinate3D contour_point_two = it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( the_intersection_index_from_voxel_intersections_ref , ahead ); while( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ){ ahead++; contour_point_two = it_poly.GetRestpectivePologonPointInVoxelCoordinatesFurther( the_intersection_index_from_voxel_intersections_ref , ahead ); } bool there_is_a_suitable_polygon_forward = false; bool there_is_a_suitable_polygon_backward = false; PolygonSnippet forward_snippet; PolygonSnippet& forward_snippet_ref = forward_snippet; PolygonSnippet backward_snippet; PolygonSnippet& backward_snippet_ref = backward_snippet; PolygonSnippet& edge_snippet_ref = snip_vec_local.at( ( which_one - erased ) ); float angle_charact_a = 0; float angle_charact_b = 0; if( GoForwardAndCreatePolygonSnippet( forward_snippet_ref ) ) { there_is_a_suitable_polygon_forward = true; } if( GoBackwardAndCreatePolygonSnippet( backward_snippet_ref ) ) { there_is_a_suitable_polygon_backward = true; } if( there_is_a_suitable_polygon_forward ) { angle_charact_a = forward_snippet_ref.angle_charact; } if( there_is_a_suitable_polygon_backward ) { angle_charact_b = backward_snippet_ref.angle_charact; } if( ( ! there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ) { edge_snippet_ref.characterize = corner; } if( ( there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ) { WorkWithForwardAndBackwardEdgeSnippet( which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); } if( ( there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ) { WorkWithForwardEdgeSnippet( edge_coord, contour_point_one, which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); } if( ( ! there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ) { WorkWithBackwardEdgeSnippet( edge_coord, contour_point_two , which_one, angle_charact_a , angle_charact_b , forward_snippet_ref , backward_snippet_ref , edge_snippet_ref , snip_vec_local , erased ); } } } if( snip_vec_local.size() > 1 ) { snip_vec_local = SortClockwise( snip_vec_local ); } InsertToSnippetVectorFront( snip_vec_local, edge_index ); } void PolygonInfo::WorkWithForwardAndBackwardEdgeSnippet( int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ if( angle_charact_a < angle_charact_b ) { Switch( forward_snippet_ref , backward_snippet_ref ); float keep_angle_charact_a = angle_charact_a; float keep_angle_charact_b = angle_charact_b; angle_charact_a = keep_angle_charact_b; angle_charact_b = keep_angle_charact_a; } if( ( angle_charact_a > 0 ) && ( angle_charact_a < 1.0 ) ) { if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) { forward_snippet_ref.characterize = inside_inside_touches; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); backward_snippet_ref.characterize = inside_inside_touches; backward_snippet_ref.why_here.x =backward_snippet_ref.point_of_interest_start.x; backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; backward_snippet_ref.is_edge = true; snippet_vector_iterator iter; iter = snip_vec_local.begin() + ( which_one - erased ) ; snip_vec_local.insert( iter , backward_snippet_ref ); } else if( angle_charact_b == 0 ) { forward_snippet_ref.characterize = edge_to_inside; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } else if( angle_charact_b == 1.0 ) { assert(0); } else if( angle_charact_b < 0 ) { forward_snippet_ref.characterize = real_intersection; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } } else if( angle_charact_a < 0 ) { assert( angle_charact_b < 0 ); int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_a == 1.0 ) { if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) { backward_snippet_ref.is_edge = true; backward_snippet_ref.characterize = inside_to_edge; backward_snippet_ref.why_here.x =backward_snippet_ref.point_of_interest_start.x; backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , backward_snippet_ref ); } else if( angle_charact_b == 1.0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_b == 0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_b < 0 ) { forward_snippet_ref.characterize = outside_to_edge; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } } } void PolygonInfo::WorkWithForwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ float angle_charact = 0; float& angle_charact_ref = angle_charact; LegacyWorldCoordinate2D contour_point_one_2d; contour_point_one_2d.x =contour_point_one.x; contour_point_one_2d.y = contour_point_one.y; GetAngle( contour_point_one_2d , edge_coord , angle_charact_ref ); if( ( angle_charact_a > 0 ) && ( angle_charact_a < 1.0 ) ) { if( ( angle_charact_ref != 0 ) && ( angle_charact_ref != 1.0 ) ) { forward_snippet_ref.characterize = real_intersection; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } else if( angle_charact_ref == 0 ) { forward_snippet_ref.characterize = edge_to_inside; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } else if( angle_charact_ref == 1.0 ) { forward_snippet_ref.characterize = inside_to_edge ; forward_snippet_ref.is_edge = true; forward_snippet_ref.why_here.x =forward_snippet_ref.point_of_interest_start.x; forward_snippet_ref.why_here.y = forward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , forward_snippet_ref ); } } else if( angle_charact_a == 0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_a == 1.0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_a < 0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } } void PolygonInfo::WorkWithBackwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ){ float angle_charact = 0; float& angle_charact_ref = angle_charact; LegacyWorldCoordinate2D contour_point_two_2d; contour_point_two_2d.x = contour_point_two.x; contour_point_two_2d.y = contour_point_two.y; GetAngle( contour_point_two_2d , edge_coord , angle_charact_ref ); if( ( angle_charact_b > 0 ) && ( angle_charact_b < 1.0 ) ) { if( ( angle_charact_ref != 0 ) && ( angle_charact_ref != 1.0 ) ) { backward_snippet_ref.characterize = real_intersection; backward_snippet_ref.is_edge = true; backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , backward_snippet_ref ); } if( ( angle_charact_ref == 1.0 ) ) { backward_snippet_ref.characterize = inside_to_edge; backward_snippet_ref.is_edge = true; backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , backward_snippet_ref ); } if( ( angle_charact_ref == 0 ) ) { backward_snippet_ref.characterize = edge_to_inside; backward_snippet_ref.is_edge = true; backward_snippet_ref.why_here.x = backward_snippet_ref.point_of_interest_start.x; backward_snippet_ref.why_here.y = backward_snippet_ref.point_of_interest_start.y; CopySnippet( edge_snippet_ref , backward_snippet_ref ); } } else if( angle_charact_b == 0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_b == 1.0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } else if( angle_charact_b < 0 ) { int position = ( which_one - erased ); RemoveFromLocalSnippetVector( snip_vec_local , position ); erased++; } } PolygonInfo::snippet_vector PolygonInfo::CreateSnippetVector( int number_of_snippets_this_edge , PolygonSnippet template_snip ){ snippet_vector vector_local; PolygonSnippet pol_snip; for( int i = 0 ; i < number_of_snippets_this_edge ; i++ ){ CopySnippet( pol_snip, template_snip ); vector_local.push_back( pol_snip ); } return vector_local; } PolygonInfo::snippet_vector PolygonInfo::SortClockwise( snippet_vector snip_vec_local ){ snippet_vector snip_vec_local_internal; std::vector do_check; do_check.clear(); for( GridIndexType i = 0 ; i < snip_vec_local.size() ; i++ ){ LegacyWorldCoordinate2D position_one = snip_vec_local.at( i ).point_of_interest_end; double distance_one = GetDistanceAlongEdge( the_dose_index , position_one ); LegacyWorldCoordinate2D position_for_reference = snip_vec_local.at( i ).why_here; double distance_for_reference = GetDistanceAlongEdge( the_dose_index , position_for_reference ); double rang_one = GetClockwiseDist( distance_for_reference , distance_one ); bool got_it = false; for( GridIndexType j = 0 ; j < snip_vec_local_internal.size() ; j++ ){ if( do_check.at(j) == true ) { LegacyWorldCoordinate2D position_two = snip_vec_local_internal.at( j ).point_of_interest_end; double distance_two = GetDistanceAlongEdge( the_dose_index , position_two ); double rang_two = GetClockwiseDist( distance_for_reference , distance_two ); if( rang_one < rang_two ) { snippet_vector_iterator iter; iter = snip_vec_local_internal.begin(); iter += j; snip_vec_local_internal.insert( iter , snip_vec_local.at( i ) ); got_it = true; bool check = true; do_check.push_back( check ); if( ( snip_vec_local.at( i ).characterize == 6 ) && ( ( i + 1 ) < snip_vec_local.size() ) ) { if( snip_vec_local.at( i + 1 ).characterize == 6 ) { snippet_vector_iterator iter; iter = snip_vec_local_internal.begin(); iter += j; snip_vec_local_internal.insert( iter , snip_vec_local.at( i + 1 ) ); i++; got_it = true; bool check = false; do_check.push_back( check ); } } j = snip_vec_local.size(); } } } if( got_it == false ) { snip_vec_local_internal.push_back( snip_vec_local.at( i ) ); bool check = true; do_check.push_back( check ); if( ( snip_vec_local.at( i ).characterize == 6 ) && ( ( i + 1 ) < snip_vec_local.size() ) ) { if( snip_vec_local.at( i + 1 ).characterize == 6 ) { snip_vec_local_internal.push_back( snip_vec_local.at( i + 1 ) ); i++; got_it = true; bool check = false; do_check.push_back( check ); } } } } return snip_vec_local_internal; } void PolygonInfo::InsertToSnippetVectorFront( snippet_vector snip_vec_local , SnippetIndex edge_index ){ snippet_vector_iterator iter; for( GridIndexType i = 0 ; i < snip_vec_local.size() ; i++ ){ PolygonSnippet pol_snip_front = snip_vec_local.at( i ); iter = pol_inf_vec.at( edge_index.edge ).begin() + ( i + 1 ); pol_inf_vec.at( edge_index.edge ).insert( iter , pol_snip_front ); } if( snip_vec_local.size() > 0 ) { iter = pol_inf_vec.at( edge_index.edge ).begin(); pol_inf_vec.at( edge_index.edge ).erase( iter ); } } void PolygonInfo::RemoveFromLocalSnippetVector( snippet_vector& snip_vec_local , GridIndexType which_one ){ snippet_vector_iterator iter; if( snip_vec_local.size() > which_one ) { iter = snip_vec_local.begin() + which_one; snip_vec_local.erase( iter ); } } void PolygonInfo::GetSectorsAndSetCharacteristicsDoubleCheck( SnippetIndex edge_index, LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two ){ PolygonSnippet& a_snippet_ref = pol_inf_vec.at( edge_index.edge ).at( edge_index.snip ); WhichSector sector_first_point = not_known; WhichSector sector_second_point = not_known; WhichSector& sector_first_point_ref = sector_first_point; WhichSector& sector_second_point_ref = sector_second_point; GetSectors( edge_coord , contour_point_one , contour_point_two , sector_first_point_ref , sector_second_point_ref ); if( edge_index.edge == 0 ) { CharacterizeIntersection charact_double_check = GetCharacteristicFirstCorner( sector_first_point_ref , sector_second_point_ref ); if( ( a_snippet_ref.characterize != charact_double_check ) && ( a_snippet_ref.characterize != corner ) ) { std::cout<< " Have double checked the characteristic of corner zero. It turned out not to be determined correctly ! " < edge_coord.x ) && ( contour_point_one.y < edge_coord.y ) ) { sector_first_point_ref = section_twelve_to_three_o_clock; return; } if( ( contour_point_one.x > edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ) { sector_first_point_ref = on_edge_three_o_clock; return; } if( ( contour_point_one.x > edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) { sector_first_point_ref = section_three_to_six_o_clock; return; } if( ( contour_point_one.x == edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) { sector_first_point_ref = on_edge_six_o_clock; return; } if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y > edge_coord.y ) ) { sector_first_point_ref = section_six_to_nine_o_clock; return; } if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y == edge_coord.y ) ) { sector_first_point_ref = on_edge_nine_o_clock; return; } if( ( contour_point_one.x < edge_coord.x ) && ( contour_point_one.y < edge_coord.y ) ) { sector_first_point_ref = section_nine_to_twelve_o_clock; return; } } void PolygonInfo::GetSectorSecondPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref ){ if( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) { sector_second_point_ref = on_edge_twelve_o_clock; return; } if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) { sector_second_point_ref = section_twelve_to_three_o_clock; return; } if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ) { sector_second_point_ref = on_edge_three_o_clock; return; } if( ( contour_point_two.x > edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) { sector_second_point_ref = section_three_to_six_o_clock; return; } if( ( contour_point_two.x == edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) { sector_second_point_ref = on_edge_six_o_clock; return; } if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y > edge_coord.y ) ) { sector_second_point_ref = section_six_to_nine_o_clock; return; } if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y == edge_coord.y ) ) { sector_second_point_ref = on_edge_nine_o_clock; return; } if( ( contour_point_two.x < edge_coord.x ) && ( contour_point_two.y < edge_coord.y ) ) { sector_second_point_ref = section_nine_to_twelve_o_clock; return; } } CharacterizeIntersection PolygonInfo::GetCharacteristicFirstCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ CharacterizeIntersection charact = unknown; CharacterizeIntersection& charact_ref = charact; std::vector in_combination_vector; std::vector& in_combination_vector_ref = in_combination_vector; GetInCombinationFirstCorner( in_combination_vector_ref ); WhichSector inside; WhichSector& inside_ref = inside; GetInsideFirstCorner( inside_ref ); WhichSector preceding_edge; WhichSector& preceding_edge_ref = preceding_edge; GetPrecedingEdgeFirstCorner( preceding_edge_ref ); WhichSector following_edge; WhichSector& following_edge_ref = following_edge; GetFollowingEdgeFirstCorner( following_edge_ref ); DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); if( charact == unknown ) { assert( 0 ); } return charact; } void PolygonInfo::DoCharacterize( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , CharacterizeIntersection& charact_ref , std::vector in_combination_vector , WhichSector& inside_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ){ if( BothOnEdge( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , following_edge_ref ) ) { charact_ref = edge_to_edge;} else if( FromEdgeIn( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , inside_ref ) ) { charact_ref = edge_to_inside; } else if( FromEdgeOut( sector_first_point_ref , sector_second_point_ref , preceding_edge_ref , in_combination_vector ) ) { charact_ref = edge_to_outside; } else if( OutToEdge( sector_first_point_ref , sector_second_point_ref , following_edge_ref , in_combination_vector ) ) { charact_ref = outside_to_edge; } else if( InToEdge( sector_first_point_ref , sector_second_point_ref , following_edge_ref , inside_ref ) ) { charact_ref = inside_to_edge; } else if( BothIn( sector_first_point_ref , sector_second_point_ref , inside_ref ) ) { charact_ref = inside_inside_touches; } else if( BothOut( sector_first_point_ref , sector_second_point_ref , in_combination_vector ) ) { charact_ref = outside_outside_touches; } else if( OneInOneOut( sector_first_point_ref , sector_second_point_ref , inside_ref , in_combination_vector ) ) charact_ref = real_intersection; else assert( 0 ); } void PolygonInfo::GetInCombinationFirstCorner( std::vector& in_combination_vector_ref ){ WhichSector sec_three_to_six = section_three_to_six_o_clock; in_combination_vector_ref.push_back( sec_three_to_six ); WhichSector sec_on_edge_six = on_edge_six_o_clock; in_combination_vector_ref.push_back( sec_on_edge_six ); WhichSector sec_on_edge_three = on_edge_three_o_clock; in_combination_vector_ref.push_back( sec_on_edge_three ); } void PolygonInfo::GetInsideFirstCorner( WhichSector& inside_ref ){ inside_ref = section_three_to_six_o_clock; } void PolygonInfo::GetPrecedingEdgeFirstCorner( WhichSector& preceding_edge_ref ){ preceding_edge_ref = on_edge_six_o_clock; } void PolygonInfo::GetFollowingEdgeFirstCorner( WhichSector& following_edge_ref ){ following_edge_ref = on_edge_three_o_clock; } bool PolygonInfo::BothOnEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ){ std::vector first_sector_vector; WhichSector sec_following_edge = following_edge_ref; first_sector_vector.push_back( sec_following_edge ); std::vector second_sector_vector; WhichSector sec_preceding = preceding_edge_ref; second_sector_vector.push_back( sec_preceding ); bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::FromEdgeIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& inside_ref ){ std::vector first_sector_vector; WhichSector sec_preceding = preceding_edge_ref; first_sector_vector.push_back( sec_preceding ); std::vector second_sector_vector; WhichSector sec_inside = inside_ref; second_sector_vector.push_back( sec_inside ); bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::FromEdgeOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , std::vector second_sector_vector ){ std::vector first_sector_vector; WhichSector sec_preceding = preceding_edge_ref; first_sector_vector.push_back( sec_preceding ); /*std::vector second_sector_vector; WhichSector sec_three_to_six = section_three_to_six_o_clock; second_sector_vector.push_back( sec_three_to_six ); WhichSector sec_on_edge_six = on_edge_six_o_clock; second_sector_vector.push_back( sec_on_edge_six ); WhichSector sec_on_edge_three = on_edge_three_o_clock; second_sector_vector.push_back( sec_on_edge_three );*/ bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::OutToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , std::vector second_sector_vector ){ std::vector first_sector_vector; WhichSector sec_following = following_edge_ref; first_sector_vector.push_back( sec_following ); /* std::vector second_sector_vector; WhichSector sec_three_to_six = section_three_to_six_o_clock; second_sector_vector.push_back( sec_three_to_six ); WhichSector sec_on_edge_six = on_edge_six_o_clock; second_sector_vector.push_back( sec_on_edge_six ); WhichSector sec_on_edge_three = on_edge_three_o_clock; second_sector_vector.push_back( sec_on_edge_three ); */ bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::InToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , WhichSector& inside_ref ){ std::vector first_sector_vector; WhichSector sec_following_edge = following_edge_ref; first_sector_vector.push_back( sec_following_edge ); std::vector second_sector_vector; WhichSector sec_inside = inside_ref; second_sector_vector.push_back( sec_inside ); bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , first_sector_vector , sector_second_point_ref , second_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_second_point_ref , first_sector_vector , sector_first_point_ref , second_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::BothIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref ){ std::vector sector_vector; WhichSector sec_inside = inside_ref; sector_vector.push_back( sec_inside ); bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( sector_first_point_ref , sector_vector , sector_second_point_ref , sector_vector ); if( it_is_a ) return true; else return false; } bool PolygonInfo::BothOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , std::vector sector_vector ){ /*std::vector sector_vector; WhichSector sec_three_to_six = section_three_to_six_o_clock; sector_vector.push_back( sec_three_to_six ); WhichSector sec_on_edge_six = on_edge_six_o_clock; sector_vector.push_back( sec_on_edge_six ); WhichSector sec_on_edge_three = on_edge_three_o_clock; sector_vector.push_back( sec_on_edge_three );*/ bool it_is_a = FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , sector_vector , sector_second_point_ref , sector_vector ); if( it_is_a ) return true; else return false; } bool PolygonInfo::OneInOneOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref , std::vector first_sector_vector ){ /*std::vector first_sector_vector; WhichSector sec_three_to_six = section_three_to_six_o_clock; first_sector_vector.push_back( sec_three_to_six ); WhichSector sec_on_edge_six = on_edge_six_o_clock; first_sector_vector.push_back( sec_on_edge_six ); WhichSector sec_on_edge_three = on_edge_three_o_clock; first_sector_vector.push_back( sec_on_edge_three );*/ std::vector second_sector_vector; WhichSector sec_inside = inside_ref; second_sector_vector.push_back( sec_inside ); bool it_is_a = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_first_point_ref , second_sector_vector , sector_second_point_ref , first_sector_vector ); bool it_is_b = FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( sector_second_point_ref , second_sector_vector , sector_first_point_ref , first_sector_vector ); if( it_is_a || it_is_b ) return true; else return false; } bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ bool first_one_of_these = false; bool second_one_of_those = false; for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ if( first_sector_vector.at( index ) == sector_first_point_ref ) first_one_of_these = true; } for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ if( second_sector_vector.at( index ) == sector_second_point_ref ) second_one_of_those = true; } if( first_one_of_these && second_one_of_those )return true; else return false; } bool PolygonInfo::FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ bool first_one_of_these = false; bool second_none_of_those = true; for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ if( first_sector_vector.at( index ) == sector_first_point_ref ) first_one_of_these = true; } for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ if( second_sector_vector.at( index ) == sector_second_point_ref ) second_none_of_those = false; } if( first_one_of_these && second_none_of_those )return true; else return false; } bool PolygonInfo::FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ){ bool first_none_of_these = true; bool second_none_of_those = true; for( unsigned int index = 0 ; index < first_sector_vector.size() ; index++ ){ if( first_sector_vector.at( index ) == sector_first_point_ref ) first_none_of_these = false; } for( unsigned int index = 0 ; index < second_sector_vector.size() ; index++ ){ if( second_sector_vector.at( index ) == sector_second_point_ref ) second_none_of_those = false; } if( first_none_of_these && second_none_of_those )return true; else return false; } CharacterizeIntersection PolygonInfo::GetCharacteristicSecondCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ CharacterizeIntersection charact = unknown; CharacterizeIntersection& charact_ref = charact; std::vector in_combination_vector; std::vector& in_combination_vector_ref = in_combination_vector; GetInCombinationSecondCorner( in_combination_vector_ref ); WhichSector inside; WhichSector& inside_ref = inside; GetInsideSecondCorner( inside_ref ); WhichSector preceding_edge; WhichSector& preceding_edge_ref = preceding_edge; GetPrecedingEdgeSecondCorner( preceding_edge_ref ); WhichSector following_edge; WhichSector& following_edge_ref = following_edge; GetFollowingEdgeSecondCorner( following_edge_ref ); DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); if( charact == unknown ) assert( 0 ); return charact; } void PolygonInfo::GetInCombinationSecondCorner( std::vector& in_combination_vector_ref ){ WhichSector sec_six_to_nine = section_six_to_nine_o_clock; in_combination_vector_ref.push_back( sec_six_to_nine ); WhichSector sec_on_edge_nine = on_edge_nine_o_clock; in_combination_vector_ref.push_back( sec_on_edge_nine ); WhichSector sec_on_edge_six = on_edge_six_o_clock; in_combination_vector_ref.push_back( sec_on_edge_six ); } void PolygonInfo::GetInsideSecondCorner( WhichSector& inside_ref ){ inside_ref = section_six_to_nine_o_clock; } void PolygonInfo::GetPrecedingEdgeSecondCorner( WhichSector& preceding_edge_ref ){ preceding_edge_ref = on_edge_nine_o_clock; } void PolygonInfo::GetFollowingEdgeSecondCorner( WhichSector& following_edge_ref ){ following_edge_ref = on_edge_six_o_clock; } CharacterizeIntersection PolygonInfo::GetCharacteristicThirdCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ CharacterizeIntersection charact = unknown; CharacterizeIntersection& charact_ref = charact; std::vector in_combination_vector; std::vector& in_combination_vector_ref = in_combination_vector; GetInCombinationThirdCorner( in_combination_vector_ref ); WhichSector inside; WhichSector& inside_ref = inside; GetInsideThirdCorner( inside_ref ); WhichSector preceding_edge; WhichSector& preceding_edge_ref = preceding_edge; GetPrecedingEdgeThirdCorner( preceding_edge_ref ); WhichSector following_edge; WhichSector& following_edge_ref = following_edge; GetFollowingEdgeThirdCorner( following_edge_ref ); DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); if( charact == unknown ) assert( 0 ); return charact; } void PolygonInfo::GetInCombinationThirdCorner( std::vector& in_combination_vector_ref ){ WhichSector sec_nine_to_twelve = section_nine_to_twelve_o_clock; in_combination_vector_ref.push_back( sec_nine_to_twelve ); WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; in_combination_vector_ref.push_back( sec_on_edge_twelve ); WhichSector sec_on_edge_nine = on_edge_nine_o_clock; in_combination_vector_ref.push_back( sec_on_edge_nine ); } void PolygonInfo::GetInsideThirdCorner( WhichSector& inside_ref ){ inside_ref = section_nine_to_twelve_o_clock; } void PolygonInfo::GetPrecedingEdgeThirdCorner( WhichSector& preceding_edge_ref ){ preceding_edge_ref = on_edge_twelve_o_clock; } void PolygonInfo::GetFollowingEdgeThirdCorner( WhichSector& following_edge_ref ){ following_edge_ref = on_edge_nine_o_clock; } CharacterizeIntersection PolygonInfo::GetCharacteristicFourthCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ){ CharacterizeIntersection charact = unknown; CharacterizeIntersection& charact_ref = charact; std::vector in_combination_vector; std::vector& in_combination_vector_ref = in_combination_vector; GetInCombinationFourthCorner( in_combination_vector_ref ); WhichSector inside; WhichSector& inside_ref = inside; GetInsideFourthCorner( inside_ref ); WhichSector preceding_edge; WhichSector& preceding_edge_ref = preceding_edge; GetPrecedingEdgeFourthCorner( preceding_edge_ref ); WhichSector following_edge; WhichSector& following_edge_ref = following_edge; GetFollowingEdgeFourthCorner( following_edge_ref ); DoCharacterize( sector_first_point_ref , sector_second_point_ref , charact_ref , in_combination_vector , inside_ref , preceding_edge_ref , following_edge_ref ); if( charact == unknown ) assert( 0 ); return charact; } void PolygonInfo::GetInCombinationFourthCorner( std::vector& in_combination_vector_ref ){ WhichSector sec_twelve_to_three = section_twelve_to_three_o_clock; in_combination_vector_ref.push_back( sec_twelve_to_three ); WhichSector sec_on_edge_three = on_edge_three_o_clock; in_combination_vector_ref.push_back( sec_on_edge_three ); WhichSector sec_on_edge_twelve = on_edge_twelve_o_clock; in_combination_vector_ref.push_back( sec_on_edge_twelve ); } void PolygonInfo::GetInsideFourthCorner( WhichSector& inside_ref ){ inside_ref = section_twelve_to_three_o_clock; } void PolygonInfo::GetPrecedingEdgeFourthCorner( WhichSector& preceding_edge_ref ){ preceding_edge_ref = on_edge_three_o_clock; } void PolygonInfo::GetFollowingEdgeFourthCorner( WhichSector& following_edge_ref ){ following_edge_ref = on_edge_twelve_o_clock; } bool PolygonInfo::AppendNextIntersectionAndCorrespoindingPolygonSnippets( snippet_vector& snip_vec_ref_local , snippet_vector& snip_vec_ref , int current_edge, VoxelIntersectionIndex& next_voxel_intersection ){ bool finished = false; bool im_done = false; LegacyWorldCoordinate2D closest_local_current_position; LegacyWorldCoordinate2D& closest_local_current_position_ref = closest_local_current_position; closest_local_current_position.x = current_position.x; closest_local_current_position.y = current_position.y; while( im_done == false ){ closest_local_current_position.x = current_position.x; closest_local_current_position.y = current_position.y; // double distance_current_position = GetDistanceAlongEdge( the_dose_index , current_position ); // die folgende Funktion macht den naechstliegenden Schnittpunkt ausfindig gespeichert in closest_local_current_position_ref // the_intersection_index speichert die Information ueber seine Lage im Polygonzug // hier wird untersucht, ob es einen naechsten Schnittpunkt gibt // float distance_next_intersection = SetToNextIntersectionAlongThisEdgeAndReturnDistance( closest_local_current_position_ref , distance_current_position , current_edge ); unsigned int the_index = 0; SnippetIndex edge_index; edge_index.edge = 0; edge_index.snip = 0; bool got_one = 0; got_one = SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( closest_local_current_position_ref, current_edge, next_voxel_intersection ); //if( distance_next_intersection != ( 1000000 ) ){ // gibt es einen naechsten Schnittpunkt? if( got_one ){ // Was der folgende Funktionsaufruf alles tut : // Hier in AddSnippetsThisIntersection wird untersucht, ob zu dem gefundenen Schnittpunkt // ein Polygon existiert das innerhalb des Voxels liegt, nur dann, wenn das der Fall ist, wird an snip_vec_ref angehaengt. // Falls es einen geeigneten Schnittpunkt gibt, all die zugehoerigen // Polygonsnippets anhaengen. // Auch wird durch die Funktion AddSnippetsThisIntersection untersucht, ob man schon ausserhalb der betrachteten Kante ist. if( AddSnippetsThisIntersection( snip_vec_ref_local , closest_local_current_position ) ){ im_done = true; finished = false; // Falls Polygone gefunden im_done auf true und finished auf false setzen. // Das bedeutet, an dieser Kante wird weitergearbeitet. Vielleicht gibt es noch mehr Schnittpunkte. } // falls kein drinnen liegendes Polygonstueck gefunden wurde, welches im Bereich der betrachteten Kante liegt // bleibt im_done auf false und es wird weiter gesucht // die current_position wird dann auf den zuletzt gefundenen Schnittpunkt gesetzt, zu dem es kein Polygonstueck gab current_position.x = closest_local_current_position.x; current_position.y = closest_local_current_position.y; } else{ // es gibt keinen weiteren Schnittpunkt mehr im_done = true; finished = true; } bool changed_loc = false; IncrementVoxelIntersectionIndex( current_edge, next_voxel_intersection , changed_loc ); if( changed_loc ){ if( snip_vec_ref_local.size() > 1 ) snip_vec_ref_local = SortClockwise( snip_vec_ref_local ); for( GridIndexType counter = 0 ; counter < snip_vec_ref_local.size() ; counter++ ){ snip_vec_ref.push_back( snip_vec_ref_local.at( counter ) ); } snip_vec_ref_local.resize( 0 ); } } return finished; } void PolygonInfo::IncrementVoxelIntersectionIndex( int current_edge, VoxelIntersectionIndex& vox_inters_index , bool& changed_location ){ if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).size() > vox_inters_index.next_intersection ){ if( voxel_intersections.edge_intersections_intersection_coord.at( current_edge ).at( vox_inters_index.next_intersection ).size() > ( vox_inters_index.intersection_douplication + 1 ) ){ vox_inters_index.intersection_douplication++; } else{ vox_inters_index.intersection_douplication = 0; vox_inters_index.next_intersection++; changed_location = true; } } } // Achtung, bei der verallgemeinerung, die Beruehrpunkte erlaubt, muss hier eine Veraenderung vor werden. // Es muessen auch naechste Punkte mit Abstand wie der bisherige erlaubt sien. // Anmerkung : ist insofern erledigt, dass diese Funktion hier nicht mehr verwendet wird. float PolygonInfo::SetToNextIntersectionAlongThisEdgeAndReturnDistance( LegacyWorldCoordinate2D& closest_local_current_position_ref , float distance_current_position , int current_edge ){ // Hier wird im Uhrzeigersinn vorwaerts gegangen um den Schnittpunkt zu finden, der dem aktuell betrachteten Schnittpunkt // am naechsten liegt. Im Uhrzeigersinn zurueck liegende Punkte werden dabei ignoriert. // Natuerlich ist jeder Punkt sich selbst der Naechste. Selbst wird daher ignoriert. // diese Funktion gibt -1000000 zurueck, falls kein Punkt gefunden werden konnte. // Die Distanz wird im Uhrzeigersinn der Voxelkante entlang gemessen. // Erkannt und gesucht wird nur was auf der betrachteten Voxelkante liegt. // Es wird der Abstand zu current_position, eindimensional entlang der // Voxelkante zurueckgegeben. float distance_current_position_local = 0; double distance_next_edge = 0; float min_local_distance = 1000000; float min_local_distance_along_edge = 1000000; LegacyWorldCoordinate2D local_current_position; local_current_position.x = current_position.x; local_current_position.y = current_position.y; float local_distance; local_distance = -1000000; it_poly.RememberPosition(); it_poly.ResetIntersectionIndex(); bool was_able_to_increment = true; while( was_able_to_increment == true ){ // if( it_poly.CheckToBeRegarded() ){ if( it_poly.ThisIntersection( local_current_position ) ){ if( IsTheSameEdgeButNoCorner( local_current_position , current_position , current_edge ) ){ distance_current_position_local = GetDistanceAlongEdge( the_dose_index , local_current_position ); distance_next_edge = GetDistanceNextEdge( current_edge ); if( ( static_cast( distance_current_position_local ) > static_cast( distance_current_position ) ) && ( static_cast( distance_next_edge ) > static_cast( distance_current_position_local ) ) ){ // betrachtet werden nur die Schnittpunkte, die im Uhrzeigersinn // entlanng der Voxelkante weiter entfernt sind // echt groesser schliesst Detektion des betracteten Punktes selbst aus local_distance = GetPeriodicDist( distance_current_position_local , distance_current_position ); if( local_distance < min_local_distance ){ min_local_distance = local_distance; min_local_distance_along_edge = distance_current_position_local; closest_local_current_position_ref.x = local_current_position.x; closest_local_current_position_ref.y = local_current_position.y; it_poly.RememberPosition(); } } } // } // check to be regarded } was_able_to_increment = it_poly.IncremtentIntersection(); } it_poly.JumpToRememberedPosition(); return min_local_distance_along_edge; } // Es ist noetig zu prufen, ob Ecke, wegen Rundungsfehlern. Hier muss auf genau die selbe Art festgestellt werden ob Ecke wie bei der unabhaengigen Betrachtung der Ecken. // nein, das ist doch nicht noetig. Diese Funktion wird nicht mehr verwendet bool PolygonInfo::IsTheSameEdgeButNoCorner( LegacyWorldCoordinate2D local_current_position , LegacyWorldCoordinate2D current_position , int current_edge ){ LegacyWorldCoordinate2D corner_coord; corner_coord.x = static_cast( the_dose_index.x ); corner_coord.y = static_cast( the_dose_index.y ); switch( current_edge ){ case 0 : if( ( local_current_position.y == current_position.y ) && ( local_current_position.x <= ( the_dose_index.x + 1 ) ) && ( local_current_position.x >= the_dose_index.x ) && ( the_dose_index.y == local_current_position.y ) ){ if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; corner_coord.x += 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; return true; } else return false; break; case 1 : if( ( local_current_position.x == current_position.x ) && ( local_current_position.y <= ( the_dose_index.y + 1 ) ) && ( local_current_position.y >= the_dose_index.y ) && ( ( the_dose_index.x + 1 ) == local_current_position.x ) ){ corner_coord.x += 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; corner_coord.y += 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; return true; } else return false; break; case 2 : if( ( local_current_position.y == current_position.y ) && ( local_current_position.x <= ( the_dose_index.x + 1 ) ) && ( local_current_position.x >= the_dose_index.x ) && ( ( the_dose_index.y + 1 ) == local_current_position.y ) ){ corner_coord.x += 1; corner_coord.y += 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; corner_coord.x -= 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; return true; } else return false; break; case 3 : if( ( local_current_position.x == current_position.x ) && ( local_current_position.y <= ( the_dose_index.y + 1 ) ) && ( local_current_position.y >= the_dose_index.y ) && ( the_dose_index.x == local_current_position.x ) ){ corner_coord.y += 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; corner_coord.y -= 1; if( ( static_cast( corner_coord.x ) == static_cast( local_current_position.x ) ) && ( static_cast( corner_coord.y ) == static_cast( local_current_position.y ) ) ) return false; return true; } else return false; break; default : assert( 0 ); } return false; } bool PolygonInfo::AddSnippetsThisIntersection( snippet_vector& snip_vec_ref , LegacyWorldCoordinate2D closest_local_current_position ){ bool there_is_a_suitable_polygon_forward = false; bool there_is_a_suitable_polygon_backward = false; PolygonSnippet forward_snippet; PolygonSnippet& forward_snippet_ref = forward_snippet; PolygonSnippet backward_snippet; PolygonSnippet& backward_snippet_ref = backward_snippet; // ersten Punkt an beide Polygonschnipsel anhaengen // Dann beide Schnittpunktelisten untersuchen um festzustellen, welche Punkte zuletzt noch aufgenommen // werden muss in dieses Polygonstueck. Das geschieht in der Vorwaertsrichtung sowie in der rueckwaertigen Richtung // durch die folgende Funktion bool do_switch = false ; float angle_charact_a = 0; float angle_charact_b = 0; if( GoForwardAndCreatePolygonSnippet( forward_snippet_ref ) ){ there_is_a_suitable_polygon_forward = true; } if( GoBackwardAndCreatePolygonSnippet( backward_snippet_ref ) ){ there_is_a_suitable_polygon_backward = true; } if( there_is_a_suitable_polygon_forward ){ angle_charact_a = forward_snippet_ref.angle_charact; } if( there_is_a_suitable_polygon_backward ){ angle_charact_b = backward_snippet_ref.angle_charact; } if( there_is_a_suitable_polygon_forward ){ if( there_is_a_suitable_polygon_backward ){ if( angle_charact_a < angle_charact_b ){ Switch( forward_snippet_ref , backward_snippet_ref ); } //if( ( JustEdge( forward_snippet_ref ) ) && ( JustEdge( backward_snippet_ref ) ) ){ // nothing happens //} if( ( JustEdge( forward_snippet_ref ) ) && ( ! JustEdge( backward_snippet_ref ) ) ){ backward_snippet_ref.characterize = inside_to_edge; backward_snippet.why_here = closest_local_current_position; snip_vec_ref.push_back( backward_snippet ); } else if( ( ! JustEdge( forward_snippet_ref ) ) && ( JustEdge( backward_snippet_ref ) ) ){ forward_snippet_ref.characterize = edge_to_inside; forward_snippet.why_here = closest_local_current_position; snip_vec_ref.push_back( forward_snippet ); } else if( ( ! JustEdge( forward_snippet_ref ) ) && ( ! JustEdge( backward_snippet_ref ) ) ){ backward_snippet_ref.characterize = inside_inside_touches; backward_snippet.why_here = closest_local_current_position; snip_vec_ref.push_back( backward_snippet ); forward_snippet_ref.characterize = inside_inside_touches; forward_snippet.why_here = closest_local_current_position; snip_vec_ref.push_back( forward_snippet ); } } } if( ( there_is_a_suitable_polygon_forward ) && ( ! there_is_a_suitable_polygon_backward ) ){ if( JustEdge( forward_snippet_ref ) ){ // nothing happens } else{ forward_snippet_ref.characterize = real_intersection; forward_snippet.why_here = closest_local_current_position; snip_vec_ref.push_back( forward_snippet ); } } if( ( ! there_is_a_suitable_polygon_forward ) && ( there_is_a_suitable_polygon_backward ) ){ if( JustEdge( backward_snippet_ref ) ){ } else{ backward_snippet_ref.characterize = real_intersection; backward_snippet_ref.why_here = closest_local_current_position; snip_vec_ref.push_back( backward_snippet ); } } // Es ist zwar so, dass man das backward snippet, falls es nur ein snippet gibt nicht anhaengen muss, denn in diesem Fall // ist das backward snippet bereits zum forward snippet geworden (und wird als forward snippet angehaengt). // Falls es zwei snippets gibt wird nur das forward snippet angehaengt, und zwar das, das im Urzeigersinn richtig liegt. // Im Zweifelsfall tauschen. // Falls es nur ein forward snippet gibt wird es angehaengt, falls es im Urzeigersinn liegt. // Dann muessen die Polygonstuecke an den snip_vec_ref dran gehaengt werden // nur falls das Polygonstueck drin liegt anhaengen (GoForwardAndCreatePolygonSnippet GoBackwardAndCreatePolygonSnippet prueft das). if( ( there_is_a_suitable_polygon_forward ) || ( there_is_a_suitable_polygon_backward ) ) return true; else return false; } bool PolygonInfo::JustEdge( PolygonSnippet& snippet_ref ){ bool just_edge = true; if( ( current_edge == 0 ) || ( current_edge == 2 ) ){ for( unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; position++ ){ LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at( position ); if( static_cast( w_coord.y ) != static_cast( snippet_ref.point_of_interest_start.y ) ) just_edge = false; } if( static_cast( snippet_ref.point_of_interest_start.y ) != static_cast( snippet_ref.point_of_interest_end.y ) ) just_edge = false; } else if( ( current_edge == 1 ) || ( current_edge == 3 ) ){ if( static_cast( snippet_ref.point_of_interest_start.x ) != static_cast( snippet_ref.point_of_interest_end.x ) ) just_edge = false; for( unsigned int position = 0 ; position < snippet_ref.snippet_intermediate_content.size() ; position++ ){ LegacyWorldCoordinate3D w_coord = snippet_ref.snippet_intermediate_content.at( position ); if( static_cast( w_coord.x ) != static_cast( snippet_ref.point_of_interest_start.x ) ) just_edge = false; } } else assert( 0 ); return just_edge; } void PolygonInfo::Switch( PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref ){ PolygonSnippet keep_snippet; PolygonSnippet& keep_snippet_ref = keep_snippet; CopySnippet( keep_snippet_ref , snippet_one_ref ); CopySnippet( snippet_one_ref, snippet_two_ref ); CopySnippet( snippet_two_ref, keep_snippet_ref ); } void PolygonInfo::CopySnippet( PolygonSnippet& to_snippet, PolygonSnippet& snip_in ){ to_snippet.characterize = snip_in.characterize; to_snippet.is_edge = snip_in.is_edge; to_snippet.why_here.x = snip_in.why_here.x; to_snippet.why_here.y = snip_in.why_here.y; to_snippet.point_of_interest_start.x = snip_in.point_of_interest_start.x; to_snippet.point_of_interest_start.y = snip_in.point_of_interest_start.y; to_snippet.point_of_interest_end.x = snip_in.point_of_interest_end.x; to_snippet.point_of_interest_end.y = snip_in.point_of_interest_end.y; to_snippet.snippet_intermediate_content.clear(); for( unsigned int counter = 0 ; counter < snip_in.snippet_intermediate_content.size() ; counter++ ){ to_snippet.snippet_intermediate_content.push_back( snip_in.snippet_intermediate_content.at( counter ) ); } } bool PolygonInfo::GoForwardAndCreatePolygonSnippet( PolygonSnippet& forward_snippet_ref ){ // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. // Falls nein kann man alles folgende ueberspringen. float& angle_charact_forward = forward_snippet_ref.angle_charact; bool is_inside_valid = CheckPolygonIsInsideForward( angle_charact_forward ); if( ( the_dose_index.x == 2 ) && ( the_dose_index.y == 2 ) ){ it_poly.PrintIntersectionIndex(); } if( is_inside_valid ){ LegacyWorldCoordinate2D& point_of_interest_start_ref = forward_snippet_ref.point_of_interest_start; LegacyWorldCoordinate2D& point_of_interest_end_ref = forward_snippet_ref.point_of_interest_end; std::vector& snippet_intermediate_content_ref = forward_snippet_ref.snippet_intermediate_content; it_poly.RunForwardToNextIntersection( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref , the_dose_index ); } return is_inside_valid; } bool PolygonInfo::GoBackwardAndCreatePolygonSnippet( PolygonSnippet& backward_snippet_ref ){ // hier muss als erstes geprueft werden, ob das Polygonsnippet ueberhaupt innerhalb des betrachteten Voxels liegt. // Falls nein kann man alles folgende ueberspringen. float& angle_charact_backward = backward_snippet_ref.angle_charact; bool is_inside_valid = CheckPolygonIsInsideBackward( angle_charact_backward ); if( is_inside_valid ){ LegacyWorldCoordinate2D& point_of_interest_start_ref = backward_snippet_ref.point_of_interest_start; LegacyWorldCoordinate2D& point_of_interest_end_ref = backward_snippet_ref.point_of_interest_end; std::vector& snippet_intermediate_content_ref = backward_snippet_ref.snippet_intermediate_content; it_poly.RunBackwardToNextIntersection( point_of_interest_start_ref , point_of_interest_end_ref , snippet_intermediate_content_ref ); } return is_inside_valid; } // To do : Sollte man it_poly.NextIntersection( the_next_point_ref ) besser als Funktions-Objekt-Dings uebergeben // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Funktionen so verfahren und hat insgesamt weniger Funtionen. // Das ist to do fuer spaeter. bool PolygonInfo::CheckPolygonIsInsideForward( float& angle_charact_forward ){ bool its_inside = false; it_poly.RememberPosition(); LegacyWorldCoordinate2D the_first_point; the_first_point.x =0; the_first_point.y = 0; LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; LegacyWorldCoordinate2D the_next_point; the_next_point.x =0; the_next_point.y = 0; LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; if( it_poly.ThisIntersection( the_first_point_ref ) ){ bool got_it = it_poly.NextPointOrIntersectionPeriodically( the_first_point_ref, the_next_point_ref, the_dose_index ); int maxNum = it_poly.MaximumNumberOfElements(); int stop_counter = -1; while( ( stop_counter < ( maxNum + 2 ) ) ){ stop_counter++; /* double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); close_first = sqrt( close_first ); if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); close_second = sqrt( close_second ); if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; */ if( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) ) stop_counter = ( maxNum + 2 ); if( ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) stop_counter = ( maxNum + 2 ); if( stop_counter < ( maxNum + 2 ) ) got_it = it_poly.NextPointOrIntersectionPeriodically( the_first_point_ref, the_next_point_ref, the_dose_index ); } if( got_it == false )assert( 0 ); if( ( got_it ) && ( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) ){ LegacyWorldCoordinate2D an_intermediate_point; an_intermediate_point.x =( ( the_first_point.x + the_next_point.x ) * 0.5) ; an_intermediate_point.y = ( ( the_first_point.y + the_next_point.y ) * 0.5) ; GetAngle( the_next_point , the_first_point , angle_charact_forward ); if( CheckPointInVoxelRegardingDoseIndex( an_intermediate_point ) ) its_inside = true; } else its_inside = false; } it_poly.JumpToRememberedPosition(); return its_inside; } // Je kleiner der Winkel zwischen Kantenrichtung im Uhrzeigersinn und Strukturelement, desto groesser der Rueckgabewert. Der // Rueckgabewert ist der Cosisnus dieses Winkels und ist daher 1, falls der Winkel null ist - minus eins ist er falls der // Winkel 180 Grad gegen die Kante laueft. Da hier nur Strukturelemente betrachtet werden, die ins Voxel rein laufen, // gibt es Winkel gruesser als 180 Grad nicht. void PolygonInfo::GetAngle( LegacyWorldCoordinate2D the_next_point , LegacyWorldCoordinate2D the_first_point , float& angle_charact ){ double hypoten = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ) + ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); assert( hypoten > 0 ); // This should never happen except in case of a structure consisting of one point only. However, that's not allowed in voxelisation. if( current_edge == 0 ){ hypoten = sqrt( hypoten ); double gekat = ( the_next_point.x - the_first_point.x ); angle_charact = static_cast( ( gekat / hypoten ) ); } if( current_edge == 1 ){ hypoten = sqrt( hypoten ); double ankat = ( the_next_point.y - the_first_point.y ); angle_charact = static_cast( ( ankat / hypoten ) ); } if( current_edge == 2 ){ hypoten = sqrt( hypoten ); double gekat = ( the_first_point.x - the_next_point.x ); angle_charact = static_cast( ( gekat / hypoten ) ); } if( current_edge == 3 ){ hypoten = sqrt( hypoten ); double ankat = ( the_first_point.y - the_next_point.y ); angle_charact = static_cast( ( ankat / hypoten ) ); } } // To do : Kann man it_poly.NextIntersection( the_next_point_ref ) nicht als Funktions-Objekts-Dings uebergeben // und dadurch CheckPolygonIsInsideForward() und CheckPolygonIsInsideBackward() in eine Funktion verpacken ? // Man kann dann eigentlich auch mit anderen "Forward" und "Backward" Sachen so verfahren. // Mache das spaeter. bool PolygonInfo::CheckPolygonIsInsideBackward( float& angle_charact_backward ){ bool its_inside = false; it_poly.RememberPosition(); LegacyWorldCoordinate2D the_first_point; the_first_point.x =0; the_first_point.y = 0; LegacyWorldCoordinate2D& the_first_point_ref = the_first_point; LegacyWorldCoordinate2D the_next_point; the_next_point.x =0; the_next_point.y = 0; LegacyWorldCoordinate2D& the_next_point_ref = the_next_point; if( it_poly.ThisIntersection( the_first_point_ref ) ){ bool got_it = it_poly.PreviousPointOrIntersectionPeriodically( the_first_point_ref , the_next_point_ref , the_dose_index ); int stop_counter = -1; int maxNum = it_poly.MaximumNumberOfElements(); while( ( stop_counter < maxNum ) ){ stop_counter++; /*double close_first = ( the_next_point.x - the_first_point.x ) * ( the_next_point.x - the_first_point.x ); close_first = sqrt( close_first ); if( close_first > ( GInformation.getPixelSpacingRow() / 10000 ) ) stop_counter = maxNum; // ( GInformation.getPixelSpacingRow() / 10000 ) weil durch Rundungsfehler manchmal nicht exakt gleich double close_second = ( the_next_point.y - the_first_point.y ) * ( the_next_point.y - the_first_point.y ); close_second = sqrt( close_second ); if( close_second > ( GInformation.getPixelSpacingColumn() /10000 ) ) stop_counter = maxNum; */ if( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) ) stop_counter = maxNum; if( ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) stop_counter = maxNum; if( stop_counter < maxNum ) got_it = it_poly.PreviousPointOrIntersectionPeriodically( the_first_point_ref , the_next_point_ref , the_dose_index ); } if( got_it == false )assert( 0 ); if( ( got_it ) && ( ( static_cast( the_next_point.x ) != static_cast( the_first_point.x ) ) || ( static_cast( the_next_point.y ) != static_cast( the_first_point.y ) ) ) ){ LegacyWorldCoordinate2D an_intermediate_point; an_intermediate_point.x =( ( the_first_point.x + the_next_point.x ) * 0.5 ); an_intermediate_point.y = ( ( the_first_point.y + the_next_point.y ) * 0.5 ); GetAngle( the_next_point , the_first_point , angle_charact_backward ); if( CheckPointInVoxelRegardingDoseIndex( an_intermediate_point ) ) its_inside = true; } else its_inside = false; } else assert(0); it_poly.JumpToRememberedPosition(); return its_inside; } bool PolygonInfo::CheckPointInVoxelRegardingDoseIndex( LegacyWorldCoordinate2D voxel_coordinate_to_be_checked ){ bool its_inside = false; if( ( voxel_coordinate_to_be_checked.x <= ( the_dose_index.x + 1 ) ) && ( voxel_coordinate_to_be_checked.x >= the_dose_index.x ) && ( voxel_coordinate_to_be_checked.y <= ( the_dose_index.y + 1 ) ) && ( voxel_coordinate_to_be_checked.y >= the_dose_index.y ) ) its_inside = true; return its_inside; } double PolygonInfo::GetDistanceNextEdge( int current_edge ){ double return_distance; switch( current_edge ){ case 0 : return_distance = GInformation.getPixelSpacingRow(); break; case 1 : return_distance = GInformation.getPixelSpacingColumn(); return_distance += GInformation.getPixelSpacingRow(); break; case 2 : return_distance = GInformation.getPixelSpacingColumn(); return_distance += 2*GInformation.getPixelSpacingRow(); break; case 3 : return_distance = 2*GInformation.getPixelSpacingColumn(); return_distance += 2*GInformation.getPixelSpacingRow(); break; } return return_distance; } float PolygonInfo::GetDistanceAlongEdge( LegacyDoseVoxelIndex3D edge_position , LegacyWorldCoordinate2D local_position ){ WorldCoordinate return_distance; if( local_position.y == edge_position.y ){ return_distance = ( local_position.x - edge_position.x ) * GInformation.getPixelSpacingRow(); } else if( local_position.y == ( edge_position.y + 1 ) ){ return_distance = GInformation.getPixelSpacingRow() - ( local_position.x - edge_position.x ) * GInformation.getPixelSpacingRow(); return_distance += GInformation.getPixelSpacingColumn(); return_distance += GInformation.getPixelSpacingRow(); } else if( local_position.x == edge_position.x ){ return_distance = 2 * GInformation.getPixelSpacingRow(); return_distance += GInformation.getPixelSpacingColumn(); return_distance += GInformation.getPixelSpacingColumn() - ( local_position.y - edge_position.y ) * GInformation.getPixelSpacingColumn(); }else if( local_position.x == ( edge_position.x + 1 ) ){ return_distance = GInformation.getPixelSpacingRow(); return_distance += ( local_position.y - edge_position.y ) * GInformation.getPixelSpacingColumn(); } else{ // assert : Etwas ist schief gegangen. Wenn es sich wirklich um einen Schnittpunkt handelt, // dann muesste einer der obigen Faelle eingetreten sein. assert( 0 ); } return return_distance; } // Returns 1D distance of two Points along edge. // Both Points are located on the edge of the voxel and the float PolygonInfo::GetPeriodicDist( float distance_current_position_local , float distance_current_position ){ float distance_oneD_return; float max_distance = static_cast( 2 * GInformation.getPixelSpacingRow() + 2 * GInformation.getPixelSpacingColumn() ); if( distance_current_position_local >= distance_current_position ){ distance_oneD_return = distance_current_position_local - distance_current_position; float cross_edge_distance = ( max_distance - distance_current_position_local ) + distance_current_position; if( cross_edge_distance < distance_oneD_return ) distance_oneD_return = cross_edge_distance; } else{ distance_oneD_return = distance_current_position - distance_current_position_local; float cross_edge_distance = ( max_distance - distance_current_position ) + distance_current_position_local; if( cross_edge_distance < distance_oneD_return ) distance_oneD_return = cross_edge_distance; } return distance_oneD_return; } double PolygonInfo::GetClockwiseDist( double distance_refer_to , double distance_compare ){ double distance_oneD_return; double max_distance = static_cast( 2 * GInformation.getPixelSpacingRow() + 2 * GInformation.getPixelSpacingColumn() ); if( distance_compare >= distance_refer_to ){ distance_oneD_return = distance_compare - distance_refer_to; } else{ distance_oneD_return = ( max_distance - distance_refer_to ) + distance_compare; } return distance_oneD_return; } /* // Es gibt einen current_static_index, der besagt welches Polygon gerade erzeugt wird. // Und einen current_moving_index, der einmal ums Voxel laueft. // Auserdem einen begin_index, der sagt, wo man mit der Erzeugung des umschliessenden Polygons angefangen hat // und wider aufhoeren will. current_static_index klappert jetzt die Voxelkante ab. Fuer jeden zweiten drinnen-drausen-Wechsel (den gibt es bei echten Schnittpunkten und manchen Beruehrpunkten) wird nun also ein innen-geschlossenes-Polygon berechnet. Das geschieht indem fuer die entsprechende Position des current_static_index solange der current_moving_index verschoben wird, bis man im Kreis rum ist. Der current_moving_index wird dabei in doppleschritten verschoben: Erst der Kante entlang zum naechsten echten Schnittpunkt oder Beruehrpunkt der zweiten Art. Dann wird diesem Polygonsnippet zu sienem anderen Schnittpunkt/Beruehrpunkt gefolgt. Das Polygonsnippet und die Randpunkte werden dabei an das derzeit zu erzeugende Innenpolygon angehaengt. Im Idealfall weiss man von einer Voxelecke anhand der Maske, dass sie draussen liegt. Falls es keine Voxelecke gibt von der man eindeutig sagen kann dass sie draussen liegt und auf die man dann den begin_index setzen kann, dann wird gesucht, ob es irgend eine Ecke gibt, die nicht Schnitt oder Beruehrpunkt ist. Per VoxelInStructure aus der Tooblox kann man sich in diesem Fall behelfen. Falls alle Ecken Beruehr oder Schnittpunkte sind, wird zunaechst geprueft, ob es nur Polygonsnippets gibt, die den Kanten entlang laufen. Falls das so ist, wird VoxelInStructure der Toolbox fuer das Zentrum des Voxels aufgerufen. Wenn das Zentrum drin ist, dann ist das ganze Voxel von der Kontur umschlossen. Falls nicht liegt das ganze Voxel ausserhalb. Falls alle Voxelecken Schnitt/Beruehrpunkte sind und falls es sehr wohl echte Schnitte gibt: Einen Punkt finden, der echter Schnittpunkt ist. Seine Nachbarschaft per VoxelInStructure aus der Tooblox untersuchen. */ // Anmerkung : Hier werden Aenderungen noetig sien, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. // Die Aenderung wird darin bestehen, dass mehrere snippets mit dem selben why_here Wert existieren, die gleichberechtigt // behandelt werden nach dem Winkel des sich nach innnen fortsetzenden Strukturelements geordnet sind. Diese werden dann // behandelt wei ueblich (also keine echte Aenderung des Programmablaufs nur der Art der Polygon - Snippets ) // Polygon aufbauen: resulting_sequence wird hier belegt bool PolygonInfo::CreatePolygonSequence(){ CalcSnippetVectors(); SnippetIndex& current_static_index_ref = current_static_index; // Es wird im idealfall in einer Ecke mit bekanntem drinnen /drausen begonnen. begin_index wird dort drauf gesetzt. // current_static_index wird solange eins weiter gesetzt bis man wieder am Anfang ankommt. // falls die Kontur gar nicht ins voxel rein laueft wird nothing_to_do auf true gesetzt bool nothing_to_do = false; bool& nothing_to_do_ref = nothing_to_do; // SetCurrentStaticIndexKnownInsideOrOutside gibt zum einen ueber its_inside die information darueber zurueck, // ob der Punkt auf den current_static_index gesetzt wurde im aussenbereich der Kontur liegt. // Zum anderen enthaelt nothing_to_do_ref nach Aufruf von SetCurrentStaticIndexKnownInsideOrOutside die // Information darueber, ob das Voxel ueberhaupt angeschnitten ist. Ist nothing_to_do_ref true, so ist das Voxel // gar nicht angeschnitten. Ist dann auch noch its_inside true, dann liegt das ganze Voxel komplett im innern der Struktur. // Ansonsten liegt das ganze Voxel komplett ausserhalb der Struktur. bool its_inside = SetCurrentStaticIndexKnownInsideOrOutside( current_static_index_ref , nothing_to_do_ref ); // Falls es eine Ecke gibt, die draussen liegt wird hier false zurueckgegeben. bool just_switched_inside = false; if( its_inside ) just_switched_inside = true; /* std::cout<< " the_dose_index.x : " << the_dose_index.x <( the_world_coordinate_3D.z ) != 0 ){ the_z_value = the_world_coordinate_3D.z; second_index = resulting_sequence.at( first_index ).size(); } } for( unsigned int second_index = 0 ; second_index < resulting_sequence.at( first_index ).size() ; second_index++ ){ LegacyWorldCoordinate3D& the_world_coordinate_3D_ref = resulting_sequence.at( first_index ).at( second_index ); the_world_coordinate_3D_ref.z = the_z_value; } if( resulting_sequence.at( first_index ).size() > 0 ){ if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).x ) != static_cast( resulting_sequence.at( first_index ).at(0).x ) )assert(0); // this must never happen. The countour must be of periodic nature. if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).y ) != static_cast( resulting_sequence.at( first_index ).at(0).y ) )assert(0); // this must never happen. The countour must be of periodic nature. if( static_cast( resulting_sequence.at( first_index ).at( resulting_sequence.at( first_index ).size() - 1 ).z ) != static_cast( resulting_sequence.at( first_index ).at(0).z ) )assert(0); // this must never happen. The countour must be of periodic nature. } } } int PolygonInfo::GetMaxNumberSnippets(){ int nr = 0; for( int ind = 0 ; ind != 4 ; ind++ ){ nr += pol_inf_vec.at( ind ).size(); } return nr; } // Hier werden Aenderungen noetig sein, sobald Beruehrpunkte der Kontur mit sich selbst erlaubt sind. // Ist erledigt. Die Beruehrpunkte sind jetzt erlaubt void PolygonInfo::GoGetPoly( bool& do_continue_ref , bool& next_is_edge_ref, int& continue_counter_ref , int& max_num_ref ){ PolygonSnippet snipp; PolygonSnippet& snipp_ref = snipp; if( next_is_edge_ref ){ bool interupt = false; GetCurrentMovingSnippet( snipp_ref ); LegacyWorldCoordinate2D why_here = snipp_ref.why_here; int the_previous_edge = current_moving_index.edge; continue_counter_ref++; IncrementSnippetIndex( current_moving_index ); if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); if( do_continue_ref == false )interupt = true; while( ! interupt ){ if( TryGetPolygonsnippetEdge( continue_counter_ref , the_previous_edge ) ){ // holt sich das Schnipsel, das zum moving index gehoert falls es Konturinhalt hat. Falls nicht wird der moving index weiter gesetzt. interupt = true; next_is_edge_ref = false; } if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); if( do_continue_ref == false ){ interupt = true; } } GetCurrentMovingSnippet( snipp_ref ); DoAppendIntermediateEdgeUpToThisSnippet( snipp_ref , why_here , the_previous_edge , current_moving_index.edge ); } else{ if( GetCurrentMovingSnippet( snipp_ref ) ){ LegacyWorldCoordinate2D why_here = snipp_ref.why_here; SetCurrentMovingProcessed(); GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( snipp_ref , continue_counter_ref ); SetCurrentMovingProcessed(); if( do_continue_ref ){ next_is_edge_ref = GetNextIsEdge( current_moving_index ); if( ! next_is_edge_ref ){ continue_counter_ref++; IncrementSnippetIndex( current_moving_index ); } } if( do_continue_ref ) do_continue_ref = DoContinue( max_num_ref , continue_counter_ref ); } else assert(0); //this should never happen } } bool PolygonInfo::CurrentSnippetIsProcessed(){ return pol_inf_vec.at( current_static_index.edge ).at( current_static_index.snip ).i_have_been_processed; } void PolygonInfo::ShowPolygonInTermsOfIntersections(){ it_poly.ShowSelf(); } void PolygonInfo::ShowResultingSequence(){ for( GridIndexType counter = 0 ; counter < resulting_sequence.size() ; counter++ ){ std::cout<< " And this is countour number : " << counter <= 0 ) && ( current_moving_index.edge >= 0 ) ){ snipp_ref = pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ); return true; } else return false; } void PolygonInfo::SetCurrentMovingProcessed(){ if( ( current_moving_index.edge < 4 ) && ( current_moving_index.snip < pol_inf_vec.at( current_moving_index.edge ).size() ) && ( current_moving_index.snip >= 0 ) && ( current_moving_index.edge >= 0 ) ){ pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ).i_have_been_processed = true; } } int PolygonInfo::EdgeDist( int edge_old , int the_current_edge ){ int edge_internal = edge_old; int counter = 0; while( edge_internal != the_current_edge ){ counter++; IncrementEdge( edge_internal ); } return counter; } void PolygonInfo::IncrementEdge( int& edge_increment ){ if( edge_increment == 3 ) edge_increment = 0; else edge_increment++; } void PolygonInfo::DoAppendIntermediateEdgeUpToThisSnippet( PolygonSnippet& snipp_ref , LegacyWorldCoordinate2D why_here , int the_previous_edge , int the_current_edge ){ PolygonSnippet snipp_internal; PolygonSnippet& snipp_internal_ref = snipp_internal; snipp_internal_ref.why_here = why_here; snipp_internal_ref.point_of_interest_start = why_here; snipp_internal_ref.point_of_interest_end = snipp_ref.why_here; std::vector& inter_content_ref = snipp_internal.snippet_intermediate_content; int edge_internal = the_previous_edge; while( EdgeDist( edge_internal , the_current_edge ) > 0 ){ edge_internal++; if( edge_internal == 4 ) edge_internal = 0; AppendEdgeToVector( inter_content_ref , edge_internal ); } if( snipp_internal_ref.snippet_intermediate_content.size() > 0 ){ if( ( snipp_internal_ref.snippet_intermediate_content.at( 0 ).x == snipp_internal_ref.point_of_interest_end.x ) && ( snipp_internal_ref.snippet_intermediate_content.at( 0 ).y == snipp_internal_ref.point_of_interest_end.y ) ) snipp_internal_ref.snippet_intermediate_content.clear(); } if( snipp_internal_ref.snippet_intermediate_content.size() > 0 ){ std::vector::iterator iter; while( ( snipp_internal_ref.snippet_intermediate_content.at( snipp_internal_ref.snippet_intermediate_content.size() - 1 ).x == snipp_internal_ref.point_of_interest_end.x ) && ( snipp_internal_ref.snippet_intermediate_content.at( snipp_internal_ref.snippet_intermediate_content.size() - 1 ).y == snipp_internal_ref.point_of_interest_end.y ) ){ iter = snipp_internal_ref.snippet_intermediate_content.begin(); iter += ( snipp_internal_ref.snippet_intermediate_content.size() - 1 ); snipp_internal_ref.snippet_intermediate_content.erase( iter ); } } AppendToResultingSequence( snipp_internal_ref ); } void PolygonInfo::AppendEdgeToVector( std::vector& vector , int edge_internal ){ LegacyWorldCoordinate3D world_coordinate; switch( edge_internal ){ case 0 : world_coordinate.x =the_dose_index.x; world_coordinate.y = the_dose_index.y; world_coordinate.z = 0; break; case 1 : world_coordinate.x =the_dose_index.x + 1; world_coordinate.y = the_dose_index.y; world_coordinate.z = 0; break; case 2 : world_coordinate.x =the_dose_index.x + 1; world_coordinate.y = the_dose_index.y + 1; world_coordinate.z = 0; break; case 3 : world_coordinate.x =the_dose_index.x; world_coordinate.y = the_dose_index.y + 1; world_coordinate.z = 0; break; default : assert( 0 ); } vector.push_back( world_coordinate ); } void PolygonInfo::AppendToResultingSequence( PolygonSnippet& snipp_ref ){ int which_polygon = ( resulting_sequence.size() - 1 ); if( resulting_sequence.at( which_polygon ).size() > 0 ){ LegacyWorldCoordinate3D the_world_coordinate_3D = resulting_sequence.at( which_polygon ).at( resulting_sequence.at( which_polygon ).size() - 1 ); if( ( snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y ) ){ DoAppendForward( snipp_ref , which_polygon ); } else if( ( snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y ) ){ DoAppendBackward( snipp_ref , which_polygon ); } else{ the_world_coordinate_3D = resulting_sequence.at( which_polygon ).at( 0 ); if( ( snipp_ref.point_of_interest_start.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_start.y == the_world_coordinate_3D.y ) ){ DoInsertForward( snipp_ref , which_polygon ); } else if( ( snipp_ref.point_of_interest_end.x == the_world_coordinate_3D.x ) && ( snipp_ref.point_of_interest_end.y == the_world_coordinate_3D.y ) ){ DoInsertBackward( snipp_ref , which_polygon ); } else{ assert( 0 ); // this should never happen } } } else AddFirstForward( snipp_ref , which_polygon ); } void PolygonInfo::DoAppendForward( PolygonSnippet& snipp_ref , int which_polygon ){ for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ resulting_sequence.at( which_polygon ).push_back( snipp_ref.snippet_intermediate_content.at( counter ) ); } LegacyWorldCoordinate3D coord_3_d; coord_3_d.x = snipp_ref.point_of_interest_end.x; coord_3_d.y = snipp_ref.point_of_interest_end.y; coord_3_d.z = 0; resulting_sequence.at( which_polygon ).push_back( coord_3_d ); } void PolygonInfo::DoAppendBackward( PolygonSnippet& snipp_ref , int which_polygon ){ int index = 0; for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ index = snipp_ref.snippet_intermediate_content.size() - counter - 1; resulting_sequence.at( which_polygon ).push_back( snipp_ref.snippet_intermediate_content.at( index ) ); } LegacyWorldCoordinate3D coord_3_d; coord_3_d.x = snipp_ref.point_of_interest_start.x; coord_3_d.y = snipp_ref.point_of_interest_start.y; coord_3_d.z = 0; resulting_sequence.at( which_polygon ).push_back( coord_3_d ); } void PolygonInfo::DoInsertForward( PolygonSnippet& snipp_ref , int which_polygon ){ LegacyPolygonTypeIterator it; for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ it = resulting_sequence.at( which_polygon ).begin(); resulting_sequence.at( which_polygon ).insert( it , snipp_ref.snippet_intermediate_content.at( counter ) ); } it = resulting_sequence.at( which_polygon ).begin(); LegacyWorldCoordinate3D coord_3_d; coord_3_d.x = snipp_ref.point_of_interest_end.x; coord_3_d.y = snipp_ref.point_of_interest_end.y; coord_3_d.z = 0; resulting_sequence.at( which_polygon ).insert( it , coord_3_d ); } void PolygonInfo::DoInsertBackward( PolygonSnippet& snipp_ref , int which_polygon ){ int index = 0; LegacyPolygonTypeIterator it; for( unsigned int counter = 0 ; counter < snipp_ref.snippet_intermediate_content.size() ; counter++ ){ index = snipp_ref.snippet_intermediate_content.size() - counter - 1; it = resulting_sequence.at( which_polygon ).begin(); resulting_sequence.at( which_polygon ).insert( it , snipp_ref.snippet_intermediate_content.at( index ) ); } it = resulting_sequence.at( which_polygon ).begin(); LegacyWorldCoordinate3D coord_3_d; coord_3_d.x = snipp_ref.point_of_interest_start.x; coord_3_d.y = snipp_ref.point_of_interest_start.y; coord_3_d.z = 0; resulting_sequence.at( which_polygon ).insert( it , coord_3_d ); } void PolygonInfo::AddFirstForward( PolygonSnippet& snipp_ref , int which_polygon ){ LegacyWorldCoordinate3D coord_3_d; coord_3_d.x = snipp_ref.point_of_interest_start.x; coord_3_d.y = snipp_ref.point_of_interest_start.y; coord_3_d.z = 0; resulting_sequence.at( which_polygon ).push_back( coord_3_d ); DoAppendForward( snipp_ref , which_polygon ); } void PolygonInfo::GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( PolygonSnippet& snipp_ref , int& continue_counter_ref ){ AppendToResultingSequence( snipp_ref ); FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( snipp_ref , continue_counter_ref ); } bool PolygonInfo::IsCorresponding( PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref ){ if( ( static_cast( snipp_ref_compare.why_here.x ) == static_cast( snipp_ref.point_of_interest_end.x ) ) && ( static_cast( snipp_ref_compare.why_here.y ) == static_cast( snipp_ref.point_of_interest_end.y ) ) ){ if( ! ( ( static_cast( snipp_ref_compare.point_of_interest_end.x ) == static_cast( snipp_ref.why_here.x ) ) || ( static_cast( snipp_ref_compare.point_of_interest_start.x ) == static_cast( snipp_ref.why_here.x ) ) ) && ( ( static_cast( snipp_ref_compare.point_of_interest_end.y ) == static_cast( snipp_ref.why_here.y ) ) || ( static_cast( snipp_ref_compare.point_of_interest_start.y ) == static_cast( snipp_ref.why_here.y ) ) ) ) return false; if( snipp_ref_compare.snippet_intermediate_content.size() != snipp_ref.snippet_intermediate_content.size() ) return false; for( GridIndexType counter = 0 ; counter < snipp_ref_compare.snippet_intermediate_content.size() ; counter++ ){ if( static_cast( snipp_ref_compare.snippet_intermediate_content.at( counter ).x ) != static_cast( snipp_ref.snippet_intermediate_content.at( snipp_ref.snippet_intermediate_content.size() - ( counter + 1 ) ).x ) ) return false; if( static_cast( snipp_ref_compare.snippet_intermediate_content.at( counter ).y ) != static_cast( snipp_ref.snippet_intermediate_content.at( snipp_ref.snippet_intermediate_content.size() - ( counter + 1 ) ).y ) ) return false; } return true; } else return false; } LegacyWorldCoordinate2D PolygonInfo::GetOtherEnd( PolygonSnippet& snipp_ref ){ if( ( snipp_ref.why_here.x == snipp_ref.point_of_interest_start.x ) && ( snipp_ref.why_here.y == snipp_ref.point_of_interest_start.y ) ){ return snipp_ref.point_of_interest_end; } else if( ( snipp_ref.why_here.x == snipp_ref.point_of_interest_end.x ) && ( snipp_ref.why_here.y == snipp_ref.point_of_interest_end.y ) ){ return snipp_ref.point_of_interest_start; } else assert( 0 ); // this should never happen return LegacyWorldCoordinate2D(); } int PolygonInfo::GetSnippetIndexDistance( SnippetIndex behind_snip_index , SnippetIndex front_snip_index ){ int dist = 0; while( !SnippetIndexIdentical( behind_snip_index , front_snip_index ) ){ dist++; IncrementSnippetIndex( behind_snip_index ); } return dist; } // returns true in case indicees are identical bool PolygonInfo::SnippetIndexIdentical( SnippetIndex first , SnippetIndex second ){ if( ( first.edge == second.edge ) && ( first.snip == second.snip ) )return true; else return false; } void PolygonInfo::FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( PolygonSnippet& snipp_ref , int& continue_counter_ref ){ SnippetIndex another_snip_index; another_snip_index.edge = current_moving_index.edge; another_snip_index.snip = current_moving_index.snip; IncrementSnippetIndex( another_snip_index ); bool there_is_one = false; while( ( !there_is_one ) && ( ( another_snip_index.edge != current_moving_index.edge ) || ( another_snip_index.snip != current_moving_index.snip ) ) ){ PolygonSnippet& snipp_ref_compare = pol_inf_vec.at( another_snip_index.edge ).at( another_snip_index.snip ) ; if( IsCorresponding( snipp_ref_compare , snipp_ref ) ){ continue_counter_ref += GetSnippetIndexDistance( current_moving_index , another_snip_index ); current_moving_index.edge = another_snip_index.edge; current_moving_index.snip = another_snip_index.snip; SetCurrentMovingProcessed(); there_is_one = true; } IncrementSnippetIndex( another_snip_index ); } assert( there_is_one ); } bool PolygonInfo::IsOtherEdge( PolygonSnippet& snipp_ref , int the_previous_edge ){ if( ( the_previous_edge == 0 ) || ( the_previous_edge == 2 ) ){ if( static_cast( snipp_ref.point_of_interest_start.y ) != static_cast( snipp_ref.point_of_interest_end.y ) ) return true; } else if( ( the_previous_edge == 1 ) || ( the_previous_edge == 3 ) ){ if( static_cast( snipp_ref.point_of_interest_start.x ) != static_cast( snipp_ref.point_of_interest_end.x ) ) return true; } else assert(0); return false; } bool PolygonInfo::TryGetPolygonsnippetEdge( int& continue_counter_ref , int the_previous_edge ){ if( pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ).snippet_intermediate_content.size() > 0 ){ // ShowSnippet(pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip )); return true; } else if( IsOtherEdge( pol_inf_vec.at( current_moving_index.edge ).at( current_moving_index.snip ) , the_previous_edge ) ){ return true; } else{ continue_counter_ref++; IncrementSnippetIndex( current_moving_index ); return false; } } void PolygonInfo::IncrementSnippetIndex( SnippetIndex& the_snippet_index ){ the_snippet_index.snip += 1; if( the_snippet_index.snip >= pol_inf_vec.at( the_snippet_index.edge ).size() ){ the_snippet_index.snip = 0; the_snippet_index.edge++; if( the_snippet_index.edge > 3 ) the_snippet_index.edge = 0; } } bool PolygonInfo::GetNextIsEdge( SnippetIndex snip_index ){ CharacterizeIntersection characterize = pol_inf_vec.at( snip_index.edge ).at( snip_index.snip ).characterize; if( characterize == inside_inside_touches ){ return false; } else{ return true; } } bool PolygonInfo::DoContinue( int& max_num , int& continue_counter_ref ){ if( max_num > ( continue_counter_ref ) ) return true; else if( max_num == ( continue_counter_ref ) )return false; else{ //std::cout<< " the_dose_index.x : " << the_dose_index.x <GetData( x, y, z ) == brightness_outside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , -1 , 0, brightness_outside ) ) ){ current_static_index_ref.edge = 0; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , -1 , 0 , brightness_outside ) ) ){ current_static_index_ref.edge = 1; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , 1 , 0, brightness_outside ) ) ){ current_static_index_ref.edge = 2; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , 1 , 0, brightness_outside ) ) ){ current_static_index_ref.edge = 3; current_static_index_ref.snip = 0; return true; } return false; } // Gibt, falls es eine Ecke gibt, die drinnen liegt true zurueck und setzt current_static_index_ref gegebenenfalls auf die entsprechende Ecke. bool PolygonInfo::CheckCornersInside( SnippetIndex& current_static_index_ref ){ Uint16 x = the_dose_index.x; Uint16 y = the_dose_index.y; Uint16 z = the_dose_index.z; if( MaskFieldReceived->GetData( x, y, z ) == brightness_outside ) assert( 0 ); // this should never happen since we are dealing with a voxel that is touched by the structure. //if( MaskFieldReceived->GetData( x, y, z ) == brightness_inside ) assert( 0 ); if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , -1 , 0, brightness_inside ) ) ){ current_static_index_ref.edge = 0; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , -1 , 0, brightness_inside ) ) ){ current_static_index_ref.edge = 1; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , 1 , 1 , 0, brightness_inside ) ) ){ current_static_index_ref.edge = 2; current_static_index_ref.snip = 0; return true; } else if( ( CheckThereIsSuchNeighbour( x , y , z , -1 , 1 , 0, brightness_inside ) ) ){ current_static_index_ref.edge = 3; current_static_index_ref.snip = 0; return true; } return false; } bool PolygonInfo::CheckThereIsSuchNeighbour( Uint16 x , Uint16 y , Uint16 z , int shift_x , int shift_y , int shift_z, field_content_type brightness ){ Uint16 x_intern = x + shift_x; Uint16 y_intern = y; if( ( x_intern < MaskFieldReceived->GetDimX() ) && ( x_intern >= 0 ) ){ if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; } x_intern = x + shift_x; y_intern = y + shift_y; if( ( x_intern < MaskFieldReceived->GetDimX() ) && ( x_intern >= 0 ) && ( y_intern < MaskFieldReceived->GetDimY() ) && ( y_intern >= 0 ) ){ if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; } x_intern = x; y_intern = y + shift_y; if( ( y_intern < MaskFieldReceived->GetDimY() ) && ( y_intern >= 0 ) ){ if( MaskFieldReceived->GetData( x_intern, y_intern, z ) == brightness ) return true; } return false; } // Gibt true zurueck, falls das Voxel von der Kontur gar nicht angeschnitten wird. bool PolygonInfo::CheckCenterSurroundingStructure( bool& inside ){ bool no_intersections = true; SnippetIndex a_snippet_index; a_snippet_index.snip = 0; a_snippet_index.edge = 0; PolygonSnippet a_snippet; for( a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++ ){ for( a_snippet_index.snip = 0 ; a_snippet_index.snip < ( pol_inf_vec.at( a_snippet_index.edge ).size() ) ; a_snippet_index.snip++ ){ a_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); if( !( ( a_snippet.characterize == outside_outside_touches ) || ( a_snippet.characterize == edge_to_edge ) || ( a_snippet.characterize == corner ) || (a_snippet.characterize == outside_to_edge ) || ( a_snippet.characterize == edge_to_outside ) ) ){ no_intersections = false; } } } if( no_intersections ){ LegacyWorldCoordinate3D a_voxel_coordinate; a_voxel_coordinate.x = (the_dose_index.x + 0.5); a_voxel_coordinate.y = (the_dose_index.y + 0.5); a_voxel_coordinate.z = the_dose_index.z; LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); Contour contour(the_polygon); inside = contour.pointInPolygon(a_world_coordinate ); } return no_intersections; } // Die folgende Funktionalitaet ist in DoseVoxel im Prinziep bereits vorhanden. Daher Lanlan fragen, ob man sie dort // zugaenglich machen kann, damit wir sie hier nicht verdoppeln muessen. Allerdings ist der Input hier . LegacyWorldCoordinate3D PolygonInfo::GetWorldCoordinate( LegacyWorldCoordinate3D voxel_coordinate ){ LegacyWorldCoordinate3D world_coordinate; LegacyWorldCoordinate3D spacing; spacing.x = GInformation.getPixelSpacingRow(); spacing.y = GInformation.getPixelSpacingColumn(); spacing.z = GInformation.getSliceThickness(); OrientationMatrix orientation = GInformation.getOrientationMatrix(); LegacyWorldCoordinate3D posPatient = GInformation.getImagePositionPatient(); world_coordinate.x = (orientation(0,0)*spacing.x*(voxel_coordinate.x-0.5)+orientation(0,1)*spacing.y*(voxel_coordinate.y-0.5)+posPatient.x); world_coordinate.y = (orientation(1,0)*spacing.x*(voxel_coordinate.x-0.5)+orientation(1,1)*spacing.y*(voxel_coordinate.y-0.5)+posPatient.y); world_coordinate.z = (posPatient.z + spacing.z *(voxel_coordinate.z-0.5)); return world_coordinate; } void PolygonInfo::SetCurrentPosition( const LegacyDoseVoxelIndex3D& aDoseIndex ){ current_position.x = static_cast(aDoseIndex.x); current_position.y = static_cast(aDoseIndex.y); } bool PolygonInfo::SnippetIndexIsIdentical( SnippetIndex first_index , SnippetIndex second_index ){ if( ( first_index.edge == second_index.edge ) && ( first_index.snip == second_index.snip ) ) return true; else return false; } // Anpassung fuer beruehrende Strukturen noetig. Dann muss sichergestellt werdedn, dass current_static_index_ref nicht ein // snippet repraesentiert das von einem anderen Snippet gefolgt wird fuer das .why_here identisch ist. bool PolygonInfo::CheckPointOnEdgeOutside( SnippetIndex& current_static_index_ref , bool& inside ){ bool got_it = false; SnippetIndex a_snippet_index; a_snippet_index.snip = 0; a_snippet_index.edge = 0; PolygonSnippet a_snippet; PolygonSnippet next_snippet; for( a_snippet_index.edge = 0 ; a_snippet_index.edge < 4 ; a_snippet_index.edge++ ){ for( a_snippet_index.snip = 0 ; a_snippet_index.snip < ( pol_inf_vec.at( a_snippet_index.edge ).size() ) ; a_snippet_index.snip++ ){ a_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); if( ( a_snippet.characterize == real_intersection ) || ( a_snippet.characterize == edge_to_inside ) || ( a_snippet.characterize == edge_to_outside ) || ( a_snippet.characterize == inside_inside_touches ) ){ int at_begin = 0; while( ( got_it == false ) && ( at_begin < 2 ) ){ // folgenden Teil auslagern als Funkton IncrementSnippetIndex() if( pol_inf_vec.at( a_snippet_index.edge ).size() > ( a_snippet_index.snip + 1 ) ){ a_snippet_index.snip += 1; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else if( a_snippet_index.edge < 3 ){ a_snippet_index.edge += 1; a_snippet_index.snip = 0; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else{ a_snippet_index.edge = 0; a_snippet_index.snip = 0; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); at_begin++; } // ende auszulagern als Funkton IncrementSnippetIndex() if( ( static_cast( a_snippet.why_here.x ) != static_cast( next_snippet.why_here.x ) ) || ( static_cast( a_snippet.why_here.y ) != static_cast( next_snippet.why_here.y ) ) ){ LegacyWorldCoordinate3D a_voxel_coordinate; a_voxel_coordinate.x = (( a_snippet.why_here.x + next_snippet.why_here.x ) * 0.5); a_voxel_coordinate.y = (( a_snippet.why_here.y + next_snippet.why_here.y ) * 0.5); a_voxel_coordinate.z = the_dose_index.z; LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); /* std::cout<< " a_voxel_coordinate.x : " << a_voxel_coordinate.x < 0 ){ a_snippet_index.snip -= 1; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else if( a_snippet_index.edge > 0 ){ a_snippet_index.edge -= 1; a_snippet_index.snip = pol_inf_vec.at( a_snippet_index.edge ).size() - 1; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else{ a_snippet_index.edge = 3; a_snippet_index.snip = pol_inf_vec.at( a_snippet_index.edge ).size() - 1; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); at_end++; } // ende auszulagern als Funkton DecrementSnippetIndex() if( ( static_cast( a_snippet.why_here.x ) != static_cast( next_snippet.why_here.x ) ) || ( static_cast( a_snippet.why_here.y ) != static_cast( next_snippet.why_here.y ) ) ){ LegacyWorldCoordinate3D a_voxel_coordinate; a_voxel_coordinate.x = (( a_snippet.why_here.x + next_snippet.why_here.x ) * 0.5); a_voxel_coordinate.y = (( a_snippet.why_here.y + next_snippet.why_here.y ) * 0.5); a_voxel_coordinate.z = the_dose_index.z; LegacyWorldCoordinate3D a_world_coordinate = GetWorldCoordinate( a_voxel_coordinate ); Contour contour(the_polygon); inside = contour.pointInPolygon( a_world_coordinate ); // folgenden Teil auslagern als Funkton IncrementSnippetIndex() if( pol_inf_vec.at( a_snippet_index.edge ).size() > ( a_snippet_index.snip + 1 ) ){ a_snippet_index.snip += 1; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else if( a_snippet_index.edge < 3 ){ a_snippet_index.edge += 1; a_snippet_index.snip = 0; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } else{ a_snippet_index.edge = 0; a_snippet_index.snip = 0; next_snippet = pol_inf_vec.at( a_snippet_index.edge ).at( a_snippet_index.snip ); } // ende auszulagern als Funkton IncrementSnippetIndex() current_static_index_ref.snip = a_snippet_index.snip; current_static_index_ref.edge = a_snippet_index.edge; got_it = true; } } } } } } return got_it; } void PolygonInfo::ResetSnippetIndicees(){ current_static_index.edge = 0; current_static_index.snip = 0; current_moving_index.edge = 0; current_moving_index.snip = 0; CopySnippetIndex( current_static_index , begin_index ); } void PolygonInfo::SetIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref ){ intersection_index_to_ref.point_index = intersection_index_from_ref.point_index; intersection_index_to_ref.intersection_index = intersection_index_from_ref.intersection_index; intersection_index_to_ref.column_raw_or_unified = intersection_index_from_ref.column_raw_or_unified; } }//namespace }//namespace }//namespace diff --git a/code/masks/rttbPolygonInfo_LEGACY.h b/code/masks/legacy/rttbPolygonInfo_LEGACY.h similarity index 97% rename from code/masks/rttbPolygonInfo_LEGACY.h rename to code/masks/legacy/rttbPolygonInfo_LEGACY.h index 17b1d7c..d48bd20 100644 --- a/code/masks/rttbPolygonInfo_LEGACY.h +++ b/code/masks/legacy/rttbPolygonInfo_LEGACY.h @@ -1,449 +1,449 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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 __PolygonInfo_H #define __PolygonInfo_H #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbStructure.h" #include "rttbDoseIteratorInterface.h" #include "rttbField_LEGACY.h" #include "rttbMaskType_LEGACY.h" #include "rttbContour_LEGACY.h" #include "rttbIterativePolygonInTermsOfIntersections_LEGACY.h" #include #include namespace rttb{ namespace masks{ namespace legacy{ typedef std::vector< std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > > edge_intersections_intersection_coord_type; typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > > intersection_coord_type; typedef std::vector< std::vector< IterativePolygonInTermsOfIntersections::WhichIntersection > >::iterator intersection_coord_iterator_type; struct VoxelIntersectionIndex{ public: unsigned int next_intersection; unsigned int intersection_douplication; VoxelIntersectionIndex(){ next_intersection = 0; intersection_douplication = 0; } void reset(){ next_intersection = 0; intersection_douplication = 0; } }; struct IntersectionsThisVoxel{ public: IntersectionsThisVoxel(){ polygon_number = -1; corner_intersections_intersection_coord.resize(4); edge_intersections_intersection_coord.resize(4); edge_intersections_vox_coord.resize(4); } ~IntersectionsThisVoxel(){}; int GetPolygonNumber(){ return polygon_number; } void SetPolygonNumber( int polygon_number_in ){ polygon_number = polygon_number_in; } std::vector< std::vector< std::vector< double > > > edge_intersections_vox_coord; intersection_coord_type corner_intersections_intersection_coord; edge_intersections_intersection_coord_type edge_intersections_intersection_coord; private: int polygon_number; }; // Die folgende Klasse handhabt die konkrete Speicherung der Schnittpunkte. // Kennt sich also mit der Speicherung der Schnittpunkte der Konturen mit den Voxelkanten aus. // Information auf Struktur-Polygonebene. // Nimmt PolygonInfo den Zugriff auf diese Information ab. // PolygonInfo: Handhabung der Polygonschnipsel die ein Voxel anschneiden : // Information auf Voxelebene. // Speichert diese derart, dass die Schnittpunkte mit der Voxelkante in Uhrzeigersinn-Reihenfolge repraesentiert sind. // Berechnet daraus dann den Anteil des Voxels, der Innerhalb der betrachteten Kontur liegt. // PolygonInfo ist ein Objekt, das alle noetigen Informationen zur Berechnung des Polygonsets enthaelt und sinnvoll //strukturiert. Es berechnet dann anhand der Gesamtheit der schneidenden Polygonschnipsel den Innenanteil. class PolygonInfo{ public: PolygonInfo(){}; PolygonInfo( const LegacyPolygonType& the_polygon_in, int polygon_number_in, field_content_type brightness_outside_in, field_content_type brightness_inside_in , FieldOfScalar* MaskFieldReceived_in , const PolygonInTermsOfIntersections& Polygon_Intersections_In , const LegacyDoseVoxelIndex3D& aDoseIndex , core::GeometricInfo& GInfIn, const IntersectionsThisVoxel& intersections_this_voxel_in ); ~PolygonInfo(){}; LegacyPolygonSequenceType& GetResultingSequence() { return resulting_sequence; }; bool CreatePolygonSequence(); struct PolygonSnippet{ PolygonSnippet(){ why_here.x =0; why_here.y = 0; point_of_interest_start.x =0; point_of_interest_start.y = 0; point_of_interest_end.x =0; point_of_interest_end.y = 0; is_edge = 0; characterize = unknown; angle_charact = (-1); i_have_been_processed = false; } //Wesentlicher Punkt: //Verantwortlich fuer die Position dieses Snipplets an dieser Stelle Position der Kante //(die Snipplets sollen anhand ihrer Schnittpositionen entlang der Kante eingeordnet werden und es soll //hier gekennzeichnet werden, welcher der beiden Schnittpunkte oder Beruehrpunkte fuer die Einordnung and dieser Stelle wesentlich war. //Ein Polygonsnippet kommt in den Kantenvektoren jeweils doppelt vor, denn es hat zwei Schnitt/Beruehrpunkte. //Einer der beiden begrenzenden Schnittpunkte/Beruehrpunkte mit der Voxlekante kann auch der Eckpunkt sein. //In vielen Faellen wird der Eckpunkt jedoch selbst kein Beruehr/Schnittpunkt sein. LegacyWorldCoordinate2D why_here; // Anfangsschnittpunkt LegacyWorldCoordinate2D point_of_interest_start; // Endschnittpunkt LegacyWorldCoordinate2D point_of_interest_end; // Polygonstueckchen zwischen den Schnitt-/Beruehrpunkten std::vector snippet_intermediate_content; bool i_have_been_processed; // handelt es sich um eine Ecke? bool is_edge; //characterize ist ein Integer: //sagt, ob es sich hier //a) um einen wahren Schnittpunkt handelt // drinnen drausen Wechsel . //Sein Wert ist dann 0. //Drinnen Drausen Wechsel geschieht. //b) um einen Beruehrpunkt vom Typ 1 : // Beide Snippets ganz auf der Kante kein Wechsel . //Kontur und Voxelkante beider angrenzenden Polygonsnipplets parallell und deckungsgleich, die Voxelkante wird von beiden zugehoerigen //Polygonsnippets nicht verlassen //Sein Wert ist dann 1 //Ein Drinnen Drausen Wechsel findet hier nicht statt. //c) um einen Beruehrpunkt vom Typ 2: //Polygon laueft halb raus. Wechsel je nachdem was folgt. //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder //ganzen Laenge auf der Kante. Es kommt von drinnen, aus dem Voxel heraus. //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. //Ein Wechsel von drausen nach drinnen findet nur statt, falls im Folgenden das an das zweite Snippet //angrenzende nach drausen weiterverlaueft. //Der Wert des integers ist 2 //d) Um einen Beruehrpunkt vom Typ 3: //Polygon laueft halb rein. //Wechsel nach drausen, je nachdem was folgt. //Das zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder //ganzen Laenge auf der Kante. Es Fuehrt nach drinnen ins voxel hinein. //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. //Ein wechsel von drinnen nach drausen findet nur statt, falls das Polygon zuletzt von drausen auf die Voxlekante zugelaufen ist. //Der Wert des integers ist dann 3 //e) Um einen Beruehrpunkt vom Typ 4: // Polygon laueft halb rein. //Das Erste der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder //ganzen Laenge auf der Kante. Es kommt von draussen auf das Voxel zu. //Das zweite der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. // Ein Wechsel findet dann statt, falls das Polygon im Folgenden nach drinnen weiter verlaueft. //Der Wert des integers ist dann 4 //f) Um einen Beruehrpunkt vom Typ 5: //Das Zweite der beiden angrenzenden Polygonsnipplets endet direkt auf der Voxelkante und ist nicht parallel, liegt also nicht in seinder //ganzen Laenge auf der Kante. Es Fuehrt nach drausen aus dem Voxel heraus. //Das erste der Angrenzenden Polygonsnippets verlaueft auf seiner angrenzenden Seite zunaechst auf der Kante. //Ein Wechsel findet dann statt, wenn das Polygon zuvor aus dem inneren des Voxels heraus kam. //Der Wert des integers ist dann 5 //g) Beruehrpunkte vom Typ 6 : // Kein Wechsel aber eventuell ein Innenbereich zu erkennen und als Polygon anzuhaengen. //(Beide angrenzenden Polygonsnipplets enden auf der Voxelkante und sind zur Voxelkante nicht paralell) // Der Wert des integers ist dann 6. // Falls der eine Schnipsel von drinnen kommt und der andere nach drinnen weiterlaueft, muss man einmal im Kreis rum fahren und // das Polygon, das dabei eintsteht anhaengen. //h) Beruehrpunkte vom Typ 7 : // Beruehrt, beide angrenzenden Polygonstuecke drausen // Ecke 8 // Ecke darf nur dann gewaehlt werden, wenn die Ecke mit sicherheit kein Schittpunkt oder Beruherpunkt mit der Kontur ist // CheckCornersOutside ist davon abhaengig. // Unklar -1. CharacterizeIntersection characterize; float angle_charact; }; typedef std::vector snippet_vector; typedef std::vector PolygonInfoVectorOfEdges; typedef snippet_vector::iterator snippet_vector_iterator; enum WhichSector{ not_known = -1 , on_edge_twelve_o_clock = 0 , section_twelve_to_three_o_clock = 1 , on_edge_three_o_clock = 2 , section_three_to_six_o_clock = 3 , on_edge_six_o_clock = 4 , section_six_to_nine_o_clock = 5 , on_edge_nine_o_clock = 6, section_nine_to_twelve_o_clock = 7 }; enum EdgeStatus{ unclear = -1 , inside = 0 , edge_or_outside = 1 }; EdgeStatus edge_status; struct SnippetIndex{ unsigned int edge; unsigned int snip; }; bool selfTest(); IterativePolygonInTermsOfIntersections GetIterativePolygoneInTermsOfIntersections(); // Constructor of PolygonInfo calls function SetIntersectionsAndResetIntersectionIndex // which calls function CreateUnifiedListOfRawAndColumnIntersections // success of this function is checked here. Calculation of the intersection points is checked as well in this process. bool TestCreateUnifiedListOfRawAndColumnIntersections( PolygonInTermsOfIntersections Expected_Unified_Polygon_Intersections ); bool CompareCalculatedAndExpectedResultingSequenceForTest( LegacyPolygonSequenceType& the_resulting_sequence_ref ); // Checks the member pol_inf_vec wihch is a vector that consists of four vectors of PolygonSnippets // representing the voxel edges. bool CheckResultingPolygonInfoVectorOfEdgesForTestStructure( PolygonInfoVectorOfEdges pol_inf_vec_expected ); void ReferenceIterativePolygonForTest( IterativePolygonInTermsOfIntersections& it_poly_ref ){ it_poly_ref = it_poly; } private: void CalcSnippetVectors(); void SetCurrentMovingProcessed(); void AppendEdgeToVector( std::vector& vector , int edge_internal ); bool GetCurrentMovingSnippet( PolygonSnippet& snipp_ref ); bool CurrentSnippetIsProcessed(); void ShowResultingSequence(); void ShowPolygonInTermsOfIntersections(); void ShowSnippet( PolygonSnippet a_snippet ); void DoCharacterize( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , CharacterizeIntersection& charact_ref , std::vector anti_outside_combination_vector , WhichSector& inside_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ); void SetDoseIndex( const LegacyDoseVoxelIndex3D& aDoseIndex ); void AppendEdges( PolygonInfoVectorOfEdges& pol_inf_vec_ref ); void CheckEdgeIntersections(); void DoAppendIntermediateEdgeUpToThisSnippet( PolygonSnippet& snipp_ref , LegacyWorldCoordinate2D why_here , int the_previous_edge , int the_current_edge ); int EdgeDist( int edge_old , int the_current_edge ); void IncrementEdge( int& edge_increment ); bool GetCornerFromVoxelIntersections( unsigned int the_index, SnippetIndex edge_index , IterativePolygonInTermsOfIntersections::WhichIntersection& intersect_index ); int GetNumberOfSnppetsThisEdge( SnippetIndex edge_index ); bool SetToNextIntersectonAlongThisEdgeAndReturnDistanceBasedOnVoxelIntersections( LegacyWorldCoordinate2D& closest_local_current_position_ref , int current_edge, VoxelIntersectionIndex next_voxel_intersection ); snippet_vector CreateSnippetVector( int number_of_snippets_this_edge , PolygonSnippet template_snip ); snippet_vector SortClockwise( snippet_vector snip_vec_local ); void InsertToSnippetVectorFront( snippet_vector snip_vec_local , SnippetIndex edge_index ); void RemoveFromLocalSnippetVector( snippet_vector& snip_vec_local , GridIndexType which_one ); void CheckEdegeTouchCharacteristicsAndAppendIntermediateContent( SnippetIndex edge_index ); void WorkWithForwardAndBackwardEdgeSnippet( int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); void WorkWithForwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_one, int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); void WorkWithBackwardEdgeSnippet( LegacyWorldCoordinate2D edge_coord, LegacyWorldCoordinate3D contour_point_two , int which_one, float& angle_charact_a , float& angle_charact_b , PolygonSnippet& forward_snippet_ref , PolygonSnippet& backward_snippet_ref , PolygonSnippet& edge_snippet_ref , std::vector& snip_vec_local , int& erased ); // The following function is just for test and easy debugging. void GetSectorsAndSetCharacteristicsDoubleCheck( SnippetIndex edge_index, LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two ); void GetSectors( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); void GetSectorFirstPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_one , WhichSector& sector_first_point_ref ); // Anmerkung : Funktion verdoppelt die obige. Kann man loeschen und ihre Aufrufe durch GetSectorFirstPoint ersetzen, // wobei GetSectorFirstPoint dann in GetSectorThisPoint umbenannt werden sollte. void GetSectorSecondPoint( LegacyWorldCoordinate2D edge_coord , LegacyWorldCoordinate3D& contour_point_two, WhichSector& sector_second_point_ref ); CharacterizeIntersection GetCharacteristicFirstCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); void GetAntiOutsideCombinationFirstCorner( std::vector& anti_outside_combination_vector_ref ); void GetInsideFirstCorner( WhichSector& inside_ref ); void GetPrecedingEdgeFirstCorner( WhichSector& preceding_edge_ref ); void GetFollowingEdgeFirstCorner( WhichSector& following_edge_ref ); bool BothOnEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& following_edge_ref ); bool FromEdgeIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , WhichSector& inside_ref ); bool FromEdgeOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& preceding_edge_ref , std::vector second_sector_vector ); bool OutToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , std::vector second_sector_vector ); bool InToEdge( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& following_edge_ref , WhichSector& inside_ref ); bool BothIn( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref ); bool BothOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , std::vector sector_vector ); bool OneInOneOut( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref , WhichSector& inside_ref , std::vector first_sector_vector ); bool FirstSectorIsOneOfTheseAndSecondSectorIsOneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); bool FirstSectorIsOneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); bool FirstSectorIsNoneOfTheseAndSecondSectorIsNoneOfThose( WhichSector& sector_first_point_ref , std::vector first_sector_vector , WhichSector& sector_second_point_ref , std::vector second_sector_vector ); CharacterizeIntersection GetCharacteristicSecondCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); void GetAntiOutsideCombinationSecondCorner( std::vector& anti_outside_combination_vector_ref ); void GetInsideSecondCorner( WhichSector& inside_ref ); void GetPrecedingEdgeSecondCorner( WhichSector& preceding_edge_ref ); void GetFollowingEdgeSecondCorner( WhichSector& following_edge_ref ); CharacterizeIntersection GetCharacteristicThirdCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); void GetAntiOutsideCombinationThirdCorner( std::vector& anti_outside_combination_vector_ref ); void GetInsideThirdCorner( WhichSector& inside_ref ); void GetPrecedingEdgeThirdCorner( WhichSector& preceding_edge_ref ); void GetFollowingEdgeThirdCorner( WhichSector& following_edge_ref ); CharacterizeIntersection GetCharacteristicFourthCorner( WhichSector& sector_first_point_ref , WhichSector& sector_second_point_ref ); void GetAntiOutsideCombinationFourthCorner( std::vector& anti_outside_combination_vector_ref ); void GetInsideFourthCorner( WhichSector& inside_ref ); void GetPrecedingEdgeFourthCorner( WhichSector& preceding_edge_ref ); void GetFollowingEdgeFourthCorner( WhichSector& following_edge_ref ); bool AppendNextIntersectionAndCorrespoindingPolygonSnippets( snippet_vector& snip_vec_ref_local , snippet_vector& snip_vec_ref , int current_edge, VoxelIntersectionIndex& next_voxel_intersection ); float SetToNextIntersectionAlongThisEdgeAndReturnDistance( LegacyWorldCoordinate2D& closest_local_current_position_ref , float distance_current_position , int current_edge ); bool IsTheSameEdgeButNoCorner( LegacyWorldCoordinate2D local_current_position , LegacyWorldCoordinate2D current_position , int current_edge ); bool AddSnippetsThisIntersection( snippet_vector& snip_vec_ref , LegacyWorldCoordinate2D closest_local_current_position ); bool JustEdge( PolygonSnippet& snippet_ref ); void Switch( PolygonSnippet& snippet_one_ref , PolygonSnippet& snippet_two_ref ); void CopySnippet( PolygonSnippet& to_snippet, PolygonSnippet& snip_in ); bool GoForwardAndCreatePolygonSnippet( PolygonSnippet& forward_snippet_ref ); bool GoBackwardAndCreatePolygonSnippet( PolygonSnippet& backward_snippet_ref); bool CheckPolygonIsInsideForward( float& angle_charact_forward ); void GetAngle( LegacyWorldCoordinate2D the_next_point , LegacyWorldCoordinate2D the_first_point , float& angle_charact ); bool CheckPolygonIsInsideBackward( float& angle_charact_backward ); bool CheckPointInVoxelRegardingDoseIndex( LegacyWorldCoordinate2D voxel_coordinate_to_be_checked ); double GetDistanceNextEdge( int current_edge ); float GetDistanceAlongEdge( LegacyDoseVoxelIndex3D edge_position , LegacyWorldCoordinate2D local_position ); float GetPeriodicDist( float distance_current_position_local , float distance_current_position ); double GetClockwiseDist( double distance_refer_to , double distance_compare ); void AppendNewPolygonToResultingSequence(); void AppendVoxelContour(); void SlicePositionUnifyAndCheckPeriodicSequence(); int GetMaxNumberSnippets(); void GoGetPoly( bool& do_continue_ref , bool& next_is_edge_ref, int& continue_counter_ref , int& max_num ); void AppendToResultingSequence( PolygonSnippet& snipp_ref ); void DoAppendForward( PolygonSnippet& snipp_ref , int which_polygon ); void DoAppendBackward( PolygonSnippet& snipp_ref , int which_polygon ); void DoInsertForward( PolygonSnippet& snipp_ref , int which_polygon ); void DoInsertBackward( PolygonSnippet& snipp_ref , int which_polygon ); void AddFirstForward( PolygonSnippet& snipp_ref , int which_polygon ); void GoAlongSnippetToNextIntersectionAndAppendToResultingSequence( PolygonSnippet& snipp_ref , int& continue_counter_ref ); bool IsCorresponding( PolygonSnippet& snipp_ref_compare , PolygonSnippet& snipp_ref ); LegacyWorldCoordinate2D GetOtherEnd( PolygonSnippet& snipp_ref ); int GetSnippetIndexDistance( SnippetIndex behind_snip_index , SnippetIndex front_snip_index ); bool SnippetIndexIdentical( SnippetIndex first , SnippetIndex second ); void FindCorrespondingOneAndSetMovingIndexAndSetContinueCounter( PolygonSnippet& snipp_ref , int& continue_counter_ref ); bool TryGetPolygonsnippetEdge( int& continue_counter_ref , int the_previous_edge ); bool IsOtherEdge( PolygonSnippet& snipp_ref , int the_previous_edge ); void IncrementSnippetIndex( SnippetIndex& the_snippet_index ); bool GetNextIsEdge( SnippetIndex snip_index ); bool DoContinue( int& max_num , int& continue_counter_ref ); void CopySnippetIndex( SnippetIndex snip_index_from , SnippetIndex& snip_index_to ); void ToZero( SnippetIndex snip_index ); void CheckInside( SnippetIndex current_moving_index , bool& it_is_inside_ref , bool& inside_switch_ref ); void SetEdgeStatus( CharacterizeIntersection characterize ); bool SetCurrentStaticIndexKnownInsideOrOutside( SnippetIndex& current_static_index_ref , bool& nothing_to_do_ref ); bool CheckCornersOutside( SnippetIndex& current_static_index_ref ); bool CheckCornersInside( SnippetIndex& current_static_index_ref ); bool CheckThereIsSuchNeighbour( Uint16 x , Uint16 y , Uint16 z , int shift_x , int shift_y , int shift_z , field_content_type brightness ); bool CheckCenterSurroundingStructure( bool& inside ); LegacyWorldCoordinate3D GetWorldCoordinate( LegacyWorldCoordinate3D actually_a_voxel_coordinate ); void SetCurrentPosition( const LegacyDoseVoxelIndex3D& aDoseIndex ); bool SnippetIndexIsIdentical( SnippetIndex first_index , SnippetIndex second_index ); bool CheckPointOnEdgeOutside( SnippetIndex& current_static_index_ref , bool& inside ); void ResetSnippetIndicees(); void SetIndexIdentical( IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_to_ref , IterativePolygonInTermsOfIntersections::WhichIntersection& intersection_index_from_ref ); void SetCurrentPositionToEdge( int voxel_edge ); bool SameSnippet( PolygonSnippet& pol_snip_a , PolygonSnippet& pol_snip_b ); void GetInCombinationFirstCorner( std::vector& in_combination_vector_ref ); void GetInCombinationSecondCorner( std::vector& in_combination_vector_ref ); void GetInCombinationThirdCorner( std::vector& in_combination_vector_ref ); void GetInCombinationFourthCorner( std::vector& in_combination_vector_ref ); void IncrementVoxelIntersectionIndex( int current_edge, VoxelIntersectionIndex& vox_inters_index , bool& changed_location ); // begin some functions and stuff for test bool CheckConstructurSuccessForTest(); // end some functions and stuff for test PolygonInfoVectorOfEdges pol_inf_vec; LegacyPolygonSequenceType resulting_sequence; FieldOfScalar* MaskFieldReceived; field_content_type brightness_outside; field_content_type brightness_inside; LegacyDoseVoxelIndex3D the_dose_index; LegacyPolygonType the_polygon; IterativePolygonInTermsOfIntersections it_poly; IntersectionsThisVoxel voxel_intersections; LegacyWorldCoordinate2D current_position; int current_edge; SnippetIndex current_static_index; SnippetIndex current_moving_index; SnippetIndex begin_index; core::GeometricInfo GInformation; }; } } } #endif diff --git a/code/masks/rttbSelfIntersectingStructureException.cpp b/code/masks/legacy/rttbSelfIntersectingStructureException.cpp similarity index 83% rename from code/masks/rttbSelfIntersectingStructureException.cpp rename to code/masks/legacy/rttbSelfIntersectingStructureException.cpp index a747cc0..974dbe8 100644 --- a/code/masks/rttbSelfIntersectingStructureException.cpp +++ b/code/masks/legacy/rttbSelfIntersectingStructureException.cpp @@ -1,39 +1,39 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include #include #include "rttbSelfIntersectingStructureException.h" namespace rttb{ namespace masks{ const char* SelfIntersectingStructureException::what() const throw() { return rttb_what.c_str(); } const char* SelfIntersectingStructureException::GetNameOfClass() const{ return "SelfIntersectingStructureException"; } }//end namespace masks }//end namespace rttb diff --git a/code/masks/rttbSelfIntersectingStructureException.h b/code/masks/legacy/rttbSelfIntersectingStructureException.h similarity index 86% rename from code/masks/rttbSelfIntersectingStructureException.h rename to code/masks/legacy/rttbSelfIntersectingStructureException.h index bdd8692..9f19afd 100644 --- a/code/masks/rttbSelfIntersectingStructureException.h +++ b/code/masks/legacy/rttbSelfIntersectingStructureException.h @@ -1,55 +1,55 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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 __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H #define __SELF_INTERSECTING_STRUCTURE_EXCEPTION_H #include #include #include "rttbException.h" namespace rttb{ namespace masks{ /*! @class SelfIntersectingStructureException @brief This exception will be thrown in case a Structure intersects with itself in a context where this is not allowed. */ class SelfIntersectingStructureException: public core::Exception { public: SelfIntersectingStructureException(const std::string& aWhat):Exception(aWhat){} virtual ~SelfIntersectingStructureException() throw() {} /*! @brief Get the exception description */ virtual const char * what() const throw(); /*! @brief Get the name of the exception class */ virtual const char* GetNameOfClass() const; }; } } #endif diff --git a/code/masks/rttbStructure_LEGACY.cpp b/code/masks/legacy/rttbStructure_LEGACY.cpp similarity index 94% rename from code/masks/rttbStructure_LEGACY.cpp rename to code/masks/legacy/rttbStructure_LEGACY.cpp index a45e02f..eec1253 100644 --- a/code/masks/rttbStructure_LEGACY.cpp +++ b/code/masks/legacy/rttbStructure_LEGACY.cpp @@ -1,256 +1,256 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; 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) +// @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) */ #include "rttbStructure_LEGACY.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbContour_LEGACY.h" //#include //#include #include #include #include #include #include namespace rttb{ namespace masks{ namespace legacy{ StructureLegacy::StructureLegacy(const core::Structure& copy) { this->_structureVector=copy.getStructureVector(); this->_legacyStructureVector.clear(); this->_strUID=copy.getUID(); this->_label=copy.getLabel(); //initialize legacy structureVector LegacyWorldCoordinate3D p; if (!(_structureVector.size() == _legacyStructureVector.size())){ //needs to be converted _legacyStructureVector.clear(); PolygonSequenceType::const_iterator itVV=_structureVector.begin(); for(;itVV!=_structureVector.end();itVV++){ PolygonType v1=*itVV; rttb::masks::legacy::LegacyPolygonType legacyPolygon; for(PolygonType::const_iterator itPP=(*itVV).begin();itPP!=(*itVV).end();itPP++){ p.x = itPP->x(); p.y = itPP->y(); p.z = itPP->z(); legacyPolygon.push_back(p); } _legacyStructureVector.push_back(legacyPolygon); } } } StructureLegacy::~StructureLegacy(){ } const PolygonSequenceType& StructureLegacy::getStructureVector() const{ return _structureVector; } const LegacyPolygonSequenceType& StructureLegacy::getLegacyStructureVector() const{ return _legacyStructureVector; } VolumeType StructureLegacy::getVolume() const{ /*check precondition: contourGeometricType must be closed planar! */ for(int i=0;i_contourGeometricTypeVector.size();i++){ std::cout << _contourGeometricTypeVector[i]<x<_legacyStructureVector.size(); std::cout <<"numberOfContours:"<getVolume() < str2.getVolume()){ LegacyPolygonSequenceType::const_iterator itVV; for(itVV=this->_legacyStructureVector.begin();itVV!=_legacyStructureVector.end();itVV++){ LegacyPolygonType::iterator itV; LegacyPolygonType vectorW=*itVV; for(itV=vectorW.begin();itV!=vectorW.end();itV++){ LegacyWorldCoordinate3D p=*itV; if(str2.pointInStructure(p)){ count++; //std::cout << "p: "<getNumberOfEndpoints()); } //this structure bigger than str2 else{ LegacyPolygonSequenceType::const_iterator itVV; const LegacyPolygonSequenceType& str2Vector = str2.getLegacyStructureVector(); for(itVV=str2Vector.begin();itVV!=str2Vector.end();itVV++){ LegacyPolygonType::iterator itV; LegacyPolygonType vectorW=*itVV; for(itV=vectorW.begin();itV!=vectorW.end();itV++){ LegacyWorldCoordinate3D p=*itV; if(this->pointInStructure(p)){ count++; } /*else std::cout << "p: "<= _legacyStructureVector.at(0).at(0).z && aPoint.z <=_legacyStructureVector.at(size-1).at(0).z){ int polygonNr=0; //get correspoinding slice for(int i=0;i= p1.z && aPoint.z #include #include "rttbBaseType.h" #include "rttbBaseType_LEGACY.h" #include "rttbStructure.h" namespace rttb{ namespace masks{ namespace legacy{ /*! @class Structure @brief This is a class representing a RT Structure */ class StructureLegacy { private: /*! @brief WorldCoordinate3D in mm */ PolygonSequenceType _structureVector; //legacy data structure for faster computation in original toolbox voxelization LegacyPolygonSequenceType _legacyStructureVector; /*! @brief Contour Geometric Type using DICOM-RT definition (3006,0042). * POINT: indicates that the contour is a single point, defining a specific location of significance. * OPEN_PLANAR: indicates that the last vertex shall not be connected to the first point, and that all points * in Contour Data (3006,0050) shall be coplanar. * OPEN_NONPLANAR: indicates that the last vertex shall not be connected to the first point, and that the points * in Contour Data(3006,0050) may be non-coplanar. * CLOSED_PLANAR: indicates that the last point shall be connected to the first point, where the first point is * not repeated in the Contour Data. All points in Contour Data (3006,0050) shall be coplanar. */ // wo und wie wird das Initialisier? Ist Vector die geeignete Datenstruktur? std::vector _contourGeometricTypeVector; /*! @brief Structure UID*/ IDType _strUID; /*! @brief Structure Label*/ StructureLabel _label; public: /** copy constructor * @param copy Structure object to be copied */ StructureLegacy(const core::Structure& copy); /*! @brief Structure Destructor */ ~StructureLegacy(); /*! @brief Get the structure vector * @Return Return a LegacyPolygonSequenceType */ const LegacyPolygonSequenceType& getLegacyStructureVector()const; /*! @brief Get the structure vector * @Return Return a PolygonSequenceType */ const PolygonSequenceType& getStructureVector() const; /*! @brief Get the volume of this Structure. Calculation using volume = 1/3 * h* (S1+S2+(S1*S2)^0,5) @return Return the absolute volume in mm3 */ VolumeType getVolume() const; /*! @brief Structure operation: contain @return Return the contain factor of str2 in this structure @brief 0 - -#include -#include -#include - -namespace rttb -{ - - namespace masks - { - - OTBMaskAccessor::OTBMaskAccessor(StructTypePointer aStructurePointer, - const core::GeometricInfo& aGeometricInfo) - : _spStructure(aStructurePointer), _legacyStructure(*aStructurePointer) - { - _spRelevantVoxelVector = MaskVoxelListPointer(); - _geoInfo = aGeometricInfo; - - //generate new structure set uid - boost::uuids::uuid id; - boost::uuids::random_generator generator; - id = generator(); - std::stringstream ss; - ss << id; - _maskUID = "OTBMask_" + ss.str(); - } - - - OTBMaskAccessor::~OTBMaskAccessor() - { - }; - - void OTBMaskAccessor::updateMask() - { - MaskVoxelList newRelevantVoxelVector; - - if (_spRelevantVoxelVector) - { - return; // already calculated - } - - - legacy::Mask legacyMask(&_geoInfo , &_legacyStructure); - - //translate result to expected values - const std::vector voxelsInStruct = legacyMask.getDoseVoxelInStructure(); - - for (std::vector::const_iterator it = voxelsInStruct.begin(); - it != voxelsInStruct.end(); ++it) - { - rttb::VoxelGridID aVoxelGridID; - rttb::VoxelGridIndex3D newIndex; - - legacy::LegacyDoseVoxelIndex3D oldIndex = it->getVoxelIndex3D(); - newIndex(0) = oldIndex.x; - newIndex(1) = oldIndex.y; - newIndex(2) = oldIndex.z; - - // new architecture - if (!_geoInfo.convert(newIndex, aVoxelGridID)) - { - throw core::MappingOutsideOfImageException("mapping outside of image occurred!"); - } - - core::MaskVoxel newMaskVoxel(aVoxelGridID); - newMaskVoxel.setRelevantVolumeFraction(it->getProportionInStr()); - - newRelevantVoxelVector.push_back(newMaskVoxel); - } - - _spRelevantVoxelVector = boost::make_shared(newRelevantVoxelVector); - return; - } - - OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector() - { - // if not already generated start voxelization here - updateMask(); - return _spRelevantVoxelVector; - } - - OTBMaskAccessor::MaskVoxelListPointer OTBMaskAccessor::getRelevantVoxelVector(float lowerThreshold) - { - MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); - updateMask(); - // filter relevant voxels - OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); - - while (it != _spRelevantVoxelVector->end()) - { - if ((*it).getRelevantVolumeFraction() > lowerThreshold) - { - filteredVoxelVectorPointer->push_back(*it); - } - - ++it; - } - - // if mask calculation was not successful this is empty! - return filteredVoxelVectorPointer; - } - - bool OTBMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const - { - //initialize return voxel - voxel.setRelevantVolumeFraction(0); - - //check if ID is valid - if (!_geoInfo.validID(aID)) - { - return false; - } - - //determine how a given voxel on the dose grid is masked - if (_spRelevantVoxelVector) - { - OTBMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); - - while (it != _spRelevantVoxelVector->end()) - { - if ((*it).getVoxelGridID() == aID) - { - voxel = (*it); - return true; - } - - ++it; - } - - //aID is not in mask - voxel.setRelevantVolumeFraction(0); - } - // returns false if mask was not calculated without triggering calculation (otherwise not const!) - else - { - return false; - } - - return false; - - } - - bool OTBMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const - { - //convert VoxelGridIndex3D to VoxelGridID - VoxelGridID aVoxelGridID; - - if (_geoInfo.convert(aIndex, aVoxelGridID)) - { - return getMaskAt(aVoxelGridID, voxel); - } - else - { - return false; - } - } - - } -} \ No newline at end of file diff --git a/code/masks/rttbOTBMaskAccessor.h b/code/masks/rttbOTBMaskAccessor.h deleted file mode 100644 index f7c8c82..0000000 --- a/code/masks/rttbOTBMaskAccessor.h +++ /dev/null @@ -1,121 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ -#ifndef __MASK_ACCESSOR_OTB_NEW_H -#define __MASK_ACCESSOR_OTB_NEW_H - -#include "rttbBaseType.h" -#include "rttbGeometricInfo.h" -#include "rttbMaskVoxel.h" -#include "rttbMaskType_LEGACY.h" -#include "rttbBaseType_LEGACY.h" -#include "rttbStructure_LEGACY.h" -#include "rttbMask.h" -#include "rttbContour_LEGACY.h" -#include "rttbPolygonInfo_LEGACY.h" -#include "DoseIteratorInterface_LEGACY.h" -#include "DoseIterator_LEGACY.h" -#include "rttbMaskAccessorInterface.h" -#include "rttbGenericDoseIterator.h" -#include "rttbStructure.h" - -#include - - -namespace rttb -{ - - namespace masks - { - /*! @class OTBMaskAccessor - * @brief Implementation of original toolbox voxelization by M. Hub. - */ - class OTBMaskAccessor: public core::MaskAccessorInterface - { - public: - typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; - typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; - - typedef core::Structure::StructTypePointer StructTypePointer; - - private: - - core::GeometricInfo _geoInfo; - - /*! vector containing list of mask voxels*/ - MaskVoxelListPointer _spRelevantVoxelVector; - - StructTypePointer _spStructure; - - legacy::StructureLegacy _legacyStructure; - - IDType _maskUID; - - - public: - - ~OTBMaskAccessor(); - - // import of structure sets (loading from data) is done elsewhere. Structures are only voxelized here. - // here the original RTToolbox voxelization shall be implemented - OTBMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo); - - /*! @brief voxelization of the given structures according to the original RTToolbox algorithm*/ - void updateMask(); - - /*! @brief get vector conatining al relevant voxels that are inside the given structure*/ - MaskVoxelListPointer getRelevantVoxelVector(); - /*! @brief get vector conatining al 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; - - bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; - - /* @ brief is true if dose is on a homogeneous grid */ - // Inhomogeneous grids are not supported at the moment, but if they will - // be supported in the future the interface does not need to change. - bool isGridHomogeneous() const - { - return true; - }; - - /*! @brief give access to GeometricInfo*/ - inline const core::GeometricInfo& getGeometricInfo() const - { - return _geoInfo; - }; - - IDType getMaskUID() const - { - return _maskUID; - }; - - }; - } -} - -#endif diff --git a/testing/examples/CMakeLists.txt b/testing/examples/CMakeLists.txt index 1b3c46a..8b6a4a9 100644 --- a/testing/examples/CMakeLists.txt +++ b/testing/examples/CMakeLists.txt @@ -1,37 +1,40 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(CORE_TEST_EXAMPLES ${EXECUTABLE_OUTPUT_PATH}/rttbExamplesTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(RTBioModelExampleTest ${CORE_TEST_EXAMPLES} RTBioModelExampleTest "${TEST_DATA_ROOT}/TestDVH/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT3.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/dvh_diff_trunk6.txt" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/dvh_diff_trunk8.txt") ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwoGridScaling.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwoGridScaling05.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantFiftyGridScaling01.dcm") ADD_TEST(RTDoseIndexTest ${CORE_TEST_EXAMPLES} RTDoseIndexTest "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT3.txt") ADD_TEST(RTDoseStatisticsTest ${CORE_TEST_EXAMPLES} RTDoseStatisticsTest "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo_withDoseGridScaling.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm") ADD_TEST(RTDVHTest ${CORE_TEST_EXAMPLES} RTDVHTest "${TEST_DATA_ROOT}/TestDVH/dvh_test.txt") ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo_withDoseGridScaling.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncreaseX.dcm") ADD_TEST(RTBioModelScatterPlotExampleTest ${CORE_TEST_EXAMPLES} RTBioModelScatterPlotExampleTest "${TEST_DATA_ROOT}/TestDVH/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt") +ADD_TEST(VoxelizationValidationTest ${CORE_TEST_EXAMPLES} VoxelizationValidationTest +"${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" +"${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/boostMask/" "${TEST_DATA_ROOT}/OTBMask/") -RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBIndices RTTBDicomIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS BoostBinaries Litmus DCMTK) +RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBOTBMask RTTBBoostMask RTTBIndices RTTBDicomIO RTTBOtherIO RTTBITKIO RTTBModels PACKAGE_DEPENDS Litmus) diff --git a/testing/examples/DVHCalculatorComparisonTest.cpp b/testing/examples/DVHCalculatorComparisonTest.cpp index e562487..9d4ef91 100644 --- a/testing/examples/DVHCalculatorComparisonTest.cpp +++ b/testing/examples/DVHCalculatorComparisonTest.cpp @@ -1,373 +1,365 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; 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 "rttbDVHTxtFileReader.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! This test can be used to get more detailed information, but it will always fail, because differences in voxelization accuracy, especially the ones caused by the change from double to float precission will not cause considerable deviations in the structure sizes, which correspond to considerable differences in the calculated DVHs. Even in double precission differences up to 0.005 between values from old and new implementation can occure. */ int DVHCalculatorComparisonTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: dose2 file name // 4: dose3 file name std::string RTSTRUCT_FILENAME; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTDOSE3_FILENAME; std::string COMPARISON_DVH_FOLDER; 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]; } if (argc > 5) { COMPARISON_DVH_FOLDER = argv[5]; } 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(); 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()); double maxDifference = 0; double difference = 0; double minDifference = 1000; clock_t start(clock()); if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) { //create MaskAccessor - boost::shared_ptr spOTBMaskAccessor = - boost::make_shared(rtStructureSet->getStructure(j), + ::boost::shared_ptr spOTBMaskAccessor = + ::boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); //create corresponding MaskedDoseIterator - boost::shared_ptr spMaskedDoseIteratorTmp = - boost::make_shared(spMaskAccessor, doseAccessor1); + ::boost::shared_ptr spMaskedDoseIteratorTmp = + ::boost::make_shared(spMaskAccessor, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); //store MaskAccessor rtStructSetMaskAccessorVec.push_back(spMaskAccessor); rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getDoseUID()); std::string dvhFileName = "dvh1"; std::string label = (rtStructureSet->getStructure(j))->getLabel(); dvhFileName.append(label); if (dvhFileName.find("/") != std::string::npos) { dvhFileName.replace(dvhFileName.find("/"), 1, ""); } std::cout << "=== Dose 1: " << label << "===" << std::endl; rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); rttb::core::DVH dvh = *(calc.generateDVH()); rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); CHECK_EQUAL(dvhOrig, dvh); CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); rttb::core::DVH::DataDifferentialType::iterator it; rttb::core::DVH::DataDifferentialType::iterator itOrig; itOrig = dvhOrigData.begin(); for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) { CHECK_CLOSE(*(itOrig), *(it), errorConstant); std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; difference = abs(*(itOrig) - * (it)); if (difference < minDifference) { minDifference = difference; } if (difference > maxDifference) { maxDifference = difference; } } } } clock_t finish(clock()); std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; std::cout << "DVH Calculation time: " << finish - start << " ms" << std::endl; maxDifference = 0; minDifference = 1000; clock_t start2(clock()); for (int j = 0; j < rtStructSetMaskAccessorVec.size(); j++) { //create corresponding MaskedDoseIterator - boost::shared_ptr spMaskedDoseIteratorTmp = - boost::make_shared(rtStructSetMaskAccessorVec.at(j), + ::boost::shared_ptr spMaskedDoseIteratorTmp = + ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor2); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor2->getDoseUID()); std::string dvhFileName = "dvh2"; std::string label = (rtStructureSet->getStructure(j))->getLabel(); dvhFileName.append(label); if (dvhFileName.find("/") != std::string::npos) { dvhFileName.replace(dvhFileName.find("/"), 1, ""); } std::cout << "=== Dose 2: " << label << "===" << std::endl; rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); rttb::core::DVH dvh = *(calc.generateDVH()); rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); CHECK_EQUAL(dvhOrig, dvh); CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); rttb::core::DVH::DataDifferentialType::iterator it; rttb::core::DVH::DataDifferentialType::iterator itOrig; itOrig = dvhOrigData.begin(); for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) { CHECK_CLOSE(*(itOrig), *(it), errorConstant); std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; difference = abs(*(itOrig) - * (it)); if (difference > 10) { std::cout << "large difference: " << abs(*(itOrig) - * (it)) << " = " << *(itOrig) << " - " << * (it) << std::endl; } if (difference < minDifference) { minDifference = difference; } if (difference > maxDifference) { maxDifference = difference; } } } clock_t finish2(clock()); std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; std::cout << "Reset dose 2, DVH Calculation time: " << finish2 - start2 << " ms" << std::endl; maxDifference = 0; minDifference = 1000; clock_t start3(clock()); for (int j = 0; j < rtStructSetMaskAccessorVec.size(); j++) { //create corresponding MaskedDoseIterator - boost::shared_ptr spMaskedDoseIteratorTmp = - boost::make_shared(rtStructSetMaskAccessorVec.at(j), + ::boost::shared_ptr spMaskedDoseIteratorTmp = + ::boost::make_shared(rtStructSetMaskAccessorVec.at(j), doseAccessor3); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor3->getDoseUID()); std::string dvhFileName = "dvh3"; std::string label = (rtStructureSet->getStructure(j))->getLabel(); dvhFileName.append(label); if (dvhFileName.find("/") != std::string::npos) { dvhFileName.replace(dvhFileName.find("/"), 1, ""); } std::cout << "=== Dose 3: " << label << "===" << std::endl; rttb::io::other::DVHTxtFileReader dvhOriginalReader = rttb::io::other::DVHTxtFileReader( COMPARISON_DVH_FOLDER + dvhFileName + ".txt"); rttb::core::DVH dvhOrig = *(dvhOriginalReader.generateDVH()); rttb::core::DVH::DataDifferentialType dvhOrigData = dvhOrig.getDataDifferential(); rttb::core::DVH dvh = *(calc.generateDVH()); rttb::core::DVH::DataDifferentialType dvhData = dvh.getDataDifferential(); CHECK_EQUAL(dvhOrig, dvh); CHECK_CLOSE(dvhOrig.getMaximum(), dvh.getMaximum(), errorConstant); CHECK_CLOSE(dvhOrig.getMinimum(), dvh.getMinimum(), errorConstant); CHECK_CLOSE(dvhOrig.getMean(), dvh.getMean(), errorConstant); rttb::core::DVH::DataDifferentialType::iterator it; rttb::core::DVH::DataDifferentialType::iterator itOrig; itOrig = dvhOrigData.begin(); for (it = dvhData.begin(); it != dvhData.end() || itOrig != dvhOrigData.end(); ++it, ++itOrig) { CHECK_CLOSE(*(itOrig), *(it), errorConstant); std::cout << std::setprecision(20) << "difference: " << abs(*(itOrig) - * (it)) << std::endl; if (difference > 10) { std::cout << "large difference: " << abs(*(itOrig) - * (it)) << " = " << *(itOrig) << " - " << * (it) << std::endl; } difference = abs(*(itOrig) - * (it)); if (difference < minDifference) { minDifference = difference; } if (difference > maxDifference) { maxDifference = difference; } } } clock_t finish3(clock()); std::cout << std::setprecision(20) << "max(difference): " << maxDifference << std::endl; std::cout << std::setprecision(20) << "min(difference): " << minDifference << std::endl; std::cout << "Reset dose 3, DVH Calculation time: " << finish3 - start3 << " ms" << std::endl; RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/DVHCalculatorExampleTest.cpp b/testing/examples/DVHCalculatorExampleTest.cpp index 2537c79..ad1a195 100644 --- a/testing/examples/DVHCalculatorExampleTest.cpp +++ b/testing/examples/DVHCalculatorExampleTest.cpp @@ -1,314 +1,306 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; 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" 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 masks::legacy::OTBMaskAccessor::StructTypePointer StructTypePointer; typedef core::DVH::DVHPointer DVHPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; 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; //create MaskAccessor for each structure - boost::shared_ptr spOTBMaskAccessor = - boost::make_shared(rtStructureSet->getStructure(j), + ::boost::shared_ptr spOTBMaskAccessor = + ::boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); //create corresponding MaskedDoseIterator - boost::shared_ptr spMaskedDoseIteratorTmp = - boost::make_shared(spMaskAccessor, doseAccessor1); + ::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), + ::boost::shared_ptr 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()); if (j == 0) { CHECK_CLOSE(1.8423272053074631, dvh.getMaximum(), 1e-1); CHECK_CLOSE(0.0069001018925373145, dvh.getMinimum(), errorConstant); CHECK_CLOSE(0.5534586388640208, dvh.getMean(), errorConstant); CHECK_CLOSE(0.42090621544477619, dvh.getMedian(), errorConstant); CHECK_CLOSE(0.075901120817910464, dvh.getModal(), errorConstant); CHECK_CLOSE(0.44688344565881616, dvh.getStdDeviation(), 1e-4); CHECK_CLOSE(0.19970481400389611, dvh.getVariance(), 1e-4); CHECK_CLOSE(89230.858052685187, dvh.getNumberOfVoxels(), 1e-1); } if (j == 4) { CHECK_CLOSE(1.6264736515373135, dvh.getMaximum(), 1e-3); CHECK_CLOSE(0.10433981915522389, dvh.getMinimum(), errorConstant); CHECK_CLOSE(0.70820073085773427, dvh.getMean(), errorConstant); CHECK_CLOSE(0.71810346124477609, dvh.getMedian(), errorConstant); CHECK_CLOSE(0.23936782041492538, dvh.getModal(), errorConstant); CHECK_CLOSE(0.36355099006842068, dvh.getStdDeviation(), errorConstant); CHECK_CLOSE(0.13216932237972889, dvh.getVariance(), errorConstant); CHECK_CLOSE(2299.7105030728999, dvh.getNumberOfVoxels(), 1e-3); } } clock_t finish2(clock()); std::cout << "Reset dose 2, DVH Calculation time: " << finish2 - start2 << " ms" << std::endl; clock_t start3(clock()); for (int j = 0; j < rtStructSetMaskAccessorVec.size(); j++) { //create corresponding MaskedDoseIterator - boost::shared_ptr spMaskedDoseIteratorTmp = - boost::make_shared(rtStructSetMaskAccessorVec.at(j), + ::boost::shared_ptr 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()); if (j == 1) { CHECK_CLOSE(0.0010765085705970151, dvh.getMaximum(), 1e-3); CHECK_CLOSE(0.00087641404074626872, dvh.getMinimum(), errorConstant); CHECK_CLOSE(0.0009788401527774486, dvh.getMean(), errorConstant); CHECK_CLOSE(0.00098846697746268666, dvh.getMedian(), errorConstant); CHECK_CLOSE(0.00098846697746268666, dvh.getModal(), errorConstant); CHECK_CLOSE(3.2977969280849566e-005, dvh.getStdDeviation(), errorConstant); CHECK_CLOSE(1.0875464578886574e-009, dvh.getVariance(), errorConstant); CHECK_CLOSE(595.30645355716683, dvh.getNumberOfVoxels(), 1e-3); } if (j == 6) { CHECK_CLOSE(0.0016589942782835824, dvh.getMaximum(), 1e-3); CHECK_CLOSE(0.00027960577723880602, dvh.getMinimum(), errorConstant); CHECK_CLOSE(0.0010389077643351956, dvh.getMean(), errorConstant); CHECK_CLOSE(0.0011246365706716419, dvh.getMedian(), errorConstant); CHECK_CLOSE(0.0013856019627611941, dvh.getModal(), errorConstant); CHECK_CLOSE(0.00036431958148461669, dvh.getStdDeviation(), errorConstant); CHECK_CLOSE(1.3272875745312625e-007, dvh.getVariance(), errorConstant); CHECK_CLOSE(8034.8878045085003, dvh.getNumberOfVoxels(), 1e-2); } } clock_t finish3(clock()); std::cout << "Reset dose 3, DVH Calculation time: " << finish3 - start3 << " ms" << std::endl; RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/examples/RTDoseIndexTest.cpp b/testing/examples/RTDoseIndexTest.cpp index d896636..3b08dca 100644 --- a/testing/examples/RTDoseIndexTest.cpp +++ b/testing/examples/RTDoseIndexTest.cpp @@ -1,207 +1,207 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include "litCheckMacros.h" #include "rttbDoseIndex.h" #include "rttbDVHSet.h" #include "rttbDVHTxtFileReader.h" #include "rttbBaseType.h" #include "rttbNullPointerException.h" #include "rttbConformalIndex.h" #include "rttbConformationNumber.h" #include "rttbConformityIndex.h" #include "rttbCoverageIndex.h" #include "rttbHomogeneityIndex.h" #include "rttbException.h" #include "rttbInvalidParameterException.h" #include #include #include namespace rttb { namespace testing { /*! @brief DoseIndexTest. ConformationNumber ConformalIndex ConformityIndex CoverageIndex HomogeneityIndex are tested. test dvh: deltaV 0.125, deltaD 0.5 1. dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133 2. dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40 3. dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50 4. dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70 Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTDoseIndexTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } /*test dvh: deltaV 0.125, deltaD 0.5*/ /*dvh TV: number of voxels 2900, maximum dose bin 133, dose bin 127~133*/ rttb::io::other::DVHTxtFileReader dvhReader = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); rttb::core::DVH dvhPTV = *(dvhReader.generateDVH()); /*dvh HT1: number of voxels 5410, maximum dose bin 40, dose bin 0~2,40*/ rttb::io::other::DVHTxtFileReader dvhReader1 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); core::DVH dvhNT1 = *(dvhReader1.generateDVH()); /*dvh HT2: number of voxels 10210, maximum dose bin 50, dose bin 0~2,50*/ rttb::io::other::DVHTxtFileReader dvhReader2 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT2); core::DVH dvhNT2 = *(dvhReader2.generateDVH()); /*dvh HT3: number of voxels 1210, maximum dose bin 70, dose bin 0~2,70*/ rttb::io::other::DVHTxtFileReader dvhReader3 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT3); core::DVH dvhNT3 = *(dvhReader3.generateDVH()); std::vector dvhTVSet; std::vector dvhHTSet; dvhTVSet.push_back(dvhPTV); dvhHTSet.push_back(dvhNT1); dvhHTSet.push_back(dvhNT2); dvhHTSet.push_back(dvhNT3); - boost::shared_ptr dvhSetPtr = boost::make_shared(dvhTVSet, dvhHTSet, "testStrSet", dvhPTV.getDoseID()); + ::boost::shared_ptr dvhSetPtr = ::boost::make_shared(dvhTVSet, dvhHTSet, "testStrSet", dvhPTV.getDoseID()); /*test exception*/ - boost::shared_ptr dvhSetNullPtr; + ::boost::shared_ptr dvhSetNullPtr; CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::CoverageIndex(dvhSetNullPtr, 0), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetNullPtr, 0), core::InvalidParameterException); /*test exception for invalid reference dose*/ CHECK_THROW_EXPLICIT(indices::ConformalIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformationNumber(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::ConformityIndex(dvhSetPtr, 100), core::InvalidParameterException); CHECK_THROW_EXPLICIT(indices::HomogeneityIndex(dvhSetPtr, 0), core::InvalidParameterException); /*test index calculation*/ /*RTConformationNumber */ //PTV covered by reference dose 30 = the whole PTV =362.5; Volume of the referece 30=362.5+1.25 indices::ConformationNumber cn = indices::ConformationNumber(dvhSetPtr, 30); //check if values are close. Equality is only achieved with double precission. CHECK_CLOSE(362.5 / 363.75, cn.getValue(), errorConstant); //cn==1*TV0/V0=362.5/2466.25 cn.setDoseReference(0); CHECK_CLOSE(362.5 / 2466.25, cn.getValue(), errorConstant); cn.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, cn.getValue(), errorConstant); //ref dose: 65 -> TVref=Vref -> cn=TVref/TV=2300/2900 CHECK_EQUAL(cn.getValue(), cn.getValueAt(0)); CHECK_THROW_EXPLICIT(cn.getValueAt(1), core::InvalidParameterException); /*ConformalIndex */ //HT 1 covered by ref=HT2 covered by ref=0, HT3 covered by ref=1.25 indices::ConformalIndex coin = indices::ConformalIndex(dvhSetPtr, 30); CHECK_CLOSE((362.5 / 363.75) * (1 - 1.25 / 151.25), coin.getValue(), errorConstant); coin.setDoseReference(0); CHECK_EQUAL(0, coin.getValue()); coin.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coin.getValue(), errorConstant); //ref dose: 65 -> Vref=0 for all HT -> cn=cn*(1-0)=cn CHECK_EQUAL(coin.getValue(), coin.getValueAt(0)); CHECK_THROW_EXPLICIT(coin.getValueAt(1), core::InvalidParameterException); /*ConformityIndex */ indices::ConformityIndex ci = indices::ConformityIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 363.75, ci.getValue(), errorConstant); ci.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, ci.getValue(), errorConstant); //ref dose: 65->ci=2300/2900*1*1*1 CHECK_EQUAL(ci.getValue(), ci.getValueAt(0)); CHECK_THROW_EXPLICIT(ci.getValueAt(1), core::InvalidParameterException); /*CoverageIndex*/ indices::CoverageIndex coverageI = indices::CoverageIndex(dvhSetPtr, 30); CHECK_CLOSE(362.5 / 362.5, coverageI.getValue(), errorConstant); //ref dose: 30 -> coverage index=1 coverageI.setDoseReference(65); CHECK_CLOSE(2300 / 2900.0, coverageI.getValue(), errorConstant); //ref dose: 65->coverage index=2300/2900 CHECK_EQUAL(coverageI.getValue(), coverageI.getValueAt(0)); CHECK_THROW_EXPLICIT(coverageI.getValueAt(1), core::InvalidParameterException); /*HomogeneityIndex TV max: 133*0.5=66.5, TV min: 127*0.5=63.5 -> hi=(66.5-63.5)/30*/ indices::HomogeneityIndex hi = indices::HomogeneityIndex(dvhSetPtr, 30); CHECK_CLOSE(3 / 30.0, hi.getValue(), errorConstant); hi.setDoseReference(65); CHECK_CLOSE(3 / 65.0, hi.getValue(), errorConstant); CHECK_EQUAL(hi.getValue(), hi.getValueAt(0)); CHECK_THROW_EXPLICIT(hi.getValueAt(1), core::InvalidParameterException); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTDoseStatisticsTest.cpp b/testing/examples/RTDoseStatisticsTest.cpp index 9b363ae..422ac21 100644 --- a/testing/examples/RTDoseStatisticsTest.cpp +++ b/testing/examples/RTDoseStatisticsTest.cpp @@ -1,132 +1,127 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; 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 "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ -#include "dcmtk/dcmrt/drtdose.h" -#include "dcmtk/dcmdata/dcfilefo.h" - #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @brief RTDoseStatisticsTest. Max, min, mean, standard deviation, variance, Vx, Dx, MOHx, MOCx, MaxOHx, MinOCx are tested. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed!*/ int RTDoseStatisticsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef algorithms::DoseStatistics::ResultListPointer ResultListPointer; //ARGUMENTS: 1: dose1 file name // 2: dose2 file name std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } if (argc > 2) { RTDOSE2_FILENAME = argv[2]; } OFCondition status; DcmFileFormat fileformat; double max, min; const double expectedVal = 5.64477e-005; const double reducedErrorConstant = 0.0001; /*Test NullPointerException*/ rttb::algorithms::DoseStatistics doseStatistics; - typedef boost::shared_ptr > > ResultsVectorPointer; + typedef ::boost::shared_ptr > > ResultsVectorPointer; ResultsVectorPointer spResults = - boost::make_shared > >(); + ::boost::make_shared > >(); ResultListPointer minListPtr(spResults); ResultListPointer maxListPtr(spResults); - ::DRTDoseIOD rtdoseDKFZ; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create corresponding DoseIterator - boost::shared_ptr spDoseIteratorTmp = - boost::make_shared(doseAccessor1); + ::boost::shared_ptr spDoseIteratorTmp = + ::boost::make_shared(doseAccessor1); DoseIteratorPointer spDoseIterator(spDoseIteratorTmp); doseStatistics.setDoseIterator(spDoseIterator); CHECK_CLOSE(doseStatistics.getMean(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics.getStdDeviation(), 0, errorConstant); CHECK_CLOSE(doseStatistics.getVariance(), 0, errorConstant); DoseTypeGy vx = doseStatistics.getVx(expectedVal); CHECK_EQUAL(vx, doseStatistics.getVx(0)); CHECK_CLOSE(expectedVal, doseStatistics.getDx(vx), reducedErrorConstant); max = doseStatistics.getMaximum(maxListPtr); CHECK_CLOSE(doseStatistics.getMaximum(maxListPtr), expectedVal, errorConstant); CHECK_EQUAL(doseStatistics.getVx(max + reducedErrorConstant), 0); min = doseStatistics.getMinimum(minListPtr); CHECK_CLOSE(min, expectedVal, errorConstant); CHECK_EQUAL(minListPtr->size(), 100); min = doseStatistics.getMinimum(minListPtr, 50); CHECK_EQUAL(minListPtr->size(), 50); DoseTypeGy wholeVolume = doseStatistics.getVx(min); CHECK_CLOSE(doseStatistics.getDx(wholeVolume), min, 0.001); CHECK_CLOSE(doseStatistics.getMOHx(vx), doseStatistics.getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics.getMOCx(20000), doseStatistics.getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics.getMinOCx(20000), doseStatistics.getMean(), reducedErrorConstant); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/VoxelizationValidationTest.cpp b/testing/examples/VoxelizationValidationTest.cpp new file mode 100644 index 0000000..a2671be --- /dev/null +++ b/testing/examples/VoxelizationValidationTest.cpp @@ -0,0 +1,192 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 929 $ (last changed revision) +// @date $Date: 2015-04-08 14:50:57 +0200 (Mi, 08 Apr 2015) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called RegisterTests + +#include +#include + +#include + +#include "litCheckMacros.h" + +#include "rttbBaseType.h" +#include "rttbDVHCalculator.h" +#include "rttbGenericMaskedDoseIterator.h" +#include "rttbGenericDoseIterator.h" +#include "rttbNullPointerException.h" +#include "rttbInvalidParameterException.h" +#include "rttbDicomDoseAccessor.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomFileStructureSetGenerator.h" +#include "rttbOTBMaskAccessor.h" +#include "rttbDVHTxtFileReader.h" +#include "rttbBoostMaskAccessor.h" +#include "rttbITKImageMaskAccessorConverter.h" +#include "rttbImageWriter.h" + + +namespace rttb +{ + + namespace testing + { + + /*! @brief VoxelizationValidationTest. + Compare two differnt voxelizations: OTB and Boost. + Check dvh maximum and minimum for each structure. + Check write mask to itk file for further validation. + */ + + int VoxelizationValidationTest(int argc, char* argv[]) + { + typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; + typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; + typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; + typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + + PREPARE_DEFAULT_TEST_REPORTING; + //ARGUMENTS: 1: structure file name + // 2: dose1 file name + // 3: directory name to write boost mask of all structures + // 4: directory name to write OTB mask of all structures + + + std::string RTSTRUCT_FILENAME ; + std::string RTDOSE_FILENAME; + std::string BoostMask_DIRNAME; + std::string OTBMask_DIRNAME; + + + if (argc > 4) + { + RTSTRUCT_FILENAME = argv[1]; + RTDOSE_FILENAME = argv[2]; + BoostMask_DIRNAME = argv[3]; + OTBMask_DIRNAME = argv[4]; + } + + OFCondition status; + DcmFileFormat fileformat; + + /* read dicom-rt dose */ + io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); + DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); + boost::shared_ptr geometricPtr = boost::make_shared(doseAccessor1->getGeometricInfo()); + + //create a vector of MaskAccessors (one for each structure) + StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( + RTSTRUCT_FILENAME.c_str()).generateStructureSet(); + + std::vector rtStructSetMaskAccessorVec; + + + if (rtStructureSet->getNumberOfStructures() > 0) + { + for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) + { + std::cout << j << ": "<< rtStructureSet->getStructure(j)->getLabel()< spOTBMaskAccessor = + ::boost::make_shared(rtStructureSet->getStructure(j), + doseAccessor1->getGeometricInfo()); + spOTBMaskAccessor->updateMask(); + MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); + + ::boost::shared_ptr spMaskedDoseIteratorTmp = + ::boost::make_shared(spMaskAccessor, doseAccessor1); + DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); + rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), + doseAccessor1->getDoseUID()); + rttb::core::DVH dvh = *(calc.generateDVH()); + + clock_t finish(clock()); + std::cout << "OTB Mask Calculation time: " << finish - start << " ms" << std::endl; + + //Write the mask image to a file. + /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. + To write all mask files, please use the outcommented code and call the .exe directly! + */ + /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter(spOTBMaskAccessor); + CHECK(itkConverter.process()); + std::stringstream fileNameSstr; + fileNameSstr<(rtStructureSet->getStructure(j), geometricPtr); + CHECK_NO_THROW(boostMaskAccessorPtr->updateMask()); + + ::boost::shared_ptr spMaskedDoseIteratorTmp2 = + ::boost::make_shared(boostMaskAccessorPtr, doseAccessor1); + DoseIteratorPointer spMaskedDoseIterator2(spMaskedDoseIteratorTmp2); + rttb::core::DVHCalculator calc2(spMaskedDoseIterator2, (rtStructureSet->getStructure(j))->getUID(), + doseAccessor1->getDoseUID()); + rttb::core::DVH dvh2 = *(calc2.generateDVH()); + + clock_t finish2(clock()); + std::cout << "Boost Mask Calculation and write file time: " << finish2 - start2 << " ms" << std::endl; + + //Write the mask image to a file. + /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. + To write all mask files, please use the outcommented code and call the .exe directly! + */ + /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter2(boostMaskAccessorPtr); + CHECK(itkConverter2.process()); + std::stringstream fileNameSstr2; + fileNameSstr2< #include #include "litCheckMacros.h" #include "litImageTester.h" #include "litTestImageIO.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomDoseAccessor.h" #include "rttbInvalidDoseException.h" #include "rttbDicomFileStructureSetGenerator.h" -#include "rttbOTBMaskAccessor.h" #include "rttbITKImageMaskAccessorConverter.h" #include "rttbITKImageFileMaskAccessorGenerator.h" +#include "rttbOTBMaskAccessor.h" namespace rttb { namespace testing { /*!@brief MaskAccessorConverterTest - test the conversion rttb dose accessor ->itk 1) test with dicom file (DicomDoseAccessorGenerator) 2) test with mhd file (ITKImageFileDoseAccessorGenerator) */ - int MaskAccessorConverterTest(int argc, char* argv[]) + int ITKMaskAccessorConverterTest(int argc, char* argv[]) { typedef core::DoseIteratorInterface::DoseAccessorPointer DoseAccessorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; - typedef io::mask::ITKImageMaskAccessor::ITKMaskImageType::Pointer ITKImageTypePointer; + typedef io::itk::ITKImageMaskAccessor::ITKMaskImageType::Pointer ITKImageTypePointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: //ARGUMENTS: 1: structure file name // 2: dose1 file name std::string RTStr_FILENAME; std::string RTDose_FILENAME; std::string Mask_FILENAME; if (argc > 3) { RTStr_FILENAME = argv[1]; RTDose_FILENAME = argv[2]; Mask_FILENAME = argv[3]; } //1) Read dicomFile and test getITKImage() io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDose_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTStr_FILENAME.c_str()).generateStructureSet(); - MaskAccessorPointer maskAccessorPtr = boost::make_shared(rtStructureSet->getStructure(0), doseAccessor1->getGeometricInfo()); + MaskAccessorPointer maskAccessorPtr = boost::make_shared(rtStructureSet->getStructure(0), doseAccessor1->getGeometricInfo()); - io::mask::ITKImageMaskAccessorConverter maskAccessorConverter(maskAccessorPtr); + maskAccessorPtr->updateMask();//!Important: Update the mask before conversion. + + io::itk::ITKImageMaskAccessorConverter maskAccessorConverter(maskAccessorPtr); CHECK_NO_THROW(maskAccessorConverter.process()); CHECK_NO_THROW(maskAccessorConverter.getITKImage()); //2) Read itk image, generate mask and convert it back to itk image, check equal - MaskAccessorPointer maskAccessorPtr2 = io::mask::ITKImageFileMaskAccessorGenerator(Mask_FILENAME.c_str()).generateMaskAccessor(); - io::mask::ITKImageMaskAccessorConverter maskAccessorConverter2(maskAccessorPtr2); + MaskAccessorPointer maskAccessorPtr2 = io::itk::ITKImageFileMaskAccessorGenerator(Mask_FILENAME.c_str()).generateMaskAccessor(); + maskAccessorPtr2->updateMask();//!Important: Update the mask before conversion. + io::itk::ITKImageMaskAccessorConverter maskAccessorConverter2(maskAccessorPtr2); maskAccessorConverter2.process(); typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; ITKImageTypePointer convertedImagePtr = maskAccessorConverter2.getITKImage(); - io::mask::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer expectedImage = - lit::TestImageIO::readImage( + io::itk::ITKImageMaskAccessor::ITKMaskImageType::ConstPointer expectedImage = + lit::TestImageIO::readImage( Mask_FILENAME); CHECK_EQUAL(convertedImagePtr->GetOrigin()[0], expectedImage->GetOrigin()[0]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[1], expectedImage->GetOrigin()[1]); CHECK_EQUAL(convertedImagePtr->GetOrigin()[2], expectedImage->GetOrigin()[2]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[0], expectedImage->GetSpacing()[0]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[1], expectedImage->GetSpacing()[1]); CHECK_EQUAL(convertedImagePtr->GetSpacing()[2], expectedImage->GetSpacing()[2]); int sizeX = convertedImagePtr->GetLargestPossibleRegion().GetSize()[0]; int sizeY = convertedImagePtr->GetLargestPossibleRegion().GetSize()[1]; int sizeZ = convertedImagePtr->GetLargestPossibleRegion().GetSize()[2]; - io::mask::ITKImageMaskAccessor::ITKMaskImageType::IndexType index; + io::itk::ITKImageMaskAccessor::ITKMaskImageType::IndexType index; for(unsigned int i=0; i<20 && iGetPixel(index) >= 0 && expectedImage->GetPixel(index)<=1){ CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for(unsigned int i=0; i<20; i++){ index[0] = sizeX -1-i; index[1] = sizeY -1-i; index[2] = sizeZ -1-i; if(expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index)<=1){ CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } for(unsigned int i=0; i<20 && (sizeX/2 -i) < sizeX && (sizeY/2 -i) < sizeY && (sizeZ/2 -i) < sizeZ; i++){ index[0] = sizeX/2 -i; index[1] = sizeY/2 -i; index[2] = sizeZ/2 -i; if(expectedImage->GetPixel(index) >= 0 && expectedImage->GetPixel(index)<=1){ CHECK_EQUAL(convertedImagePtr->GetPixel(index), expectedImage->GetPixel(index)); } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/mask/MaskAccessorGeneratorTest.cpp b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp similarity index 79% rename from testing/io/mask/MaskAccessorGeneratorTest.cpp rename to testing/io/itk/ITKMaskAccessorGeneratorTest.cpp index 7c58759..f162d78 100644 --- a/testing/io/mask/MaskAccessorGeneratorTest.cpp +++ b/testing/io/itk/ITKMaskAccessorGeneratorTest.cpp @@ -1,97 +1,97 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 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 #include #include #include "litCheckMacros.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "rttbBaseType.h" #include "rttbInvalidDoseException.h" #include "rttbITKImageFileMaskAccessorGenerator.h" #include "rttbITKImageMaskAccessorGenerator.h" namespace rttb { namespace testing { /*!@brief MaskAccessorGeneratorTest - test the generators for dicom data 1) test itk file generator generateDoseAccessor() 2) test itk generator generateDoseAccessor() */ - int MaskAccessorGeneratorTest(int argc, char* argv[]) + int ITKMaskAccessorGeneratorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: // 1: mhd/raw file name std::string Mask_FILENAME; if (argc > 1) { Mask_FILENAME = argv[1]; } /* test ITKImageFileMaskAccessorGenerator generateDoseAccessor()*/ - CHECK_THROW_EXPLICIT(io::mask::ITKImageFileMaskAccessorGenerator("test.test").generateMaskAccessor(), + CHECK_THROW_EXPLICIT(io::itk::ITKImageFileMaskAccessorGenerator("test.test").generateMaskAccessor(), core::InvalidDoseException); - CHECK_NO_THROW(io::mask::ITKImageFileMaskAccessorGenerator( + CHECK_NO_THROW(io::itk::ITKImageFileMaskAccessorGenerator( Mask_FILENAME.c_str()).generateMaskAccessor()); /* test ITKImageMaskAccessorGenerator generateDoseAccessor()*/ typedef itk::Image< DoseTypeGy, 3 > MaskImageType; typedef itk::ImageFileReader ReaderType; MaskImageType::ConstPointer invalidDose = MaskImageType::New(); ReaderType::Pointer reader = ReaderType::New(); - CHECK_THROW_EXPLICIT(io::mask::ITKImageMaskAccessorGenerator( + CHECK_THROW_EXPLICIT(io::itk::ITKImageMaskAccessorGenerator( invalidDose.GetPointer()).generateMaskAccessor(), core::InvalidDoseException); reader->SetFileName(Mask_FILENAME); //important to update the reader (won't work without) reader->Update(); - CHECK_NO_THROW(io::mask::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor()); + CHECK_NO_THROW(io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor()); - io::mask::ITKImageMaskAccessorGenerator::MaskAccessorPointer maskAcc = io::mask::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor(); + io::itk::ITKImageMaskAccessorGenerator::MaskAccessorPointer maskAcc = io::itk::ITKImageMaskAccessorGenerator(reader->GetOutput()).generateMaskAccessor(); CHECK_NO_THROW( maskAcc->getRelevantVoxelVector()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/io/itk/files.cmake b/testing/io/itk/files.cmake index 5cc66aa..b8458a7 100644 --- a/testing/io/itk/files.cmake +++ b/testing/io/itk/files.cmake @@ -1,9 +1,11 @@ SET(CPP_FILES ITKDoseAccessorGeneratorTest.cpp ITKDoseAccessorConverterTest.cpp + ITKMaskAccessorGeneratorTest.cpp + ITKMaskAccessorConverterTest.cpp ITKIOTest.cpp rttbITKIOTests.cpp - ) +) SET(H_FILES ) diff --git a/testing/io/itk/rttbITKIOTests.cpp b/testing/io/itk/rttbITKIOTests.cpp index 24e286e..e9e2a37 100644 --- a/testing/io/itk/rttbITKIOTests.cpp +++ b/testing/io/itk/rttbITKIOTests.cpp @@ -1,60 +1,62 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb{ namespace testing{ void registerTests() { LIT_REGISTER_TEST(ITKDoseAccessorGeneratorTest); LIT_REGISTER_TEST(ITKDoseAccessorConverterTest); LIT_REGISTER_TEST(ITKIOTest); + LIT_REGISTER_TEST(ITKMaskAccessorGeneratorTest); + LIT_REGISTER_TEST(ITKMaskAccessorConverterTest); } } } 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/io/mask/CMakeLists.txt b/testing/io/mask/CMakeLists.txt deleted file mode 100644 index f366b1c..0000000 --- a/testing/io/mask/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -#----------------------------------------------------------------------------- -# 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 BoostBinaries Litmus MatchPoint ITK DCMTK) - diff --git a/testing/io/virtuos/CMakeLists.txt b/testing/io/virtuos/CMakeLists.txt index 68840d9..e1a6624 100644 --- a/testing/io/virtuos/CMakeLists.txt +++ b/testing/io/virtuos/CMakeLists.txt @@ -1,52 +1,52 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(VIRTUOSIO_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbVirtuosIOTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(VirtuosDoseAccessorGeneratorTest ${VIRTUOSIO_TEST} VirtuosDoseAccessorGeneratorTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos") ADD_TEST(VirtuosDoseIOTest ${VIRTUOSIO_TEST} VirtuosDoseIOTest "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.pln" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos") #ADD_TEST(VirtuosDoseIOTest ${VIRTUOSIO_TEST} VirtuosDoseIOTest #"${TEST_DATA_ROOT}/Virtuos/0001220308_Loga_Ivonne/0001220308_Loga_Ivonne111.pln" "${TEST_DATA_ROOT}/Virtuos/0001220308_Loga_Ivonne/0001220308_Loga_Ivonne111.dos.gz" #"${TEST_DATA_ROOT}/Virtuos/0001220308_Loga_Ivonne/0001220308_Loga_Ivonne112.dos.gz") ADD_TEST(VirtuosStructureIOTest ${VIRTUOSIO_TEST} VirtuosStructureIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac101.dos.gz") ADD_TEST(VirtuosStructureSetGeneratorTest ${VIRTUOSIO_TEST} VirtuosStructureSetGeneratorTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.vdx" "${TEST_DATA_ROOT}/Virtuos/prostate_ac/prostate_ac000.ctx.gz" ) #trip data ADD_TEST(TripStructureIOTest ${VIRTUOSIO_TEST} TripStructureIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.vdx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx.gz" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030000.ctx" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/NHHTrip/NHH030101.dos") ADD_TEST(TripDoseIOTest ${VIRTUOSIO_TEST} TripDoseIOTest "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.pln" "${TEST_DATA_ROOT}/Virtuos/NHH030/NHH030101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/NHHTrip/NHH030101.dos") ADD_TEST(VirtuosDVHCalculatorExampleTest ${VIRTUOSIO_TEST} VirtuosDVHCalculatorExampleTest "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/MPM_LR_ah101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/MPM_LR_ah000.vdx" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/MPM_LR_ah101.pln" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/MPM_LR_ah000.ctx.gz" ) -RTTB_CREATE_TEST_MODULE(rttbVirtuosIO DEPENDS RTTBVirtuosIO RTTBMasks PACKAGE_DEPENDS Boost Litmus VirtuosIO) +RTTB_CREATE_TEST_MODULE(rttbVirtuosIO DEPENDS RTTBVirtuosIO RTTBMasks RTTBOTBMask PACKAGE_DEPENDS Boost Litmus VirtuosIO) diff --git a/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp b/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp index eea93fe..7944d97 100644 --- a/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp +++ b/testing/io/virtuos/VirtuosDVHCalculatorExampleTest.cpp @@ -1,183 +1,183 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbOTBMaskAccessor.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosDoseAccessor.h" #include "rttbVirtuosFileStructureSetGenerator.h" namespace rttb { namespace testing { /*! @brief VirtuosDVHCalculatorExampleTest. 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 VirtuosDVHCalculatorExampleTest(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 masks::legacy::OTBMaskAccessor::StructTypePointer StructTypePointer; typedef core::DVH::DVHPointer DVHPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: virtuos dose file name // 2: virtuos structure file name // 3: virtuos plan file name // 4: virtuos CT file name std::string Virtuos_Dose_File; std::string Virtuos_Structure_File; std::string Virtuos_Plan_File; std::string Virtuos_CT_File; if (argc > 1) { Virtuos_Dose_File = argv[1]; } if (argc > 2) { Virtuos_Structure_File = argv[2]; } if (argc > 3) { Virtuos_Plan_File = argv[3]; } if (argc > 4) { Virtuos_CT_File = argv[4]; } //Virtuos DVH Test io::virtuos::VirtuosPlanFileDoseAccessorGenerator doseAccessorGeneratorVirtuos(Virtuos_Dose_File, Virtuos_Plan_File); DoseAccessorPointer doseAccessorVirtuos(doseAccessorGeneratorVirtuos.generateDoseAccessor()); StructureSetPointer rtStructureSetVirtuos = io::virtuos::VirtuosFileStructureSetGenerator( Virtuos_Structure_File, Virtuos_CT_File).generateStructureSet(); for (int i = 1; i < rtStructureSetVirtuos->getNumberOfStructures(); i++) { //if(i=6 || i==8){//todo: assertion bug! if (i == 8) { //create MaskAccessor for each structure - boost::shared_ptr spOTBMaskAccessorVirtuos = - boost::make_shared(rtStructureSetVirtuos->getStructure(i), + boost::shared_ptr spOTBMaskAccessorVirtuos = + boost::make_shared(rtStructureSetVirtuos->getStructure(i), doseAccessorVirtuos->getGeometricInfo()); spOTBMaskAccessorVirtuos->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessorVirtuos); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, doseAccessorVirtuos); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); std::cout << "dvh calc" << std::endl; rttb::core::DVHCalculator* calc; if (i == 6) { calc = new rttb::core::DVHCalculator(spMaskedDoseIterator, (rtStructureSetVirtuos->getStructure(i))->getUID(), doseAccessorVirtuos->getDoseUID(), 0.367944); } else { calc = new rttb::core::DVHCalculator(spMaskedDoseIterator, (rtStructureSetVirtuos->getStructure(i))->getUID(), doseAccessorVirtuos->getDoseUID(), 0.510107); } DVHPointer dvhPtr = calc->generateDVH(); if (i == 6) { CHECK_CLOSE(42.497532, dvhPtr->getMaximum(), errorConstant); CHECK_CLOSE(2.7595800000000001, dvhPtr->getMinimum(), errorConstant); CHECK_CLOSE(7.4752642058590695, dvhPtr->getMean(), errorConstant); CHECK_CLOSE(6.4390200000000002, dvhPtr->getMedian(), errorConstant); CHECK_CLOSE(5.7031320000000001, dvhPtr->getModal(), errorConstant); CHECK_CLOSE(3.5065188466477824, dvhPtr->getStdDeviation(), errorConstant); CHECK_CLOSE(12.295674421896095, dvhPtr->getVariance(), errorConstant); CHECK_CLOSE(177218.04900734947, dvhPtr->getNumberOfVoxels(), 1e-2); } if (i == 8) { CHECK_CLOSE(68.099284499999996, dvhPtr->getMaximum(), errorConstant); CHECK_CLOSE(24.7401895, dvhPtr->getMinimum(), errorConstant); CHECK_CLOSE(54.384709827101481, dvhPtr->getMean(), errorConstant); CHECK_CLOSE(54.836502499999995, dvhPtr->getMedian(), errorConstant); CHECK_CLOSE(54.836502499999995, dvhPtr->getModal(), errorConstant); CHECK_CLOSE(3.3345924130915088, dvhPtr->getStdDeviation(), errorConstant); CHECK_CLOSE(11.119506561447452, dvhPtr->getVariance(), errorConstant); CHECK_CLOSE(338856.04793872859, dvhPtr->getNumberOfVoxels(), 1e-2); } } } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/CMakeLists.txt b/testing/masks/CMakeLists.txt index 24b8248..7f7d4ae 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/CMakeLists.txt @@ -1,20 +1,17 @@ -#----------------------------------------------------------------------------- -# Setup the system information test. Write out some basic failsafe -# information in case the test doesn't run. -#----------------------------------------------------------------------------- + MESSAGE (STATUS "Process All Mask Tests...") -SET(MASKS_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbMasksTests) + #----------------------------------------------------------------------------- + # Include sub directories + #----------------------------------------------------------------------------- -SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) + IF(BUILD_MASK_BOOST) + ADD_SUBDIRECTORY(boost) + ENDIF(BUILD_MASK_BOOST) + + IF(BUILD_OTBMASK) + ADD_SUBDIRECTORY(legacy) + ENDIF(BUILD_OTBMASK) + -SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) - - -#----------------------------------------------------------------------------- - -ADD_TEST(OTBMaskAccessorTest ${MASKS_TESTS} OTBMaskAccessorTest -) - -RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBMasks PACKAGE_DEPENDS BoostBinaries Litmus DCMTK) diff --git a/testing/io/mask/BoostMaskAccessorTest.cpp b/testing/masks/boost/BoostMaskAccessorTest.cpp similarity index 87% rename from testing/io/mask/BoostMaskAccessorTest.cpp rename to testing/masks/boost/BoostMaskAccessorTest.cpp index 5c4211e..6102ffb 100644 --- a/testing/io/mask/BoostMaskAccessorTest.cpp +++ b/testing/masks/boost/BoostMaskAccessorTest.cpp @@ -1,128 +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 "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 io::mask::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; - typedef io::mask::BoostMaskAccessor::MaskVoxelList MaskVoxelList; + typedef masks::boost::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; + typedef masks::boost::BoostMaskAccessor::MaskVoxelList MaskVoxelList; // generate test structure set boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); boost::shared_ptr geometricPtr = boost::make_shared(spTestDoseAccessor->getGeometricInfo()); //1) test BoostMask and BoostMaskAccessor constructor - CHECK_NO_THROW( rttb::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); + CHECK_NO_THROW( rttb::masks::boost::BoostMask(geometricPtr, spMyStruct)); + rttb::masks::boost::BoostMask boostMask = rttb::masks::boost::BoostMask(geometricPtr, spMyStruct); + CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, geometricPtr)); + rttb::masks::boost::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/masks/CMakeLists.txt b/testing/masks/boost/CMakeLists.txt similarity index 59% copy from testing/masks/CMakeLists.txt copy to testing/masks/boost/CMakeLists.txt index 24b8248..48355d3 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/boost/CMakeLists.txt @@ -1,20 +1,21 @@ #----------------------------------------------------------------------------- # 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(Boost_Mask_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbBoostMaskTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- - -ADD_TEST(OTBMaskAccessorTest ${MASKS_TESTS} OTBMaskAccessorTest +ADD_TEST(BoostMaskAccessorTest ${Boost_Mask_TESTS} BoostMaskAccessorTest ) -RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBMasks PACKAGE_DEPENDS BoostBinaries Litmus DCMTK) + + +RTTB_CREATE_TEST_MODULE(rttbBoostMask DEPENDS RTTBDicomIO RTTBITKIO RTTBMasks RTTBBoostMask PACKAGE_DEPENDS Boost BoostBinaries Litmus ITK DCMTK) diff --git a/testing/io/mask/files.cmake b/testing/masks/boost/files.cmake similarity index 71% rename from testing/io/mask/files.cmake rename to testing/masks/boost/files.cmake index af41734..c401dd6 100644 --- a/testing/io/mask/files.cmake +++ b/testing/masks/boost/files.cmake @@ -1,15 +1,13 @@ SET(CPP_FILES ../../core/DummyStructure.cpp ../../core/CreateTestStructure.cpp ../../core/DummyDoseAccessor.cpp BoostMaskAccessorTest.cpp - MaskAccessorGeneratorTest.cpp - MaskAccessorConverterTest.cpp - rttbMaskIOTests.cpp - ) + rttbBoostMaskTests.cpp +) SET(H_FILES ../../core/DummyStructure.h ../../core/CreateTestStructure.h ../../core/DummyDoseAccessor.h ) diff --git a/testing/io/mask/rttbMaskIOTests.cpp b/testing/masks/boost/rttbBoostMaskTests.cpp similarity index 62% rename from testing/io/mask/rttbMaskIOTests.cpp rename to testing/masks/boost/rttbBoostMaskTests.cpp index 52e3d82..dcf6e16 100644 --- a/testing/io/mask/rttbMaskIOTests.cpp +++ b/testing/masks/boost/rttbBoostMaskTests.cpp @@ -1,60 +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: 793 $ (last changed revision) -// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) -// @author $Author: hentsch $ (last changed by) +// @version $Revision$ (last changed revision) +// @date $Date$ (last change date) +// @author $Author$ (last changed by) */ -// this file defines the rttbCoreTests for the test driver +// this file defines the rttbAlgorithmsTests 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{ +#include "litMultiTestsMain.h" + +namespace rttb +{ + namespace testing + { void registerTests() - { - LIT_REGISTER_TEST(BoostMaskAccessorTest); - LIT_REGISTER_TEST(MaskAccessorGeneratorTest); - LIT_REGISTER_TEST(MaskAccessorConverterTest); - } + { + LIT_REGISTER_TEST(BoostMaskAccessorTest); } } +} int main(int argc, char* argv[]) - { +{ int result = 0; rttb::testing::registerTests(); try - { - result = lit::multiTestsMain(argc,argv); - } - - catch(...) - { + { + result = lit::multiTestsMain(argc, argv); + } + catch (const std::exception& /*e*/) + { result = -1; - } + } + catch (...) + { + result = -1; + } return result; - } +} diff --git a/testing/masks/files.cmake b/testing/masks/files.cmake deleted file mode 100644 index fc32ea9..0000000 --- a/testing/masks/files.cmake +++ /dev/null @@ -1,17 +0,0 @@ -SET(CPP_FILES - ../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/CMakeLists.txt b/testing/masks/legacy/CMakeLists.txt similarity index 64% copy from testing/masks/CMakeLists.txt copy to testing/masks/legacy/CMakeLists.txt index 24b8248..6506f34 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/legacy/CMakeLists.txt @@ -1,20 +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(OTB_MASK_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbOTBMaskTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- -ADD_TEST(OTBMaskAccessorTest ${MASKS_TESTS} OTBMaskAccessorTest +ADD_TEST(OTBMaskAccessorTest ${OTB_MASK_TESTS} OTBMaskAccessorTest ) -RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBMasks PACKAGE_DEPENDS BoostBinaries Litmus DCMTK) +RTTB_CREATE_TEST_MODULE(rttbOTBMask DEPENDS RTTBMasks RTTBOTBMask PACKAGE_DEPENDS Litmus DCMTK) diff --git a/testing/masks/OTBMaskAccessorTest.cpp b/testing/masks/legacy/OTBMaskAccessorTest.cpp similarity index 85% rename from testing/masks/OTBMaskAccessorTest.cpp rename to testing/masks/legacy/OTBMaskAccessorTest.cpp index cc1e5c8..2edde89 100644 --- a/testing/masks/OTBMaskAccessorTest.cpp +++ b/testing/masks/legacy/OTBMaskAccessorTest.cpp @@ -1,197 +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) +// @version $Revision: 748 $ (last changed revision) +// @date $Date: 2014-09-17 12:02:48 +0200 (Mi, 17 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (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 "../../core/DummyStructure.h" +#include "../../core/DummyDoseAccessor.h" +#include "../rttbMaskVoxelListTester.h" +#include "../rttbMaskRectStructTester.h" namespace rttb { namespace testing { /*! @brief GenericMaskedDoseIteratorTest. 1) test constructors 2) test updateMask (do relevant voxels match?) 3) test valid/convert 4) test getMaskAt 5) other interface functions (simple getters) */ int OTBMaskAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::Structure::StructTypePointer StructTypePointer; - typedef masks::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; - typedef masks::OTBMaskAccessor::MaskVoxelList MaskVoxelList; + typedef masks::legacy::OTBMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; + typedef masks::legacy::OTBMaskAccessor::MaskVoxelList MaskVoxelList; // generate test structure set boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); //1) test constructors - CHECK_NO_THROW(masks::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); - masks::OTBMaskAccessor testOTB1(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + CHECK_NO_THROW(masks::legacy::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); + masks::legacy::OTBMaskAccessor testOTB1(spMyStruct, spTestDoseAccessor->getGeometricInfo()); CHECK_EQUAL(spTestDoseAccessor->getGeometricInfo(), testOTB1.getGeometricInfo()); - CHECK_NO_THROW(masks::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); - masks::OTBMaskAccessor testOTB2(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + CHECK_NO_THROW(masks::legacy::OTBMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); + masks::legacy::OTBMaskAccessor testOTB2(spMyStruct, spTestDoseAccessor->getGeometricInfo()); CHECK_EQUAL(spTestDoseAccessor->getGeometricInfo(), testOTB2.getGeometricInfo()); //2) test updateMask (do relevant voxels match?) CHECK_NO_THROW(testOTB1.updateMask()); CHECK_NO_THROW(testOTB1.getRelevantVoxelVector()); MaskVoxelListPointer relVoxelOTB1 = testOTB1.getRelevantVoxelVector(); - boost::shared_ptr spMaskAccessor = - boost::make_shared(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + boost::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/legacy/files.cmake b/testing/masks/legacy/files.cmake new file mode 100644 index 0000000..5720825 --- /dev/null +++ b/testing/masks/legacy/files.cmake @@ -0,0 +1,17 @@ +SET(CPP_FILES + ../../core/DummyStructure.cpp + ../../core/CreateTestStructure.cpp + ../../core/DummyDoseAccessor.cpp + OTBMaskAccessorTest.cpp + ../rttbMaskVoxelListTester.cpp + ../rttbMaskRectStructTester.cpp + rttbOTBMaskTests.cpp + ) + +SET(H_FILES + ../../core/DummyStructure.h + ../../core/CreateTestStructure.h + ../../core/DummyDoseAccessor.h + ../rttbMaskVoxelListTester.h + ../rttbMaskRectStructTester.h +) diff --git a/testing/io/itk/rttbITKIOTests.cpp b/testing/masks/legacy/rttbOTBMaskTests.cpp similarity index 73% copy from testing/io/itk/rttbITKIOTests.cpp copy to testing/masks/legacy/rttbOTBMaskTests.cpp index 24e286e..c865e78 100644 --- a/testing/io/itk/rttbITKIOTests.cpp +++ b/testing/masks/legacy/rttbOTBMaskTests.cpp @@ -1,60 +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 +// this file defines the rttbAlgorithmsTests 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{ +#include "litMultiTestsMain.h" + +namespace rttb +{ + namespace testing + { void registerTests() - { - LIT_REGISTER_TEST(ITKDoseAccessorGeneratorTest); - LIT_REGISTER_TEST(ITKDoseAccessorConverterTest); - LIT_REGISTER_TEST(ITKIOTest); - } + { + LIT_REGISTER_TEST(OTBMaskAccessorTest); } } +} int main(int argc, char* argv[]) - { +{ int result = 0; rttb::testing::registerTests(); try - { - result = lit::multiTestsMain(argc,argv); - } - - catch(...) - { + { + result = lit::multiTestsMain(argc, argv); + } + catch (const std::exception& /*e*/) + { result = -1; - } + } + catch (...) + { + result = -1; + } return result; - } +}