0028417: Using PRECOMPILED HEADER to speed up compilation time
[occt.git] / src / SelectMgr / SelectMgr_SelectableObjectSet.cxx
index ffd330b..68c8060 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-#include <Bnd_Box.hxx>
+#include <SelectMgr_SelectableObjectSet.hxx>
+#include <SelectMgr_VectorTypes.hxx>
+
 #include <BVH_BinnedBuilder.hxx>
+#include <BVH_LinearBuilder.hxx>
 
-#include <SelectMgr_SelectableObjectSet.hxx>
+namespace
+{
+  //! Short-cut definition of indexed data map of selectable objects
+  typedef NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> ObjectsMap;
+
+  //-------------------------------------------------------------------------------------
+  // Adaptor over regular objects subset of SelectMgr_SelectableObjectSet for BVH builder
+  //-------------------------------------------------------------------------------------
+
+  //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
+  //! so the BVH builder could explicitly arrange objects in the map as necessary
+  //! to provide synchronization of indexes with constructed BVH tree.
+  class BVHBuilderAdaptorRegular : public BVH_Set<Standard_Real, 3>
+  {
+  public:
+
+    //! Construct adaptor.
+    BVHBuilderAdaptorRegular (ObjectsMap& theObjects) : myObjects (theObjects) {};
+
+    //! Returns bounding box of object with index theIndex
+    virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
+    {
+      const Handle(SelectMgr_SelectableObject)& anObject = myObjects.FindKey (theIndex + 1);
+      Bnd_Box aBox;
+      anObject->BoundingBox (aBox);
+      if (aBox.IsVoid())
+        return Select3D_BndBox3d();
+
+      return Select3D_BndBox3d (SelectMgr_Vec3 (aBox.CornerMin().X(), aBox.CornerMin().Y(), aBox.CornerMin().Z()),
+                                SelectMgr_Vec3 (aBox.CornerMax().X(), aBox.CornerMax().Y(), aBox.CornerMax().Z()));
+    }
+
+    //! Returns bounding box of the whole subset.
+    virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
+    {
+      if (!myBox.IsValid())
+      {
+        myBox = BVH_Set<Standard_Real, 3>::Box();
+      }
+      return myBox;
+    }
+
+    //! Make inherited method Box() visible to avoid CLang warning
+    using BVH_Set<Standard_Real, 3>::Box;
+
+    //! Returns center of object with index theIndex in the set
+    //! along the given axis theAxis
+    virtual Standard_Real Center (const Standard_Integer theIndex,
+                                  const Standard_Integer theAxis) const Standard_OVERRIDE
+    {
+      const Select3D_BndBox3d aBndBox = Box (theIndex);
+
+      return (aBndBox.CornerMin()[theAxis] +
+              aBndBox.CornerMax()[theAxis]) * 0.5;
+    }
+
+    //! Returns size of objects set.
+    virtual Standard_Integer Size() const Standard_OVERRIDE
+    {
+      return myObjects.Size();
+    }
+
+    //! Swaps items with indexes theIndex1 and theIndex2 in the set
+    virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
+    {
+      myObjects.Swap (theIndex1 + 1, theIndex2 + 1);
+    }
+
+  private:
+    BVHBuilderAdaptorRegular& operator=(BVHBuilderAdaptorRegular) { return *this; }
+
+  private:
+    ObjectsMap& myObjects;
+    mutable Select3D_BndBox3d myBox;
+  };
+
+  //----------------------------------------------------------------------------------------
+  // Adaptor over persistent objects subset of SelectMgr_SelectableObjectSet for BVH builder
+  //----------------------------------------------------------------------------------------
+
+  //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
+  //! so the BVH builder could explicitly arrange objects in the map as necessary
+  //! to provide synchronization of indexes with constructed BVH tree.
+  class BVHBuilderAdaptorPersistent : public BVH_Set<Standard_Real, 3>
+  {
+  public:
+
+    //! Construct adaptor.
+    //! @param theCamera, theProjectionMat, theWorldViewMat,
+    //!        theWidth, theHeight [in] view properties used for computation of
+    //!        bounding boxes within the world view camera space.
+    BVHBuilderAdaptorPersistent (ObjectsMap& theObjects,
+                                 const Handle(Graphic3d_Camera)& theCamera,
+                                 const Graphic3d_Mat4d& theProjectionMat,
+                                 const Graphic3d_Mat4d& theWorldViewMat,
+                                 const Standard_Integer theWidth,
+                                 const Standard_Integer theHeight)
+    : myObjects (theObjects)
+    {
+      myBoundings.ReSize (myObjects.Size());
+      for (Standard_Integer anI = 1; anI <= myObjects.Size(); ++anI)
+      {
+        const Handle(SelectMgr_SelectableObject)& anObject = myObjects (anI);
+
+        Bnd_Box aBoundingBox;
+        anObject->BoundingBox (aBoundingBox);
+        if (aBoundingBox.IsVoid()
+         || anObject->TransformPersistence().IsNull())
+        {
+          myBoundings.Add (new Select3D_HBndBox3d());
+        }
+        else
+        {
+          anObject->TransformPersistence()->Apply (theCamera, theProjectionMat, theWorldViewMat, theWidth, theHeight, aBoundingBox);
+
+          const gp_Pnt aMin = aBoundingBox.CornerMin();
+          const gp_Pnt aMax = aBoundingBox.CornerMax();
+          myBoundings.Add (new Select3D_HBndBox3d (Select3D_Vec3 (aMin.X(), aMin.Y(), aMin.Z()),
+                                                   Select3D_Vec3 (aMax.X(), aMax.Y(), aMax.Z())));
+        }
+      }
+    }
+
+    //! Returns bounding box of object with index theIndex
+    virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
+    {
+      return *myBoundings (theIndex + 1);
+    }
+
+    //! Returns bounding box of the whole subset.
+    virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
+    {
+      if (!myBox.IsValid())
+      {
+        myBox = BVH_Set<Standard_Real, 3>::Box();
+      }
+      return myBox;
+    }
+
+    //! Make inherited method Box() visible to avoid CLang warning
+    using BVH_Set<Standard_Real, 3>::Box;
+
+    //! Returns center of object with index theIndex in the set
+    //! along the given axis theAxis
+    virtual Standard_Real Center (const Standard_Integer theIndex,
+                                  const Standard_Integer theAxis) const Standard_OVERRIDE
+    {
+      const Select3D_BndBox3d& aBoundingBox = *myBoundings (theIndex + 1);
+
+      return (aBoundingBox.CornerMin()[theAxis] + aBoundingBox.CornerMax()[theAxis]) * 0.5;
+    }
+
+    //! Returns size of objects set.
+    virtual Standard_Integer Size() const Standard_OVERRIDE
+    {
+      return myObjects.Size();
+    }
+
+    //! Swaps items with indexes theIndex1 and theIndex2 in the set
+    virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
+    {
+      const Standard_Integer aStructIdx1 = theIndex1 + 1;
+      const Standard_Integer aStructIdx2 = theIndex2 + 1;
+
+      myObjects.Swap (aStructIdx1, aStructIdx2);
+      myBoundings.Swap (aStructIdx1, aStructIdx2);
+    }
+
+  private:
+    BVHBuilderAdaptorPersistent& operator=(BVHBuilderAdaptorPersistent) { return *this; }
+
+  private:
+    ObjectsMap& myObjects;
+    mutable Select3D_BndBox3d myBox;
+    typedef NCollection_Shared<Select3D_BndBox3d> Select3D_HBndBox3d;
+    NCollection_IndexedMap<Handle(Select3D_HBndBox3d)> myBoundings;
+  };
+
+  static const Graphic3d_Mat4d SelectMgr_SelectableObjectSet_THE_IDENTITY_MAT;
+}
 
