Medical Imaging Interaction Toolkit  2018.4.99-12ad79a3
Medical Imaging Interaction Toolkit
mitkPlanarDoubleEllipse.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 #include <mitkProperties.h>
15 
16 #include <algorithm>
17 
19  : FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")),
20  FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")),
21  FEATURE_ID_THICKNESS(Superclass::AddFeature("Thickness", "mm")),
22  m_NumberOfSegments(64),
23  m_ConstrainCircle(true),
24  m_ConstrainThickness(true)
25 {
27  this->SetNumberOfPolyLines(2);
28  this->SetProperty("closed", mitk::BoolProperty::New(true));
29 }
30 
32 {
33  if (index == 2 && !m_ConstrainCircle)
34  {
35  const Point2D centerPoint = this->GetControlPoint(0);
36  const Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
37 
38  Vector2D minorDirection;
39  minorDirection[0] = outerMajorVector[1];
40  minorDirection[1] = -outerMajorVector[0];
41  minorDirection.Normalize();
42 
43  const double outerMajorRadius = outerMajorVector.GetNorm();
44  const double innerMajorRadius = (this->GetControlPoint(3) - centerPoint).GetNorm();
45  const ScalarType radius =
46  std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
47 
48  return centerPoint + minorDirection * radius;
49  }
50  else if (index == 3 && !m_ConstrainThickness)
51  {
52  const Point2D centerPoint = this->GetControlPoint(0);
53  Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
54 
55  const double outerMajorRadius = outerMajorVector.GetNorm();
56  const double outerMinorRadius = (this->GetControlPoint(2) - centerPoint).GetNorm();
57  const ScalarType radius =
58  std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
59 
60  outerMajorVector.Normalize();
61 
62  return centerPoint - outerMajorVector * radius;
63  }
64 
65  return point;
66 }
67 
69 {
70  const Point2D centerPoint = this->GetControlPoint(0);
71  const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(1));
72 
73  this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * outerMajorRadius);
74  this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)));
75  this->SetQuantity(FEATURE_ID_THICKNESS, outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(3)));
76 }
77 
79 {
80 }
81 
83 {
84  this->ClearPolyLines();
85 
86  const Point2D centerPoint = this->GetControlPoint(0);
87  const Point2D outerMajorPoint = this->GetControlPoint(1);
88 
89  Vector2D direction = outerMajorPoint - centerPoint;
90  direction.Normalize();
91 
92  const ScalarType deltaAngle = vnl_math::pi / (m_NumberOfSegments / 2);
93 
94  int start = 0;
95  int end = m_NumberOfSegments;
96 
97  if (direction[1] < 0.0)
98  {
99  direction[0] = -direction[0];
100  end = m_NumberOfSegments / 2;
101  start = -end;
102  }
103 
104  vnl_matrix_fixed<mitk::ScalarType, 2, 2> rotation;
105  rotation[1][0] = std::sin(std::acos(direction[0]));
106  rotation[0][0] = direction[0];
107  rotation[1][1] = direction[0];
108  rotation[0][1] = -rotation[1][0];
109 
110  const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(outerMajorPoint);
111  const ScalarType outerMinorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
112  const ScalarType innerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(3));
113  const ScalarType innerMinorRadius = innerMajorRadius - (outerMajorRadius - outerMinorRadius);
114 
115  ScalarType angle;
116  ScalarType cosAngle;
117  ScalarType sinAngle;
118  vnl_vector_fixed<mitk::ScalarType, 2> vector;
119  Point2D point;
120 
121  for (int i = start; i < end; ++i)
122  {
123  angle = i * deltaAngle;
124  cosAngle = std::cos(angle);
125  sinAngle = std::sin(angle);
126 
127  vector[0] = outerMajorRadius * cosAngle;
128  vector[1] = outerMinorRadius * sinAngle;
129  vector = rotation * vector;
130 
131  point[0] = centerPoint[0] + vector[0];
132  point[1] = centerPoint[1] + vector[1];
133 
134  this->AppendPointToPolyLine(0, point);
135 
136  vector[0] = innerMajorRadius * cosAngle;
137  vector[1] = innerMinorRadius * sinAngle;
138  vector = rotation * vector;
139 
140  point[0] = centerPoint[0] + vector[0];
141  point[1] = centerPoint[1] + vector[1];
142 
143  this->AppendPointToPolyLine(1, point);
144  }
145 }
146 
148 {
149  return m_NumberOfSegments;
150 }
151 
153 {
154  m_NumberOfSegments = std::max(4U, numSegments);
155 
156  if (this->IsPlaced())
157  {
158  this->GeneratePolyLine();
159  this->Modified();
160  }
161 }
162 
164 {
165  return 4;
166 }
167 
169 {
170  return 4;
171 }
172 
173 bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist)
174 {
175  switch (index)
176  {
177  case 0:
178  {
179  const Point2D centerPoint = this->GetControlPoint(0);
180  const Vector2D vector = point - centerPoint;
181 
182  Superclass::SetControlPoint(0, point, createIfDoesNotExist);
183  Superclass::SetControlPoint(1, this->GetControlPoint(1) + vector, createIfDoesNotExist);
184  Superclass::SetControlPoint(2, this->GetControlPoint(2) + vector, createIfDoesNotExist);
185  Superclass::SetControlPoint(3, this->GetControlPoint(3) + vector, createIfDoesNotExist);
186 
187  break;
188  }
189 
190  case 1:
191  {
192  const Vector2D vector = point - this->GetControlPoint(1);
193 
194  Superclass::SetControlPoint(1, point, createIfDoesNotExist);
195 
196  const Point2D centerPoint = this->GetControlPoint(0);
197  const Vector2D outerMajorVector = point - centerPoint;
198 
199  Vector2D outerMinorVector;
200  outerMinorVector[0] = outerMajorVector[1];
201  outerMinorVector[1] = -outerMajorVector[0];
202 
203  if (!m_ConstrainCircle)
204  {
205  outerMinorVector.Normalize();
206  outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
207  }
208 
209  Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist);
210 
211  Vector2D innerMajorVector = outerMajorVector;
212 
213  if (!m_ConstrainThickness)
214  {
215  innerMajorVector.Normalize();
216  innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(3) - vector);
217  }
218 
219  Superclass::SetControlPoint(3, centerPoint - innerMajorVector, createIfDoesNotExist);
220 
221  break;
222  }
223 
224  case 2:
225  {
226  m_ConstrainCircle = false;
227  Superclass::SetControlPoint(2, point, createIfDoesNotExist);
228 
229  break;
230  }
231 
232  case 3:
233  {
234  m_ConstrainThickness = false;
235  Superclass::SetControlPoint(3, point, createIfDoesNotExist);
236 
237  break;
238  }
239 
240  default:
241  return false;
242  }
243 
244  return true;
245 }
246 
248 {
249  const auto *otherDoubleEllipse = dynamic_cast<const mitk::PlanarDoubleEllipse *>(&other);
250  if (otherDoubleEllipse)
251  {
252  if (this->m_ConstrainCircle != otherDoubleEllipse->m_ConstrainCircle)
253  return false;
254  if (this->m_ConstrainThickness != otherDoubleEllipse->m_ConstrainThickness)
255  return false;
256  if (this->m_NumberOfSegments != otherDoubleEllipse->m_NumberOfSegments)
257  return false;
258  return Superclass::Equals(other);
259  }
260  else
261  {
262  return false;
263  }
264 }
Point2D GetControlPoint(unsigned int index) const
Returns specified control point in 2D world coordinates.
bool SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist=true) override
void GenerateHelperPolyLine(double, unsigned int) override
Generates the poly-lines that should be drawn the same size regardless of zoom. Must be implemented i...
double ScalarType
unsigned int GetMinimumNumberOfControlPoints() const override
Returns the minimum number of control points needed to represent this figure.
void SetNumberOfSegments(unsigned int numSegments)
void ResetNumberOfControlPoints(int numberOfControlPoints)
Set the initial number of control points of the planar figure.
static Matrix3D rotation
itk::DataObject Superclass
Definition: mitkBaseData.h:41
void SetProperty(const std::string &propertyKey, BaseProperty *property, const std::string &contextName="", bool fallBackOnDefaultContext=false) override
Add new or change existent property.
const unsigned int FEATURE_ID_THICKNESS
static Pointer New()
const unsigned int FEATURE_ID_MAJOR_AXIS
virtual bool IsPlaced() const
True if the planar figure has been placed (and can be displayed/interacted with). ...
void SetQuantity(unsigned int index, double quantity)
mitkCloneMacro(Self) mitk void EvaluateFeaturesInternal() override
Calculates quantities of all features of this planar figure. Must be implemented in sub-classes...
virtual Point2D ApplyControlPointConstraints(unsigned int, const Point2D &point)
Allow sub-classes to apply constraints on control points.
unsigned int GetMaximumNumberOfControlPoints() const override
Returns the maximum number of control points allowed for this figure (e.g. 3 for triangles).
const unsigned int FEATURE_ID_MINOR_AXIS
static T max(T x, T y)
Definition: svm.cpp:56
void AppendPointToPolyLine(unsigned int index, PolyLineElement element)
Append a point to the PolyLine # index.
void GeneratePolyLine() override
Generates the poly-line representation of the planar figure. Must be implemented in sub-classes...
static T min(T x, T y)
Definition: svm.cpp:53
void SetNumberOfPolyLines(unsigned int numberOfPolyLines)
defines the number of PolyLines that will be available
bool Equals(const mitk::PlanarFigure &other) const override
Compare two PlanarFigure objects Note: all subclasses have to implement the method on their own...
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void ClearPolyLines()
clears the list of PolyLines. Call before re-calculating a new Polyline.
unsigned int GetNumberOfSegments() const