0030686: Visualization, SelectMgr_ViewerSelector - sorting issues of transformation...
[occt.git] / src / SelectMgr / SelectMgr_ViewerSelector.cxx
index 31210be..0099563 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-// Modified by  ...
-//              ROB JAN/07/98 : Improve Storage of detected entities
-//              AGV OCT/23/03 : Optimize the method SortResult() (OCC4201)
+#include <SelectMgr_ViewerSelector.hxx>
 
-#include <SelectMgr_ViewerSelector.ixx>
-#include <SelectMgr_CompareResults.hxx>
-#include <gp_Pnt2d.hxx>
+#include <BVH_Tree.hxx>
+#include <gp_GTrsf.hxx>
 #include <gp_Pnt.hxx>
-#include <gp_Lin.hxx>
-#include <Bnd_HArray1OfBox2d.hxx>
-#include <Bnd_Array1OfBox2d.hxx>
+#include <OSD_Environment.hxx>
 #include <Precision.hxx>
-#include <TColStd_Array1OfInteger.hxx>
-#include <TCollection_AsciiString.hxx>
-#include <NCollection_DataMap.hxx>
 #include <SelectBasics_EntityOwner.hxx>
-#include <SelectBasics_ListIteratorOfListOfBox2d.hxx>
 #include <SelectBasics_SensitiveEntity.hxx>
-#include <SelectBasics_ListOfBox2d.hxx>
-#include <SelectBasics_PickArgs.hxx>
-#include <SelectMgr_DataMapIteratorOfDataMapOfIntegerSensitive.hxx>
-#include <SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation.hxx>
+#include <SelectBasics_PickResult.hxx>
+#include <SelectMgr_EntityOwner.hxx>
 #include <SelectMgr_SortCriterion.hxx>
-#include <SortTools_QuickSortOfInteger.hxx>
-#include <OSD_Environment.hxx>
+#include <SelectMgr_SensitiveEntitySet.hxx>
+#include <TColStd_Array1OfInteger.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TColStd_HArray1OfInteger.hxx>
+#include <TColStd_ListOfInteger.hxx>
 
-static Standard_Boolean SelectDebugModeOnVS()
-{
-  static Standard_Integer isDebugMode( -1 );
-  if ( isDebugMode < 0 ) {
-    isDebugMode = 1;
-    OSD_Environment selectdb("SELDEBUGMODE");
-    if ( selectdb.Value().IsEmpty() )
-      isDebugMode = 0;
-  }
-  return ( isDebugMode != 0 );
-}
+#include <algorithm>
 
-namespace
-{
-  // container to store depth limits in collection map
-  struct SelectMgr_DepthRange
-  {
-    Standard_Real DepthMin;
-    Standard_Real DepthMax;
-    Standard_Boolean IsEmpty() const { return (DepthMin == DepthMax); }
+IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_ViewerSelector, Standard_Transient)
 
-    void Common (const SelectMgr_DepthRange& theOther)
+namespace {
+  // Comparison operator for sorting selection results
+  class CompareResults
+  {
+  public:
+   
+    CompareResults (const SelectMgr_IndexedDataMapOfOwnerCriterion& aMapOfCriterion)
+      : myMapOfCriterion (aMapOfCriterion)
     {
-      if (theOther.DepthMin > DepthMax || theOther.DepthMax < DepthMin)
-      {
-        DepthMin = RealFirst();
-        DepthMax = RealLast();
-        return;
-      }
+    }
 
-      DepthMin = Max (DepthMin, theOther.DepthMin);
-      DepthMax = Min (DepthMax, theOther.DepthMax);
+    Standard_Boolean operator() (Standard_Integer theLeft, Standard_Integer theRight) const
+    {
+      return myMapOfCriterion.FindFromIndex(theLeft) > myMapOfCriterion.FindFromIndex(theRight);
     }
+
+  private:
+    void operator = (const CompareResults&);
+
+  private:
+    const SelectMgr_IndexedDataMapOfOwnerCriterion&  myMapOfCriterion;
   };
-};
 
-//==================================================
-// Function: Initialize
-// Purpose :
-//==================================================
-SelectMgr_ViewerSelector::SelectMgr_ViewerSelector():
-toupdate(Standard_True),
-tosort(Standard_True),
-preferclosest(Standard_True),
-mytolerance(0.),
-myCurRank(0),
-myLastPickArgs (0.0, 0.0, 0.0, RealFirst(), RealLast(), gp_Lin()),
-lastx (Precision::Infinite()),
-lasty (Precision::Infinite()),
-myUpdateSortPossible( Standard_True )
-{
+  static const Graphic3d_Mat4d SelectMgr_ViewerSelector_THE_IDENTITY_MAT;
 }
 
-
-//==================================================
-// Function: Activate
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::
-Activate (const Handle(SelectMgr_Selection)& aSelection,
-          const Standard_Boolean AutomaticProj)
+//=======================================================================
+// function : updatePoint3d
+// purpose  :
+//=======================================================================
+void SelectMgr_ViewerSelector::updatePoint3d (SelectMgr_SortCriterion& theCriterion,
+                                              const SelectBasics_PickResult& thePickResult,
+                                              const Handle(SelectBasics_SensitiveEntity)& theEntity,
+                                              const gp_GTrsf& theInversedTrsf,
+                                              const SelectMgr_SelectingVolumeManager& theMgr) const
 {
-  tosort = Standard_True;
+  if (theMgr.GetActiveSelectionType() != SelectMgr_SelectingVolumeManager::Point)
+  {
+    return;
+  }
 
-  if (!myselections.IsBound(aSelection))
+  if (thePickResult.HasPickedPoint())
   {
-    myselections.Bind(aSelection,0);
+    theCriterion.Point = thePickResult.PickedPoint();
   }
-  else if (myselections(aSelection)!=0)
+  else if (!thePickResult.IsValid())
   {
-    myselections(aSelection)= 0;
+    theCriterion.Point = thePickResult.PickedPoint();
+    return;
+  }
+  else
+  {
+    theCriterion.Point = theMgr.DetectedPoint (theCriterion.Depth);
+  }
+
+  gp_GTrsf anInvTrsf = theInversedTrsf;
+  if (theCriterion.Entity->HasInitLocation())
+  {
+    anInvTrsf = theCriterion.Entity->InvInitLocation() * anInvTrsf;
+  }
+  if (anInvTrsf.Form() != gp_Identity)
+  {
+    anInvTrsf.Inverted().Transforms (theCriterion.Point.ChangeCoord());
   }
-  if(AutomaticProj)
-    Convert(aSelection);
-}
 
+  if (mySelectingVolumeMgr.Camera().IsNull())
+  {
+    theCriterion.Tolerance = theEntity->SensitivityFactor() / 33.0;
+  }
+  else if (mySelectingVolumeMgr.Camera()->IsOrthographic())
+  {
+    theCriterion.Tolerance = myCameraScale * theEntity->SensitivityFactor();
+  }
+  else
+  {
+    const Standard_Real aDistFromEye = Abs ((theCriterion.Point.XYZ() - myCameraEye.XYZ()).Dot (myCameraDir.XYZ()));
+    theCriterion.Tolerance = aDistFromEye * myCameraScale * theEntity->SensitivityFactor();
+  }
+}
 
 //==================================================
-// Function: Deactivate
+// Function: Initialize
 // Purpose :
 //==================================================
-void SelectMgr_ViewerSelector::
-Deactivate (const Handle(SelectMgr_Selection)& aSel)
+SelectMgr_ViewerSelector::SelectMgr_ViewerSelector():
+preferclosest(Standard_True),
+myToUpdateTolerance (Standard_True),
+myCameraScale (1.0),
+myCurRank (0),
+myIsLeftChildQueuedFirst (Standard_False),
+myEntityIdx (0)
 {
-  if(myselections.IsBound(aSel))
-  {myselections(aSel)=1;
-  tosort = Standard_True;}
+  myEntitySetBuilder = new BVH_BinnedBuilder<Standard_Real, 3, 4> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True);
 }
 
-
-
-
-
 //==================================================
-// Function: Sleep
+// Function: Activate
 // Purpose :
 //==================================================
