1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkScenePicker.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 "vtkScenePicker.h"
16 
17 #include "vtkCommand.h"
18 #include "vtkDataObject.h"
19 #include "vtkHardwareSelector.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkProp.h"
22 #include "vtkRenderWindow.h"
23 #include "vtkRenderWindowInteractor.h"
24 #include "vtkRenderer.h"
25 
26 class vtkScenePickerSelectionRenderCommand : public vtkCommand
27 {
28 public:
29   vtkScenePicker* m_Picker;
New()30   static vtkScenePickerSelectionRenderCommand* New()
31   {
32     return new vtkScenePickerSelectionRenderCommand;
33   }
34 
Execute(vtkObject * vtkNotUsed (o),unsigned long event,void *)35   void Execute(vtkObject* vtkNotUsed(o), unsigned long event, void*) override
36   {
37     if (event == vtkCommand::StartInteractionEvent)
38     {
39       this->InteractiveRender = true;
40     }
41     else if (event == vtkCommand::EndInteractionEvent)
42     {
43       this->InteractiveRender = false;
44     }
45     else if (event == vtkCommand::EndEvent)
46     {
47       if (!this->InteractiveRender)
48       {
49         m_Picker->PickRender();
50       }
51       this->m_Picker->SetRenderer(this->m_Picker->Renderer);
52     }
53   }
54 
55 protected:
vtkScenePickerSelectionRenderCommand()56   vtkScenePickerSelectionRenderCommand()
57     : InteractiveRender(false)
58   {
59   }
60   ~vtkScenePickerSelectionRenderCommand() override = default;
61   bool InteractiveRender;
62 };
63 
64 vtkStandardNewMacro(vtkScenePicker);
65 
66 //------------------------------------------------------------------------------
vtkScenePicker()67 vtkScenePicker::vtkScenePicker()
68 {
69   this->EnableVertexPicking = 1;
70   this->Renderer = nullptr;
71   this->Interactor = nullptr;
72   this->Selector = vtkHardwareSelector::New();
73   this->NeedToUpdate = false;
74   this->VertId = -1;
75   this->CellId = -1;
76   this->Prop = nullptr;
77   this->SelectionRenderCommand = vtkScenePickerSelectionRenderCommand::New();
78   this->SelectionRenderCommand->m_Picker = this;
79 }
80 
81 //------------------------------------------------------------------------------
~vtkScenePicker()82 vtkScenePicker::~vtkScenePicker()
83 {
84   this->SetRenderer(nullptr);
85   this->Selector->Delete();
86   this->SelectionRenderCommand->Delete();
87 }
88 
89 //------------------------------------------------------------------------------
SetRenderer(vtkRenderer * r)90 void vtkScenePicker::SetRenderer(vtkRenderer* r)
91 {
92   vtkRenderWindowInteractor* rwi = nullptr;
93   if (r && r->GetRenderWindow())
94   {
95     rwi = r->GetRenderWindow()->GetInteractor();
96   }
97   this->SetInteractor(rwi);
98 
99   if (this->Renderer == r)
100   {
101     return;
102   }
103   if (r && !r->GetRenderWindow())
104   {
105     vtkErrorMacro(<< "Renderer: " << this->Renderer << " does not have its render window set.");
106     return;
107   }
108 
109   if (this->Renderer)
110   {
111     this->Renderer->GetRenderWindow()->RemoveObserver(this->SelectionRenderCommand);
112   }
113 
114   vtkSetObjectBodyMacro(Renderer, vtkRenderer, r);
115 
116   if (this->Renderer)
117   {
118     this->Renderer->GetRenderWindow()->AddObserver(
119       vtkCommand::EndEvent, this->SelectionRenderCommand, 0.01);
120   }
121 
122   this->Selector->SetRenderer(this->Renderer);
123 }
124 
125 //------------------------------------------------------------------------------
SetInteractor(vtkRenderWindowInteractor * rwi)126 void vtkScenePicker::SetInteractor(vtkRenderWindowInteractor* rwi)
127 {
128   if (this->Interactor == rwi)
129   {
130     return;
131   }
132   if (this->Interactor)
133   {
134     this->Interactor->RemoveObserver(this->SelectionRenderCommand);
135   }
136 
137   vtkSetObjectBodyMacro(Interactor, vtkRenderWindowInteractor, rwi);
138 
139   if (this->Interactor)
140   {
141     this->Interactor->AddObserver(
142       vtkCommand::StartInteractionEvent, this->SelectionRenderCommand, 0.01);
143     this->Interactor->AddObserver(
144       vtkCommand::EndInteractionEvent, this->SelectionRenderCommand, 0.01);
145   }
146 }
147 
148 //------------------------------------------------------------------------------
149 // Do a selection render.. for caching object selection stuff.
150 // This is used for Object selection . We have to perform
151 // "select" and "mouse over" and "mouse out" as the mouse moves around the
152 // scene (or the mouse is clicked in the case of "select"). I do not want
153 // to do a conventional pick for this function because it's too darn slow.
154 // The Selector will be used here to pick-render the entire
155 // screen, store on a buffer the colored cells and read back as
156 // the mouse moves around the moused pick. This extra render from the
157 // Selector will be done only if the camera isn't in motion,
158 // otherwise motion would be too frickin slow.
159 //
PickRender()160 void vtkScenePicker::PickRender()
161 {
162   if (!this->Renderer || !this->Renderer->GetRenderWindow())
163   {
164     return;
165   }
166 
167   double vp[4];
168   this->Renderer->GetViewport(vp);
169   int size[2] = { this->Renderer->GetRenderWindow()->GetSize()[0],
170     this->Renderer->GetRenderWindow()->GetSize()[1] };
171 
172   int rx1 = static_cast<int>(vp[0] * (size[0] - 1));
173   int ry1 = static_cast<int>(vp[1] * (size[1] - 1));
174   int rx2 = static_cast<int>(vp[2] * (size[0] - 1));
175   int ry2 = static_cast<int>(vp[3] * (size[1] - 1));
176 
177   this->PickRender(rx1, ry1, rx2, ry2);
178 }
179 
180 //------------------------------------------------------------------------------
181 // Do a selection render.. for caching object selection stuff.
PickRender(int x0,int y0,int x1,int y1)182 void vtkScenePicker::PickRender(int x0, int y0, int x1, int y1)
183 {
184   this->Renderer->GetRenderWindow()->RemoveObserver(this->SelectionRenderCommand);
185 
186   if (this->EnableVertexPicking)
187   {
188     this->Selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_POINTS);
189   }
190   else
191   {
192     this->Selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS);
193   }
194   cout << "Area: " << x0 << ", " << y0 << ", " << x1 << ", " << y1 << endl;
195   this->Selector->SetArea(x0, y0, x1, y1);
196   if (!this->Selector->CaptureBuffers())
197   {
198     vtkErrorMacro("Failed to capture buffers.");
199   }
200   this->NeedToUpdate = true;
201   this->PickRenderTime.Modified();
202   this->Renderer->GetRenderWindow()->AddObserver(
203     vtkCommand::EndEvent, this->SelectionRenderCommand, 0.01);
204 }
205 
206 //------------------------------------------------------------------------------
GetCellId(int displayPos[2])207 vtkIdType vtkScenePicker::GetCellId(int displayPos[2])
208 {
209   if (this->EnableVertexPicking)
210   {
211     return -1;
212   }
213   this->Update(displayPos);
214   return this->CellId;
215 }
216 
217 //------------------------------------------------------------------------------
GetViewProp(int displayPos[2])218 vtkProp* vtkScenePicker::GetViewProp(int displayPos[2])
219 {
220   this->Update(displayPos);
221   return this->Prop;
222 }
223 
224 //------------------------------------------------------------------------------
GetVertexId(int displayPos[2])225 vtkIdType vtkScenePicker::GetVertexId(int displayPos[2])
226 {
227   if (!this->EnableVertexPicking)
228   {
229     return -1;
230   }
231   this->Update(displayPos);
232   return this->CellId;
233 }
234 
235 //------------------------------------------------------------------------------
Update(int displayPos[2])236 void vtkScenePicker::Update(int displayPos[2])
237 {
238   if (this->PickRenderTime <= this->GetMTime())
239   {
240     this->PickRender();
241   }
242 
243   if (this->NeedToUpdate || this->LastQueriedDisplayPos[0] != displayPos[0] ||
244     this->LastQueriedDisplayPos[1] != displayPos[1])
245   {
246     this->Prop = nullptr;
247     unsigned int dpos[2] = { 0, 0 };
248     if (displayPos[0] >= 0 && displayPos[1] >= 0)
249     {
250       dpos[0] = static_cast<unsigned int>(displayPos[0]);
251       dpos[1] = static_cast<unsigned int>(displayPos[1]);
252       vtkHardwareSelector::PixelInformation info = this->Selector->GetPixelInformation(dpos);
253       this->CellId = info.AttributeID;
254       this->Prop = info.Prop;
255     }
256     this->LastQueriedDisplayPos[0] = displayPos[0];
257     this->LastQueriedDisplayPos[1] = displayPos[1];
258     this->NeedToUpdate = false;
259   }
260 }
261 
262 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)263 void vtkScenePicker::PrintSelf(ostream& os, vtkIndent indent)
264 {
265   this->Superclass::PrintSelf(os, indent);
266   os << indent << "Renderer: " << this->Renderer << endl;
267   os << indent << "EnableVertexPicking: " << this->EnableVertexPicking << endl;
268 }
269