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