-//=======================================================================
-// function : SelectMgr_SelectableObjectSet
-// purpose  : Creates new empty objects set and initializes BVH tree
-//            builder to Binned builder with 1 element per list
-//=======================================================================
+//=============================================================================
+// Function: Constructor
+// Purpose :
+//=============================================================================
 SelectMgr_SelectableObjectSet::SelectMgr_SelectableObjectSet()
+: myLastWidth (0),
+  myLastHeight (0)
 {
-  myBuilder = new BVH_BinnedBuilder<Standard_Real, 3, 32> (1, 32, Standard_False);
+  myBVH[BVHSubset_2dPersistent] = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_3dPersistent] = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_3d]           = new BVH_Tree<Standard_Real, 3>();
+
+  myBuilder[BVHSubset_2dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_3dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_3d]           = new BVH_BinnedBuilder<Standard_Real, 3, 4> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True);
+
+  myIsDirty[BVHSubset_2dPersistent] = Standard_False;
+  myIsDirty[BVHSubset_3dPersistent] = Standard_False;
+  myIsDirty[BVHSubset_3d]           = Standard_False;
 }
 
-//=======================================================================
-// function : Append
-// purpose  : Adds new object to the set and marks BVH tree for rebuild
-//=======================================================================
-void SelectMgr_SelectableObjectSet::Append (const Handle(SelectMgr_SelectableObject)& theObject)
+//=============================================================================
+// Function: Append
+// Purpose :
+//=============================================================================
+Standard_Boolean SelectMgr_SelectableObjectSet::Append (const Handle(SelectMgr_SelectableObject)& theObject)
 {
-  if (Size() < myObjects.Add (theObject))
+  // get an appropriate BVH subset to insert the object into it
+  const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
+
+  // check that the object is excluded from other subsets
+  if (myObjects[(aSubsetIdx + 1) % BVHSubsetNb].Contains (theObject)
+   || myObjects[(aSubsetIdx + 2) % BVHSubsetNb].Contains (theObject))
   {
-    MarkDirty();
+    return Standard_False;
   }
-}
 
