1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPointHandleRepresentation3D.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 "vtkPointHandleRepresentation3D.h"
16 #include "vtkActor.h"
17 #include "vtkAssemblyPath.h"
18 #include "vtkCamera.h"
19 #include "vtkCellPicker.h"
20 #include "vtkCoordinate.h"
21 #include "vtkCursor3D.h"
22 #include "vtkEventData.h"
23 #include "vtkFocalPlanePointPlacer.h"
24 #include "vtkInteractorObserver.h"
25 #include "vtkLine.h"
26 #include "vtkMath.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPickingManager.h"
29 #include "vtkPolyDataMapper.h"
30 #include "vtkProperty.h"
31 #include "vtkRenderWindow.h"
32 #include "vtkRenderWindowInteractor.h"
33 #include "vtkRenderer.h"
34 
35 #include <cassert>
36 
37 vtkStandardNewMacro(vtkPointHandleRepresentation3D);
38 
39 vtkCxxSetObjectMacro(vtkPointHandleRepresentation3D, Property, vtkProperty);
40 vtkCxxSetObjectMacro(vtkPointHandleRepresentation3D, SelectedProperty, vtkProperty);
41 
42 //------------------------------------------------------------------------------
vtkPointHandleRepresentation3D()43 vtkPointHandleRepresentation3D::vtkPointHandleRepresentation3D()
44 {
45   // Initialize state
46   this->InteractionState = vtkHandleRepresentation::Outside;
47 
48   // Represent the line
49   this->Cursor3D = vtkCursor3D::New();
50   this->Cursor3D->AllOff();
51   this->Cursor3D->AxesOn();
52   this->Cursor3D->TranslationModeOn();
53 
54   this->Mapper = vtkPolyDataMapper::New();
55   this->Mapper->SetInputConnection(this->Cursor3D->GetOutputPort());
56 
57   // Set up the initial properties
58   this->CreateDefaultProperties();
59 
60   this->Actor = vtkActor::New();
61   this->Actor->SetMapper(this->Mapper);
62   this->Actor->SetProperty(this->Property);
63 
64   // Manage the picking stuff
65   this->CursorPicker = vtkCellPicker::New();
66   this->CursorPicker->PickFromListOn();
67   this->CursorPicker->AddPickList(this->Actor);
68   this->CursorPicker->SetTolerance(0.01); // need some fluff
69 
70   // Override superclass'
71   this->PlaceFactor = 1.0;
72 
73   // The size of the hot spot
74   this->HotSpotSize = 0.05;
75   this->WaitingForMotion = 0;
76   this->ConstraintAxis = -1;
77 
78   // Current handle size
79   this->HandleSize = 15.0; // in pixels
80   this->CurrentHandleSize = this->HandleSize;
81 
82   // Translation control
83   this->TranslationMode = 1;
84 
85   vtkFocalPlanePointPlacer* pointPlacer = vtkFocalPlanePointPlacer::New();
86   this->SetPointPlacer(pointPlacer);
87   pointPlacer->Delete();
88 
89   // Continuous moves
90   this->SmoothMotion = 1;
91 }
92 
93 //------------------------------------------------------------------------------
~vtkPointHandleRepresentation3D()94 vtkPointHandleRepresentation3D::~vtkPointHandleRepresentation3D()
95 {
96   this->Cursor3D->Delete();
97   this->CursorPicker->Delete();
98   this->Mapper->Delete();
99   this->Actor->Delete();
100   this->Property->Delete();
101   this->SelectedProperty->Delete();
102 }
103 
104 //------------------------------------------------------------------------------
RegisterPickers()105 void vtkPointHandleRepresentation3D::RegisterPickers()
106 {
107   vtkPickingManager* pm = this->GetPickingManager();
108   if (!pm)
109   {
110     return;
111   }
112   pm->AddPicker(this->CursorPicker, this);
113 }
114 
115 //------------------------------------------------------------------------------
PlaceWidget(double bds[6])116 void vtkPointHandleRepresentation3D::PlaceWidget(double bds[6])
117 {
118   int i;
119   double bounds[6], center[3];
120 
121   this->AdjustBounds(bds, bounds, center);
122 
123   this->Cursor3D->SetModelBounds(bounds);
124   this->SetWorldPosition(center);
125 
126   for (i = 0; i < 6; i++)
127   {
128     this->InitialBounds[i] = bounds[i];
129   }
130   this->InitialLength = sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
131     (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
132     (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
133 }
134 
135 //------------------------------------------------------------------------------
GetBounds()136 double* vtkPointHandleRepresentation3D::GetBounds()
137 {
138   return this->Cursor3D->GetModelBounds();
139 }
140 
141 //------------------------------------------------------------------------------
SetWorldPosition(double p[3])142 void vtkPointHandleRepresentation3D::SetWorldPosition(double p[3])
143 {
144   if (this->Renderer && this->PointPlacer)
145   {
146     if (this->PointPlacer->ValidateWorldPosition(p))
147     {
148       this->Cursor3D->SetFocalPoint(p); // this may clamp the point
149       this->WorldPosition->SetValue(this->Cursor3D->GetFocalPoint());
150       this->WorldPositionTime.Modified();
151     }
152   }
153   else
154   {
155     this->Cursor3D->SetFocalPoint(p); // this may clamp the point
156     this->WorldPosition->SetValue(this->Cursor3D->GetFocalPoint());
157     this->WorldPositionTime.Modified();
158   }
159 }
160 
161 //------------------------------------------------------------------------------
SetDisplayPosition(double p[3])162 void vtkPointHandleRepresentation3D::SetDisplayPosition(double p[3])
163 {
164   if (this->Renderer && this->PointPlacer)
165   {
166     if (this->PointPlacer->ValidateDisplayPosition(this->Renderer, p))
167     {
168       double worldPos[3], worldOrient[9];
169       if (this->PointPlacer->ComputeWorldPosition(this->Renderer, p, worldPos, worldOrient))
170       {
171         this->DisplayPosition->SetValue(p);
172         this->WorldPosition->SetValue(worldPos);
173         this->DisplayPositionTime.Modified();
174         this->SetWorldPosition(this->WorldPosition->GetValue());
175       }
176     }
177   }
178   else
179   {
180     this->DisplayPosition->SetValue(p);
181     this->DisplayPositionTime.Modified();
182   }
183 }
184 
185 //------------------------------------------------------------------------------
SetHandleSize(double size)186 void vtkPointHandleRepresentation3D::SetHandleSize(double size)
187 {
188   this->Superclass::SetHandleSize(size);
189   this->CurrentHandleSize = this->HandleSize;
190 }
191 
192 //------------------------------------------------------------------------------
ComputeInteractionState(int X,int Y,int vtkNotUsed (modify))193 int vtkPointHandleRepresentation3D ::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify))
194 {
195   this->VisibilityOn(); // actor must be on to be picked
196 
197   // First make sure that the cursor is within the bounding sphere of the
198   // representation in display space.
199   double d[3], bounds[6];
200   this->Cursor3D->GetModelBounds(bounds);
201   this->GetDisplayPosition(d);
202 
203   if (!this->NearbyEvent(X, Y, bounds))
204   {
205     this->InteractionState = vtkHandleRepresentation::Outside;
206     return this->InteractionState;
207   }
208 
209   // Now see if anything is picked
210   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->CursorPicker);
211 
212   if (path != nullptr)
213   {
214     this->InteractionState = vtkHandleRepresentation::Nearby;
215   }
216   else
217   {
218     this->InteractionState = vtkHandleRepresentation::Outside;
219     if (this->ActiveRepresentation)
220     {
221       this->VisibilityOff();
222     }
223   }
224 
225   return this->InteractionState;
226 }
227 
228 //------------------------------------------------------------------------------
ComputeComplexInteractionState(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata,int)229 int vtkPointHandleRepresentation3D::ComputeComplexInteractionState(
230   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata, int)
231 {
232   this->VisibilityOn(); // actor must be on to be picked
233 
234   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
235   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
236   if (edd)
237   {
238     double pos[3];
239     edd->GetWorldPosition(pos);
240     vtkAssemblyPath* path = this->GetAssemblyPath3DPoint(pos, this->CursorPicker);
241     double focus[3];
242     this->Cursor3D->GetFocalPoint(focus);
243     double d[3];
244     this->GetDisplayPosition(d);
245 
246     if (path != nullptr)
247     {
248       this->InteractionState = vtkHandleRepresentation::Nearby;
249     }
250     else
251     {
252       this->InteractionState = vtkHandleRepresentation::Outside;
253       if (this->ActiveRepresentation)
254       {
255         this->VisibilityOff();
256       }
257     }
258   }
259 
260   return this->InteractionState;
261 }
262 
263 //------------------------------------------------------------------------------
DetermineConstraintAxis(int constraint,double * x,double * startPickPoint)264 int vtkPointHandleRepresentation3D::DetermineConstraintAxis(
265   int constraint, double* x, double* startPickPoint)
266 {
267   // Look for trivial cases
268   if (!this->Constrained)
269   {
270     return -1;
271   }
272   else if (constraint >= 0 && constraint < 3)
273   {
274     return constraint;
275   }
276 
277   // Okay, figure out constraint. First see if the choice is
278   // outside the hot spot
279   if (!x)
280   {
281     double p[3], d2, tol;
282     this->CursorPicker->GetPickPosition(p);
283     d2 = vtkMath::Distance2BetweenPoints(p, this->LastPickPosition);
284     tol = this->HotSpotSize * this->InitialLength;
285     if (d2 > (tol * tol))
286     {
287       this->WaitingForMotion = 0;
288       return this->CursorPicker->GetCellId();
289     }
290     else
291     {
292       this->WaitingForMotion = 1;
293       this->WaitCount = 0;
294       return -1;
295     }
296   }
297   else if (x)
298   {
299     this->WaitingForMotion = 0;
300     double v[3];
301     v[0] = fabs(x[0] - startPickPoint[0]);
302     v[1] = fabs(x[1] - startPickPoint[1]);
303     v[2] = fabs(x[2] - startPickPoint[2]);
304     return (v[0] > v[1] ? (v[0] > v[2] ? 0 : 2) : (v[1] > v[2] ? 1 : 2));
305   }
306   else
307   {
308     return -1;
309   }
310 }
311 
312 //------------------------------------------------------------------------------
313 // Record the current event position, and the translation state
StartWidgetInteraction(double startEventPos[2])314 void vtkPointHandleRepresentation3D::StartWidgetInteraction(double startEventPos[2])
315 {
316   this->StartEventPosition[0] = startEventPos[0];
317   this->StartEventPosition[1] = startEventPos[1];
318   this->StartEventPosition[2] = 0.0;
319 
320   this->LastEventPosition[0] = startEventPos[0];
321   this->LastEventPosition[1] = startEventPos[1];
322 
323   // Make sure events are close to widget and something is picked
324   double bounds[6];
325   this->Cursor3D->GetModelBounds(bounds);
326   bool nearby = this->NearbyEvent(startEventPos[0], startEventPos[1], bounds);
327   vtkAssemblyPath* path =
328     this->GetAssemblyPath(startEventPos[0], startEventPos[1], 0., this->CursorPicker);
329 
330   if (nearby && path != nullptr)
331   {
332     this->InteractionState = vtkHandleRepresentation::Nearby;
333     this->ConstraintAxis = -1;
334     this->CursorPicker->GetPickPosition(this->LastPickPosition);
335   }
336   else
337   {
338     this->InteractionState = vtkHandleRepresentation::Outside;
339     this->ConstraintAxis = -1;
340   }
341   this->Cursor3D->SetTranslationMode(this->TranslationMode);
342   this->WaitCount = 0;
343 }
344 
345 //------------------------------------------------------------------------------
StartComplexInteraction(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata)346 void vtkPointHandleRepresentation3D::StartComplexInteraction(
347   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata)
348 {
349   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
350   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
351   if (edd)
352   {
353     edd->GetWorldPosition(this->StartEventPosition);
354     this->LastEventPosition[0] = this->StartEventPosition[0];
355     this->LastEventPosition[1] = this->StartEventPosition[1];
356     this->LastEventPosition[2] = this->StartEventPosition[2];
357 
358     double bounds[6];
359     this->Cursor3D->GetModelBounds(bounds);
360     bool nearby =
361       this->NearbyEvent(this->StartEventPosition[0], this->StartEventPosition[1], bounds);
362     vtkAssemblyPath* path =
363       this->GetAssemblyPath3DPoint(this->StartEventPosition, this->CursorPicker);
364 
365     if (nearby && path != nullptr)
366     {
367       this->InteractionState = vtkHandleRepresentation::Nearby;
368       this->ConstraintAxis = -1;
369       this->CursorPicker->GetPickPosition(this->LastPickPosition);
370     }
371     else
372     {
373       this->InteractionState = vtkHandleRepresentation::Outside;
374       this->ConstraintAxis = -1;
375     }
376     this->Cursor3D->SetTranslationMode(this->TranslationMode);
377     this->WaitCount = 0;
378   }
379 }
380 
381 //------------------------------------------------------------------------------
382 // Based on the displacement vector (computed in display coordinates) and
383 // the cursor state (which corresponds to which part of the widget has been
384 // selected), the widget points are modified.
385 // First construct a local coordinate system based on the display coordinates
386 // of the widget.
WidgetInteraction(double eventPos[2])387 void vtkPointHandleRepresentation3D::WidgetInteraction(double eventPos[2])
388 {
389   // Do different things depending on state
390   // Calculations everybody does
391   double focalPoint[4], pickPoint[4], prevPickPoint[4], startPickPoint[4], z;
392 
393   // Compute the two points defining the motion vector
394   vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, this->LastPickPosition[0],
395     this->LastPickPosition[1], this->LastPickPosition[2], focalPoint);
396   z = focalPoint[2];
397   vtkInteractorObserver::ComputeDisplayToWorld(
398     this->Renderer, this->LastEventPosition[0], this->LastEventPosition[1], z, prevPickPoint);
399   vtkInteractorObserver::ComputeDisplayToWorld(
400     this->Renderer, eventPos[0], eventPos[1], z, pickPoint);
401 
402   // Process the motion
403   if (this->InteractionState == vtkHandleRepresentation::Selecting ||
404     this->InteractionState == vtkHandleRepresentation::Translating)
405   {
406     this->WaitCount++;
407 
408     if (this->WaitCount > 3 || !this->Constrained)
409     {
410       vtkInteractorObserver::ComputeDisplayToWorld(this->Renderer, this->StartEventPosition[0],
411         this->StartEventPosition[1], z, startPickPoint);
412 
413       this->ConstraintAxis =
414         this->DetermineConstraintAxis(this->ConstraintAxis, pickPoint, startPickPoint);
415 
416       if (this->InteractionState == vtkHandleRepresentation::Selecting && !this->TranslationMode)
417       {
418         vtkDebugMacro(<< "Processing widget interaction for Select mode");
419 
420         // If we are doing axis constrained motion, ignore the placer.
421         // Can't have both the placer and an axis constraint dictating
422         // handle placement.
423         if (this->ConstraintAxis >= 0 || this->Constrained || !this->PointPlacer)
424         {
425           this->MoveFocus(prevPickPoint, pickPoint);
426         }
427         else
428         {
429           double newCenterPointRequested[3]; // displayPosition
430           double newCenterPoint[3], worldOrient[9];
431 
432           // Make a request for the new position.
433           this->MoveFocusRequest(prevPickPoint, pickPoint, eventPos, newCenterPointRequested);
434 
435           vtkFocalPlanePointPlacer* fPlacer =
436             vtkFocalPlanePointPlacer::SafeDownCast(this->PointPlacer);
437           if (fPlacer)
438           {
439             // Offset the placer plane to one that passes through the current
440             // world position and is parallel to the focal plane. Offset =
441             // the distance currentWorldPos is from the focal plane
442             //
443             double currentWorldPos[3], projDir[3], fp[3];
444             this->GetWorldPosition(currentWorldPos);
445             this->Renderer->GetActiveCamera()->GetFocalPoint(fp);
446             double vec[3] = { currentWorldPos[0] - fp[0], currentWorldPos[1] - fp[1],
447               currentWorldPos[2] - fp[2] };
448             this->Renderer->GetActiveCamera()->GetDirectionOfProjection(projDir);
449             fPlacer->SetOffset(vtkMath::Dot(vec, projDir));
450           }
451 
452           vtkDebugMacro(<< "Request for computing world position at "
453                         << "display position of " << newCenterPointRequested[0] << ","
454                         << newCenterPointRequested[1]);
455 
456           // See what the placer says.
457           if (this->PointPlacer->ComputeWorldPosition(
458                 this->Renderer, newCenterPointRequested, newCenterPoint, worldOrient))
459           {
460             // Once the placer has validated us, update the handle position
461             this->SetWorldPosition(newCenterPoint);
462           }
463         }
464       }
465       else
466       {
467         vtkDebugMacro(<< "Processing widget interaction for translate");
468 
469         // If we are doing axis constrained motion, ignore the placer.
470         // Can't have both the placer and the axis constraint dictating
471         // handle placement.
472         if (this->ConstraintAxis >= 0 || this->Constrained || !this->PointPlacer)
473         {
474           this->Translate(prevPickPoint, pickPoint);
475         }
476         else
477         {
478           double newCenterPointRequested[3]; // displayPosition
479           double newCenterPoint[3], worldOrient[9];
480 
481           // Make a request for the new position.
482           this->MoveFocusRequest(prevPickPoint, pickPoint, eventPos, newCenterPointRequested);
483 
484           vtkFocalPlanePointPlacer* fPlacer =
485             vtkFocalPlanePointPlacer::SafeDownCast(this->PointPlacer);
486           if (fPlacer)
487           {
488             // Offset the placer plane to one that passes through the current
489             // world position and is parallel to the focal plane. Offset =
490             // the distance currentWorldPos is from the focal plane
491             //
492             double currentWorldPos[3], projDir[3], fp[3];
493             this->GetWorldPosition(currentWorldPos);
494             this->Renderer->GetActiveCamera()->GetFocalPoint(fp);
495             double vec[3] = { currentWorldPos[0] - fp[0], currentWorldPos[1] - fp[1],
496               currentWorldPos[2] - fp[2] };
497             this->Renderer->GetActiveCamera()->GetDirectionOfProjection(projDir);
498             fPlacer->SetOffset(vtkMath::Dot(vec, projDir));
499           }
500 
501           vtkDebugMacro(<< "Request for computing world position at "
502                         << "display position of " << newCenterPointRequested[0] << ","
503                         << newCenterPointRequested[1]);
504 
505           // See what the placer says.
506           if (this->PointPlacer->ComputeWorldPosition(
507                 this->Renderer, newCenterPointRequested, newCenterPoint, worldOrient))
508           {
509 
510             // Once the placer has validated us, update the handle
511             // position and its bounds.
512             double* p = this->GetWorldPosition();
513 
514             // Get the motion vector
515             double v[3] = { newCenterPoint[0] - p[0], newCenterPoint[1] - p[1],
516               newCenterPoint[2] - p[2] };
517             double *bounds = this->Cursor3D->GetModelBounds(), newBounds[6];
518             for (int i = 0; i < 3; i++)
519             {
520               newBounds[2 * i] = bounds[2 * i] + v[i];
521               newBounds[2 * i + 1] = bounds[2 * i + 1] + v[i];
522             }
523 
524             this->Cursor3D->SetModelBounds(newBounds);
525             this->SetWorldPosition(newCenterPoint);
526           }
527         }
528       }
529     }
530   }
531 
532   else if (this->InteractionState == vtkHandleRepresentation::Scaling)
533   {
534     // Scaling does not change the position of the handle, we needn't
535     // ask the placer..
536     this->Scale(prevPickPoint, pickPoint, eventPos);
537   }
538 
539   // Book keeping
540   this->LastEventPosition[0] = eventPos[0];
541   this->LastEventPosition[1] = eventPos[1];
542 
543   this->Modified();
544 }
545 
ComplexInteraction(vtkRenderWindowInteractor *,vtkAbstractWidget *,unsigned long,void * calldata)546 void vtkPointHandleRepresentation3D::ComplexInteraction(
547   vtkRenderWindowInteractor*, vtkAbstractWidget*, unsigned long, void* calldata)
548 {
549   vtkEventData* edata = static_cast<vtkEventData*>(calldata);
550   vtkEventDataDevice3D* edd = edata->GetAsEventDataDevice3D();
551   if (edd)
552   {
553     double eventPos[3];
554     edd->GetWorldPosition(eventPos);
555     // Process the motion
556     if (this->InteractionState == vtkHandleRepresentation::Selecting ||
557       this->InteractionState == vtkHandleRepresentation::Translating)
558     {
559       this->WaitCount++;
560 
561       if (this->WaitCount > 3 || !this->Constrained)
562       {
563         this->ConstraintAxis =
564           this->DetermineConstraintAxis(this->ConstraintAxis, eventPos, this->StartEventPosition);
565 
566         if (this->InteractionState == vtkHandleRepresentation::Selecting && !this->TranslationMode)
567         {
568           vtkDebugMacro(<< "Processing widget interaction for Select mode");
569 
570           this->MoveFocus(this->LastEventPosition, eventPos);
571         }
572         else
573         {
574           vtkDebugMacro(<< "Processing widget interaction for translate");
575           this->Translate(this->LastEventPosition, eventPos);
576         }
577       }
578     }
579 
580     // Book keeping
581     this->LastEventPosition[0] = eventPos[0];
582     this->LastEventPosition[1] = eventPos[1];
583     this->LastEventPosition[2] = eventPos[2];
584 
585     this->Modified();
586   }
587 }
588 
589 //------------------------------------------------------------------------------
MoveFocusRequest(const double * p1,const double * p2,const double eventPos[2],double center[3])590 void vtkPointHandleRepresentation3D ::MoveFocusRequest(
591   const double* p1, const double* p2, const double eventPos[2], double center[3])
592 {
593   if (this->SmoothMotion)
594   {
595     double focus[4], v[3];
596     this->Cursor3D->GetFocalPoint(focus);
597     this->GetTranslationVector(p1, p2, v);
598 
599     // Move the center of the handle along the motion vector
600     focus[0] += v[0];
601     focus[1] += v[1];
602     focus[2] += v[2];
603     focus[3] = 1.0;
604 
605     // Get the display position that this center would fall on.
606     this->Renderer->SetWorldPoint(focus);
607     this->Renderer->WorldToDisplay();
608     this->Renderer->GetDisplayPoint(center);
609   }
610   else
611   {
612     center[0] = eventPos[0];
613     center[1] = eventPos[1];
614     center[2] = 1.0;
615   }
616 }
617 
618 //------------------------------------------------------------------------------
MoveFocus(const double * p1,const double * p2)619 void vtkPointHandleRepresentation3D::MoveFocus(const double* p1, const double* p2)
620 {
621   this->Translate(p1, p2);
622 }
623 
624 //------------------------------------------------------------------------------
SetTranslationMode(vtkTypeBool mode)625 void vtkPointHandleRepresentation3D::SetTranslationMode(vtkTypeBool mode)
626 {
627   if (this->TranslationMode != mode)
628   {
629     this->TranslationMode = mode;
630     // Pass new setting to Cursor3D, otherwise PlaceWidget will not work
631     // as it should when TranslationMode is off.
632     this->Cursor3D->SetTranslationMode(mode);
633     this->Modified();
634   }
635 }
636 
637 //------------------------------------------------------------------------------
638 // Translate everything
Translate(const double * p1,const double * p2)639 void vtkPointHandleRepresentation3D::Translate(const double* p1, const double* p2)
640 {
641   double v[3] = { 0, 0, 0 };
642   vtkHandleRepresentation::Translate(p1, p2);
643   this->GetTranslationVector(p1, p2, v);
644 
645   double* bounds = this->Cursor3D->GetModelBounds();
646   double* pos = this->Cursor3D->GetFocalPoint();
647   double newBounds[6], newFocus[3];
648   int i;
649 
650   if (this->ConstraintAxis >= 0)
651   { // move along axis
652     for (i = 0; i < 3; i++)
653     {
654       if (i != this->ConstraintAxis)
655       {
656         v[i] = 0.0;
657       }
658     }
659   }
660 
661   for (i = 0; i < 3; i++)
662   {
663     newBounds[2 * i] = bounds[2 * i] + v[i];
664     newBounds[2 * i + 1] = bounds[2 * i + 1] + v[i];
665     newFocus[i] = pos[i] + v[i];
666   }
667 
668   this->Cursor3D->SetModelBounds(newBounds);
669   this->Cursor3D->SetFocalPoint(newFocus);
670 }
671 
672 //------------------------------------------------------------------------------
SizeBounds()673 void vtkPointHandleRepresentation3D::SizeBounds()
674 {
675   // Only change the size of the bounding box if translation mode is on.
676   if (this->TranslationMode)
677   {
678     double center[3], bounds[6];
679     this->Cursor3D->GetFocalPoint(center);
680     double radius = this->SizeHandlesInPixels(1.0, center);
681     radius *= this->CurrentHandleSize / this->HandleSize;
682 
683     for (int i = 0; i < 3; i++)
684     {
685       bounds[2 * i] = center[i] - radius;
686       bounds[2 * i + 1] = center[i] + radius;
687     }
688     this->Cursor3D->SetModelBounds(bounds);
689   }
690 }
691 
692 //------------------------------------------------------------------------------
Scale(const double * p1,const double * p2,const double eventPos[2])693 void vtkPointHandleRepresentation3D::Scale(
694   const double* p1, const double* p2, const double eventPos[2])
695 {
696   // Get the motion vector
697   double v[3];
698   v[0] = p2[0] - p1[0];
699   v[1] = p2[1] - p1[1];
700   v[2] = p2[2] - p1[2];
701 
702   double* bounds = this->Cursor3D->GetModelBounds();
703 
704   // Compute the scale factor
705   double sf = vtkMath::Norm(v) /
706     sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
707       (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
708       (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
709 
710   if (eventPos[1] > this->LastEventPosition[1])
711   {
712     sf = 1.0 + sf;
713   }
714   else
715   {
716     sf = 1.0 - sf;
717   }
718 
719   this->CurrentHandleSize *= sf;
720   this->CurrentHandleSize = (this->CurrentHandleSize < 0.001 ? 0.001 : this->CurrentHandleSize);
721 
722   this->SizeBounds();
723 }
724 
725 //------------------------------------------------------------------------------
Highlight(int highlight)726 void vtkPointHandleRepresentation3D::Highlight(int highlight)
727 {
728   if (highlight)
729   {
730     this->Actor->SetProperty(this->SelectedProperty);
731   }
732   else
733   {
734     this->Actor->SetProperty(this->Property);
735   }
736 }
737 
738 //------------------------------------------------------------------------------
CreateDefaultProperties()739 void vtkPointHandleRepresentation3D::CreateDefaultProperties()
740 {
741   this->Property = vtkProperty::New();
742   this->Property->SetAmbient(1.0);
743   this->Property->SetAmbientColor(1.0, 1.0, 1.0);
744   this->Property->SetLineWidth(0.5);
745 
746   this->SelectedProperty = vtkProperty::New();
747   this->SelectedProperty->SetAmbient(1.0);
748   this->SelectedProperty->SetAmbientColor(0.0, 1.0, 0.0);
749   this->SelectedProperty->SetLineWidth(2.0);
750 }
751 
752 //------------------------------------------------------------------------------
SetVisibility(vtkTypeBool visible)753 void vtkPointHandleRepresentation3D::SetVisibility(vtkTypeBool visible)
754 {
755   this->Actor->SetVisibility(visible);
756   // Forward to superclass
757   this->Superclass::SetVisibility(visible);
758 }
759 
760 //------------------------------------------------------------------------------
BuildRepresentation()761 void vtkPointHandleRepresentation3D::BuildRepresentation()
762 {
763   // The net effect is to resize the handle
764   if (this->GetMTime() > this->BuildTime ||
765     (this->Renderer && this->Renderer->GetVTKWindow() &&
766       this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime))
767   {
768     if (!this->Placed)
769     {
770       this->ValidPick = 1;
771       this->Placed = 1;
772     }
773 
774     this->SizeBounds();
775     this->Cursor3D->Update();
776     this->BuildTime.Modified();
777   }
778 }
779 
780 //------------------------------------------------------------------------------
ShallowCopy(vtkProp * prop)781 void vtkPointHandleRepresentation3D::ShallowCopy(vtkProp* prop)
782 {
783   vtkPointHandleRepresentation3D* rep = vtkPointHandleRepresentation3D::SafeDownCast(prop);
784   if (rep)
785   {
786     this->SetOutline(rep->GetOutline());
787     this->SetXShadows(rep->GetXShadows());
788     this->SetYShadows(rep->GetYShadows());
789     this->SetZShadows(rep->GetZShadows());
790     this->SetTranslationMode(rep->GetTranslationMode());
791     this->SetProperty(rep->GetProperty());
792     this->Actor->SetProperty(rep->GetProperty());
793     this->SetSelectedProperty(rep->GetSelectedProperty());
794     this->SetHotSpotSize(rep->GetHotSpotSize());
795   }
796   this->Superclass::ShallowCopy(prop);
797 }
798 
799 //------------------------------------------------------------------------------
DeepCopy(vtkProp * prop)800 void vtkPointHandleRepresentation3D::DeepCopy(vtkProp* prop)
801 {
802   vtkPointHandleRepresentation3D* rep = vtkPointHandleRepresentation3D::SafeDownCast(prop);
803   if (rep)
804   {
805     this->SetOutline(rep->GetOutline());
806     this->SetXShadows(rep->GetXShadows());
807     this->SetYShadows(rep->GetYShadows());
808     this->SetZShadows(rep->GetZShadows());
809     this->SetTranslationMode(rep->GetTranslationMode());
810     this->SetProperty(rep->GetProperty());
811     this->Actor->SetProperty(rep->GetProperty());
812     this->SetSelectedProperty(rep->GetSelectedProperty());
813     this->SetHotSpotSize(rep->GetHotSpotSize());
814   }
815   this->Superclass::DeepCopy(prop);
816 }
817 
818 //------------------------------------------------------------------------------
GetActors(vtkPropCollection * pc)819 void vtkPointHandleRepresentation3D::GetActors(vtkPropCollection* pc)
820 {
821   this->Actor->GetActors(pc);
822 }
823 
824 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * win)825 void vtkPointHandleRepresentation3D::ReleaseGraphicsResources(vtkWindow* win)
826 {
827   this->Actor->ReleaseGraphicsResources(win);
828 }
829 
830 //------------------------------------------------------------------------------
RenderOpaqueGeometry(vtkViewport * viewport)831 int vtkPointHandleRepresentation3D::RenderOpaqueGeometry(vtkViewport* viewport)
832 {
833   this->BuildRepresentation();
834 
835   // Sanity check
836   double worldPos[3];
837   this->GetWorldPosition(worldPos);
838   if (worldPos[0] == VTK_DOUBLE_MAX)
839   {
840     return 0;
841   }
842 
843   return this->Actor->RenderOpaqueGeometry(viewport);
844 }
845 
846 //------------------------------------------------------------------------------
RenderTranslucentPolygonalGeometry(vtkViewport * viewport)847 int vtkPointHandleRepresentation3D::RenderTranslucentPolygonalGeometry(vtkViewport* viewport)
848 {
849   this->BuildRepresentation();
850 
851   // Sanity check
852   double worldPos[3];
853   this->GetWorldPosition(worldPos);
854   if (worldPos[0] == VTK_DOUBLE_MAX)
855   {
856     return 0;
857   }
858 
859   return this->Actor->RenderTranslucentPolygonalGeometry(viewport);
860 }
861 //------------------------------------------------------------------------------
HasTranslucentPolygonalGeometry()862 vtkTypeBool vtkPointHandleRepresentation3D::HasTranslucentPolygonalGeometry()
863 {
864   this->BuildRepresentation();
865   return this->Actor->HasTranslucentPolygonalGeometry();
866 }
867 
868 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)869 void vtkPointHandleRepresentation3D::PrintSelf(ostream& os, vtkIndent indent)
870 {
871   // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
872   this->Superclass::PrintSelf(os, indent);
873 
874   os << indent << "Hot Spot Size: " << this->HotSpotSize << "\n";
875   if (this->Property)
876   {
877     os << indent << "Property: " << this->Property << "\n";
878   }
879   else
880   {
881     os << indent << "Property: (none)\n";
882   }
883   if (this->SelectedProperty)
884   {
885     os << indent << "Selected Property: " << this->SelectedProperty << "\n";
886   }
887   else
888   {
889     os << indent << "Selected Property: (none)\n";
890   }
891 
892   os << indent << "Outline: " << (this->GetOutline() ? "On\n" : "Off\n");
893   os << indent << "XShadows: " << (this->GetXShadows() ? "On\n" : "Off\n");
894   os << indent << "YShadows: " << (this->GetYShadows() ? "On\n" : "Off\n");
895   os << indent << "ZShadows: " << (this->GetZShadows() ? "On\n" : "Off\n");
896 
897   os << indent << "Translation Mode: " << (this->TranslationMode ? "On\n" : "Off\n");
898   os << indent << "SmoothMotion: " << this->SmoothMotion << endl;
899 }
900