Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkPlanarAngle.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 
13 #include "mitkPlanarAngle.h"
14 #include "mitkPlaneGeometry.h"
15 
16 mitk::PlanarAngle::PlanarAngle() : FEATURE_ID_ANGLE(this->AddFeature("Angle", "deg"))
17 {
18  // Start with two control points
20 
21  this->SetNumberOfPolyLines(1);
23 
24  m_HelperPolyLinesToBePainted->InsertElement(0, false);
25 }
26 
28 {
29  this->ClearPolyLines();
30 
31  for (unsigned int i = 0; i < this->GetNumberOfControlPoints(); i++)
32  this->AppendPointToPolyLine(0, this->GetControlPoint(i));
33 }
34 
35 void mitk::PlanarAngle::GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight)
36 {
37  // Generate helper-poly-line for angle
38  if (this->GetNumberOfControlPoints() < 3)
39  {
40  m_HelperPolyLinesToBePainted->SetElement(0, false);
41  return; // We do not need to draw an angle as there are no two arms yet
42  }
43 
44  this->ClearHelperPolyLines();
45 
46  const Point2D centerPoint = this->GetControlPoint(1);
47  const Point2D boundaryPointOne = this->GetControlPoint(0);
48  const Point2D boundaryPointTwo = this->GetControlPoint(2);
49 
50  double radius = centerPoint.EuclideanDistanceTo(boundaryPointOne);
51  if (radius > centerPoint.EuclideanDistanceTo(boundaryPointTwo))
52  {
53  radius = centerPoint.EuclideanDistanceTo(boundaryPointTwo);
54  }
55 
56  // Fixed size radius depending on screen size for the angle
57  double nonScalingRadius = displayHeight * mmPerDisplayUnit * 0.05;
58 
59  if (nonScalingRadius > radius)
60  {
61  m_HelperPolyLinesToBePainted->SetElement(0, false);
62  return; // if the arc has a radius that is longer than the shortest arm it should not be painted
63  }
64 
65  m_HelperPolyLinesToBePainted->SetElement(0, true);
66  radius = nonScalingRadius;
67 
68  double angle = this->GetQuantity(FEATURE_ID_ANGLE);
69 
70  // Determine from which arm the angle should be drawn
71 
72  Vector2D v0 = boundaryPointOne - centerPoint;
73  Vector2D v1 = boundaryPointTwo - centerPoint;
74  Vector2D v2;
75  v2[0] = 1.0;
76  v2[1] = 0.0;
77 
78  v0[0] = v0[0] * cos(0.001) - v0[1] * sin(0.001); // rotate one arm a bit
79  v0[1] = v0[0] * sin(0.001) + v0[1] * cos(0.001);
80  v0.Normalize();
81  v1.Normalize();
82  double testAngle = acos(v0 * v1);
83  // if the rotated arm is closer to the other arm than before it is the one from which we start drawing
84  // else we start drawing from the other arm (we want to draw in the mathematically positive direction)
85  if (angle > testAngle)
86  {
87  v1[0] = v0[0] * cos(-0.001) - v0[1] * sin(-0.001);
88  v1[1] = v0[0] * sin(-0.001) + v0[1] * cos(-0.001);
89 
90  // We determine if the arm is mathematically forward or backward
91  // assuming we rotate between -pi and pi
92  if (acos(v0 * v2) > acos(v1 * v2))
93  {
94  testAngle = acos(v1 * v2);
95  }
96  else
97  {
98  testAngle = -acos(v1 * v2);
99  }
100  }
101  else
102  {
103  v0[0] = v1[0] * cos(-0.001) - v1[1] * sin(-0.001);
104  v0[1] = v1[0] * sin(-0.001) + v1[1] * cos(-0.001);
105  // We determine if the arm is mathematically forward or backward
106  // assuming we rotate between -pi and pi
107  if (acos(v0 * v2) < acos(v1 * v2))
108  {
109  testAngle = acos(v1 * v2);
110  }
111  else
112  {
113  testAngle = -acos(v1 * v2);
114  }
115  }
116  // Generate poly-line with 16 segments
117  for (int t = 0; t < 16; ++t)
118  {
119  double alpha = (double)t * angle / 15.0 + testAngle;
120 
121  Point2D polyLinePoint;
122  polyLinePoint[0] = centerPoint[0] + radius * cos(alpha);
123  polyLinePoint[1] = centerPoint[1] + radius * sin(alpha);
124 
125  this->AppendPointToHelperPolyLine(0, polyLinePoint);
126  }
127 }
128 
130 {
131  if (this->GetNumberOfControlPoints() < 3)
132  {
133  // Angle not yet complete.
134  return;
135  }
136 
137  // Calculate angle between lines
138  const Point2D &p0 = this->GetControlPoint(0);
139  const Point2D &p1 = this->GetControlPoint(1);
140  const Point2D &p2 = this->GetControlPoint(2);
141 
142  Vector2D v0 = p1 - p0;
143  Vector2D v1 = p1 - p2;
144 
145  v0.Normalize();
146  v1.Normalize();
147  double angle = acos(v0 * v1);
148 
149  this->SetQuantity(FEATURE_ID_ANGLE, angle);
150 }
151 
152 void mitk::PlanarAngle::PrintSelf(std::ostream &os, itk::Indent indent) const
153 {
154  Superclass::PrintSelf(os, indent);
155 }
156 
157 bool mitk::PlanarAngle::Equals(const PlanarFigure &other) const
158 {
159  const auto *otherAngle = dynamic_cast<const mitk::PlanarAngle *>(&other);
160  if (otherAngle)
161  {
162  return Superclass::Equals(other);
163  }
164  else
165  {
166  return false;
167  }
168 }
bool Equals(const mitk::PlanarFigure &other) const override
Compare two PlanarFigure objects Note: all subclasses have to implement the method on their own...
void PrintSelf(std::ostream &os, itk::Indent indent) const override
Point2D GetControlPoint(unsigned int index) const
Returns specified control point in 2D world coordinates.
Implementation of PlanarFigure to display an angle through three control points.
void GenerateHelperPolyLine(double mmPerDisplayUnit, unsigned int displayHeight) override
Generates the poly-lines that should be drawn the same size regardless of zoom.
void ResetNumberOfControlPoints(int numberOfControlPoints)
Set the initial number of control points of the planar figure.
void GeneratePolyLine() override
Generates the poly-line representation of the planar figure.
double GetQuantity(unsigned int index) const
void EvaluateFeaturesInternal() override
Calculates feature quantities of the planar figure.
unsigned int GetNumberOfControlPoints() const
Returns the current number of 2D control points defining this figure.
void SetQuantity(unsigned int index, double quantity)
void SetNumberOfHelperPolyLines(unsigned int numberOfHelperPolyLines)
defines the number of HelperPolyLines that will be available
void AppendPointToPolyLine(unsigned int index, PolyLineElement element)
Append a point to the PolyLine # index.
void SetNumberOfPolyLines(unsigned int numberOfPolyLines)
defines the number of PolyLines that will be available
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
void AppendPointToHelperPolyLine(unsigned int index, PolyLineElement element)
Append a point to the HelperPolyLine # index.
void ClearHelperPolyLines()
clears the list of HelperPolyLines. Call before re-calculating a new HelperPolyline.
BoolContainerType::Pointer m_HelperPolyLinesToBePainted
const unsigned int FEATURE_ID_ANGLE
void ClearPolyLines()
clears the list of PolyLines. Call before re-calculating a new Polyline.