Medical Imaging Interaction Toolkit  2016.11.0
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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 #include <mitkProperties.h>
19 
20 #include <algorithm>
21 
23  : FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")),
24  FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")),
25  FEATURE_ID_THICKNESS(Superclass::AddFeature("Thickness", "mm")),
26  m_NumberOfSegments(64),
27  m_ConstrainCircle(true),
28  m_ConstrainThickness(true)
29 {
31  this->SetNumberOfPolyLines(2);
32  this->SetProperty("closed", mitk::BoolProperty::New(true));
33 }
34 
36 {
37  if (index == 2 && !m_ConstrainCircle)
38  {
39  const Point2D centerPoint = this->GetControlPoint(0);
40  const Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
41 
42  Vector2D minorDirection;
43  minorDirection[0] = outerMajorVector[1];
44  minorDirection[1] = -outerMajorVector[0];
45  minorDirection.Normalize();
46 
47  const double outerMajorRadius = outerMajorVector.GetNorm();
48  const double innerMajorRadius = (this->GetControlPoint(3) - centerPoint).GetNorm();
49  const ScalarType radius =
50  std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
51 
52  return centerPoint + minorDirection * radius;
53  }
54  else if (index == 3 && !m_ConstrainThickness)
55  {
56  const Point2D centerPoint = this->GetControlPoint(0);
57  Vector2D outerMajorVector = this->GetControlPoint(1) - centerPoint;
58 
59  const double outerMajorRadius = outerMajorVector.GetNorm();
60  const double outerMinorRadius = (this->GetControlPoint(2) - centerPoint).GetNorm();
61  const ScalarType radius =
62  std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
63 
64  outerMajorVector.Normalize();
65 
66  return centerPoint - outerMajorVector * radius;
67  }
68 
69  return point;
70 }
71 
73 {
74  const Point2D centerPoint = this->GetControlPoint(0);
75  const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(1));
76 
77  this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * outerMajorRadius);
78  this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * centerPoint.EuclideanDistanceTo(this->GetControlPoint(2)));
79  this->SetQuantity(FEATURE_ID_THICKNESS, outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(3)));
80 }
81 
83 {
84 }
85 
87 {
88  this->ClearPolyLines();
89 
90  const Point2D centerPoint = this->GetControlPoint(0);
91  const Point2D outerMajorPoint = this->GetControlPoint(1);
92 
93  Vector2D direction = outerMajorPoint - centerPoint;
94  direction.Normalize();
95 
96  const ScalarType deltaAngle = vnl_math::pi / (m_NumberOfSegments / 2);
97 
98  int start = 0;
99  int end = m_NumberOfSegments;
100 
101  if (direction[1] < 0.0)
102  {
103  direction[0] = -direction[0];
104  end = m_NumberOfSegments / 2;
105  start = -end;
106  }
107 
108  vnl_matrix_fixed<mitk::ScalarType, 2, 2> rotation;
109  rotation[1][0] = std::sin(std::acos(direction[0]));
110  rotation[0][0] = direction[0];
111  rotation[1][1] = direction[0];
112  rotation[0][1] = -rotation[1][0];
113 
114  const ScalarType outerMajorRadius = centerPoint.EuclideanDistanceTo(outerMajorPoint);
115  const ScalarType outerMinorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
116  const ScalarType innerMajorRadius = centerPoint.EuclideanDistanceTo(this->GetControlPoint(3));
117  const ScalarType innerMinorRadius = innerMajorRadius - (outerMajorRadius - outerMinorRadius);
118 
119  ScalarType angle;
120  ScalarType cosAngle;
121  ScalarType sinAngle;
122  vnl_vector_fixed<mitk::ScalarType, 2> vector;
123  Point2D point;
124 
125  for (int i = start; i < end; ++i)
126  {
127  angle = i * deltaAngle;
128  cosAngle = std::cos(angle);
129  sinAngle = std::sin(angle);
130 
131  vector[0] = outerMajorRadius * cosAngle;
132  vector[1] = outerMinorRadius * sinAngle;
133  vector = rotation * vector;
134 
135  point[0] = centerPoint[0] + vector[0];
136  point[1] = centerPoint[1] + vector[1];
137 
138  this->AppendPointToPolyLine(0, point);
139 
140  vector[0] = innerMajorRadius * cosAngle;
141  vector[1] = innerMinorRadius * sinAngle;
142  vector = rotation * vector;
143 
144  point[0] = centerPoint[0] + vector[0];
145  point[1] = centerPoint[1] + vector[1];
146 
147  this->AppendPointToPolyLine(1, point);
148  }
149 }
150 
152 {
153  return m_NumberOfSegments;
154 }
155 
157 {
158  m_NumberOfSegments = std::max(4U, numSegments);
159 
160  if (this->IsPlaced())
161  {
162  this->GeneratePolyLine();
163  this->Modified();
164  }
165 }
166 
168 {
169  return 4;
170 }
171 
173 {
174  return 4;
175 }
176 
177 bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist)
178 {
179  switch (index)
180  {
181  case 0:
182  {
183  const Point2D centerPoint = this->GetControlPoint(0);
184  const Vector2D vector = point - centerPoint;
185 
186  Superclass::SetControlPoint(0, point, createIfDoesNotExist);
187  Superclass::SetControlPoint(1, this->GetControlPoint(1) + vector, createIfDoesNotExist);
188  Superclass::SetControlPoint(2, this->GetControlPoint(2) + vector, createIfDoesNotExist);
189  Superclass::SetControlPoint(3, this->GetControlPoint(3) + vector, createIfDoesNotExist);
190 
191  break;
192  }
193 
194  case 1:
195  {
196  const Vector2D vector = point - this->GetControlPoint(1);
197 
198  Superclass::SetControlPoint(1, point, createIfDoesNotExist);
199 
200  const Point2D centerPoint = this->GetControlPoint(0);
201  const Vector2D outerMajorVector = point - centerPoint;
202 
203  Vector2D outerMinorVector;
204  outerMinorVector[0] = outerMajorVector[1];
205  outerMinorVector[1] = -outerMajorVector[0];
206 
207  if (!m_ConstrainCircle)
208  {
209  outerMinorVector.Normalize();
210  outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(2));
211  }
212 
213  Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist);
214 
215  Vector2D innerMajorVector = outerMajorVector;
216 
217  if (!m_ConstrainThickness)
218  {
219  innerMajorVector.Normalize();
220  innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(3) - vector);
221  }
222 
223  Superclass::SetControlPoint(3, centerPoint - innerMajorVector, createIfDoesNotExist);
224 
225  break;
226  }
227 
228  case 2:
229  {
230  m_ConstrainCircle = false;
231  Superclass::SetControlPoint(2, point, createIfDoesNotExist);
232 
233  break;
234  }
235 
236  case 3:
237  {
238  m_ConstrainThickness = false;
239  Superclass::SetControlPoint(3, point, createIfDoesNotExist);
240 
241  break;
242  }
243 
244  default:
245  return false;
246  }
247 
248  return true;
249 }
250 
252 {
253  const mitk::PlanarDoubleEllipse *otherDoubleEllipse = dynamic_cast<const mitk::PlanarDoubleEllipse *>(&other);
254  if (otherDoubleEllipse)
255  {
256  if (this->m_ConstrainCircle != otherDoubleEllipse->m_ConstrainCircle)
257  return false;
258  if (this->m_ConstrainThickness != otherDoubleEllipse->m_ConstrainThickness)
259  return false;
260  if (this->m_NumberOfSegments != otherDoubleEllipse->m_NumberOfSegments)
261  return false;
262  return Superclass::Equals(other);
263  }
264  else
265  {
266  return false;
267  }
268 }
Point< ScalarType, 2 > Point2D
Definition: mitkPoint.h:98
virtual bool SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist=true) override
virtual 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
virtual 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:42
static Pointer New()
void SetProperty(const char *propertyKey, BaseProperty *property)
Vector< ScalarType, 2 > Vector2D
Definition: mitkVector.h:133
virtual mitkCloneMacro(Self) virtual 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.
virtual unsigned int GetMaximumNumberOfControlPoints() const override
Returns the maximum number of control points allowed for this figure (e.g. 3 for triangles).
static T max(T x, T y)
Definition: svm.cpp:70
unsigned int GetNumberOfSegments() const
virtual 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:67
void SetNumberOfPolyLines(unsigned int numberOfPolyLines)
defines the number of PolyLines that will be available
virtual 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...