Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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