diff --git a/Core/Code/DataManagement/mitkSurface.cpp b/Core/Code/DataManagement/mitkSurface.cpp index 81dfb66e43..b7d5e51c13 100644 --- a/Core/Code/DataManagement/mitkSurface.cpp +++ b/Core/Code/DataManagement/mitkSurface.cpp @@ -1,386 +1,485 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSurface.h" #include "mitkInteractionConst.h" #include "mitkSurfaceOperation.h" #include #include static vtkPolyData* DeepCopy(vtkPolyData* other) { if (other == NULL) return NULL; vtkPolyData* copy = vtkPolyData::New(); copy->DeepCopy(other); return copy; } static void Delete(vtkPolyData* polyData) { if (polyData != NULL) polyData->Delete(); } static void Update(vtkPolyData* polyData) { if (polyData != NULL) polyData->Update(); } mitk::Surface::Surface() : m_CalculateBoundingBox(false) { this->InitializeEmpty(); } mitk::Surface::Surface(const mitk::Surface& other) : BaseData(other), m_LargestPossibleRegion(other.m_LargestPossibleRegion), m_RequestedRegion(other.m_RequestedRegion), m_CalculateBoundingBox(other.m_CalculateBoundingBox) { if(!other.m_PolyDatas.empty()) { m_PolyDatas.resize(other.m_PolyDatas.size()); std::transform(other.m_PolyDatas.begin(), other.m_PolyDatas.end(), m_PolyDatas.begin(), DeepCopy); } else { this->InitializeEmpty(); } } void mitk::Surface::Swap(mitk::Surface& other) { std::swap(m_PolyDatas, other.m_PolyDatas); std::swap(m_LargestPossibleRegion, other.m_LargestPossibleRegion); std::swap(m_RequestedRegion, other.m_RequestedRegion); std::swap(m_CalculateBoundingBox, other.m_CalculateBoundingBox); } mitk::Surface& mitk::Surface::operator=(Surface other) { this->Swap(other); return *this; } mitk::Surface::~Surface() { this->ClearData(); } void mitk::Surface::ClearData() { using ::Delete; std::for_each(m_PolyDatas.begin(), m_PolyDatas.end(), Delete); m_PolyDatas.clear(); Superclass::ClearData(); } const mitk::Surface::RegionType& mitk::Surface::GetLargestPossibleRegion() const { m_LargestPossibleRegion.SetIndex(3, 0); m_LargestPossibleRegion.SetSize(3, GetTimeSlicedGeometry()->GetTimeSteps()); return m_LargestPossibleRegion; } const mitk::Surface::RegionType& mitk::Surface::GetRequestedRegion() const { return m_RequestedRegion; } void mitk::Surface::InitializeEmpty() { if (!m_PolyDatas.empty()) this->ClearData(); Superclass::InitializeTimeSlicedGeometry(); m_PolyDatas.push_back(NULL); m_Initialized = true; } void mitk::Surface::SetVtkPolyData(vtkPolyData* polyData, unsigned int t) { this->Expand(t + 1); if (m_PolyDatas[t] != NULL) { if (m_PolyDatas[t] == polyData) return; m_PolyDatas[t]->Delete(); } m_PolyDatas[t] = polyData; if(polyData != NULL) polyData->Register(NULL); m_CalculateBoundingBox = true; this->Modified(); this->UpdateOutputInformation(); } bool mitk::Surface::IsEmptyTimeStep(unsigned int t) const { if(!IsInitialized()) return false; vtkPolyData* polyData = const_cast(this)->GetVtkPolyData(t); return polyData == NULL || ( polyData->GetNumberOfLines() == 0 && polyData->GetNumberOfPolys() == 0 && polyData->GetNumberOfStrips() == 0 && polyData->GetNumberOfVerts() == 0 ); } vtkPolyData* mitk::Surface::GetVtkPolyData(unsigned int t) { if (t < m_PolyDatas.size()) { if(m_PolyDatas[t] == NULL && this->GetSource().IsNotNull()) { RegionType requestedRegion; requestedRegion.SetIndex(3, t); requestedRegion.SetSize(3, 1); this->SetRequestedRegion(&requestedRegion); this->GetSource()->Update(); } return m_PolyDatas[t]; } return NULL; } void mitk::Surface::UpdateOutputInformation() { if (this->GetSource().IsNotNull()) this->GetSource()->UpdateOutputInformation(); if (m_CalculateBoundingBox == true && !m_PolyDatas.empty()) this->CalculateBoundingBox(); else this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::Surface::CalculateBoundingBox() { mitk::TimeSlicedGeometry* timeSlicedGeometry = this->GetTimeSlicedGeometry(); if (timeSlicedGeometry->GetTimeSteps() != m_PolyDatas.size()) mitkThrow() << "Number of geometry time steps is inconsistent with number of poly data pointers."; for (unsigned int i = 0; i < m_PolyDatas.size(); ++i) { vtkPolyData* polyData = m_PolyDatas[i]; vtkFloatingPointType bounds[6] = {0}; if (polyData != NULL && polyData->GetNumberOfPoints() > 0) { polyData->Update(); polyData->ComputeBounds(); polyData->GetBounds(bounds); } mitk::Geometry3D::Pointer geometry = timeSlicedGeometry->GetGeometry3D(i); if (geometry.IsNull()) mitkThrow() << "Time-sliced geometry is invalid (equals NULL)."; geometry->SetFloatBounds(bounds); } timeSlicedGeometry->UpdateInformation(); m_CalculateBoundingBox = false; } void mitk::Surface::SetRequestedRegionToLargestPossibleRegion() { m_RequestedRegion = GetLargestPossibleRegion(); } bool mitk::Surface::RequestedRegionIsOutsideOfTheBufferedRegion() { RegionType::IndexValueType end = m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3); if(static_cast(m_PolyDatas.size()) < end) return true; for(RegionType::IndexValueType t = m_RequestedRegion.GetIndex(3); t < end; ++t) { if(m_PolyDatas[t] == NULL) return true; } return false; } bool mitk::Surface::VerifyRequestedRegion() { if(m_RequestedRegion.GetIndex(3) >= 0 && m_RequestedRegion.GetIndex(3) + m_RequestedRegion.GetSize(3) <= m_PolyDatas.size()) return true; return false; } void mitk::Surface::SetRequestedRegion(const itk::DataObject* data ) { const mitk::Surface *surface = dynamic_cast(data); if (surface != NULL) m_RequestedRegion = surface->GetRequestedRegion(); else mitkThrow() << "Data object used to get requested region is not a mitk::Surface."; } void mitk::Surface::SetRequestedRegion(Surface::RegionType* region) { if (region == NULL) mitkThrow() << "Requested region is invalid (equals NULL)"; m_RequestedRegion = *region; } void mitk::Surface::CopyInformation(const itk::DataObject* data) { Superclass::CopyInformation(data); const mitk::Surface* surface = dynamic_cast(data); if (surface == NULL) mitkThrow() << "Data object used to get largest possible region is not a mitk::Surface."; m_LargestPossibleRegion = surface->GetLargestPossibleRegion(); } void mitk::Surface::Update() { using ::Update; if (this->GetSource().IsNull()) std::for_each(m_PolyDatas.begin(), m_PolyDatas.end(), Update); Superclass::Update(); } void mitk::Surface::Expand(unsigned int timeSteps) { if (timeSteps > m_PolyDatas.size()) { Superclass::Expand(timeSteps); m_PolyDatas.resize(timeSteps); m_CalculateBoundingBox = true; } } void mitk::Surface::ExecuteOperation(Operation* operation) { switch (operation->GetOperationType()) { case OpSURFACECHANGED: { mitk::SurfaceOperation* surfaceOperation = dynamic_cast(operation); if(surfaceOperation == NULL) break; unsigned int timeStep = surfaceOperation->GetTimeStep(); if(m_PolyDatas[timeStep] != NULL) { vtkPolyData* updatedPolyData = surfaceOperation->GetVtkPolyData(); if(updatedPolyData != NULL) { this->SetVtkPolyData(updatedPolyData, timeStep); this->CalculateBoundingBox(); this->Modified(); } } break; } default: return; } } unsigned int mitk::Surface::GetSizeOfPolyDataSeries() const { return m_PolyDatas.size(); } void mitk::Surface::Graft(const DataObject* data) { const Surface* surface = dynamic_cast(data); if(surface == NULL) mitkThrow() << "Data object used to graft surface is not a mitk::Surface."; this->CopyInformation(data); m_PolyDatas.clear(); for (unsigned int i = 0; i < surface->GetSizeOfPolyDataSeries(); ++i) { m_PolyDatas.push_back(vtkPolyData::New()); m_PolyDatas.back()->DeepCopy(const_cast(surface)->GetVtkPolyData(i)); } } void mitk::Surface::PrintSelf(std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "\nNumber PolyDatas: " << m_PolyDatas.size() << "\n"; unsigned int count = 0; for (std::vector::const_iterator it = m_PolyDatas.begin(); it != m_PolyDatas.end(); ++it) { os << "\n"; if(*it != NULL) { os << indent << "PolyData at time step " << count << ":\n"; os << indent << "Number of cells: " << (*it)->GetNumberOfCells() << "\n"; os << indent << "Number of points: " << (*it)->GetNumberOfPoints() << "\n\n"; os << indent << "VTKPolyData:\n"; (*it)->Print(os); } else { os << indent << "Empty PolyData at time step " << count << "\n"; } ++count; } } + +bool Equal( const mitk::Surface* rightHandSide, const mitk::Surface* leftHandSide, ScalarType eps ) +{ + bool noDifferenceFound = true; + + + if( rightHandSide == NULL ) + { + MITK_INFO << "[Equal( mitk::surface*, mitk::surface* )] rightHandSide NULL."; + return false; + } + + if( leftHandSide == NULL ) + { + MITK_INFO << "[Equal( mitk::surface*, mitk::surface* )] leftHandSide NULL."; + return false; + } + + MITK_INFO << "Checking size of PolyData series for equality"; + if( !mitk:::Equal( rightHandSide->GetSizeOfPolyDataSeries(), leftHandSide->GetSizeOfPolyDataSeries(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking time sliced geometries for equality"; + if( !mitk:::Equal( rightHandSide->GetTimeSlicedGeometry(), leftHandSide->GetTimeSlicedGeometry(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking largest possible region for equality"; + if( !mitk:::Equal( rightHandSide->GetLargestPossibleRegion(), leftHandSide->GetLargestPossibleRegion(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking poly datas for equality"; + for( unsigned int i( 0 ); i < rightHandSide->GetSizeOfPolyDataSeries(); i++ ) + { + if( !mitk:::Equal( rightHandSide->GetVtkPolyData( i ), leftHandSide->GetVtkPolyData( i ), eps ) ) + { + noDifferenceFound = false; + } + } + + return noDifferenceFound; +} + +bool Equal( const vtkPolyData* rightHandSide, const vtkPolyData* leftHandSide, ScalarType eps = mitk::eps) +{ + bool noDifferenceFound = true; + + + if( rightHandSide == NULL ) + { + MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] rightHandSide NULL."; + return false; + } + + if( leftHandSide == NULL ) + { + MITK_INFO << "[Equal( vtkPolyData*, vtkPolyData* )] leftHandSide NULL."; + return false; + } + + MITK_INFO << "Checking number of cells for equality"; + if( !mitk:::Equal( rightHandSide->GetNumberOfCells(), leftHandSide->GetNumberOfCells(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking number of vertices for equality"; + if( !mitk:::Equal( rightHandSide->GetNumberOfVerts(), leftHandSide->GetNumberOfVerts(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking number of lines for equality"; + if( !mitk:::Equal( rightHandSide->GetNumberOfLines(), leftHandSide->GetNumberOfLines(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking number of polys for equality"; + if( !mitk:::Equal( rightHandSide->GetNumberOfPolys(), leftHandSide->GetNumberOfPolys(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking number of strips for equality"; + if( !mitk:::Equal( rightHandSide->GetNumberOfStrips(), leftHandSide->GetNumberOfStrips(), eps ) ) + { + noDifferenceFound = false; + } + + MITK_INFO << "Checking whether all coordinates are present"; + + return noDifferenceFound; +} diff --git a/Core/Code/DataManagement/mitkSurface.h b/Core/Code/DataManagement/mitkSurface.h index 8c406d34e6..b2ea1d50ce 100644 --- a/Core/Code/DataManagement/mitkSurface.h +++ b/Core/Code/DataManagement/mitkSurface.h @@ -1,79 +1,96 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSurface_h #define mitkSurface_h #include "mitkBaseData.h" #include "itkImageRegion.h" class vtkPolyData; namespace mitk { /** * \brief Class for storing surfaces (vtkPolyData). * \ingroup Data */ class MITK_CORE_EXPORT Surface : public BaseData { public: typedef itk::ImageRegion<5> RegionType; mitkClassMacro(Surface, BaseData); itkNewMacro(Self); mitkCloneMacro(Surface); void CalculateBoundingBox(); virtual void CopyInformation(const itk::DataObject *data); virtual void ExecuteOperation(Operation *operation); virtual void Expand( unsigned int timeSteps = 1 ); const RegionType& GetLargestPossibleRegion() const; virtual const RegionType& GetRequestedRegion() const; unsigned int GetSizeOfPolyDataSeries() const; virtual vtkPolyData* GetVtkPolyData(unsigned int t = 0); virtual void Graft( const DataObject* data ); virtual bool IsEmptyTimeStep(unsigned int t) const; virtual void PrintSelf( std::ostream& os, itk::Indent indent ) const; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion(); virtual void SetRequestedRegion(const itk::DataObject *data); virtual void SetRequestedRegion(Surface::RegionType *region); virtual void SetRequestedRegionToLargestPossibleRegion(); virtual void SetVtkPolyData(vtkPolyData* polydata, unsigned int t = 0); virtual void Swap(Surface& other); virtual void Update(); virtual void UpdateOutputInformation(); virtual bool VerifyRequestedRegion(); + protected: Surface(); virtual ~Surface(); Surface(const Surface& other); Surface& operator=(Surface other); virtual void ClearData(); virtual void InitializeEmpty(); private: std::vector m_PolyDatas; mutable RegionType m_LargestPossibleRegion; RegionType m_RequestedRegion; bool m_CalculateBoundingBox; }; + + /** + * \brief Compare two surfaces for equality, returns true if found equal + * + */ + bool Equal( const mitk::Surface* rightHandSide, const mitk::Surface* leftHandSide, ScalarType eps = mitk::eps); + + /** + * \brief Compare two vtk PolyDatas for equality, returns true if found equal + * + * This will only check if the number of cells, vertices, polygons, stripes and lines is the same and whether + * all the two poly datas have the same number of points with the same coordinates. It is not checked whether + * all points are correctly connected. + */ + bool Equal( const vtkPolyData* rightHandSide, const vtkPolyData* leftHandSide, ScalarType eps = mitk::eps); + } #endif diff --git a/Core/Code/Testing/files.cmake b/Core/Code/Testing/files.cmake index d7ee12d316..d48116311c 100644 --- a/Core/Code/Testing/files.cmake +++ b/Core/Code/Testing/files.cmake @@ -1,159 +1,160 @@ # tests with no extra command line parameter set(MODULE_TESTS mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkEventTest.cpp mitkFocusManagerTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometry3DEqualTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkGlobalInteractionTest.cpp mitkImageEqualTest.cpp mitkImageDataItemTest.cpp #mitkImageMapper2DTest.cpp mitkImageGeneratorTest.cpp mitkBaseDataTest.cpp #mitkImageToItkTest.cpp mitkImportItkImageTest.cpp mitkGrabItkImageMemoryTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkInteractorTest.cpp #mitkITKThreadingTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp #mitkPipelineSmartPointerCorrectnessTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetEqualTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetTest.cpp mitkPointSetWriterTest.cpp mitkPointSetReaderTest.cpp mitkPointSetInteractorTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp #mitkRegistrationBaseTest.cpp #mitkSegmentationInterpolationTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkStateMachineTest.cpp ##mitkStateMachineContainerTest.cpp ## rewrite test, indirect since no longer exported Bug 14529 mitkStateTest.cpp mitkSurfaceTest.cpp + mitkSurfaceEqualTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeSlicedGeometryTest.cpp mitkTransitionTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp #mitkAbstractTransformGeometryTest.cpp mitkStepperTest.cpp itkTotalVariationDenoisingImageFilterTest.cpp mitkRenderingManagerTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp mitkShaderRepositoryTest.cpp mitkPlanePositionManagerTest.cpp mitkAffineTransformBaseTest.cpp mitkPropertyAliasesTest.cpp mitkPropertyDescriptionsTest.cpp mitkPropertyExtensionsTest.cpp mitkPropertyFiltersTest.cpp ) # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkImageTimeSelectorTest.cpp #only runs on images mitkImageAccessorTest.cpp #only runs on images mitkDataNodeFactoryTest.cpp #runs on all types of data ) set(MODULE_SURFACE_TESTS mitkSurfaceVtkWriterTest.cpp #only runs on surfaces mitkDataNodeFactoryTest.cpp #runs on all types of data ) # list of images for which the tests are run set(MODULE_TESTIMAGES US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) set(MODULE_TESTSURFACES binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS #mitkLabeledImageToSurfaceFilterTest.cpp #mitkExternalToolsTest.cpp mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkDicomSeriesReaderTest.cpp mitkDICOMLocaleTest.cpp mitkEventMapperTest.cpp mitkEventConfigTest.cpp mitkNodeDependentPointSetInteractorTest.cpp mitkStateMachineFactoryTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageWriterTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DResliceInterpolationPropertyTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkImageVtkMapper2DTransferFunctionTest.cpp mitkIOUtilTest.cpp mitkSurfaceVtkMapper3DTest mitkSurfaceVtkMapper3DTexturedSphereTest.cpp mitkSurfaceGLMapper2DColorTest.cpp mitkSurfaceGLMapper2DOpacityTest.cpp mitkVolumeCalculatorTest.cpp mitkLevelWindowManagerTest.cpp mitkPointSetVtkMapper2DTest.cpp mitkPointSetVtkMapper2DImageTest.cpp mitkPointSetVtkMapper2DGlyphTypeTest.cpp ) set(MODULE_RESOURCE_FILES Interactions/AddAndRemovePoints.xml Interactions/globalConfig.xml Interactions/StatemachineTest.xml Interactions/StatemachineConfigTest.xml ) # Create an artificial module initializing class for # the usServiceListenerTest.cpp usFunctionGenerateExecutableInit(testdriver_init_file IDENTIFIER ${MODULE_NAME}TestDriver ) # Embed the resources set(testdriver_resources ) usFunctionEmbedResources(testdriver_resources EXECUTABLE_NAME ${MODULE_NAME}TestDriver ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Resources FILES ${MODULE_RESOURCE_FILES} ) set(TEST_CPP_FILES ${testdriver_init_file} ${testdriver_resources}) diff --git a/Core/Code/Testing/mitkSurfaceEqualTest.cpp b/Core/Code/Testing/mitkSurfaceEqualTest.cpp new file mode 100644 index 0000000000..627226598d --- /dev/null +++ b/Core/Code/Testing/mitkSurfaceEqualTest.cpp @@ -0,0 +1,33 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkSurface.h" +#include "mitkTestingMacros.h" + + +/** + * @brief mitkSurfaceEqualTest A test class for Equal methods in mitk::Surface. + */ +int mitkSurfaceEqualTest(int /*argc*/, char* /*argv*/[]) +{ + MITK_TEST_BEGIN(mitkSurfaceEqualTest); + + // Needs to be implemented + + MITK_TEST_END(); + + return EXIT_SUCCESS; +}