0029938: Visualization - SelectMgr_ViewerSelector::PickedPoint() should return point...
[occt.git] / src / Select3D / Select3D_SensitiveGroup.cxx
1 // Created on: 1998-04-16
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <Select3D_SensitiveGroup.hxx>
18
19 #include <Precision.hxx>
20
21 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveGroup,Select3D_SensitiveSet)
22
23 //=======================================================================
24 //function : Creation
25 //purpose  :
26 //=======================================================================
27 Select3D_SensitiveGroup::Select3D_SensitiveGroup (const Handle(SelectBasics_EntityOwner)& theOwnerId,
28                                                   const Standard_Boolean theIsMustMatchAll)
29 : Select3D_SensitiveSet (theOwnerId),
30   myMustMatchAll (theIsMustMatchAll),
31   myToCheckOverlapAll (Standard_False),
32   myCenter (0.0, 0.0, 0.0) {}
33
34 //=======================================================================
35 //function : Creation
36 //purpose  :
37 //=======================================================================
38 Select3D_SensitiveGroup::Select3D_SensitiveGroup (const Handle(SelectBasics_EntityOwner)& theOwnerId,
39                                                   Select3D_EntitySequence& theEntities,
40                                                   const Standard_Boolean theIsMustMatchAll)
41 : Select3D_SensitiveSet (theOwnerId),
42   myEntities (Max (1, theEntities.Size())),
43   myMustMatchAll (theIsMustMatchAll),
44   myToCheckOverlapAll (Standard_False),
45   myCenter (0.0, 0.0, 0.0)
46 {
47   for (Select3D_EntitySequenceIter anIter (theEntities); anIter.More(); anIter.Next())
48   {
49     const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value();
50     const Standard_Integer aPrevExtent = myEntities.Extent();
51     if (myEntities.Add (anEntity) <= aPrevExtent)
52     {
53       continue;
54     }
55
56     myBndBox.Combine (anEntity->BoundingBox());
57     myBVHPrimIndexes.Append (myEntities.Extent());
58     myCenter.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
59   }
60
61   myCenter.ChangeCoord().Divide (static_cast<Standard_Real> (myEntities.Extent()));
62
63   MarkDirty();
64 }
65
66 //=======================================================================
67 //function : Add
68 //purpose  : No control of entities inside
69 //=======================================================================
70 void Select3D_SensitiveGroup::Add (Select3D_EntitySequence& theEntities)
71 {
72   if (theEntities.IsEmpty())
73   {
74     return;
75   }
76
77   gp_Pnt aCent (0.0, 0.0, 0.0);
78   myEntities.ReSize (myEntities.Extent() + theEntities.Size());
79   for (Select3D_EntitySequenceIter anIter (theEntities); anIter.More(); anIter.Next())
80   {
81     const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value();
82     const Standard_Integer aPrevExtent = myEntities.Extent();
83     if (myEntities.Add (anEntity) <= aPrevExtent)
84     {
85       continue;
86     }
87
88     myBndBox.Combine (anEntity->BoundingBox());
89     myBVHPrimIndexes.Append (myEntities.Extent());
90     aCent.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
91   }
92   aCent.ChangeCoord().Divide (myEntities.Extent());
93   myCenter = (myCenter.XYZ() + aCent.XYZ()).Multiplied (0.5);
94 }
95
96 //=======================================================================
97 //function : Add
98 //purpose  :
99 //=======================================================================
100 void Select3D_SensitiveGroup::Add (const Handle(Select3D_SensitiveEntity)& theSensitive)
101 {
102   const Standard_Integer aPrevExtent = myEntities.Extent();
103   if (myEntities.Add (theSensitive) <= aPrevExtent)
104   {
105     return;
106   }
107
108   myBVHPrimIndexes.Append (myEntities.Extent());
109   myBndBox.Combine (theSensitive->BoundingBox());
110   myCenter.ChangeCoord() += theSensitive->CenterOfGeometry().XYZ();
111   if (myEntities.Extent() >= 2)
112   {
113     myCenter.ChangeCoord().Multiply (0.5);
114   }
115 }
116
117 //=======================================================================
118 //function : Remove
119 //purpose  :
120 //=======================================================================
121 void Select3D_SensitiveGroup::Remove (const Handle(Select3D_SensitiveEntity)& theSensitive)
122 {
123   if (!myEntities.RemoveKey (theSensitive))
124   {
125     return;
126   }
127
128   myBndBox.Clear();
129   myCenter = gp_Pnt (0.0, 0.0, 0.0);
130   myBVHPrimIndexes.Clear();
131   for (Standard_Integer anIdx = 1; anIdx <= myEntities.Size(); ++anIdx)
132   {
133     const Handle(Select3D_SensitiveEntity)& anEntity = myEntities.FindKey (anIdx);
134     myBndBox.Combine (anEntity->BoundingBox());
135     myCenter.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
136     myBVHPrimIndexes.Append (anIdx);
137   }
138   myCenter.ChangeCoord().Divide (static_cast<Standard_Real> (myEntities.Extent()));
139 }
140
141 //=======================================================================
142 //function : IsIn
143 //purpose  :
144 //=======================================================================
145 Standard_Boolean Select3D_SensitiveGroup::IsIn (const Handle(Select3D_SensitiveEntity)& theSensitive) const
146 {
147   return myEntities.Contains (theSensitive);
148 }
149
150 //=======================================================================
151 //function : Clear
152 //purpose  :
153 //=======================================================================
154
155 void Select3D_SensitiveGroup::Clear()
156 {
157   myEntities.Clear();
158   myBndBox.Clear();
159   myCenter = gp_Pnt (0.0, 0.0, 0.0);
160   myEntities.Clear();
161 }
162
163 //=======================================================================
164 // function : NbSubElements
165 // purpose  : Returns the amount of sub-entities
166 //=======================================================================
167 Standard_Integer Select3D_SensitiveGroup::NbSubElements()
168 {
169   return myEntities.Size();
170 }
171
172 //=======================================================================
173 //function : GetConnected
174 //purpose  :
175 //=======================================================================
176
177 Handle(Select3D_SensitiveEntity) Select3D_SensitiveGroup::GetConnected()
178 {
179   Handle(Select3D_SensitiveGroup) aNewEntity = new Select3D_SensitiveGroup (myOwnerId, myMustMatchAll);
180   Select3D_EntitySequence aConnectedEnt;
181   for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
182   {
183     aConnectedEnt.Append (anEntityIter.Value()->GetConnected());
184   }
185   aNewEntity->Add (aConnectedEnt);
186   return aNewEntity;
187 }
188
189 //=======================================================================
190 //function : Matches
191 //purpose  :
192 //=======================================================================
193 Standard_Boolean Select3D_SensitiveGroup::Matches (SelectBasics_SelectingVolumeManager& theMgr,
194                                                    SelectBasics_PickResult& thePickResult)
195 {
196   const Standard_Boolean toMatchAll = theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point
197                                    && myMustMatchAll;
198   const Standard_Boolean toCheckAll = theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point
199                                    && myToCheckOverlapAll;
200   if (!toMatchAll && !toCheckAll)
201   {
202     return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
203   }
204
205   SelectBasics_PickResult aPickResult;
206   Standard_Boolean isFailed = Standard_False;
207   for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
208   {
209     const Handle(Select3D_SensitiveEntity)& aChild = anEntityIter.Value();
210     if (!aChild->Matches (theMgr, aPickResult))
211     {
212       if (toMatchAll)
213       {
214         isFailed = Standard_True;
215         if (!toCheckAll)
216         {
217           break;
218         }
219       }
220     }
221     else
222     {
223       thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
224     }
225   }
226   if (isFailed)
227   {
228     return Standard_False;
229   }
230
231   thePickResult.SetDistToGeomCenter(distanceToCOG(theMgr));
232   return Standard_True;
233 }
234
235 //=======================================================================
236 //function : Set
237 //purpose  :
238 //=======================================================================
239 void Select3D_SensitiveGroup::Set (const Handle(SelectBasics_EntityOwner)& theOwnerId)
240
241   Select3D_SensitiveEntity::Set (theOwnerId);
242   for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
243   {
244     anEntityIter.Value()->Set (theOwnerId);
245   }
246 }
247
248 //=======================================================================
249 // function : BoundingBox
250 // purpose  : Returns bounding box of the group. If location
251 //            transformation is set, it will be applied
252 //=======================================================================
253 Select3D_BndBox3d Select3D_SensitiveGroup::BoundingBox()
254 {
255   if (myBndBox.IsValid())
256     return myBndBox;
257
258   // do not apply the transformation because sensitives AABBs
259   // are already transformed
260   for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
261   {
262     myBndBox.Combine (anEntityIter.Value()->BoundingBox());
263   }
264
265   return myBndBox;
266 }
267
268 //=======================================================================
269 // function : CenterOfGeometry
270 // purpose  : Returns center of group. If location transformation
271 //            is set, it will be applied
272 //=======================================================================
273 gp_Pnt Select3D_SensitiveGroup::CenterOfGeometry() const
274 {
275   return myCenter;
276 }
277
278 //=======================================================================
279 // function : Box
280 // purpose  : Returns bounding box of sensitive entity with index theIdx
281 //=======================================================================
282 Select3D_BndBox3d Select3D_SensitiveGroup::Box (const Standard_Integer theIdx) const
283 {
284   const Standard_Integer anElemIdx = myBVHPrimIndexes.Value (theIdx);
285   return myEntities.FindKey (anElemIdx)->BoundingBox();
286 }
287
288 //=======================================================================
289 // function : Center
290 // purpose  : Returns geometry center of sensitive entity with index
291 //            theIdx in the vector along the given axis theAxis
292 //=======================================================================
293 Standard_Real Select3D_SensitiveGroup::Center (const Standard_Integer theIdx,
294                                                const Standard_Integer theAxis) const
295 {
296   const Standard_Integer anElemIdx = myBVHPrimIndexes.Value (theIdx);
297   const gp_Pnt aCenter = myEntities.FindKey (anElemIdx)->CenterOfGeometry();
298   return theAxis == 0 ? aCenter.X() : (theAxis == 1 ? aCenter.Y() : aCenter.Z());
299 }
300
301 //=======================================================================
302 // function : Swap
303 // purpose  : Swaps items with indexes theIdx1 and theIdx2 in the vector
304 //=======================================================================
305 void Select3D_SensitiveGroup::Swap (const Standard_Integer theIdx1,
306                                     const Standard_Integer theIdx2)
307 {
308   const Standard_Integer anEntIdx1 = myBVHPrimIndexes.Value (theIdx1);
309   const Standard_Integer anEntIdx2 = myBVHPrimIndexes.Value (theIdx2);
310
311   myBVHPrimIndexes.ChangeValue (theIdx1) = anEntIdx2;
312   myBVHPrimIndexes.ChangeValue (theIdx2) = anEntIdx1;
313 }
314
315 //=======================================================================
316 // function : Size
317 // purpose  : Returns the length of vector of sensitive entities
318 //=======================================================================
319 Standard_Integer Select3D_SensitiveGroup::Size() const
320 {
321   return myBVHPrimIndexes.Size();
322 }
323
324 // =======================================================================
325 // function : overlapsElement
326 // purpose  : Checks whether the entity with index theIdx overlaps the
327 //            current selecting volume
328 // =======================================================================
329 Standard_Boolean Select3D_SensitiveGroup::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
330                                                            Standard_Integer theElemIdx,
331                                                            SelectBasics_PickResult& thePickResult)
332 {
333   const Standard_Integer aSensitiveIdx = myBVHPrimIndexes.Value (theElemIdx);
334   if (myEntities.FindKey (aSensitiveIdx)->Matches (theMgr, thePickResult))
335   {
336     return Standard_True;
337   }
338
339   return Standard_False;
340 }
341
342 // =======================================================================
343 // function : elementIsInside
344 // purpose  :
345 // =======================================================================
346 Standard_Boolean Select3D_SensitiveGroup::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
347                                                            const Standard_Integer               theElemIdx)
348 {
349   SelectBasics_PickResult aDummy;
350   return overlapsElement(theMgr, theElemIdx, aDummy);
351 }
352
353 // =======================================================================
354 // function : distanceToCOG
355 // purpose  : Calculates distance from the 3d projection of used-picked
356 //            screen point to center of the geometry
357 // =======================================================================
358 Standard_Real Select3D_SensitiveGroup::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
359 {
360   return theMgr.DistToGeometryCenter (CenterOfGeometry());
361 }