0030520: VIS - IVtkTools_ShapePicker::GetPickPosition() returns incorrect point
[occt.git] / src / IVtkOCC / IVtkOCC_ShapePickerAlgo.cxx
1 // Created on: 2011-10-14 
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 <IVtk_Types.hxx>
17 #include <IVtkOCC_ShapePickerAlgo.hxx>
18 #include <IVtkOCC_Shape.hxx>
19 #include <IVtkOCC_SelectableObject.hxx>
20 #include <Message.hxx>
21 #include <Message_Messenger.hxx>
22 #include <StdSelect_BRepOwner.hxx>
23
24 IMPLEMENT_STANDARD_RTTIEXT(IVtkOCC_ShapePickerAlgo,IVtk_IShapePickerAlgo)
25
26 // Handle implementation
27
28
29 //================================================================
30 // Function : Constructor
31 // Purpose  : 
32 //================================================================
33 IVtkOCC_ShapePickerAlgo::IVtkOCC_ShapePickerAlgo() :
34 myViewerSelector (new IVtkOCC_ViewerSelector())
35 { }
36
37 //================================================================
38 // Function : Destructor
39 // Purpose  : 
40 //================================================================
41 IVtkOCC_ShapePickerAlgo::~IVtkOCC_ShapePickerAlgo()
42 { }
43
44 //================================================================
45 // Function : SetView
46 // Purpose  :
47 //================================================================
48 void IVtkOCC_ShapePickerAlgo::SetView (const IVtk_IView::Handle& theView)
49 {
50   myView = theView;
51 }
52
53 //================================================================
54 // Function : GetSelectionModes
55 // Purpose  :
56 //================================================================
57 IVtk_SelectionModeList IVtkOCC_ShapePickerAlgo::GetSelectionModes (
58                                   const IVtk_IShape::Handle& theShape) const
59 {
60   IVtk_SelectionModeList aRes;
61
62   if (! theShape.IsNull())
63   {
64     // Get shape implementation from shape interface.
65     Handle(IVtkOCC_Shape) aShapeImpl = Handle(IVtkOCC_Shape)::DownCast(theShape);
66
67     // Get selectable object from the shape implementation.
68     Handle(IVtkOCC_SelectableObject) aSelObj = 
69       Handle(IVtkOCC_SelectableObject)::DownCast(aShapeImpl->GetSelectableObject());
70
71     if (!aSelObj.IsNull())
72     {
73       IVtk_SelectionMode aSelMode;
74       for (aSelMode = SM_Shape; aSelMode <= SM_Compound; aSelMode = (IVtk_SelectionMode)(aSelMode + 1))
75       {
76         if (myViewerSelector->IsActive (aSelObj, aSelMode))
77         {
78           aRes.Append (aSelMode);
79         }
80       }
81     }
82   }
83
84   return aRes;
85 }
86
87 //================================================================
88 // Function : SetSelectionMode
89 // Purpose  :
90 //================================================================
91 void IVtkOCC_ShapePickerAlgo::SetSelectionMode (const IVtk_IShape::Handle& theShape,
92                                                 const IVtk_SelectionMode theMode,
93                                                 const bool theIsTurnOn)
94 {
95   if (theShape.IsNull())
96   {
97     return;
98   }
99
100   // TODO: treatment for mode == -1 - deactivate the shape...
101   // Is this really needed? The picker and all selection classes
102   // are destroyed when shapes are deactivated...
103
104   // Get shape implementation from shape interface.
105   Handle(IVtkOCC_Shape) aShapeImpl = 
106     Handle(IVtkOCC_Shape)::DownCast(theShape);
107
108   // Get selectable object from the shape implementation.
109   Handle(IVtkOCC_SelectableObject) aSelObj = 
110     Handle(IVtkOCC_SelectableObject)::DownCast(aShapeImpl->GetSelectableObject());
111
112   if (theIsTurnOn)
113   {
114     // If there is no selectable object then create a new one for this shape.
115     if (aSelObj.IsNull())
116     {
117       aSelObj = new IVtkOCC_SelectableObject (aShapeImpl);
118     }
119
120     // If the selectable object has no selection in the given mode
121     if (!aSelObj->HasSelection (theMode))
122     {
123       // then create a new selection in the given mode for this object (shape).
124       Handle(SelectMgr_Selection) aNewSelection = new SelectMgr_Selection (theMode); 
125       aSelObj->AddSelection (aNewSelection, theMode);
126       myViewerSelector->AddSelectionToObject (aSelObj, aNewSelection);
127     }
128
129     // Update the selection for the given mode according to its status.
130     const Handle(SelectMgr_Selection)& aSel = aSelObj->Selection (theMode);
131
132     switch (aSel->UpdateStatus())
133     {
134       case SelectMgr_TOU_Full:
135         // Recompute the sensitive primitives which correspond to the mode.
136         myViewerSelector->RemoveSelectionOfObject (aSelObj, aSelObj->Selection (theMode));
137         aSelObj->RecomputePrimitives (theMode);
138         myViewerSelector->AddSelectionToObject (aSelObj, aSelObj->Selection (theMode));
139         myViewerSelector->RebuildObjectsTree();
140         myViewerSelector->RebuildSensitivesTree (aSelObj);
141       case SelectMgr_TOU_Partial:
142         {
143           if (aSelObj->HasTransformation())
144           {
145             myViewerSelector->RebuildObjectsTree();
146           }
147           break;
148         }
149       default:
150         break;
151     }
152     // Set status of the selection to "nothing to update".
153     aSel->UpdateStatus (SelectMgr_TOU_None);
154
155     // Activate the selection in the viewer selector.
156     myViewerSelector->Activate (aSelObj->Selection (theMode));
157
158   }
159   else
160   { // turn off the selection mode
161
162     if (!aSelObj.IsNull())
163     {
164       if (aSelObj->HasSelection (theMode))
165       {
166         const Handle(SelectMgr_Selection)& aSel = aSelObj->Selection (theMode);
167         myViewerSelector->Deactivate (aSel);
168       }
169     }
170   }
171 }
172
173 //================================================================
174 // Function : SetSelectionMode
175 // Purpose  :
176 //================================================================
177 void IVtkOCC_ShapePickerAlgo::SetSelectionMode (const IVtk_ShapePtrList& theShapes,
178                                                 const IVtk_SelectionMode theMode,
179                                                 const bool /*theIsTurnOn*/)
180 {
181   IVtk_IShape::Handle aShape;
182   IVtk_ShapePtrList::Iterator anIt (theShapes);
183   for (; anIt.More(); anIt.Next())
184   {
185     aShape = anIt.Value();
186     SetSelectionMode (aShape, theMode);
187   }
188 }
189
190 //================================================================
191 // Function : Pick
192 // Purpose  :
193 //================================================================
194 bool IVtkOCC_ShapePickerAlgo::Pick (const double theX, const double theY)
195 {
196   clearPicked();
197
198   // Calling OCCT algortihm
199   myViewerSelector->Pick ((Standard_Integer)theX,
200                           (Standard_Integer)theY,
201                           myView);
202
203   // Fill the results
204   return processPicked();
205 }
206
207 //================================================================
208 // Function : Pick
209 // Purpose  :
210 //================================================================
211 bool IVtkOCC_ShapePickerAlgo::Pick (const double theXMin,
212                                     const double theYMin,
213                                     const double theXMax,
214                                     const double theYMax)
215 {
216   clearPicked();
217
218   // Calling OCCT algortihm
219   myViewerSelector->Pick ((Standard_Integer)theXMin,
220                           (Standard_Integer)theYMin,
221                           (Standard_Integer)theXMax,
222                           (Standard_Integer)theYMax,
223                           myView);
224
225   // Fill the results
226   return processPicked();
227 }
228
229 //================================================================
230 // Function : Pick
231 // Purpose  :
232 //================================================================
233 bool IVtkOCC_ShapePickerAlgo::Pick (double** thePoly,
234                                     const int theNbPoints)
235 {
236   clearPicked();
237
238   // Calling OCCT algortihm
239   myViewerSelector->Pick (thePoly, theNbPoints, myView);
240
241   // Fill the results
242   return processPicked();
243 }
244
245 //================================================================
246 // Function : ShapesPicked
247 // Purpose  :
248 //================================================================
249 const IVtk_ShapeIdList& IVtkOCC_ShapePickerAlgo::ShapesPicked() const
250 {
251   return myShapesPicked;
252 }
253
254 //================================================================
255 // Function : SubShapesPicked
256 // Purpose  :
257 //================================================================
258 void IVtkOCC_ShapePickerAlgo::SubShapesPicked (const IVtk_IdType theId, IVtk_ShapeIdList& theShapeList) const
259 {
260   if (mySubShapesPicked.IsBound (theId))
261   {
262     theShapeList = mySubShapesPicked (theId);
263   }
264 }
265
266 //================================================================
267 // Function : clearPicked
268 // Purpose  : Internal method, resets picked data
269 //================================================================
270 void IVtkOCC_ShapePickerAlgo::clearPicked()
271 {
272   myTopPickedPoint.SetCoord (RealLast(), RealLast(), RealLast());
273   myShapesPicked.Clear();
274   mySubShapesPicked.Clear();
275 }
276
277 //================================================================
278 // Function : NbPicked
279 // Purpose  : Get number of picked entities.
280 //================================================================
281 int IVtkOCC_ShapePickerAlgo::NbPicked()
282 {
283   return myShapesPicked.Extent();
284 }
285
286 //================================================================
287 // Function : processPicked
288 // Purpose  :
289 //================================================================
290 bool IVtkOCC_ShapePickerAlgo::processPicked()
291 {
292   Standard_Integer aNbPicked =  myViewerSelector->NbPicked();
293
294   Handle(StdSelect_BRepOwner) anEntityOwner;
295   Handle(Message_Messenger) anOutput = Message::DefaultMessenger();
296
297   bool isTop = true;
298   for (Standard_Integer aDetectIt = 1; aDetectIt <= aNbPicked; aDetectIt++)
299   {
300     // ViewerSelector detects sensitive entities under the mouse
301     // and for each entity returns its entity owner.
302     // StdSelect_BRepOwner instance holds corresponding sub-shape (TopoDS_Shape)
303     // and in general entity owners have a pointer to SelectableObject that can tell us
304     // what is the top-level TopoDS_Shape.
305     anEntityOwner = Handle(StdSelect_BRepOwner)::DownCast (myViewerSelector->Picked (aDetectIt));
306     if (!anEntityOwner.IsNull())
307     {
308       Handle(IVtkOCC_SelectableObject) aSelectable =
309         Handle(IVtkOCC_SelectableObject)::DownCast (anEntityOwner->Selectable());
310
311       if (aSelectable.IsNull())
312       {
313         anOutput << "Error: EntityOwner having null SelectableObject picked!";
314         continue;
315       }
316
317       Handle(IVtkOCC_Shape) aSelShape = aSelectable->GetShape();
318       if (aSelShape.IsNull())
319       {
320         anOutput << "Error: SelectableObject with null OccShape pointer picked!";
321         continue;
322       }
323
324       IVtk_IdType aTopLevelId = aSelShape->GetId();
325       myShapesPicked.Append (aTopLevelId);
326       if (isTop)
327       {
328         isTop = false;
329         myTopPickedPoint = myViewerSelector->PickedPoint (aDetectIt);
330       }
331
332       // Now try to guess if it's the top-level shape itself or just a sub-shape picked
333       TopoDS_Shape aTopLevelShape = aSelShape->GetShape();
334       TopoDS_Shape aSubShape      = anEntityOwner->Shape();
335       if (aTopLevelShape.IsNull())
336       {
337         anOutput << "Error: OccShape with null top-level TopoDS_Shape picked!";
338         continue;
339       }
340       if (aSubShape.IsNull())
341       {
342         anOutput << "Error: EntityOwner with null TopoDS_Shape picked!";
343         continue;
344       }
345
346       if (!aSubShape.IsSame (aTopLevelShape))
347       {
348         IVtk_IdType aSubId = aSelShape->GetSubShapeId (aSubShape);
349
350         if (!mySubShapesPicked.IsBound (aTopLevelId))
351         {
352           const IVtk_ShapeIdList aList;
353           mySubShapesPicked.Bind (aTopLevelId, aList);
354         }
355         // Order of selected sub-shapes
356         mySubShapesPicked (aTopLevelId).Append (aSubId);
357       }
358     }
359   }
360
361   return !myShapesPicked.IsEmpty();
362 }
363
364 //============================================================================
365 //  Method: RemoveSelectableActor
366 // Purpose: Remove selectable object from the picker (from internal maps).
367 //============================================================================
368 void IVtkOCC_ShapePickerAlgo::RemoveSelectableObject(const IVtk_IShape::Handle& theShape)
369 {
370   clearPicked();
371   // Get shape implementation from shape interface.
372   Handle(IVtkOCC_Shape) aShapeImpl =
373     Handle(IVtkOCC_Shape)::DownCast(theShape);
374
375   // Get selectable object from the shape implementation.
376   Handle(IVtkOCC_SelectableObject) aSelObj =
377     Handle(IVtkOCC_SelectableObject)::DownCast(aShapeImpl->GetSelectableObject());
378
379   myViewerSelector->RemoveSelectableObject(aSelObj);
380   myViewerSelector->Clear();
381   aShapeImpl->SetSelectableObject(NULL);
382 }