1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestPickingManagerWidgets.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 
16 /*==============================================================================
17 
18   Library: MSVTK
19 
20   Copyright (c) Kitware Inc.
21 
22   Licensed under the Apache License, Version 2.0 (the "License");
23   you may not use this file except in compliance with the License.
24   You may obtain a copy of the License at
25 
26       http://www.apache.org/licenses/LICENSE-2.0.txt
27 
28   Unless required by applicable law or agreed to in writing, software
29   distributed under the License is distributed on an "AS IS" BASIS,
30   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31   See the License for the specific language governing permissions and
32   limitations under the License.
33 
34 ==============================================================================*/
35 
36 //
37 // This example tests the PickingManager using different widgets and associated
38 // pickers:
39 // * vtkBalloonWidget
40 // * vtkBoxWidget
41 // * vtkImplicitPlaneWidget2
42 // By default the Picking Manager is enabled.
43 // Press 'Ctrl' to switch the activation of the Picking Manager.
44 // Press 'o' to enable/disable the Optimization on render events.
45 
46 #include "vtkActor.h"
47 #include "vtkAppendPolyData.h"
48 #include "vtkBalloonRepresentation.h"
49 #include "vtkBalloonWidget.h"
50 #include "vtkBoxWidget.h"
51 #include "vtkCamera.h"
52 #include "vtkClipPolyData.h"
53 #include "vtkCommand.h"
54 #include "vtkConeSource.h"
55 #include "vtkCylinderSource.h"
56 #include "vtkGlyph3D.h"
57 #include "vtkImplicitPlaneRepresentation.h"
58 #include "vtkImplicitPlaneWidget2.h"
59 #include "vtkInteractorStyleTrackballCamera.h"
60 #include "vtkLODActor.h"
61 #include "vtkNew.h"
62 #include "vtkPickingManager.h"
63 #include "vtkPlane.h"
64 #include "vtkPolyData.h"
65 #include "vtkPolyDataMapper.h"
66 #include "vtkPropPicker.h"
67 #include "vtkProperty.h"
68 #include "vtkRenderWindow.h"
69 #include "vtkRenderWindowInteractor.h"
70 #include "vtkRenderer.h"
71 #include "vtkSmartPointer.h"
72 #include "vtkSphereSource.h"
73 
74 //------------------------------------------------------------------------------
75 class vtkBalloonPickCallback : public vtkCommand
76 {
77 public:
New()78   static vtkBalloonPickCallback* New() { return new vtkBalloonPickCallback; }
Execute(vtkObject * caller,unsigned long,void *)79   void Execute(vtkObject* caller, unsigned long, void*) override
80   {
81     vtkPropPicker* picker = reinterpret_cast<vtkPropPicker*>(caller);
82     vtkProp* prop = picker->GetViewProp();
83     if (prop != nullptr)
84     {
85       this->BalloonWidget->UpdateBalloonString(prop, "Picked");
86     }
87   }
88 
89   vtkBalloonWidget* BalloonWidget;
90 };
91 
92 //------------------------------------------------------------------------------
93 // Updates the vtkPlane implicit function.
94 // This in turn causes the pipeline to update and clip the object.
95 // Callback for the interaction
96 class vtkTIPW2Callback : public vtkCommand
97 {
98 public:
New()99   static vtkTIPW2Callback* New() { return new vtkTIPW2Callback; }
Execute(vtkObject * caller,unsigned long,void *)100   void Execute(vtkObject* caller, unsigned long, void*) override
101   {
102     vtkImplicitPlaneWidget2* planeWidget = reinterpret_cast<vtkImplicitPlaneWidget2*>(caller);
103     vtkImplicitPlaneRepresentation* rep =
104       reinterpret_cast<vtkImplicitPlaneRepresentation*>(planeWidget->GetRepresentation());
105     rep->GetPlane(this->Plane);
106     this->Actor->VisibilityOn();
107   }
108 
vtkTIPW2Callback()109   vtkTIPW2Callback()
110     : Plane(nullptr)
111     , Actor(nullptr)
112   {
113   }
114   vtkPlane* Plane;
115   vtkActor* Actor;
116 };
117 
118 //------------------------------------------------------------------------------
119 // Press 'Ctrl' to switch the activation of the Picking Manager.
120 // Press 'o' to switch the activation of the optimization based on the render
121 // events.
122 class vtkEnableManagerCallback : public vtkCommand
123 {
124 public:
New()125   static vtkEnableManagerCallback* New() { return new vtkEnableManagerCallback; }
126 
Execute(vtkObject * caller,unsigned long,void *)127   void Execute(vtkObject* caller, unsigned long, void*) override
128   {
129     vtkRenderWindowInteractor* iren = static_cast<vtkRenderWindowInteractor*>(caller);
130 
131     if ((vtkStdString(iren->GetKeySym()) == "Control_L" ||
132           vtkStdString(iren->GetKeySym()) == "Control_R") &&
133       iren->GetPickingManager())
134     {
135       if (!iren->GetPickingManager()->GetEnabled())
136       {
137         std::cout << "PickingManager ON !" << std::endl;
138         iren->GetPickingManager()->EnabledOn();
139       }
140       else
141       {
142         std::cout << "PickingManager OFF !" << std::endl;
143         iren->GetPickingManager()->EnabledOff();
144       }
145     }
146     // Enable/Disable the Optimization on render events.
147     else if (vtkStdString(iren->GetKeySym()) == "o" && iren->GetPickingManager())
148     {
149       if (!iren->GetPickingManager()->GetOptimizeOnInteractorEvents())
150       {
151         std::cout << "Optimization on Interactor events ON !" << std::endl;
152         iren->GetPickingManager()->SetOptimizeOnInteractorEvents(true);
153       }
154       else
155       {
156         std::cout << "Optimization on Interactor events OFF !" << std::endl;
157         iren->GetPickingManager()->SetOptimizeOnInteractorEvents(false);
158       }
159     }
160   }
161 
162   vtkEnableManagerCallback() = default;
163 };
164 
165 //------------------------------------------------------------------------------
166 // Test Picking Manager with a several widgets
167 //------------------------------------------------------------------------------
TestPickingManagerWidgets(int vtkNotUsed (argc),char * vtkNotUsed (argv)[])168 int TestPickingManagerWidgets(int vtkNotUsed(argc), char* vtkNotUsed(argv)[])
169 {
170   // Create the RenderWindow, Renderer and both Actors
171   //
172   vtkNew<vtkRenderer> ren1;
173   vtkNew<vtkRenderWindow> renWin;
174   renWin->AddRenderer(ren1);
175 
176   vtkNew<vtkRenderWindowInteractor> iren;
177   vtkNew<vtkInteractorStyleTrackballCamera> irenStyle;
178   iren->SetRenderWindow(renWin);
179   iren->SetInteractorStyle(irenStyle);
180 
181   // Instantiate a picker and link it to the ballonWidgetCallback
182   vtkNew<vtkPropPicker> picker;
183   vtkNew<vtkBalloonPickCallback> pcbk;
184   picker->AddObserver(vtkCommand::PickEvent, pcbk);
185   iren->SetPicker(picker);
186 
187   /*--------------------------------------------------------------------------*/
188   // PICKING MANAGER
189   /*--------------------------------------------------------------------------*/
190   // Callback to switch between the managed and non-managed mode of the
191   // Picking Manager
192   vtkNew<vtkEnableManagerCallback> callMode;
193   iren->AddObserver(vtkCommand::KeyPressEvent, callMode);
194 
195   /*--------------------------------------------------------------------------*/
196   // BALLOON WIDGET
197   /*--------------------------------------------------------------------------*/
198   // Create a test pipeline
199   vtkNew<vtkSphereSource> ss;
200   vtkNew<vtkPolyDataMapper> mapper;
201   mapper->SetInputConnection(ss->GetOutputPort());
202   vtkNew<vtkActor> sph;
203   sph->SetMapper(mapper);
204 
205   vtkNew<vtkCylinderSource> cs;
206   vtkNew<vtkPolyDataMapper> csMapper;
207   csMapper->SetInputConnection(cs->GetOutputPort());
208   vtkNew<vtkActor> cyl;
209   cyl->SetMapper(csMapper);
210   cyl->AddPosition(5, 0, 0);
211 
212   vtkNew<vtkConeSource> coneSource;
213   vtkNew<vtkPolyDataMapper> coneMapper;
214   coneMapper->SetInputConnection(coneSource->GetOutputPort());
215   vtkNew<vtkActor> cone;
216   cone->SetMapper(coneMapper);
217   cone->AddPosition(0, 5, 0);
218 
219   // Create the widget
220   vtkNew<vtkBalloonRepresentation> rep;
221   rep->SetBalloonLayoutToImageRight();
222 
223   vtkNew<vtkBalloonWidget> widget;
224   widget->SetInteractor(iren);
225   widget->SetRepresentation(rep);
226   widget->AddBalloon(sph, "This is a sphere", nullptr);
227   widget->AddBalloon(cyl, "This is a\ncylinder", nullptr);
228   widget->AddBalloon(cone, "This is a\ncone,\na really big.", nullptr);
229   pcbk->BalloonWidget = widget;
230 
231   /*--------------------------------------------------------------------------*/
232   // BOX WIDGET
233   /*--------------------------------------------------------------------------*/
234   vtkNew<vtkBoxWidget> boxWidget;
235   boxWidget->SetInteractor(iren);
236   boxWidget->SetPlaceFactor(1.25);
237 
238   // Create the mass actor
239   vtkNew<vtkConeSource> cone1;
240   cone1->SetResolution(6);
241   vtkNew<vtkSphereSource> sphere;
242   sphere->SetThetaResolution(8);
243   sphere->SetPhiResolution(8);
244   sphere->SetCenter(5, 5, 0);
245   vtkNew<vtkGlyph3D> glyph;
246   glyph->SetInputConnection(sphere->GetOutputPort());
247   glyph->SetSourceData(cone1->GetOutput());
248   glyph->SetVectorModeToUseNormal();
249   glyph->SetScaleModeToScaleByVector();
250   glyph->SetScaleFactor(0.25);
251 
252   vtkNew<vtkAppendPolyData> append;
253   append->AddInputData(glyph->GetOutput());
254   append->AddInputData(sphere->GetOutput());
255 
256   vtkNew<vtkPolyDataMapper> maceMapper;
257   maceMapper->SetInputConnection(append->GetOutputPort());
258 
259   vtkNew<vtkActor> maceActor;
260   maceActor->SetMapper(maceMapper);
261 
262   /*--------------------------------------------------------------------------*/
263   // Multiple ImplicitPlane Widgets
264   /*--------------------------------------------------------------------------*/
265   // Create a mace out of filters.
266   //
267   vtkNew<vtkSphereSource> sphereImpPlane;
268   vtkNew<vtkConeSource> coneImpPlane;
269   vtkNew<vtkGlyph3D> glyphImpPlane;
270   glyphImpPlane->SetInputConnection(sphereImpPlane->GetOutputPort());
271   glyphImpPlane->SetSourceConnection(coneImpPlane->GetOutputPort());
272   glyphImpPlane->SetVectorModeToUseNormal();
273   glyphImpPlane->SetScaleModeToScaleByVector();
274   glyphImpPlane->SetScaleFactor(0.25);
275   glyphImpPlane->Update();
276 
277   // The sphere and spikes are appended into a single polydata.
278   // This just makes things simpler to manage.
279   vtkNew<vtkAppendPolyData> apdImpPlane;
280   apdImpPlane->AddInputData(glyphImpPlane->GetOutput());
281   apdImpPlane->AddInputData(sphereImpPlane->GetOutput());
282 
283   vtkNew<vtkPolyDataMapper> maceMapperImpPlane;
284   maceMapperImpPlane->SetInputConnection(apdImpPlane->GetOutputPort());
285 
286   vtkNew<vtkActor> maceActorImpPlane;
287   maceActorImpPlane->SetMapper(maceMapperImpPlane);
288   maceActorImpPlane->AddPosition(0, 0, 0);
289   maceActorImpPlane->VisibilityOn();
290 
291   // This portion of the code clips the mace with the vtkPlanes
292   // implicit function. The clipped region is colored green.
293   vtkNew<vtkPlane> plane;
294   vtkNew<vtkClipPolyData> clipper;
295   clipper->SetInputConnection(apdImpPlane->GetOutputPort());
296   clipper->SetClipFunction(plane);
297   clipper->InsideOutOn();
298 
299   vtkNew<vtkPolyDataMapper> selectMapper;
300   selectMapper->SetInputConnection(clipper->GetOutputPort());
301 
302   vtkNew<vtkActor> selectActor;
303   selectActor->SetMapper(selectMapper);
304   selectActor->GetProperty()->SetColor(0, 1, 0);
305   selectActor->VisibilityOff();
306   selectActor->AddPosition(0, 0, 0);
307   selectActor->SetScale(1.01, 1.01, 1.01);
308 
309   // The SetInteractor method is how 3D widgets are associated with the render
310   // window interactor. Internally, SetInteractor sets up a bunch of callbacks
311   // using the Command/Observer mechanism (AddObserver()).
312   vtkNew<vtkTIPW2Callback> impPlaneCallback;
313   impPlaneCallback->Plane = plane;
314   impPlaneCallback->Actor = selectActor;
315 
316   // First ImplicitPlaneWidget (Green)
317   vtkNew<vtkImplicitPlaneRepresentation> impPlaneRep;
318   impPlaneRep->SetPlaceFactor(1.);
319   impPlaneRep->SetOutlineTranslation(0);
320   impPlaneRep->SetScaleEnabled(0);
321   impPlaneRep->PlaceWidget(glyphImpPlane->GetOutput()->GetBounds());
322   impPlaneRep->SetEdgeColor(0., 1., 0.);
323   impPlaneRep->SetNormal(1, 0, 1);
324 
325   vtkNew<vtkImplicitPlaneWidget2> planeWidget;
326   planeWidget->SetInteractor(iren);
327   planeWidget->SetRepresentation(impPlaneRep);
328   planeWidget->On();
329 
330   planeWidget->AddObserver(vtkCommand::InteractionEvent, impPlaneCallback);
331   planeWidget->AddObserver(vtkCommand::UpdateEvent, impPlaneCallback);
332 
333   // Second ImplicitPlaneWidget (Red)
334   vtkNew<vtkImplicitPlaneRepresentation> impPlaneRep2;
335   impPlaneRep2->SetOutlineTranslation(0);
336   impPlaneRep2->SetScaleEnabled(0);
337   impPlaneRep2->SetPlaceFactor(1.);
338   impPlaneRep2->PlaceWidget(glyphImpPlane->GetOutput()->GetBounds());
339   impPlaneRep2->SetEdgeColor(1., 0., 0.);
340 
341   vtkNew<vtkImplicitPlaneWidget2> planeWidget2;
342   planeWidget2->SetInteractor(iren);
343   planeWidget2->SetRepresentation(impPlaneRep2);
344   planeWidget2->On();
345 
346   /*--------------------------------------------------------------------------*/
347   // Rendering
348   /*--------------------------------------------------------------------------*/
349   // Add the actors to the renderer, set the background and size
350   ren1->AddActor(sph);
351   ren1->AddActor(cyl);
352   ren1->AddActor(cone);
353   ren1->AddActor(maceActorImpPlane);
354   ren1->AddActor(selectActor);
355   ren1->AddActor(maceActor);
356   ren1->SetBackground(0.1, 0.2, 0.4);
357   renWin->SetSize(600, 600);
358 
359   // Configure the box widget
360   boxWidget->SetProp3D(maceActor);
361   boxWidget->PlaceWidget();
362 
363   // render the image
364   iren->Initialize();
365   double extent[6] = { -2, 7, -2, 7, -1, 1 };
366   ren1->ResetCamera(extent);
367   renWin->Render();
368   widget->On();
369   boxWidget->On();
370   iren->Start();
371 
372   return EXIT_SUCCESS;
373 }
374