diff --git a/Modules/Core/include/mitkNodePredicateGeometry.h b/Modules/Core/include/mitkNodePredicateGeometry.h index 11fce80904..cc4f2d430f 100644 --- a/Modules/Core/include/mitkNodePredicateGeometry.h +++ b/Modules/Core/include/mitkNodePredicateGeometry.h @@ -1,59 +1,73 @@ /*=================================================================== 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 MITKNODEPREDICATEGEOMETRY_H_HEADER_INCLUDED_ #define MITKNODEPREDICATEGEOMETRY_H_HEADER_INCLUDED_ #include "mitkNodePredicateBase.h" #include "mitkBaseGeometry.h" #include "mitkTimeGeometry.h" namespace mitk { class BaseData; /**Documentation @brief Predicate that evaluates if the given DataNode's data object has the same geometry (in terms of spacing, origin, orientation) like - the reference geometry. - If no timepoint to check is defined the predicate will evaluate the geometry in - the first timestep of the data's time geometry. + the reference geometry. One can either check the whole time geometry of + the date node by defining a referenc time geometry or check against one given + reference base geometry. If the predicate should check against a base geometry, + you can specify the timepoint of the data's time geometry that should be checked. + If no timepoint is defined the predicate will evaluate the data geometry in + the first timestep. Evaluates to "false" for unsupported or undefined data objects/geometries. @ingroup DataStorage */ class MITKCORE_EXPORT NodePredicateGeometry : public NodePredicateBase { public: mitkClassMacro(NodePredicateGeometry, NodePredicateBase); + mitkNewMacro1Param(NodePredicateGeometry, const TimeGeometry*); mitkNewMacro1Param(NodePredicateGeometry, const BaseGeometry*); mitkNewMacro2Param(NodePredicateGeometry, const BaseGeometry*, TimePointType); + itkSetMacro(CheckPrecision, mitk::ScalarType); + itkGetMacro(CheckPrecision, mitk::ScalarType); + virtual ~NodePredicateGeometry(); virtual bool CheckNode(const mitk::DataNode *node) const override; protected: - NodePredicateGeometry(const BaseGeometry* refGeometry); + /**Constructor that is used configures the predicate to check against the the refernce geometry against the first data timepoint.*/ + NodePredicateGeometry(const BaseGeometry* refGeometry); /**Constructor allows to define the timepoint that should be evaluated against the reference.*/ NodePredicateGeometry(const BaseGeometry* refGeometry, TimePointType relevantTimePoint); + /**Constructor that is used configures the predicate to check against the whole time geometry.*/ + NodePredicateGeometry(const TimeGeometry* refGeometry); BaseGeometry::ConstPointer m_RefGeometry; + TimeGeometry::ConstPointer m_RefTimeGeometry; TimePointType m_TimePoint; + /**Indicates if m_TimePoint should be regarded or always the first timestep should be used.*/ bool m_UseTimePoint; + /**Precision that should be used for the equal checks.*/ + mitk::ScalarType m_CheckPrecision; }; } // namespace mitk #endif /* MITKNodePredicateGeometry_H_HEADER_INCLUDED_ */ diff --git a/Modules/Core/src/DataManagement/mitkNodePredicateGeometry.cpp b/Modules/Core/src/DataManagement/mitkNodePredicateGeometry.cpp index 06f35645e4..322e4c6b99 100644 --- a/Modules/Core/src/DataManagement/mitkNodePredicateGeometry.cpp +++ b/Modules/Core/src/DataManagement/mitkNodePredicateGeometry.cpp @@ -1,56 +1,71 @@ /*=================================================================== 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 "mitkNodePredicateGeometry.h" #include "mitkDataNode.h" #include "mitkImage.h" mitk::NodePredicateGeometry::NodePredicateGeometry(const BaseGeometry* refGeometry, TimePointType relevantTimePoint) - : m_RefGeometry(refGeometry), m_TimePoint(relevantTimePoint), m_UseTimePoint(true) + : m_RefGeometry(refGeometry), m_RefTimeGeometry(nullptr), m_TimePoint(relevantTimePoint), m_UseTimePoint(true), m_CheckPrecision(mitk::eps) { + if (m_RefGeometry.IsNull()) mitkThrow() << "Invalid constructor initialization. Reference base geometry instance is NULL pointer."; } mitk::NodePredicateGeometry::NodePredicateGeometry(const BaseGeometry* refGeometry) - : m_RefGeometry(refGeometry), m_TimePoint(0), m_UseTimePoint(false) + : m_RefGeometry(refGeometry), m_RefTimeGeometry(nullptr), m_TimePoint(0), m_UseTimePoint(false), m_CheckPrecision(mitk::eps) { + if (m_RefGeometry.IsNull()) mitkThrow() << "Invalid constructor initialization. Reference base geometry instance is NULL pointer."; +} + +mitk::NodePredicateGeometry::NodePredicateGeometry(const TimeGeometry* refGeometry) + : m_RefGeometry(nullptr), m_RefTimeGeometry(refGeometry), m_TimePoint(0), m_UseTimePoint(false), m_CheckPrecision(mitk::eps) +{ + if (m_RefTimeGeometry.IsNull()) mitkThrow() << "Invalid constructor initialization. Reference base geometry instance is NULL pointer."; } mitk::NodePredicateGeometry::~NodePredicateGeometry() { } bool mitk::NodePredicateGeometry::CheckNode(const mitk::DataNode *node) const { if (node == nullptr) - throw std::invalid_argument("NodePredicateGeometry: invalid node"); + mitkThrow() << "NodePredicateGeometry: invalid node"; mitk::BaseData *data = node->GetData(); - if (node->GetData()) + if (data) { - mitk::BaseGeometry::Pointer testGeometry = node->GetData()->GetGeometry(); - if (this->m_UseTimePoint) - { - testGeometry = node->GetData()->GetTimeGeometry()->GetGeometryForTimePoint(m_TimePoint); - } + if (m_RefGeometry.IsNotNull()) + { //check only one time point. + mitk::BaseGeometry::Pointer testGeometry = data->GetGeometry(); + if (this->m_UseTimePoint) + { + testGeometry = data->GetTimeGeometry()->GetGeometryForTimePoint(m_TimePoint); + } - if (testGeometry) - { - return Equal(*testGeometry, *m_RefGeometry, 1e-5, false); + if (testGeometry) + { + return Equal(*testGeometry, *m_RefGeometry, this->m_CheckPrecision, false); + } + } + else + { //check whole time geometry + return Equal(*data->GetTimeGeometry(), *m_RefTimeGeometry, this->m_CheckPrecision, false); } } return false; } diff --git a/Modules/Core/test/mitkNodePredicateGeometryTest.cpp b/Modules/Core/test/mitkNodePredicateGeometryTest.cpp index 7d06c784d4..dc90682e10 100644 --- a/Modules/Core/test/mitkNodePredicateGeometryTest.cpp +++ b/Modules/Core/test/mitkNodePredicateGeometryTest.cpp @@ -1,144 +1,192 @@ /*=================================================================== 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 "mitkGeometry3D.h" #include "mitkBaseDataTestImplementation.h" #include "mitkNodePredicateGeometry.h" #include "mitkDataNode.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" +#include "mitkProportionalTimeGeometry.h" class mitkNodePredicateGeometryTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkNodePredicateGeometryTestSuite); + MITK_TEST(Check_InvalidConstructor); MITK_TEST(Check_CloneAndOriginal); MITK_TEST(Check_DifferentOrigin); MITK_TEST(Check_DifferentIndexToWorldTransform); MITK_TEST(Check_DifferentSpacing); MITK_TEST(Check_DifferentBoundingBox); CPPUNIT_TEST_SUITE_END(); private: mitk::BaseDataTestImplementation::Pointer m_Data; mitk::DataNode::Pointer m_Node; mitk::Geometry3D::Pointer m_RefGeometry; + mitk::TimeGeometry::Pointer m_RefTimeGeometry; + mitk::Geometry3D::Pointer m_AnotherGeometry3D; public: /** * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used members * for a new test case. (If the members are not used in a test, the method does not need to be called). */ void setUp() override { m_RefGeometry = mitk::Geometry3D::New(); m_RefGeometry->Initialize(); + mitk::ProportionalTimeGeometry::Pointer tgeo = mitk::ProportionalTimeGeometry::New(); + tgeo->Initialize(m_RefGeometry, 1); + + m_RefTimeGeometry = tgeo.GetPointer(); + m_Data = mitk::BaseDataTestImplementation::New(); m_Data->SetClonedGeometry(m_RefGeometry); m_Node = mitk::DataNode::New(); m_Node->SetData(m_Data); m_AnotherGeometry3D = m_RefGeometry->Clone(); } void tearDown() override { m_RefGeometry = nullptr; + m_RefTimeGeometry = nullptr; m_AnotherGeometry3D = nullptr; m_Data = nullptr; } + void Check_InvalidConstructor() + { + m_RefGeometry = nullptr; + m_RefTimeGeometry = nullptr; + CPPUNIT_ASSERT_THROW(mitk::NodePredicateGeometry::New(m_RefGeometry, 3), mitk::Exception); + CPPUNIT_ASSERT_THROW(mitk::NodePredicateGeometry::New(m_RefGeometry), mitk::Exception); + CPPUNIT_ASSERT_THROW(mitk::NodePredicateGeometry::New(m_RefTimeGeometry), mitk::Exception); + } + void Check_CloneAndOriginal() { mitk::NodePredicateGeometry::Pointer predicate = mitk::NodePredicateGeometry::New(m_RefGeometry); + mitk::NodePredicateGeometry::Pointer predicateTime = mitk::NodePredicateGeometry::New(m_RefTimeGeometry); + CPPUNIT_ASSERT(predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(predicateTime->CheckNode(m_Node)); } void Check_DifferentOrigin() { mitk::NodePredicateGeometry::Pointer predicate = mitk::NodePredicateGeometry::New(m_RefGeometry); + mitk::NodePredicateGeometry::Pointer predicateTime = mitk::NodePredicateGeometry::New(m_RefTimeGeometry); mitk::Point3D origin; origin[0] = 0.0; origin[1] = 0.0; origin[2] = 1.0; m_AnotherGeometry3D->SetOrigin(origin); m_Data->SetClonedGeometry(m_AnotherGeometry3D); CPPUNIT_ASSERT(!predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(!predicateTime->CheckNode(m_Node)); predicate = mitk::NodePredicateGeometry::New(m_AnotherGeometry3D); CPPUNIT_ASSERT(predicate->CheckNode(m_Node)); } void Check_DifferentIndexToWorldTransform() { mitk::NodePredicateGeometry::Pointer predicate = mitk::NodePredicateGeometry::New(m_RefGeometry); + mitk::NodePredicateGeometry::Pointer predicateTime = mitk::NodePredicateGeometry::New(m_RefTimeGeometry); mitk::AffineTransform3D::Pointer differentIndexToWorldTransform = mitk::AffineTransform3D::New(); mitk::AffineTransform3D::MatrixType differentMatrix; differentMatrix.SetIdentity(); differentMatrix(1, 1) = 2; differentIndexToWorldTransform->SetMatrix(differentMatrix); m_AnotherGeometry3D->SetIndexToWorldTransform(differentIndexToWorldTransform); m_Data->SetClonedGeometry(m_AnotherGeometry3D); CPPUNIT_ASSERT(!predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(!predicateTime->CheckNode(m_Node)); predicate = mitk::NodePredicateGeometry::New(m_AnotherGeometry3D); CPPUNIT_ASSERT(predicate->CheckNode(m_Node)); } void Check_DifferentSpacing() { mitk::NodePredicateGeometry::Pointer predicate = mitk::NodePredicateGeometry::New(m_RefGeometry); + mitk::NodePredicateGeometry::Pointer predicateTime = mitk::NodePredicateGeometry::New(m_RefTimeGeometry); mitk::Vector3D differentSpacing; differentSpacing[0] = 1.0; differentSpacing[1] = 2.0; - differentSpacing[2] = 3.0; + differentSpacing[2] = 3.0+3*mitk::eps; m_AnotherGeometry3D->SetSpacing(differentSpacing); m_Data->SetClonedGeometry(m_AnotherGeometry3D); CPPUNIT_ASSERT(!predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(!predicateTime->CheckNode(m_Node)); + + //check with altered geometry as reference (sanity check). + mitk::NodePredicateGeometry::Pointer predicate2 = mitk::NodePredicateGeometry::New(m_AnotherGeometry3D); + CPPUNIT_ASSERT(predicate2->CheckNode(m_Node)); + + //check less strict precission checkings + differentSpacing[0] = 1.0; + differentSpacing[1] = 1.0; + differentSpacing[2] = 1.0 + 3 * mitk::eps; + + m_AnotherGeometry3D->SetSpacing(differentSpacing); + m_Data->SetClonedGeometry(m_AnotherGeometry3D); + + CPPUNIT_ASSERT(!predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(!predicateTime->CheckNode(m_Node)); + + predicate->SetCheckPrecision(1e-3); + predicateTime->SetCheckPrecision(1e-3); - predicate = mitk::NodePredicateGeometry::New(m_AnotherGeometry3D); CPPUNIT_ASSERT(predicate->CheckNode(m_Node)); + CPPUNIT_ASSERT(predicateTime->CheckNode(m_Node)); } void Check_DifferentBoundingBox() { mitk::NodePredicateGeometry::Pointer predicate = mitk::NodePredicateGeometry::New(m_RefGeometry); + mitk::NodePredicateGeometry::Pointer predicateTime = mitk::NodePredicateGeometry::New(m_RefTimeGeometry); mitk::ScalarType bounds[] = { 0.0, 0.0, 0.0, 1.0, 2.0, 3.0 }; m_AnotherGeometry3D->SetBounds(bounds); m_Data->SetClonedGeometry(m_AnotherGeometry3D); CPPUNIT_ASSERT(!predicate->CheckNode(m_Node)); - + CPPUNIT_ASSERT(!predicateTime->CheckNode(m_Node)); + predicate = mitk::NodePredicateGeometry::New(m_AnotherGeometry3D); CPPUNIT_ASSERT(predicate->CheckNode(m_Node)); } }; MITK_TEST_SUITE_REGISTRATION(mitkNodePredicateGeometry)