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
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.