Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkExtrudePlanarFigureFilter.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 "mitkPlanarFigure.h"
19 #include <mitkPlaneGeometry.h>
20 #include <mitkSurface.h>
21 #include <vtkCellArray.h>
22 #include <vtkPoints.h>
23 #include <vtkPolyData.h>
24 #include <vtkPolyDataNormals.h>
25 #include <vtkSmartPointer.h>
26 
28 {
29  mitk::Point2D centerPoint;
30 
31  centerPoint[0] = 0;
32  centerPoint[1] = 0;
33 
34  auto polyLineEnd = polyLine.cend();
35 
36  for (auto polyLineIter = polyLine.cbegin(); polyLineIter != polyLineEnd; ++polyLineIter)
37  {
38  centerPoint[0] += static_cast<mitk::Point2D>(*polyLineIter)[0];
39  centerPoint[1] += static_cast<mitk::Point2D>(*polyLineIter)[1];
40  }
41 
42  const size_t numPoints = polyLine.size();
43 
44  centerPoint[0] /= numPoints;
45  centerPoint[1] /= numPoints;
46 
47  return centerPoint;
48 }
49 
51 {
52  mitk::Point2D centerPoint;
53 
54  centerPoint[0] = 0;
55  centerPoint[1] = 0;
56 
57  const size_t numPolyLines = planarFigure->GetPolyLinesSize();
58 
59  for (size_t i = 0; i < numPolyLines; ++i)
60  {
61  const mitk::Point2D polyLineCenterPoint = GetCenterPoint(planarFigure->GetPolyLine(i));
62 
63  centerPoint[0] += polyLineCenterPoint[0];
64  centerPoint[1] += polyLineCenterPoint[1];
65  }
66 
67  centerPoint[0] /= numPolyLines;
68  centerPoint[1] /= numPolyLines;
69 
70  return centerPoint;
71 }
72 
74  const mitk::Point2D &centerPoint2d,
75  const mitk::Vector2D &bendDirection2d)
76 {
77  const mitk::Point2D point2d = centerPoint2d + bendDirection2d;
78 
79  mitk::Point3D point3d;
80  planeGeometry->Map(point2d, point3d);
81 
82  mitk::Point3D centerPoint3d;
83  planeGeometry->Map(centerPoint2d, centerPoint3d);
84 
85  mitk::Vector3D bendDirection3d = point3d - centerPoint3d;
86  bendDirection3d.Normalize();
87 
88  return bendDirection3d;
89 }
90 
92  : m_Length(1), m_NumberOfSegments(1), m_TwistAngle(0), m_BendAngle(0), m_FlipDirection(false), m_FlipNormals(false)
93 {
94  m_BendDirection[0] = 0;
95  m_BendDirection[1] = 0;
96 
97  this->SetNumberOfRequiredInputs(1);
98  this->SetNumberOfRequiredOutputs(1);
99 
100  this->SetNthOutput(0, this->MakeOutput(0));
101 }
102 
104 {
105 }
106 
108 {
109  typedef PlanarFigure::PolyLineType PolyLine;
110  typedef PolyLine::const_iterator PolyLineConstIter;
111 
112  if (m_Length <= 0)
113  mitkThrow() << "Length is not positive!";
114 
115  if (m_NumberOfSegments == 0)
116  mitkThrow() << "Number of segments is zero!";
117 
118  if (m_BendAngle != 0 && m_BendDirection[0] == 0 && m_BendDirection[1] == 0)
119  mitkThrow() << "Bend direction is zero-length vector!";
120 
121  PlanarFigure *input = dynamic_cast<PlanarFigure *>(this->GetPrimaryInput());
122 
123  if (input == nullptr)
124  mitkThrow() << "Primary input is not a planar figure!";
125 
126  size_t numPolyLines = input->GetPolyLinesSize();
127 
128  if (numPolyLines == 0)
129  mitkThrow() << "Primary input does not contain any poly lines!";
130 
131  const PlaneGeometry *planeGeometry = dynamic_cast<const PlaneGeometry *>(input->GetPlaneGeometry());
132 
133  if (planeGeometry == nullptr)
134  mitkThrow() << "Could not get plane geometry from primary input!";
135 
136  Vector3D planeNormal = planeGeometry->GetNormal();
137  planeNormal.Normalize();
138 
139  const Point2D centerPoint2d = GetCenterPoint(input);
140 
141  Point3D centerPoint3d;
142  planeGeometry->Map(centerPoint2d, centerPoint3d);
143 
144  const Vector3D bendDirection3d =
145  m_BendAngle != 0 ? ::GetBendDirection(planeGeometry, centerPoint2d, m_BendDirection) : Vector3D();
146 
147  const ScalarType radius = m_Length * (360 / m_BendAngle) / (2 * vnl_math::pi);
148  const Vector3D scaledBendDirection3d = bendDirection3d * radius;
149 
150  Vector3D bendAxis = itk::CrossProduct(planeNormal, bendDirection3d);
151  bendAxis.Normalize();
152 
153  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
154  vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
155  vtkIdType baseIndex = 0;
156 
157  for (size_t i = 0; i < numPolyLines; ++i)
158  {
159  const PolyLine polyLine = input->GetPolyLine(i);
160  const size_t numPoints = polyLine.size();
161 
162  if (numPoints < 2)
163  mitkThrow() << "Poly line " << i << " of primary input consists of less than two points!";
164 
165  std::vector<mitk::Point3D> crossSection;
166 
167  PolyLineConstIter polyLineEnd = polyLine.end();
168 
169  for (PolyLineConstIter polyLineIter = polyLine.begin(); polyLineIter != polyLineEnd; ++polyLineIter)
170  {
171  Point3D point;
172  planeGeometry->Map(*polyLineIter, point);
173  crossSection.push_back(point);
174  }
175 
176  const ScalarType segmentLength = m_Length / m_NumberOfSegments;
177  Vector3D translation = planeNormal * segmentLength;
178 
179  const bool bend = std::abs(m_BendAngle) > mitk::eps;
180  const bool twist = std::abs(m_TwistAngle) > mitk::eps;
181 
182  const ScalarType twistAngle = twist ? m_TwistAngle / m_NumberOfSegments * vnl_math::pi / 180 : 0;
183 
184  ScalarType bendAngle = bend ? m_BendAngle / m_NumberOfSegments * vnl_math::pi / 180 : 0;
185 
186  if (m_FlipDirection)
187  {
188  translation *= -1;
189  bendAngle *= -1;
190  }
191 
192  for (size_t k = 0; k < numPoints; ++k)
193  points->InsertNextPoint(crossSection[k].GetDataPointer());
194 
195  for (size_t j = 1; j <= m_NumberOfSegments; ++j)
196  {
198 
199  if (bend || twist)
200  transform->Translate(centerPoint3d.GetVectorFromOrigin(), true);
201 
202  if (bend)
203  {
204  transform->Translate(scaledBendDirection3d, true);
205  transform->Rotate3D(bendAxis, bendAngle * j, true);
206  transform->Translate(-scaledBendDirection3d, true);
207  }
208  else
209  {
210  transform->Translate(translation * j, true);
211  }
212 
213  if (twist)
214  transform->Rotate3D(planeNormal, twistAngle * j, true);
215 
216  if (bend || twist)
217  transform->Translate(-centerPoint3d.GetVectorFromOrigin(), true);
218 
219  for (size_t k = 0; k < numPoints; ++k)
220  {
221  const mitk::Point3D transformedPoint = transform->TransformPoint(crossSection[k]);
222  points->InsertNextPoint(transformedPoint.GetDataPointer());
223  }
224  }
225 
226  for (size_t j = 0; j < m_NumberOfSegments; ++j)
227  {
228  for (size_t k = 1; k < numPoints; ++k)
229  {
230  vtkIdType cell[3];
231  cell[0] = baseIndex + j * numPoints + (k - 1);
232  cell[1] = baseIndex + (j + 1) * numPoints + (k - 1);
233  cell[2] = baseIndex + j * numPoints + k;
234 
235  cells->InsertNextCell(3, cell);
236 
237  cell[0] = cell[1];
238  cell[1] = baseIndex + (j + 1) * numPoints + k;
239 
240  cells->InsertNextCell(3, cell);
241  }
242 
243  if (input->IsClosed() && numPoints > 2)
244  {
245  vtkIdType cell[3];
246  cell[0] = baseIndex + j * numPoints + (numPoints - 1);
247  cell[1] = baseIndex + (j + 1) * numPoints + (numPoints - 1);
248  cell[2] = baseIndex + j * numPoints;
249 
250  cells->InsertNextCell(3, cell);
251 
252  cell[0] = cell[1];
253  cell[1] = baseIndex + (j + 1) * numPoints;
254 
255  cells->InsertNextCell(3, cell);
256  }
257  }
258 
259  baseIndex += points->GetNumberOfPoints();
260  }
261 
262  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
263  polyData->SetPoints(points);
264  polyData->SetPolys(cells);
265 
266  vtkSmartPointer<vtkPolyDataNormals> polyDataNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
267  polyDataNormals->SetFlipNormals(m_FlipNormals);
268  polyDataNormals->SetInputData(polyData);
269  polyDataNormals->SplittingOff();
270 
271  polyDataNormals->Update();
272 
273  Surface *output = static_cast<Surface *>(this->GetPrimaryOutput());
274  output->SetVtkPolyData(polyDataNormals->GetOutput());
275 }
276 
278 {
279 }
280 
281 itk::ProcessObject::DataObjectPointer mitk::ExtrudePlanarFigureFilter::MakeOutput(DataObjectPointerArraySizeType idx)
282 {
283  return idx == 0 ? Surface::New().GetPointer() : nullptr;
284 }
285 
286 itk::ProcessObject::DataObjectPointer mitk::ExtrudePlanarFigureFilter::MakeOutput(const DataObjectIdentifierType &name)
287 {
288  return this->IsIndexedOutputName(name) ? this->MakeOutput(this->MakeIndexFromOutputName(name)) : nullptr;
289 }
290 
291 void mitk::ExtrudePlanarFigureFilter::PrintSelf(std::ostream &os, itk::Indent indent) const
292 {
293  Superclass::PrintSelf(os, indent);
294 
295  os << indent << "Length: " << m_Length << std::endl;
296  os << indent << "Number of Segments: " << m_NumberOfSegments << std::endl;
297  os << indent << "Twist Angle: " << m_TwistAngle << std::endl;
298  os << indent << "Bend Angle: " << m_BendAngle << std::endl;
299  os << indent << "Bend Direction: " << m_BendDirection << std::endl;
300  os << indent << "Flip Normals: " << m_FlipNormals << std::endl;
301 }
302 
304 {
305  this->SetPrimaryInput(planarFigure);
306 }
307 
309 {
310  return static_cast<Surface *>(this->GetPrimaryOutput());
311 }
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:32
itk::SmartPointer< Self > Pointer
virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const
Project a 3D point given in mm (pt3d_mm) onto the 2D geometry. The result is a 2D point in mm (pt2d_m...
double ScalarType
virtual const PlaneGeometry * GetPlaneGeometry() const
Returns (previously set) 2D geometry of this figure.
const PolyLineType GetPolyLine(unsigned int index)
Returns the polyline representing the planar figure (for rendering, measurements, etc...
Vector3D GetNormal() const
Normal of the plane.
Vector< ScalarType, 3 > Vector3D
Definition: mitkVector.h:134
virtual bool IsClosed() const
True if the planar figure is closed.
#define mitkThrow()
virtual unsigned short GetPolyLinesSize()
Returns the current number of polylines.
virtual void SetVtkPolyData(vtkPolyData *polydata, unsigned int t=0)
void PrintSelf(std::ostream &os, itk::Indent indent) const override
static mitk::Vector3D GetBendDirection(const mitk::PlaneGeometry *planeGeometry, const mitk::Point2D &centerPoint2d, const mitk::Vector2D &bendDirection2d)
virtual DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override
Base-class for geometric planar (2D) figures, such as lines, circles, rectangles, polygons...
MITKCORE_EXPORT const ScalarType eps
std::vector< PolyLineElement > PolyLineType
Describes a two-dimensional, rectangular plane.
static Pointer New()
void SetInput(mitk::PlanarFigure *planarFigure)
static mitk::Point2D GetCenterPoint(const mitk::PlanarFigure::PolyLineType &polyLine)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.