Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkPlanarSubdivisionPolygon.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 "mitkPlaneGeometry.h"
19 #include "mitkProperties.h"
20 
21 // stl related includes
22 #include <algorithm>
23 
24 mitk::PlanarSubdivisionPolygon::PlanarSubdivisionPolygon() : m_TensionParameter(0.0625), m_SubdivisionRounds(5)
25 {
26  // Polygon is subdivision (in contrast to parent class PlanarPolygon
27  this->SetProperty("closed", mitk::BoolProperty::New(true));
28  this->SetProperty("subdivision", mitk::BoolProperty::New(true));
29 
30  // Other properties are inherited / already initialized by parent class PlanarPolygon
31 }
32 
34 {
35  this->ClearPolyLines();
36  ControlPointListType subdivisionPoints;
37  ControlPointListType newSubdivisionPoints;
38  subdivisionPoints.clear();
39  subdivisionPoints = m_ControlPoints;
40 
41  if (m_ControlPoints.size() >= GetMinimumNumberOfControlPoints())
42  {
43  for (unsigned int i = 0; i < GetSubdivisionRounds(); i++)
44  {
45  // Indices
46  unsigned int index, indexPrev, indexNext, indexNextNext;
47 
48  const unsigned int numberOfPoints = subdivisionPoints.size();
49 
50  Point2D newPoint;
51 
52  // Keep cycling our array indices forward until they wrap around at the end
53  for (index = 0; index < numberOfPoints; ++index)
54  {
55  // Create new subdivision point according to formula
56  // p_new = (0.5 + tension) * (p_here + p_next) - tension * (p_prev + p_nextnext)
57  indexPrev = (numberOfPoints + index - 1) % numberOfPoints;
58  indexNext = (index + 1) % numberOfPoints;
59  indexNextNext = (index + 2) % numberOfPoints;
60 
61  newPoint[0] =
62  (0.5 + GetTensionParameter()) * (double)(subdivisionPoints[index][0] + subdivisionPoints[indexNext][0]) -
63  GetTensionParameter() * (double)(subdivisionPoints[indexPrev][0] + subdivisionPoints[indexNextNext][0]);
64  newPoint[1] =
65  (0.5 + GetTensionParameter()) * (double)(subdivisionPoints[index][1] + subdivisionPoints[indexNext][1]) -
66  GetTensionParameter() * (double)(subdivisionPoints[indexPrev][1] + subdivisionPoints[indexNextNext][1]);
67 
68  newSubdivisionPoints.push_back(newPoint);
69  }
70 
71  ControlPointListType mergedSubdivisionPoints;
72  ControlPointListType::const_iterator it, itNew;
73 
74  for (it = subdivisionPoints.cbegin(), itNew = newSubdivisionPoints.cbegin(); it != subdivisionPoints.cend();
75  ++it, ++itNew)
76  {
77  mergedSubdivisionPoints.push_back(*it);
78  mergedSubdivisionPoints.push_back(*itNew);
79  }
80 
81  subdivisionPoints = mergedSubdivisionPoints;
82 
83  newSubdivisionPoints.clear();
84  }
85  }
86 
87  const bool isInitiallyPlaced = this->GetProperty("initiallyplaced");
88 
89  unsigned int i;
90  ControlPointListType::const_iterator it;
91  for (it = subdivisionPoints.cbegin(), i = 0; it != subdivisionPoints.cend(); ++it, ++i)
92  {
93  // Determine the index of the control point FOLLOWING this poly-line element
94  // (this is needed by PlanarFigureInteractor to insert new points at the correct position,
95  // namely BEFORE the next control point)
96  unsigned int nextIndex;
97  if (i == 0)
98  {
99  // For the FIRST polyline point, use the index of the LAST control point
100  // (it will used to check if the mouse is near the very last polyline element)
101  nextIndex = m_ControlPoints.size() - 1;
102  }
103  else
104  {
105  // For all other polyline points, use the index of the control point succeeding it
106  // (for polyline points lying on control points, the index of the previous control point
107  // is used)
108  nextIndex = (((i - 1) >> this->GetSubdivisionRounds()) + 1) % m_ControlPoints.size();
109  if (!isInitiallyPlaced && nextIndex > m_ControlPoints.size() - 2)
110  {
111  this->AppendPointToPolyLine(0, m_ControlPoints[m_ControlPoints.size() - 1]);
112  break;
113  }
114  }
115 
116  this->AppendPointToPolyLine(0, *it);
117  }
118  subdivisionPoints.clear();
119 }
120 
122 {
123  const mitk::PlanarSubdivisionPolygon *otherSubDivPoly = dynamic_cast<const mitk::PlanarSubdivisionPolygon *>(&other);
124  if (otherSubDivPoly)
125  {
126  if (this->m_SubdivisionRounds != otherSubDivPoly->m_SubdivisionRounds)
127  return false;
128  if (std::abs(this->m_TensionParameter - otherSubDivPoly->m_TensionParameter) > mitk::eps)
129  return false;
130  return Superclass::Equals(other);
131  }
132  else
133  {
134  return false;
135  }
136 }
137 
138 int mitk::PlanarSubdivisionPolygon::GetControlPointForPolylinePoint(int indexOfPolylinePoint, int polyLineIndex) const
139 {
140  const mitk::PlanarFigure::PolyLineType polyLine = GetPolyLine(polyLineIndex);
141 
142  if (indexOfPolylinePoint < 0 || indexOfPolylinePoint > static_cast<int>(polyLine.size()))
143  return -1;
144 
145  mitk::PlanarFigure::ControlPointListType::const_iterator elem;
146  mitk::PlanarFigure::ControlPointListType::const_iterator first = m_ControlPoints.cbegin();
147  mitk::PlanarFigure::ControlPointListType::const_iterator end = m_ControlPoints.cend();
148 
149  mitk::PlanarFigure::PolyLineType::const_iterator polyLineIter;
150  mitk::PlanarFigure::PolyLineType::const_iterator polyLineEnd = polyLine.cend();
151  mitk::PlanarFigure::PolyLineType::const_iterator polyLineStart = polyLine.cbegin();
152  polyLineStart += indexOfPolylinePoint;
153 
154  for (polyLineIter = polyLineStart; polyLineIter != polyLineEnd; ++polyLineIter)
155  {
156  elem = std::find(first, end, *polyLineIter);
157 
158  if (elem != end)
159  return std::distance(first, elem);
160  }
161 
162  return GetNumberOfControlPoints();
163 }
virtual bool Equals(const mitk::PlanarFigure &other) const override
Compare two PlanarFigure objects Note: all subclasses have to implement the method on their own...
int GetControlPointForPolylinePoint(int indexOfPolylinePoint, int polyLineIndex) const
Returns the id of the control-point that corresponds to the given polyline-point. ...
virtual void GeneratePolyLine() override
Generates the poly-line representation of the planar figure.
static Pointer New()
std::deque< Point2D > ControlPointListType
void SetProperty(const char *propertyKey, BaseProperty *property)
Implementation of PlanarFigure representing a polygon with two or more control points.
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
MITKCORE_EXPORT const ScalarType eps
std::vector< PolyLineElement > PolyLineType