diff --git a/Modules/PlanarFigure/include/mitkPlanarCircle.h b/Modules/PlanarFigure/include/mitkPlanarCircle.h index e51cd66d03..12eb82b6a6 100644 --- a/Modules/PlanarFigure/include/mitkPlanarCircle.h +++ b/Modules/PlanarFigure/include/mitkPlanarCircle.h @@ -1,100 +1,105 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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 + * either through two control points or by one control point (fixed radius mode) + * The mode is defined by the chosen constructor. */ class MITKPLANARFIGURE_EXPORT PlanarCircle : public PlanarFigure { public: mitkClassMacro(PlanarCircle, PlanarFigure); - + mitkNewMacro1Param(PlanarCircle, double); 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) override; /** \brief Circle has 2 control points per definition. */ - unsigned int GetMinimumNumberOfControlPoints() const override { return 2; } + unsigned int GetMinimumNumberOfControlPoints() const override { return (m_RadiusFixed) ? 1 : 2; } /** \brief Circle has 2 control points per definition. */ - unsigned int GetMaximumNumberOfControlPoints() const override { return 2; } + unsigned int GetMaximumNumberOfControlPoints() const override { return (m_RadiusFixed) ? 1 : 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; } bool SetCurrentControlPoint(const Point2D &point) override; bool Equals(const mitk::PlanarFigure &other) const override; protected: PlanarCircle(); + /** Constructor for fixed radius mode.*/ + PlanarCircle(double fixedRadius); mitkCloneMacro(Self); /** \brief Generates the poly-line representation of the planar figure. */ void GeneratePolyLine() override; /** \brief Generates the poly-lines that should be drawn the same size regardless of zoom.*/ void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) override; /** \brief Spatially constrain control points of second (orthogonal) line */ Point2D ApplyControlPointConstraints(unsigned int index, const Point2D &point) override; /** \brief Calculates feature quantities of the planar figure. */ void EvaluateFeaturesInternal() override; void PrintSelf(std::ostream &os, itk::Indent indent) const override; // 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; + //indicate if the circle is created with fixed radius. The radius is stored in m_MinRadius + bool m_RadiusFixed; private: }; } // namespace mitk #endif //_MITK_PLANAR_CIRCLE_H_ diff --git a/Modules/PlanarFigure/include/mitkPlanarDoubleEllipse.h b/Modules/PlanarFigure/include/mitkPlanarDoubleEllipse.h index 1245cfdb49..9e9139931b 100644 --- a/Modules/PlanarFigure/include/mitkPlanarDoubleEllipse.h +++ b/Modules/PlanarFigure/include/mitkPlanarDoubleEllipse.h @@ -1,58 +1,74 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPlanarDoubleEllipse_h #define mitkPlanarDoubleEllipse_h #include #include namespace mitk { + /** \brief Planar representing a double ellipse. + The double ellipse is either represented by 4 control points (center, outer major axis, outer minor axis and inner major axis) + or be one control point (center, fixed size mode). The mode is selected via the constructor. + */ class MITKPLANARFIGURE_EXPORT PlanarDoubleEllipse : public PlanarFigure { public: mitkClassMacro(PlanarDoubleEllipse, PlanarFigure); - itkFactorylessNewMacro(Self); + mitkNewMacro2Param(PlanarDoubleEllipse, double, double) + + itkFactorylessNewMacro(Self); itkCloneMacro(Self); unsigned int GetNumberOfSegments() const; void SetNumberOfSegments(unsigned int numSegments); unsigned int GetMaximumNumberOfControlPoints() const override; unsigned int GetMinimumNumberOfControlPoints() const override; bool SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist = true) override; const unsigned int FEATURE_ID_MAJOR_AXIS; const unsigned int FEATURE_ID_MINOR_AXIS; const unsigned int FEATURE_ID_THICKNESS; + static const unsigned int CP_CENTER = 0; + static const unsigned int CP_OUTER_MAJOR_AXIS = 1; + static const unsigned int CP_OUTER_MINOR_AXIS = 2; + static const unsigned int CP_INNER_MAJOR_AXIS = 3; + bool Equals(const mitk::PlanarFigure &other) const override; protected: PlanarDoubleEllipse(); + /** Constructor for fixed size mode.*/ + PlanarDoubleEllipse(double fixedRadius, double fixedThickness); mitkCloneMacro(Self); mitk::Point2D ApplyControlPointConstraints(unsigned int index, const Point2D &point) override; void EvaluateFeaturesInternal() override; void GenerateHelperPolyLine(double, unsigned int) override; void GeneratePolyLine() override; private: unsigned int m_NumberOfSegments; bool m_ConstrainCircle; bool m_ConstrainThickness; + double m_FixedRadius = 0; + double m_FixedThickness = 0; + bool m_SizeIsFixed = false; }; } #endif diff --git a/Modules/PlanarFigure/src/DataManagement/mitkPlanarCircle.cpp b/Modules/PlanarFigure/src/DataManagement/mitkPlanarCircle.cpp index 199977f3db..12e8abb842 100644 --- a/Modules/PlanarFigure/src/DataManagement/mitkPlanarCircle.cpp +++ b/Modules/PlanarFigure/src/DataManagement/mitkPlanarCircle.cpp @@ -1,187 +1,216 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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) + m_MinMaxRadiusContraintsActive(false), + m_RadiusFixed(false) { // Circle has two control points this->ResetNumberOfControlPoints(2); this->SetNumberOfPolyLines(1); this->SetProperty("closed", mitk::BoolProperty::New(true)); } +mitk::PlanarCircle::PlanarCircle(double fixedRadius) + : FEATURE_ID_RADIUS(this->AddFeature("Radius", "mm")), + FEATURE_ID_DIAMETER(this->AddFeature("Diameter", "mm")), + FEATURE_ID_AREA(this->AddFeature("Area", "mm2")), + m_MinRadius(fixedRadius), + m_MaxRadius(100), + m_MinMaxRadiusContraintsActive(false), + m_RadiusFixed(true) +{ + // Fixed Circle has 1 control points + this->ResetNumberOfControlPoints(1); + this->SetNumberOfPolyLines(1); + this->SetProperty("closed", mitk::BoolProperty::New(true)); +} + 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); - const vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector()); + if (!m_RadiusFixed) + { + Point2D boundaryPoint = GetControlPoint(1); + const vnl_vector vec = (point.GetVnlVector() - centerPoint.GetVnlVector()); - boundaryPoint[0] += vec[0]; - boundaryPoint[1] += vec[1]; + boundaryPoint[0] += vec[0]; + boundaryPoint[1] += vec[1]; + PlanarFigure::SetControlPoint(1, boundaryPoint); + } 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() == nullptr) { return point; } Point2D indexPoint; this->GetPlaneGeometry()->WorldToIndex(point, indexPoint); const 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); const double euclideanDinstanceFromCenterToPoint1 = centerPoint.EuclideanDistanceTo(point); Vector2D 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); - const double radius = centerPoint.EuclideanDistanceTo(boundaryPoint); + double radius = m_MinRadius; + + if (!m_RadiusFixed) + { + const Point2D &boundaryPoint = GetControlPoint(1); + radius = centerPoint.EuclideanDistanceTo(boundaryPoint); + } // Generate poly-line with 64 segments for (int t = 0; t < 64; ++t) { const 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 = m_MinRadius; + + if (!m_RadiusFixed) + { + const Point3D &p1 = this->GetWorldControlPoint(1); + radius = p0.EuclideanDistanceTo(p1); + } - const double radius = p0.EuclideanDistanceTo(p1); const 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(const PlanarFigure &other) const { const auto *otherCircle = dynamic_cast(&other); if (otherCircle) { return Superclass::Equals(other); } else { return false; } } diff --git a/Modules/PlanarFigure/src/DataManagement/mitkPlanarDoubleEllipse.cpp b/Modules/PlanarFigure/src/DataManagement/mitkPlanarDoubleEllipse.cpp index f2fd9030f1..7e553743fc 100644 --- a/Modules/PlanarFigure/src/DataManagement/mitkPlanarDoubleEllipse.cpp +++ b/Modules/PlanarFigure/src/DataManagement/mitkPlanarDoubleEllipse.cpp @@ -1,264 +1,294 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #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(double fixedRadius, double fixedThickness) + : 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), + m_FixedRadius(fixedRadius), + m_FixedThickness(fixedThickness), + m_SizeIsFixed(true) +{ + this->ResetNumberOfControlPoints(1); + this->SetNumberOfPolyLines(2); + this->SetProperty("closed", mitk::BoolProperty::New(true)); + + if (fixedThickness>fixedRadius) + { + mitkThrow() << "Invalid constructor of fixed sized double ellipses. Thickness (" << fixedThickness << ") is greater than the radius (" << fixedRadius << ")"; + } +} + mitk::Point2D mitk::PlanarDoubleEllipse::ApplyControlPointConstraints(unsigned int index, const Point2D &point) { if (index == 2 && !m_ConstrainCircle) { - const Point2D centerPoint = this->GetControlPoint(0); - const Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint; + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); + const Vector2D outerMajorVector = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - centerPoint; Vector2D minorDirection; minorDirection[0] = outerMajorVector[1]; minorDirection[1] = -outerMajorVector[0]; minorDirection.Normalize(); const double outerMajorRadius = outerMajorVector.GetNorm(); - const double innerMajorRadius = (this->GetControlPoint(3) - centerPoint).GetNorm(); + const double innerMajorRadius = (this->GetControlPoint(CP_INNER_MAJOR_AXIS) - centerPoint).GetNorm(); const ScalarType radius = std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius)); return centerPoint + minorDirection * radius; } else if (index == 3 && !m_ConstrainThickness) { - const Point2D centerPoint = this->GetControlPoint(0); - Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint; + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); + Vector2D outerMajorVector = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - centerPoint; const double outerMajorRadius = outerMajorVector.GetNorm(); - const double outerMinorRadius = (this->GetControlPoint(2) - centerPoint).GetNorm(); + const double outerMinorRadius = (this->GetControlPoint(CP_OUTER_MINOR_AXIS) - centerPoint).GetNorm(); const ScalarType radius = std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius)); outerMajorVector.Normalize(); return centerPoint - outerMajorVector * radius; } return point; } void mitk::PlanarDoubleEllipse::EvaluateFeaturesInternal() { - const Point2D centerPoint = this->GetControlPoint(0); - const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(1)); + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); + const ScalarType outerMajorRadius = (m_SizeIsFixed)? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MAJOR_AXIS)); + const ScalarType outerMinorRadius = (m_SizeIsFixed)? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS)); + const ScalarType thickness = (m_SizeIsFixed)? m_FixedThickness : outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS)); 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))); + this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * outerMinorRadius); + this->SetQuantity(FEATURE_ID_THICKNESS, thickness); } void mitk::PlanarDoubleEllipse::GenerateHelperPolyLine(double, unsigned int) { } void mitk::PlanarDoubleEllipse::GeneratePolyLine() { this->ClearPolyLines(); - const Point2D centerPoint = this->GetControlPoint(0); - const Point2D outerMajorPoint = this->GetControlPoint(1); + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); - Vector2D direction = outerMajorPoint - centerPoint; - direction.Normalize(); + Vector2D direction(0.); + direction[0] = 1.; + if (!m_SizeIsFixed) + { + direction = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - 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]; - const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(outerMajorPoint); - const ScalarType outerMinorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)); - const ScalarType innerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(3)); - const ScalarType innerMinorRadius = innerMajorRadius - (outerMajorRadius - outerMinorRadius); + const ScalarType outerMajorRadius = (m_SizeIsFixed) ? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MAJOR_AXIS)); + const ScalarType outerMinorRadius = (m_SizeIsFixed) ? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS)); + const ScalarType innerMajorRadius = (m_SizeIsFixed) ? (m_FixedRadius-m_FixedThickness) : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS)); + const ScalarType innerMinorRadius = (m_SizeIsFixed) ? (m_FixedRadius-m_FixedThickness) : innerMajorRadius - (outerMajorRadius - outerMinorRadius); - ScalarType angle; - ScalarType cosAngle; - ScalarType sinAngle; + ScalarType angle = 0; + ScalarType cosAngle = 0; + ScalarType sinAngle = 0; 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; + return (m_SizeIsFixed)? 1 : 4; } unsigned int mitk::PlanarDoubleEllipse::GetMinimumNumberOfControlPoints() const { - return 4; + return (m_SizeIsFixed)? 1 : 4; } bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist) { switch (index) { case 0: { - const Point2D centerPoint = this->GetControlPoint(0); + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); const 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); + if (!m_SizeIsFixed) + { + Superclass::SetControlPoint(1, this->GetControlPoint(CP_OUTER_MAJOR_AXIS) + vector, createIfDoesNotExist); + Superclass::SetControlPoint(2, this->GetControlPoint(CP_OUTER_MINOR_AXIS) + vector, createIfDoesNotExist); + Superclass::SetControlPoint(3, this->GetControlPoint(CP_INNER_MAJOR_AXIS) + vector, createIfDoesNotExist); + } break; } case 1: { - const Vector2D vector = point - this->GetControlPoint(1); + const Vector2D vector = point - this->GetControlPoint(CP_OUTER_MAJOR_AXIS); Superclass::SetControlPoint(1, point, createIfDoesNotExist); - const Point2D centerPoint = this->GetControlPoint(0); + const Point2D centerPoint = this->GetControlPoint(CP_CENTER); const 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)); + outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS)); } Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist); Vector2D innerMajorVector = outerMajorVector; if (!m_ConstrainThickness) { innerMajorVector.Normalize(); - innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(3) - vector); + innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS) - 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(const mitk::PlanarFigure &other) const { const auto *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; } }