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