From a87b2d82e52bb3454cc514b339a07eb12d8e1f0b Mon Sep 17 00:00:00 2001 From: Adrian Holfter Date: Mon, 11 Jul 2011 14:04:51 +0200 Subject: [PATCH] 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 + +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; iAppendPointToPolyLine( 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; iIsClosed() && !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::PlanarSubdivisionPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2 ) const +{ + std::vector 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; iIsClosed() ) + { + 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 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