0027860: Visualization - clean up Transformation Persistence API
[occt.git] / src / SelectMgr / SelectMgr_SelectableObjectSet.cxx
1 // Created on: 2014-08-15
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-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 <SelectMgr_SelectableObjectSet.hxx>
17 #include <SelectMgr_VectorTypes.hxx>
18
19 #include <BVH_BinnedBuilder.hxx>
20 #include <BVH_LinearBuilder.hxx>
21
22 namespace
23 {
24   //! Short-cut definition of indexed data map of selectable objects
25   typedef NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> ObjectsMap;
26
27   //-------------------------------------------------------------------------------------
28   // Adaptor over regular objects subset of SelectMgr_SelectableObjectSet for BVH builder
29   //-------------------------------------------------------------------------------------
30
31   //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
32   //! so the BVH builder could explicitly arrange objects in the map as necessary
33   //! to provide synchronization of indexes with constructed BVH tree.
34   class BVHBuilderAdaptorRegular : public BVH_Set<Standard_Real, 3>
35   {
36   public:
37
38     //! Construct adaptor.
39     BVHBuilderAdaptorRegular (ObjectsMap& theObjects) : myObjects (theObjects) {};
40
41     //! Returns bounding box of object with index theIndex
42     virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
43     {
44       const Handle(SelectMgr_SelectableObject)& anObject = myObjects.FindKey (theIndex + 1);
45       Bnd_Box aBox;
46       anObject->BoundingBox (aBox);
47       if (aBox.IsVoid())
48         return Select3D_BndBox3d();
49
50       return Select3D_BndBox3d (SelectMgr_Vec3 (aBox.CornerMin().X(), aBox.CornerMin().Y(), aBox.CornerMin().Z()),
51                                 SelectMgr_Vec3 (aBox.CornerMax().X(), aBox.CornerMax().Y(), aBox.CornerMax().Z()));
52     }
53
54     //! Returns bounding box of the whole subset.
55     virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
56     {
57       if (!myBox.IsValid())
58       {
59         myBox = BVH_Set<Standard_Real, 3>::Box();
60       }
61       return myBox;
62     }
63
64     //! Make inherited method Box() visible to avoid CLang warning
65     using BVH_Set<Standard_Real, 3>::Box;
66
67     //! Returns center of object with index theIndex in the set
68     //! along the given axis theAxis
69     virtual Standard_Real Center (const Standard_Integer theIndex,
70                                   const Standard_Integer theAxis) const Standard_OVERRIDE
71     {
72       const Select3D_BndBox3d aBndBox = Box (theIndex);
73
74       return (aBndBox.CornerMin()[theAxis] +
75               aBndBox.CornerMax()[theAxis]) * 0.5;
76     }
77
78     //! Returns size of objects set.
79     virtual Standard_Integer Size() const Standard_OVERRIDE
80     {
81       return myObjects.Size();
82     }
83
84     //! Swaps items with indexes theIndex1 and theIndex2 in the set
85     virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
86     {
87       myObjects.Swap (theIndex1 + 1, theIndex2 + 1);
88     }
89
90   private:
91     BVHBuilderAdaptorRegular& operator=(BVHBuilderAdaptorRegular) { return *this; }
92
93   private:
94     ObjectsMap& myObjects;
95     mutable Select3D_BndBox3d myBox;
96   };
97
98   //----------------------------------------------------------------------------------------
99   // Adaptor over persistent objects subset of SelectMgr_SelectableObjectSet for BVH builder
100   //----------------------------------------------------------------------------------------
101
102   //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
103   //! so the BVH builder could explicitly arrange objects in the map as necessary
104   //! to provide synchronization of indexes with constructed BVH tree.
105   class BVHBuilderAdaptorPersistent : public BVH_Set<Standard_Real, 3>
106   {
107   public:
108
109     //! Construct adaptor.
110     //! @param theCamera, theProjectionMat, theWorldViewMat,
111     //!        theWidth, theHeight [in] view properties used for computation of
112     //!        bounding boxes within the world view camera space.
113     BVHBuilderAdaptorPersistent (ObjectsMap& theObjects,
114                                  const Handle(Graphic3d_Camera)& theCamera,
115                                  const Graphic3d_Mat4d& theProjectionMat,
116                                  const Graphic3d_Mat4d& theWorldViewMat,
117                                  const Standard_Integer theWidth,
118                                  const Standard_Integer theHeight)
119     : myObjects (theObjects)
120     {
121       myBoundings.ReSize (myObjects.Size());
122       for (Standard_Integer anI = 1; anI <= myObjects.Size(); ++anI)
123       {
124         const Handle(SelectMgr_SelectableObject)& anObject = myObjects (anI);
125
126         Bnd_Box aBoundingBox;
127         anObject->BoundingBox (aBoundingBox);
128         if (aBoundingBox.IsVoid()
129          || anObject->TransformPersistence().IsNull())
130         {
131           myBoundings.Add (new Select3D_HBndBox3d());
132         }
133         else
134         {
135           anObject->TransformPersistence()->Apply (theCamera, theProjectionMat, theWorldViewMat, theWidth, theHeight, aBoundingBox);
136
137           const gp_Pnt aMin = aBoundingBox.CornerMin();
138           const gp_Pnt aMax = aBoundingBox.CornerMax();
139           myBoundings.Add (new Select3D_HBndBox3d (Select3D_Vec3 (aMin.X(), aMin.Y(), aMin.Z()),
140                                                    Select3D_Vec3 (aMax.X(), aMax.Y(), aMax.Z())));
141         }
142       }
143     }
144
145     //! Returns bounding box of object with index theIndex
146     virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
147     {
148       return *myBoundings (theIndex + 1);
149     }
150
151     //! Returns bounding box of the whole subset.
152     virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
153     {
154       if (!myBox.IsValid())
155       {
156         myBox = BVH_Set<Standard_Real, 3>::Box();
157       }
158       return myBox;
159     }
160
161     //! Make inherited method Box() visible to avoid CLang warning
162     using BVH_Set<Standard_Real, 3>::Box;
163
164     //! Returns center of object with index theIndex in the set
165     //! along the given axis theAxis
166     virtual Standard_Real Center (const Standard_Integer theIndex,
167                                   const Standard_Integer theAxis) const Standard_OVERRIDE
168     {
169       const Select3D_BndBox3d& aBoundingBox = *myBoundings (theIndex + 1);
170
171       return (aBoundingBox.CornerMin()[theAxis] + aBoundingBox.CornerMax()[theAxis]) * 0.5;
172     }
173
174     //! Returns size of objects set.
175     virtual Standard_Integer Size() const Standard_OVERRIDE
176     {
177       return myObjects.Size();
178     }
179
180     //! Swaps items with indexes theIndex1 and theIndex2 in the set
181     virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
182     {
183       const Standard_Integer aStructIdx1 = theIndex1 + 1;
184       const Standard_Integer aStructIdx2 = theIndex2 + 1;
185
186       myObjects.Swap (aStructIdx1, aStructIdx2);
187       myBoundings.Swap (aStructIdx1, aStructIdx2);
188     }
189
190   private:
191     BVHBuilderAdaptorPersistent& operator=(BVHBuilderAdaptorPersistent) { return *this; }
192
193   private:
194     ObjectsMap& myObjects;
195     mutable Select3D_BndBox3d myBox;
196     typedef NCollection_Shared<Select3D_BndBox3d> Select3D_HBndBox3d;
197     NCollection_IndexedMap<Handle(Select3D_HBndBox3d)> myBoundings;
198   };
199
200   static const Graphic3d_Mat4d THE_IDENTITY_MAT;
201 }
202
203 //=============================================================================
204 // Function: Constructor
205 // Purpose :
206 //=============================================================================
207 SelectMgr_SelectableObjectSet::SelectMgr_SelectableObjectSet()
208 : myLastWidth (0),
209   myLastHeight (0)
210 {
211   myBVH[BVHSubset_2dPersistent] = new BVH_Tree<Standard_Real, 3>();
212   myBVH[BVHSubset_3dPersistent] = new BVH_Tree<Standard_Real, 3>();
213   myBVH[BVHSubset_3d]           = new BVH_Tree<Standard_Real, 3>();
214
215   myBuilder[BVHSubset_2dPersistent] = new BVH_LinearBuilder<Standard_Real, 3> (1, 32);
216   myBuilder[BVHSubset_3dPersistent] = new BVH_LinearBuilder<Standard_Real, 3> (1, 32);
217   myBuilder[BVHSubset_3d]           = new BVH_BinnedBuilder<Standard_Real, 3, 4> (1, 32, Standard_True);
218
219   myIsDirty[BVHSubset_2dPersistent] = Standard_False;
220   myIsDirty[BVHSubset_3dPersistent] = Standard_False;
221   myIsDirty[BVHSubset_3d]           = Standard_False;
222 }
223
224 //=============================================================================
225 // Function: Append
226 // Purpose :
227 //=============================================================================
228 Standard_Boolean SelectMgr_SelectableObjectSet::Append (const Handle(SelectMgr_SelectableObject)& theObject)
229 {
230   // get an appropriate BVH subset to insert the object into it
231   const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
232
233   // check that the object is excluded from other subsets
234   if (myObjects[(aSubsetIdx + 1) % BVHSubsetNb].Contains (theObject)
235    || myObjects[(aSubsetIdx + 2) % BVHSubsetNb].Contains (theObject))
236   {
237     return Standard_False;
238   }
239
240   // try adding it into the appropriate object subset
241   const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
242
243   if (aSize < myObjects[aSubsetIdx].Add (theObject))
244   {
245     myIsDirty[aSubsetIdx] = Standard_True;
246
247     return Standard_True;
248   }
249
250   return Standard_False;
251 }
252
253 //=============================================================================
254 // Function: Remove
255 // Purpose :
256 //=============================================================================
257 Standard_Boolean SelectMgr_SelectableObjectSet::Remove (const Handle(SelectMgr_SelectableObject)& theObject)
258 {
259   // remove object from the first found subset
260   for (Standard_Integer aSubsetIdx = 0; aSubsetIdx < BVHSubsetNb; ++aSubsetIdx)
261   {
262     const Standard_Integer anIndex = myObjects[aSubsetIdx].FindIndex (theObject);
263
264     if (anIndex != 0)
265     {
266       const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
267
268       if (anIndex != aSize)
269       {
270         myObjects[aSubsetIdx].Swap (anIndex, aSize);
271       }
272
273       myObjects[aSubsetIdx].RemoveLast();
274       myIsDirty[aSubsetIdx] = Standard_True;
275
276       return Standard_True;
277     }
278   }
279
280   return Standard_False;
281 }
282
283 //=============================================================================
284 // Function: ChangeSubset
285 // Purpose :
286 //=============================================================================
287 void SelectMgr_SelectableObjectSet::ChangeSubset (const Handle(SelectMgr_SelectableObject)& theObject)
288 {
289   // do not do anything is object is not in the map
290   const Standard_Integer aCurrSubsetIdx = currentSubset (theObject);
291
292   if (aCurrSubsetIdx < 0)
293   {
294     return;
295   }
296
297   // check whether the subset need to be changed at all
298   const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
299
300   if (aCurrSubsetIdx == aSubsetIdx)
301   {
302     return;
303   }
304
305   // replace object in the maps
306   Remove (theObject);
307   Append (theObject);
308 }
309
310 //=============================================================================
311 // Function: UpdateBVH
312 // Purpose :
313 //=============================================================================
314 void SelectMgr_SelectableObjectSet::UpdateBVH (const Handle(Graphic3d_Camera)& theCamera,
315                                                const Graphic3d_Mat4d& theProjectionMat,
316                                                const Graphic3d_Mat4d& theWorldViewMat,
317                                                const Graphic3d_WorldViewProjState& theViewState,
318                                                const Standard_Integer theViewportWidth,
319                                                const Standard_Integer theViewportHeight)
320 {
321   // -----------------------------------------
322   // check and update 3D BVH tree if necessary
323   // -----------------------------------------
324   if (!IsEmpty (BVHSubset_3d) && myIsDirty[BVHSubset_3d])
325   {
326     // construct adaptor over private fields to provide direct access for the BVH builder
327     BVHBuilderAdaptorRegular anAdaptor (myObjects[BVHSubset_3d]);
328
329     // update corresponding BVH tree data structure
330     myBuilder[BVHSubset_3d]->Build (&anAdaptor, myBVH[BVHSubset_3d].operator->(), anAdaptor.Box());
331
332     // release dirty state
333     myIsDirty[BVHSubset_3d] = Standard_False;
334   }
335
336   if (!theCamera.IsNull())
337   {
338     const Standard_Boolean isWindowSizeChanged =
339       (myLastHeight != theViewportHeight) || (myLastWidth != theViewportWidth);
340
341     // -----------------------------------------------------
342     // check and update 3D persistence BVH tree if necessary
343     // -----------------------------------------------------
344     if (!IsEmpty (BVHSubset_3dPersistent) &&
345          (myIsDirty[BVHSubset_3dPersistent] || myLastViewState.IsChanged (theViewState) || isWindowSizeChanged))
346     {
347       // construct adaptor over private fields to provide direct access for the BVH builder
348       BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_3dPersistent],
349         theCamera, theProjectionMat, theWorldViewMat, theViewportWidth, theViewportHeight);
350
351       // update corresponding BVH tree data structure
352       myBuilder[BVHSubset_3dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_3dPersistent].operator->(), anAdaptor.Box());
353     }
354
355     // -----------------------------------------------------
356     // check and update 2D persistence BVH tree if necessary
357     // -----------------------------------------------------
358     if (!IsEmpty (BVHSubset_2dPersistent) &&
359          (myIsDirty[BVHSubset_2dPersistent] || myLastViewState.IsProjectionChanged (theViewState) || isWindowSizeChanged))
360     {
361       // construct adaptor over private fields to provide direct access for the BVH builder
362       BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_2dPersistent],
363         theCamera, theProjectionMat, THE_IDENTITY_MAT, theViewportWidth, theViewportHeight);
364
365       // update corresponding BVH tree data structure
366       myBuilder[BVHSubset_2dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_2dPersistent].operator->(), anAdaptor.Box());
367     }
368
369     // release dirty state for every subset
370     myIsDirty[BVHSubset_3dPersistent] = Standard_False;
371     myIsDirty[BVHSubset_2dPersistent] = Standard_False;
372
373     // keep last view state
374     myLastViewState = theViewState;
375   }
376
377   // keep last window state
378   myLastWidth  = theViewportWidth;
379   myLastHeight = theViewportHeight;
380 }
381
382 //=============================================================================
383 // Function: MarkDirty
384 // Purpose :
385 //=============================================================================
386 void SelectMgr_SelectableObjectSet::MarkDirty()
387 {
388   myIsDirty[BVHSubset_3d]           = Standard_True;
389   myIsDirty[BVHSubset_3dPersistent] = Standard_True;
390   myIsDirty[BVHSubset_2dPersistent] = Standard_True;
391 }