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