-//=======================================================================
-// function : Remove
-// purpose  : Removes object theObject from set and marks BVH tree for
-//            rebuild
-//=======================================================================
-void SelectMgr_SelectableObjectSet::Remove (const Handle(SelectMgr_SelectableObject)& theObject)
-{
-  const Standard_Integer anIndex = myObjects.FindIndex (theObject);
+  // try adding it into the appropriate object subset
+  const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
 
-  if (anIndex != 0)
+  if (aSize < myObjects[aSubsetIdx].Add (theObject))
   {
-    Swap (anIndex - 1, Size() - 1);
+    myIsDirty[aSubsetIdx] = Standard_True;
 
-    myObjects.RemoveLast();
-
-    MarkDirty();
+    return Standard_True;
   }
-}
 
-//=======================================================================
-// function : Box
-// purpose  : Returns bounding box of object with index theIndex
-//=======================================================================
-Select3D_BndBox3d SelectMgr_SelectableObjectSet::Box (const Standard_Integer theIndex) const
-{
-  const Handle(SelectMgr_SelectableObject)& anObject = GetObjectById (theIndex);
-  Bnd_Box aBox;
-  anObject->BoundingBox (aBox);
-  if (aBox.IsVoid())
-    return Select3D_BndBox3d();
-
-  return Select3D_BndBox3d (SelectMgr_Vec3 (aBox.CornerMin().X(), aBox.CornerMin().Y(), aBox.CornerMin().Z()),
-                            SelectMgr_Vec3 (aBox.CornerMax().X(), aBox.CornerMax().Y(), aBox.CornerMax().Z()));
+  return Standard_False;
 }
 
-//=======================================================================
-// function : Center
-// purpose  : Returns center of object with index theIndex in the set
-//            along the given axis theAxis
-//=======================================================================
-Standard_Real SelectMgr_SelectableObjectSet::Center (const Standard_Integer theIndex,
-                                                     const Standard_Integer theAxis) const
+//=============================================================================
+// Function: Remove
+// Purpose :
+//=============================================================================
+Standard_Boolean SelectMgr_SelectableObjectSet::Remove (const Handle(SelectMgr_SelectableObject)& theObject)
 {
-  Select3D_BndBox3d aBndBox = Box (theIndex);
+  // remove object from the first found subset
+  for (Standard_Integer aSubsetIdx = 0; aSubsetIdx < BVHSubsetNb; ++aSubsetIdx)
+  {
+    const Standard_Integer anIndex = myObjects[aSubsetIdx].FindIndex (theObject);
 
-  return (aBndBox.CornerMin()[theAxis] +
-          aBndBox.CornerMax()[theAxis]) * 0.5;
-}
+    if (anIndex != 0)
+    {
+      const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
 
-//=======================================================================
-// function : Swap
-// purpose  : Swaps items with indexes theIndex1 and theIndex2 in the set
-//=======================================================================
-void SelectMgr_SelectableObjectSet::Swap (const Standard_Integer theIndex1,
-                                          const Standard_Integer theIndex2)
-{
-  const Standard_Integer aIndex1 = theIndex1 + 1;
-  const Standard_Integer aIndex2 = theIndex2 + 1;
+      if (anIndex != aSize)
+      {
+        myObjects[aSubsetIdx].Swap (anIndex, aSize);
+      }
 
-  Handle(SelectMgr_SelectableObject) anObject1 = myObjects.FindKey (aIndex1);
-  Handle(SelectMgr_SelectableObject) anObject2 = myObjects.FindKey (aIndex2);
+      myObjects[aSubsetIdx].RemoveLast();
+      myIsDirty[aSubsetIdx] = Standard_True;
 
-  myObjects.Substitute (aIndex1, EMPTY_OBJ);
-  myObjects.Substitute (aIndex2, anObject1);
-  myObjects.Substitute (aIndex1, anObject2);
+      return Standard_True;
+    }
+  }
+
+  return Standard_False;
 }
 
