1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSphereHandleRepresentation.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkSphereHandleRepresentation.h"
16 #include "vtkActor.h"
17 #include "vtkAssemblyPath.h"
18 #include "vtkCellPicker.h"
19 #include "vtkCoordinate.h"
20 #include "vtkInteractorObserver.h"
21 #include "vtkLine.h"
22 #include "vtkMath.h"
23 #include "vtkObjectFactory.h"
24 #include "vtkPickingManager.h"
25 #include "vtkPolyDataMapper.h"
26 #include "vtkProperty.h"
27 #include "vtkRenderWindow.h"
28 #include "vtkRenderWindowInteractor.h"
29 #include "vtkRenderer.h"
30 #include "vtkSphereSource.h"
31 
32 vtkStandardNewMacro(vtkSphereHandleRepresentation);
33 vtkCxxSetObjectMacro(vtkSphereHandleRepresentation, SelectedProperty, vtkProperty);
34 
35 //------------------------------------------------------------------------------
vtkSphereHandleRepresentation()36 vtkSphereHandleRepresentation::vtkSphereHandleRepresentation()
37 {
38   // Initialize state
39   this->InteractionState = vtkHandleRepresentation::Outside;
40 
41   // Represent the line
42   this->Sphere = vtkSphereSource::New();
43   this->Sphere->SetThetaResolution(16);
44   this->Sphere->SetPhiResolution(8);
45 
46   this->Mapper = vtkPolyDataMapper::New();
47   this->Mapper->SetInputConnection(this->Sphere->GetOutputPort());
48 
49   // Set up the initial properties
50   this->CreateDefaultProperties();
51 
52   this->Actor = vtkActor::New();
53   this->Actor->SetMapper(this->Mapper);
54   this->Actor->SetProperty(this->Property);
55 
56   // Manage the picking stuff
57   this->CursorPicker = vtkCellPicker::New();
58   this->CursorPicker->PickFromListOn();
59   this->CursorPicker->AddPickList(this->Actor);
60   this->CursorPicker->SetTolerance(0.01); // need some fluff
61 
62   // Override superclass'
63   this->PlaceFactor = 1.0;
64 
65   // The size of the hot spot
66   this->HotSpotSize = 0.05;
67   this->WaitingForMotion = 0;
68 
69   // Current handle size
70   this->HandleSize = 15.0; // in pixels
71   this->CurrentHandleSize = this->HandleSize;
72 
73   // Translation control
74   this->TranslationMode = 1;
75 }
76 
77 //------------------------------------------------------------------------------
~vtkSphereHandleRepresentation()78 vtkSphereHandleRepresentation::~vtkSphereHandleRepresentation()
79 {
80   this->Sphere->Delete();
81   this->CursorPicker->Delete();
82   this->Mapper->Delete();
83   this->Actor->Delete();
84   this->Property->Delete();
85   this->SelectedProperty->Delete();
86 }
87 
88 //------------------------------------------------------------------------------
RegisterPickers()89 void vtkSphereHandleRepresentation::RegisterPickers()
90 {
91   vtkPickingManager* pm = this->GetPickingManager();
92   if (!pm)
93   {
94     return;
95   }
96   pm->AddPicker(this->CursorPicker, this);
97 }
98 
99 //------------------------------------------------------------------------------
PlaceWidget(double bds[6])100 void vtkSphereHandleRepresentation::PlaceWidget(double bds[6])
101 {
102   int i;
103   double bounds[6], center[3];
104 
105   this->AdjustBounds(bds, bounds, center);
106 
107   //  this->Sphere->SetModelBounds(bounds);
108   this->SetWorldPosition(center);
109 
110   for (i = 0; i < 6; i++)
111   {
112     this->InitialBounds[i] = bounds[i];
113   }
114   this->InitialLength = sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
115     (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
116     (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
117 }
118 
119 //------------------------------------------------------------------------------
SetSphereRadius(double radius)120 void vtkSphereHandleRepresentation::SetSphereRadius(double radius)
121 {
122   if (radius == this->Sphere->GetRadius())
123   {
124     return;
125   }
126 
127   this->Sphere->SetRadius(radius);
128   this->Modified();
129 }
130 
131 //------------------------------------------------------------------------------
GetSphereRadius()132 double vtkSphereHandleRepresentation::GetSphereRadius()
133 {
134   return this->Sphere->GetRadius();
135 }
136 
137 //------------------------------------------------------------------------------
GetBounds()138 double* vtkSphereHandleRepresentation::GetBounds()
139 {
140   static double bounds[6];
141   double center[3];
142   double radius = this->Sphere->GetRadius();
143   this->Sphere->GetCenter(center);
144 
145   bounds[0] = this->PlaceFactor * (center[0] - radius);
146   bounds[1] = this->PlaceFactor * (center[0] + radius);
147   bounds[2] = this->PlaceFactor * (center[1] - radius);
148   bounds[3] = this->PlaceFactor * (center[1] + radius);
149   bounds[4] = this->PlaceFactor * (center[2] - radius);
150   bounds[5] = this->PlaceFactor * (center[2] + radius);
151 
152   return bounds;
153 }
154 
155 //------------------------------------------------------------------------------
SetWorldPosition(double p[3])156 void vtkSphereHandleRepresentation::SetWorldPosition(double p[3])
157 {
158   this->Sphere->SetCenter(p); // this may clamp the point
159   this->Superclass::SetWorldPosition(this->Sphere->GetCenter());
160 }
161 
162 //------------------------------------------------------------------------------
SetDisplayPosition(double p[3])163 void vtkSphereHandleRepresentation::SetDisplayPosition(double p[3])
164 {
165   this->Superclass::SetDisplayPosition(p);
166   this->SetWorldPosition(this->WorldPosition->GetValue());
167 }
168 
169 //------------------------------------------------------------------------------
SetHandleSize(double size)170 void vtkSphereHandleRepresentation::SetHandleSize(double size)
171 {
172   this->Superclass::SetHandleSize(size);
173   this->CurrentHandleSize = this->HandleSize;
174 }
175 
176 //------------------------------------------------------------------------------
ComputeInteractionState(int X,int Y,int vtkNotUsed (modify))177 int vtkSphereHandleRepresentation::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify))
178 {
179   this->VisibilityOn(); // actor must be on to be picked
180 
181   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->CursorPicker);
182 
183   if (path != nullptr)
184   {
185     //    this->InteractionState = vtkHandleRepresentation::Nearby;
186     this->InteractionState = vtkHandleRepresentation::Selecting;
187   }
188   else
189   {
190     this->InteractionState = vtkHandleRepresentation::Outside;
191     if (this->ActiveRepresentation)
192     {
193       this->VisibilityOff();
194     }
195   }
196 
197   return this->InteractionState;
198 }
199 
200 //------------------------------------------------------------------------------
201 // Record the current event position, and the rectilinear wipe position.
StartWidgetInteraction(double startEventPos[2])202 void vtkSphereHandleRepresentation::StartWidgetInteraction(double startEventPos[2])
203 {
204   this->StartEventPosition[0] = startEventPos[0];
205   this->StartEventPosition[1] = startEventPos[1];
206   this->StartEventPosition[2] = 0.0;
207 
208   this->LastEventPosition[0] = startEventPos[0];
209   this->LastEventPosition[1] = startEventPos[1];
210 
211   vtkAssemblyPath* path =
212     this->GetAssemblyPath(startEventPos[0], startEventPos[1], 0., this->CursorPicker);
213 
214   if (path != nullptr)
215   {
216     //    this->InteractionState = vtkHandleRepresentation::Nearby;
217     this->InteractionState = vtkHandleRepresentation::Selecting;
218     this->CursorPicker->GetPickPosition(this->LastPickPosition);
219   }
220   else
221   {
222     this->InteractionState = vtkHandleRepresentation::Outside;
223     this->ConstraintAxis = -1;
224   }
225 }
226 
227 //------------------------------------------------------------------------------
228 // Based on the displacement vector (computed in display coordinates) and
229 // the cursor state (which corresponds to which part of the widget has been
230 // selected), the widget points are modified.
231 // First construct a local coordinate system based on the display coordinates
232 // of the widget.
WidgetInteraction(double eventPos[2])233 void vtkSphereHandleRepresentation::WidgetInteraction(double eventPos[2])
234 {
235   // Do different things depending on state
236   // Calculations everybody does
237   double focalPoint[4], pickPoint[4], prevPickPoint[4];
238   double z;
239 
240   // Compute the two points defining the motion vector
241   vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, this->LastPickPosition[0],
242     this->LastPickPosition[1], this->LastPickPosition[2], focalPoint);
243   z = focalPoint[2];
244   vtkInteractorObserver::ComputeDisplayToWorld(
245     this->Renderer, this->LastEventPosition[0], this->LastEventPosition[1], z, prevPickPoint);
246   vtkInteractorObserver::ComputeDisplayToWorld(
247     this->Renderer, eventPos[0], eventPos[1], z, pickPoint);
248 
249   // Process the motion
250   if (this->InteractionState == vtkHandleRepresentation::Selecting ||
251     this->InteractionState == vtkHandleRepresentation::Translating)
252   {
253     if (!this->WaitingForMotion || this->WaitCount++ > 3)
254     {
255       if (this->InteractionState == vtkHandleRepresentation::Selecting && !this->TranslationMode)
256       {
257         this->MoveFocus(prevPickPoint, pickPoint);
258       }
259       else
260       {
261         this->Translate(prevPickPoint, pickPoint);
262       }
263     }
264   }
265 
266   else if (this->InteractionState == vtkHandleRepresentation::Scaling)
267   {
268     this->Scale(prevPickPoint, pickPoint, eventPos);
269   }
270 
271   // Book keeping
272   this->LastEventPosition[0] = eventPos[0];
273   this->LastEventPosition[1] = eventPos[1];
274 
275   this->Modified();
276 }
277 /*
278 //------------------------------------------------------------------------------
279 void vtkSphereHandleRepresentation::MoveFocus(const double *p1, const double *p2)
280 {
281   //Get the motion vector
282   double v[3];
283   v[0] = p2[0] - p1[0];
284   v[1] = p2[1] - p1[1];
285   v[2] = p2[2] - p1[2];
286 
287   double focus[3];
288   this->Sphere->GetCenter(focus);
289   if ( this->ConstraintAxis >= 0 )
290   {
291     focus[this->ConstraintAxis] += v[this->ConstraintAxis];
292   }
293   else
294   {
295     focus[0] += v[0];
296     focus[1] += v[1];
297     focus[2] += v[2];
298   }
299 
300   this->SetWorldPosition(focus);
301 }
302 
303 //------------------------------------------------------------------------------
304 // Translate everything
305 void vtkSphereHandleRepresentation::Translate(const double *p1, const double *p2)
306 {
307   //Get the motion vector
308   double v[3];
309   v[0] = p2[0] - p1[0];
310   v[1] = p2[1] - p1[1];
311   v[2] = p2[2] - p1[2];
312 
313   double *pos = this->Sphere->GetCenter();
314   double newFocus[3];
315 
316   if ( this->ConstraintAxis >= 0 )
317   {//move along axis
318     for (int i=0; i<3; i++)
319     {
320       if ( i != this->ConstraintAxis )
321       {
322         v[i] = 0.0;
323       }
324     }
325   }
326 
327   for (int i=0; i<3; i++)
328   {
329     newFocus[i] = pos[i] + v[i];
330   }
331   this->SetWorldPosition(newFocus);
332 
333   double radius = this->SizeHandlesInPixels(1.0,newFocus);
334   radius *= this->CurrentHandleSize / this->HandleSize;
335 
336   this->Sphere->SetRadius(radius);
337 }*/
338 
339 //------------------------------------------------------------------------------
MoveFocus(const double * p1,const double * p2)340 void vtkSphereHandleRepresentation::MoveFocus(const double* p1, const double* p2)
341 {
342   Superclass::Translate(p1, p2);
343 }
344 
345 //------------------------------------------------------------------------------
346 // Translate everything
Translate(const double * p1,const double * p2)347 void vtkSphereHandleRepresentation::Translate(const double* p1, const double* p2)
348 {
349   double v[3];
350   this->GetTranslationVector(p1, p2, v);
351   double* pos = this->Sphere->GetCenter();
352   double focus[3];
353   for (int i = 0; i < 3; i++)
354   {
355     focus[i] = pos[i] + v[i];
356   }
357   this->SetWorldPosition(focus);
358 
359   double radius = this->SizeHandlesInPixels(1.0, focus);
360   radius *= this->CurrentHandleSize / this->HandleSize;
361 
362   this->Sphere->SetRadius(radius);
363 }
364 
365 //------------------------------------------------------------------------------
SizeBounds()366 void vtkSphereHandleRepresentation::SizeBounds()
367 {
368   double center[3];
369   this->Sphere->GetCenter(center);
370   double radius = this->SizeHandlesInPixels(1.0, center);
371   radius *= this->CurrentHandleSize / this->HandleSize;
372 
373   this->Sphere->SetRadius(radius);
374 }
375 
376 //------------------------------------------------------------------------------
Scale(const double * p1,const double * p2,const double eventPos[2])377 void vtkSphereHandleRepresentation::Scale(
378   const double* p1, const double* p2, const double eventPos[2])
379 {
380   // Get the motion vector
381   double v[3];
382   v[0] = p2[0] - p1[0];
383   v[1] = p2[1] - p1[1];
384   v[2] = p2[2] - p1[2];
385 
386   const double* bounds = this->GetBounds();
387 
388   // Compute the scale factor
389   double sf = vtkMath::Norm(v) /
390     sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
391       (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
392       (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
393 
394   if (eventPos[1] > this->LastEventPosition[1])
395   {
396     sf = 1.0 + sf;
397   }
398   else
399   {
400     sf = 1.0 - sf;
401   }
402 
403   this->CurrentHandleSize *= sf;
404   this->CurrentHandleSize = (this->CurrentHandleSize < 0.001 ? 0.001 : this->CurrentHandleSize);
405 
406   this->SizeBounds();
407 }
408 
409 //------------------------------------------------------------------------------
Highlight(int highlight)410 void vtkSphereHandleRepresentation::Highlight(int highlight)
411 {
412   if (highlight)
413   {
414     this->Actor->SetProperty(this->SelectedProperty);
415   }
416   else
417   {
418     this->Actor->SetProperty(this->Property);
419   }
420 }
421 
422 //------------------------------------------------------------------------------
CreateDefaultProperties()423 void vtkSphereHandleRepresentation::CreateDefaultProperties()
424 {
425   this->Property = vtkProperty::New();
426   this->Property->SetColor(1, 1, 1);
427 
428   this->SelectedProperty = vtkProperty::New();
429   this->SelectedProperty->SetColor(0, 1, 0);
430 }
431 
432 //------------------------------------------------------------------------------
BuildRepresentation()433 void vtkSphereHandleRepresentation::BuildRepresentation()
434 {
435   // The net effect is to resize the handle
436   if (this->GetMTime() > this->BuildTime ||
437     (this->Renderer && this->Renderer->GetVTKWindow() &&
438       this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime))
439   {
440     if (!this->Placed)
441     {
442       this->ValidPick = 1;
443       this->Placed = 1;
444     }
445 
446     this->SizeBounds();
447     this->Sphere->Update();
448     this->BuildTime.Modified();
449   }
450 }
451 
452 //------------------------------------------------------------------------------
ShallowCopy(vtkProp * prop)453 void vtkSphereHandleRepresentation::ShallowCopy(vtkProp* prop)
454 {
455   vtkSphereHandleRepresentation* rep = vtkSphereHandleRepresentation::SafeDownCast(prop);
456   if (rep)
457   {
458     this->SetTranslationMode(rep->GetTranslationMode());
459     this->SetProperty(rep->GetProperty());
460     this->SetSelectedProperty(rep->GetSelectedProperty());
461     this->SetHotSpotSize(rep->GetHotSpotSize());
462   }
463   this->Superclass::ShallowCopy(prop);
464 }
465 
466 //------------------------------------------------------------------------------
DeepCopy(vtkProp * prop)467 void vtkSphereHandleRepresentation::DeepCopy(vtkProp* prop)
468 {
469   vtkSphereHandleRepresentation* rep = vtkSphereHandleRepresentation::SafeDownCast(prop);
470   if (rep)
471   {
472     this->SetTranslationMode(rep->GetTranslationMode());
473     this->Property->DeepCopy(rep->GetProperty());
474     this->SelectedProperty->DeepCopy(rep->GetSelectedProperty());
475     this->SetHotSpotSize(rep->GetHotSpotSize());
476   }
477   this->Superclass::DeepCopy(prop);
478 }
479 
480 //------------------------------------------------------------------------------
GetActors(vtkPropCollection * pc)481 void vtkSphereHandleRepresentation::GetActors(vtkPropCollection* pc)
482 {
483   this->Actor->GetActors(pc);
484 }
485 
486 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * win)487 void vtkSphereHandleRepresentation::ReleaseGraphicsResources(vtkWindow* win)
488 {
489   this->Actor->ReleaseGraphicsResources(win);
490 }
491 
492 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * viewport)493 int vtkSphereHandleRepresentation::RenderOpaqueGeometry(vtkViewport* viewport)
494 {
495   this->BuildRepresentation();
496   return this->Actor->RenderOpaqueGeometry(viewport);
497 }
498 
499 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * viewport)500 int vtkSphereHandleRepresentation ::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
501 {
502   this->BuildRepresentation();
503   return this->Actor->RenderTranslucentPolygonalGeometry(viewport);
504 }
505 
506 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()507 vtkTypeBool vtkSphereHandleRepresentation::HasTranslucentPolygonalGeometry()
508 {
509   return 0; // this->Actor->HasTranslucentPolygonalGeometry();
510 }
511 
512 //------------------------------------------------------------------------------
SetProperty(vtkProperty * p)513 void vtkSphereHandleRepresentation::SetProperty(vtkProperty* p)
514 {
515   vtkSetObjectBodyMacro(Property, vtkProperty, p);
516   if (p)
517   {
518     this->Actor->SetProperty(p);
519   }
520 }
521 
522 //------------------------------------------------------------------------------
SetVisibility(vtkTypeBool visible)523 void vtkSphereHandleRepresentation::SetVisibility(vtkTypeBool visible)
524 {
525   this->Actor->SetVisibility(visible);
526   // Forward to superclass
527   this->Superclass::SetVisibility(visible);
528 }
529 
530 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)531 void vtkSphereHandleRepresentation::PrintSelf(ostream& os, vtkIndent indent)
532 {
533   // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
534   this->Superclass::PrintSelf(os, indent);
535 
536   os << indent << "Hot Spot Size: " << this->HotSpotSize << "\n";
537   if (this->Property)
538   {
539     os << indent << "Property: " << this->Property << "\n";
540   }
541   else
542   {
543     os << indent << "Property: (none)\n";
544   }
545   if (this->SelectedProperty)
546   {
547     os << indent << "Selected Property: " << this->SelectedProperty << "\n";
548   }
549   else
550   {
551     os << indent << "Selected Property: (none)\n";
552   }
553 
554   os << indent << "Translation Mode: " << (this->TranslationMode ? "On\n" : "Off\n");
555   os << indent << "Sphere: " << this->Sphere << "\n";
556 
557   this->Sphere->PrintSelf(os, indent.GetNextIndent());
558 }
559