diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index d06f759795..6ffec6ebad 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,686 +1,686 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-07-08 11:04:08 +0200 (Mi, 08 Jul 2009) $ 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 "mitkPlanarFigure.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" #include "algorithm" mitk::PlanarFigure::PlanarFigure() : m_FigurePlaced( false ), m_PreviewControlPointVisible( false ), m_SelectedControlPoint( -1 ), m_Geometry2D( NULL ), m_PolyLineUpToDate(false), m_HelperLinesUpToDate(false), m_FeaturesUpToDate(false), m_FeaturesMTime( 0 ) { m_HelperPolyLinesToBePainted = BoolContainerType::New(); m_DisplaySize.first = 0.0; m_DisplaySize.second = 0; this->SetProperty( "closed", mitk::BoolProperty::New( false ) ); // Currently only single-time-step geometries are supported this->InitializeTimeSlicedGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } void mitk::PlanarFigure::SetGeometry2D( mitk::Geometry2D *geometry ) { this->SetGeometry( geometry ); m_Geometry2D = geometry; } const mitk::Geometry2D *mitk::PlanarFigure::GetGeometry2D() const { return m_Geometry2D; } bool mitk::PlanarFigure::IsClosed() const { mitk::BoolProperty* closed = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "closed" ).GetPointer() ); if ( closed != NULL ) { return closed->GetValue(); } return false; } void mitk::PlanarFigure::PlaceFigure( const mitk::Point2D& point ) { for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( i, point ) ); } m_FigurePlaced = true; m_SelectedControlPoint = 1; } bool mitk::PlanarFigure::AddControlPoint( const mitk::Point2D& point, int position ) { // if we already have the maximum number of control points, do nothing if ( m_NumberOfControlPoints < this->GetMaximumNumberOfControlPoints() ) { // if position has not been defined or position would be the last control point, just append the new one // we also append a new point if we click onto the line between the first two control-points if the second control-point is selected // -> special case for PlanarCross if ( position == -1 || position > m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) ) { if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 ) { m_ControlPoints.resize( this->GetMaximumNumberOfControlPoints()-1 ); } m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { // insert the point at the given position ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } // polylines & helperpolylines need to be repainted m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; // one control point more ++m_NumberOfControlPoints; return true; } else { return false; } } bool mitk::PlanarFigure::SetControlPoint( unsigned int index, const Point2D& point, bool createIfDoesNotExist ) { bool controlPointSetCorrectly = false; if (createIfDoesNotExist) { if ( m_NumberOfControlPoints <= index ) { m_ControlPoints.push_back( this->ApplyControlPointConstraints( index, point ) ); m_NumberOfControlPoints++; } else { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); } controlPointSetCorrectly = true; } else if ( index < m_NumberOfControlPoints ) { m_ControlPoints.at( index ) = this->ApplyControlPointConstraints( index, point ); controlPointSetCorrectly = true; } else { return false; } if ( controlPointSetCorrectly ) { m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; } return controlPointSetCorrectly; } bool mitk::PlanarFigure::SetCurrentControlPoint( const Point2D& point ) { if ( (m_SelectedControlPoint < 0) || (m_SelectedControlPoint >= (int)m_NumberOfControlPoints) ) { return false; } return this->SetControlPoint(m_SelectedControlPoint, point, false); } unsigned int mitk::PlanarFigure::GetNumberOfControlPoints() const { return m_NumberOfControlPoints; } bool mitk::PlanarFigure::SelectControlPoint( unsigned int index ) { if ( index < this->GetNumberOfControlPoints() ) { m_SelectedControlPoint = index; return true; } else { return false; } } void mitk::PlanarFigure::DeselectControlPoint() { m_SelectedControlPoint = -1; } void mitk::PlanarFigure::SetPreviewControlPoint( const Point2D& point ) { m_PreviewControlPoint = point; m_PreviewControlPointVisible = true; } void mitk::PlanarFigure::ResetPreviewContolPoint() { m_PreviewControlPointVisible = false; } mitk::Point2D mitk::PlanarFigure::GetPreviewControlPoint() { return m_PreviewControlPoint; } bool mitk::PlanarFigure::IsPreviewControlPointVisible() { return m_PreviewControlPointVisible; } mitk::Point2D mitk::PlanarFigure::GetControlPoint( unsigned int index ) const { if ( index < m_NumberOfControlPoints ) { return m_ControlPoints.at( index ); } itkExceptionMacro( << "GetControlPoint(): Invalid index!" ); } mitk::Point3D mitk::PlanarFigure::GetWorldControlPoint( unsigned int index ) const { Point3D point3D; if ( (m_Geometry2D != NULL) && (index < m_NumberOfControlPoints) ) { m_Geometry2D->Map( m_ControlPoints.at( index ), point3D ); return point3D; } itkExceptionMacro( << "GetWorldControlPoint(): Invalid index!" ); } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) { mitk::PlanarFigure::PolyLineType polyLine; if ( m_PolyLines.size() > index || !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.at( index );; } const mitk::PlanarFigure::PolyLineType mitk::PlanarFigure::GetPolyLine(unsigned int index) const { return m_PolyLines.at( index ); } void mitk::PlanarFigure::ClearPolyLines() { for ( int i=0; iGenerateHelperPolyLine(mmPerDisplayUnit, displayHeight); m_HelperLinesUpToDate = true; // store these parameters to be able to check next time if somebody zoomed in or out m_DisplaySize.first = mmPerDisplayUnit; m_DisplaySize.second = displayHeight; } helperPolyLine = m_HelperPolyLines.at(index); } return helperPolyLine; } void mitk::PlanarFigure::ClearHelperPolyLines() { for ( int i=0; iEvaluateFeaturesInternal(); m_FeaturesUpToDate = true; } } void mitk::PlanarFigure::UpdateOutputInformation() { // Bounds are NOT calculated here, since the Geometry2D defines a fixed // frame (= bounds) for the planar figure. Superclass::UpdateOutputInformation(); this->GetTimeSlicedGeometry()->UpdateInformation(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion( itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { m_NumberOfControlPoints = numberOfControlPoints; } mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ) { if ( m_Geometry2D == NULL ) { return point; } Point2D indexPoint; m_Geometry2D->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = m_Geometry2D->GetBounds(); if ( indexPoint[0] < bounds[0] ) { indexPoint[0] = bounds[0]; } if ( indexPoint[0] > bounds[1] ) { indexPoint[0] = bounds[1]; } if ( indexPoint[1] < bounds[2] ) { indexPoint[1] = bounds[2]; } if ( indexPoint[1] > bounds[3] ) { indexPoint[1] = bounds[3]; } Point2D constrainedPoint; m_Geometry2D->IndexToWorld( indexPoint, constrainedPoint ); return constrainedPoint; } unsigned int mitk::PlanarFigure::AddFeature( const char *featureName, const char *unitName ) { unsigned int index = m_Features.size(); Feature newFeature( featureName, unitName ); m_Features.push_back( newFeature ); return index; } void mitk::PlanarFigure::SetFeatureName( unsigned int index, const char *featureName ) { if ( index < m_Features.size() ) { m_Features[index].Name = featureName; } } void mitk::PlanarFigure::SetFeatureUnit( unsigned int index, const char *unitName ) { if ( index < m_Features.size() ) { m_Features[index].Unit = unitName; } } void mitk::PlanarFigure::SetQuantity( unsigned int index, double quantity ) { if ( index < m_Features.size() ) { m_Features[index].Quantity = quantity; } } void mitk::PlanarFigure::ActivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = true; } } void mitk::PlanarFigure::DeactivateFeature( unsigned int index ) { if ( index < m_Features.size() ) { m_Features[index].Active = false; } } void mitk::PlanarFigure::InitializeTimeSlicedGeometry( unsigned int timeSteps ) { mitk::TimeSlicedGeometry::Pointer timeGeometry = this->GetTimeSlicedGeometry(); mitk::Geometry2D::Pointer geometry2D = mitk::Geometry2D::New(); geometry2D->Initialize(); if ( timeSteps > 1 ) { mitk::ScalarType timeBounds[] = {0.0, 1.0}; geometry2D->SetTimeBounds( timeBounds ); } // The geometry is propagated automatically to all time steps, // if EvenlyTimed is true... timeGeometry->InitializeEvenlyTimed( geometry2D, timeSteps ); } void mitk::PlanarFigure::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << this->GetNameOfClass() << ":\n"; if (this->IsClosed()) os << indent << "This figure is closed\n"; else os << indent << "This figure is not closed\n"; os << indent << "Minimum number of control points: " << this->GetMinimumNumberOfControlPoints() << std::endl; os << indent << "Maximum number of control points: " << this->GetMaximumNumberOfControlPoints() << std::endl; os << indent << "Current number of control points: " << this->GetNumberOfControlPoints() << std::endl; os << indent << "Control points:" << std::endl; for ( unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i ) { //os << indent.GetNextIndent() << i << ": " << m_ControlPoints->ElementAt( i ) << std::endl; os << indent.GetNextIndent() << i << ": " << m_ControlPoints.at( i ) << std::endl; } os << indent << "Geometry:\n"; this->GetGeometry2D()->Print(os, indent.GetNextIndent()); } unsigned short mitk::PlanarFigure::GetPolyLinesSize() { if ( !m_PolyLineUpToDate ) { this->GeneratePolyLine(); m_PolyLineUpToDate = true; } return m_PolyLines.size(); } unsigned short mitk::PlanarFigure::GetHelperPolyLinesSize() { return m_HelperPolyLines.size(); } bool mitk::PlanarFigure::IsHelperToBePainted(unsigned int index) { return m_HelperPolyLinesToBePainted->GetElement( index ); } bool mitk::PlanarFigure::ResetOnPointSelect() { return false; } void mitk::PlanarFigure::RemoveControlPoint( unsigned int index ) { if ( index > m_ControlPoints.size() ) return; if ( (m_ControlPoints.size() -1) < this->GetMinimumNumberOfControlPoints() ) return; ControlPointListType::iterator iter; iter = m_ControlPoints.begin() + index; m_ControlPoints.erase( iter ); m_PolyLineUpToDate = false; m_HelperLinesUpToDate = false; m_FeaturesUpToDate = false; --m_NumberOfControlPoints; } void mitk::PlanarFigure::RemoveLastControlPoint() { RemoveControlPoint( m_ControlPoints.size()-1 ); } void mitk::PlanarFigure::DeepCopy(Self::Pointer oldFigure) { //DeepCopy only same types of planar figures //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; } m_ControlPoints.clear(); this->ClearPolyLines(); this->ClearHelperPolyLines(); // clone base data members SetPropertyList(oldFigure->GetPropertyList()->Clone()); /// deep copy members m_FigurePlaced = oldFigure->m_FigurePlaced; m_SelectedControlPoint = oldFigure->m_SelectedControlPoint; m_FeaturesMTime = oldFigure->m_FeaturesMTime; m_Features = oldFigure->m_Features; m_NumberOfControlPoints = oldFigure->m_NumberOfControlPoints; //copy geometry 2D of planar figure SetGeometry2D((mitk::Geometry2D*)oldFigure->m_Geometry2D->Clone().GetPointer()); for(unsigned long index=0; index < oldFigure->GetNumberOfControlPoints(); index++) { m_ControlPoints.push_back( oldFigure->GetControlPoint( index )); } //After setting the control points we can generate the polylines this->GeneratePolyLine(); } void mitk::PlanarFigure::SetNumberOfPolyLines( unsigned int numberOfPolyLines ) { m_PolyLines.resize(numberOfPolyLines); } void mitk::PlanarFigure::SetNumberOfHelperPolyLines( unsigned int numberOfHerlperPolyLines ) { m_HelperPolyLines.resize(numberOfHerlperPolyLines); } void mitk::PlanarFigure::AppendPointToPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_PolyLines.size() ) { m_PolyLines.at( index ).push_back( element ); } else { MITK_ERROR << "Tried to add point to PolyLine " << index+1 << ", although only " << m_PolyLines.size() << " exists"; } } void mitk::PlanarFigure::AppendPointToHelperPolyLine( unsigned int index, PolyLineElement element ) { if ( index < m_HelperPolyLines.size() ) { m_HelperPolyLines.at( index ).push_back( element ); } else { MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp index bd0d945d6b..7bf3c612cd 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp @@ -1,265 +1,266 @@ /*========================================================================= 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 "mitkPlanarPolygon.h" #include "mitkGeometry2D.h" #include "mitkProperties.h" // stl related includes #include mitk::PlanarPolygon::PlanarPolygon() : 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( false ) ); } mitk::PlanarPolygon::~PlanarPolygon() { } void mitk::PlanarPolygon::SetClosed( bool closed ) { this->SetProperty( "closed", mitk::BoolProperty::New( closed ) ); if ( !closed ) { // For non-closed polygons: use "Length" as feature name; disable area this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Length" ); this->DeactivateFeature( FEATURE_ID_AREA ); } else { // For closed polygons: use "Circumference" as feature name; enable area this->SetFeatureName( FEATURE_ID_CIRCUMFERENCE, "Circumference" ); this->ActivateFeature( FEATURE_ID_AREA ); } this->Modified(); } void mitk::PlanarPolygon::GeneratePolyLine() { this->ClearPolyLines(); for ( int i=0; iAppendPointToPolyLine( 0, elem ); } } void mitk::PlanarPolygon::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A polygon does not require helper objects } void mitk::PlanarPolygon::EvaluateFeaturesInternal() { // Calculate circumference double circumference = 0.0; unsigned int i,j; for ( i = 0; i < this->GetNumberOfControlPoints() - 1; ++i ) { circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo( this->GetWorldControlPoint( i + 1 ) ); } if ( this->IsClosed() ) { circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo( this->GetWorldControlPoint( 0 ) ); } 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 = (unsigned int)GetNumberOfControlPoints(); if( numberOfPoints >= 4) { for ( i = 0; i < (numberOfPoints - 1); ++i ) { // line 1 Point2D p0 = this->GetControlPoint( i ); Point2D p1 = this->GetControlPoint(i + 1); // check for intersection with all other lines for (j = i+1; j < (numberOfPoints - 1); ++j ) { Point2D p2 = this->GetControlPoint(j); Point2D p3 = this->GetControlPoint(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 = this->GetControlPoint(0); Point2D p3 = this->GetControlPoint(numberOfPoints - 1); intersection = CheckForLineIntersection(p0,p1,p2,p3); if (intersection) break; } } // calculate area for ( i = 0; i < this->GetNumberOfControlPoints(); ++i ) { Point2D p0 = this->GetControlPoint( i ); Point2D p1 = this->GetControlPoint( (i + 1) % this->GetNumberOfControlPoints() ); 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 ); } } void mitk::PlanarPolygon::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); if (this->IsClosed()) os << indent << "Polygon is closed\n"; else os << indent << "Polygon is not closed\n"; } // based on // http://flassari.is/2008/11/line-line-intersection-in-cplusplus/ bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4, Point2D& intersection ) const { // do not check for intersections with control points if(p1 == p2 || p1 == p3 || p1 == p4 || p2 == p3 || p2 == p4 || p3 == p4) return false; // Store the values for fast access and easy // equations-to-code conversion double x1 = p1[0], x2 = p2[0], x3 = p3[0], x4 = p4[0]; double y1 = p1[1], y2 = p2[1], y3 = p3[1], y4 = p4[1]; double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); // If d is zero, there is no intersection //if (d < mitk::eps) return false; if (d == 0) return false; // Get the x and y double pre = (x1*y2 - y1*x2); double post = (x3*y4 - y3*x4); double x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d; double y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d; double tolerance = 0.001; // Check if the x coordinates are within both lines, including tolerance if ( x < ( std::min(x1, x2) - tolerance ) || x > ( std::max(x1, x2) + tolerance ) || x < ( std::min(x3, x4) - tolerance ) || x > ( std::max(x3, x4) + tolerance ) ) { return false; } // Check if the y coordinates are within both lines, including tolerance if ( y < ( std::min(y1, y2) - tolerance ) || y > ( std::max(y1, y2) + tolerance ) || y < ( std::min(y3, y4) - tolerance ) || y > ( std::max(y3, y4) + tolerance ) ) { return false; } // point of intersection Point2D ret; ret[0] = x; ret[1] = y; intersection = ret; return true; } bool mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4 ) const { mitk::Point2D intersection; return mitk::PlanarPolygon::CheckForLineIntersection( p1, p2, p3, p4, intersection ); } std::vector mitk::PlanarPolygon::CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2 ) const { std::vector intersectionList; for ( int i=0; iGetNumberOfControlPoints()-1; i++ ) { mitk::Point2D pnt1 = this->GetControlPoint( i ); mitk::Point2D pnt2 = this->GetControlPoint( i+1 ); mitk::Point2D intersection; if ( mitk::PlanarPolygon::CheckForLineIntersection( p1, p2, pnt1, pnt2, intersection ) ) { intersectionList.push_back( intersection ); } } if ( this->IsClosed() ) { mitk::Point2D intersection, lastControlPoint, firstControlPoint; lastControlPoint = this->GetControlPoint(this->GetNumberOfControlPoints()-1); firstControlPoint = this->GetControlPoint(0); if ( mitk::PlanarPolygon::CheckForLineIntersection( lastControlPoint, firstControlPoint, p1, p2, intersection ) ) { intersectionList.push_back( intersection ); } } return intersectionList; } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp new file mode 100644 index 0000000000..2ea43562c8 --- /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 0000000000..4348ae6228 --- /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 83a88751a8..60458ef981 100644 --- a/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp +++ b/Modules/PlanarFigure/IO/mitkPlanarFigureReader.cpp @@ -1,426 +1,431 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date: 2009-06-17 14:15:34 +0200 (Mi, 17. Jun 2009) $ Version: $Revision: 17745 $ 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 "mitkPlanarFigureReader.h" #include "mitkPlanarAngle.h" #include "mitkPlanarCircle.h" #include "mitkPlanarLine.h" #include "mitkPlanarArrow.h" #include "mitkPlanarCross.h" #include "mitkPlanarFourPointAngle.h" #include "mitkPlanarPolygon.h" +#include "mitkPlanarSubdivisionPolygon.h" #include "mitkPlanarRectangle.h" #include "mitkPlaneGeometry.h" #include "mitkBasePropertySerializer.h" #include #include mitk::PlanarFigureReader::PlanarFigureReader() : PlanarFigureSource(), FileReader(), m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false) { this->SetNumberOfRequiredOutputs(1); this->SetNumberOfOutputs(1); this->SetNthOutput(0, this->MakeOutput(0)); m_CanReadFromMemory = true; //this->Modified(); //this->GetOutput()->Modified(); //this->GetOutput()->ReleaseData(); } mitk::PlanarFigureReader::~PlanarFigureReader() {} mitk::PlanarFigureSource::DataObjectPointer mitk::PlanarFigureReader::MakeOutput ( unsigned int ) { return static_cast(PlanarCircle::New().GetPointer()); // just as a stand in for the pipeline update mechanism. This will be overwritten in GenerateData() } void mitk::PlanarFigureReader::GenerateData() { m_Success = false; this->SetNumberOfOutputs(0); // reset all outputs, we add new ones depending on the file content TiXmlDocument document; if(m_ReadFromMemory) { if(m_MemoryBuffer == NULL || m_MemorySize == 0) { //check itkWarningMacro( << "Sorry, memory buffer has not been set!" ); return; } if(m_MemoryBuffer[ m_MemorySize - 1 ] == '\0') { document.Parse(m_MemoryBuffer); } else { char * tmpArray = new char[(int)m_MemorySize+1]; tmpArray[m_MemorySize] = '\0'; memcpy(tmpArray,m_MemoryBuffer,m_MemorySize); document.Parse(m_MemoryBuffer); delete [] tmpArray; } } else { if (m_FileName.empty()) { itkWarningMacro( << "Sorry, filename has not been set!" ); return; } if (this->CanReadFile( m_FileName.c_str()) == false) { itkWarningMacro( << "Sorry, can't read file " << m_FileName << "!" ); return; } if (!document.LoadFile(m_FileName)) { MITK_ERROR << "Could not open/read/parse " << m_FileName << ". TinyXML reports: '" << document.ErrorDesc() << "'. " << "The error occurred in row " << document.ErrorRow() << ", column " << document.ErrorCol() << "."; return; } } int fileVersion = 1; TiXmlElement* versionObject = document.FirstChildElement("Version"); if (versionObject != NULL) { if ( versionObject->QueryIntAttribute( "FileVersion", &fileVersion ) != TIXML_SUCCESS ) { MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl; } } else { MITK_WARN << m_FileName << " does not contain version information! Trying version 1 format." << std::endl; } if (fileVersion != 1) // add file version selection and version specific file parsing here, if newer file versions are created { MITK_WARN << "File version > 1 is not supported by this reader."; return; } /* file version 1 reader code */ for( TiXmlElement* pfElement = document.FirstChildElement("PlanarFigure"); pfElement != NULL; pfElement = pfElement->NextSiblingElement("PlanarFigure") ) { if (pfElement == NULL) continue; std::string type = pfElement->Attribute("type"); mitk::PlanarFigure::Pointer planarFigure = NULL; if (type == "PlanarAngle") { planarFigure = mitk::PlanarAngle::New(); } else if (type == "PlanarCircle") { planarFigure = mitk::PlanarCircle::New(); } else if (type == "PlanarCross") { planarFigure = mitk::PlanarCross::New(); } else if (type == "PlanarFourPointAngle") { planarFigure = mitk::PlanarFourPointAngle::New(); } else if (type == "PlanarLine") { planarFigure = mitk::PlanarLine::New(); } else if (type == "PlanarPolygon") { planarFigure = mitk::PlanarPolygon::New(); } + else if (type == "PlanarSubdivisionPolygon") + { + planarFigure = mitk::PlanarSubdivisionPolygon::New(); + } else if (type == "PlanarRectangle") { planarFigure = mitk::PlanarRectangle::New(); } else if (type == "PlanarArrow") { planarFigure = mitk::PlanarArrow::New(); } else { // unknown type MITK_WARN << "encountered unknown planar figure type '" << type << "'. Skipping this element."; continue; } // Read properties of the planar figure for( TiXmlElement* propertyElement = pfElement->FirstChildElement("property"); propertyElement != NULL; propertyElement = propertyElement->NextSiblingElement("property") ) { const char* keya = propertyElement->Attribute("key"); std::string key( keya ? keya : ""); const char* typea = propertyElement->Attribute("type"); std::string type( typea ? typea : ""); // hand propertyElement to specific reader std::stringstream propertyDeserializerClassName; propertyDeserializerClassName << type << "Serializer"; std::list readers = itk::ObjectFactoryBase::CreateAllInstance(propertyDeserializerClassName.str().c_str()); if (readers.size() < 1) { MITK_ERROR << "No property reader found for " << type; } if (readers.size() > 1) { MITK_WARN << "Multiple property readers found for " << type << ". Using arbitrary first one."; } for ( std::list::iterator iter = readers.begin(); iter != readers.end(); ++iter ) { if (BasePropertySerializer* reader = dynamic_cast( iter->GetPointer() ) ) { BaseProperty::Pointer property = reader->Deserialize( propertyElement->FirstChildElement() ); if (property.IsNotNull()) { planarFigure->GetPropertyList()->ReplaceProperty(key, property); } else { MITK_ERROR << "There were errors while loading property '" << key << "' of type " << type << ". Your data may be corrupted"; } break; } } } // Read geometry of containing plane TiXmlElement* geoElement = pfElement->FirstChildElement("Geometry"); if (geoElement != NULL) { try { // Create plane geometry mitk::PlaneGeometry::Pointer planeGeo = mitk::PlaneGeometry::New(); // Extract and set plane transform parameters DoubleList transformList = this->GetDoubleAttributeListFromXMLNode( geoElement->FirstChildElement( "transformParam" ), "param", 12 ); typedef mitk::AffineGeometryFrame3D::TransformType TransformType; TransformType::ParametersType parameters; parameters.SetSize( 12 ); unsigned int i; DoubleList::iterator it; for ( it = transformList.begin(), i = 0; it != transformList.end(); ++it, ++i ) { parameters.SetElement( i, *it ); } typedef mitk::AffineGeometryFrame3D::TransformType TransformType; TransformType::Pointer affineGeometry = TransformType::New(); affineGeometry->SetParameters( parameters ); planeGeo->SetIndexToWorldTransform( affineGeometry ); // Extract and set plane bounds DoubleList boundsList = this->GetDoubleAttributeListFromXMLNode( geoElement->FirstChildElement( "boundsParam" ), "bound", 6 ); typedef mitk::Geometry3D::BoundsArrayType BoundsArrayType; BoundsArrayType bounds; for ( it = boundsList.begin(), i = 0; it != boundsList.end(); ++it, ++i ) { bounds[i] = *it; } planeGeo->SetBounds( bounds ); // Extract and set spacing and origin Vector3D spacing = this->GetVectorFromXMLNode(geoElement->FirstChildElement("Spacing")); planeGeo->SetSpacing( spacing ); Point3D origin = this->GetPointFromXMLNode(geoElement->FirstChildElement("Origin")); planeGeo->SetOrigin( origin ); planarFigure->SetGeometry2D(planeGeo); } catch (...) { } } TiXmlElement* cpElement = pfElement->FirstChildElement("ControlPoints"); bool first = true; if (cpElement != NULL) for( TiXmlElement* vertElement = cpElement->FirstChildElement("Vertex"); vertElement != NULL; vertElement = vertElement->NextSiblingElement("Vertex")) { if (vertElement == NULL) continue; int id = 0; mitk::Point2D::ValueType x = 0.0; mitk::Point2D::ValueType y = 0.0; if (vertElement->QueryIntAttribute("id", &id) == TIXML_WRONG_TYPE) return; // TODO: can we do a better error handling? if (vertElement->QueryFloatAttribute("x", &x) == TIXML_WRONG_TYPE) return; // TODO: can we do a better error handling? if (vertElement->QueryFloatAttribute("y", &y) == TIXML_WRONG_TYPE) return; // TODO: can we do a better error handling? Point2D p; p.SetElement(0, x); p.SetElement(1, y); if (first == true) // needed to set m_FigurePlaced to true { planarFigure->PlaceFigure(p); first = false; } planarFigure->SetControlPoint(id, p, true); } // Calculate feature quantities of this PlanarFigure planarFigure->EvaluateFeatures(); // Make sure that no control point is currently selected planarFigure->DeselectControlPoint(); // \TODO: what about m_FigurePlaced and m_SelectedControlPoint ?? this->SetNthOutput( this->GetNumberOfOutputs(), planarFigure ); // add planarFigure as new output of this filter } m_Success = true; } mitk::Point3D mitk::PlanarFigureReader::GetPointFromXMLNode(TiXmlElement* e) { if (e == NULL) throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling? mitk::Point3D point; mitk::ScalarType p(-1.0); if (e->QueryFloatAttribute("x", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? point.SetElement(0, p); if (e->QueryFloatAttribute("y", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? point.SetElement(1, p); if (e->QueryFloatAttribute("z", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? point.SetElement(2, p); return point; } mitk::Vector3D mitk::PlanarFigureReader::GetVectorFromXMLNode(TiXmlElement* e) { if (e == NULL) throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling? mitk::Vector3D vector; mitk::ScalarType p(-1.0); if (e->QueryFloatAttribute("x", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? vector.SetElement(0, p); if (e->QueryFloatAttribute("y", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? vector.SetElement(1, p); if (e->QueryFloatAttribute("z", &p) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? vector.SetElement(2, p); return vector; } mitk::PlanarFigureReader::DoubleList mitk::PlanarFigureReader::GetDoubleAttributeListFromXMLNode(TiXmlElement* e, const char *attributeNameBase, unsigned int count) { DoubleList list; if (e == NULL) throw std::invalid_argument("node invalid"); // TODO: can we do a better error handling? for ( unsigned int i = 0; i < count; ++i ) { mitk::ScalarType p(-1.0); std::stringstream attributeName; attributeName << attributeNameBase << i; if (e->QueryFloatAttribute( attributeName.str().c_str(), &p ) == TIXML_WRONG_TYPE) throw std::invalid_argument("node malformatted"); // TODO: can we do a better error handling? list.push_back( p ); } return list; } void mitk::PlanarFigureReader::GenerateOutputInformation() { } int mitk::PlanarFigureReader::CanReadFile ( const char *name ) { if (std::string(name).empty()) return false; return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(name)) == ".pf"); //assume, we can read all .pf files //TiXmlDocument document(name); //if (document.LoadFile() == false) // return false; //return (document.FirstChildElement("PlanarFigure") != NULL); } bool mitk::PlanarFigureReader::CanReadFile(const std::string filename, const std::string, const std::string) { if (filename.empty()) return false; return (itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameLastExtension(filename)) == ".pf"); //assume, we can read all .pf files //TiXmlDocument document(filename); //if (document.LoadFile() == false) // return false; //return (document.FirstChildElement("PlanarFigure") != NULL); } void mitk::PlanarFigureReader::ResizeOutputs( const unsigned int& num ) { unsigned int prevNum = this->GetNumberOfOutputs(); this->SetNumberOfOutputs( num ); for ( unsigned int i = prevNum; i < num; ++i ) { this->SetNthOutput( i, this->MakeOutput( i ).GetPointer() ); } } diff --git a/Modules/PlanarFigure/files.cmake b/Modules/PlanarFigure/files.cmake index 931d605501..4572a68d2c 100644 --- a/Modules/PlanarFigure/files.cmake +++ b/Modules/PlanarFigure/files.cmake @@ -1,24 +1,25 @@ SET(CPP_FILES Algorithms/mitkImageToPlanarFigureFilter.cpp Algorithms/mitkPlanarFigureObjectFactory.cpp Algorithms/mitkPlanarFigureSource.cpp Algorithms/mitkPlanarFigureToPlanarFigureFilter.cpp DataManagement/mitkPlanarAngle.cpp DataManagement/mitkPlanarCircle.cpp DataManagement/mitkPlanarCross.cpp DataManagement/mitkPlanarFigure.cpp DataManagement/mitkPlanarFourPointAngle.cpp DataManagement/mitkPlanarLine.cpp DataManagement/mitkPlanarArrow.cpp DataManagement/mitkPlanarPolygon.cpp + DataManagement/mitkPlanarSubdivisionPolygon.cpp DataManagement/mitkPlanarRectangle.cpp DataManagement/mitkPlanarFigureControlPointStyleProperty.cpp IO/mitkPlanarFigureIOFactory.cpp IO/mitkPlanarFigureReader.cpp IO/mitkPlanarFigureWriter.cpp IO/mitkPlanarFigureWriterFactory.cpp IO/mitkPlanarFigureSerializer.cpp IO/mitkPlanarFigureSubclassesSerializer.cpp Interactions/mitkPlanarFigureInteractor.cpp Rendering/mitkPlanarFigureMapper2D.cpp )