-void SelectMgr_ViewerSelector::Sleep()
-{ SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It(myselections);
-for (;It.More();It.Next()){
-  if(It.Value()==0) myselections(It.Key())= 2;
-}
-UpdateSort();
-}
-//=======================================================================
-//function : Sleep
-//purpose  :
-//=======================================================================
-
-void SelectMgr_ViewerSelector::Sleep(const Handle(SelectMgr_SelectableObject)& SO)
+void SelectMgr_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSelection)
 {
+  for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
+  {
+    aSelEntIter.Value()->SetActiveForSelection();
+  }
 
-  for(SO->Init();SO->More();SO->Next()){
-    if(myselections.IsBound(SO->CurrentSelection())){
-      myselections(SO->CurrentSelection()) = 2;
-    }
+  if (theSelection->GetSelectionState() != SelectMgr_SOS_Activated)
+  {
+    theSelection->SetSelectionState (SelectMgr_SOS_Activated);
+
+    myTolerances.Add (theSelection->Sensitivity());
+    myToUpdateTolerance = Standard_True;
   }
-  UpdateSort();
 }
 
-
 //==================================================
-// Function: Awake
+// Function: Deactivate
 // Purpose :
 //==================================================
-void SelectMgr_ViewerSelector::Awake(const Standard_Boolean AutomaticProj)
+void SelectMgr_ViewerSelector::Deactivate (const Handle(SelectMgr_Selection)& theSelection)
 {
-  SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It(myselections);
-  for (;It.More();It.Next()){
-    if(It.Value()==2)
-      myselections(It.Key())=0;
-    if(AutomaticProj)
-      UpdateConversion();
-    UpdateSort();
+  for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
+  {
+    aSelEntIter.Value()->ResetSelectionActiveStatus();
   }
-}
 
-void SelectMgr_ViewerSelector::Awake(const Handle(SelectMgr_SelectableObject)& SO,
-                                     const Standard_Boolean AutomaticProj)
-{
-  for(SO->Init();SO->More();SO->Next()){
-    if(myselections.IsBound(SO->CurrentSelection())){
-      myselections(SO->CurrentSelection()) =0;
-      if(AutomaticProj)
-        Convert(SO->CurrentSelection());
-    }
-  }
+  if (theSelection->GetSelectionState() == SelectMgr_SOS_Activated)
+  {
+    theSelection->SetSelectionState (SelectMgr_SOS_Deactivated);
 
+    myTolerances.Decrement (theSelection->Sensitivity());
+    myToUpdateTolerance = Standard_True;
+  }
 }
+
 //==================================================
 // Function: Clear
 // Purpose :
 //==================================================
 void SelectMgr_ViewerSelector::Clear()
 {
-  myentities.Clear();
-  myselections.Clear();
-  toupdate = Standard_True;
-  tosort = Standard_True;
   mystored.Clear();
-  lastx = Precision::Infinite();
-  lasty = Precision::Infinite();
-
 }
 
-//==================================================
-// Function: UpdateConversion
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::UpdateConversion()
+//=======================================================================
+// function: isToScaleFrustum
+// purpose : Checks if the entity given requires to scale current selecting frustum
+//=======================================================================
+Standard_Boolean SelectMgr_ViewerSelector::isToScaleFrustum (const Handle(SelectBasics_SensitiveEntity)& theEntity)
 {
-  if( SelectDebugModeOnVS() )
-    cout<<"\t\t\t\t\t SelectMgr_VS::UpdateConversion"<<endl;
-
-  SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It(myselections);
-  for(;It.More();It.Next()){
-    //Convert only if active...
-    if(It.Value()==0)
-      Convert(It.Key());
-  }
-  toupdate = Standard_False;
-  tosort = Standard_True;
+  return mySelectingVolumeMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Point
+    && sensitivity (theEntity) < myTolerances.Tolerance();
 }
 
-
-//==================================================
-// Function: Convert
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::
-Convert (const Handle(SelectMgr_Selection)& /*aSel*/) {tosort=Standard_True;}
-
-
-//==================================================
-// Function: UpdateSort
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::UpdateSort()
+//=======================================================================
+// function: sensitivity
+// purpose : In case if custom tolerance is set, this method will return sum of entity
+//           sensitivity and custom tolerance.
+//=======================================================================
+Standard_Integer SelectMgr_ViewerSelector::sensitivity (const Handle(SelectBasics_SensitiveEntity)& theEntity) const
 {
-  if( !myUpdateSortPossible )
-    return;
+  return myTolerances.IsCustomTolSet() ?
+    theEntity->SensitivityFactor() + myTolerances.CustomTolerance() : theEntity->SensitivityFactor();
+}
 
-  if( SelectDebugModeOnVS() )
-    cout<<"\t\t\t\t\t SelectMgr_ViewerSelector::UpdateSort()"<<endl;
-  mystored.Clear();
-  myentities.Clear();
-  myactivenb = NbBoxes();
-
-  if(myactivenb > 0) {
-    Standard_Boolean NoClip = myclip.IsVoid();
-    Handle(Bnd_HArray1OfBox2d) refToTab = new Bnd_HArray1OfBox2d(1,myactivenb);
-    Bnd_Array1OfBox2d & tab = refToTab->ChangeArray1();
-    Standard_Real xmin=Precision::Infinite(),ymin=Precision::Infinite(),xmax=-Precision::Infinite(),ymax=-Precision::Infinite();
-    Standard_Real curxmin,curymin,curxmax,curymax;
-    //    Standard_Integer boxindex=0,indexsel=0,indexprim=0;
-    Standard_Integer boxindex=0;
-
-    SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It;
-    SelectBasics_ListIteratorOfListOfBox2d LIt;
-    Handle(SelectMgr_Selection) curEntity;
-    Standard_Real ScaleFactor;
-    for(It.Initialize(myselections);It.More();It.Next()){
-      if(It.Value()== 0)
-      { curEntity = It.Key();
-      for(curEntity->Init();curEntity->More();curEntity->Next())
+//=======================================================================
+// function: checkOverlap
+// purpose : Internal function that checks if a particular sensitive
+//           entity theEntity overlaps current selecting volume precisely
+//=======================================================================
+void SelectMgr_ViewerSelector::checkOverlap (const Handle(SelectBasics_SensitiveEntity)& theEntity,
+                                             const gp_GTrsf& theInversedTrsf,
+                                             SelectMgr_SelectingVolumeManager& theMgr)
+{
+  Handle(SelectMgr_EntityOwner) anOwner (Handle(SelectMgr_EntityOwner)::DownCast (theEntity->OwnerId()));
+  Handle(SelectMgr_SelectableObject) aSelectable;
+  Standard_Boolean toRestoresViewClipEnabled = Standard_False;
+  if (!anOwner.IsNull())
+  {
+    aSelectable = anOwner->Selectable();
+  }
+  if (!aSelectable.IsNull())
+  {
+    if (!aSelectable->ClipPlanes().IsNull()
+      && aSelectable->ClipPlanes()->ToOverrideGlobal())
+    {
+      theMgr.SetViewClippingEnabled (Standard_False);
+      toRestoresViewClipEnabled = Standard_True;
+    }
+    else if (!aSelectable->TransformPersistence().IsNull())
+    {
+      if (aSelectable->TransformPersistence()->IsZoomOrRotate()
+      && !theMgr.ViewClipping().IsNull())
       {
-        static SelectBasics_ListOfBox2d BoxList;
-        BoxList.Clear();
-        curEntity->Sensitive()->Areas(BoxList);
-        ScaleFactor = curEntity->Sensitive()->SensitivityFactor();
-
-
-        for(LIt.Initialize(BoxList);LIt.More();LIt.Next()){
-          boxindex++;
-
-          tab.SetValue(boxindex,LIt.Value());
-
-          tab(boxindex).SetGap(mytolerance*ScaleFactor);
-          myentities.Bind(boxindex,curEntity->Sensitive());
-          if(NoClip){
-            if (!tab(boxindex).IsVoid()) {
-              tab(boxindex).Get(curxmin,curymin,curxmax,curymax);
-              if(curxmin<xmin) xmin=curxmin;
-              if(curxmax>xmax) xmax=curxmax;
-              if(curymin<ymin) ymin=curymin;
-              if(curymax>ymax) ymax=curymax;
-            }
+        // Zoom/rotate persistence object lives in two worlds at the same time.
+        // Global clipping planes can not be trivially applied without being converted
+        // into local space of transformation persistence object.
+        // As more simple alternative - just clip entire object by its anchor point defined in the world space.
+        const Handle(Graphic3d_SequenceOfHClipPlane)& aViewPlanes = theMgr.ViewClipping();
+
+        const gp_Pnt anAnchor = aSelectable->TransformPersistence()->AnchorPoint();
+        for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (*aViewPlanes); aPlaneIt.More(); aPlaneIt.Next())
+        {
+          const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
+          if (!aPlane->IsOn())
+          {
+            continue;
+          }
+
+          const Graphic3d_Vec4d aCheckPnt (anAnchor.X(), anAnchor.Y(), anAnchor.Z(), 1.0);
+          if (aPlane->ProbePoint (aCheckPnt) == Graphic3d_ClipState_Out)
+          {
+            return;
           }
         }
       }
-      }
-    }
-
 
-    if(NoClip) {myclip.SetVoid();myclip.Update(xmin,ymin,xmax,ymax);}
-    myselector.Initialize(myclip, mytolerance,refToTab);
-    tosort = Standard_False;
-    if(NoClip) myclip.SetVoid();
+      theMgr.SetViewClippingEnabled (Standard_False);
+      toRestoresViewClipEnabled = Standard_True;
+    }
   }
-}
-
 
-//==================================================
-// Function: Remove
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::
-Remove(const Handle(SelectMgr_Selection)& aSel)
-{
-  if (myselections.IsBound(aSel))
-  { myselections.UnBind(aSel);
-  tosort = Standard_True;
+  SelectBasics_PickResult aPickResult;
+  const Standard_Boolean isMatched = theEntity->Matches(theMgr, aPickResult);
+  if (toRestoresViewClipEnabled)
+  {
+    theMgr.SetViewClippingEnabled (Standard_True);
   }
-}
 
-//==================================================
-// Function: SetSensitivity
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::SetSensitivity(const Standard_Real aVal)
-{mytolerance = aVal;
-tosort=Standard_True;}
-
-//==================================================
-// Function: SetClipping
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::SetClipping(const Standard_Real Xc,
-                                           const Standard_Real Yc,
-                                           const Standard_Real Height,
-                                           const Standard_Real Width)
-{
-  Bnd_Box2d aClip;
-  aClip.Set(gp_Pnt2d(Xc-Width/2, Yc-Height/2));
-  aClip.Add(gp_Pnt2d(Xc+Width/2, Yc+Height/2));
-  myclip = aClip;
-  tosort = Standard_True;
-}
+  if (!isMatched
+    || anOwner.IsNull())
+  {
+    return;
+  }
 
+  if (HasDepthClipping (anOwner)
+  && !aSelectable.IsNull()
+  &&  theMgr.GetActiveSelectionType() == SelectMgr_SelectingVolumeManager::Point)
+  {
+    Standard_Boolean isClipped = mySelectingVolumeMgr.IsClipped (*aSelectable->ClipPlanes(),
+                                                                  aPickResult.Depth());
+    if (isClipped)
+      return;
+  }
 
-//==================================================
-// Function: SetClipping
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::SetClipping (const Bnd_Box2d& abox)
-{myclip = abox;
-tosort = Standard_True;
-}
+  SelectMgr_SortCriterion aCriterion;
+  myZLayerOrderMap.Find (!aSelectable.IsNull() ? aSelectable->ZLayer() : Graphic3d_ZLayerId_Default, aCriterion.ZLayerPosition);
+  aCriterion.Entity    = theEntity;
+  aCriterion.Priority  = anOwner->Priority();
+  aCriterion.Depth     = aPickResult.Depth();
+  aCriterion.MinDist   = aPickResult.DistToGeomCenter();
+  aCriterion.ToPreferClosest = preferclosest;
 
-//==================================================
-// Function: InitSelect
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::InitSelect(const Standard_Real Xr,
-                                          const Standard_Real Yr)
-{
-  Standard_OutOfRange_Raise_if(Abs(Xr-Precision::Infinite())<=Precision::Confusion() ||
-    Abs(Yr-Precision::Infinite())<=Precision::Confusion(),
-    " Infinite values in IniSelect");
-  mystored.Clear();
-  myprim.Clear();
-  if (toupdate) UpdateConversion();
-  if (tosort) UpdateSort();
-  if(myactivenb!=0){
-    myselector.InitSelect(Xr,Yr);
-    if(myselector.More()) {lastx = Xr;lasty=Yr;}
-    LoadResult();
+  if (SelectMgr_SortCriterion* aPrevCriterion = mystored.ChangeSeek (anOwner))
+  {
+    ++aPrevCriterion->NbOwnerMatches;
+    aCriterion.NbOwnerMatches = aPrevCriterion->NbOwnerMatches;
+    if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Box)
+    {
+      if (aCriterion > *aPrevCriterion)
+      {
+        updatePoint3d (aCriterion, aPickResult, theEntity, theInversedTrsf, theMgr);
+        *aPrevCriterion = aCriterion;
+      }
+    }
   }
-}
-
-//==================================================
-// Function: InitSelect
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::InitSelect(const Bnd_Box2d& aBox)
-{
-  mystored.Clear();
-  if(toupdate) UpdateConversion();
-  if (tosort) UpdateSort();
-  if (myactivenb!=0){
-    myselector.InitSelect(aBox);
-    LoadResult(aBox);
+  else
+  {
+    aCriterion.NbOwnerMatches = 1;
+    updatePoint3d (aCriterion, aPickResult, theEntity, theInversedTrsf, theMgr);
+    mystored.Add (anOwner, aCriterion);
   }
 }
 
-//==================================================
-// Function: InitSelect
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::InitSelect(const Standard_Real Xmin,
-                                          const Standard_Real Ymin,
-                                          const Standard_Real Xmax,
-                                          const Standard_Real Ymax)
-{
-  mystored.Clear();
-
-  if (toupdate) UpdateConversion();
-  if (tosort)   UpdateSort();
-  if (myactivenb!=0){
-    Bnd_Box2d aBox;
-    aBox.Update(Xmin,Ymin,Xmax,Ymax);
-    myselector.InitSelect(aBox);
-    LoadResult(aBox);
+//=======================================================================
+// function: computeFrustum
+// purpose : Internal function that checks if a current selecting frustum
+//           needs to be scaled and transformed for the entity and performs
+//           necessary calculations
+//=======================================================================
+void SelectMgr_ViewerSelector::computeFrustum (const Handle(SelectBasics_SensitiveEntity)& theEnt,
+                                               const SelectMgr_SelectingVolumeManager&     theMgr,
+                                               const gp_GTrsf&                             theInvTrsf,
+                                               SelectMgr_FrustumCache&                     theCachedMgrs,
+                                               SelectMgr_SelectingVolumeManager&           theResMgr)
+{
+  Standard_Integer aScale = isToScaleFrustum (theEnt) ? sensitivity (theEnt) : 1;
+  const gp_GTrsf aTrsfMtr = theEnt->HasInitLocation() ? theEnt->InvInitLocation() * theInvTrsf : theInvTrsf;
+  const Standard_Boolean toScale = aScale != 1;
+  const Standard_Boolean toTransform = aTrsfMtr.Form() != gp_Identity;
+  if (toScale && toTransform)
+  {
+    theResMgr = theMgr.ScaleAndTransform (aScale, aTrsfMtr, NULL);
+  }
+  else if (toScale)
+  {
+    if (!theCachedMgrs.IsBound (aScale))
+    {
+      theCachedMgrs.Bind (aScale, theMgr.ScaleAndTransform (aScale, gp_Trsf(), NULL));
+    }
+    theResMgr = theCachedMgrs.Find (aScale);
+  }
+  else if (toTransform)
+  {
+    theResMgr = theMgr.ScaleAndTransform (1, aTrsfMtr, NULL);
   }
 }
 
-//==================================================
-// Function: InitSelect
-// Purpose : Polyline Selection
-//==================================================
-void SelectMgr_ViewerSelector::InitSelect(const TColgp_Array1OfPnt2d& aPoly)
-{
-  mystored.Clear();
+//=======================================================================
+// function: traverseObject
+// purpose : Internal function that checks if there is possible overlap
+//           between some entity of selectable object theObject and
+//           current selecting volume
+//=======================================================================
+void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_SelectableObject)& theObject,
+                                               const SelectMgr_SelectingVolumeManager& theMgr,
+                                               const Handle(Graphic3d_Camera)& theCamera,
+                                               const Graphic3d_Mat4d& theProjectionMat,
+                                               const Graphic3d_Mat4d& theWorldViewMat,
+                                               const Standard_Integer theViewportWidth,
+                                               const Standard_Integer theViewportHeight)
+{
+  Handle(SelectMgr_SensitiveEntitySet)& anEntitySet = myMapOfObjectSensitives.ChangeFind (theObject);
+  if (anEntitySet->Size() == 0)
+  {
+    return;
+  }
 
-  if (toupdate) UpdateConversion();
-  if (tosort)   UpdateSort();
-  if (myactivenb!=0){
-    // the Bnd boxes are used for the first time
-    Bnd_Box2d aBox;
-    Standard_Integer NbPnt = aPoly.Length();
-    Standard_Integer i;
-    for(i=1;i<=NbPnt;i++) {
-      aBox.Update(aPoly(i).X(),aPoly(i).Y());
+  const opencascade::handle<BVH_Tree<Standard_Real, 3> >& aSensitivesTree = anEntitySet->BVH();
+  gp_GTrsf aInversedTrsf;
+  if (theObject->HasTransformation() || !theObject->TransformPersistence().IsNull())
+  {
+    if (theObject->TransformPersistence().IsNull())
+    {
+      aInversedTrsf = theObject->InversedTransformation();
+    }
+    else
+    {
+      gp_GTrsf aTPers;
+      Graphic3d_Mat4d aMat = theObject->TransformPersistence()->Compute (theCamera, theProjectionMat, theWorldViewMat, theViewportWidth, theViewportHeight);
+
+      aTPers.SetValue (1, 1, aMat.GetValue (0, 0));
+      aTPers.SetValue (1, 2, aMat.GetValue (0, 1));
+      aTPers.SetValue (1, 3, aMat.GetValue (0, 2));
+      aTPers.SetValue (2, 1, aMat.GetValue (1, 0));
+      aTPers.SetValue (2, 2, aMat.GetValue (1, 1));
+      aTPers.SetValue (2, 3, aMat.GetValue (1, 2));
+      aTPers.SetValue (3, 1, aMat.GetValue (2, 0));
+      aTPers.SetValue (3, 2, aMat.GetValue (2, 1));
+      aTPers.SetValue (3, 3, aMat.GetValue (2, 2));
+      aTPers.SetTranslationPart (gp_XYZ (aMat.GetValue (0, 3), aMat.GetValue (1, 3), aMat.GetValue (2, 3)));
+
+      aInversedTrsf = (aTPers * gp_GTrsf (theObject->Transformation())).Inverted();
     }
-    myselector.InitSelect(aBox);
-    LoadResult(aPoly);
-    //    LoadResult(aBox);
   }
-}
 
+  SelectMgr_SelectingVolumeManager aMgr = aInversedTrsf.Form() != gp_Identity
+                                        ? theMgr.ScaleAndTransform (1, aInversedTrsf, NULL)
+                                        : theMgr;
 
-//==================================================
-// Function: LoadResult
-// Purpose : for the moment the size of the primitive
-//           is not taken into account in the search criteriai...
-//           The priority, the depth and the min. distance to CDG or Borders is taken...
-//==================================================
-void SelectMgr_ViewerSelector::LoadResult()
-{
-  if (myselector.More())
-  {
-    NCollection_DataMap<Handle(SelectMgr_EntityOwner), SelectMgr_DepthRange> aMapOfOwnerRanges;
+  SelectMgr_FrustumCache aScaledTrnsfFrustums;
 
-    // collect information on depth clipping from implementations
-    gp_Lin aPickLine = PickingLine (lastx, lasty);
-    SelectMgr_DepthRange aViewDRange;
-    DepthClipping (lastx, lasty, aViewDRange.DepthMin, aViewDRange.DepthMax);
+  Standard_Integer aNode = 0; // a root node
+  if (!aMgr.Overlaps (aSensitivesTree->MinPoint (0),
+                      aSensitivesTree->MaxPoint (0)))
+  {
+    return;
+  }
 
-    Standard_Real aDMin;
-    Standard_Real aDepthMin;
-    Standard_Integer aNument;
+  const Standard_Integer aFirstStored = mystored.Extent() + 1;
 
-    if (!aViewDRange.IsEmpty())
+  Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
+  Standard_Integer aHead = -1;
+  for (;;)
+  {
+    if (!aSensitivesTree->IsOuter (aNode))
     {
-      for (; myselector.More(); myselector.Next())
+      const Standard_Integer aLeftChildIdx  = aSensitivesTree->Child<0> (aNode);
+      const Standard_Integer aRightChildIdx = aSensitivesTree->Child<1> (aNode);
+      const Standard_Boolean isLeftChildIn  =  aMgr.Overlaps (aSensitivesTree->MinPoint (aLeftChildIdx),
+                                                              aSensitivesTree->MaxPoint (aLeftChildIdx));
+      const Standard_Boolean isRightChildIn = aMgr.Overlaps (aSensitivesTree->MinPoint (aRightChildIdx),
+                                                             aSensitivesTree->MaxPoint (aRightChildIdx));
+      if (isLeftChildIn
+          && isRightChildIn)
       {
-        aNument = myselector.Value();
-
-        const Handle(SelectBasics_SensitiveEntity)& SE = myentities (aNument);
-        const Handle(SelectMgr_EntityOwner)& anOwner =
-          Handle(SelectMgr_EntityOwner)::DownCast (SE->OwnerId());
-
-        // compute depth range for sensitives of entity owner
-        SelectMgr_DepthRange anEntityDRange (aViewDRange);
-        if (!anOwner.IsNull() && HasDepthClipping (anOwner) && !aMapOfOwnerRanges.Find (anOwner, anEntityDRange))
-        {
-          // get depth range from implementation
-          SelectMgr_DepthRange aGetRange;
-          DepthClipping (lastx, lasty, anOwner, aGetRange.DepthMin, aGetRange.DepthMax);
-
-          // concatenate and remember depth range for pefromance increase
-          anEntityDRange.Common (aGetRange);
-          aMapOfOwnerRanges.Bind (anOwner, anEntityDRange);
-        }
-
-        if (anEntityDRange.IsEmpty())
+        aNode = aLeftChildIdx;
+        ++aHead;
+        aStack[aHead] = aRightChildIdx;
+      }
+      else if (isLeftChildIn
+        || isRightChildIn)
+      {
+        aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
+      }
+      else
+      {
+        if (aHead < 0)
         {
-          continue;
+          break;
         }
 
-        myLastPickArgs = SelectBasics_PickArgs (lastx, lasty, mytolerance,
-                                                anEntityDRange.DepthMin,
-                                                anEntityDRange.DepthMax,
-                                                aPickLine);
-
-        if (SE->Matches (myLastPickArgs, aDMin, aDepthMin))
+        aNode = aStack[aHead];
+        --aHead;
+      }
+    }
+    else
+    {
+      Standard_Integer aStartIdx = aSensitivesTree->BegPrimitive (aNode);
+      Standard_Integer anEndIdx = aSensitivesTree->EndPrimitive (aNode);
+      for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
+      {
+        const Handle(SelectMgr_SensitiveEntity)& aSensitive = anEntitySet->GetSensitiveById (anIdx);
+        if (aSensitive->IsActiveForSelection())
         {
-          if (!anOwner.IsNull())
-          {
-            Standard_Integer aPrior = anOwner->Priority();
-
-            SelectMgr_SortCriterion SC (aPrior, aDepthMin, aDMin, mytolerance, preferclosest);
-            if (mystored.Contains (anOwner))
-            {
-              SelectMgr_SortCriterion& Crit = mystored.ChangeFromKey (anOwner);
-              if (SC > Crit)
-              {
-                Crit = SC;
-
-                // update previously recorded entity for this owner
-                for (int i = 1; i <= myprim.Length(); i++)
-                {
-                  if (myentities (myprim(i))->OwnerId() == anOwner)
-                  {
-                    myprim.SetValue (i, aNument);
-                    break;
-                  }
-                }
-              }
-            }
-            else
-            {
-              mystored.Add (anOwner, SC);
-
-              // record entity
-              myprim.Append (aNument);
-            }
-          }
+          const Handle(SelectBasics_SensitiveEntity)& anEnt = aSensitive->BaseSensitive();
+          SelectMgr_SelectingVolumeManager aTmpMgr = aMgr;
+          computeFrustum (anEnt, theMgr, aInversedTrsf, aScaledTrnsfFrustums, aTmpMgr);
+          checkOverlap (anEnt, aInversedTrsf, aTmpMgr);
         }
       }
-    }
+      if (aHead < 0)
+      {
+        break;
+      }
 
-    SortResult();
+      aNode = aStack[aHead];
+      --aHead;
+    }
   }
 
-  if (SelectDebugModeOnVS())
+  // in case of Box/Polyline selection - keep only Owners having all Entities detected
+  if (mySelectingVolumeMgr.IsOverlapAllowed()
+  || (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Box
+   && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Polyline))
   {
-    cout<<"\tSelectMgr_VS:: Resultat du move"<<endl;
-    cout<<"\tNb Detectes :"<<mystored.Extent()<<endl;
+    return;
+  }
 
-    for(Standard_Integer i=1; i<=mystored.Extent(); i++)
+  for (Standard_Integer aStoredIter = mystored.Extent(); aStoredIter >= aFirstStored; --aStoredIter)
+  {
+    const SelectMgr_SortCriterion& aCriterion = mystored.FindFromIndex (aStoredIter);
+    const Handle(SelectBasics_EntityOwner)& anOwner = aCriterion.Entity->OwnerId();
+    Standard_Integer aNbOwnerEntities = 0;
+    for (SelectMgr_IndexedMapOfHSensitive::Iterator aSensIter (anEntitySet->Sensitives()); aSensIter.More(); aSensIter.Next())
     {
-      const SelectMgr_SortCriterion& Crit = mystored (myIndexes->Value(i));
-      cout << "\t" << i << " - Prior" << Crit.Priority()
-           << " - prof :" << Crit.Depth()
-           << "  - Dist. :" << Crit.MinDist() << endl;
+      if (aSensIter.Value()->BaseSensitive()->OwnerId() == anOwner)
+      {
+        if (++aNbOwnerEntities > aCriterion.NbOwnerMatches)
+        {
+          // Remove from index map.
+          // Considering NCollection_IndexedDataMap implementation, the values for lower indexes will not be modified.
+          // Hence, just keep iterating in backward direction.
+          mystored.RemoveFromIndex (aStoredIter);
+          break;
+        }
+      }
     }
   }
 }
 
-//==================================================
-// Function: LoadResult
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::LoadResult(const Bnd_Box2d& abox)
+//=======================================================================
+// function: TraverseSensitives
+// purpose : Traverses BVH containing all added selectable objects and
+//           finds candidates for further search of overlap
+//=======================================================================
+void SelectMgr_ViewerSelector::TraverseSensitives()
 {
   mystored.Clear();
 
-  //  Handle(SelectMgr_EntityOwner)  OWNR;
-  if(myselector.More())
-  { Standard_Real xmin,ymin,xmax,ymax;
-  abox.Get(xmin,ymin,xmax,ymax);
-  //      Standard_Boolean Found(Standard_False);
-  //      Standard_Real DMin=0.;
-  Standard_Integer nument;
-  for(;myselector.More();myselector.Next()){
-    nument = myselector.Value();
-    const Handle(SelectBasics_SensitiveEntity)& SE = myentities(nument);
-    if (SE->Matches(xmin,ymin,xmax,ymax,0.0)){
-      const Handle(SelectBasics_EntityOwner)& OWNR = SE->OwnerId();
-      if(!OWNR.IsNull()){
-        if(!mystored.Contains(OWNR)){
-          SelectMgr_SortCriterion SC(OWNR->Priority(),Precision::Infinite(),
-            Precision::Infinite(),mytolerance,preferclosest);
-          mystored.Add(OWNR,SC);
-          myprim.Append(nument);
-        }
-      }
-    }
+  Standard_Integer aWidth;
+  Standard_Integer aHeight;
+  mySelectingVolumeMgr.WindowSize (aWidth, aHeight);
+  mySelectableObjects.UpdateBVH (mySelectingVolumeMgr.Camera(),
+                                 mySelectingVolumeMgr.ProjectionMatrix(),
+                                 mySelectingVolumeMgr.WorldViewMatrix(),
+                                 mySelectingVolumeMgr.WorldViewProjState(),
+                                 aWidth, aHeight);
+  const Handle(Graphic3d_Camera)& aCamera = mySelectingVolumeMgr.Camera();
+  if (!aCamera.IsNull())
+  {
+    myCameraEye = aCamera->Eye().XYZ();
+    myCameraDir = aCamera->Direction().XYZ();
+    myCameraScale = aCamera->IsOrthographic()
+                  ? aCamera->Scale()
+                  : 2.0 * Tan (aCamera->FOVy() * M_PI / 360.0);
+    const double aPixelSize = Max (1.0 / aWidth, 1.0 / aHeight);
+    myCameraScale *= aPixelSize;
   }
 
-  // do not parse in case of selection by elastic rectangle (BUG ANALYST)
-  if(mystored.IsEmpty()) return;
-  if(myIndexes.IsNull())
-    myIndexes = new TColStd_HArray1OfInteger(1,mystored.Extent());
-  else if(mystored.Extent() !=myIndexes->Length())
-    myIndexes = new TColStd_HArray1OfInteger (1,mystored.Extent());
-
-  // to work faster...
-  TColStd_Array1OfInteger& thearr = myIndexes->ChangeArray1();
-  for(Standard_Integer I=1;I<=mystored.Extent();I++)
-    thearr(I)=I;
-  }
-}
-//==================================================
-// Function: LoadResult
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::LoadResult(const TColgp_Array1OfPnt2d& aPoly)
-{
-  mystored.Clear();
-  Bnd_Box2d aBox;
-  Standard_Integer NbPnt = aPoly.Length();
-  Standard_Integer i;
-  for(i=1;i<=NbPnt;i++) {
-    aBox.Update(aPoly(i).X(),aPoly(i).Y());
-  }
-  Standard_Integer NB=0;
-  //  Handle(SelectMgr_EntityOwner)  OWNR;
-  if(myselector.More())
+  for (Standard_Integer aBVHSetIt = 0; aBVHSetIt < SelectMgr_SelectableObjectSet::BVHSubsetNb; ++aBVHSetIt)
   {
-    Standard_Integer nument;
-
-    for(;myselector.More();myselector.Next()){
-      NB++;
-      nument = myselector.Value();
-      const Handle(SelectBasics_SensitiveEntity)& SE = myentities(nument);
-      if (SE->Matches(aPoly,aBox,0.0)){
-        const Handle(SelectBasics_EntityOwner)& OWNR = SE->OwnerId();
-        if(!OWNR.IsNull()){
-          if(!mystored.Contains(OWNR)){
-            SelectMgr_SortCriterion SC(OWNR->Priority(),Precision::Infinite(),
-              Precision::Infinite(),mytolerance,preferclosest);
-            mystored.Add(OWNR,SC);
-            myprim.Append(nument);
+    SelectMgr_SelectableObjectSet::BVHSubset aBVHSubset =
+      static_cast<SelectMgr_SelectableObjectSet::BVHSubset> (aBVHSetIt);
+
+    if (mySelectableObjects.IsEmpty (aBVHSubset))
+    {
+      continue;
+    }
+
+    gp_GTrsf aTFrustum;
+
+    SelectMgr_SelectingVolumeManager aMgr (Standard_False);
+
+    // for 2D space selection transform selecting volumes to perform overap testing
+    // directly in camera's eye space omitting the camera position, which is not
+    // needed there at all
+    if (aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent)
+    {
+      const Graphic3d_Mat4d& aMat = mySelectingVolumeMgr.WorldViewMatrix();
+      aTFrustum.SetValue (1, 1, aMat.GetValue (0, 0));
+      aTFrustum.SetValue (1, 2, aMat.GetValue (0, 1));
+      aTFrustum.SetValue (1, 3, aMat.GetValue (0, 2));
+      aTFrustum.SetValue (2, 1, aMat.GetValue (1, 0));
+      aTFrustum.SetValue (2, 2, aMat.GetValue (1, 1));
+      aTFrustum.SetValue (2, 3, aMat.GetValue (1, 2));
+      aTFrustum.SetValue (3, 1, aMat.GetValue (2, 0));
+      aTFrustum.SetValue (3, 2, aMat.GetValue (2, 1));
+      aTFrustum.SetValue (3, 3, aMat.GetValue (2, 2));
+      aTFrustum.SetTranslationPart (gp_XYZ (aMat.GetValue (0, 3), aMat.GetValue (1, 3), aMat.GetValue (2, 3)));
+
+      // define corresponding frustum builder parameters
+      Handle(SelectMgr_FrustumBuilder) aBuilder = new SelectMgr_FrustumBuilder();
+      aBuilder->SetProjectionMatrix (mySelectingVolumeMgr.ProjectionMatrix());
+      aBuilder->SetWorldViewMatrix (SelectMgr_ViewerSelector_THE_IDENTITY_MAT);
+      aBuilder->SetWindowSize (aWidth, aHeight);
+      aMgr = mySelectingVolumeMgr.ScaleAndTransform (1, aTFrustum, aBuilder);
+    }
+    else
+    {
+      aMgr = mySelectingVolumeMgr;
+    }
+
+    const Graphic3d_Mat4d& aProjectionMat   = mySelectingVolumeMgr.ProjectionMatrix();
+    const Graphic3d_Mat4d& aWorldViewMat    = aBVHSubset != SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent
+                                            ? mySelectingVolumeMgr.WorldViewMatrix()
+                                            : SelectMgr_ViewerSelector_THE_IDENTITY_MAT;
+
+    const opencascade::handle<BVH_Tree<Standard_Real, 3> >& aBVHTree = mySelectableObjects.BVH (aBVHSubset);
+
+    Standard_Integer aNode = 0;
+    if (!aMgr.Overlaps (aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
+    {
+      continue;
+    }
+
+    Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
+    Standard_Integer aHead = -1;
+    for (;;)
+    {
+      if (!aBVHTree->IsOuter (aNode))
+      {
+        const Standard_Integer aLeftChildIdx  = aBVHTree->Child<0> (aNode);
+        const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
+        const Standard_Boolean isLeftChildIn  =
+          aMgr.Overlaps (aBVHTree->MinPoint (aLeftChildIdx), aBVHTree->MaxPoint (aLeftChildIdx));
+        const Standard_Boolean isRightChildIn =
+          aMgr.Overlaps (aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
+        if (isLeftChildIn
+          && isRightChildIn)
+        {
+          aNode = aLeftChildIdx;
+          ++aHead;
+          aStack[aHead] = aRightChildIdx;
+        }
+        else if (isLeftChildIn
+          || isRightChildIn)
+        {
+          aNode = isLeftChildIn ? aLeftChildIdx : aRightChildIdx;
+        }
+        else
+        {
+          if (aHead < 0)
+          {
+            break;
           }
+
+          aNode = aStack[aHead];
+          --aHead;
         }
       }
-    }
+      else
+      {
+        Standard_Integer aStartIdx = aBVHTree->BegPrimitive (aNode);
+        Standard_Integer anEndIdx  = aBVHTree->EndPrimitive (aNode);
+        for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
+        {
+          const Handle(SelectMgr_SelectableObject)& aSelectableObject =
+            mySelectableObjects.GetObjectById (aBVHSubset, anIdx);
 
-    if(mystored.IsEmpty()) return;
-    if(myIndexes.IsNull())
-      myIndexes = new TColStd_HArray1OfInteger(1,mystored.Extent());
-    else if(mystored.Extent() !=myIndexes->Length())
-      myIndexes = new TColStd_HArray1OfInteger (1,mystored.Extent());
+          traverseObject (aSelectableObject, aMgr, aCamera, aProjectionMat, aWorldViewMat, aWidth, aHeight);
+        }
+        if (aHead < 0)
+        {
+          break;
+        }
 
-    // to work faster...
-    TColStd_Array1OfInteger& thearr = myIndexes->ChangeArray1();
-    for(Standard_Integer I=1;I<=mystored.Extent();I++)
-      thearr(I)=I;
+        aNode = aStack[aHead];
+        --aHead;
+      }
+    }
   }
-}
 
+  SortResult();
+}
 
 //==================================================
-// Function: HasStored
+// Function: ClearPicked
 // Purpose :
 //==================================================
-Standard_Boolean SelectMgr_ViewerSelector::
-HasStored ()
+void SelectMgr_ViewerSelector::ClearPicked()
 {
-  if(Abs(lastx-Precision::Infinite())<=Precision::Confusion()) return Standard_False;
-  if(Abs(lasty-Precision::Infinite())<=Precision::Confusion()) return Standard_False;
-  InitSelect(lastx,lasty);
-  Init();
-  return More();
+  mystored.Clear();
 }
 
-
-
-
 //==================================================
 // Function: Picked
 // Purpose :
@@ -658,94 +658,40 @@ HasStored ()
 Handle(SelectMgr_EntityOwner) SelectMgr_ViewerSelector
 ::Picked() const
 {
-  Standard_Integer RankInMap = myIndexes->Value(myCurRank);
+  Standard_Integer RankInMap = myIndexes->Value (myCurRank);
   const Handle(SelectBasics_EntityOwner)& toto = mystored.FindKey(RankInMap);
-  Handle(SelectMgr_EntityOwner) Ownr = *((Handle(SelectMgr_EntityOwner)*) &toto);
+  Handle(SelectMgr_EntityOwner) Ownr = Handle(SelectMgr_EntityOwner)::DownCast (toto);
   return Ownr;
 }
 
-
-
 //=======================================================================
-//function : More
+//function : Picked
 //purpose  :
 //=======================================================================
-Standard_Boolean SelectMgr_ViewerSelector::More()
-{
-  if(mystored.Extent()==0) return Standard_False;
-  if(myCurRank==0) return Standard_False;
-  return myCurRank <= myIndexes->Length();
-}
-
-//==================================================
-// Function: OnePicked
-// Purpose : only the best one is chosen
-//           depend on priority and mindist...
-//==================================================
-
-Handle(SelectMgr_EntityOwner) SelectMgr_ViewerSelector
-::OnePicked()
+Handle(SelectMgr_EntityOwner) SelectMgr_ViewerSelector::Picked (const Standard_Integer theRank) const
 {
-
-  Init();
-  if(More()){
-    Standard_Integer RankInMap = myIndexes->Value(1);
-    const Handle(SelectBasics_EntityOwner)& toto = mystored.FindKey(RankInMap);
-    Handle(SelectMgr_EntityOwner) Ownr = *((Handle(SelectMgr_EntityOwner)*) &toto);
-    return Ownr;
+  Handle(SelectMgr_EntityOwner) anOwner;
+  if (theRank < 1 || theRank > NbPicked())
+  {
+    return anOwner;
   }
 
-  Handle (SelectMgr_EntityOwner) NullObj; //returns a null Handle if there was not successfull pick...
-  return NullObj;
+  const Standard_Integer anOwnerIdx = myIndexes->Value (theRank);
+  const Handle(SelectBasics_EntityOwner)& aStoredOwner = mystored.FindKey (anOwnerIdx);
+  anOwner = Handle(SelectMgr_EntityOwner)::DownCast (aStoredOwner);
+  return anOwner;
 }
 
-
 //=======================================================================
-//function : NbPicked
+//function : PickedData
 //purpose  :
 //=======================================================================
-
-Standard_Integer SelectMgr_ViewerSelector::NbPicked() const
+const SelectMgr_SortCriterion& SelectMgr_ViewerSelector::PickedData(const Standard_Integer theRank) const
 {
-  return mystored.Extent();
+  Standard_OutOfRange_Raise_if (theRank < 1 || theRank > NbPicked(), "SelectMgr_ViewerSelector::PickedData() out of range index");
+  const Standard_Integer anOwnerIdx = myIndexes->Value (theRank);
+  return mystored.FindFromIndex (anOwnerIdx);
 }
-//=======================================================================
-//function : Picked
-//purpose  :
-//=======================================================================
-Handle(SelectMgr_EntityOwner) SelectMgr_ViewerSelector::Picked(const Standard_Integer aRank) const
-{
-
-  Handle(SelectMgr_EntityOwner) Own;
-  if (aRank<1 || aRank>NbPicked())
-    return Own;
-  Standard_Integer Indx = myIndexes->Value(aRank);
-
-
-  const Handle(SelectBasics_EntityOwner)& toto = mystored.FindKey(Indx);
-  Own = *((Handle(SelectMgr_EntityOwner)*) &toto);
-  return Own;
-}
-//=======================================================================
-//function : Primitive
-//purpose  :
-//=======================================================================
-Handle(SelectBasics_SensitiveEntity) SelectMgr_ViewerSelector::Primitive
-(const Standard_Integer /*Index*/) const
-{
-  return myentities(myprim(myCurRank));
-}
-
-
-//==================================================
-// Function: LastPosition
-// Purpose :
-//==================================================
-void SelectMgr_ViewerSelector::LastPosition(Standard_Real& Xlast,
-                                            Standard_Real& YLast) const
-{   Xlast = lastx;YLast = lasty;}
-
-
 
 //===================================================
 //
@@ -753,193 +699,116 @@ void SelectMgr_ViewerSelector::LastPosition(Standard_Real& Xlast,
 //
 //==================================================
 
-
-
-
 //==================================================
-// Function: NbBoxes
+// Function: SetEntitySetBuilder
 // Purpose :
 //==================================================
-Standard_Integer SelectMgr_ViewerSelector::NbBoxes()
+void SelectMgr_ViewerSelector::SetEntitySetBuilder (const Handle(Select3D_BVHBuilder3d)& theBuilder)
 {
-  SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It(myselections);
-  //  Standard_Integer Nbb=0, first,last;
-  Standard_Integer Nbb=0;
-
-  for(;It.More();It.Next()){
-    if(It.Value()==0){
-      for(It.Key()->Init();It.Key()->More();It.Key()->Next())
-      {Nbb+= It.Key()->Sensitive()->MaxBoxes();}
-    }
+  myEntitySetBuilder = theBuilder;
+  for (SelectMgr_MapOfObjectSensitives::Iterator aSetIter (myMapOfObjectSensitives); aSetIter.More(); aSetIter.Next())
+  {
+    aSetIter.ChangeValue()->SetBuilder (myEntitySetBuilder);
   }
-  return Nbb;
 }
 
-
-
-
 //==================================================
 // Function: Contains
 // Purpose :
 //==================================================
-Standard_Boolean SelectMgr_ViewerSelector::
-Contains(const Handle(SelectMgr_SelectableObject)& anObject) const
+Standard_Boolean SelectMgr_ViewerSelector::Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
 {
-  for (anObject->Init();anObject->More();anObject->Next()){
-    if(myselections.IsBound(anObject->CurrentSelection()))
-      return Standard_True;
-  }
-  return Standard_False;
+  return mySelectableObjects.Contains (theObject);
 }
 
-
-
 //==================================================
 // Function: ActiveModes
 // Purpose : return all the  modes with a given state for an object
 //==================================================
-
-
-Standard_Boolean SelectMgr_ViewerSelector::
-Modes(const Handle(SelectMgr_SelectableObject)& SO,
-      TColStd_ListOfInteger& TheActiveList,
-      const SelectMgr_StateOfSelection WantedState) const
+Standard_Boolean SelectMgr_ViewerSelector::Modes (const Handle(SelectMgr_SelectableObject)& theSelectableObject,
+                                                  TColStd_ListOfInteger& theModeList,
+                                                  const SelectMgr_StateOfSelection theWantedState) const
 {
-  Standard_Boolean Found= Standard_False;
-  for(SO->Init();SO->More();SO->Next()){
-    if(myselections.IsBound(SO->CurrentSelection())){
-      if(WantedState==SelectMgr_SOS_Any)
-        TheActiveList.Append(SO->CurrentSelection()->Mode());
-      else if( myselections(SO->CurrentSelection())==WantedState)
-        TheActiveList.Append(SO->CurrentSelection()->Mode());
-
-      if(!Found) Found=Standard_True;
+  Standard_Boolean hasActivatedStates = Contains (theSelectableObject);
+  for (SelectMgr_SequenceOfSelection::Iterator aSelIter (theSelectableObject->Selections()); aSelIter.More(); aSelIter.Next())
+  {
+    if (theWantedState == SelectMgr_SOS_Any)
+    {
+      theModeList.Append (aSelIter.Value()->Mode());
     }
-  }
-  return Found;
-}
-
-
-Standard_Boolean SelectMgr_ViewerSelector::
-IsActive(const Handle(SelectMgr_SelectableObject)& SO,
-         const Standard_Integer aMode) const
-{
-  for(SO->Init();SO->More();SO->Next()){
-    if(aMode==SO->CurrentSelection()->Mode()){
-      if(myselections.IsBound(SO->CurrentSelection()) &&
-        myselections(SO->CurrentSelection())==SelectMgr_SOS_Activated)
-        return Standard_True;
-      else return Standard_False;
+    else if (theWantedState == aSelIter.Value()->GetSelectionState())
+    {
+      theModeList.Append (aSelIter.Value()->Mode());
     }
   }
-  return Standard_False;
-}
 
+  return hasActivatedStates;
+}
 
-Standard_Boolean SelectMgr_ViewerSelector::
-IsInside(const Handle(SelectMgr_SelectableObject)& SO,
-         const Standard_Integer aMode) const
+//==================================================
+// Function: IsActive
+// Purpose :
+//==================================================
+Standard_Boolean SelectMgr_ViewerSelector::IsActive (const Handle(SelectMgr_SelectableObject)& theSelectableObject,
+                                                     const Standard_Integer theMode) const
 {
-  for(SO->Init();SO->More();SO->Next()){
-    if(aMode==SO->CurrentSelection()->Mode()){
-      if(myselections.IsBound(SO->CurrentSelection())) return Standard_True;
-      else return Standard_False;
+  if (!Contains (theSelectableObject))
+    return Standard_False;
 
-    }
-  }
-  return Standard_False;
+  const Handle(SelectMgr_Selection)& aSel = theSelectableObject->Selection (theMode);
+  return !aSel.IsNull()
+       && aSel->GetSelectionState() == SelectMgr_SOS_Activated;
 }
 
-
-//=======================================================================
-//function : Status
-//purpose  :
-//=======================================================================
-
-SelectMgr_StateOfSelection SelectMgr_ViewerSelector::Status(const Handle(SelectMgr_Selection)& aSel) const
+//==================================================
+// Function: IsInside
+// Purpose :
+//==================================================
+Standard_Boolean SelectMgr_ViewerSelector::IsInside (const Handle(SelectMgr_SelectableObject)& theSelectableObject,
+                                                     const Standard_Integer theMode) const
 {
-  if(!myselections.IsBound(aSel)) return SelectMgr_SOS_Unknown;
-  //JR/Hp
-  Standard_Integer ie = myselections(aSel) ;
-  return SelectMgr_StateOfSelection( ie );
-  //  return SelectMgr_StateOfSelection(myselections(aSel));
+  if (!Contains (theSelectableObject))
+    return Standard_False;
 
+  const Handle(SelectMgr_Selection)& aSel = theSelectableObject->Selection (theMode);
+  return !aSel.IsNull()
+       && aSel->GetSelectionState() != SelectMgr_SOS_Unknown;
 }
 
 
-
 //=======================================================================
-//function : Dump
+//function : Status
 //purpose  :
 //=======================================================================
 
-void SelectMgr_ViewerSelector::Dump(Standard_OStream& S) const
+SelectMgr_StateOfSelection SelectMgr_ViewerSelector::Status (const Handle(SelectMgr_Selection)& theSelection) const
 {
-  S<<"=========================="<<endl;
-  S<<" SelectMgr_ViewerSelector "<<endl;
-  S<<"=========================="<<endl;
-  S<<" "<<endl;
+  return theSelection->GetSelectionState();
 }
 
-
-
 //==================================================
 // Function: Status
 // Purpose : gives Information about selectors
 //==================================================
 
-TCollection_AsciiString SelectMgr_ViewerSelector::
-Status(const Handle(SelectMgr_SelectableObject)& SO) const
+TCollection_AsciiString SelectMgr_ViewerSelector::Status (const Handle(SelectMgr_SelectableObject)& theSelectableObject) const
 {
-  TCollection_AsciiString Status("Status Object :\n\t");
-  Standard_Boolean Found= Standard_False;
-  for(SO->Init();SO->More();SO->Next()){
-    if(myselections.IsBound(SO->CurrentSelection()))
+  TCollection_AsciiString aStatus ("Status Object :\n\t");
+  for (SelectMgr_SequenceOfSelection::Iterator aSelIter (theSelectableObject->Selections()); aSelIter.More(); aSelIter.Next())
+  {
+    if (aSelIter.Value()->GetSelectionState() != SelectMgr_SOS_Unknown)
     {
-      Found = Standard_True;
-      Status = Status + "Mode " +
-        TCollection_AsciiString(SO->CurrentSelection()->Mode()) +
-        " present - " ;
-      if(myselections(SO->CurrentSelection()))
-        Status = Status + " Active \n\t";
-      else
-        Status = Status + " Inactive \n\t";
+      aStatus = aStatus + "Mode " + TCollection_AsciiString (aSelIter.Value()->Mode()) + " present - "
+              + (aSelIter.Value()->GetSelectionState() == SelectMgr_SOS_Activated ? " Active \n\t" : " Inactive \n\t");
     }
   }
 
-  if(!Found) Status = Status + "Not Present in the selector\n\n";
-  return Status;
-}
-
-
-TCollection_AsciiString SelectMgr_ViewerSelector::
-Status () const
-{
-  // sevsitive primitives present
-  //-----------------------------
-  TCollection_AsciiString Status("\t\tSelector Status :\n\t");
-  // selections
-  //-----------
-  Standard_Integer NbActive =0,NbPrim=0;
-  Status = Status + "Number of already computed selections : " +
-    TCollection_AsciiString(myselections.Extent());
-
-  SelectMgr_DataMapIteratorOfDataMapOfSelectionActivation It(myselections);
-  for(;It.More();It.Next())
+  if (!Contains (theSelectableObject))
   {
-    if(It.Value()==0) {NbActive++;
-    for(It.Key()->Init();It.Key()->More();It.Key()->Next()){NbPrim++;}
-    }
+    aStatus = aStatus + "Not Present in the selector\n\n";
   }
-  Status = Status + " - " + TCollection_AsciiString(NbActive) + " activated ones\n\t";
-  Status = Status + "Number of active sensitive primitives : " +
-    TCollection_AsciiString(NbPrim)+"\n\t";
-  Status = Status + "Real stored Pick Tolerance : " + TCollection_AsciiString(mytolerance) +"\n\t";
-  if(toupdate) {
-    Status = Status + "\nWARNING : those informations will be obsolete for the next Pick\n"
-      +"to get the real status of the selector - make One pick and call Status again\n";
-  }
-  return Status;
+
+  return aStatus;
 }
 
 //=======================================================================
@@ -960,119 +829,194 @@ void SelectMgr_ViewerSelector::SortResult()
   if(myIndexes.IsNull() || anExtent != myIndexes->Length())
     myIndexes = new TColStd_HArray1OfInteger (1, anExtent);
 
-  // to work faster...
-  TColStd_Array1OfInteger& thearr = myIndexes->ChangeArray1();
-
-  // indices from 1 to N are loaded
-  Standard_Integer I ;
-  for (I=1; I <= anExtent; I++)
-    thearr(I)=I;
-
-  // OCC4201 (AGV): This loop is inefficient on large arrays, so I replace it
-  //                with a standard sort algo
-  //  // on trie suivant les criteres  (i) (Owner) (SortCriterion)
-  //  Standard_Boolean OKSort;
-  //  Standard_Integer temp,indx,indx1;
-  //  Standard_Integer tmprim;
-  //  // merci lbr...
-  //  do{
-  //    OKSort =Standard_True;
-  //    for(I=1;I<thearr.Length();I++){
-  //      indx = thearr(I);
-  //      indx1 = thearr(I+1);
-  //      if(mystored(indx) < mystored(indx1)){
-  //      OKSort = Standard_False;
-  //
-  //      temp = thearr(I+1);
-  //      thearr(I+1) = thearr (I);
-  //      thearr(I) = temp;
-  //
-  //      tmprim = myprim(I+1);
-  //      myprim(I+1) = myprim(I);
-  //      myprim(I) = tmprim;
-  //
-  //      }
-  //    }
-  //  } while (OKSort==Standard_False);
-  //
-  // OCC4201 (AGV): debut
-
-  SortTools_QuickSortOfInteger::Sort (thearr,
-    SelectMgr_CompareResults(mystored));
-  TColStd_Array1OfInteger myPrimArr (1, myprim.Length());
-  for (I = 1; I <= myPrimArr.Length(); I++)
-    myPrimArr (I) = myprim (I);
-  for (I = 1; I <= thearr.Length(); I++) {
-    const Standard_Integer ind = thearr(I);
-    if (ind > 0 && ind <= myPrimArr.Upper())
-      myprim (I) = myPrimArr (ind);
+  TColStd_Array1OfInteger& anIndexArray = myIndexes->ChangeArray1();
+  for (Standard_Integer anIndexIter = 1; anIndexIter <= anExtent; ++anIndexIter)
+  {
+    anIndexArray.SetValue (anIndexIter, anIndexIter);
   }
-  // OCC4201 (AGV): fin
-  // it is enough to return owners corresponding to parced indices...
+  std::sort (anIndexArray.begin(), anIndexArray.end(), CompareResults (mystored));
+}
 
+//=======================================================================
+//function : HasDepthClipping
+//purpose  : Stub
+//=======================================================================
+Standard_Boolean SelectMgr_ViewerSelector::HasDepthClipping (const Handle(SelectMgr_EntityOwner)& /*theOwner*/) const
+{
+  return Standard_False;
 }
 
+//=======================================================================
+// function : AddSelectableObject
+// purpose  : Adds new object to the map of selectable objects
+//=======================================================================
+void SelectMgr_ViewerSelector::AddSelectableObject (const Handle(SelectMgr_SelectableObject)& theObject)
+{
+  if (!myMapOfObjectSensitives.IsBound (theObject))
+  {
+    mySelectableObjects.Append (theObject);
+    Handle(SelectMgr_SensitiveEntitySet) anEntitySet = new SelectMgr_SensitiveEntitySet (myEntitySetBuilder);
+    myMapOfObjectSensitives.Bind (theObject, anEntitySet);
+  }
+}
 
 //=======================================================================
-//function :
-//purpose  :
+// function : AddSelectionToObject
+// purpose  : Adds new selection to the object and builds its BVH tree
 //=======================================================================
-Standard_Boolean SelectMgr_ViewerSelector::IsUpdateSortPossible() const
+void SelectMgr_ViewerSelector::AddSelectionToObject (const Handle(SelectMgr_SelectableObject)& theObject,
+                                                     const Handle(SelectMgr_Selection)& theSelection)
 {
-  return myUpdateSortPossible;
+  if (Handle(SelectMgr_SensitiveEntitySet)* anEntitySet = myMapOfObjectSensitives.ChangeSeek (theObject))
+  {
+    (*anEntitySet)->Append (theSelection);
+    (*anEntitySet)->BVH();
+  }
+  else
+  {
+    AddSelectableObject (theObject);
+    AddSelectionToObject (theObject, theSelection);
+  }
 }
 
 //=======================================================================
-//function :
-//purpose  :
+// function : MoveSelectableObject
+// purpose  :
 //=======================================================================
-void SelectMgr_ViewerSelector::SetUpdateSortPossible( const Standard_Boolean possible )
+void SelectMgr_ViewerSelector::MoveSelectableObject (const Handle(SelectMgr_SelectableObject)& theObject)
 {
-  myUpdateSortPossible = possible;
+  mySelectableObjects.ChangeSubset (theObject);
 }
 
 //=======================================================================
-//function : PickingLine
-//purpose  : Stub
+// function : RemoveSelectableObject
+// purpose  : Removes selectable object from map of selectable ones
 //=======================================================================
-gp_Lin SelectMgr_ViewerSelector::PickingLine (const Standard_Real /*theX*/,
-                                              const Standard_Real /*theY*/) const
+void SelectMgr_ViewerSelector::RemoveSelectableObject (const Handle(SelectMgr_SelectableObject)& theObject)
 {
-  return gp_Lin();
+  Handle(SelectMgr_SelectableObject) anObj = theObject;
+  if (myMapOfObjectSensitives.UnBind (theObject))
+  {
+    mySelectableObjects.Remove (theObject);
+  }
 }
 
 //=======================================================================
-//function : DepthClipping
-//purpose  : Stub
+// function : RemoveSelectionOfObject
+// purpose  : Removes selection of the object and marks its BVH tree
+//            for rebuild
 //=======================================================================
-void SelectMgr_ViewerSelector::DepthClipping (const Standard_Real /*theX*/,
-                                              const Standard_Real /*theY*/,
-                                              Standard_Real& theMin,
-                                              Standard_Real& theMax) const
+void SelectMgr_ViewerSelector::RemoveSelectionOfObject (const Handle(SelectMgr_SelectableObject)& theObject,
+                                                        const Handle(SelectMgr_Selection)& theSelection)
 {
-  theMin = RealFirst();
-  theMax = RealLast();
+  if (Handle(SelectMgr_SensitiveEntitySet)* anEntitySet = myMapOfObjectSensitives.ChangeSeek (theObject))
+  {
+    (*anEntitySet)->Remove (theSelection);
+  }
 }
 
 //=======================================================================
-//function : DepthClipping
-//purpose  : Stub
+// function : RebuildObjectsTree
+// purpose  : Marks BVH of selectable objects for rebuild
 //=======================================================================
-void SelectMgr_ViewerSelector::DepthClipping (const Standard_Real /*theX*/,
-                                              const Standard_Real /*theY*/,
-                                              const Handle(SelectMgr_EntityOwner)& /*theOwner*/,
-                                              Standard_Real& theMin,
-                                              Standard_Real& theMax) const
+void SelectMgr_ViewerSelector::RebuildObjectsTree (const Standard_Boolean theIsForce)
 {
-  theMin = RealFirst();
-  theMax = RealLast();
+  mySelectableObjects.MarkDirty();
+
+  if (theIsForce)
+  {
+    Standard_Integer aViewportWidth, aViewportHeight;
+    mySelectingVolumeMgr.WindowSize (aViewportWidth, aViewportHeight);
+
+    Standard_Integer aWidth;
+    Standard_Integer aHeight;
+    mySelectingVolumeMgr.WindowSize (aWidth, aHeight);
+    mySelectableObjects.UpdateBVH (mySelectingVolumeMgr.Camera(),
+                                   mySelectingVolumeMgr.ProjectionMatrix(),
+                                   mySelectingVolumeMgr.WorldViewMatrix(),
+                                   mySelectingVolumeMgr.WorldViewProjState(),
+                                   aWidth, aHeight);
+  }
 }
 
 //=======================================================================
-//function : HasDepthClipping
-//purpose  : Stub
+// function : RebuildSensitivesTree
+// purpose  : Marks BVH of sensitive entities of particular selectable
+//            object for rebuild
 //=======================================================================
-Standard_Boolean SelectMgr_ViewerSelector::HasDepthClipping (const Handle(SelectMgr_EntityOwner)& /*theOwner*/) const
+void SelectMgr_ViewerSelector::RebuildSensitivesTree (const Handle(SelectMgr_SelectableObject)& theObject,
+                                                      const Standard_Boolean theIsForce)
 {
-  return Standard_False;
+  if (!Contains (theObject))
+    return;
+
+  Handle(SelectMgr_SensitiveEntitySet)& anEntitySet = myMapOfObjectSensitives.ChangeFind (theObject);
+  anEntitySet->MarkDirty();
+
+  if (theIsForce)
+  {
+    anEntitySet->BVH();
+  }
+}
+
+//=======================================================================
+// function : resetSelectionActivationStatus
+// purpose  : Marks all added sensitive entities of all objects as
+//            non-selectable
+//=======================================================================
+void SelectMgr_ViewerSelector::ResetSelectionActivationStatus()
+{
+  for (SelectMgr_MapOfObjectSensitivesIterator aSensitivesIter (myMapOfObjectSensitives); aSensitivesIter.More(); aSensitivesIter.Next())
+  {
+    Handle(SelectMgr_SensitiveEntitySet)& anEntitySet = aSensitivesIter.ChangeValue();
+    const Standard_Integer anEntitiesNb = anEntitySet->Size();
+    for (Standard_Integer anIdx = 0; anIdx < anEntitiesNb; ++anIdx)
+    {
+      anEntitySet->GetSensitiveById (anIdx)->ResetSelectionActiveStatus();
+    }
+  }
+}
+
+//=======================================================================
+// function : DetectedEntity
+// purpose  : Returns sensitive entity that was detected during the
+//            previous run of selection algorithm
+//=======================================================================
+const Handle(SelectBasics_SensitiveEntity)& SelectMgr_ViewerSelector::DetectedEntity() const
+{
+  const Standard_Integer aRankInMap = myIndexes->Value(myCurRank);
+  return mystored.FindFromIndex (aRankInMap).Entity;
+}
+
+//=======================================================================
+// function : ActiveOwners
+// purpose  : Returns the list of active entity owners
+//=======================================================================
+void SelectMgr_ViewerSelector::ActiveOwners (NCollection_List<Handle(SelectBasics_EntityOwner)>& theOwners) const
+{
+  for (SelectMgr_MapOfObjectSensitivesIterator anIter (myMapOfObjectSensitives); anIter.More(); anIter.Next())
+  {
+    const Handle(SelectMgr_SensitiveEntitySet)& anEntitySet = anIter.Value();
+    const Standard_Integer anEntitiesNb = anEntitySet->Size();
+    for (Standard_Integer anIdx = 0; anIdx < anEntitiesNb; ++anIdx)
+    {
+      const Handle(SelectMgr_SensitiveEntity)& aSensitive = anEntitySet->GetSensitiveById (anIdx);
+      if (aSensitive->IsActiveForSelection())
+      {
+        theOwners.Append (aSensitive->BaseSensitive()->OwnerId());
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : AllowOverlapDetection
+//purpose  : Sets the detection type: if theIsToAllow is false,
+//           only fully included sensitives will be detected, otherwise
+//           the algorithm will mark both included and overlapped entities
+//           as matched
+//=======================================================================
+void SelectMgr_ViewerSelector::AllowOverlapDetection (const Standard_Boolean theIsToAllow)
+{
+  mySelectingVolumeMgr.AllowOverlapDetection (theIsToAllow);
 }