fw4spl
fwVtkWheelRepresentation.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2017-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwRenderVTK/vtk/fwVtkWheelRepresentation.hpp"
8 
9 #include <fwServices/macros.hpp>
10 
11 #include <glm/common.hpp>
12 #include <glm/gtc/constants.hpp>
13 #include <glm/gtc/vec1.hpp>
14 
15 #include <vtkCellArray.h>
16 #include <vtkCellData.h>
17 #include <vtkDoubleArray.h>
18 #include <vtkPolyData.h>
19 #include <vtkPolyDataMapper2D.h>
20 #include <vtkQuad.h>
21 #include <vtkRenderer.h>
22 #include <vtkRenderWindow.h>
23 
24 #include <cmath>
25 
26 vtkStandardNewMacro(fwVtkWheelRepresentation);
27 
28 //------------------------------------------------------------------------------
29 
30 fwVtkWheelRepresentation::fwVtkWheelRepresentation() :
31  m_wheelPoints(vtkPoints::New()),
32  m_wheelActor(vtkActor2D::New()),
33  m_colors(vtkUnsignedCharArray::New()),
34  m_orientation(0.),
35  m_nSectors(288),
36  m_nMarkedSectors(8),
37  m_hover(false)
38 {
39  this->m_center.x = -std::numeric_limits<double>::infinity();
40  this->m_center.y = -std::numeric_limits<double>::infinity();
41 
42  this->BuildRepresentation();
43 }
44 
45 //------------------------------------------------------------------------------
46 
47 fwVtkWheelRepresentation::~fwVtkWheelRepresentation()
48 {
49  m_wheelPoints->Delete();
50  m_wheelActor->Delete();
51  m_colors->Delete();
52 }
53 
54 //------------------------------------------------------------------------------
55 
57 {
58  // Setup points
59 
60  // Define some colors
61  const double color[4] = {0., 0., 0., 0.};
62 
63  // Setup the colors array
64  this->m_colors->SetNumberOfComponents(4);
65  this->m_colors->SetName("Colors");
66 
67  // Create a triangle
68  vtkSmartPointer<vtkCellArray> quads = vtkSmartPointer<vtkCellArray>::New();
69 
70  // Add the points to a vtkPoints object
71  this->m_wheelPoints = vtkPoints::New();
72 
73  // Add quads and corresponding colors
74  for(unsigned int i = 0; i < this->m_nSectors * 2; i++)
75  {
76  vtkSmartPointer<vtkQuad> quad = vtkSmartPointer<vtkQuad>::New();
77 
78  quad->GetPointIds()->SetId(0, (i * 2) + 0);
79  quad->GetPointIds()->SetId(1, (i * 2) + 1);
80  quad->GetPointIds()->SetId(2, (i * 2) + 3);
81  quad->GetPointIds()->SetId(3, (i * 2) + 2);
82 
83  quads->InsertNextCell(quad);
84 
85  this->m_colors->InsertNextTuple(color);
86  }
87 
88  // Add points corresponding to the previous quads (4 points per quad)
89  for(unsigned int i = 0; i < (this->m_nSectors + 1) * 4; i++)
90  {
91  this->m_wheelPoints->InsertNextPoint(0, 0, 0.0);
92  }
93 
94  // Create a polydata object and add everything to it.
95  vtkSmartPointer<vtkPolyData> wheelPolyData = vtkSmartPointer<vtkPolyData>::New();
96  wheelPolyData->SetPoints(this->m_wheelPoints);
97  wheelPolyData->SetPolys(quads);
98  wheelPolyData->GetCellData()->SetScalars(this->m_colors);
99 
100  // Visualize
101  vtkSmartPointer<vtkPolyDataMapper2D> wheelMapper = vtkSmartPointer<vtkPolyDataMapper2D>::New();
102  wheelMapper->SetInputData(wheelPolyData);
103  this->m_wheelActor->SetMapper(wheelMapper);
104  this->m_wheelActor->PickableOn();
105 
106  const ::glm::dvec2 actorPos(this->m_wheelActor->GetPosition()[0], this->m_wheelActor->GetPosition()[1]);
107 }
108 
109 //------------------------------------------------------------------------------
110 
112 {
113  if ( this->GetMTime() > this->BuildTime ||
114  (this->Renderer && this->Renderer->GetVTKWindow() &&
115  this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime) )
116  {
117  const auto viewportSize = this->GetRenderer()->GetRenderWindow()->GetSize();
118  const int viewportWidth = viewportSize[0];
119  const int viewportHeight = viewportSize[1];
120 
121  // Define usefull colors
122  const double defaultColor[4] = {70., 100., 140., 192.};
123  const double hoverColor[4] = {255., 255., 255., 255.};
124 
125  // Clamp actor position to ensure that the widget center stays inside the viewport.
126  ::glm::dvec2 actorPos(this->m_wheelActor->GetPosition()[0], this->m_wheelActor->GetPosition()[1]);
127 
128  if(this->m_center.x == -std::numeric_limits<double>::infinity() &&
129  this->m_center.y == -std::numeric_limits<double>::infinity() )
130  {
131  this->m_center.x = static_cast<double>(viewportWidth) / 2.0;
132  this->m_center.y = static_cast<double>(viewportHeight) / 2.0;
133  this->m_widgetToCenterTranslation = this->m_center - actorPos;
134  }
135 
136  actorPos.x = ::glm::clamp(actorPos.x, -this->m_widgetToCenterTranslation.x,
137  static_cast<double>(viewportWidth) - this->m_widgetToCenterTranslation.x);
138  actorPos.y = ::glm::clamp(actorPos.y, -this->m_widgetToCenterTranslation.y,
139  static_cast<double>(viewportHeight) - this->m_widgetToCenterTranslation.y);
140 
141  this->m_wheelActor->SetPosition(actorPos.x, actorPos.y);
142 
143  // Update the outer wheel by modifying all its points.
144  const double deltaAngle = 2.0 * ::glm::pi<double>() / static_cast<double>(this->m_nSectors);
145  double initAngle = -deltaAngle / 2.0 + m_orientation;
146 
147  const double minViewportComp = std::min(viewportWidth, viewportHeight);
148  this->m_wheelInnerRadius = 2.0 / 3.0 * minViewportComp / 2.0;
149  this->m_wheelOuterRadius = this->m_wheelInnerRadius + 0.02 * minViewportComp;
150  const double outerMarkedRadius = this->m_wheelOuterRadius + 0.01 * minViewportComp;
151 
152  double c, s;
153  c = std::cos(initAngle + 0.0);
154  s = std::sin(initAngle + 0.0);
155 
156  // Set position to the two first points ...
157  this->m_wheelPoints->SetPoint(0, this->m_center.x + this->m_wheelInnerRadius * c,
158  this->m_center.y + this->m_wheelInnerRadius * s, 0.0);
159  this->m_wheelPoints->SetPoint(1, this->m_center.x + this->m_wheelOuterRadius * c,
160  this->m_center.y + this->m_wheelOuterRadius * s, 0.0);
161 
162  // ... then, define two second points and corresponding colors of the previously created quad
163  for(unsigned int i = 0; i < this->m_nSectors; i++)
164  {
165  c = std::cos(initAngle + static_cast<double>(i + 1) * deltaAngle);
166  s = std::sin(initAngle + static_cast<double>(i + 1) * deltaAngle);
167 
168  const unsigned int j = i + 1;
169  this->m_wheelPoints->SetPoint(j*2, this->m_center.x + this->m_wheelInnerRadius * c,
170  this->m_center.y + this->m_wheelInnerRadius * s, 0.0);
171 
172  // Difference between small and big tick of the wheel
173  if(i % this->m_nMarkedSectors == 6 || i % this->m_nMarkedSectors == 7)
174  {
175  this->m_wheelPoints->SetPoint(j*2 + 1, this->m_center.x + outerMarkedRadius * c,
176  this->m_center.y + outerMarkedRadius * s, 0.0);
177  }
178  else
179  {
180  this->m_wheelPoints->SetPoint(j*2 + 1, this->m_center.x + this->m_wheelOuterRadius * c,
181  this->m_center.y + this->m_wheelOuterRadius * s, 0.0);
182  }
183 
184  // Display one out of two quads
185  if(i % 2 == 1)
186  {
187  if(m_hover)
188  {
189 
190  this->m_colors->SetTuple(i, hoverColor);
191  }
192  else
193  {
194  this->m_colors->SetTuple(i, defaultColor);
195  }
196  }
197  }
198 
199  // Update the center.
200  this->m_centerOuterRadius = 0.05 * this->m_wheelOuterRadius;
201  this->m_centerInnerRadius = 0.2 * this->m_centerOuterRadius;
202 
203  initAngle = -deltaAngle / 2.0;
204  c = std::cos(initAngle + 0.0);
205  s = std::sin(initAngle + 0.0);
206 
207  // Same definition for the small inside wheel
208  this->m_wheelPoints->SetPoint((this->m_nSectors + 1) * 2, this->m_center.x + this->m_centerInnerRadius * c,
209  this->m_center.y + this->m_centerInnerRadius * s, 0.0);
210 
211  this->m_wheelPoints->SetPoint((this->m_nSectors + 1) * 2 + 1, this->m_center.x + this->m_centerOuterRadius * c,
212  this->m_center.y + this->m_centerOuterRadius * s, 0.0);
213 
214  const double holeThickness = 0.15;
215 
216  for(unsigned int i = this->m_nSectors + 1; i < this->m_nSectors * 2; i++)
217  {
218  c = std::cos(initAngle + static_cast<double>(i + 1) * deltaAngle);
219  s = std::sin(initAngle + static_cast<double>(i + 1) * deltaAngle);
220 
221  const unsigned int j = i + 1;
222 
223  this->m_wheelPoints->SetPoint(j * 2, this->m_center.x + this->m_centerInnerRadius * c,
224  this->m_center.y + this->m_centerInnerRadius * s, 0.0);
225 
226  this->m_wheelPoints->SetPoint(j * 2 + 1, this->m_center.x + this->m_centerOuterRadius * c,
227  this->m_center.y + this->m_centerOuterRadius * s, 0.0);
228 
229  if( !(c < holeThickness && c > -holeThickness) &&
230  !(s < holeThickness && s > -holeThickness) )
231  {
232  if(m_hover)
233  {
234  this->m_colors->SetTuple(i, hoverColor);
235  }
236  else
237  {
238  this->m_colors->SetTuple(i, defaultColor);
239  }
240  }
241  }
242 
243  this->m_wheelPoints->Modified();
244  this->BuildTime.Modified();
245  }
246 }
247 
248 //------------------------------------------------------------------------------
249 
250 void fwVtkWheelRepresentation::GetActors2D(vtkPropCollection* pc)
251 {
252  pc->AddItem(this->m_wheelActor);
253 }
254 
255 //------------------------------------------------------------------------------
256 
258 {
259  this->m_wheelActor->ReleaseGraphicsResources(w);
260  this->Superclass::ReleaseGraphicsResources(w);
261 }
262 
263 //------------------------------------------------------------------------------
264 
266 {
267  this->UpdateRepresentation();
268  if(!this->m_wheelActor->GetVisibility() )
269  {
270  return 0;
271  }
272  return this->m_wheelActor->RenderOverlay(v);
273 }
274 
275 //------------------------------------------------------------------------------
276 
277 int fwVtkWheelRepresentation::RenderOpaqueGeometry(vtkViewport* w)
278 {
279  this->UpdateRepresentation();
280  if ( !this->m_wheelActor->GetVisibility() )
281  {
282  return 0;
283  }
284  return this->m_wheelActor->RenderOpaqueGeometry(w);
285 }
286 
287 //------------------------------------------------------------------------------
288 
289 int fwVtkWheelRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* w)
290 {
291  this->UpdateRepresentation();
292  if ( !this->m_wheelActor->GetVisibility() )
293  {
294  return 0;
295  }
296  return this->m_wheelActor->RenderTranslucentPolygonalGeometry(w);
297 }
298 
299 //------------------------------------------------------------------------------
300 
302 {
303  this->UpdateRepresentation();
304  if ( !this->m_wheelActor->GetVisibility() )
305  {
306  return 0;
307  }
308  return this->m_wheelActor->HasTranslucentPolygonalGeometry();
309 }
310 
311 //------------------------------------------------------------------------------
312 
314 {
315  this->m_orientation = ::glm::mod(orientation, ::glm::two_pi<double>());
316  this->Modified();
317  this->UpdateRepresentation();
318 }
319 
320 //------------------------------------------------------------------------------
321 
323 {
324  this->m_hover = hover;
325  this->Modified();
326  this->UpdateRepresentation();
327 }
328 
329 //------------------------------------------------------------------------------
330 
332 {
333  const ::glm::dvec2 actorPos(this->m_wheelActor->GetPosition()[0], this->m_wheelActor->GetPosition()[1]);
334  return actorPos + this->m_widgetToCenterTranslation;
335 }
336 
337 //------------------------------------------------------------------------------
338 
339 bool fwVtkWheelRepresentation::isInCenter(int X, int Y) const
340 {
341  bool inCenter = false;
342 
343  if(this->Visibility != 0)
344  {
345  const ::glm::dvec2 actorPos(this->m_wheelActor->GetPosition()[0], this->m_wheelActor->GetPosition()[1]);
346 
347  const ::glm::dvec2 delta = ::glm::dvec2(X, Y) - (actorPos + this->m_widgetToCenterTranslation);
348 
349  const double squaredDistance = delta.x * delta.x + delta.y * delta.y;
350 
351  const double squaredRadius = this->m_centerOuterRadius * this->m_centerOuterRadius;
352 
353  inCenter = (squaredDistance < squaredRadius);
354  }
355 
356  return inCenter;
357 }
358 
359 //------------------------------------------------------------------------------
360 
361 bool fwVtkWheelRepresentation::isOnWheel(int X, int Y) const
362 {
363  bool pointOnWheel = false;
364 
365  if(this->Visibility != 0)
366  {
367  const ::glm::dvec2 actorPos(this->m_wheelActor->GetPosition()[0], this->m_wheelActor->GetPosition()[1]);
368 
369  const ::glm::dvec2 delta = ::glm::dvec2(X, Y) - (actorPos + this->m_widgetToCenterTranslation);
370 
371  const double squaredDistance = delta.x * delta.x + delta.y * delta.y;
372 
373  const double squaredOuterRadius = this->m_wheelOuterRadius * this->m_wheelOuterRadius;
374  const double squaredInnerRadius = this->m_wheelInnerRadius * this->m_wheelInnerRadius;
375 
376  pointOnWheel = (squaredDistance < squaredOuterRadius) && (squaredDistance > squaredInnerRadius);
377  }
378 
379  return pointOnWheel;
380 }
381 
382 //------------------------------------------------------------------------------
383 
384 void fwVtkWheelRepresentation::PrintSelf(ostream&, vtkIndent)
385 {
386  SLM_WARN("Method not implemented.");
387 }
388 
389 //------------------------------------------------------------------------------
FWRENDERVTK_API int HasTranslucentPolygonalGeometry() VTK_OVERRIDE
Check if this class holds any translucent geometry. (Not implemented)
FWRENDERVTK_API void UpdateRepresentation()
Updates wheel geometry using the center, radius and orientation.
FWRENDERVTK_API void GetActors2D(vtkPropCollection *pc) VTK_OVERRIDE
Adds the wheel actor to the prop collection.
FWRENDERVTK_API int RenderOverlay(vtkViewport *) VTK_OVERRIDE
Standard VTK render methods.
void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Prints class information. Not implemented.
#define SLM_WARN(message)
Definition: spyLog.hpp:261
FWRENDERVTK_API::glm::dvec2 GetCenterInScreenSpace() const
Returns the center in viewport coordinates.
FWRENDERVTK_API void BuildRepresentation() VTK_OVERRIDE
Generates the representation using the center, radius and orientation.
FWRENDERVTK_API void SetOrientation(double orientation)
Set the wheel orientation, expressed in radians.
FWRENDERVTK_API void SetHovering(bool hover)
Set the wheel hovering.
FWRENDERVTK_API void ReleaseGraphicsResources(vtkWindow *) VTK_OVERRIDE
Releases graphic resources used by this class&#39; actor.
FWRENDERVTK_API bool isOnWheel(int X, int Y) const
Check if the (X, Y) screen position is on the wheel.
FWRENDERVTK_API bool isInCenter(int X, int Y) const
Check if the (X, Y) screen position is inside the wheel center.
Representation of a wheel widget.