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