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