diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp index 32d3781458..f559a6ffd7 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.cpp @@ -1,184 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarAngle.h" #include "mitkPlaneGeometry.h" mitk::PlanarAngle::PlanarAngle() : FEATURE_ID_ANGLE( this->AddFeature( "Angle", "deg" ) ) { // Start with two control points this->ResetNumberOfControlPoints( 2 ); this->SetNumberOfPolyLines(1); this->SetNumberOfHelperPolyLines(1); m_HelperPolyLinesToBePainted->InsertElement( 0, false ); } mitk::PlanarAngle::~PlanarAngle() { } void mitk::PlanarAngle::GeneratePolyLine() { this->ClearPolyLines(); for ( unsigned int i=0; iGetNumberOfControlPoints(); i++ ) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); } void mitk::PlanarAngle::GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) { // Generate helper-poly-line for angle if ( this->GetNumberOfControlPoints() < 3) { m_HelperPolyLinesToBePainted->SetElement(0, false); return; //We do not need to draw an angle as there are no two arms yet } this->ClearHelperPolyLines(); const Point2D centerPoint = this->GetControlPoint( 1 ); const Point2D boundaryPointOne = this->GetControlPoint( 0 ); const Point2D boundaryPointTwo = this->GetControlPoint( 2 ); double radius = centerPoint.EuclideanDistanceTo( boundaryPointOne ); if ( radius > centerPoint.EuclideanDistanceTo( boundaryPointTwo ) ) { radius = centerPoint.EuclideanDistanceTo( boundaryPointTwo ); } //Fixed size radius depending on screen size for the angle double nonScalingRadius = displayHeight * mmPerDisplayUnit * 0.05; if (nonScalingRadius > radius) { m_HelperPolyLinesToBePainted->SetElement(0, false); return; //if the arc has a radius that is longer than the shortest arm it should not be painted } m_HelperPolyLinesToBePainted->SetElement(0, true); radius = nonScalingRadius; double angle = this->GetQuantity( FEATURE_ID_ANGLE ); //Determine from which arm the angle should be drawn Vector2D v0 = boundaryPointOne - centerPoint; Vector2D v1 = boundaryPointTwo - centerPoint; Vector2D v2; v2[0] = 1.0; v2[1] = 0.0; v0[0] = v0[0] * cos( 0.001 ) - v0[1] * sin( 0.001 ); //rotate one arm a bit v0[1] = v0[0] * sin( 0.001 ) + v0[1] * cos( 0.001 ); v0.Normalize(); v1.Normalize(); double testAngle = acos( v0 * v1 ); //if the rotated arm is closer to the other arm than before it is the one from which we start drawing //else we start drawing from the other arm (we want to draw in the mathematically positive direction) if( angle > testAngle ) { v1[0] = v0[0] * cos( -0.001 ) - v0[1] * sin( -0.001 ); v1[1] = v0[0] * sin( -0.001 ) + v0[1] * cos( -0.001 ); //We determine if the arm is mathematically forward or backward //assuming we rotate between -pi and pi if ( acos( v0 * v2 ) > acos ( v1 * v2 )) { testAngle = acos( v1 * v2 ); } else { testAngle = -acos( v1 * v2 ); } } else { v0[0] = v1[0] * cos( -0.001 ) - v1[1] * sin( -0.001 ); v0[1] = v1[0] * sin( -0.001 ) + v1[1] * cos( -0.001 ); //We determine if the arm is mathematically forward or backward //assuming we rotate between -pi and pi if ( acos( v0 * v2 ) < acos ( v1 * v2 )) { testAngle = acos( v1 * v2 ); } else { testAngle = -acos( v1 * v2 ); } } // Generate poly-line with 16 segments for ( int t = 0; t < 16; ++t ) { double alpha = (double) t * angle / 15.0 + testAngle; Point2D polyLinePoint; polyLinePoint[0] = centerPoint[0] + radius * cos( alpha ); polyLinePoint[1] = centerPoint[1] + radius * sin( alpha ); this->AppendPointToHelperPolyLine(0, polyLinePoint); } } void mitk::PlanarAngle::EvaluateFeaturesInternal() { if ( this->GetNumberOfControlPoints() < 3 ) { // Angle not yet complete. return; } // Calculate angle between lines const Point2D &p0 = this->GetControlPoint( 0 ); const Point2D &p1 = this->GetControlPoint( 1 ); const Point2D &p2 = this->GetControlPoint( 2 ); Vector2D v0 = p1 - p0; Vector2D v1 = p1 - p2; v0.Normalize(); v1.Normalize(); double angle = acos( v0 * v1 ); this->SetQuantity( FEATURE_ID_ANGLE, angle ); } void mitk::PlanarAngle::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } -bool mitk::PlanarAngle::Equals(mitk::PlanarFigure& other) +bool mitk::PlanarAngle::Equals(const PlanarFigure &other) const { - mitk::PlanarAngle* otherAngle = dynamic_cast(&other); + const mitk::PlanarAngle* otherAngle = dynamic_cast(&other); if ( otherAngle ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h index f016977bfd..ab2a69c49c 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarAngle.h @@ -1,90 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_ANGLE_H_ #define _MITK_PLANAR_ANGLE_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure to display an angle * through three control points */ class MitkPlanarFigure_EXPORT PlanarAngle : public PlanarFigure { public: mitkClassMacro( PlanarAngle, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) public: // Feature identifiers const unsigned int FEATURE_ID_ANGLE; /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); /** \brief Angle has 3 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 3; } /** \brief Angle has 3 control points per definition. */ unsigned int GetMaximumNumberOfControlPoints() const { return 3; } - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarAngle(); virtual ~PlanarAngle(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; private: }; } // namespace mitk #endif //_MITK_PLANAR_ANGLE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp index 77e11929c5..cab3d12c23 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.cpp @@ -1,136 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarBezierCurve.h" #include #include mitk::PlanarBezierCurve::PlanarBezierCurve() : FEATURE_ID_LENGTH(Superclass::AddFeature("Length", "mm")), m_NumberOfSegments(100) { this->ResetNumberOfControlPoints(2); this->SetNumberOfPolyLines(1); this->SetNumberOfHelperPolyLines(1); } mitk::PlanarBezierCurve::~PlanarBezierCurve() { } void mitk::PlanarBezierCurve::EvaluateFeaturesInternal() { double length = 0.0; for (unsigned int i = 0; i < m_NumberOfSegments; ++i) length += static_cast(m_PolyLines[0][i]).EuclideanDistanceTo(static_cast(m_PolyLines[0][i + 1])); this->SetQuantity(FEATURE_ID_LENGTH, length); } unsigned int mitk::PlanarBezierCurve::GetNumberOfSegments() const { return m_NumberOfSegments; } void mitk::PlanarBezierCurve::SetNumberOfSegments(unsigned int numSegments) { m_NumberOfSegments = std::max(1U, numSegments); if (this->IsPlaced()) { this->GeneratePolyLine(); this->Modified(); } } void mitk::PlanarBezierCurve::GenerateHelperPolyLine(double, unsigned int) { this->ClearHelperPolyLines(); unsigned int numHelperPolyLinePoints = m_ControlPoints.size(); for (unsigned int i = 0; i < numHelperPolyLinePoints; ++i) this->AppendPointToHelperPolyLine(0, m_ControlPoints[i]); } void mitk::PlanarBezierCurve::GeneratePolyLine() { this->ClearPolyLines(); const unsigned int numPolyLinePoints = m_NumberOfSegments + 1; for (unsigned int i = 0; i < numPolyLinePoints; ++i) this->AppendPointToPolyLine(0, this->ComputeDeCasteljauPoint(i / static_cast(m_NumberOfSegments))); } mitk::Point2D mitk::PlanarBezierCurve::ComputeDeCasteljauPoint(mitk::ScalarType t) { unsigned int n = m_ControlPoints.size() - 1; if (m_DeCasteljauPoints.size() != n) m_DeCasteljauPoints.resize(n); for (unsigned int i = 0; i < n; ++i) { m_DeCasteljauPoints[i][0] = (1 - t) * m_ControlPoints[i][0] + t * m_ControlPoints[i + 1][0]; m_DeCasteljauPoints[i][1] = (1 - t) * m_ControlPoints[i][1] + t * m_ControlPoints[i + 1][1]; } for (--n; n > 0; --n) { for (unsigned int i = 0; i < n; ++i) { m_DeCasteljauPoints[i][0] = (1 - t) * m_DeCasteljauPoints[i][0] + t * m_DeCasteljauPoints[i + 1][0]; m_DeCasteljauPoints[i][1] = (1 - t) * m_DeCasteljauPoints[i][1] + t * m_DeCasteljauPoints[i + 1][1]; } } return m_DeCasteljauPoints[0]; } unsigned int mitk::PlanarBezierCurve::GetMaximumNumberOfControlPoints() const { return std::numeric_limits::max(); } unsigned int mitk::PlanarBezierCurve::GetMinimumNumberOfControlPoints() const { return 2; } bool mitk::PlanarBezierCurve::IsHelperToBePainted(unsigned int index) { return index == 0 && m_ControlPoints.size() > 2; } -bool mitk::PlanarBezierCurve::Equals(mitk::PlanarFigure& other) +bool mitk::PlanarBezierCurve::Equals(const PlanarFigure &other) const { - mitk::PlanarBezierCurve* otherBezierCurve = dynamic_cast(&other); + const mitk::PlanarBezierCurve* otherBezierCurve = dynamic_cast(&other); if ( otherBezierCurve ) { if( this->m_NumberOfSegments != otherBezierCurve->m_NumberOfSegments ) return false; if( this->m_DeCasteljauPoints != otherBezierCurve->m_DeCasteljauPoints ) return false; return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h index 71bb4bf5da..905c6fc1fe 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarBezierCurve.h @@ -1,62 +1,62 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPlanarBezierCurve_h #define mitkPlanarBezierCurve_h #include #include namespace mitk { class MitkPlanarFigure_EXPORT PlanarBezierCurve : public PlanarFigure { public: mitkClassMacro(PlanarBezierCurve, PlanarFigure) itkFactorylessNewMacro(Self) itkCloneMacro(Self) unsigned int GetNumberOfSegments() const; void SetNumberOfSegments(unsigned int numSegments); virtual unsigned int GetMaximumNumberOfControlPoints() const; virtual unsigned int GetMinimumNumberOfControlPoints() const; virtual bool IsHelperToBePainted(unsigned int index); const unsigned int FEATURE_ID_LENGTH; - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other)const; protected: PlanarBezierCurve(); virtual ~PlanarBezierCurve(); mitkCloneMacro(Self) virtual void EvaluateFeaturesInternal(); virtual void GenerateHelperPolyLine(double, unsigned int); virtual void GeneratePolyLine(); private: Point2D ComputeDeCasteljauPoint(ScalarType t); std::vector m_DeCasteljauPoints; unsigned int m_NumberOfSegments; }; } #endif diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp index d465aa71bf..d6e248be95 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.cpp @@ -1,188 +1,188 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarCircle.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" mitk::PlanarCircle::PlanarCircle() : FEATURE_ID_RADIUS( this->AddFeature( "Radius", "mm" ) ), FEATURE_ID_DIAMETER( this->AddFeature( "Diameter", "mm" ) ), FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) ), m_MinRadius(0), m_MaxRadius(100), m_MinMaxRadiusContraintsActive(false) { // Circle has two control points this->ResetNumberOfControlPoints( 2 ); this->SetNumberOfPolyLines( 1 ); this->SetProperty( "closed", mitk::BoolProperty::New(true) ); } mitk::PlanarCircle::~PlanarCircle() { } bool mitk::PlanarCircle::SetControlPoint( unsigned int index, const Point2D &point, bool /*createIfDoesNotExist*/ ) { // moving center point if(index == 0) { const Point2D ¢erPoint = GetControlPoint( 0 ); Point2D boundaryPoint = GetControlPoint( 1 ); vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector()); boundaryPoint[0] += vec[0]; boundaryPoint[1] += vec[1]; PlanarFigure::SetControlPoint( 0, point ); PlanarFigure::SetControlPoint( 1, boundaryPoint ); return true; } else if ( index == 1 ) { PlanarFigure::SetControlPoint( index, point ); return true; } return false; } mitk::Point2D mitk::PlanarCircle::ApplyControlPointConstraints(unsigned int index, const Point2D &point) { if ( this->GetPlaneGeometry() == NULL ) { return point; } Point2D indexPoint; this->GetPlaneGeometry()->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = this->GetPlaneGeometry()->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; this->GetPlaneGeometry()->IndexToWorld( indexPoint, constrainedPoint ); if(m_MinMaxRadiusContraintsActive) { if( index != 0) { const Point2D ¢erPoint = this->GetControlPoint(0); double euclideanDinstanceFromCenterToPoint1 = centerPoint.EuclideanDistanceTo(point); Vector2D vectorProjectedPoint; vectorProjectedPoint = point - centerPoint; vectorProjectedPoint.Normalize(); if( euclideanDinstanceFromCenterToPoint1 > m_MaxRadius ) { vectorProjectedPoint *= m_MaxRadius; constrainedPoint = centerPoint; constrainedPoint += vectorProjectedPoint; } else if( euclideanDinstanceFromCenterToPoint1 < m_MinRadius ) { vectorProjectedPoint *= m_MinRadius; constrainedPoint = centerPoint; constrainedPoint += vectorProjectedPoint; } } } return constrainedPoint; } void mitk::PlanarCircle::GeneratePolyLine() { // TODO: start circle at specified boundary point... // clear the PolyLine-Contrainer, it will be reconstructed soon enough... this->ClearPolyLines(); const Point2D ¢erPoint = GetControlPoint( 0 ); const Point2D &boundaryPoint = GetControlPoint( 1 ); double radius = centerPoint.EuclideanDistanceTo( boundaryPoint ); // Generate poly-line with 64 segments for ( int t = 0; t < 64; ++t ) { double alpha = (double) t * vnl_math::pi / 32.0; // construct the new polyline point ... Point2D polyLinePoint; polyLinePoint[0] = centerPoint[0] + radius * cos( alpha ); polyLinePoint[1] = centerPoint[1] + radius * sin( alpha ); // ... and append it to the PolyLine. // No extending supported here, so we can set the index of the PolyLineElement to '0' this->AppendPointToPolyLine(0, polyLinePoint); } } void mitk::PlanarCircle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A circle does not require a helper object } void mitk::PlanarCircle::EvaluateFeaturesInternal() { // Calculate circle radius and area const Point3D &p0 = this->GetWorldControlPoint( 0 ); const Point3D &p1 = this->GetWorldControlPoint( 1 ); double radius = p0.EuclideanDistanceTo( p1 ); double area = vnl_math::pi * radius * radius; this->SetQuantity( FEATURE_ID_RADIUS, radius ); this->SetQuantity( FEATURE_ID_DIAMETER, 2*radius ); this->SetQuantity( FEATURE_ID_AREA, area ); } void mitk::PlanarCircle::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } bool mitk::PlanarCircle::SetCurrentControlPoint( const Point2D& point ) { if ( m_SelectedControlPoint < 0 ) { m_SelectedControlPoint = 1; } return this->SetControlPoint( m_SelectedControlPoint, point, false); } - bool mitk::PlanarCircle::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarCircle::Equals(const PlanarFigure &other) const { - mitk::PlanarCircle* otherCircle = dynamic_cast(&other); + const mitk::PlanarCircle* otherCircle = dynamic_cast(&other); if ( otherCircle ) { return Superclass::Equals(other); } else { return false; } - } \ No newline at end of file + } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h index c6fbd7e080..8e40da1975 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCircle.h @@ -1,139 +1,139 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_CIRCLE_H_ #define _MITK_PLANAR_CIRCLE_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a circle * through two control points */ class MitkPlanarFigure_EXPORT PlanarCircle : public PlanarFigure { public: mitkClassMacro( PlanarCircle, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = false ); /** \brief Circle has 2 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 2; } /** \brief Circle has 2 control points per definition. */ unsigned int GetMaximumNumberOfControlPoints() const { return 2; } /** \brief Sets the minimum radius */ void SetMinimumRadius( double radius ) { m_MinRadius = radius; } /** \brief Gets the minimum radius */ double GetMinimumRadius() { return m_MinRadius; } /** \brief Sets the maximum radius */ void SetMaximumRadius( double radius ) { m_MaxRadius = radius; } /** \brief Gets the minimum radius */ double GetMaximumRadius() { return m_MaxRadius; } void ActivateMinMaxRadiusContstraints( bool active ) { m_MinMaxRadiusContraintsActive = active; } virtual bool SetCurrentControlPoint( const Point2D& point ); - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarCircle(); virtual ~PlanarCircle(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Spatially constrain control points of second (orthogonal) line */ virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point ); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; // Feature identifiers const unsigned int FEATURE_ID_RADIUS; const unsigned int FEATURE_ID_DIAMETER; const unsigned int FEATURE_ID_AREA; //Member variables: double m_MinRadius; double m_MaxRadius; bool m_MinMaxRadiusContraintsActive; private: }; } // namespace mitk #endif //_MITK_PLANAR_CIRCLE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp index d3be5e13af..7ed28a6cc3 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.cpp @@ -1,356 +1,356 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarCross.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" mitk::PlanarCross::PlanarCross() : FEATURE_ID_LONGESTDIAMETER( this->AddFeature( "Longest Axis", "mm" ) ), FEATURE_ID_SHORTAXISDIAMETER( this->AddFeature( "Short Axis", "mm" ) ) { // Cross has two control points at the beginning this->ResetNumberOfControlPoints( 2 ); // Create property for SingleLineMode (default: false) this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( false ) ); // Create helper polyline object (for drawing the orthogonal orientation line) this->SetNumberOfHelperPolyLines( 1 ); m_HelperPolyLinesToBePainted->InsertElement( 0, false ); } mitk::PlanarCross::~PlanarCross() { } void mitk::PlanarCross::SetSingleLineMode( bool singleLineMode ) { this->SetProperty( "SingleLineMode", mitk::BoolProperty::New( singleLineMode ) ); this->Modified(); } bool mitk::PlanarCross::GetSingleLineMode() const { mitk::BoolProperty* singleLineMode = dynamic_cast< mitk::BoolProperty* >( this->GetProperty( "SingleLineMode" ).GetPointer() ); if ( singleLineMode != NULL ) { return singleLineMode->GetValue(); } return false; } bool mitk::PlanarCross::ResetOnPointSelect() { if ( this->GetSingleLineMode() ) { // In single line mode --> nothing to reset return false; } switch ( m_SelectedControlPoint ) { default: // Nothing selected --> nothing to reset return false; case 0: { // Control point 0 selected: exchange points 0 and 1 Point2D tmpPoint = this->GetControlPoint( 0 ); this->SetControlPoint( 0, this->GetControlPoint( 1 ) ); this->SetControlPoint( 1, tmpPoint ); // FALLS THROUGH! } case 1: { // Control point 0 or 1 selected: reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } case 2: { // Control point 2 selected: replace point 0 with point 3 and point 1 with point 2 this->SetControlPoint( 0, this->GetControlPoint( 3 ) ); this->SetControlPoint( 1, this->GetControlPoint( 2 ) ); // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } case 3: { // Control point 3 selected: replace point 0 with point 2 and point 1 with point 3 this->SetControlPoint( 0, this->GetControlPoint( 2 ) ); this->SetControlPoint( 1, this->GetControlPoint( 3 ) ); // Adjust selected control point, reset number of control points to two this->ResetNumberOfControlPoints( 2 ); this->SelectControlPoint( 1 ); return true; } } } unsigned int mitk::PlanarCross::GetNumberOfFeatures() const { if ( this->GetSingleLineMode() || (this->GetNumberOfControlPoints() < 4) ) { return 1; } else { return 2; } } mitk::Point2D mitk::PlanarCross::ApplyControlPointConstraints( unsigned int index, const Point2D& point ) { // Apply spatial constraints from superclass and from this class until the resulting constrained // point converges. Although not an optimal implementation, this iterative approach // helps to respect both constraints from the superclass and from this class. Without this, // situations may occur where control points are constrained by the superclass, but again // moved out of the superclass bounds by the subclass, or vice versa. unsigned int count = 0; // ensures stop of approach if point does not converge in reasonable time Point2D confinedPoint = point; Point2D superclassConfinedPoint; do { superclassConfinedPoint = Superclass::ApplyControlPointConstraints( index, confinedPoint ); confinedPoint = this->InternalApplyControlPointConstraints( index, superclassConfinedPoint ); ++count; } while ( (confinedPoint.EuclideanDistanceTo( superclassConfinedPoint ) > mitk::eps) && (count < 32) ); return confinedPoint; } mitk::Point2D mitk::PlanarCross::InternalApplyControlPointConstraints( unsigned int index, const Point2D& point ) { // Apply constraints depending on current interaction state switch ( index ) { case 2: { // Check if 3rd control point is outside of the range (2D area) defined by the first // line (via the first two control points); if it is outside, clip it to the bounds const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = point - p1; double dotProduct = n1 * v1; Point2D crossPoint = p1 + n1 * dotProduct;; Vector2D crossVector = point - crossPoint; if ( dotProduct < 0.0 ) { // Out-of-bounds on the left: clip point to left boundary return (p1 + crossVector); } else if ( dotProduct > p2.EuclideanDistanceTo( p1 ) ) { // Out-of-bounds on the right: clip point to right boundary return (p2 + crossVector); } else { // Pass back original point return point; } } case 3: { // Constrain 4th control point so that with the 3rd control point it forms // a line orthogonal to the first line (constraint 1); the 4th control point // must lie on the opposite side of the line defined by the first two control // points than the 3rd control point (constraint 2) const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); const Point2D p3 = this->GetControlPoint( 2 ); // Calculate distance of original point from orthogonal line the corrected // point should lie on to project the point onto this line Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = point - p3; double dotProduct1 = n1 * v1; Point2D pointOnLine = point - n1 * dotProduct1; // Project new point onto line [p1, p2] Vector2D v2 = pointOnLine - p1; double dotProduct2 = n1 * v2; Point2D crossingPoint = p1 + n1 * dotProduct2; // Determine whether the projected point on the line, or the crossing point should be // used (according to the second constraint in the comment above) if ( (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > crossingPoint.SquaredEuclideanDistanceTo( p3 )) && (pointOnLine.SquaredEuclideanDistanceTo( p3 ) > pointOnLine.SquaredEuclideanDistanceTo( crossingPoint )) ) { return pointOnLine; } else { return crossingPoint; } } default: return point; } } void mitk::PlanarCross::GeneratePolyLine() { this->SetNumberOfPolyLines(1); this->ClearPolyLines(); if (this->GetNumberOfControlPoints() > 2) this->SetNumberOfPolyLines( 2 ); for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i) { if (i < 2) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); if (i > 1) this->AppendPointToPolyLine(1, this->GetControlPoint(i)); } } void mitk::PlanarCross::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // Generate helper polyline (orientation line orthogonal to first line) // if the third control point is currently being set if ( this->GetNumberOfControlPoints() != 3 ) { m_HelperPolyLinesToBePainted->SetElement( 0, false ); return; } m_HelperPolyLinesToBePainted->SetElement( 0, true ); this->ClearHelperPolyLines(); // Calculate cross point of first line (p1 to p2) and orthogonal line through // the third control point (p3) const Point2D p1 = this->GetControlPoint( 0 ); const Point2D p2 = this->GetControlPoint( 1 ); const Point2D p3 = this->GetControlPoint( 2 ); Vector2D n1 = p2 - p1; n1.Normalize(); Vector2D v1 = p3 - p1; Point2D crossPoint = p1 + n1 * (n1 * v1); Vector2D v2 = crossPoint - p3; if ( v2.GetNorm() < 1.0 ) { // If third point is on the first line, draw orthogonal "infinite" line // through cross point on line Vector2D v0; v0[0] = n1[1]; v0[1] = -n1[0]; this->AppendPointToHelperPolyLine(0, Point2D(p3 - v0 * 10000.0)); this->AppendPointToHelperPolyLine(0, Point2D(p3 + v0 * 10000.0)); } else { // Else, draw orthogonal line starting from third point and crossing the // first line, open-ended only on the other side this->AppendPointToHelperPolyLine(0, p3); this->AppendPointToHelperPolyLine(0, Point2D(p3 + v2 * 10000.0)); } } void mitk::PlanarCross::EvaluateFeaturesInternal() { // Calculate length of first line const Point3D &p0 = this->GetWorldControlPoint( 0 ); const Point3D &p1 = this->GetWorldControlPoint( 1 ); double l1 = p0.EuclideanDistanceTo( p1 ); // Calculate length of second line double l2 = 0.0; if ( !this->GetSingleLineMode() && (this->GetNumberOfControlPoints() > 3) ) { const Point3D &p2 = this->GetWorldControlPoint( 2 ); const Point3D &p3 = this->GetWorldControlPoint( 3 ); l2 = p2.EuclideanDistanceTo( p3 ); } double longestDiameter; double shortAxisDiameter; if ( l1 > l2 ) { longestDiameter = l1; shortAxisDiameter = l2; } else { longestDiameter = l2; shortAxisDiameter = l1; } this->SetQuantity( FEATURE_ID_LONGESTDIAMETER, longestDiameter ); this->SetQuantity( FEATURE_ID_SHORTAXISDIAMETER, shortAxisDiameter ); } void mitk::PlanarCross::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } - bool mitk::PlanarCross::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarCross::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarCross* otherCross = dynamic_cast(&other); + const mitk::PlanarCross* otherCross = dynamic_cast(&other); if ( otherCross ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h index c8cdcd2a65..83a667e4df 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarCross.h @@ -1,133 +1,133 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_CROSS_H_ #define _MITK_PLANAR_CROSS_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure modeling a cross with two orthogonal lines * on a plane. * * The cross consists of two two orthogonal lines, which are defined by four control points * lying on a plane. The two control points of the first line are freely placable within * the bounds of the underlying 2D geometry, while the two control points of the second line * are ensured to meet the following constraints: * * 1.) The lines must be orthogonal to each other * 2.) The second line must lie within the 2D area defined by the first line * 3.) The two lines must intersect (at least with their boundaries) * * When placing the second line interactively, a graphical helper polyline is provided to the * user to indicate the position and orthogonal orientation of the line if it would be placed * at the current mouse position. * * When modifying one of the lines by interactively moving its control points, the respective * other line is deleted and the user is prompted to draw it again. * * The class provide a special mode for drawing single lines (SingleLineModeOn/Off); in this * case, interaction stops after the first line has been placed. * * The class provides the lengths of both lines via the "feature" interface, ordered by size. * * \sa PlanarFigureMapper2D */ class MitkPlanarFigure_EXPORT PlanarCross : public PlanarFigure { public: mitkClassMacro( PlanarCross, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an * orthogonal cross. */ void SetSingleLineMode( bool singleLineMode ); /** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an * orthogonal cross. */ bool GetSingleLineMode() const; /** \brief Indicates whether the PlanarFigure shall represent only a single line instead of an * orthogonal cross. */ itkBooleanMacro( SingleLineMode ); // No need to reimplement; calls SetSingleLineMode() /** \brief PlanarCross has either two or four control points, depending on the operation mode. */ unsigned int GetMinimumNumberOfControlPoints() const { return this->GetSingleLineMode() ? 2 : 4; } /** \brief PlanarCross has either two or four control points, depending on the operation mode. */ unsigned int GetMaximumNumberOfControlPoints() const { return this->GetSingleLineMode() ? 2 : 4; } /** \brief The cross shall be reset to a single line when a control point is selected. */ virtual bool ResetOnPointSelect(); /** \brief Returns the number of features available for this PlanarCross (1 or 2). */ virtual unsigned int GetNumberOfFeatures() const; - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarCross(); virtual ~PlanarCross(); mitkCloneMacro(Self); /** \brief Spatially constrain control points of second (orthogonal) line */ virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point ); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; // Feature identifiers const unsigned int FEATURE_ID_LONGESTDIAMETER; const unsigned int FEATURE_ID_SHORTAXISDIAMETER; private: /** Internal method for applying spatial constraints. */ virtual Point2D InternalApplyControlPointConstraints( unsigned int index, const Point2D& point ); }; } // namespace mitk #endif //_MITK_PLANAR_CROSS_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp index 223249639f..5068f00549 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.cpp @@ -1,270 +1,270 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarDoubleEllipse.h" #include #include mitk::PlanarDoubleEllipse::PlanarDoubleEllipse() : FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")), FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")), FEATURE_ID_THICKNESS(Superclass::AddFeature("Thickness", "mm")), m_NumberOfSegments(64), m_ConstrainCircle(true), m_ConstrainThickness(true) { this->ResetNumberOfControlPoints(4); this->SetNumberOfPolyLines(2); this->SetProperty("closed", mitk::BoolProperty::New(true)); } mitk::PlanarDoubleEllipse::~PlanarDoubleEllipse() { } mitk::Point2D mitk::PlanarDoubleEllipse::ApplyControlPointConstraints(unsigned int index, const Point2D& point) { if (index == 2 && !m_ConstrainCircle) { Point2D centerPoint = this->GetControlPoint(0); Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint; Vector2D minorDirection; minorDirection[0] = outerMajorVector[1]; minorDirection[1] = -outerMajorVector[0]; minorDirection.Normalize(); double outerMajorRadius = outerMajorVector.GetNorm(); double innerMajorRadius = (this->GetControlPoint(3) - centerPoint).GetNorm(); ScalarType radius = std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius)); return centerPoint + minorDirection * radius; } else if (index == 3 && !m_ConstrainThickness) { Point2D centerPoint = this->GetControlPoint(0); Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint; double outerMajorRadius = outerMajorVector.GetNorm(); double outerMinorRadius = (this->GetControlPoint(2) - centerPoint).GetNorm(); ScalarType radius = std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius)); outerMajorVector.Normalize(); return centerPoint - outerMajorVector * radius; } return point; } void mitk::PlanarDoubleEllipse::EvaluateFeaturesInternal() { Point2D centerPoint = this->GetControlPoint(0); ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(1)); this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * outerMajorRadius); this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2))); this->SetQuantity(FEATURE_ID_THICKNESS, outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(3))); } void mitk::PlanarDoubleEllipse::GenerateHelperPolyLine(double, unsigned int) { } void mitk::PlanarDoubleEllipse::GeneratePolyLine() { this->ClearPolyLines(); Point2D centerPoint = this->GetControlPoint(0); Point2D outerMajorPoint = this->GetControlPoint(1); Vector2D direction = outerMajorPoint - centerPoint; direction.Normalize(); const ScalarType deltaAngle = vnl_math::pi / (m_NumberOfSegments / 2); int start = 0; int end = m_NumberOfSegments; if (direction[1] < 0.0) { direction[0] = -direction[0]; end = m_NumberOfSegments / 2; start = -end; } vnl_matrix_fixed rotation; rotation[1][0] = std::sin(std::acos(direction[0])); rotation[0][0] = direction[0]; rotation[1][1] = direction[0]; rotation[0][1] = -rotation[1][0]; ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(outerMajorPoint); ScalarType outerMinorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)); ScalarType innerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(3)); ScalarType innerMinorRadius = innerMajorRadius - (outerMajorRadius - outerMinorRadius); ScalarType angle; ScalarType cosAngle; ScalarType sinAngle; vnl_vector_fixed vector; Point2D point; for (int i = start; i < end; ++i) { angle = i * deltaAngle; cosAngle = std::cos(angle); sinAngle = std::sin(angle); vector[0] = outerMajorRadius * cosAngle; vector[1] = outerMinorRadius * sinAngle; vector = rotation * vector; point[0] = centerPoint[0] + vector[0]; point[1] = centerPoint[1] + vector[1]; this->AppendPointToPolyLine(0, point); vector[0] = innerMajorRadius * cosAngle; vector[1] = innerMinorRadius * sinAngle; vector = rotation * vector; point[0] = centerPoint[0] + vector[0]; point[1] = centerPoint[1] + vector[1]; this->AppendPointToPolyLine(1, point); } } unsigned int mitk::PlanarDoubleEllipse::GetNumberOfSegments() const { return m_NumberOfSegments; } void mitk::PlanarDoubleEllipse::SetNumberOfSegments(unsigned int numSegments) { m_NumberOfSegments = std::max(4U, numSegments); if (this->IsPlaced()) { this->GeneratePolyLine(); this->Modified(); } } unsigned int mitk::PlanarDoubleEllipse::GetMaximumNumberOfControlPoints() const { return 4; } unsigned int mitk::PlanarDoubleEllipse::GetMinimumNumberOfControlPoints() const { return 4; } bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D& point, bool createIfDoesNotExist) { switch (index) { case 0: { Point2D centerPoint = this->GetControlPoint(0); Vector2D vector = point - centerPoint; Superclass::SetControlPoint(0, point, createIfDoesNotExist); Superclass::SetControlPoint(1, this->GetControlPoint(1) + vector, createIfDoesNotExist); Superclass::SetControlPoint(2, this->GetControlPoint(2) + vector, createIfDoesNotExist); Superclass::SetControlPoint(3, this->GetControlPoint(3) + vector, createIfDoesNotExist); break; } case 1: { Vector2D vector = point - this->GetControlPoint(1); Superclass::SetControlPoint(1, point, createIfDoesNotExist); Point2D centerPoint = this->GetControlPoint(0); Vector2D outerMajorVector = point - centerPoint; Vector2D outerMinorVector; outerMinorVector[0] = outerMajorVector[1]; outerMinorVector[1] = -outerMajorVector[0]; if (!m_ConstrainCircle) { outerMinorVector.Normalize(); outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)); } Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist); Vector2D innerMajorVector = outerMajorVector; if (!m_ConstrainThickness) { innerMajorVector.Normalize(); innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(3) - vector); } Superclass::SetControlPoint(3, centerPoint - innerMajorVector, createIfDoesNotExist); break; } case 2: { m_ConstrainCircle = false; Superclass::SetControlPoint(2, point, createIfDoesNotExist); break; } case 3: { m_ConstrainThickness = false; Superclass::SetControlPoint(3, point, createIfDoesNotExist); break; } default: return false; } return true; } - bool mitk::PlanarDoubleEllipse::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarDoubleEllipse::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarDoubleEllipse* otherDoubleEllipse = dynamic_cast(&other); + const mitk::PlanarDoubleEllipse* otherDoubleEllipse = dynamic_cast(&other); if ( otherDoubleEllipse ) { if( this->m_ConstrainCircle != otherDoubleEllipse->m_ConstrainCircle) return false; if( this->m_ConstrainThickness != otherDoubleEllipse->m_ConstrainThickness) return false; if( this->m_NumberOfSegments != otherDoubleEllipse->m_NumberOfSegments) return false; return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h index b867812cee..7f42148beb 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarDoubleEllipse.h @@ -1,63 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPlanarDoubleEllipse_h #define mitkPlanarDoubleEllipse_h #include #include namespace mitk { class MitkPlanarFigure_EXPORT PlanarDoubleEllipse : public PlanarFigure { public: mitkClassMacro(PlanarDoubleEllipse, PlanarFigure); itkFactorylessNewMacro(Self) itkCloneMacro(Self) unsigned int GetNumberOfSegments() const; void SetNumberOfSegments(unsigned int numSegments); virtual unsigned int GetMaximumNumberOfControlPoints() const; virtual unsigned int GetMinimumNumberOfControlPoints() const; virtual bool SetControlPoint(unsigned int index, const Point2D& point, bool createIfDoesNotExist = true); const unsigned int FEATURE_ID_MAJOR_AXIS; const unsigned int FEATURE_ID_MINOR_AXIS; const unsigned int FEATURE_ID_THICKNESS; - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarDoubleEllipse(); virtual ~PlanarDoubleEllipse(); mitkCloneMacro(Self) virtual mitk::Point2D ApplyControlPointConstraints(unsigned int index, const Point2D& point); virtual void EvaluateFeaturesInternal(); virtual void GenerateHelperPolyLine(double, unsigned int); virtual void GeneratePolyLine(); private: unsigned int m_NumberOfSegments; bool m_ConstrainCircle; bool m_ConstrainThickness; }; } #endif diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp index e6d8d91917..443e89b7f7 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.cpp @@ -1,296 +1,296 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkPlanarEllipse.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include mitk::PlanarEllipse::PlanarEllipse() : FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")), FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")), m_MinRadius(0), m_MaxRadius(100), m_MinMaxRadiusContraintsActive(false), m_TreatAsCircle(true) { // Ellipse has three control points this->ResetNumberOfControlPoints( 4 ); this->SetNumberOfPolyLines( 2 ); this->SetProperty( "closed", mitk::BoolProperty::New(true) ); } mitk::PlanarEllipse::~PlanarEllipse() { } bool mitk::PlanarEllipse::SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist ) { if(index == 0) // moving center point and control points accordingly { const Point2D ¢erPoint = GetControlPoint( 0 ); Point2D boundaryPoint1 = GetControlPoint( 1 ); Point2D boundaryPoint2 = GetControlPoint( 2 ); Point2D boundaryPoint3 = GetControlPoint( 3 ); vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector()); boundaryPoint1[0] += vec[0]; boundaryPoint1[1] += vec[1]; boundaryPoint2[0] += vec[0]; boundaryPoint2[1] += vec[1]; boundaryPoint3[0] += vec[0]; boundaryPoint3[1] += vec[1]; PlanarFigure::SetControlPoint( 0, point, createIfDoesNotExist ); PlanarFigure::SetControlPoint( 1, boundaryPoint1, createIfDoesNotExist ); PlanarFigure::SetControlPoint( 2, boundaryPoint2, createIfDoesNotExist ); PlanarFigure::SetControlPoint( 3, boundaryPoint3, createIfDoesNotExist ); return true; } else if (index < 3) { PlanarFigure::SetControlPoint( index, point, createIfDoesNotExist ); int otherIndex = index+1; if (otherIndex > 2) otherIndex = 1; const Point2D ¢erPoint = GetControlPoint( 0 ); Point2D otherPoint = GetControlPoint( otherIndex ); Point2D point3 = GetControlPoint( 3 ); Vector2D vec1 = point - centerPoint; Vector2D vec2; if (index == 1 && m_TreatAsCircle ) { float x = vec1[0]; vec2[0] = vec1[1]; vec2[1] = x; if (index==1) vec2[0] *= -1; else vec2[1] *= -1; otherPoint = centerPoint+vec2; PlanarFigure::SetControlPoint( otherIndex, otherPoint, createIfDoesNotExist ); float r = centerPoint.EuclideanDistanceTo(otherPoint); // adjust additional third control point Point2D p3 = this->GetControlPoint(3); Vector2D vec3; vec3[0] = p3[0]-centerPoint[0]; vec3[1] = p3[1]-centerPoint[1]; if (vec3[0]!=0 || vec3[1]!=0) { vec3.Normalize(); vec3 *= r; } else { vec3[0] = r; vec3[1] = 0; } point3 = centerPoint + vec3; PlanarFigure::SetControlPoint( 3, point3, createIfDoesNotExist ); } else if ( vec1.GetNorm() > 0 ) { float r = centerPoint.EuclideanDistanceTo(otherPoint); float x = vec1[0]; vec2[0] = vec1[1]; vec2[1] = x; if (index==1) vec2[0] *= -1; else vec2[1] *= -1; vec2.Normalize(); vec2 *= r; if ( vec2.GetNorm() > 0 ) { otherPoint = centerPoint+vec2; PlanarFigure::SetControlPoint( otherIndex, otherPoint, createIfDoesNotExist ); } // adjust third control point Vector2D vec3 = point3 - centerPoint; vec3.Normalize(); double r1 = centerPoint.EuclideanDistanceTo( GetControlPoint( 1 ) ); double r2 = centerPoint.EuclideanDistanceTo( GetControlPoint( 2 ) ); Point2D newPoint = centerPoint + vec3*std::max(r1, r2); PlanarFigure::SetControlPoint( 3, newPoint, createIfDoesNotExist ); m_TreatAsCircle = false; } return true; } else if (index == 3) { Point2D centerPoint = GetControlPoint( 0 ); Vector2D vec3 = point - centerPoint; vec3.Normalize(); double r1 = centerPoint.EuclideanDistanceTo( GetControlPoint( 1 ) ); double r2 = centerPoint.EuclideanDistanceTo( GetControlPoint( 2 ) ); Point2D newPoint = centerPoint + vec3*std::max(r1, r2); PlanarFigure::SetControlPoint( index, newPoint, createIfDoesNotExist ); m_TreatAsCircle = false; return true; } return false; } void mitk::PlanarEllipse::PlaceFigure( const mitk::Point2D &point ) { PlanarFigure::PlaceFigure( point ); m_SelectedControlPoint = 1; } mitk::Point2D mitk::PlanarEllipse::ApplyControlPointConstraints(unsigned int index, const Point2D &point) { return point; Point2D indexPoint; this->GetPlaneGeometry()->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = this->GetPlaneGeometry()->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; this->GetPlaneGeometry()->IndexToWorld( indexPoint, constrainedPoint ); if(m_MinMaxRadiusContraintsActive) { if( index != 0) { const Point2D ¢erPoint = this->GetControlPoint(0); double euclideanDinstanceFromCenterToPoint1 = centerPoint.EuclideanDistanceTo(point); Vector2D vectorProjectedPoint; vectorProjectedPoint = point - centerPoint; vectorProjectedPoint.Normalize(); if( euclideanDinstanceFromCenterToPoint1 > m_MaxRadius ) { vectorProjectedPoint *= m_MaxRadius; constrainedPoint = centerPoint; constrainedPoint += vectorProjectedPoint; } else if( euclideanDinstanceFromCenterToPoint1 < m_MinRadius ) { vectorProjectedPoint *= m_MinRadius; constrainedPoint = centerPoint; constrainedPoint += vectorProjectedPoint; } } } return constrainedPoint; } void mitk::PlanarEllipse::GeneratePolyLine() { // clear the PolyLine-Contrainer, it will be reconstructed soon enough... this->ClearPolyLines(); const Point2D ¢erPoint = GetControlPoint( 0 ); const Point2D &boundaryPoint1 = GetControlPoint( 1 ); const Point2D &boundaryPoint2 = GetControlPoint( 2 ); Vector2D dir = boundaryPoint1 - centerPoint; dir.Normalize(); vnl_matrix_fixed rot; // differentiate between clockwise and counterclockwise rotation int start = 0; int end = 64; if (dir[1]<0) { dir[0] = -dir[0]; start = -32; end = 32; } // construct rotation matrix to align ellipse with control point vector rot[0][0] = dir[0]; rot[1][1] = rot[0][0]; rot[1][0] = sin(acos(rot[0][0])); rot[0][1] = -rot[1][0]; double radius1 = centerPoint.EuclideanDistanceTo( boundaryPoint1 ); double radius2 = centerPoint.EuclideanDistanceTo( boundaryPoint2 ); // Generate poly-line with 64 segments for ( int t = start; t < end; ++t ) { double alpha = (double) t * vnl_math::pi / 32.0; // construct the new polyline point ... vnl_vector_fixed< float, 2 > vec; vec[0] = radius1 * cos( alpha ); vec[1] = radius2 * sin( alpha ); vec = rot*vec; Point2D polyLinePoint; polyLinePoint[0] = centerPoint[0] + vec[0]; polyLinePoint[1] = centerPoint[1] + vec[1]; // ... and append it to the PolyLine. // No extending supported here, so we can set the index of the PolyLineElement to '0' this->AppendPointToPolyLine(0, polyLinePoint); } this->AppendPointToPolyLine(1, centerPoint); this->AppendPointToPolyLine(1, this->GetControlPoint(3)); } void mitk::PlanarEllipse::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A circle does not require a helper object } void mitk::PlanarEllipse::EvaluateFeaturesInternal() { Point2D centerPoint = this->GetControlPoint(0); this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(1))); this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2))); } void mitk::PlanarEllipse::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } - bool mitk::PlanarEllipse::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarEllipse::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarEllipse* otherEllipse = dynamic_cast(&other); + const mitk::PlanarEllipse* otherEllipse = dynamic_cast(&other); if ( otherEllipse ) { if(this->m_TreatAsCircle != otherEllipse->m_TreatAsCircle) return false; return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h index 3204786bb2..5654e737cb 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarEllipse.h @@ -1,142 +1,142 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_ELLIPSE_H_ #define _MITK_PLANAR_ELLIPSE_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a circle * through two control points */ class MitkPlanarFigure_EXPORT PlanarEllipse : public PlanarFigure { public: mitkClassMacro( PlanarEllipse, PlanarFigure ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ virtual void PlaceFigure( const Point2D &point ); bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = true ); /** \brief Ellipse has 3 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 4; } /** \brief Ellipse has 3 control points per definition. */ unsigned int GetMaximumNumberOfControlPoints() const { return 4; } /** \brief Sets the minimum radius */ void SetMinimumRadius( double radius ) { m_MinRadius = radius; } /** \brief Gets the minimum radius */ double GetMinimumRadius() { return m_MinRadius; } /** \brief Sets the maximum radius */ void SetMaximumRadius( double radius ) { m_MaxRadius = radius; } /** \brief Gets the minimum radius */ double GetMaximumRadius() { return m_MaxRadius; } void ActivateMinMaxRadiusContstraints( bool active ) { m_MinMaxRadiusContraintsActive = active; } /** \brief Treat ellipse as circle (equal radii) */ void SetTreatAsCircle( bool active ) { m_TreatAsCircle = active; } - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; const unsigned int FEATURE_ID_MAJOR_AXIS; const unsigned int FEATURE_ID_MINOR_AXIS; protected: PlanarEllipse(); virtual ~PlanarEllipse(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Spatially constrain control points of second (orthogonal) line */ virtual Point2D ApplyControlPointConstraints( unsigned int index, const Point2D& point ); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; //Member variables: double m_MinRadius; double m_MaxRadius; bool m_MinMaxRadiusContraintsActive; bool m_TreatAsCircle; private: }; } // namespace mitk #endif //_MITK_PLANAR_ELLIPSE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp index cf6a9609aa..d51f575765 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFigure.cpp @@ -1,884 +1,884 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFigure.h" #include "mitkPlaneGeometry.h" #include #include #include #ifdef __GNUC__ # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #elif __clang__ # pragma clang diagnostic ignored "-Wdeprecated-declarations" #elif _MSC_VER # pragma warning (push) # pragma warning (disable: 4996) #endif mitk::PlanarFigure::PolyLineElement::PolyLineElement(Point2D point, int index) : Point(point), Index(index) { } mitk::PlanarFigure::PolyLineElement::PolyLineElement(const Point2D& point) : Point(point), Index(-1) { } mitk::PlanarFigure::PolyLineElement::PolyLineElement(const PolyLineElement &other) : Point(other.Point), Index(other.Index) { } mitk::PlanarFigure::PolyLineElement& mitk::PlanarFigure::PolyLineElement::operator=(const PolyLineElement &other) { if (this != &other) { Point = other.Point; Index = other.Index; } return *this; } mitk::PlanarFigure::PolyLineElement::operator mitk::Point2D&() { return Point; } mitk::PlanarFigure::PolyLineElement::operator const mitk::Point2D&() const { return Point; } mitk::PlanarFigure::PlanarFigure() : m_SelectedControlPoint( -1 ), m_PreviewControlPointVisible( false ), m_FigurePlaced( false ), m_PlaneGeometry( 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->InitializeTimeGeometry( 1 ); } mitk::PlanarFigure::~PlanarFigure() { } mitk::PlanarFigure::PlanarFigure(const Self& other) : BaseData(other), m_ControlPoints(other.m_ControlPoints), m_NumberOfControlPoints(other.m_NumberOfControlPoints), m_SelectedControlPoint(other.m_SelectedControlPoint), m_PolyLines(other.m_PolyLines), m_HelperPolyLines(other.m_HelperPolyLines), m_HelperPolyLinesToBePainted(other.m_HelperPolyLinesToBePainted->Clone()), m_PreviewControlPoint(other.m_PreviewControlPoint), m_PreviewControlPointVisible(other.m_PreviewControlPointVisible), m_FigurePlaced(other.m_FigurePlaced), m_PlaneGeometry(other.m_PlaneGeometry), // do not clone since SetPlaneGeometry() doesn't clone either m_PolyLineUpToDate(other.m_PolyLineUpToDate), m_HelperLinesUpToDate(other.m_HelperLinesUpToDate), m_FeaturesUpToDate(other.m_FeaturesUpToDate), m_Features(other.m_Features), m_FeaturesMTime(other.m_FeaturesMTime), m_DisplaySize(other.m_DisplaySize) { } void mitk::PlanarFigure::SetPlaneGeometry( mitk::PlaneGeometry *geometry ) { this->SetGeometry( geometry ); m_PlaneGeometry = dynamic_cast(GetGeometry(0));//geometry; } const mitk::PlaneGeometry *mitk::PlanarFigure::GetPlaneGeometry() const { return m_PlaneGeometry; } 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 > (int)m_NumberOfControlPoints-1 || (position == 1 && m_SelectedControlPoint == 2) ) { if ( m_ControlPoints.size() > this->GetMaximumNumberOfControlPoints()-1 ) { // get rid of deprecated control points in the list. This is necessary // as ::ResetNumberOfControlPoints() only sets the member, does not resize the list! m_ControlPoints.resize( this->GetNumberOfControlPoints() ); } m_ControlPoints.push_back( this->ApplyControlPointConstraints( m_NumberOfControlPoints, point ) ); m_SelectedControlPoint = m_NumberOfControlPoints; } else { // insert the point at the given position and set it as selected point ControlPointListType::iterator iter = m_ControlPoints.begin() + position; m_ControlPoints.insert( iter, this->ApplyControlPointConstraints( position, point ) ); for( unsigned int i = 0; i < m_ControlPoints.size(); ++i ) { if( point == m_ControlPoints.at(i) ) { m_SelectedControlPoint = i; } } } // 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; } } bool mitk::PlanarFigure::DeselectControlPoint() { bool wasSelected = ( m_SelectedControlPoint != -1); m_SelectedControlPoint = -1; return wasSelected; } 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_PlaneGeometry != NULL) && (index < m_NumberOfControlPoints) ) { m_PlaneGeometry->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 ( index > m_PolyLines.size() || !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 ( std::vector::size_type 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 ( std::vector::size_type i=0; iGeneratePolyLine(); } this->EvaluateFeaturesInternal(); m_FeaturesUpToDate = true; } } void mitk::PlanarFigure::UpdateOutputInformation() { // Bounds are NOT calculated here, since the PlaneGeometry defines a fixed // frame (= bounds) for the planar figure. Superclass::UpdateOutputInformation(); this->GetTimeGeometry()->Update(); } void mitk::PlanarFigure::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::PlanarFigure::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::PlanarFigure::VerifyRequestedRegion() { return true; } void mitk::PlanarFigure::SetRequestedRegion(const itk::DataObject * /*data*/ ) { } void mitk::PlanarFigure::ResetNumberOfControlPoints( int numberOfControlPoints ) { // DO NOT resize the list here, will cause crash!! m_NumberOfControlPoints = numberOfControlPoints; } mitk::Point2D mitk::PlanarFigure::ApplyControlPointConstraints( unsigned int /*index*/, const Point2D& point ) { if ( m_PlaneGeometry == NULL ) { return point; } Point2D indexPoint; m_PlaneGeometry->WorldToIndex( point, indexPoint ); BoundingBox::BoundsArrayType bounds = m_PlaneGeometry->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_PlaneGeometry->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::InitializeTimeGeometry( unsigned int timeSteps ) { mitk::PlaneGeometry::Pointer geometry2D = mitk::PlaneGeometry::New(); geometry2D->Initialize(); // The geometry is propagated automatically to all time steps, // if EvenlyTimed is true... ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(geometry2D, timeSteps); SetTimeGeometry(timeGeometry); } 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->GetPlaneGeometry()->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 (" << 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 PlaneGeometry::Pointer affineGeometry = oldFigure->m_PlaneGeometry->Clone(); SetPlaneGeometry(affineGeometry.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() ) { if(element.Index == -1) element.Index = m_PolyLines[index].size(); m_PolyLines[index].push_back(element); m_PolyLineUpToDate = false; } 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() ) { if(element.Index == -1) element.Index = m_HelperPolyLines[index].size(); m_HelperPolyLines[index].push_back(element); m_HelperLinesUpToDate = false; } else { MITK_ERROR << "Tried to add point to HelperPolyLine " << index+1 << ", although only " << m_HelperPolyLines.size() << " exists"; } } #ifdef __GNUC__ # pragma GCC diagnostic error "-Wdeprecated-declarations" #elif __clang__ # pragma clang diagnostic error "-Wdeprecated-declarations" #elif _MSC_VER # pragma warning (pop) #endif bool mitk::PlanarFigure::Equals(const mitk::PlanarFigure& other) const { //check geometries - if ( this->GetGeometry2D() && other.GetGeometry2D() ) + if ( this->GetPlaneGeometry() && other.GetPlaneGeometry() ) { - if( !Equal(*(this->GetGeometry2D()), *(other.GetGeometry2D()), mitk::eps, true)) + if( !Equal(*(this->GetPlaneGeometry()), *(other.GetPlaneGeometry()), mitk::eps, true)) { return false; } } else { return false; } //check isPlaced member if ( this->m_FigurePlaced != other.m_FigurePlaced) { return false; } //check closed property if (this->IsClosed() != other.IsClosed()) { return false; } //check control points if (this->m_ControlPoints != other.m_ControlPoints) { return false; } //check poly lines if (this->m_PolyLines.size() != other.m_PolyLines.size()) { return false; } else { std::vector::const_iterator itThis = this->m_PolyLines.begin(); std::vector::const_iterator itEnd = this->m_PolyLines.end(); std::vector::const_iterator itOther = other.m_PolyLines.begin(); while( itThis != itEnd ) { if(itThis->size() != itOther->size()) return false; else { PolyLineType::const_iterator itLineThis = itThis->begin(); PolyLineType::const_iterator itLineEnd = itThis->end(); PolyLineType::const_iterator itLineOther = itOther->begin(); while(itLineThis != itLineEnd) { - if(itLineThis->Index != itLineOther->Index) - return false; - if(itLineThis->Point != itLineOther->Point) + Point2D p1 = *itLineThis; + Point2D p2 = *itLineOther; + if(p1 != p2) return false; ++itLineThis; ++itLineOther; } } ++itThis; ++itOther; } } //check features if (this->GetNumberOfFeatures() != other.GetNumberOfFeatures()) { return false; } else { std::vector::const_iterator itThis = m_Features.begin(); std::vector::const_iterator itEnd = m_Features.end(); std::vector::const_iterator itOther = other.m_Features.begin(); while(itThis != itEnd) { if( itThis->Quantity != itOther->Quantity ) return false; if( itThis->Unit.compare(itOther->Unit) != 0 ) return false; if( itThis->Name.compare(itOther->Name) != 0 ) return false; ++itThis; ++itOther; } } return true; } bool mitk::Equal( const mitk::PlanarFigure& leftHandSide, const mitk::PlanarFigure& rightHandSide, ScalarType eps, bool verbose ) { return leftHandSide.Equals(rightHandSide); } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp index ba43f20359..ca7c048a98 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.cpp @@ -1,92 +1,92 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarFourPointAngle.h" #include "mitkPlaneGeometry.h" mitk::PlanarFourPointAngle::PlanarFourPointAngle() : FEATURE_ID_ANGLE( this->AddFeature( "Angle", "deg" ) ) { // Four point angle has two control points this->ResetNumberOfControlPoints( 2 ); this->SetNumberOfPolyLines( 2 ); } mitk::PlanarFourPointAngle::~PlanarFourPointAngle() { } void mitk::PlanarFourPointAngle::GeneratePolyLine() { this->ClearPolyLines(); for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i) this->AppendPointToPolyLine(i / 2, this->GetControlPoint(i)); } void mitk::PlanarFourPointAngle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // Generate helper-poly-line for an four point angle // Need to discuss a sensible implementation } void mitk::PlanarFourPointAngle::EvaluateFeaturesInternal() { if ( this->GetNumberOfControlPoints() < 4 ) { // Angle not yet complete. return; } // Calculate angle between lines const Point2D &p0 = this->GetControlPoint( 0 ); const Point2D &p1 = this->GetControlPoint( 1 ); const Point2D &p2 = this->GetControlPoint( 2 ); const Point2D &p3 = this->GetControlPoint( 3 ); Vector2D v0 = p1 - p0; Vector2D v1 = p3 - p2; v0.Normalize(); v1.Normalize(); double angle = acos( v0 * v1 ); this->SetQuantity( FEATURE_ID_ANGLE, angle ); } void mitk::PlanarFourPointAngle::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } - bool mitk::PlanarFourPointAngle::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarFourPointAngle::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarFourPointAngle* otherFourPtAngle = dynamic_cast(&other); + const mitk::PlanarFourPointAngle* otherFourPtAngle = dynamic_cast(&other); if ( otherFourPtAngle ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h index 25642eddc0..44189715de 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarFourPointAngle.h @@ -1,94 +1,94 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_FOURPOINTANGLE_H_ #define _MITK_PLANAR_FOURPOINTANGLE_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a four point * angle, which is defined by two non-intersecting lines in 2D. Each of those lines * is defined by two control points. */ class MitkPlanarFigure_EXPORT PlanarFourPointAngle : public PlanarFigure { public: mitkClassMacro( PlanarFourPointAngle, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) public: // Feature identifiers const unsigned int FEATURE_ID_ANGLE; /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); /** \brief Four point angle has 4 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 4; } /** \brief Four point angle has 4 control points per definition. */ unsigned int GetMaximumNumberOfControlPoints() const { return 4; } - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const ; protected: PlanarFourPointAngle(); virtual ~PlanarFourPointAngle(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; private: }; } // namespace mitk #endif //_MITK_PLANAR_FOURPOINTANGLE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp index 5bf989ff05..ffee0a38bd 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.cpp @@ -1,78 +1,78 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarLine.h" #include "mitkPlaneGeometry.h" mitk::PlanarLine::PlanarLine() : FEATURE_ID_LENGTH( this->AddFeature( "Length", "mm" ) ) { // Line has two control points this->ResetNumberOfControlPoints( 2 ); this->SetNumberOfPolyLines( 1 ); } mitk::PlanarLine::~PlanarLine() { } void mitk::PlanarLine::GeneratePolyLine() { this->ClearPolyLines(); this->AppendPointToPolyLine(0, this->GetControlPoint(0)); this->AppendPointToPolyLine(0, this->GetControlPoint(1)); } void mitk::PlanarLine::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A line does not require a helper object } void mitk::PlanarLine::EvaluateFeaturesInternal() { // Calculate line length const Point3D &p0 = this->GetWorldControlPoint( 0 ); const Point3D &p1 = this->GetWorldControlPoint( 1 ); double length = p0.EuclideanDistanceTo( p1 ); this->SetQuantity( FEATURE_ID_LENGTH, length ); } void mitk::PlanarLine::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); } - bool mitk::PlanarLine::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarLine::Equals(const PlanarFigure &other) const { - mitk::PlanarLine* otherLine = dynamic_cast(&other); + const mitk::PlanarLine* otherLine = dynamic_cast(&other); if ( otherLine ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h index 7e33aceb2b..cdfd7bfd55 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarLine.h @@ -1,94 +1,94 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_LINE_H_ #define _MITK_PLANAR_LINE_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a line * through two control points */ class MitkPlanarFigure_EXPORT PlanarLine : public PlanarFigure { public: mitkClassMacro( PlanarLine, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); /** \brief Line has 2 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 2; } /** \brief Line has 2 control points per definition. */ unsigned int GetMaximumNumberOfControlPoints() const { return 2; } - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarLine(); virtual ~PlanarLine(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; // Feature identifiers const unsigned int FEATURE_ID_LENGTH; private: }; } // namespace mitk #endif //_MITK_PLANAR_LINE_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp index 8071eb2d60..e47a71eebd 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.cpp @@ -1,287 +1,287 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarPolygon.h" #include "mitkPlaneGeometry.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 (ControlPointListType::size_type i = 0; i < m_ControlPoints.size(); ++i) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); } 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; PolyLineType polyLine = m_PolyLines[0]; if(polyLine.empty()) return; for ( i = 0; i <(polyLine.size()-1); ++i ) { circumference += static_cast(polyLine[i]).EuclideanDistanceTo( static_cast(polyLine[i + 1]) ); } if ( this->IsClosed() ) { circumference += static_cast(polyLine[i]).EuclideanDistanceTo( static_cast(polyLine.front()) ); } this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference ); // Calculate polygon area (if closed) double area = 0.0; bool intersection = false; if ( this->IsClosed() && (this->GetPlaneGeometry() != NULL) ) { // does PlanarPolygon overlap/intersect itself? unsigned int numberOfPoints = polyLine.size(); if( numberOfPoints >= 4) { for ( i = 0; i < (numberOfPoints - 1); ++i ) { // line 1 Point2D p0 = polyLine[i]; Point2D p1 = polyLine[i + 1]; // check for intersection with all other lines for (j = i+1; j < (numberOfPoints - 1); ++j ) { Point2D p2 = polyLine[j]; Point2D p3 = polyLine[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 = polyLine.front(); Point2D p3 = polyLine.back(); intersection = CheckForLineIntersection(p0,p1,p2,p3); if (intersection) break; } } // calculate area for ( i = 0; i < polyLine.size(); ++i ) { Point2D p0 = polyLine[i]; Point2D p1 = polyLine[ (i + 1) % polyLine.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 ); } } 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; ControlPointListType polyLinePoints; PolyLineType tempList = m_PolyLines[0]; PolyLineType::iterator iter; for( iter = tempList.begin(); iter != tempList.end(); ++iter ) { polyLinePoints.push_back(*iter); } for ( ControlPointListType::size_type i=0; iIsClosed() ) { mitk::Point2D intersection, lastControlPoint, firstControlPoint; lastControlPoint = polyLinePoints.back(); firstControlPoint = polyLinePoints.front(); if ( mitk::PlanarPolygon::CheckForLineIntersection( lastControlPoint, firstControlPoint, p1, p2, intersection ) ) { intersectionList.push_back( intersection ); } } return intersectionList; } - bool mitk::PlanarPolygon::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarPolygon::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarPolygon* otherPolygon = dynamic_cast(&other); + const mitk::PlanarPolygon* otherPolygon = dynamic_cast(&other); if ( otherPolygon ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h index c92e38920a..e37b70934b 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarPolygon.h @@ -1,104 +1,104 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_POLYGON_H_ #define _MITK_PLANAR_POLYGON_H_ #include "mitkPlanarFigure.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a polygon * with two or more control points */ class MitkPlanarFigure_EXPORT PlanarPolygon : public PlanarFigure { public: mitkClassMacro( PlanarPolygon, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Set whether the polygon should be closed between first and last control point or not. */ virtual void SetClosed( bool closed ); itkBooleanMacro( Closed ); // Calls SetClosed(); no need to re-implement /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); /** \brief Polygon has 3 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 3; } /** \brief Polygon maximum number of control points is principally not limited. */ unsigned int GetMaximumNumberOfControlPoints() const { return 1000; } std::vector CheckForLineIntersection( const Point2D& p1, const Point2D& p2 ) const; - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarPolygon(); virtual ~PlanarPolygon(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); bool CheckForLineIntersection(const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4, Point2D& intersection) const ; bool CheckForLineIntersection( const mitk::Point2D& p1, const mitk::Point2D& p2, const mitk::Point2D& p3, const mitk::Point2D& p4 ) const; virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; const unsigned int FEATURE_ID_CIRCUMFERENCE; const unsigned int FEATURE_ID_AREA; private: }; } // namespace mitk #endif //_MITK_PLANAR_POLYGON_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp index 2f6f30f0d4..d4fdeb80d6 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.cpp @@ -1,159 +1,159 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkProperties.h" #include "mitkPlanarRectangle.h" #include "mitkPlaneGeometry.h" mitk::PlanarRectangle::PlanarRectangle() : FEATURE_ID_CIRCUMFERENCE( this->AddFeature( "Circumference", "mm" ) ), FEATURE_ID_AREA( this->AddFeature( "Area", "mm2" ) ) { // Rectangle has four control points this->ResetNumberOfControlPoints( 4 ); this->SetProperty( "closed", mitk::BoolProperty::New(true) ); this->SetNumberOfPolyLines( 1 ); } mitk::PlanarRectangle::~PlanarRectangle() { } bool mitk::PlanarRectangle::SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist ) { // heres the deal with the rectangle: // when a point is moved all corresponding corner points are moved with him // e.g. if the lower right point (index=3) is moved the upper right point (index=1) // is moved in the same x direction // and the lower left point (index=2) is moved in the same y direction // the upper left point (index=0) is left untouched bool set = PlanarFigure::SetControlPoint( index, point, createIfDoesNotExist ); if(set) { // can be made better ... unsigned int horizontalCorrespondingPointIndex = 1; unsigned int verticalCorrespondingPointIndex = 3; if(index == 1) { horizontalCorrespondingPointIndex = 0; verticalCorrespondingPointIndex = 2; } else if(index == 2) { horizontalCorrespondingPointIndex = 3; verticalCorrespondingPointIndex = 1; } else if(index == 3) { horizontalCorrespondingPointIndex = 2; verticalCorrespondingPointIndex = 0; } Point2D verticalCorrespondingPoint = GetControlPoint( verticalCorrespondingPointIndex ); verticalCorrespondingPoint[0] = point[0]; PlanarFigure::SetControlPoint( verticalCorrespondingPointIndex, verticalCorrespondingPoint ); Point2D horizontalCorrespondingPoint = GetControlPoint( horizontalCorrespondingPointIndex ); horizontalCorrespondingPoint[1] = point[1]; PlanarFigure::SetControlPoint( horizontalCorrespondingPointIndex, horizontalCorrespondingPoint ); } return set; } void mitk::PlanarRectangle::PlaceFigure( const mitk::Point2D &point ) { PlanarFigure::PlaceFigure( point ); m_SelectedControlPoint = 3; } void mitk::PlanarRectangle::GeneratePolyLine() { this->ClearPolyLines(); for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); ++i) this->AppendPointToPolyLine(0, this->GetControlPoint(i)); } void mitk::PlanarRectangle::GenerateHelperPolyLine(double /*mmPerDisplayUnit*/, unsigned int /*displayHeight*/) { // A polygon does not require helper objects } void mitk::PlanarRectangle::EvaluateFeaturesInternal() { // Calculate circumference double circumference = 0.0; unsigned int i; for ( i = 0; i < this->GetNumberOfControlPoints(); ++i ) { circumference += this->GetWorldControlPoint( i ).EuclideanDistanceTo( this->GetWorldControlPoint( (i + 1) % this->GetNumberOfControlPoints() ) ); } this->SetQuantity( FEATURE_ID_CIRCUMFERENCE, circumference ); // Calculate rectangle area (well, done a bit clumsy...) double area = 0.0; if ( this->GetPlaneGeometry() != NULL ) { 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; } this->SetQuantity( FEATURE_ID_AREA, fabs(area) ); } void mitk::PlanarRectangle::PrintSelf( std::ostream& os, itk::Indent indent) const { Superclass::PrintSelf( os, indent ); os << indent << "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 << indent << i << ": " <(&other); + const mitk::PlanarRectangle* otherRectangle = dynamic_cast(&other); if ( otherRectangle ) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h index 343a3c8d96..b4890c5ce8 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarRectangle.h @@ -1,94 +1,94 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_RECTANGLE_H_ #define _MITK_PLANAR_RECTANGLE_H_ #include "mitkPlanarPolygon.h" #include namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a polygon * with two or more control points */ class MitkPlanarFigure_EXPORT PlanarRectangle : public PlanarFigure { public: mitkClassMacro( PlanarRectangle, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Place figure in its minimal configuration (a point at least) * onto the given 2D geometry. * * Must be implemented in sub-classes. */ //virtual void Initialize(); virtual void PlaceFigure( const Point2D &point ); /** \brief Polygon has 2 control points per definition. */ virtual unsigned int GetMinimumNumberOfControlPoints() const { return 4; } /** \brief Polygon maximum number of control points is principally not limited. */ virtual unsigned int GetMaximumNumberOfControlPoints() const { return 4; } virtual bool SetControlPoint( unsigned int index, const Point2D &point, bool createIfDoesNotExist = false); protected: PlanarRectangle(); virtual ~PlanarRectangle(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ virtual void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight); /** \brief Calculates feature quantities of the planar figure. */ virtual void EvaluateFeaturesInternal(); virtual void PrintSelf( std::ostream &os, itk::Indent indent ) const; const unsigned int FEATURE_ID_CIRCUMFERENCE; const unsigned int FEATURE_ID_AREA; - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; private: }; } // namespace mitk #endif //_MITK_PLANAR_POLYGON_H_ diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp index a57ac63c71..2b63f2dffd 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.cpp @@ -1,149 +1,149 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPlanarSubdivisionPolygon.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" // stl related includes #include mitk::PlanarSubdivisionPolygon::PlanarSubdivisionPolygon(): m_TensionParameter(0.0625), m_SubdivisionRounds(5) { // Polygon is subdivision (in contrast to parent class PlanarPolygon this->SetProperty( "closed", mitk::BoolProperty::New( true ) ); this->SetProperty( "subdivision", mitk::BoolProperty::New( true ) ); // Other properties are inherited / already initialized by parent class PlanarPolygon } mitk::PlanarSubdivisionPolygon::~PlanarSubdivisionPolygon() { } void mitk::PlanarSubdivisionPolygon::GeneratePolyLine() { this->ClearPolyLines(); ControlPointListType subdivisionPoints; ControlPointListType newSubdivisionPoints; subdivisionPoints.clear(); subdivisionPoints = m_ControlPoints; if( m_ControlPoints.size() >= GetMinimumNumberOfControlPoints() ) { for( unsigned int i=0; i < GetSubdivisionRounds(); i++ ) { // Indices unsigned int index, indexPrev, indexNext, indexNextNext; unsigned int numberOfPoints = subdivisionPoints.size(); Point2D newPoint; // Keep cycling our array indices forward until they wrap around at the end for ( index = 0; index < numberOfPoints; ++index ) { // Create new subdivision point according to formula // p_new = (0.5 + tension) * (p_here + p_next) - tension * (p_prev + p_nextnext) indexPrev = (numberOfPoints + index - 1) % numberOfPoints; indexNext = (index + 1) % numberOfPoints; indexNextNext = (index + 2) % numberOfPoints; newPoint[0] = (0.5 + GetTensionParameter()) * (double)( subdivisionPoints[index][0] + subdivisionPoints[indexNext][0] ) - GetTensionParameter() * (double)( subdivisionPoints[indexPrev][0] + subdivisionPoints[indexNextNext][0]); newPoint[1] = (0.5 + GetTensionParameter()) * (double)( subdivisionPoints[index][1] + subdivisionPoints[indexNext][1] ) - GetTensionParameter() * (double)( subdivisionPoints[indexPrev][1] + subdivisionPoints[indexNextNext][1]); newSubdivisionPoints.push_back( newPoint ); } ControlPointListType mergedSubdivisionPoints; ControlPointListType::iterator it, itNew; for ( it = subdivisionPoints.begin() , itNew = newSubdivisionPoints.begin(); it != subdivisionPoints.end(); ++it, ++itNew ) { mergedSubdivisionPoints.push_back( *it ); mergedSubdivisionPoints.push_back( *itNew ); } subdivisionPoints = mergedSubdivisionPoints; newSubdivisionPoints.clear(); } } bool isInitiallyPlaced = this->GetProperty("initiallyplaced"); unsigned int i; ControlPointListType::iterator it; for ( it = subdivisionPoints.begin(), i = 0; it != subdivisionPoints.end(); ++it, ++i ) { // Determine the index of the control point FOLLOWING this poly-line element // (this is needed by PlanarFigureInteractor to insert new points at the correct position, // namely BEFORE the next control point) unsigned int nextIndex; if ( i == 0 ) { // For the FIRST polyline point, use the index of the LAST control point // (it will used to check if the mouse is near the very last polyline element) nextIndex = m_ControlPoints.size() - 1; } else { // For all other polyline points, use the index of the control point succeeding it // (for polyline points lying on control points, the index of the previous control point // is used) nextIndex = (((i - 1) >> this->GetSubdivisionRounds()) + 1) % m_ControlPoints.size(); if(!isInitiallyPlaced && nextIndex > m_ControlPoints.size()-2) { PolyLineElement elem( m_ControlPoints[m_ControlPoints.size()-1], nextIndex ); this->AppendPointToPolyLine( 0, elem ); break; } } PolyLineElement elem( *it, nextIndex ); this->AppendPointToPolyLine( 0, elem ); } subdivisionPoints.clear(); } - bool mitk::PlanarSubdivisionPolygon::Equals(mitk::PlanarFigure& other) + bool mitk::PlanarSubdivisionPolygon::Equals(const mitk::PlanarFigure& other) const { - mitk::PlanarSubdivisionPolygon* otherSubDivPoly = dynamic_cast(&other); + const mitk::PlanarSubdivisionPolygon* otherSubDivPoly = dynamic_cast(&other); if ( otherSubDivPoly ) { if ( this->m_SubdivisionRounds != otherSubDivPoly->m_SubdivisionRounds) return false; if ( std::abs(this->m_TensionParameter - otherSubDivPoly->m_TensionParameter) > mitk::eps) return false; return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h index 51e9a12ab4..8f17c66805 100644 --- a/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h +++ b/Modules/PlanarFigure/DataManagement/mitkPlanarSubdivisionPolygon.h @@ -1,109 +1,109 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_PLANAR_SUBDIVISION_POLYGON_H_ #define _MITK_PLANAR_SUBDIVISION_POLYGON_H_ #include "mitkPlanarFigure.h" #include #include "mitkPlanarPolygon.h" namespace mitk { class PlaneGeometry; /** * \brief Implementation of PlanarFigure representing a polygon * with two or more control points */ class MitkPlanarFigure_EXPORT PlanarSubdivisionPolygon : public PlanarPolygon { public: mitkClassMacro( PlanarSubdivisionPolygon, PlanarFigure ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** \brief Subdivision Polygon has 3 control points per definition. */ unsigned int GetMinimumNumberOfControlPoints() const { return 3; } /** \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 m_SubdivisionRounds; } void SetSubdivisionRounds( int subdivisionRounds ) { m_SubdivisionRounds = subdivisionRounds; } /** \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 m_TensionParameter; } void SetTensionParameter(float tensionParameter ) { m_TensionParameter = tensionParameter; } std::vector CheckForLineIntersection( const Point2D& p1, const Point2D& p2 ) const; void IncreaseSubdivisions(); void DecreaseSubdivisions(); - virtual bool Equals(mitk::PlanarFigure& other); + virtual bool Equals(const mitk::PlanarFigure& other) const; protected: PlanarSubdivisionPolygon(); virtual ~PlanarSubdivisionPolygon(); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ virtual void GeneratePolyLine(); float m_TensionParameter; int m_SubdivisionRounds; private: }; } // namespace mitk #endif //_MITK_PLANAR_SUBDIVISION_POLYGON_H_