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