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