Medical Imaging Interaction Toolkit  2018.4.99-a3d2e8fb
Medical Imaging Interaction Toolkit
mitkMeshMapper2D.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 "mitkMeshMapper2D.h"
14 #include "mitkBaseRenderer.h"
15 #include "mitkColorProperty.h"
16 #include "mitkGL.h"
17 #include "mitkLine.h"
18 #include "mitkMesh.h"
19 #include "mitkPlaneGeometry.h"
20 #include "mitkProperties.h"
21 
22 #include <vtkLinearTransform.h>
23 
24 #include <algorithm>
25 
26 const float selectedColor[] = {1.0f, 0.0f, 0.6f}; // for selected!
27 
29 {
30 }
31 
33 {
34 }
35 
37 {
38  return static_cast<const mitk::Mesh *>(GetDataNode()->GetData());
39 }
40 
41 // Return whether a point is "smaller" than the second
42 static bool point3DSmaller(const mitk::Point3D &elem1, const mitk::Point3D &elem2)
43 {
44  if (elem1[0] != elem2[0])
45  return elem1[0] < elem2[0];
46  if (elem1[1] != elem2[1])
47  return elem1[1] < elem2[1];
48  return elem1[2] < elem2[2];
49 }
50 
52 {
53  bool visible = true;
54 
55  GetDataNode()->GetVisibility(visible, renderer, "visible");
56 
57  if (!visible)
58  return;
59 
60  // @FIXME: Logik fuer update
61  bool updateNeccesary = true;
62 
63  if (updateNeccesary)
64  {
65  // aus GenerateData
66  mitk::Mesh::Pointer input = const_cast<mitk::Mesh *>(this->GetInput());
67 
68  // Get the TimeGeometry of the input object
69  const TimeGeometry *inputTimeGeometry = input->GetTimeGeometry();
70  if ((inputTimeGeometry == nullptr) || (inputTimeGeometry->CountTimeSteps() == 0))
71  {
72  return;
73  }
74 
75  //
76  // get the world time
77  //
78  ScalarType time = renderer->GetTime();
79 
80  //
81  // convert the world time in time steps of the input object
82  //
83  int timeStep = 0;
84  if (time > itk::NumericTraits<mitk::ScalarType>::NonpositiveMin())
85  timeStep = inputTimeGeometry->TimePointToTimeStep(time);
86  if (inputTimeGeometry->IsValidTimeStep(timeStep) == false)
87  {
88  return;
89  }
90 
91  mitk::Mesh::MeshType::Pointer itkMesh = input->GetMesh(timeStep);
92 
93  if (itkMesh.GetPointer() == nullptr)
94  {
95  return;
96  }
97 
98  const PlaneGeometry *worldplanegeometry = (renderer->GetCurrentWorldPlaneGeometry());
99 
100  // apply color and opacity read from the PropertyList
102 
103  vtkLinearTransform *transform = GetDataNode()->GetVtkTransform();
104 
105  // List of the Points
106  Mesh::DataType::PointsContainerConstIterator it, end;
107  it = itkMesh->GetPoints()->Begin();
108  end = itkMesh->GetPoints()->End();
109 
110  // iterator on the additional data of each point
111  Mesh::PointDataIterator dataIt; //, dataEnd;
112  dataIt = itkMesh->GetPointData()->Begin();
113 
114  // for switching back to old color after using selected color
115  float unselectedColor[4];
116  glGetFloatv(GL_CURRENT_COLOR, unselectedColor);
117 
118  while (it != end)
119  {
120  mitk::Point3D p, projected_p;
121  float vtkp[3];
122 
123  itk2vtk(it->Value(), vtkp);
124  transform->TransformPoint(vtkp, vtkp);
125  vtk2itk(vtkp, p);
126 
127  renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p);
128  Vector3D diff = p - projected_p;
129  if (diff.GetSquaredNorm() < 4.0)
130  {
131  Point2D pt2d, tmp;
132  renderer->WorldToDisplay(p, pt2d);
133 
134  Vector2D horz, vert;
135  horz[0] = 5;
136  horz[1] = 0;
137  vert[0] = 0;
138  vert[1] = 5;
139 
140  // check if the point is to be marked as selected
141  if (dataIt->Value().selected)
142  {
143  horz[0] = 8;
144  vert[1] = 8;
145  glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red
146 
147  switch (dataIt->Value().pointSpec)
148  {
149  case PTSTART:
150  // a quad
151  glBegin(GL_LINE_LOOP);
152  tmp = pt2d - horz + vert;
153  glVertex2dv(&tmp[0]);
154  tmp = pt2d + horz + vert;
155  glVertex2dv(&tmp[0]);
156  tmp = pt2d + horz - vert;
157  glVertex2dv(&tmp[0]);
158  tmp = pt2d - horz - vert;
159  glVertex2dv(&tmp[0]);
160  glEnd();
161  break;
162  case PTUNDEFINED:
163  // a diamond around the point
164  glBegin(GL_LINE_LOOP);
165  tmp = pt2d - horz;
166  glVertex2dv(&tmp[0]);
167  tmp = pt2d + vert;
168  glVertex2dv(&tmp[0]);
169  tmp = pt2d + horz;
170  glVertex2dv(&tmp[0]);
171  tmp = pt2d - vert;
172  glVertex2dv(&tmp[0]);
173  glEnd();
174  break;
175  default:
176  break;
177  } // switch
178 
179  // the actual point
180  glBegin(GL_POINTS);
181  tmp = pt2d;
182  glVertex2dv(&tmp[0]);
183  glEnd();
184  }
185  else // if not selected
186  {
187  glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]);
188  switch (dataIt->Value().pointSpec)
189  {
190  case PTSTART:
191  // a quad
192  glBegin(GL_LINE_LOOP);
193  tmp = pt2d - horz + vert;
194  glVertex2dv(&tmp[0]);
195  tmp = pt2d + horz + vert;
196  glVertex2dv(&tmp[0]);
197  tmp = pt2d + horz - vert;
198  glVertex2dv(&tmp[0]);
199  tmp = pt2d - horz - vert;
200  glVertex2dv(&tmp[0]);
201  glEnd();
202  break;
203  case PTUNDEFINED:
204  // drawing crosses
205  glBegin(GL_LINES);
206  tmp = pt2d - horz;
207  glVertex2dv(&tmp[0]);
208  tmp = pt2d + horz;
209  glVertex2dv(&tmp[0]);
210  tmp = pt2d - vert;
211  glVertex2dv(&tmp[0]);
212  tmp = pt2d + vert;
213  glVertex2dv(&tmp[0]);
214  glEnd();
215  break;
216  default:
217  {
218  break;
219  }
220  } // switch
221  } // else
222  }
223  ++it;
224  ++dataIt;
225  }
226 
227  // now connect the lines inbetween
228  mitk::Mesh::PointType thisPoint;
229  thisPoint.Fill(0);
230  Point2D *firstOfCell = nullptr;
231  Point2D *lastPoint = nullptr;
232  unsigned int lastPointId = 0;
233  bool lineSelected = false;
234 
235  Point3D firstOfCell3D;
236  Point3D lastPoint3D;
237  bool first;
239  std::vector<mitk::Point3D> intersectionPoints;
240  double t;
241 
242  // iterate through all cells and then iterate through all indexes of points in that cell
243  Mesh::CellIterator cellIt, cellEnd;
244  Mesh::CellDataIterator cellDataIt; //, cellDataEnd;
245  Mesh::PointIdIterator cellIdIt, cellIdEnd;
246 
247  cellIt = itkMesh->GetCells()->Begin();
248  cellEnd = itkMesh->GetCells()->End();
249  cellDataIt = itkMesh->GetCellData()->Begin();
250 
251  while (cellIt != cellEnd)
252  {
253  unsigned int numOfPointsInCell = cellIt->Value()->GetNumberOfPoints();
254  if (numOfPointsInCell > 1)
255  {
256  // iterate through all id's in the cell
257  cellIdIt = cellIt->Value()->PointIdsBegin();
258  cellIdEnd = cellIt->Value()->PointIdsEnd();
259 
260  firstOfCell3D = input->GetPoint(*cellIdIt, timeStep);
261 
262  intersectionPoints.clear();
263  intersectionPoints.reserve(numOfPointsInCell);
264 
265  first = true;
266 
267  while (cellIdIt != cellIdEnd)
268  {
269  lastPoint3D = thisPoint;
270 
271  thisPoint = input->GetPoint(*cellIdIt, timeStep);
272 
273  // search in data (vector<> selectedLines) if the index of the point is set. if so, then the line is selected.
274  lineSelected = false;
275  Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines;
276 
277  // a line between 1(lastPoint) and 2(pt2d) has the Id 1, so look for the Id of lastPoint
278  // since we only start, if we have more than one point in the cell, lastPointId is initiated with 0
279  auto position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId);
280  if (position != selectedLines.end())
281  {
282  lineSelected = true;
283  }
284 
285  mitk::Point3D p, projected_p;
286  float vtkp[3];
287  itk2vtk(thisPoint, vtkp);
288  transform->TransformPoint(vtkp, vtkp);
289  vtk2itk(vtkp, p);
290  renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p);
291  Vector3D diff = p - projected_p;
292  if (diff.GetSquaredNorm() < 4.0)
293  {
294  Point2D pt2d, tmp;
295  renderer->WorldToDisplay(p, pt2d);
296 
297  if (lastPoint == nullptr)
298  {
299  // set the first point in the cell. This point in needed to close the polygon
300  firstOfCell = new Point2D;
301  *firstOfCell = pt2d;
302  lastPoint = new Point2D;
303  *lastPoint = pt2d;
304  lastPointId = *cellIdIt;
305  }
306  else
307  {
308  if (lineSelected)
309  {
310  glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red
311  // a line from lastPoint to thisPoint
312  glBegin(GL_LINES);
313  glVertex2dv(&(*lastPoint)[0]);
314  glVertex2dv(&pt2d[0]);
315  glEnd();
316  }
317  else // if not selected
318  {
319  glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]);
320  // drawing crosses
321  glBegin(GL_LINES);
322  glVertex2dv(&(*lastPoint)[0]);
323  glVertex2dv(&pt2d[0]);
324  glEnd();
325  }
326  // to draw the line to the next in iteration step
327  *lastPoint = pt2d;
328  // and to search for the selection state of the line
329  lastPointId = *cellIdIt;
330  } // if..else
331  } // if <4.0
332 
333  // fill off-plane polygon part 1
334  if ((!first) && (worldplanegeometry != nullptr))
335  {
336  line.SetPoints(lastPoint3D, thisPoint);
337  if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1)))
338  {
339  intersectionPoints.push_back(line.GetPoint(t));
340  }
341  }
342  ++cellIdIt;
343  first = false;
344  } // while cellIdIter
345 
346  // closed polygon?
347  if (cellDataIt->Value().closed)
348  {
349  // close the polygon if needed
350  if (firstOfCell != nullptr)
351  {
352  lineSelected = false;
353  Mesh::SelectedLinesType selectedLines = cellDataIt->Value().selectedLines;
354  auto position = std::find(selectedLines.begin(), selectedLines.end(), lastPointId);
355  if (position != selectedLines.end()) // found the index
356  {
357  glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red
358  // a line from lastPoint to firstPoint
359  glBegin(GL_LINES);
360  glVertex2dv(&(*lastPoint)[0]);
361  glVertex2dv(&(*firstOfCell)[0]);
362  glEnd();
363  }
364  else
365  {
366  glColor3f(unselectedColor[0], unselectedColor[1], unselectedColor[2]);
367  glBegin(GL_LINES);
368  glVertex2dv(&(*lastPoint)[0]);
369  glVertex2dv(&(*firstOfCell)[0]);
370  glEnd();
371  }
372  }
373  } // if closed
374 
375  // Axis-aligned bounding box(AABB) around the cell if selected and set in Property
376  bool showBoundingBox;
377  if (dynamic_cast<mitk::BoolProperty *>(this->GetDataNode()->GetProperty("showBoundingBox")) == nullptr)
378  showBoundingBox = false;
379  else
380  showBoundingBox =
381  dynamic_cast<mitk::BoolProperty *>(this->GetDataNode()->GetProperty("showBoundingBox"))->GetValue();
382 
383  if (showBoundingBox)
384  {
385  if (cellDataIt->Value().selected)
386  {
387  mitk::Mesh::DataType::BoundingBoxPointer aABB = input->GetBoundingBoxFromCell(cellIt->Index());
388  if (aABB.IsNotNull())
389  {
391  min = aABB->GetMinimum();
392  max = aABB->GetMaximum();
393 
394  // project to the displayed geometry
395  Point2D min2D, max2D;
396  Point3D p, projected_p;
397  float vtkp[3];
398  itk2vtk(min, vtkp);
399  transform->TransformPoint(vtkp, vtkp);
400  vtk2itk(vtkp, p);
401  renderer->WorldToDisplay(p, min2D);
402 
403  itk2vtk(max, vtkp);
404  transform->TransformPoint(vtkp, vtkp);
405  vtk2itk(vtkp, p);
406  renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p);
407  Vector3D diff = p - projected_p;
408  if (diff.GetSquaredNorm() < 4.0)
409  {
410  renderer->WorldToDisplay(p, max2D);
411 
412  // draw the BoundingBox
413  glColor3f(selectedColor[0], selectedColor[1], selectedColor[2]); // red
414  // a line from lastPoint to firstPoint
415  glBegin(GL_LINE_LOOP);
416  glVertex2f(min2D[0], min2D[1]);
417  glVertex2f(min2D[0], max2D[1]);
418  glVertex2f(max2D[0], max2D[1]);
419  glVertex2f(max2D[0], min2D[1]);
420  glEnd();
421  } // draw bounding-box
422  } // bounding-box exists
423  } // cell selected
424  } // show bounding-box
425 
426  // fill off-plane polygon part 2
427  if (worldplanegeometry != nullptr)
428  {
429  // consider line from last to first
430  line.SetPoints(thisPoint, firstOfCell3D);
431  if (worldplanegeometry->IntersectionPointParam(line, t) && ((t >= 0) && (t <= 1)))
432  {
433  intersectionPoints.push_back(line.GetPoint(t));
434  }
435  std::sort(intersectionPoints.begin(), intersectionPoints.end(), point3DSmaller);
436  std::vector<mitk::Point3D>::iterator it, end;
437  end = intersectionPoints.end();
438  if ((intersectionPoints.size() % 2) != 0)
439  {
440  --end; // ensure even number of intersection-points
441  }
442  Point2D pt2d;
443  for (it = intersectionPoints.begin(); it != end; ++it)
444  {
445  glBegin(GL_LINES);
446  renderer->WorldToDisplay(*it, pt2d);
447  glVertex2dv(pt2d.GetDataPointer());
448  ++it;
449  renderer->WorldToDisplay(*it, pt2d);
450  glVertex2dv(pt2d.GetDataPointer());
451  glEnd();
452  }
453  if (it != intersectionPoints.end())
454  {
455  glBegin(GL_LINES);
456  renderer->WorldToDisplay(*it, pt2d);
457  glVertex2dv(pt2d.GetDataPointer());
458  glVertex2dv(pt2d.GetDataPointer());
459  glEnd();
460  }
461  } // fill off-plane polygon part 2
462  } // if numOfPointsInCell>1
463  delete firstOfCell;
464  delete lastPoint;
465  lastPoint = nullptr;
466  firstOfCell = nullptr;
467  lastPointId = 0;
468  ++cellIt;
469  ++cellDataIt;
470  }
471  }
472 }
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr, bool fallBackOnDataProperties=true) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
static bool point3DSmaller(const mitk::Point3D &elem1, const mitk::Point3D &elem2)
ScalarType GetTime() const
Get the time in ms of the currently displayed content.
Point< ScalarType, 2 > Point2D
Definition: mitkPoint.h:94
Descibes a line.
Definition: mitkLine.h:28
static char * line
Definition: svm.cpp:2870
virtual TimeStepType CountTimeSteps() const =0
Returns the number of time steps.
DataType::CellDataContainerIterator CellDataIterator
Definition: mitkMesh.h:65
virtual DataNode * GetDataNode() const
Get the DataNode containing the data to map. Method only returns valid DataNode Pointer if the mapper...
Definition: mitkMapper.cpp:31
double ScalarType
bool IntersectionPointParam(const Line3D &line, double &t) const
Calculate line parameter of intersection point between the plane and a line.
Organizes the rendering process.
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
virtual bool Project(const mitk::Point3D &pt3d_mm, mitk::Point3D &projectedPt3d_mm) const
Project a 3D point given in mm (pt3d_mm) onto the 2D geometry. The result is a 3D point in mm (projec...
void WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const
This method converts a 3D world index to the display point using the geometry of the renderWindow...
const itk::Point< TCoordRep, NPointDimension > & GetPoint() const
Get start point of the line.
Definition: mitkLine.h:49
Superclass::DataType::CellsContainer::Iterator CellIterator
Definition: mitkMesh.h:66
std::vector< unsigned int > SelectedLinesType
cellDataType, that stores all indexes of the lines, that are selected e.g.: points A...
Definition: mitkPointSet.h:108
void Paint(mitk::BaseRenderer *renderer) override
Do the painting into the renderer.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
DataStructure which stores a set of points (incl. pointdata) where each point can be associated to an...
Definition: mitkMesh.h:50
virtual TimeStepType TimePointToTimeStep(TimePointType timePoint) const =0
Converts a time point to the corresponding time step.
void SetPoints(const itk::Point< TCoordRep, NPointDimension > &point1, const itk::Point< TCoordRep, NPointDimension > &point2)
Define line by two points.
Definition: mitkLine.h:90
void ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor *actor=nullptr) override
Apply color and opacity properties read from the PropertyList. The actor is not used in the GLMappers...
bool GetVisibility(bool &visible, const mitk::BaseRenderer *renderer, const char *propertyKey="visible") const
Convenience access method for visibility properties (instances of BoolProperty with property-key "vis...
Definition: mitkDataNode.h:421
const mitk::Mesh * GetInput(void)
Get the Mesh to map.
void vtk2itk(const Tin &in, Tout &out)
vtkLinearTransform * GetVtkTransform(int t=0) const
Get the transformation applied prior to displaying the data as a vtkTransform.
static T max(T x, T y)
Definition: svm.cpp:56
static T min(T x, T y)
Definition: svm.cpp:53
void itk2vtk(const Tin &in, Tout &out)
const float selectedColor[]
Describes a two-dimensional, rectangular plane.
DataType::PointDataContainerIterator PointDataIterator
Definition: mitkPointSet.h:138
CellTraits::PointIdIterator PointIdIterator
Definition: mitkMesh.h:63
BoundingBoxType::Pointer BoundingBoxPointer
virtual bool IsValidTimeStep(TimeStepType timeStep) const =0
Test for the given time step if a geometry is availible.