Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkGizmoMapper2D.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 "mitkGizmoMapper2D.h"
18 
19 #include "mitkGizmo.h"
20 
21 // MITK includes
22 #include <mitkBaseRenderer.h>
27 
28 // VTK includes
29 #include <vtkAppendPolyData.h>
30 #include <vtkCamera.h>
31 #include <vtkCellArray.h>
32 #include <vtkCharArray.h>
33 #include <vtkConeSource.h>
34 #include <vtkMath.h>
35 #include <vtkPointData.h>
36 #include <vtkSphereSource.h>
37 #include <vtkVectorOperators.h>
38 
39 mitk::GizmoMapper2D::LocalStorage::LocalStorage()
40 {
41  m_VtkPolyDataMapper = vtkSmartPointer<vtkPainterPolyDataMapper>::New();
43  m_Actor->SetMapper(m_VtkPolyDataMapper);
44 }
45 
46 const mitk::Gizmo *mitk::GizmoMapper2D::GetInput()
47 {
48  return static_cast<const Gizmo *>(GetDataNode()->GetData());
49 }
50 
52 {
53  LocalStorage *ls = m_LSH.GetLocalStorage(renderer);
54  ls->m_Actor->VisibilityOff();
55 }
56 
57 namespace
58 {
60  void AssignScalarValueTo(vtkPolyData *polydata, char value)
61  {
62  vtkSmartPointer<vtkCharArray> pointData = vtkSmartPointer<vtkCharArray>::New();
63 
64  int numberOfPoints = polydata->GetNumberOfPoints();
65  pointData->SetNumberOfComponents(1);
66  pointData->SetNumberOfTuples(numberOfPoints);
67  pointData->FillComponent(0, value);
68  polydata->GetPointData()->SetScalars(pointData);
69  }
70 
74  vtkSmartPointer<vtkPolyData> Create2DDisk(mitk::Vector3D viewRight,
75  mitk::Vector3D viewUp,
76  mitk::Point3D center,
77  double radius)
78 
79  {
80  // build the axis itself (as a tube around the line defining the axis)
81  vtkSmartPointer<vtkPolyData> disk = vtkSmartPointer<vtkPolyData>::New();
82 
83  mitk::Vector3D ringPointer;
84  unsigned int numberOfRingPoints = 36;
85  vtkSmartPointer<vtkPoints> ringPoints = vtkSmartPointer<vtkPoints>::New();
86  vtkSmartPointer<vtkCellArray> ringPoly = vtkSmartPointer<vtkCellArray>::New();
87  ringPoly->InsertNextCell(numberOfRingPoints + 1);
88  for (unsigned int segment = 0; segment < numberOfRingPoints; ++segment)
89  {
90  double x = std::cos((double)(segment) / (double)numberOfRingPoints * 2.0 * vtkMath::Pi());
91  double y = std::sin((double)(segment) / (double)numberOfRingPoints * 2.0 * vtkMath::Pi());
92 
93  ringPointer = viewRight * x + viewUp * y;
94 
95  ringPoints->InsertPoint(segment, (center + ringPointer * radius).GetDataPointer());
96  ringPoly->InsertCellPoint(segment);
97  }
98  ringPoly->InsertCellPoint(0);
99 
100  disk->SetPoints(ringPoints);
101  disk->SetPolys(ringPoly);
102 
103  return disk;
104  }
105 
111  vtkSmartPointer<vtkPolyData> Create2DArrow(mitk::Vector3D cameraDirection,
112  mitk::Point3D arrowStart,
113  mitk::Point3D arrowTip,
114  int vertexValueMove,
115  int vertexValueScale)
116  {
117  mitk::Vector3D arrowDirection = arrowTip - arrowStart;
118  mitk::Vector3D arrowOrthogonal = itk::CrossProduct(cameraDirection, arrowDirection);
119  arrowOrthogonal.Normalize();
120 
121  double triangleFraction = 0.2;
122 
123  vtkSmartPointer<vtkPolyData> arrow = vtkSmartPointer<vtkPolyData>::New();
124  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
125  // shaft : points 0, 1
126  points->InsertPoint(0, arrowStart.GetDataPointer());
127  points->InsertPoint(1, (arrowStart + arrowDirection * (1.0 - triangleFraction)).GetDataPointer());
128 
129  // tip : points 2, 3, 4
130  points->InsertPoint(2, arrowTip.GetDataPointer());
131  points->InsertPoint(3,
132  (arrowStart + (1.0 - triangleFraction) * arrowDirection +
133  arrowOrthogonal * (0.5 * triangleFraction * arrowDirection.GetNorm()))
134  .GetDataPointer());
135  points->InsertPoint(4,
136  (arrowStart + (1.0 - triangleFraction) * arrowDirection -
137  arrowOrthogonal * (0.5 * triangleFraction * arrowDirection.GetNorm()))
138  .GetDataPointer());
139  arrow->SetPoints(points);
140 
141  // define line connection for shaft
142  vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
143  vtkIdType shaftLinePoints[] = {0, 1};
144  lines->InsertNextCell(2, shaftLinePoints);
145  arrow->SetLines(lines);
146 
147  // define polygon for triangle
148  vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
149  vtkIdType tipLinePoints[] = {2, 3, 4};
150  polys->InsertNextCell(3, tipLinePoints);
151  arrow->SetPolys(polys);
152 
153  // assign scalar values
154  vtkSmartPointer<vtkCharArray> pointData = vtkSmartPointer<vtkCharArray>::New();
155  pointData->SetNumberOfComponents(1);
156  pointData->SetNumberOfTuples(5);
157  pointData->FillComponent(0, vertexValueScale);
158  pointData->SetTuple1(0, vertexValueMove);
159  pointData->SetTuple1(1, vertexValueMove);
160  arrow->GetPointData()->SetScalars(pointData);
161 
162  return arrow;
163  }
164 }
165 
167 {
168  return m_LSH.GetLocalStorage(renderer)->m_VtkPolyDataMapper->GetInput();
169 }
170 
171 void mitk::GizmoMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer)
172 {
173  auto gizmo = GetInput();
174  auto node = GetDataNode();
175 
176  LocalStorage *ls = m_LSH.GetLocalStorage(renderer);
177 
178  // check if something important has changed and we need to re-render
179  if ((ls->m_LastUpdateTime >= node->GetMTime()) && (ls->m_LastUpdateTime >= gizmo->GetPipelineMTime()) &&
180  (ls->m_LastUpdateTime >= renderer->GetCurrentWorldPlaneGeometryUpdateTime()) &&
181  (ls->m_LastUpdateTime >= renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) &&
182  (ls->m_LastUpdateTime >= node->GetPropertyList()->GetMTime()) &&
183  (ls->m_LastUpdateTime >= node->GetPropertyList(renderer)->GetMTime()))
184  {
185  return;
186  }
187 
188  ls->m_LastUpdateTime.Modified();
189 
190  // some special handling around visibility: let two properties steer
191  // visibility in 2D instead of many renderer specific "visible" properties
192  bool visible2D = true;
193  this->GetDataNode()->GetBoolProperty("show in 2D", visible2D);
194  if (!visible2D && renderer->GetMapperID() == BaseRenderer::Standard2D)
195  {
196  ls->m_Actor->VisibilityOff();
197  return;
198  }
199  else
200  {
201  ls->m_Actor->VisibilityOn();
202  }
203 
204  auto camera = renderer->GetVtkRenderer()->GetActiveCamera();
205 
206  auto plane = renderer->GetCurrentWorldPlaneGeometry();
207 
208  Point3D gizmoCenterView = plane->ProjectPointOntoPlane(gizmo->GetCenter());
209 
210  Vector3D viewUp;
211  camera->GetViewUp(viewUp.GetDataPointer());
212  Vector3D cameraDirection;
213  camera->GetDirectionOfProjection(cameraDirection.GetDataPointer());
214  Vector3D viewRight = itk::CrossProduct(viewUp, cameraDirection);
215 
216  auto appender = vtkSmartPointer<vtkAppendPolyData>::New();
217 
218  double diagonal = std::min(renderer->GetSizeX(), renderer->GetSizeY());
219  double arrowLength = 0.1 * diagonal; // fixed in relation to window size
220  auto disk = Create2DDisk(viewRight, viewUp, gizmoCenterView - cameraDirection, 0.1 * arrowLength);
221  AssignScalarValueTo(disk, Gizmo::MoveFreely);
222  appender->AddInputData(disk);
223 
224  // loop over directions -1 and +1 for arrows
225  for (double direction = -1.0; direction < 2.0; direction += 2.0)
226  {
227  auto axisX =
228  Create2DArrow(cameraDirection,
229  gizmoCenterView,
230  plane->ProjectPointOntoPlane(gizmo->GetCenter() + (gizmo->GetAxisX() * arrowLength) * direction),
232  Gizmo::ScaleX);
233  appender->AddInputData(axisX);
234 
235  auto axisY =
236  Create2DArrow(cameraDirection,
237  gizmoCenterView,
238  plane->ProjectPointOntoPlane(gizmo->GetCenter() + (gizmo->GetAxisY() * arrowLength) * direction),
240  Gizmo::ScaleY);
241  appender->AddInputData(axisY);
242 
243  auto axisZ =
244  Create2DArrow(cameraDirection,
245  gizmoCenterView,
246  plane->ProjectPointOntoPlane(gizmo->GetCenter() + (gizmo->GetAxisZ() * arrowLength) * direction),
248  Gizmo::ScaleZ);
249  appender->AddInputData(axisZ);
250  }
251 
252  ls->m_VtkPolyDataMapper->SetInputConnection(appender->GetOutputPort());
253 
254  ApplyVisualProperties(renderer);
255 }
256 
257 void mitk::GizmoMapper2D::ApplyVisualProperties(BaseRenderer *renderer)
258 {
259  LocalStorage *ls = m_LSH.GetLocalStorage(renderer);
260 
261  float lineWidth = 3.0f;
262  ls->m_Actor->GetProperty()->SetLineWidth(lineWidth);
263 
264  mitk::LookupTableProperty::Pointer lookupTableProp;
265  this->GetDataNode()->GetProperty(lookupTableProp, "LookupTable", renderer);
266  if (lookupTableProp.IsNotNull())
267  {
268  ls->m_VtkPolyDataMapper->SetLookupTable(lookupTableProp->GetLookupTable()->GetVtkLookupTable());
269  }
270 
271  bool scalarVisibility = false;
272  this->GetDataNode()->GetBoolProperty("scalar visibility", scalarVisibility);
273  ls->m_VtkPolyDataMapper->SetScalarVisibility((scalarVisibility ? 1 : 0));
274 
275  if (scalarVisibility)
276  {
277  mitk::VtkScalarModeProperty *scalarMode;
278  if (this->GetDataNode()->GetProperty(scalarMode, "scalar mode", renderer))
279  ls->m_VtkPolyDataMapper->SetScalarMode(scalarMode->GetVtkScalarMode());
280  else
281  ls->m_VtkPolyDataMapper->SetScalarModeToDefault();
282 
283  bool colorMode = false;
284  this->GetDataNode()->GetBoolProperty("color mode", colorMode);
285  ls->m_VtkPolyDataMapper->SetColorMode((colorMode ? 1 : 0));
286 
287  double scalarsMin = 0;
288  this->GetDataNode()->GetDoubleProperty("ScalarsRangeMinimum", scalarsMin, renderer);
289 
290  double scalarsMax = 1.0;
291  this->GetDataNode()->GetDoubleProperty("ScalarsRangeMaximum", scalarsMax, renderer);
292 
293  ls->m_VtkPolyDataMapper->SetScalarRange(scalarsMin, scalarsMax);
294  }
295 }
296 
298  mitk::BaseRenderer *renderer /*= nullptr*/,
299  bool /*= false*/)
300 {
301  node->SetProperty("color", ColorProperty::New(0.3, 0.3, 0.3)); // a little lighter than the
302  // "plane widgets" of
303  // QmitkStdMultiWidget
304  node->SetProperty("scalar visibility", BoolProperty::New(true), renderer);
305  node->SetProperty("ScalarsRangeMinimum", DoubleProperty::New(0), renderer);
306  node->SetProperty("ScalarsRangeMaximum", DoubleProperty::New((int)Gizmo::NoHandle), renderer);
307 
308  double colorMoveFreely[] = {1, 0, 0, 1}; // RGBA
309  double colorAxisX[] = {0.753, 0, 0, 1}; // colors copied from QmitkStdMultiWidget to
310  double colorAxisY[] = {0, 0.69, 0, 1}; // look alike
311  double colorAxisZ[] = {0, 0.502, 1, 1};
312  double colorInactive[] = {0.7, 0.7, 0.7, 1};
313 
314  // build a nice color table
315  vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
316  lut->SetNumberOfTableValues((int)Gizmo::NoHandle + 1);
317  lut->SetTableRange(0, (int)Gizmo::NoHandle);
318  lut->SetTableValue(Gizmo::MoveFreely, colorMoveFreely);
319  lut->SetTableValue(Gizmo::MoveAlongAxisX, colorAxisX);
320  lut->SetTableValue(Gizmo::MoveAlongAxisY, colorAxisY);
321  lut->SetTableValue(Gizmo::MoveAlongAxisZ, colorAxisZ);
322  lut->SetTableValue(Gizmo::RotateAroundAxisX, colorAxisX);
323  lut->SetTableValue(Gizmo::RotateAroundAxisY, colorAxisY);
324  lut->SetTableValue(Gizmo::RotateAroundAxisZ, colorAxisZ);
325  lut->SetTableValue(Gizmo::ScaleX, colorAxisX);
326  lut->SetTableValue(Gizmo::ScaleY, colorAxisY);
327  lut->SetTableValue(Gizmo::ScaleZ, colorAxisZ);
328  lut->SetTableValue(Gizmo::NoHandle, colorInactive);
329 
331  mlut->SetVtkLookupTable(lut);
332 
334  lutProp->SetLookupTable(mlut);
335  node->SetProperty("LookupTable", lutProp, renderer);
336 
337  node->SetProperty("helper object", BoolProperty::New(true), renderer);
338  node->SetProperty("visible", BoolProperty::New(true), renderer);
339  node->SetProperty("show in 2D", BoolProperty::New(true), renderer);
340  // no "show in 3D" because this would require a specialized mapper for gizmos in 3D
341 }
int GetSizeX() const
get the x_size of the RendererWindow
static Pointer New()
static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer=nullptr, bool overwrite=false)
static Pointer New()
Organizes the rendering process.
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
static Pointer New()
Vector< ScalarType, 3 > Vector3D
Definition: mitkVector.h:134
static Pointer New()
int GetSizeY() const
get the y_size of the RendererWindow
virtual MapperSlotId GetMapperID()
Get the MapperSlotId to use.
Point< ScalarType, 3 > Point3D
Definition: mitkPoint.h:99
void ResetMapper(mitk::BaseRenderer *renderer) override
"Resets" the mapper, setting its result to invisible.
static T min(T x, T y)
Definition: svm.cpp:67
vtkPolyData * GetVtkPolyData(mitk::BaseRenderer *renderer)
unsigned long GetCurrentWorldPlaneGeometryUpdateTime()
Get timestamp of last call of SetCurrentWorldPlaneGeometry.
void SetProperty(const char *propertyKey, BaseProperty *property, const mitk::BaseRenderer *renderer=nullptr)
Set the property (instance of BaseProperty) with key propertyKey in the PropertyList of the renderer ...
virtual DataNode * GetDataNode() const
Get the DataNode containing the data to map. Method only returns valid DataNode Pointer if the mapper...
Definition: mitkMapper.cpp:36
static Pointer New()
vtkRenderer * GetVtkRenderer() const
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.