Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkExtrudedContour.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 "mitkExtrudedContour.h"
18 #include "mitkBaseProcess.h"
19 #include "mitkNumericTypes.h"
21 
22 #include <vtkCellArray.h>
23 #include <vtkClipPolyData.h>
24 #include <vtkLinearExtrusionFilter.h>
25 #include <vtkPlanes.h>
26 #include <vtkPoints.h>
27 #include <vtkPolyData.h>
28 
29 #include <vtkDoubleArray.h>
30 #include <vtkFloatArray.h>
31 #include <vtkPlane.h>
32 #include <vtkPolygon.h>
33 
34 // vtkButterflySubdivisionFilter * subdivs;
35 #include <vtkCubeSource.h>
36 #include <vtkImageData.h>
37 #include <vtkLinearSubdivisionFilter.h>
38 #include <vtkSampleFunction.h>
39 #include <vtkTriangleFilter.h>
40 
42  : m_Contour(nullptr), m_ClippingGeometry(nullptr), m_AutomaticVectorGeneration(false)
43 {
45  timeGeometry->Initialize(1);
46  SetTimeGeometry(timeGeometry);
47 
48  FillVector3D(m_Vector, 0.0, 0.0, 1.0);
49  m_RightVector.Fill(0.0);
50 
52 
53  m_ExtrusionFilter->CappingOff();
54  m_ExtrusionFilter->SetExtrusionTypeToVectorExtrusion();
55 
56  double vtkvector[3] = {0, 0, 1};
57 
58  // set extrusion vector
59  m_ExtrusionFilter->SetVector(vtkvector);
60 
62  m_TriangleFilter->SetInputConnection(m_ExtrusionFilter->GetOutputPort());
63 
65  m_SubdivisionFilter->SetInputConnection(m_TriangleFilter->GetOutputPort());
66  m_SubdivisionFilter->SetNumberOfSubdivisions(4);
67 
70  m_ClipPolyDataFilter->SetInputConnection(m_SubdivisionFilter->GetOutputPort());
71  m_ClipPolyDataFilter->SetClipFunction(m_ClippingBox);
72  m_ClipPolyDataFilter->InsideOutOn();
73 
75 
77 }
78 
80 {
81  m_ClipPolyDataFilter->Delete();
82  m_ClippingBox->Delete();
83  m_SubdivisionFilter->Delete();
84  m_TriangleFilter->Delete();
85  m_ExtrusionFilter->Delete();
86  m_Polygon->Delete();
87 }
88 
89 bool mitk::ExtrudedContour::IsInside(const Point3D &worldPoint) const
90 {
91  static double polygonNormal[3] = {0.0, 0.0, 1.0};
92 
93  // project point onto plane
94  float xt[3];
95  itk2vtk(worldPoint, xt);
96 
97  xt[0] = worldPoint[0] - m_Origin[0];
98  xt[1] = worldPoint[1] - m_Origin[1];
99  xt[2] = worldPoint[2] - m_Origin[2];
100 
101  float dist = xt[0] * m_Normal[0] + xt[1] * m_Normal[1] + xt[2] * m_Normal[2];
102  xt[0] -= dist * m_Normal[0];
103  xt[1] -= dist * m_Normal[1];
104  xt[2] -= dist * m_Normal[2];
105 
106  double x[3];
107 
108  x[0] = xt[0] * m_Right[0] + xt[1] * m_Right[1] + xt[2] * m_Right[2];
109  x[1] = xt[0] * m_Down[0] + xt[1] * m_Down[1] + xt[2] * m_Down[2];
110  x[2] = 0;
111 
112  // determine whether it's in the selection loop and then evaluate point
113  // in polygon only if absolutely necessary.
114  if (x[0] >= this->m_ProjectedContourBounds[0] && x[0] <= this->m_ProjectedContourBounds[1] &&
115  x[1] >= this->m_ProjectedContourBounds[2] && x[1] <= this->m_ProjectedContourBounds[3] &&
116  this->m_Polygon->PointInPolygon(x,
117  m_Polygon->Points->GetNumberOfPoints(),
118  ((vtkDoubleArray *)this->m_Polygon->Points->GetData())->GetPointer(0),
119  (double *)const_cast<mitk::ExtrudedContour *>(this)->m_ProjectedContourBounds,
120  polygonNormal) == 1)
121  return true;
122  else
123  return false;
124 }
125 
127 {
128  return -1.0;
129 }
130 
132 {
133  if (this->GetSource())
134  {
135  this->GetSource()->UpdateOutputInformation();
136  }
137  if (GetMTime() > m_LastCalculateExtrusionTime)
138  {
139  BuildGeometry();
140  BuildSurface();
141  }
142  // if ( ( m_CalculateBoundingBox ) && ( m_PolyDataSeries.size() > 0 ) )
143  // CalculateBoundingBox();
144 }
145 
147 {
148  if (m_Contour.IsNull())
149  {
150  SetVtkPolyData(nullptr);
151  return;
152  }
153 
154  // set extrusion contour
155  vtkPolyData *polyData = vtkPolyData::New();
156  vtkCellArray *polys = vtkCellArray::New();
157 
158  polys->InsertNextCell(m_Polygon->GetPointIds());
159  polyData->SetPoints(m_Polygon->GetPoints());
160 
161  // float vtkpoint[3];
162  // unsigned int i, numPts = m_Polygon->GetNumberOfPoints();
163  // for(i=0; i<numPts; ++i)
164  //{
165  // float * vtkpoint = this->m_Polygon->Points->GetPoint(i);
166 
167  // pointids[i]=loopPoints->InsertNextPoint(vtkpoint);
168  //}
169  // polys->InsertNextCell( i, pointids );
170  // delete [] pointids;
171 
172  // polyData->SetPoints( loopPoints );
173  polyData->SetPolys(polys);
174  polys->Delete();
175 
176  m_ExtrusionFilter->SetInputData(polyData);
177 
178  polyData->Delete();
179 
180  // set extrusion scale factor
181  m_ExtrusionFilter->SetScaleFactor(GetGeometry()->GetExtentInMM(2));
182  SetVtkPolyData(m_SubdivisionFilter->GetOutput());
183  // if(m_ClippingGeometry.IsNull())
184  //{
185  // SetVtkPolyData(m_SubdivisionFilter->GetOutput());
186  //}
187  // else
188  //{
189  // m_ClipPolyDataFilter->SetInput(m_SubdivisionFilter->GetOutput());
190  // mitk::BoundingBox::BoundsArrayType bounds=m_ClippingGeometry->GetBounds();
191 
192  // m_ClippingBox->SetBounds(bounds[0], bounds[1], bounds[2], bounds[3], bounds[4], bounds[5]);
193  // m_ClippingBox->SetTransform(GetGeometry()->GetVtkTransform());
194  // m_ClipPolyDataFilter->SetClipFunction(m_ClippingBox);
195  // m_ClipPolyDataFilter->SetValue(0);
196  // SetVtkPolyData(m_ClipPolyDataFilter->GetOutput());
197  //}
198 
199  m_LastCalculateExtrusionTime.Modified();
200 }
201 
203 {
204  if (m_Contour.IsNull())
205  return;
206 
207  // Initialize(1);
208 
209  Vector3D nullvector;
210  nullvector.Fill(0.0);
211  float xProj[3];
212  unsigned int i;
213  unsigned int numPts = 20; // m_Contour->GetNumberOfPoints();
214  mitk::Contour::PathPointer path = m_Contour->GetContourPath();
215  mitk::Contour::PathType::InputType cstart = path->StartOfInput();
216  mitk::Contour::PathType::InputType cend = path->EndOfInput();
217  mitk::Contour::PathType::InputType cstep = (cend - cstart) / numPts;
218  mitk::Contour::PathType::InputType ccur;
219 
220  // Part I: guarantee/calculate legal vectors
221 
222  m_Vector.Normalize();
223  itk2vtk(m_Vector, m_Normal);
224  // check m_Vector
225  if (mitk::Equal(m_Vector, nullvector) || m_AutomaticVectorGeneration)
226  {
227  if (m_AutomaticVectorGeneration == false)
228  itkWarningMacro("Extrusion vector is 0 (" << m_Vector << "); trying to use normal of polygon");
229 
230  vtkPoints *loopPoints = vtkPoints::New();
231  // mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin();
232  double vtkpoint[3];
233 
234  unsigned int i = 0;
235  for (i = 0, ccur = cstart; i < numPts; ++i, ccur += cstep)
236  {
237  itk2vtk(path->Evaluate(ccur), vtkpoint);
238  loopPoints->InsertNextPoint(vtkpoint);
239  }
240 
241  // Make sure points define a loop with a m_Normal
242  vtkPolygon::ComputeNormal(loopPoints, m_Normal);
243  loopPoints->Delete();
244 
245  vtk2itk(m_Normal, m_Vector);
246  if (mitk::Equal(m_Vector, nullvector))
247  {
248  itkExceptionMacro("Cannot calculate normal of polygon");
249  }
250  }
251  // check m_RightVector
252  if ((mitk::Equal(m_RightVector, nullvector)) || (mitk::Equal(m_RightVector * m_Vector, 0.0) == false))
253  {
254  if (mitk::Equal(m_RightVector, nullvector))
255  {
256  itkDebugMacro("Right vector is 0. Calculating.");
257  }
258  else
259  {
260  itkWarningMacro("Right vector (" << m_RightVector << ") not perpendicular to extrusion vector " << m_Vector
261  << ": "
262  << m_RightVector * m_Vector);
263  }
264  // calculate a legal m_RightVector
265  if (mitk::Equal(m_Vector[1], 0.0f) == false)
266  {
267  FillVector3D(m_RightVector, 1.0f, -m_Vector[0] / m_Vector[1], 0.0f);
268  m_RightVector.Normalize();
269  }
270  else
271  {
272  FillVector3D(m_RightVector, 0.0f, 1.0f, 0.0f);
273  }
274  }
275 
276  // calculate down-vector
277  VnlVector rightDV = m_RightVector.GetVnlVector();
278  rightDV.normalize();
279  vnl2vtk(rightDV, m_Right);
280  VnlVector downDV = vnl_cross_3d(m_Vector.GetVnlVector(), rightDV);
281  downDV.normalize();
282  vnl2vtk(downDV, m_Down);
283 
284  // Part II: calculate plane as base for extrusion, project the contour
285  // on this plane and store as polygon for IsInside test and BoundingBox calculation
286 
287  // initialize m_ProjectionPlane, yet with origin at 0
288  m_ProjectionPlane->InitializeStandardPlane(rightDV, downDV);
289 
290  // create vtkPolygon from contour and simultaneously determine 2D bounds of
291  // contour projected on m_ProjectionPlane
292  // mitk::Contour::PointsContainerIterator pointsIt = m_Contour->GetPoints()->Begin();
293  m_Polygon->Points->Reset();
294  m_Polygon->Points->SetNumberOfPoints(numPts);
295  m_Polygon->PointIds->Reset();
296  m_Polygon->PointIds->SetNumberOfIds(numPts);
297  mitk::Point2D pt2d;
298  mitk::Point3D pt3d;
302  xProj[2] = 0.0;
303  for (i = 0, ccur = cstart; i < numPts; ++i, ccur += cstep)
304  {
305  pt3d.CastFrom(path->Evaluate(ccur));
306  m_ProjectionPlane->Map(pt3d, pt2d);
307  xProj[0] = pt2d[0];
308  if (pt2d[0] < min[0])
309  min[0] = pt2d[0];
310  if (pt2d[0] > max[0])
311  max[0] = pt2d[0];
312  xProj[1] = pt2d[1];
313  if (pt2d[1] < min[1])
314  min[1] = pt2d[1];
315  if (pt2d[1] > max[1])
316  max[1] = pt2d[1];
317  m_Polygon->Points->SetPoint(i, xProj);
318  m_Polygon->PointIds->SetId(i, i);
319  }
320  // shift parametric origin to (0,0)
321  for (i = 0; i < numPts; ++i)
322  {
323  double *pt = this->m_Polygon->Points->GetPoint(i);
324 
325  pt[0] -= min[0];
326  pt[1] -= min[1];
327  itkDebugMacro(<< i << ": (" << pt[0] << "," << pt[1] << "," << pt[2] << ")");
328  }
329  this->m_Polygon->GetBounds(m_ProjectedContourBounds);
330  // m_ProjectedContourBounds[4]=-1.0; m_ProjectedContourBounds[5]=1.0;
331 
332  // calculate origin (except translation along the normal) and bounds
333  // of m_ProjectionPlane:
334  // origin is composed of the minimum x-/y-coordinates of the polygon,
335  // bounds from the extent of the polygon, both after projecting on the plane
336  mitk::Point3D origin;
337  m_ProjectionPlane->Map(min, origin);
338  ScalarType bounds[6] = {0, max[0] - min[0], 0, max[1] - min[1], 0, 1};
339  m_ProjectionPlane->SetBounds(bounds);
340  m_ProjectionPlane->SetOrigin(origin);
341 
342  // Part III: initialize geometry
343  if (m_ClippingGeometry.IsNotNull())
344  {
347  unsigned char i;
348  for (i = 0; i < 8; ++i)
349  {
350  dist = m_ProjectionPlane->SignedDistance(m_ClippingGeometry->GetCornerPoint(i));
351  if (dist < min_dist)
352  min_dist = dist;
353  if (dist > max_dist)
354  max_dist = dist;
355  }
356  // incorporate translation along the normal into origin
357  origin = origin + m_Vector * min_dist;
358  m_ProjectionPlane->SetOrigin(origin);
359  bounds[5] = max_dist - min_dist;
360  }
361  else
362  bounds[5] = 20;
363 
364  itk2vtk(origin, m_Origin);
365 
366  mitk::BaseGeometry::Pointer g3d = GetGeometry(0);
367  assert(g3d.IsNotNull());
368  g3d->SetBounds(bounds);
369  g3d->SetIndexToWorldTransform(m_ProjectionPlane->GetIndexToWorldTransform());
370 
372  timeGeometry->Initialize(g3d, 1);
373  SetTimeGeometry(timeGeometry);
374 }
375 
376 unsigned long mitk::ExtrudedContour::GetMTime() const
377 {
378  unsigned long latestTime = Superclass::GetMTime();
379  if (m_Contour.IsNotNull())
380  {
381  unsigned long localTime;
382  localTime = m_Contour->GetMTime();
383  if (localTime > latestTime)
384  latestTime = localTime;
385  }
386  return latestTime;
387 }
vnl_vector< ScalarType > VnlVector
Definition: mitkVector.h:138
double ScalarType
virtual mitk::ScalarType GetVolume() override
vtkLinearSubdivisionFilter * m_SubdivisionFilter
virtual void SetTimeGeometry(TimeGeometry *geometry)
Set the TimeGeometry of the data, which will be referenced (not copied!).
vtkLinearExtrusionFilter * m_ExtrusionFilter
mitk::PlaneGeometry::Pointer m_ProjectionPlane
void FillVector3D(Tout &out, mitk::ScalarType x, mitk::ScalarType y, mitk::ScalarType z)
Definition: mitkArray.h:110
mitk::Vector3D m_RightVector
void vnl2vtk(const vnl_vector< Tin > &in, Tout *out)
virtual unsigned long GetMTime() const override
Get the modified time of the last change of the contents this data object or its geometry.
void vtk2itk(const Tin &in, Tout &out)
static T max(T x, T y)
Definition: svm.cpp:70
virtual void UpdateOutputInformation() override
PathType::Pointer PathPointer
Definition: mitkContour.h:43
static T min(T x, T y)
Definition: svm.cpp:67
void itk2vtk(const Tin &in, Tout &out)
vtkClipPolyData * m_ClipPolyDataFilter
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.
static Pointer New()
virtual bool IsInside(const Point3D &p) const override
vtkTriangleFilter * m_TriangleFilter
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.