Page MenuHomePhabricator

bug-8506-unittest-smooth-polygon_NEW.patch

Authored By
holfter
Jul 14 2011, 4:48 PM
Size
36 KB
Referenced Files
None
Subscribers
None

bug-8506-unittest-smooth-polygon_NEW.patch

From a87b2d82e52bb3454cc514b339a07eb12d8e1f0b Mon Sep 17 00:00:00 2001
From: Adrian Holfter <adrian@adrian-laptop.(none)>
Date: Mon, 11 Jul 2011 14:04:51 +0200
Subject: [PATCH 1/3] Implemented new class PlanarSubdivisionPolygon.
---
.../DataManagement/mitkPlanarFigure.cpp | 2 +-
.../DataManagement/mitkPlanarPolygon.cpp | 1 +
.../mitkPlanarSubdivisionPolygon.cpp | 297 ++++++++++++++++++++
.../DataManagement/mitkPlanarSubdivisionPolygon.h | 97 +++++++
Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp | 5 +
Modules/PlanarFigure/files.cmake | 1 +
6 files changed, 402 insertions(+), 1 deletions(-)
create mode 100644 Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
create mode 100644 Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
index d06f759..6ffec6e 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp
@@ -619,7 +619,7 @@ void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure)
//Notice to get typeid polymorph you have to use the *operator
if(typeid(*oldFigure) != typeid(*this))
{
- itkExceptionMacro( << "DeepCopy(): Inconsistent type of source and destination figure!" );
+ itkExceptionMacro( << "DeepCopy(): Inconsistent type of source (" << typeid(*oldFigure).name() << ") and destination figure (" << typeid(*this).name() << ")!" );
return;
}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
index bd0d945..7bf3c61 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp
@@ -34,6 +34,7 @@ mitk::PlanarPolygon::PlanarPolygon()
// Polygon is closed by default
this->SetProperty( "closed", mitk::BoolProperty::New( true ) );
+ this->SetProperty( "subdivision", mitk::BoolProperty::New( false ) );
}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
new file mode 100644
index 0000000..cd72df8
--- /dev/null
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
@@ -0,0 +1,297 @@
+/*=========================================================================
+
+Program: Medical Imaging & Interaction Toolkit
+Language: C++
+Date: $Date$
+Version: $Revision: 18029 $
+
+Copyright (c) German Cancer Research Center, Division of Medical and
+Biological Informatics. All rights reserved.
+See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.
+
+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.
+
+=========================================================================*/
+
+
+#include "mitkPlanarSubdivisionPolygon.h"
+#include "mitkGeometry2D.h"
+#include "mitkProperties.h"
+
+// stl related includes
+#include <algorithm>
+
+mitk::PlanarSubdivisionPolygon::PlanarSubdivisionPolygon()
+: FEATURE_ID_CIRCUMFERENCE( this->AddFeature( "Circumference", "mm" ) ),
+ FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) )
+{
+ // Polygon has at least two control points
+ this->ResetNumberOfControlPoints( 2 );
+ this->SetNumberOfPolyLines( 1 );
+
+ // Polygon is closed by default
+ this->SetProperty( "closed", mitk::BoolProperty::New( true ) );
+ this->SetProperty( "subdivision", mitk::BoolProperty::New( true ) );
+}
+
+
+mitk::PlanarSubdivisionPolygon::~PlanarSubdivisionPolygon()
+{
+}
+
+void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
+{
+ this->ClearPolyLines();
+ ControlPointListType m_SubdivisionPoints = m_ControlPoints;
+
+ // Later, we have to know which points are control points
+ ControlPointListType m_ControlPointsCopy = m_ControlPoints;
+
+ if( m_ControlPoints.size() >= GetMinimumNumberOfControlPoints() ){
+
+ for( unsigned int i=0; i < GetSubdivisionRounds(); i++ )
+ {
+ // Indices
+ unsigned int p_here, p_prev, p_next, p_nextnext;
+
+ // Just in case the poly isn't closed. It should be, but who knows...
+ if(this->IsClosed())
+ {
+ p_here = 0;
+ p_prev = m_SubdivisionPoints.size() - 1;
+ p_next = 1;
+ p_nextnext = 2;
+ }else{
+ p_prev = 0;
+ p_here = 1;
+ p_next = 2;
+ p_nextnext = 3;
+ }
+
+ double distanceToSubPoint;
+ double distanceToPointLeft;
+ double distanceToPointRight;
+
+ Point2D newPoint;
+
+ while(true)
+ {
+ // Get distance to neighbors
+ distanceToSubPoint = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[p_next]);
+
+ // Only calculate distance to control points if we are the "major" / last control point being dragged around
+ if (p_here == m_SubdivisionPoints.size() - 1)
+ {
+ unsigned int prev = 0;
+ unsigned int next = ( m_SubdivisionPoints.size() > 1 ? p_here - 1 : 0 );
+ distanceToPointLeft = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[0]);
+ distanceToPointRight = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[p_here - 1]);
+ }
+
+ // distance to next subPoint has to be > 2
+ // distance from main control point has to be > 20
+ if( distanceToSubPoint > 2.0 && ( p_here != m_SubdivisionPoints.size() || distanceToPointRight > 20 && distanceToPointLeft > 20 ))
+ {
+ double x,y;
+
+ x = (0.5 + GetTensionParameter()) * (double)( m_SubdivisionPoints[p_here][0] + m_SubdivisionPoints[p_next][0] )
+ - GetTensionParameter() * (double)( m_SubdivisionPoints[p_prev][0] + m_SubdivisionPoints[p_nextnext][0]);
+ y = (0.5 + GetTensionParameter()) * (double)( m_SubdivisionPoints[p_here][1] + m_SubdivisionPoints[p_next][1] )
+ - GetTensionParameter() * (double)( m_SubdivisionPoints[p_prev][1] + m_SubdivisionPoints[p_nextnext][1]);
+
+ newPoint[0] = x;
+ newPoint[1] = y;
+
+ m_SubdivisionPoints.insert(m_SubdivisionPoints.begin() + p_next, newPoint);
+
+ // The new point gets inserted between p_here and p_next, so our array indices are outdated -> advance them
+ p_here++;
+ p_next++;
+ p_nextnext++;
+ }
+
+ // Advance array indices and wrap around at the end
+ p_prev = p_here;
+
+ if(p_here >= (m_SubdivisionPoints.size() -1 ))
+ {
+ p_here = 0;
+ break;
+ }
+ else
+ {
+ p_here += 1;
+ }
+
+ if((p_next >= m_SubdivisionPoints.size() - 1))
+ {
+ p_next = 0;
+ }
+ else
+ {
+ p_next += 1;
+ }
+
+ if((p_nextnext >= m_SubdivisionPoints.size() - 1 ))
+ {
+ p_nextnext = 0;
+ if(!this->IsClosed()){
+ break;
+ }
+ }
+ else
+ {
+ p_nextnext += 1;
+ }
+
+ }
+ }
+ }
+
+
+ int lastControlPoint = m_SubdivisionPoints.size() - 1;
+ for ( unsigned int i=0; i<m_SubdivisionPoints.size(); ++i )
+ {
+ Point2D pnt = m_SubdivisionPoints[i];
+ for ( unsigned int j=0; j<m_ControlPointsCopy.size(); j++ )
+ {
+ if( pnt == m_ControlPointsCopy[j])
+ {
+ // It's j+1 because the insert() method of a vector inserts the new entry BEHIND the current one with index i
+ lastControlPoint = j+1;
+ }
+ }
+ PolyLineElement elem(pnt, lastControlPoint);
+ this->AppendPointToPolyLine( 0, elem );
+ }
+}
+
+void mitk::PlanarSubdivisionPolygon::EvaluateFeaturesInternal()
+{
+ // Calculate circumference
+ double circumference = 0.0;
+ unsigned int i,j;
+
+ ControlPointListType m_SubdivisionPoints;
+ m_SubdivisionPoints.clear();
+ PolyLineType::iterator iter;
+ for( iter = m_PolyLines[0].begin(); iter != m_PolyLines[0].end(); ++iter )
+ {
+ m_SubdivisionPoints.push_back((*iter).Point);
+ }
+
+ if(m_SubdivisionPoints.size() < 3){
+ return;
+ }
+
+ for ( i = 0; i < (m_SubdivisionPoints.size() - 1); ++i )
+ {
+ circumference += m_SubdivisionPoints[i].EuclideanDistanceTo(m_SubdivisionPoints[i + 1]);
+ }
+
+ if ( this->IsClosed() )
+ {
+ circumference += m_SubdivisionPoints.back().EuclideanDistanceTo( m_SubdivisionPoints.front() );
+ }
+
+ this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference );
+
+ // Calculate polygon area (if closed)
+ double area = 0.0;
+ bool intersection = false;
+ if ( this->IsClosed() && (this->GetGeometry2D() != NULL) )
+ {
+ // does PlanarPolygon overlap/intersect itself?
+ unsigned int numberOfPoints = m_SubdivisionPoints.size();
+ if( numberOfPoints >= GetMinimumNumberOfControlPoints())
+ {
+ for ( i=0; i<m_SubdivisionPoints.size() - 1; ++i )
+ {
+ // line 1
+ Point2D p0 = m_SubdivisionPoints[i];
+ Point2D p1 = m_SubdivisionPoints[i+1];
+
+ // check for intersection with all other lines
+ for ( j = i+1; j<m_SubdivisionPoints.size() - 1; ++j )
+ {
+ Point2D p2 = m_SubdivisionPoints[j];
+ Point2D p3 = m_SubdivisionPoints[j+1];
+ intersection = CheckForLineIntersection(p0,p1,p2,p3);
+ if (intersection) break;
+ }
+ if (intersection) break; // only because the inner loop might have changed "intersection"
+
+ // last line from p_x to p_0
+ Point2D p2 = m_SubdivisionPoints.front();
+ Point2D p3 = m_SubdivisionPoints.back();
+
+ intersection = CheckForLineIntersection(p0,p1,p2,p3);
+ if (intersection) break;
+ }
+ }
+
+ // calculate area
+ for ( i = 0; i < m_SubdivisionPoints.size(); ++i )
+ {
+ Point2D p0 = m_SubdivisionPoints[i];
+ Point2D p1 = m_SubdivisionPoints[ (i + 1) % m_SubdivisionPoints.size() ];
+
+ area += p0[0] * p1[1] - p1[0] * p0[1];
+ }
+ area /= 2.0;
+ }
+
+ // set area if appropiate (i.e. closed and not intersected)
+ if(this->IsClosed() && !intersection)
+ {
+ SetQuantity( FEATURE_ID_AREA, fabs( area ) );
+ this->ActivateFeature( FEATURE_ID_AREA );
+ }
+ else
+ {
+ SetQuantity( FEATURE_ID_AREA, 0 );
+ this->DeactivateFeature( FEATURE_ID_AREA );
+ }
+}
+
+std::vector<mitk::Point2D> mitk::PlanarSubdivisionPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2 ) const
+{
+ std::vector<mitk::Point2D> intersectionList;
+
+ ControlPointListType m_SubdivisionPoints;
+ PolyLineType tempList = m_PolyLines[0];
+ PolyLineType::iterator iter;
+ for( iter = tempList.begin(); iter != tempList.end(); ++iter )
+ {
+ m_SubdivisionPoints.push_back((*iter).Point);
+ }
+
+ for ( unsigned int i=0; i<m_SubdivisionPoints.size() - 1; i++ )
+ {
+ mitk::Point2D pnt1 = m_SubdivisionPoints[i];
+ mitk::Point2D pnt2 = m_SubdivisionPoints[i+1];
+ mitk::Point2D intersection;
+
+ if ( mitk::PlanarSubdivisionPolygon::CheckForLineIntersection( p1, p2, pnt1, pnt2, intersection ) )
+ {
+ intersectionList.push_back( intersection );
+ }
+ }
+
+ if ( this->IsClosed() )
+ {
+ mitk::Point2D intersection, lastControlPoint, firstControlPoint;
+ lastControlPoint = m_SubdivisionPoints.back();
+ firstControlPoint = m_SubdivisionPoints.front();
+
+ if ( mitk::PlanarSubdivisionPolygon::CheckForLineIntersection( lastControlPoint,
+ firstControlPoint, p1, p2, intersection ) )
+ {
+ intersectionList.push_back( intersection );
+ }
+ }
+
+ return intersectionList;
+}
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
new file mode 100644
index 0000000..4348ae6
--- /dev/null
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
@@ -0,0 +1,97 @@
+/*=========================================================================
+
+Program: Medical Imaging & Interaction Toolkit
+Language: C++
+Date: $Date$
+Version: $Revision: 17258 $
+
+Copyright (c) German Cancer Research Center, Division of Medical and
+Biological Informatics. All rights reserved.
+See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.
+
+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.
+
+=========================================================================*/
+
+
+#ifndef _MITK_PLANAR_SUBDIVISION_POLYGON_H_
+#define _MITK_PLANAR_SUBDIVISION_POLYGON_H_
+
+#include "mitkPlanarFigure.h"
+#include "PlanarFigureExports.h"
+#include "mitkPlanarPolygon.h"
+
+namespace mitk
+{
+
+class Geometry2D;
+
+/**
+ * \brief Implementation of PlanarFigure representing a polygon
+ * with two or more control points
+ */
+class PlanarFigure_EXPORT PlanarSubdivisionPolygon : public PlanarPolygon
+{
+public:
+ mitkClassMacro( PlanarSubdivisionPolygon, PlanarFigure );
+
+ itkNewMacro( Self );
+
+ /** \brief Subdivision Polygon has 4 control points per definition. */
+ unsigned int GetMinimumNumberOfControlPoints() const
+ {
+ return 4;
+ }
+
+
+ /** \brief Polygon maximum number of control points is principally not limited. */
+ unsigned int GetMaximumNumberOfControlPoints() const
+ {
+ return 1000;
+ }
+
+ /** \brief How many times should we generate a round of subdivisions? */
+ unsigned int GetSubdivisionRounds() const
+ {
+ return 5;
+ }
+
+ /** \brief Parameter w_tension defines the tension.
+ * the higher w_tension, the lower the "tension" on points.
+ * Rule: 0 < w_tension < 0.1
+ * 0.0625 (1 / 16) seems to be a good value.
+ */
+ float GetTensionParameter() const
+ {
+ return 0.0625;
+ }
+
+ std::vector<mitk::Point2D> CheckForLineIntersection( const Point2D& p1, const Point2D& p2 ) const;
+
+ void IncreaseSubdivisions();
+ void DecreaseSubdivisions();
+
+protected:
+ PlanarSubdivisionPolygon();
+ virtual ~PlanarSubdivisionPolygon();
+
+ /** \brief Generates the poly-line representation of the planar figure. */
+ virtual void GeneratePolyLine();
+
+ /** \brief Calculates feature quantities of the planar figure. */
+ virtual void EvaluateFeaturesInternal();
+
+ using PlanarPolygon::CheckForLineIntersection;
+
+ const unsigned int FEATURE_ID_CIRCUMFERENCE;
+ const unsigned int FEATURE_ID_AREA;
+
+private:
+
+};
+
+} // namespace mitk
+
+#endif //_MITK_PLANAR_SUBDIVISION_POLYGON_H_
diff --git a/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp b/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
index 83a8875..60458ef 100644
--- a/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
+++ b/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp
@@ -25,6 +25,7 @@ PURPOSE. See the above copyright notices for more information.
#include "mitkPlanarCross.h"
#include "mitkPlanarFourPointAngle.h"
#include "mitkPlanarPolygon.h"
+#include "mitkPlanarSubdivisionPolygon.h"
#include "mitkPlanarRectangle.h"
#include "mitkPlaneGeometry.h"
@@ -164,6 +165,10 @@ void mitk::PlanarFigureReader::GenerateData()
{
planarFigure = mitk::PlanarPolygon::New();
}
+ else if (type == "PlanarSubdivisionPolygon")
+ {
+ planarFigure = mitk::PlanarSubdivisionPolygon::New();
+ }
else if (type == "PlanarRectangle")
{
planarFigure = mitk::PlanarRectangle::New();
diff --git a/Modules/PlanarFigure/files.cmake b/Modules/PlanarFigure/files.cmake
index 931d605..4572a68 100644
--- a/Modules/PlanarFigure/files.cmake
+++ b/Modules/PlanarFigure/files.cmake
@@ -11,6 +11,7 @@ SET(CPP_FILES
DataManagement/mitkPlanarLine.cpp
DataManagement/mitkPlanarArrow.cpp
DataManagement/mitkPlanarPolygon.cpp
+ DataManagement/mitkPlanarSubdivisionPolygon.cpp
DataManagement/mitkPlanarRectangle.cpp
DataManagement/mitkPlanarFigureControlPointStyleProperty.cpp
IO/mitkPlanarFigureIOFactory.cpp
--
1.7.0.4
From 95b443f4763fff4830945d4f3dbf37a540d118ef Mon Sep 17 00:00:00 2001
From: Adrian Holfter <adrian@adrian-laptop.(none)>
Date: Tue, 12 Jul 2011 10:55:11 +0200
Subject: [PATCH 2/3] Created unittest for PlanarSubdivisionPolygon and added it to IOTest
---
.../DataManagement/mitkPlanarSubdivisionPolygon.h | 4 +-
Modules/PlanarFigure/Testing/files.cmake | 1 +
.../Testing/mitkPlanarFigureIOTest.cpp | 25 +++
.../Testing/mitkPlanarSubdivisionPolygonTest.cpp | 174 ++++++++++++++++++++
4 files changed, 202 insertions(+), 2 deletions(-)
create mode 100644 Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
index 4348ae6..15fcec7 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h
@@ -39,10 +39,10 @@ public:
itkNewMacro( Self );
- /** \brief Subdivision Polygon has 4 control points per definition. */
+ /** \brief Subdivision Polygon has 3 control points per definition. */
unsigned int GetMinimumNumberOfControlPoints() const
{
- return 4;
+ return 3;
}
diff --git a/Modules/PlanarFigure/Testing/files.cmake b/Modules/PlanarFigure/Testing/files.cmake
index 5eae54b..9f34bf1 100644
--- a/Modules/PlanarFigure/Testing/files.cmake
+++ b/Modules/PlanarFigure/Testing/files.cmake
@@ -1,6 +1,7 @@
SET(MODULE_TESTS
mitkPlanarCrossTest.cpp
mitkPlanarPolygonTest.cpp
+ mitkPlanarSubdivisionPolygonTest.cpp
mitkPlanarFigureIOTest.cpp
mitkPlanarFigureObjectFactoryTest.cpp
mitkPlanarArrowTest.cpp
diff --git a/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp
index 8257e67..2c59c3e 100644
--- a/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp
+++ b/Modules/PlanarFigure/Testing/mitkPlanarFigureIOTest.cpp
@@ -17,6 +17,7 @@ PURPOSE. See the above copyright notices for more information.
#include "mitkPlanarFourPointAngle.h"
#include "mitkPlanarLine.h"
#include "mitkPlanarPolygon.h"
+#include "mitkPlanarSubdivisionPolygon.h"
#include "mitkPlanarRectangle.h"
#include "mitkPlanarFigureWriter.h"
@@ -99,6 +100,16 @@ public:
planarPolygon->AddControlPoint( p2 );
planarPolygon->AddControlPoint( p3 );
planarFigures.push_back( planarPolygon.GetPointer() );
+
+ // Create PlanarSubdivisionPolygon
+ mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon = mitk::PlanarSubdivisionPolygon::New();
+ planarSubdivisionPolygon->SetClosed( false );
+ planarSubdivisionPolygon->SetGeometry2D( planeGeometry );
+ planarSubdivisionPolygon->PlaceFigure( p0 );
+ planarSubdivisionPolygon->SetCurrentControlPoint( p1 );
+ planarSubdivisionPolygon->AddControlPoint( p2 );
+ planarSubdivisionPolygon->AddControlPoint( p3 );
+ planarFigures.push_back( planarSubdivisionPolygon.GetPointer() );
// Create PlanarRectangle
mitk::PlanarRectangle::Pointer planarRectangle = mitk::PlanarRectangle::New();
@@ -183,6 +194,16 @@ public:
planarPolygonPrecise->AddControlPoint( p3precise );
planarFigures.push_back( planarPolygonPrecise.GetPointer() );
+ // Create PlanarSubdivisionPolygon
+ mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygonPrecise = mitk::PlanarSubdivisionPolygon::New();
+ planarSubdivisionPolygonPrecise->SetClosed( false );
+ planarSubdivisionPolygonPrecise->SetGeometry2D( preciseGeometry );
+ planarSubdivisionPolygonPrecise->PlaceFigure( p0precise );
+ planarSubdivisionPolygonPrecise->SetCurrentControlPoint( p1precise );
+ planarSubdivisionPolygonPrecise->AddControlPoint( p2precise );
+ planarSubdivisionPolygonPrecise->AddControlPoint( p3precise );
+ planarFigures.push_back( planarSubdivisionPolygonPrecise.GetPointer() );
+
// Create PlanarRectangle
mitk::PlanarRectangle::Pointer planarRectanglePrecise = mitk::PlanarRectangle::New();
planarRectanglePrecise->SetGeometry2D( preciseGeometry );
@@ -218,6 +239,10 @@ public:
{
copiedFigure = mitk::PlanarPolygon::New();
}
+ if(strcmp((*it1)->GetNameOfClass(), "PlanarSubdivisionPolygon") == 0)
+ {
+ copiedFigure = mitk::PlanarSubdivisionPolygon::New();
+ }
if(strcmp((*it1)->GetNameOfClass(), "PlanarCross") == 0)
{
copiedFigure = mitk::PlanarCross::New();
diff --git a/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
new file mode 100644
index 0000000..93307c6
--- /dev/null
+++ b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
@@ -0,0 +1,174 @@
+/*=========================================================================
+
+Program: Medical Imaging & Interaction Toolkit
+Language: C++
+Date: $Date: 2010-03-15 11:12:36 +0100 (Mo, 15 Mrz 2010) $
+Version: $Revision: 21745 $
+
+Copyright (c) German Cancer Research Center, Division of Medical and
+Biological Informatics. All rights reserved.
+See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.
+
+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.
+
+=========================================================================*/
+
+#include "mitkTestingMacros.h"
+#include "mitkPlanarSubdivisionPolygon.h"
+#include "mitkPlaneGeometry.h"
+
+
+class mitkPlanarSubdivisionPolygonTestClass
+{
+
+public:
+
+
+static void TestPlanarSubdivisionPolygonPlacement( mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon )
+{
+ // Test for correct minimum number of control points in cross-mode
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetMinimumNumberOfControlPoints() == 3, "Minimum number of control points" );
+
+ // Test for correct maximum number of control points in cross-mode
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetMaximumNumberOfControlPoints() == 1000, "Maximum number of control points" );
+
+ // Test for correct rounds of subdivisionPoints
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetSubdivisionRounds() == 5, "Subdivision point generation depth" );
+
+ // Test for correct tension parameter
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetTensionParameter() == 0.0625, "Tension parameter" );
+
+ // Initial placement of planarSubdivisionPolygon
+ mitk::Point2D p0;
+ p0[0] = 25.0; p0[1] = 25.0;
+ planarSubdivisionPolygon->PlaceFigure( p0 );
+
+ // Add second control point
+ mitk::Point2D p1;
+ p1[0] = 75.0; p1[1] = 25.0;
+ planarSubdivisionPolygon->SetControlPoint(1, p1 );
+
+ // Add third control point
+ mitk::Point2D p2;
+ p2[0] = 75.0; p2[1] = 75.0;
+ planarSubdivisionPolygon->AddControlPoint( p2 );
+
+ // Add fourth control point
+ mitk::Point2D p3;
+ p3[0] = 25.0; p3[1] = 75.0;
+ planarSubdivisionPolygon->AddControlPoint( p3 );
+
+ // Test for number of control points
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 4, "Number of control points after placement" );
+
+ // Test if PlanarFigure is closed
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->IsClosed(), "Test if property 'closed' is set by default" );
+
+ // Test for number of polylines
+ const mitk::PlanarFigure::PolyLineType polyLine0 = planarSubdivisionPolygon->GetPolyLine( 0 );
+ mitk::PlanarFigure::PolyLineType::const_iterator iter = polyLine0.begin();
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetPolyLinesSize() == 1, "Number of polylines after placement" );
+
+ // Test if subdivision point count is correct
+ MITK_TEST_CONDITION( polyLine0.size() == 128, "correct number of subdivision points for this depth level" );
+
+ // Test if control points are in correct order between subdivision points
+ bool correctPoint = true;
+ iter = polyLine0.begin();
+ advance(iter, 31);
+ if( iter->Point != p0 ){ correctPoint = false; }
+ advance(iter, 32);
+ if( iter->Point != p1 ){ correctPoint = false; }
+ advance(iter, 32);
+ if( iter->Point != p2 ){ correctPoint = false; }
+ advance(iter, 32);
+ if( iter->Point != p3 ){ correctPoint = false; }
+ MITK_TEST_CONDITION( correctPoint, "Test if control points are in correct order in polyline" );
+
+ // Test if a picked point has the correct coordinates
+ mitk::Point2D testPoint;
+ testPoint[0] = 50.000;
+ testPoint[1] = 18.750;
+ iter = polyLine0.begin();
+ advance(iter, 47);
+ MITK_TEST_CONDITION( iter->Point == testPoint, "Test if subdivision points are calculated correctly" );
+
+ // Test for number of measurement features
+ /*
+ Does not work yet
+
+ planarSubdivisionPolygon->EvaluateFeatures();
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfFeatures() == 2, "Number of measurement features" );
+
+ // Test for correct feature evaluation
+ double length0 = 4 * 50.0; // circumference
+ MITK_TEST_CONDITION( fabs( planarSubdivisionPolygon->GetQuantity( 0 ) - length0) < mitk::eps, "Size of longest diameter" );
+
+ double length1 = 50.0 * 50.0 ; // area
+ MITK_TEST_CONDITION( fabs( planarSubdivisionPolygon->GetQuantity( 1 ) - length1) < mitk::eps, "Size of short axis diameter" );
+ */
+}
+
+static void TestPlanarSubdivisionPolygonEditing( mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon )
+{
+ int initialNumberOfControlPoints = planarSubdivisionPolygon->GetNumberOfControlPoints();
+
+ mitk::Point2D pnt;
+ pnt[0] = 75.0; pnt[1] = 25.0;
+ planarSubdivisionPolygon->AddControlPoint( pnt);
+
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints+1, "A new control-point shall be added" );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( planarSubdivisionPolygon->GetNumberOfControlPoints()-1 ) == pnt, "Control-point shall be added at the end." );
+
+
+ planarSubdivisionPolygon->RemoveControlPoint( 3 );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == initialNumberOfControlPoints, "A control-point has been removed" );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( 3 ) == pnt, "It shall be possible to remove any control-point." );
+
+ planarSubdivisionPolygon->RemoveControlPoint( 0 );
+ planarSubdivisionPolygon->RemoveControlPoint( 0 );
+ planarSubdivisionPolygon->RemoveControlPoint( 0 );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 3, "Control-points cannot be removed if only three points remain." );
+
+ mitk::Point2D pnt1;
+ pnt1[0] = 33.0; pnt1[1] = 33.0;
+ planarSubdivisionPolygon->AddControlPoint( pnt1, 0 );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetNumberOfControlPoints() == 4, "A control-point has been added" );
+ MITK_TEST_CONDITION( planarSubdivisionPolygon->GetControlPoint( 0 ) == pnt1, "It shall be possible to insert a control-point at any position." );
+
+}
+
+};
+/**
+ * mitkplanarSubdivisionPolygonTest tests the methods and behavior of mitk::planarSubdivisionPolygon with sub-tests:
+ *
+ * 1. Instantiation and basic tests, including feature evaluation
+ *
+ */
+int mitkPlanarSubdivisionPolygonTest(int /* argc */, char* /*argv*/[])
+{
+ // always start with this!
+ MITK_TEST_BEGIN("planarSubdivisionPolygon")
+
+ // create PlaneGeometry on which to place the planarSubdivisionPolygon
+ mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New();
+ planeGeometry->InitializeStandardPlane( 100.0, 100.0 );
+
+ // **************************************************************************
+ // 1. Instantiation and basic tests, including feature evaluation
+ mitk::PlanarSubdivisionPolygon::Pointer planarSubdivisionPolygon = mitk::PlanarSubdivisionPolygon::New();
+ planarSubdivisionPolygon->SetGeometry2D( planeGeometry );
+
+ // first test: did this work?
+ MITK_TEST_CONDITION_REQUIRED( planarSubdivisionPolygon.IsNotNull(), "Testing instantiation" );
+
+ // Test placement of planarSubdivisionPolygon by control points
+ mitkPlanarSubdivisionPolygonTestClass::TestPlanarSubdivisionPolygonPlacement( planarSubdivisionPolygon );
+
+ mitkPlanarSubdivisionPolygonTestClass::TestPlanarSubdivisionPolygonEditing( planarSubdivisionPolygon );
+
+ // always end with this!
+ MITK_TEST_END();
+}
--
1.7.0.4
From a1fc9ee6e2b779ea855efcdbc2a2c045836e1711 Mon Sep 17 00:00:00 2001
From: Adrian Holfter <adrian@adrian-laptop.(none)>
Date: Thu, 14 Jul 2011 16:42:07 +0200
Subject: [PATCH 3/3] Fixes in SubdivisionPolygon class and unittest.
---
.../mitkPlanarSubdivisionPolygon.cpp | 58 +++++++++++---------
.../Testing/mitkPlanarSubdivisionPolygonTest.cpp | 18 ++++++-
2 files changed, 48 insertions(+), 28 deletions(-)
diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
index cd72df8..6872393 100644
--- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
+++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp
@@ -46,9 +46,6 @@ void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
this->ClearPolyLines();
ControlPointListType m_SubdivisionPoints = m_ControlPoints;
- // Later, we have to know which points are control points
- ControlPointListType m_ControlPointsCopy = m_ControlPoints;
-
if( m_ControlPoints.size() >= GetMinimumNumberOfControlPoints() ){
for( unsigned int i=0; i < GetSubdivisionRounds(); i++ )
@@ -56,19 +53,10 @@ void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
// Indices
unsigned int p_here, p_prev, p_next, p_nextnext;
- // Just in case the poly isn't closed. It should be, but who knows...
- if(this->IsClosed())
- {
- p_here = 0;
- p_prev = m_SubdivisionPoints.size() - 1;
- p_next = 1;
- p_nextnext = 2;
- }else{
- p_prev = 0;
- p_here = 1;
- p_next = 2;
- p_nextnext = 3;
- }
+ p_prev = m_SubdivisionPoints.size() -1;
+ p_here = 0;
+ p_next = 1;
+ p_nextnext = 2;
double distanceToSubPoint;
double distanceToPointLeft;
@@ -76,26 +64,33 @@ void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
Point2D newPoint;
+ // Keep cycling our array indices forward until they wrap around at the end
while(true)
{
// Get distance to neighbors
distanceToSubPoint = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[p_next]);
- // Only calculate distance to control points if we are the "major" / last control point being dragged around
+ /*
+ * Only calculate distance to left and right subdivisionPoints if we are the "major" / last control point being dragged around
+ *
+ * Cause: If any point is in a 20 pixel(?) radius to the point being dragged around,
+ * the PlanarFigureInteractor tries to insert the new point on this existing polyline (between subdivision points!!)
+ * rather than creating a new point at the end of the line.
+ */
if (p_here == m_SubdivisionPoints.size() - 1)
{
- unsigned int prev = 0;
- unsigned int next = ( m_SubdivisionPoints.size() > 1 ? p_here - 1 : 0 );
distanceToPointLeft = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[0]);
distanceToPointRight = m_SubdivisionPoints[p_here].EuclideanDistanceTo(m_SubdivisionPoints[p_here - 1]);
}
// distance to next subPoint has to be > 2
- // distance from main control point has to be > 20
+ // distance from main control point has to be > 20 (see above comment)
if( distanceToSubPoint > 2.0 && ( p_here != m_SubdivisionPoints.size() || distanceToPointRight > 20 && distanceToPointLeft > 20 ))
{
double x,y;
+ // Create new subdivision point according to formula
+ // p_new = (0.5 + tension) * (p_here + p_next) - tension * (p_prev + p_nextnext)
x = (0.5 + GetTensionParameter()) * (double)( m_SubdivisionPoints[p_here][0] + m_SubdivisionPoints[p_next][0] )
- GetTensionParameter() * (double)( m_SubdivisionPoints[p_prev][0] + m_SubdivisionPoints[p_nextnext][0]);
y = (0.5 + GetTensionParameter()) * (double)( m_SubdivisionPoints[p_here][1] + m_SubdivisionPoints[p_next][1] )
@@ -112,7 +107,7 @@ void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
p_nextnext++;
}
- // Advance array indices and wrap around at the end
+ // Advance array indices and wrap them around at the end
p_prev = p_here;
if(p_here >= (m_SubdivisionPoints.size() -1 ))
@@ -151,19 +146,27 @@ void mitk::PlanarSubdivisionPolygon::GeneratePolyLine()
}
- int lastControlPoint = m_SubdivisionPoints.size() - 1;
+ // The polyline needs to know between which control points each subdivision point is.
+ // The first point is generally on the line between the last and first control point
+ int lastControlPointIndex = m_SubdivisionPoints.size() - 1;
+
for ( unsigned int i=0; i<m_SubdivisionPoints.size(); ++i )
{
Point2D pnt = m_SubdivisionPoints[i];
- for ( unsigned int j=0; j<m_ControlPointsCopy.size(); j++ )
+
+ // Find out if this (subdivision)point is actually a control point
+ for ( unsigned int j=0; j<m_ControlPoints.size(); j++ )
{
- if( pnt == m_ControlPointsCopy[j])
+ // if so, every subdivision point following after this point belongs to this control point
+ if( pnt == m_ControlPoints[j])
{
- // It's j+1 because the insert() method of a vector inserts the new entry BEHIND the current one with index i
- lastControlPoint = j+1;
+ // It's j+1 because the insert() method of a vector inserts the new subdivision point BEHIND the current one with index i
+ lastControlPointIndex = j+1;
}
}
- PolyLineElement elem(pnt, lastControlPoint);
+ // the index of the last control point is needed to correctly insert points afterwards
+ PolyLineElement elem(pnt, lastControlPointIndex);
+ // Append to poly line number 0 (we only have one polyline, even if it has many polyline elements).
this->AppendPointToPolyLine( 0, elem );
}
}
@@ -174,6 +177,7 @@ void mitk::PlanarSubdivisionPolygon::EvaluateFeaturesInternal()
double circumference = 0.0;
unsigned int i,j;
+ // We need to construct our subdivisionPoints-array out of the existing polyline, because subdivision points aren't stored in the class
ControlPointListType m_SubdivisionPoints;
m_SubdivisionPoints.clear();
PolyLineType::iterator iter;
diff --git a/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
index 93307c6..2632b29 100644
--- a/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
+++ b/Modules/PlanarFigure/Testing/mitkPlanarSubdivisionPolygonTest.cpp
@@ -88,12 +88,28 @@ static void TestPlanarSubdivisionPolygonPlacement( mitk::PlanarSubdivisionPolygo
MITK_TEST_CONDITION( correctPoint, "Test if control points are in correct order in polyline" );
// Test if a picked point has the correct coordinates
+ correctPoint = true;
+
mitk::Point2D testPoint;
testPoint[0] = 50.000;
testPoint[1] = 18.750;
iter = polyLine0.begin();
advance(iter, 47);
- MITK_TEST_CONDITION( iter->Point == testPoint, "Test if subdivision points are calculated correctly" );
+ if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > mitk::eps ){ correctPoint = false; }
+
+ testPoint[0] = 20.96007347106933593750;
+ testPoint[1] = 58.74700927734375000000;
+ iter = polyLine0.begin();
+ advance(iter, 10);
+ if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > mitk::eps ){ correctPoint = false; }
+
+ testPoint[0] = 76.96900177001953125000;
+ testPoint[1] = 30.05101013183593750000;
+ iter = polyLine0.begin();
+ advance(iter, 67);
+ if( (iter->Point[0] - testPoint[0]) + (iter->Point[1] - testPoint[1]) > mitk::eps ){ correctPoint = false; }
+
+ MITK_TEST_CONDITION( correctPoint, "Test if subdivision points are calculated correctly" )
// Test for number of measurement features
/*
--
1.7.0.4

File Metadata

Mime Type
text/plain
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
668
Default Alt Text
bug-8506-unittest-smooth-polygon_NEW.patch (36 KB)

Event Timeline

updated patch, including fixes in planarSubdivisionPolygon.