Medical Imaging Interaction Toolkit  2018.4.99-ef453c4b
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 
31 mitk::PlanarDoubleEllipse::PlanarDoubleEllipse(double fixedRadius, double fixedThickness)
32  : FEATURE_ID_MAJOR_AXIS(Superclass::AddFeature("Major Axis", "mm")),
33  FEATURE_ID_MINOR_AXIS(Superclass::AddFeature("Minor Axis", "mm")),
34  FEATURE_ID_THICKNESS(Superclass::AddFeature("Thickness", "mm")),
35  m_NumberOfSegments(64),
36  m_ConstrainCircle(true),
37  m_ConstrainThickness(true),
38  m_FixedRadius(fixedRadius),
39  m_FixedThickness(fixedThickness),
40  m_SizeIsFixed(true)
41 {
43  this->SetNumberOfPolyLines(2);
44  this->SetProperty("closed", mitk::BoolProperty::New(true));
45 
46  if (fixedThickness>fixedRadius)
47  {
48  mitkThrow() << "Invalid constructor of fixed sized double ellipses. Thickness (" << fixedThickness << ") is greater than the radius (" << fixedRadius << ")";
49  }
50 }
51 
53 {
54  if (index == 2 && !m_ConstrainCircle)
55  {
56  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
57  const Vector2D outerMajorVector = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - centerPoint;
58 
59  Vector2D minorDirection;
60  minorDirection[0] = outerMajorVector[1];
61  minorDirection[1] = -outerMajorVector[0];
62  minorDirection.Normalize();
63 
64  const double outerMajorRadius = outerMajorVector.GetNorm();
65  const double innerMajorRadius = (this->GetControlPoint(CP_INNER_MAJOR_AXIS) - centerPoint).GetNorm();
66  const ScalarType radius =
67  std::max(outerMajorRadius - innerMajorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
68 
69  return centerPoint + minorDirection * radius;
70  }
71  else if (index == 3 && !m_ConstrainThickness)
72  {
73  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
74  Vector2D outerMajorVector = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - centerPoint;
75 
76  const double outerMajorRadius = outerMajorVector.GetNorm();
77  const double outerMinorRadius = (this->GetControlPoint(CP_OUTER_MINOR_AXIS) - centerPoint).GetNorm();
78  const ScalarType radius =
79  std::max(outerMajorRadius - outerMinorRadius, std::min(centerPoint.EuclideanDistanceTo(point), outerMajorRadius));
80 
81  outerMajorVector.Normalize();
82 
83  return centerPoint - outerMajorVector * radius;
84  }
85 
86  return point;
87 }
88 
90 {
91  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
92  const ScalarType outerMajorRadius = (m_SizeIsFixed)? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MAJOR_AXIS));
93  const ScalarType outerMinorRadius = (m_SizeIsFixed)? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS));
94  const ScalarType thickness = (m_SizeIsFixed)? m_FixedThickness : outerMajorRadius - centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS));
95 
96  this->SetQuantity(FEATURE_ID_MAJOR_AXIS, 2 * outerMajorRadius);
97  this->SetQuantity(FEATURE_ID_MINOR_AXIS, 2 * outerMinorRadius);
98  this->SetQuantity(FEATURE_ID_THICKNESS, thickness);
99 }
100 
102 {
103 }
104 
106 {
107  this->ClearPolyLines();
108 
109  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
110 
111  Vector2D direction(0.);
112  direction[0] = 1.;
113  if (!m_SizeIsFixed)
114  {
115  direction = this->GetControlPoint(CP_OUTER_MAJOR_AXIS) - centerPoint;
116  direction.Normalize();
117  }
118 
119  const ScalarType deltaAngle = vnl_math::pi / (m_NumberOfSegments / 2);
120 
121  int start = 0;
122  int end = m_NumberOfSegments;
123 
124  if (direction[1] < 0.0)
125  {
126  direction[0] = -direction[0];
127  end = m_NumberOfSegments / 2;
128  start = -end;
129  }
130 
131  vnl_matrix_fixed<mitk::ScalarType, 2, 2> rotation;
132  rotation[1][0] = std::sin(std::acos(direction[0]));
133  rotation[0][0] = direction[0];
134  rotation[1][1] = direction[0];
135  rotation[0][1] = -rotation[1][0];
136 
137  const ScalarType outerMajorRadius = (m_SizeIsFixed) ? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MAJOR_AXIS));
138  const ScalarType outerMinorRadius = (m_SizeIsFixed) ? m_FixedRadius : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS));
139  const ScalarType innerMajorRadius = (m_SizeIsFixed) ? (m_FixedRadius-m_FixedThickness) : centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS));
140  const ScalarType innerMinorRadius = (m_SizeIsFixed) ? (m_FixedRadius-m_FixedThickness) : innerMajorRadius - (outerMajorRadius - outerMinorRadius);
141 
142  ScalarType angle = 0;
143  ScalarType cosAngle = 0;
144  ScalarType sinAngle = 0;
145  vnl_vector_fixed<mitk::ScalarType, 2> vector;
146  Point2D point;
147 
148  for (int i = start; i < end; ++i)
149  {
150  angle = i * deltaAngle;
151  cosAngle = std::cos(angle);
152  sinAngle = std::sin(angle);
153 
154  vector[0] = outerMajorRadius * cosAngle;
155  vector[1] = outerMinorRadius * sinAngle;
156  vector = rotation * vector;
157 
158  point[0] = centerPoint[0] + vector[0];
159  point[1] = centerPoint[1] + vector[1];
160 
161  this->AppendPointToPolyLine(0, point);
162 
163  vector[0] = innerMajorRadius * cosAngle;
164  vector[1] = innerMinorRadius * sinAngle;
165  vector = rotation * vector;
166 
167  point[0] = centerPoint[0] + vector[0];
168  point[1] = centerPoint[1] + vector[1];
169 
170  this->AppendPointToPolyLine(1, point);
171  }
172 }
173 
175 {
176  return m_NumberOfSegments;
177 }
178 
180 {
181  m_NumberOfSegments = std::max(4U, numSegments);
182 
183  if (this->IsPlaced())
184  {
185  this->GeneratePolyLine();
186  this->Modified();
187  }
188 }
189 
191 {
192  return (m_SizeIsFixed)? 1 : 4;
193 }
194 
196 {
197  return (m_SizeIsFixed)? 1 : 4;
198 }
199 
200 bool mitk::PlanarDoubleEllipse::SetControlPoint(unsigned int index, const Point2D &point, bool createIfDoesNotExist)
201 {
202  switch (index)
203  {
204  case 0:
205  {
206  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
207  const Vector2D vector = point - centerPoint;
208 
209  Superclass::SetControlPoint(0, point, createIfDoesNotExist);
210  if (!m_SizeIsFixed)
211  {
212  Superclass::SetControlPoint(1, this->GetControlPoint(CP_OUTER_MAJOR_AXIS) + vector, createIfDoesNotExist);
213  Superclass::SetControlPoint(2, this->GetControlPoint(CP_OUTER_MINOR_AXIS) + vector, createIfDoesNotExist);
214  Superclass::SetControlPoint(3, this->GetControlPoint(CP_INNER_MAJOR_AXIS) + vector, createIfDoesNotExist);
215  }
216 
217  break;
218  }
219 
220  case 1:
221  {
222  const Vector2D vector = point - this->GetControlPoint(CP_OUTER_MAJOR_AXIS);
223 
224  Superclass::SetControlPoint(1, point, createIfDoesNotExist);
225 
226  const Point2D centerPoint = this->GetControlPoint(CP_CENTER);
227  const Vector2D outerMajorVector = point - centerPoint;
228 
229  Vector2D outerMinorVector;
230  outerMinorVector[0] = outerMajorVector[1];
231  outerMinorVector[1] = -outerMajorVector[0];
232 
233  if (!m_ConstrainCircle)
234  {
235  outerMinorVector.Normalize();
236  outerMinorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_OUTER_MINOR_AXIS));
237  }
238 
239  Superclass::SetControlPoint(2, centerPoint + outerMinorVector, createIfDoesNotExist);
240 
241  Vector2D innerMajorVector = outerMajorVector;
242 
243  if (!m_ConstrainThickness)
244  {
245  innerMajorVector.Normalize();
246  innerMajorVector *= centerPoint.EuclideanDistanceTo(this->GetControlPoint(CP_INNER_MAJOR_AXIS) - vector);
247  }
248 
249  Superclass::SetControlPoint(3, centerPoint - innerMajorVector, createIfDoesNotExist);
250 
251  break;
252  }
253 
254  case 2:
255  {
256  m_ConstrainCircle = false;
257  Superclass::SetControlPoint(2, point, createIfDoesNotExist);
258 
259  break;
260  }
261 
262  case 3:
263  {
264  m_ConstrainThickness = false;
265  Superclass::SetControlPoint(3, point, createIfDoesNotExist);
266 
267  break;
268  }
269 
270  default:
271  return false;
272  }
273 
274  return true;
275 }
276 
278 {
279  const auto *otherDoubleEllipse = dynamic_cast<const mitk::PlanarDoubleEllipse *>(&other);
280  if (otherDoubleEllipse)
281  {
282  if (this->m_ConstrainCircle != otherDoubleEllipse->m_ConstrainCircle)
283  return false;
284  if (this->m_ConstrainThickness != otherDoubleEllipse->m_ConstrainThickness)
285  return false;
286  if (this->m_NumberOfSegments != otherDoubleEllipse->m_NumberOfSegments)
287  return false;
288  return Superclass::Equals(other);
289  }
290  else
291  {
292  return false;
293  }
294 }
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...
virtual unsigned int AddFeature(const char *featureName, const char *unitName)
double ScalarType
static const unsigned int CP_OUTER_MAJOR_AXIS
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 const unsigned int CP_CENTER
static const unsigned int CP_OUTER_MINOR_AXIS
static Matrix3D rotation
Planar representing a double ellipse. The double ellipse is either represented by 4 control points (c...
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
static const unsigned int CP_INNER_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)
void EvaluateFeaturesInternal() override
Calculates quantities of all features of this planar figure. Must be implemented in sub-classes...
#define mitkThrow()
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...
mitk::Point2D ApplyControlPointConstraints(unsigned int index, const Point2D &point) override
Allow sub-classes to apply constraints on control points.
void ClearPolyLines()
clears the list of PolyLines. Call before re-calculating a new Polyline.
unsigned int GetNumberOfSegments() const