0030520: VIS - IVtkTools_ShapePicker::GetPickPosition() returns incorrect point
[occt.git] / src / IVtkTools / IVtkTools_ShapePicker.cxx
1 // Created on: 2011-10-27 
2 // Created by: Roman KOZLOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS 
4 // 
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <IVtkTools_ShapePicker.hxx>
17 #include <IVtkTools_ShapeObject.hxx>
18 #include <IVtkVTK_View.hxx>
19
20 // prevent disabling some MSVC warning messages by VTK headers 
21 #ifdef _MSC_VER
22 #pragma warning(push)
23 #endif
24 #include <vtkCommand.h>
25 #include <vtkObjectFactory.h>
26 #include <vtkRenderer.h>
27 #include <vtkActorCollection.h>
28 #ifdef _MSC_VER
29 #pragma warning(pop)
30 #endif
31
32 //! @class IVtkTools_ShapePicker
33 //! VTK picker implementation for OCCT shapes.
34 //! Can pick either whole shapes or sub-shapes.
35 //! The kind of selectable entities is defined by the current selection mode.
36 //! NOTE: For performance reasons, setRenderer() method should be called in advance,
37 //! before the user starts to select interactively, in order for the OCCT selection
38 //! algorithm to prepare its internal selection data.
39
40 vtkStandardNewMacro(IVtkTools_ShapePicker)
41
42 //============================================================================
43 //  Method: IVtkTools_ShapePicker
44 // Purpose: Constructs the picker with empty renderer and ready for point selection.
45 //============================================================================
46 IVtkTools_ShapePicker::IVtkTools_ShapePicker()
47 : myRenderer (NULL),
48   myIsRectSelection (false)
49 {
50   myOccPickerAlgo = new IVtkOCC_ShapePickerAlgo();
51 }
52
53 //============================================================================
54 //  Method: ~IVtkTools_ShapePicker
55 // Purpose: Destructor
56 //============================================================================
57 IVtkTools_ShapePicker::~IVtkTools_ShapePicker()
58 {
59 }
60
61 //============================================================================
62 //  Method: SetTolerance
63 // Purpose: Setter for tolerance of picking.
64 //============================================================================
65 void IVtkTools_ShapePicker::SetTolerance (float theTolerance )
66 {
67   myTolerance = theTolerance;
68 }
69
70 //============================================================================
71 //  Method: GetTolerance
72 // Purpose: Getter for tolerance of picking.
73 //============================================================================
74 float IVtkTools_ShapePicker::GetTolerance( ) const
75 {
76   return myTolerance;
77 }
78
79 //============================================================================
80 //  Method: convertDisplayToWorld
81 // Purpose: Convert display coordinates to world coordinates
82 //============================================================================
83 bool IVtkTools_ShapePicker::convertDisplayToWorld (vtkRenderer *theRenderer,
84                                                    double theDisplayCoord[3],
85                                                    double theWorldCoord[3])
86 {
87   // Convert the selection point into world coordinates.
88   theRenderer->SetDisplayPoint (theDisplayCoord[0], theDisplayCoord[1], theDisplayCoord[2]);
89   theRenderer->DisplayToWorld();
90
91   double aCoords[4];
92   theRenderer->GetWorldPoint(aCoords);
93   if (aCoords[3] == 0.0)
94   {
95     return false;
96   }
97
98   for (Standard_Integer anI = 0; anI < 3; anI++)
99   {
100     theWorldCoord[anI] = aCoords[anI] / aCoords[3];
101   }
102   
103   return true;
104 }
105
106 //============================================================================
107 // Method:  Pick
108 // Purpose: Pick entities in the given point.
109 //============================================================================
110 int IVtkTools_ShapePicker::Pick (double theX, double theY, double /*theZ*/, vtkRenderer *theRenderer)
111 {
112   double aPos[2] = {theX, theY};
113   myIsRectSelection = false;
114   myIsPolySelection = false;
115   return pick (aPos, theRenderer);
116 }
117
118 //============================================================================
119 //  Method: pick
120 // Purpose: Pick entities in the given rectangle area.
121 //============================================================================
122 int IVtkTools_ShapePicker::Pick (double theXPMin, double theYPMin, double theXPMax, double theYPMax,
123                                  vtkRenderer *theRenderer)
124 {
125   double aPos[4] = {theXPMin, theYPMin, theXPMax, theYPMax};
126   myIsRectSelection = true;
127   myIsPolySelection = false;
128   return pick (aPos, theRenderer);
129 }
130 //============================================================================
131 //  Method: pick
132 // Purpose: Pick entities in the given polygonal area.
133 //============================================================================
134 int IVtkTools_ShapePicker::Pick (double thePoly[][3], const int theNbPoints,
135                                  vtkRenderer *theRenderer)
136 {
137   myIsRectSelection = false;
138   myIsPolySelection = true;
139   return pick ((double*)thePoly, theRenderer, theNbPoints);
140 }
141
142 //============================================================================
143 //  Method: pick
144 // Purpose: Pick entities in the given point or area.
145 //============================================================================
146 int IVtkTools_ShapePicker::pick (double* thePos,
147                                  vtkRenderer *theRenderer,
148                                  const int theNbPoints)
149 {
150  //  Initialize picking process
151   Initialize();
152
153   // Emit StartPickEvent for observer callbacks (if any)
154   InvokeEvent(vtkCommand::StartPickEvent, NULL);
155
156   vtkSmartPointer<vtkRenderer> aRenderer;
157   if (theRenderer == NULL)
158   {
159     aRenderer = myRenderer; // by default use own renderer
160   }
161   else
162   {
163     aRenderer = theRenderer;
164   }
165   doPickImpl (thePos, aRenderer, theNbPoints);
166
167   // Emit EndPickEvent for observer callbacks (if any)
168   InvokeEvent(vtkCommand::EndPickEvent, NULL);
169
170   return myOccPickerAlgo->NbPicked();
171 }
172
173 //============================================================================
174 //  Method: doPickImpl
175 // Purpose: Implementation of picking algorithm.
176 //============================================================================
177 void IVtkTools_ShapePicker::doPickImpl (double* thePos,
178                                         vtkRenderer* theRenderer, 
179                                         const int theNbPoints)
180 {
181   // Make sure the correct renderer is used
182   SetRenderer (theRenderer);
183
184   if (myIsPolySelection)
185   {
186     myOccPickerAlgo->Pick ((double**)thePos, theNbPoints);
187   }
188   else if (myIsRectSelection)
189   {
190     myOccPickerAlgo->Pick (thePos[0], thePos[1], thePos[2], thePos[3]);
191   }
192   else
193   {
194     myOccPickerAlgo->Pick (thePos[0], thePos[1]);
195   }
196
197   PickPosition[0] = myOccPickerAlgo->TopPickedPoint().X();
198   PickPosition[1] = myOccPickerAlgo->TopPickedPoint().Y();
199   PickPosition[2] = myOccPickerAlgo->TopPickedPoint().Z();
200 }
201
202 //============================================================================
203 //  Method: SetRenderer
204 // Purpose: Sets the renderer to be used by OCCT selection algorithm
205 //============================================================================
206 void IVtkTools_ShapePicker::SetRenderer (vtkRenderer* theRenderer)
207 {
208   if (theRenderer == myRenderer.GetPointer())
209   {
210     return;
211     // In this case we should not do anything.
212     // In the worth case we need to update picker algorithm (view er selector and projection options)
213     // If any needs this , call myOccPickerAlgo->Modified();
214   }
215
216   myRenderer = theRenderer;
217   IVtkVTK_View::Handle aView = new IVtkVTK_View (myRenderer);
218   myOccPickerAlgo->SetView (aView);
219 }
220
221 //============================================================================
222 //  Method: SetAreaSelection
223 // Purpose: Sets area selection on/off
224 //============================================================================
225 void IVtkTools_ShapePicker::SetAreaSelection (bool theIsOn)
226 {
227   myIsRectSelection = theIsOn;
228 }
229
230 //============================================================================
231 //  Method: GetSelectionModes
232 // Purpose: Get activated selection modes for a shape.
233 //============================================================================
234 IVtk_SelectionModeList IVtkTools_ShapePicker::GetSelectionModes (
235                                               const IVtk_IShape::Handle& theShape) const
236 {
237   return myOccPickerAlgo->GetSelectionModes (theShape);
238 }
239
240 //============================================================================
241 //  Method: GetSelectionModes
242 // Purpose: Get activated selection modes for a shape actor.
243 //============================================================================
244 IVtk_SelectionModeList IVtkTools_ShapePicker::GetSelectionModes (
245                                               vtkActor* theShapeActor) const
246 {
247   IVtk_SelectionModeList aRes;
248   IVtk_IShape::Handle aShape = IVtkTools_ShapeObject::GetOccShape (theShapeActor);
249   if (!aShape.IsNull())
250   {
251     aRes = myOccPickerAlgo->GetSelectionModes (aShape);
252   }
253   return aRes;
254 }
255
256 //============================================================================
257 //  Method: SetSelectionMode
258 // Purpose: Turn on/off a selection mode for a shape.
259 //============================================================================
260 void IVtkTools_ShapePicker::SetSelectionMode (const IVtk_IShape::Handle& theShape,
261                                               const IVtk_SelectionMode   theMode,
262                                               const bool                 theIsTurnOn) const
263 {
264   myOccPickerAlgo->SetSelectionMode (theShape, theMode, theIsTurnOn);
265 }
266
267 //============================================================================
268 //  Method: SetSelectionMode
269 // Purpose: Turn on/off a selection mode for a shape actor.
270 //============================================================================
271 void IVtkTools_ShapePicker::SetSelectionMode (vtkActor*                theShapeActor,
272                                               const IVtk_SelectionMode theMode,
273                                               const bool               theIsTurnOn) const
274 {
275   IVtk_IShape::Handle aShape = IVtkTools_ShapeObject::GetOccShape (theShapeActor);
276   if (!aShape.IsNull())
277   {
278     myOccPickerAlgo->SetSelectionMode (aShape, theMode, theIsTurnOn);
279   }
280 }
281
282 //============================================================================
283 //  Method: SetSelectionMode
284 // Purpose: Sets the current selection mode for all visible shape objects.
285 //============================================================================
286 void IVtkTools_ShapePicker::SetSelectionMode (const IVtk_SelectionMode theMode, 
287                                               const bool               theIsTurnOn) const
288 {
289   if (myRenderer.GetPointer() != NULL)
290   {
291     // Obtain all OccShapes displayed and activate the specified selection mode
292     vtkSmartPointer<vtkActorCollection> anActors = myRenderer->GetActors();
293     anActors->InitTraversal();
294     vtkSmartPointer<vtkActor> anActor = anActors->GetNextActor();
295     while ( anActor.GetPointer() != NULL )
296     {
297       if (anActor->GetPickable() && anActor->GetVisibility())
298       {
299         if (anActor->GetMapper())
300         {
301           IVtk_IShape::Handle aShape = IVtkTools_ShapeObject::GetOccShape (anActor);
302           if (!aShape.IsNull())
303           {
304             myOccPickerAlgo->SetSelectionMode (aShape, theMode, theIsTurnOn);
305           }
306         }
307       }
308       anActor = anActors->GetNextActor();
309     }
310   }
311 }
312
313 //============================================================================
314 //  Method: GetPickedShapesIds
315 // Purpose: Access to the list of top-level shapes picked.
316 //============================================================================
317 IVtk_ShapeIdList IVtkTools_ShapePicker::GetPickedShapesIds (bool theIsAll) const
318 {
319   if (theIsAll || myIsRectSelection )
320   {
321     return myOccPickerAlgo->ShapesPicked();
322   }
323
324   IVtk_ShapeIdList aRes;
325   IVtk_ShapeIdList aPicked = myOccPickerAlgo->ShapesPicked();
326   if (!aPicked.IsEmpty())
327   {
328     aRes.Append (aPicked.First());
329   }
330   return aRes;
331 }
332
333 //============================================================================
334 //  Method: RemoveSelectableActor
335 // Purpose: Remove selectable object from the picker (from internal maps).
336 //============================================================================
337 void IVtkTools_ShapePicker::RemoveSelectableObject(const IVtk_IShape::Handle& theShape)
338 {
339   myOccPickerAlgo->RemoveSelectableObject(theShape);
340 }
341
342 //============================================================================
343 //  Method: RemoveSelectableActor
344 // Purpose: Remove selectable object from the picker (from internal maps).
345 //============================================================================
346 void IVtkTools_ShapePicker::RemoveSelectableActor(vtkActor* theShapeActor)
347 {
348   IVtk_IShape::Handle aShape = IVtkTools_ShapeObject::GetOccShape(theShapeActor);
349   if (!aShape.IsNull())
350   {
351     RemoveSelectableObject(aShape);
352   }
353 }
354
355 //============================================================================
356 //  Method: GetPickedSubShapesIds
357 // Purpose: Access to the list of sub-shapes ids picked.
358 //============================================================================
359 IVtk_ShapeIdList IVtkTools_ShapePicker::GetPickedSubShapesIds (const IVtk_IdType theId, bool theIsAll) const
360 {
361   IVtk_ShapeIdList aRes;
362   if (theIsAll)
363   {
364     myOccPickerAlgo->SubShapesPicked (theId, aRes);
365   }
366   else
367   {
368     IVtk_ShapeIdList aList;
369     myOccPickerAlgo->SubShapesPicked (theId, aList);
370     if (!aList.IsEmpty())
371     {
372       aRes.Append (aList.First());
373     }
374   }
375   return aRes;
376 }
377
378 //============================================================================
379 //  Method: GetPickedActors
380 // Purpose: Access to the list of actors picked.
381 //============================================================================
382 vtkSmartPointer<vtkActorCollection> IVtkTools_ShapePicker::GetPickedActors (bool theIsAll) const
383 {
384   vtkSmartPointer<vtkActorCollection> aRes = vtkSmartPointer<vtkActorCollection>::New();
385   IVtk_ShapeIdList anIds = GetPickedShapesIds (theIsAll);
386   if (myRenderer.GetPointer() != NULL)
387   {
388     // Obtain all actors whose source shape ids are within selected ids.
389     vtkSmartPointer<vtkActorCollection> anActors = myRenderer->GetActors();
390     anActors->InitTraversal();
391     vtkSmartPointer<vtkActor> anActor = anActors->GetNextActor();
392     while ( anActor.GetPointer() != NULL )
393     {
394       if (anActor->GetPickable() && anActor->GetVisibility())
395       {
396         if (anActor->GetMapper())
397         {
398           IVtk_IShape::Handle aShape = IVtkTools_ShapeObject::GetOccShape (anActor);
399           if (!aShape.IsNull())
400           {
401             for (IVtk_ShapeIdList::Iterator anIt (anIds); anIt.More(); anIt.Next())
402             {
403               if (aShape->GetId() == anIt.Value())
404               {
405                 aRes->AddItem (anActor);
406               }
407             }
408           }
409         }
410       }
411       anActor = anActors->GetNextActor();
412     }
413   }
414   return aRes;
415 }