-//=======================================================================
-// function : Size
-// purpose  : Returns size of objects set
-//=======================================================================
-Standard_Integer SelectMgr_SelectableObjectSet::Size() const
+//=============================================================================
+// Function: ChangeSubset
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::ChangeSubset (const Handle(SelectMgr_SelectableObject)& theObject)
 {
-  return myObjects.Size();
+  // do not do anything is object is not in the map
+  const Standard_Integer aCurrSubsetIdx = currentSubset (theObject);
+
+  if (aCurrSubsetIdx < 0)
+  {
+    return;
+  }
+
+  // check whether the subset need to be changed at all
+  const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
+
+  if (aCurrSubsetIdx == aSubsetIdx)
+  {
+    return;
+  }
+
+  // replace object in the maps
+  Remove (theObject);
+  Append (theObject);
 }
 
-//=======================================================================
-// function : GetObjectById
-// purpose  : Returns object from set by theIndex given
-//=======================================================================
-const Handle(SelectMgr_SelectableObject)& SelectMgr_SelectableObjectSet::GetObjectById (const Standard_Integer theIndex) const
+//=============================================================================
+// Function: UpdateBVH
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::UpdateBVH (const Handle(Graphic3d_Camera)& theCamera,
+                                               const Graphic3d_Mat4d& theProjectionMat,
+                                               const Graphic3d_Mat4d& theWorldViewMat,
+                                               const Graphic3d_WorldViewProjState& theViewState,
+                                               const Standard_Integer theViewportWidth,
+                                               const Standard_Integer theViewportHeight)
 {
-  return myObjects.FindKey (theIndex + 1);
+  // -----------------------------------------
+  // check and update 3D BVH tree if necessary
+  // -----------------------------------------
+  if (!IsEmpty (BVHSubset_3d) && myIsDirty[BVHSubset_3d])
+  {
+    // construct adaptor over private fields to provide direct access for the BVH builder
+    BVHBuilderAdaptorRegular anAdaptor (myObjects[BVHSubset_3d]);
+
+    // update corresponding BVH tree data structure
+    myBuilder[BVHSubset_3d]->Build (&anAdaptor, myBVH[BVHSubset_3d].get(), anAdaptor.Box());
+
+    // release dirty state
+    myIsDirty[BVHSubset_3d] = Standard_False;
+  }
+
+  if (!theCamera.IsNull())
+  {
+    const Standard_Boolean isWindowSizeChanged =
+      (myLastHeight != theViewportHeight) || (myLastWidth != theViewportWidth);
+
+    // -----------------------------------------------------
+    // check and update 3D persistence BVH tree if necessary
+    // -----------------------------------------------------
+    if (!IsEmpty (BVHSubset_3dPersistent) &&
+         (myIsDirty[BVHSubset_3dPersistent] || myLastViewState.IsChanged (theViewState) || isWindowSizeChanged))
+    {
+      // construct adaptor over private fields to provide direct access for the BVH builder
+      BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_3dPersistent],
+        theCamera, theProjectionMat, theWorldViewMat, theViewportWidth, theViewportHeight);
+
+      // update corresponding BVH tree data structure
+      myBuilder[BVHSubset_3dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_3dPersistent].get(), anAdaptor.Box());
+    }
+
+    // -----------------------------------------------------
+    // check and update 2D persistence BVH tree if necessary
+    // -----------------------------------------------------
+    if (!IsEmpty (BVHSubset_2dPersistent) &&
+         (myIsDirty[BVHSubset_2dPersistent] || myLastViewState.IsProjectionChanged (theViewState) || isWindowSizeChanged))
+    {
+      // construct adaptor over private fields to provide direct access for the BVH builder
+      BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_2dPersistent],
+        theCamera, theProjectionMat, SelectMgr_SelectableObjectSet_THE_IDENTITY_MAT, theViewportWidth, theViewportHeight);
+
+      // update corresponding BVH tree data structure
+      myBuilder[BVHSubset_2dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_2dPersistent].get(), anAdaptor.Box());
+    }
+
+    // release dirty state for every subset
+    myIsDirty[BVHSubset_3dPersistent] = Standard_False;
+    myIsDirty[BVHSubset_2dPersistent] = Standard_False;
+
+    // keep last view state
+    myLastViewState = theViewState;
+  }
+
+  // keep last window state
+  myLastWidth  = theViewportWidth;
+  myLastHeight = theViewportHeight;
 }
 
-//=======================================================================
-// function : Contains
-// purpose  : Returns true if this objects set contains theObject given
-//=======================================================================
-Standard_Boolean SelectMgr_SelectableObjectSet::Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
+//=============================================================================
+// Function: MarkDirty
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::MarkDirty()
 {
-  return myObjects.Contains (theObject);
+  myIsDirty[BVHSubset_3d]           = Standard_True;
+  myIsDirty[BVHSubset_3dPersistent] = Standard_True;
+  myIsDirty[BVHSubset_2dPersistent] = Standard_True;
 }