1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLineWidget.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 "vtkLineWidget.h"
16 
17 #include "vtkActor.h"
18 #include "vtkAssemblyNode.h"
19 #include "vtkAssemblyPath.h"
20 #include "vtkCallbackCommand.h"
21 #include "vtkCamera.h"
22 #include "vtkCellPicker.h"
23 #include "vtkCommand.h"
24 #include "vtkDoubleArray.h"
25 #include "vtkFloatArray.h"
26 #include "vtkMath.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPickingManager.h"
29 #include "vtkPlanes.h"
30 #include "vtkPointWidget.h"
31 #include "vtkPolyData.h"
32 #include "vtkPolyDataMapper.h"
33 #include "vtkProperty.h"
34 #include "vtkRenderWindow.h"
35 #include "vtkRenderWindowInteractor.h"
36 #include "vtkRenderer.h"
37 #include "vtkSphereSource.h"
38 
39 vtkStandardNewMacro(vtkLineWidget);
40 
41 //------------------------------------------------------------------------------
42 // This class is used to coordinate the interaction between the point widget
43 // at the center of the line and the line widget. When the line is selected
44 // (as compared to the handles), a point widget appears at the selection
45 // point, which can be manipulated in the usual way.
46 class vtkPWCallback : public vtkCommand
47 {
48 public:
New()49   static vtkPWCallback* New() { return new vtkPWCallback; }
Execute(vtkObject * vtkNotUsed (caller),unsigned long,void *)50   void Execute(vtkObject* vtkNotUsed(caller), unsigned long, void*) override
51   {
52     double x[3];
53     this->PointWidget->GetPosition(x);
54     this->LineWidget->SetLinePosition(x);
55   }
vtkPWCallback()56   vtkPWCallback()
57     : LineWidget(nullptr)
58     , PointWidget(nullptr)
59   {
60   }
61   vtkLineWidget* LineWidget;
62   vtkPointWidget* PointWidget;
63 };
64 
65 //------------------------------------------------------------------------------
66 // This class is used to coordinate the interaction between the point widget
67 // (point 1) and the line widget.
68 class vtkPW1Callback : public vtkCommand
69 {
70 public:
New()71   static vtkPW1Callback* New() { return new vtkPW1Callback; }
Execute(vtkObject * vtkNotUsed (caller),unsigned long,void *)72   void Execute(vtkObject* vtkNotUsed(caller), unsigned long, void*) override
73   {
74     double x[3];
75     this->PointWidget->GetPosition(x);
76     this->LineWidget->SetPoint1(x);
77   }
vtkPW1Callback()78   vtkPW1Callback()
79     : LineWidget(nullptr)
80     , PointWidget(nullptr)
81   {
82   }
83   vtkLineWidget* LineWidget;
84   vtkPointWidget* PointWidget;
85 };
86 
87 //------------------------------------------------------------------------------
88 // This class is used to coordinate the interaction between the point widget
89 // (point 2) and the line widget.
90 class vtkPW2Callback : public vtkCommand
91 {
92 public:
New()93   static vtkPW2Callback* New() { return new vtkPW2Callback; }
Execute(vtkObject * vtkNotUsed (caller),unsigned long,void *)94   void Execute(vtkObject* vtkNotUsed(caller), unsigned long, void*) override
95   {
96     double x[3];
97     this->PointWidget->GetPosition(x);
98     this->LineWidget->SetPoint2(x);
99   }
vtkPW2Callback()100   vtkPW2Callback()
101     : LineWidget(nullptr)
102     , PointWidget(nullptr)
103   {
104   }
105   vtkLineWidget* LineWidget;
106   vtkPointWidget* PointWidget;
107 };
108 
109 //------------------------------------------------------------------------------
110 // Begin the definition of the vtkLineWidget methods
111 //
vtkLineWidget()112 vtkLineWidget::vtkLineWidget()
113 {
114   this->State = vtkLineWidget::Start;
115   this->EventCallbackCommand->SetCallback(vtkLineWidget::ProcessEvents);
116 
117   this->Align = vtkLineWidget::XAxis;
118 
119   // Build the representation of the widget
120   int i;
121   // Represent the line
122   this->LineSource = vtkLineSource::New();
123   this->LineSource->SetResolution(5);
124   this->LineMapper = vtkPolyDataMapper::New();
125   this->LineMapper->SetInputConnection(this->LineSource->GetOutputPort());
126   this->LineActor = vtkActor::New();
127   this->LineActor->SetMapper(this->LineMapper);
128 
129   // Create the handles
130   this->Handle = new vtkActor*[2];
131   this->HandleMapper = new vtkPolyDataMapper*[2];
132   this->HandleGeometry = new vtkSphereSource*[2];
133   for (i = 0; i < 2; i++)
134   {
135     this->HandleGeometry[i] = vtkSphereSource::New();
136     this->HandleGeometry[i]->SetThetaResolution(16);
137     this->HandleGeometry[i]->SetPhiResolution(8);
138     this->HandleMapper[i] = vtkPolyDataMapper::New();
139     this->HandleMapper[i]->SetInputConnection(this->HandleGeometry[i]->GetOutputPort());
140     this->Handle[i] = vtkActor::New();
141     this->Handle[i]->SetMapper(this->HandleMapper[i]);
142   }
143 
144   // Define the point coordinates
145   double bounds[6];
146   bounds[0] = -0.5;
147   bounds[1] = 0.5;
148   bounds[2] = -0.5;
149   bounds[3] = 0.5;
150   bounds[4] = -0.5;
151   bounds[5] = 0.5;
152   this->PlaceFactor = 1.0; // overload parent's value
153 
154   // Initial creation of the widget, serves to initialize it
155   this->PlaceWidget(bounds);
156   this->ClampToBounds = 0;
157 
158   // Manage the picking stuff
159   this->HandlePicker = vtkCellPicker::New();
160   this->HandlePicker->SetTolerance(0.001);
161   for (i = 0; i < 2; i++)
162   {
163     this->HandlePicker->AddPickList(this->Handle[i]);
164   }
165   this->HandlePicker->PickFromListOn();
166 
167   this->LinePicker = vtkCellPicker::New();
168   this->LinePicker->SetTolerance(0.005); // need some fluff
169   this->LinePicker->AddPickList(this->LineActor);
170   this->LinePicker->PickFromListOn();
171 
172   this->CurrentHandle = nullptr;
173 
174   // Set up the initial properties
175   this->CreateDefaultProperties();
176 
177   // Create the point widgets and associated callbacks
178   this->PointWidget = vtkPointWidget::New();
179   this->PointWidget->AllOff();
180   this->PointWidget->SetHotSpotSize(0.5);
181 
182   this->PointWidget1 = vtkPointWidget::New();
183   this->PointWidget1->AllOff();
184   this->PointWidget1->SetHotSpotSize(0.5);
185 
186   this->PointWidget2 = vtkPointWidget::New();
187   this->PointWidget2->AllOff();
188   this->PointWidget2->SetHotSpotSize(0.5);
189 
190   this->PWCallback = vtkPWCallback::New();
191   this->PWCallback->LineWidget = this;
192   this->PWCallback->PointWidget = this->PointWidget;
193   this->PW1Callback = vtkPW1Callback::New();
194   this->PW1Callback->LineWidget = this;
195   this->PW1Callback->PointWidget = this->PointWidget1;
196   this->PW2Callback = vtkPW2Callback::New();
197   this->PW2Callback->LineWidget = this;
198   this->PW2Callback->PointWidget = this->PointWidget2;
199 
200   // Very tricky, the point widgets watch for their own
201   // interaction events.
202   this->PointWidget->AddObserver(vtkCommand::InteractionEvent, this->PWCallback, 0.0);
203   this->PointWidget1->AddObserver(vtkCommand::InteractionEvent, this->PW1Callback, 0.0);
204   this->PointWidget2->AddObserver(vtkCommand::InteractionEvent, this->PW2Callback, 0.0);
205   this->CurrentPointWidget = nullptr;
206 }
207 
208 //------------------------------------------------------------------------------
~vtkLineWidget()209 vtkLineWidget::~vtkLineWidget()
210 {
211   this->LineActor->Delete();
212   this->LineMapper->Delete();
213   this->LineSource->Delete();
214 
215   for (int i = 0; i < 2; i++)
216   {
217     this->HandleGeometry[i]->Delete();
218     this->HandleMapper[i]->Delete();
219     this->Handle[i]->Delete();
220   }
221   delete[] this->Handle;
222   delete[] this->HandleMapper;
223   delete[] this->HandleGeometry;
224 
225   this->HandlePicker->Delete();
226   this->LinePicker->Delete();
227 
228   this->HandleProperty->Delete();
229   this->SelectedHandleProperty->Delete();
230   this->LineProperty->Delete();
231   this->SelectedLineProperty->Delete();
232 
233   this->PointWidget->RemoveObserver(this->PWCallback);
234   this->PointWidget1->RemoveObserver(this->PW1Callback);
235   this->PointWidget2->RemoveObserver(this->PW2Callback);
236   this->PointWidget->Delete();
237   this->PointWidget1->Delete();
238   this->PointWidget2->Delete();
239   this->PWCallback->Delete();
240   this->PW1Callback->Delete();
241   this->PW2Callback->Delete();
242 }
243 
244 //------------------------------------------------------------------------------
SetEnabled(int enabling)245 void vtkLineWidget::SetEnabled(int enabling)
246 {
247   if (!this->Interactor)
248   {
249     vtkErrorMacro(<< "The interactor must be set prior to enabling/disabling widget");
250     return;
251   }
252 
253   if (enabling) //-----------------------------------------------------------
254   {
255     vtkDebugMacro(<< "Enabling line widget");
256 
257     if (this->Enabled) // already enabled, just return
258     {
259       return;
260     }
261 
262     if (!this->CurrentRenderer)
263     {
264       this->SetCurrentRenderer(this->Interactor->FindPokedRenderer(
265         this->Interactor->GetLastEventPosition()[0], this->Interactor->GetLastEventPosition()[1]));
266       if (this->CurrentRenderer == nullptr)
267       {
268         return;
269       }
270     }
271 
272     this->PointWidget->SetCurrentRenderer(this->CurrentRenderer);
273     this->PointWidget1->SetCurrentRenderer(this->CurrentRenderer);
274     this->PointWidget2->SetCurrentRenderer(this->CurrentRenderer);
275 
276     this->Enabled = 1;
277 
278     // listen for the following events
279     vtkRenderWindowInteractor* i = this->Interactor;
280     i->AddObserver(vtkCommand::MouseMoveEvent, this->EventCallbackCommand, this->Priority);
281     i->AddObserver(vtkCommand::LeftButtonPressEvent, this->EventCallbackCommand, this->Priority);
282     i->AddObserver(vtkCommand::LeftButtonReleaseEvent, this->EventCallbackCommand, this->Priority);
283     i->AddObserver(vtkCommand::MiddleButtonPressEvent, this->EventCallbackCommand, this->Priority);
284     i->AddObserver(
285       vtkCommand::MiddleButtonReleaseEvent, this->EventCallbackCommand, this->Priority);
286     i->AddObserver(vtkCommand::RightButtonPressEvent, this->EventCallbackCommand, this->Priority);
287     i->AddObserver(vtkCommand::RightButtonReleaseEvent, this->EventCallbackCommand, this->Priority);
288 
289     // Add the line
290     this->CurrentRenderer->AddActor(this->LineActor);
291     this->LineActor->SetProperty(this->LineProperty);
292 
293     // turn on the handles
294     for (int j = 0; j < 2; j++)
295     {
296       this->CurrentRenderer->AddActor(this->Handle[j]);
297       this->Handle[j]->SetProperty(this->HandleProperty);
298     }
299 
300     this->BuildRepresentation();
301     this->SizeHandles();
302     this->RegisterPickers();
303 
304     this->InvokeEvent(vtkCommand::EnableEvent, nullptr);
305   }
306 
307   else // disabling----------------------------------------------------------
308   {
309     vtkDebugMacro(<< "Disabling line widget");
310 
311     if (!this->Enabled) // already disabled, just return
312     {
313       return;
314     }
315 
316     this->Enabled = 0;
317 
318     // don't listen for events any more
319     this->Interactor->RemoveObserver(this->EventCallbackCommand);
320 
321     // turn off the line
322     this->CurrentRenderer->RemoveActor(this->LineActor);
323 
324     // turn off the handles
325     for (int i = 0; i < 2; i++)
326     {
327       this->CurrentRenderer->RemoveActor(this->Handle[i]);
328     }
329 
330     if (this->CurrentPointWidget)
331     {
332       this->CurrentPointWidget->EnabledOff();
333     }
334 
335     this->CurrentHandle = nullptr;
336     this->InvokeEvent(vtkCommand::DisableEvent, nullptr);
337     this->SetCurrentRenderer(nullptr);
338     this->UnRegisterPickers();
339   }
340 
341   this->Interactor->Render();
342 }
343 
344 //------------------------------------------------------------------------------
RegisterPickers()345 void vtkLineWidget::RegisterPickers()
346 {
347   vtkPickingManager* pm = this->GetPickingManager();
348   if (!pm)
349   {
350     return;
351   }
352   pm->AddPicker(this->HandlePicker, this);
353   pm->AddPicker(this->LinePicker, this);
354 }
355 
356 //------------------------------------------------------------------------------
ProcessEvents(vtkObject * vtkNotUsed (object),unsigned long event,void * clientdata,void * vtkNotUsed (calldata))357 void vtkLineWidget::ProcessEvents(
358   vtkObject* vtkNotUsed(object), unsigned long event, void* clientdata, void* vtkNotUsed(calldata))
359 {
360   vtkLineWidget* self = reinterpret_cast<vtkLineWidget*>(clientdata);
361 
362   // okay, let's do the right thing
363   switch (event)
364   {
365     case vtkCommand::LeftButtonPressEvent:
366       self->OnLeftButtonDown();
367       break;
368     case vtkCommand::LeftButtonReleaseEvent:
369       self->OnLeftButtonUp();
370       break;
371     case vtkCommand::MiddleButtonPressEvent:
372       self->OnMiddleButtonDown();
373       break;
374     case vtkCommand::MiddleButtonReleaseEvent:
375       self->OnMiddleButtonUp();
376       break;
377     case vtkCommand::RightButtonPressEvent:
378       self->OnRightButtonDown();
379       break;
380     case vtkCommand::RightButtonReleaseEvent:
381       self->OnRightButtonUp();
382       break;
383     case vtkCommand::MouseMoveEvent:
384       self->OnMouseMove();
385       break;
386   }
387 }
388 
389 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)390 void vtkLineWidget::PrintSelf(ostream& os, vtkIndent indent)
391 {
392   this->Superclass::PrintSelf(os, indent);
393 
394   if (this->HandleProperty)
395   {
396     os << indent << "Handle Property: " << this->HandleProperty << "\n";
397   }
398   else
399   {
400     os << indent << "Handle Property: (none)\n";
401   }
402   if (this->SelectedHandleProperty)
403   {
404     os << indent << "Selected Handle Property: " << this->SelectedHandleProperty << "\n";
405   }
406   else
407   {
408     os << indent << "Selected Handle Property: (none)\n";
409   }
410 
411   if (this->LineProperty)
412   {
413     os << indent << "Line Property: " << this->LineProperty << "\n";
414   }
415   else
416   {
417     os << indent << "Line Property: (none)\n";
418   }
419   if (this->SelectedLineProperty)
420   {
421     os << indent << "Selected Line Property: " << this->SelectedLineProperty << "\n";
422   }
423   else
424   {
425     os << indent << "Selected Line Property: (none)\n";
426   }
427 
428   os << indent << "Constrain To Bounds: " << (this->ClampToBounds ? "On\n" : "Off\n");
429 
430   os << indent << "Align with: ";
431   switch (this->Align)
432   {
433     case XAxis:
434       os << "X Axis";
435       break;
436     case YAxis:
437       os << "Y Axis";
438       break;
439     case ZAxis:
440       os << "Z Axis";
441       break;
442     default:
443       os << "None";
444   }
445   int res = this->LineSource->GetResolution();
446   double* pt1 = this->LineSource->GetPoint1();
447   double* pt2 = this->LineSource->GetPoint2();
448 
449   os << indent << "Resolution: " << res << "\n";
450   os << indent << "Point 1: (" << pt1[0] << ", " << pt1[1] << ", " << pt1[2] << ")\n";
451   os << indent << "Point 2: (" << pt2[0] << ", " << pt2[1] << ", " << pt2[2] << ")\n";
452 }
453 
454 //------------------------------------------------------------------------------
BuildRepresentation()455 void vtkLineWidget::BuildRepresentation()
456 {
457   // int res = this->LineSource->GetResolution();
458   double* pt1 = this->LineSource->GetPoint1();
459   double* pt2 = this->LineSource->GetPoint2();
460 
461   this->HandleGeometry[0]->SetCenter(pt1);
462   this->HandleGeometry[1]->SetCenter(pt2);
463 }
464 
465 //------------------------------------------------------------------------------
SizeHandles()466 void vtkLineWidget::SizeHandles()
467 {
468   double radius = this->vtk3DWidget::SizeHandles(1.0);
469   this->HandleGeometry[0]->SetRadius(radius);
470   this->HandleGeometry[1]->SetRadius(radius);
471 }
472 
473 //------------------------------------------------------------------------------
HighlightHandle(vtkProp * prop)474 int vtkLineWidget::HighlightHandle(vtkProp* prop)
475 {
476   // first unhighlight anything picked
477   if (this->CurrentHandle)
478   {
479     this->CurrentHandle->SetProperty(this->HandleProperty);
480   }
481 
482   // set the current handle
483   this->CurrentHandle = static_cast<vtkActor*>(prop);
484 
485   // find the current handle
486   if (this->CurrentHandle)
487   {
488     this->ValidPick = 1;
489     this->HandlePicker->GetPickPosition(this->LastPickPosition);
490     this->CurrentHandle->SetProperty(this->SelectedHandleProperty);
491     return (this->CurrentHandle == this->Handle[0] ? 0 : 1);
492   }
493   return -1;
494 }
495 
496 //------------------------------------------------------------------------------
ForwardEvent(unsigned long event)497 int vtkLineWidget::ForwardEvent(unsigned long event)
498 {
499   if (!this->CurrentPointWidget)
500   {
501     return 0;
502   }
503 
504   vtkPointWidget::ProcessEvents(this, event, this->CurrentPointWidget, nullptr);
505 
506   return 1;
507 }
508 
509 //------------------------------------------------------------------------------
510 // assumed current handle is set
EnablePointWidget()511 void vtkLineWidget::EnablePointWidget()
512 {
513   // Set up the point widgets
514   double x[3];
515   if (this->CurrentHandle) // picking the handles
516   {
517     if (this->CurrentHandle == this->Handle[0])
518     {
519       this->CurrentPointWidget = this->PointWidget1;
520       this->LineSource->GetPoint1(x);
521     }
522     else
523     {
524       this->CurrentPointWidget = this->PointWidget2;
525       this->LineSource->GetPoint2(x);
526     }
527   }
528   else // picking the line
529   {
530     this->CurrentPointWidget = this->PointWidget;
531     this->LinePicker->GetPickPosition(x);
532     this->LastPosition[0] = x[0];
533     this->LastPosition[1] = x[1];
534     this->LastPosition[2] = x[2];
535   }
536 
537   double bounds[6];
538   for (int i = 0; i < 3; i++)
539   {
540     bounds[2 * i] = x[i] - 0.1 * this->InitialLength;
541     bounds[2 * i + 1] = x[i] + 0.1 * this->InitialLength;
542   }
543 
544   // Note: translation mode is disabled and enabled to control
545   // the proper positioning of the bounding box.
546   this->CurrentPointWidget->SetInteractor(this->Interactor);
547   this->CurrentPointWidget->TranslationModeOff();
548   this->CurrentPointWidget->SetPlaceFactor(1.0);
549   this->CurrentPointWidget->PlaceWidget(bounds);
550   this->CurrentPointWidget->TranslationModeOn();
551   this->CurrentPointWidget->SetPosition(x);
552   this->CurrentPointWidget->SetCurrentRenderer(this->CurrentRenderer);
553   this->CurrentPointWidget->On();
554 }
555 
556 //------------------------------------------------------------------------------
557 // assumed current handle is set
DisablePointWidget()558 void vtkLineWidget::DisablePointWidget()
559 {
560   if (this->CurrentPointWidget)
561   {
562     this->CurrentPointWidget->Off();
563   }
564   this->CurrentPointWidget = nullptr;
565 }
566 
567 //------------------------------------------------------------------------------
HighlightHandles(int highlight)568 void vtkLineWidget::HighlightHandles(int highlight)
569 {
570   if (highlight)
571   {
572     this->ValidPick = 1;
573     this->HandlePicker->GetPickPosition(this->LastPickPosition);
574     this->Handle[0]->SetProperty(this->SelectedHandleProperty);
575     this->Handle[1]->SetProperty(this->SelectedHandleProperty);
576   }
577   else
578   {
579     this->Handle[0]->SetProperty(this->HandleProperty);
580     this->Handle[1]->SetProperty(this->HandleProperty);
581   }
582 }
583 
584 //------------------------------------------------------------------------------
HighlightLine(int highlight)585 void vtkLineWidget::HighlightLine(int highlight)
586 {
587   if (highlight)
588   {
589     this->ValidPick = 1;
590     this->LinePicker->GetPickPosition(this->LastPickPosition);
591     this->LineActor->SetProperty(this->SelectedLineProperty);
592   }
593   else
594   {
595     this->LineActor->SetProperty(this->LineProperty);
596   }
597 }
598 
599 //------------------------------------------------------------------------------
OnLeftButtonDown()600 void vtkLineWidget::OnLeftButtonDown()
601 {
602   int forward = 0;
603 
604   int X = this->Interactor->GetEventPosition()[0];
605   int Y = this->Interactor->GetEventPosition()[1];
606 
607   // Okay, make sure that the pick is in the current renderer
608   if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
609   {
610     this->State = vtkLineWidget::Outside;
611     return;
612   }
613 
614   // Okay, we can process this. Try to pick handles first;
615   // if no handles picked, then try to pick the line.
616   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
617 
618   if (path != nullptr)
619   {
620     this->EventCallbackCommand->SetAbortFlag(1);
621     this->StartInteraction();
622     this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
623     this->State = vtkLineWidget::MovingHandle;
624     this->HighlightHandle(path->GetFirstNode()->GetViewProp());
625     this->EnablePointWidget();
626     forward = this->ForwardEvent(vtkCommand::LeftButtonPressEvent);
627   }
628   else
629   {
630     path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
631 
632     if (path != nullptr)
633     {
634       this->EventCallbackCommand->SetAbortFlag(1);
635       this->StartInteraction();
636       this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
637       this->State = vtkLineWidget::MovingLine;
638       this->HighlightLine(1);
639       this->EnablePointWidget();
640       forward = this->ForwardEvent(vtkCommand::LeftButtonPressEvent);
641     }
642     else
643     {
644       this->State = vtkLineWidget::Outside;
645       this->HighlightHandle(nullptr);
646       return;
647     }
648   }
649 
650   if (!forward)
651   {
652     this->Interactor->Render();
653   }
654 }
655 
656 //------------------------------------------------------------------------------
OnLeftButtonUp()657 void vtkLineWidget::OnLeftButtonUp()
658 {
659   if (this->State == vtkLineWidget::Outside || this->State == vtkLineWidget::Start)
660   {
661     return;
662   }
663 
664   this->State = vtkLineWidget::Start;
665   this->HighlightHandle(nullptr);
666   this->HighlightLine(0);
667 
668   this->SizeHandles();
669 
670   int forward = this->ForwardEvent(vtkCommand::LeftButtonReleaseEvent);
671   this->DisablePointWidget();
672 
673   this->EventCallbackCommand->SetAbortFlag(1);
674   this->EndInteraction();
675   this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
676   if (!forward)
677   {
678     this->Interactor->Render();
679   }
680 }
681 
682 //------------------------------------------------------------------------------
OnMiddleButtonDown()683 void vtkLineWidget::OnMiddleButtonDown()
684 {
685   int forward = 0;
686 
687   int X = this->Interactor->GetEventPosition()[0];
688   int Y = this->Interactor->GetEventPosition()[1];
689 
690   // Okay, make sure that the pick is in the current renderer
691   if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
692   {
693     this->State = vtkLineWidget::Outside;
694     return;
695   }
696 
697   // Okay, we can process this. Try to pick handles first;
698   // if no handles picked, then pick the bounding box.
699   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
700 
701   if (path != nullptr)
702   {
703     this->EventCallbackCommand->SetAbortFlag(1);
704     this->StartInteraction();
705     this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
706     this->State = vtkLineWidget::MovingLine;
707     this->HighlightHandles(1);
708     this->HighlightLine(1);
709     this->EnablePointWidget();
710     forward = this->ForwardEvent(vtkCommand::LeftButtonPressEvent);
711   }
712   else
713   {
714     path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
715 
716     if (path != nullptr)
717     {
718       this->EventCallbackCommand->SetAbortFlag(1);
719       this->StartInteraction();
720       this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
721       // The highlight methods set the LastPickPosition, so they are ordered
722       this->HighlightHandles(1);
723       this->HighlightLine(1);
724       this->State = vtkLineWidget::MovingLine;
725       this->EnablePointWidget();
726       forward = this->ForwardEvent(vtkCommand::LeftButtonPressEvent);
727     }
728     else
729     {
730       this->State = vtkLineWidget::Outside;
731       return;
732     }
733   }
734 
735   if (!forward)
736   {
737     this->Interactor->Render();
738   }
739 }
740 
741 //------------------------------------------------------------------------------
OnMiddleButtonUp()742 void vtkLineWidget::OnMiddleButtonUp()
743 {
744   if (this->State == vtkLineWidget::Outside || this->State == vtkLineWidget::Start)
745   {
746     return;
747   }
748 
749   this->State = vtkLineWidget::Start;
750   this->HighlightLine(0);
751   this->HighlightHandles(0);
752 
753   this->SizeHandles();
754 
755   int forward = this->ForwardEvent(vtkCommand::LeftButtonReleaseEvent);
756   this->DisablePointWidget();
757 
758   this->EventCallbackCommand->SetAbortFlag(1);
759   this->EndInteraction();
760   this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
761   if (!forward)
762   {
763     this->Interactor->Render();
764   }
765 }
766 
767 //------------------------------------------------------------------------------
OnRightButtonDown()768 void vtkLineWidget::OnRightButtonDown()
769 {
770   int X = this->Interactor->GetEventPosition()[0];
771   int Y = this->Interactor->GetEventPosition()[1];
772 
773   // Okay, make sure that the pick is in the current renderer
774   if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y))
775   {
776     this->State = vtkLineWidget::Outside;
777     return;
778   }
779 
780   // Okay, we can process this. Try to pick handles first;
781   // if no handles picked, then pick the bounding box.
782   vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
783 
784   if (path != nullptr)
785   {
786     this->HighlightLine(1);
787     this->HighlightHandles(1);
788     this->State = vtkLineWidget::Scaling;
789   }
790   else
791   {
792     path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
793 
794     if (path != nullptr)
795     {
796       this->HighlightHandles(1);
797       this->HighlightLine(1);
798       this->State = vtkLineWidget::Scaling;
799     }
800     else
801     {
802       this->State = vtkLineWidget::Outside;
803       this->HighlightLine(0);
804       return;
805     }
806   }
807 
808   this->EventCallbackCommand->SetAbortFlag(1);
809   this->StartInteraction();
810   this->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr);
811   this->Interactor->Render();
812 }
813 
814 //------------------------------------------------------------------------------
OnRightButtonUp()815 void vtkLineWidget::OnRightButtonUp()
816 {
817   if (this->State == vtkLineWidget::Outside || this->State == vtkLineWidget::Start)
818   {
819     return;
820   }
821 
822   this->State = vtkLineWidget::Start;
823   this->HighlightLine(0);
824   this->HighlightHandles(0);
825 
826   this->SizeHandles();
827 
828   this->EventCallbackCommand->SetAbortFlag(1);
829   this->EndInteraction();
830   this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
831   this->Interactor->Render();
832 }
833 
834 //------------------------------------------------------------------------------
OnMouseMove()835 void vtkLineWidget::OnMouseMove()
836 {
837   // See whether we're active
838   if (this->State == vtkLineWidget::Outside || this->State == vtkLineWidget::Start)
839   {
840     return;
841   }
842 
843   int X = this->Interactor->GetEventPosition()[0];
844   int Y = this->Interactor->GetEventPosition()[1];
845 
846   // Do different things depending on state
847   // Calculations everybody does
848   double focalPoint[4], pickPoint[4], prevPickPoint[4];
849   double z;
850 
851   vtkCamera* camera = this->CurrentRenderer->GetActiveCamera();
852   if (!camera)
853   {
854     return;
855   }
856 
857   // Compute the two points defining the motion vector
858   this->ComputeWorldToDisplay(
859     this->LastPickPosition[0], this->LastPickPosition[1], this->LastPickPosition[2], focalPoint);
860   z = focalPoint[2];
861   this->ComputeDisplayToWorld(double(this->Interactor->GetLastEventPosition()[0]),
862     double(this->Interactor->GetLastEventPosition()[1]), z, prevPickPoint);
863   this->ComputeDisplayToWorld(double(X), double(Y), z, pickPoint);
864 
865   // Process the motion
866   int forward = 0;
867   if (this->State == vtkLineWidget::MovingHandle)
868   {
869     forward = this->ForwardEvent(vtkCommand::MouseMoveEvent);
870   }
871   else if (this->State == vtkLineWidget::MovingLine)
872   {
873     forward = this->ForwardEvent(vtkCommand::MouseMoveEvent);
874   }
875   else if (this->State == vtkLineWidget::Scaling)
876   {
877     this->Scale(prevPickPoint, pickPoint, X, Y);
878   }
879 
880   // Interact, if desired
881   this->EventCallbackCommand->SetAbortFlag(1);
882   this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
883   if (!forward)
884   {
885     this->Interactor->Render();
886   }
887 }
888 
889 //------------------------------------------------------------------------------
Scale(double * p1,double * p2,int vtkNotUsed (X),int Y)890 void vtkLineWidget::Scale(double* p1, double* p2, int vtkNotUsed(X), int Y)
891 {
892   // Get the motion vector
893   double v[3];
894   v[0] = p2[0] - p1[0];
895   v[1] = p2[1] - p1[1];
896   v[2] = p2[2] - p1[2];
897 
898   // int res = this->LineSource->GetResolution();
899   double* pt1 = this->LineSource->GetPoint1();
900   double* pt2 = this->LineSource->GetPoint2();
901 
902   double center[3];
903   center[0] = (pt1[0] + pt2[0]) / 2.0;
904   center[1] = (pt1[1] + pt2[1]) / 2.0;
905   center[2] = (pt1[2] + pt2[2]) / 2.0;
906 
907   // Compute the scale factor
908   double sf = vtkMath::Norm(v) / sqrt(vtkMath::Distance2BetweenPoints(pt1, pt2));
909   if (Y > this->Interactor->GetLastEventPosition()[1])
910   {
911     sf = 1.0 + sf;
912   }
913   else
914   {
915     sf = 1.0 - sf;
916   }
917 
918   // Move the end points
919   double point1[3], point2[3];
920   for (int i = 0; i < 3; i++)
921   {
922     point1[i] = sf * (pt1[i] - center[i]) + center[i];
923     point2[i] = sf * (pt2[i] - center[i]) + center[i];
924   }
925 
926   this->LineSource->SetPoint1(point1);
927   this->LineSource->SetPoint2(point2);
928   this->LineSource->Update();
929 
930   this->BuildRepresentation();
931 }
932 
933 //------------------------------------------------------------------------------
CreateDefaultProperties()934 void vtkLineWidget::CreateDefaultProperties()
935 {
936   // Handle properties
937   this->HandleProperty = vtkProperty::New();
938   this->HandleProperty->SetColor(1, 1, 1);
939 
940   this->SelectedHandleProperty = vtkProperty::New();
941   this->SelectedHandleProperty->SetColor(1, 0, 0);
942 
943   // Line properties
944   this->LineProperty = vtkProperty::New();
945   this->LineProperty->SetRepresentationToWireframe();
946   this->LineProperty->SetAmbient(1.0);
947   this->LineProperty->SetAmbientColor(1.0, 1.0, 1.0);
948   this->LineProperty->SetLineWidth(2.0);
949 
950   this->SelectedLineProperty = vtkProperty::New();
951   this->SelectedLineProperty->SetRepresentationToWireframe();
952   this->SelectedLineProperty->SetAmbient(1.0);
953   this->SelectedLineProperty->SetAmbientColor(0.0, 1.0, 0.0);
954   this->SelectedLineProperty->SetLineWidth(2.0);
955 }
956 
957 //------------------------------------------------------------------------------
PlaceWidget(double bds[6])958 void vtkLineWidget::PlaceWidget(double bds[6])
959 {
960   int i;
961   double bounds[6], center[3];
962 
963   this->AdjustBounds(bds, bounds, center);
964 
965   if (this->Align == vtkLineWidget::YAxis)
966   {
967     this->LineSource->SetPoint1(center[0], bounds[2], center[2]);
968     this->LineSource->SetPoint2(center[0], bounds[3], center[2]);
969   }
970   else if (this->Align == vtkLineWidget::ZAxis)
971   {
972     this->LineSource->SetPoint1(center[0], center[1], bounds[4]);
973     this->LineSource->SetPoint2(center[0], center[1], bounds[5]);
974   }
975   else if (this->Align == vtkLineWidget::XAxis) // default or x-aligned
976   {
977     this->LineSource->SetPoint1(bounds[0], center[1], center[2]);
978     this->LineSource->SetPoint2(bounds[1], center[1], center[2]);
979   }
980   this->LineSource->Update();
981 
982   for (i = 0; i < 6; i++)
983   {
984     this->InitialBounds[i] = bounds[i];
985   }
986   this->InitialLength = sqrt((bounds[1] - bounds[0]) * (bounds[1] - bounds[0]) +
987     (bounds[3] - bounds[2]) * (bounds[3] - bounds[2]) +
988     (bounds[5] - bounds[4]) * (bounds[5] - bounds[4]));
989 
990   // Position the handles at the end of the lines
991   this->BuildRepresentation();
992   this->SizeHandles();
993 }
994 
995 //------------------------------------------------------------------------------
SetPoint1(double x,double y,double z)996 void vtkLineWidget::SetPoint1(double x, double y, double z)
997 {
998   double xyz[3];
999   xyz[0] = x;
1000   xyz[1] = y;
1001   xyz[2] = z;
1002 
1003   if (this->ClampToBounds)
1004   {
1005     this->ClampPosition(xyz);
1006     this->PointWidget1->SetPosition(xyz);
1007   }
1008   this->LineSource->SetPoint1(xyz);
1009   this->BuildRepresentation();
1010 }
1011 
1012 //------------------------------------------------------------------------------
SetPoint2(double x,double y,double z)1013 void vtkLineWidget::SetPoint2(double x, double y, double z)
1014 {
1015   double xyz[3];
1016   xyz[0] = x;
1017   xyz[1] = y;
1018   xyz[2] = z;
1019 
1020   if (this->ClampToBounds)
1021   {
1022     this->ClampPosition(xyz);
1023     this->PointWidget2->SetPosition(xyz);
1024   }
1025   this->LineSource->SetPoint2(xyz);
1026   this->BuildRepresentation();
1027 }
1028 
1029 //------------------------------------------------------------------------------
SetLinePosition(double x[3])1030 void vtkLineWidget::SetLinePosition(double x[3])
1031 {
1032   double p1[3], p2[3], v[3];
1033 
1034   // vector of motion
1035   v[0] = x[0] - this->LastPosition[0];
1036   v[1] = x[1] - this->LastPosition[1];
1037   v[2] = x[2] - this->LastPosition[2];
1038 
1039   // update position
1040   this->GetPoint1(p1);
1041   this->GetPoint2(p2);
1042   for (int i = 0; i < 3; i++)
1043   {
1044     p1[i] += v[i];
1045     p2[i] += v[i];
1046   }
1047 
1048   // See whether we can move
1049   if (this->ClampToBounds && (!this->InBounds(p1) || !this->InBounds(p2)))
1050   {
1051     this->PointWidget->SetPosition(this->LastPosition);
1052     return;
1053   }
1054 
1055   this->SetPoint1(p1);
1056   this->SetPoint2(p2);
1057 
1058   // remember last position
1059   this->LastPosition[0] = x[0];
1060   this->LastPosition[1] = x[1];
1061   this->LastPosition[2] = x[2];
1062 }
1063 
1064 //------------------------------------------------------------------------------
ClampPosition(double x[3])1065 void vtkLineWidget::ClampPosition(double x[3])
1066 {
1067   for (int i = 0; i < 3; i++)
1068   {
1069     if (x[i] < this->InitialBounds[2 * i])
1070     {
1071       x[i] = this->InitialBounds[2 * i];
1072     }
1073     if (x[i] > this->InitialBounds[2 * i + 1])
1074     {
1075       x[i] = this->InitialBounds[2 * i + 1];
1076     }
1077   }
1078 }
1079 
1080 //------------------------------------------------------------------------------
InBounds(double x[3])1081 int vtkLineWidget::InBounds(double x[3])
1082 {
1083   for (int i = 0; i < 3; i++)
1084   {
1085     if (x[i] < this->InitialBounds[2 * i] || x[i] > this->InitialBounds[2 * i + 1])
1086     {
1087       return 0;
1088     }
1089   }
1090   return 1;
1091 }
1092 
1093 //------------------------------------------------------------------------------
GetPolyData(vtkPolyData * pd)1094 void vtkLineWidget::GetPolyData(vtkPolyData* pd)
1095 {
1096   pd->ShallowCopy(this->LineSource->GetOutput());
1097 }
1098