0030480: Visualization - Clear of Select3D_SensitiveGroup does not update internal...
[occt.git] / src / Select3D / Select3D_SensitiveGroup.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 3cfcbf9..9827b39
-// File:       Select3D_SensitiveGroup.cxx
-// Created:    Thu Apr 16 16:17:00 1998
-// Author:     Robert COUBLANC
-//             <rob@robox.paris1.matra-dtv.fr>
+// Created on: 1998-04-16
+// Created by: Robert COUBLANC
+// Copyright (c) 1998-1999 Matra Datavision
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
 
+#include <Select3D_SensitiveGroup.hxx>
 
-#include <Select3D_SensitiveGroup.ixx>
-#include <Select3D_ListIteratorOfListOfSensitive.hxx>
 #include <Precision.hxx>
 
-Select3D_SensitiveGroup::Select3D_SensitiveGroup(const Handle(SelectBasics_EntityOwner)& OwnerId,
-                                                const Standard_Boolean MatchAll):
-Select3D_SensitiveEntity(OwnerId),
-myMustMatchAll(MatchAll),
-myLastRank(0),
-myX(0.),
-myY(0.)
-{
-}
+IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveGroup,Select3D_SensitiveSet)
 
-Select3D_SensitiveGroup::Select3D_SensitiveGroup(const Handle(SelectBasics_EntityOwner)& OwnerId,
-                                                 Select3D_ListOfSensitive& TheList,
-                                                const Standard_Boolean MatchAll):
+//=======================================================================
+//function : Creation
+//purpose  :
+//=======================================================================
+Select3D_SensitiveGroup::Select3D_SensitiveGroup (const Handle(SelectBasics_EntityOwner)& theOwnerId,
+                                                  const Standard_Boolean theIsMustMatchAll)
+: Select3D_SensitiveSet (theOwnerId),
+  myMustMatchAll (theIsMustMatchAll),
+  myToCheckOverlapAll (Standard_False),
+  myCenter (0.0, 0.0, 0.0) {}
 
-Select3D_SensitiveEntity(OwnerId),
-myMustMatchAll(MatchAll),
-myLastRank(0),
-myX(0.),
-myY(0.)
+//=======================================================================
+//function : Creation
+//purpose  :
+//=======================================================================
+Select3D_SensitiveGroup::Select3D_SensitiveGroup (const Handle(SelectBasics_EntityOwner)& theOwnerId,
+                                                  Select3D_EntitySequence& theEntities,
+                                                  const Standard_Boolean theIsMustMatchAll)
+: Select3D_SensitiveSet (theOwnerId),
+  myEntities (Max (1, theEntities.Size())),
+  myMustMatchAll (theIsMustMatchAll),
+  myToCheckOverlapAll (Standard_False),
+  myCenter (0.0, 0.0, 0.0)
 {
-  myList.Append(TheList);
+  for (Select3D_EntitySequenceIter anIter (theEntities); anIter.More(); anIter.Next())
+  {
+    const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value();
+    const Standard_Integer aPrevExtent = myEntities.Extent();
+    if (myEntities.Add (anEntity) <= aPrevExtent)
+    {
+      continue;
+    }
+
+    myBndBox.Combine (anEntity->BoundingBox());
+    myBVHPrimIndexes.Append (myEntities.Extent());
+    myCenter.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
+  }
+
+  myCenter.ChangeCoord().Divide (static_cast<Standard_Real> (myEntities.Extent()));
+
+  MarkDirty();
 }
 
 //=======================================================================
 //function : Add
-//purpose  : No control of  entities inside 
+//purpose  : No control of entities inside
 //=======================================================================
-void Select3D_SensitiveGroup::Add(Select3D_ListOfSensitive& LL) 
-{myList.Append(LL);}
+void Select3D_SensitiveGroup::Add (Select3D_EntitySequence& theEntities)
+{
+  if (theEntities.IsEmpty())
+  {
+    return;
+  }
+
+  gp_Pnt aCent (0.0, 0.0, 0.0);
+  myEntities.ReSize (myEntities.Extent() + theEntities.Size());
+  for (Select3D_EntitySequenceIter anIter (theEntities); anIter.More(); anIter.Next())
+  {
+    const Handle(Select3D_SensitiveEntity)& anEntity = anIter.Value();
+    const Standard_Integer aPrevExtent = myEntities.Extent();
+    if (myEntities.Add (anEntity) <= aPrevExtent)
+    {
+      continue;
+    }
+
+    myBndBox.Combine (anEntity->BoundingBox());
+    myBVHPrimIndexes.Append (myEntities.Extent());
+    aCent.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
+  }
+  aCent.ChangeCoord().Divide (myEntities.Extent());
+  myCenter = (myCenter.XYZ() + aCent.XYZ()).Multiplied (0.5);
+}
 
 //=======================================================================
 //function : Add
-//purpose  : 
+//purpose  :
 //=======================================================================
-void Select3D_SensitiveGroup::Add(const Handle(Select3D_SensitiveEntity)& aSensitive) 
+void Select3D_SensitiveGroup::Add (const Handle(Select3D_SensitiveEntity)& theSensitive)
 {
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()==aSensitive) return;
+  const Standard_Integer aPrevExtent = myEntities.Extent();
+  if (myEntities.Add (theSensitive) <= aPrevExtent)
+  {
+    return;
+  }
+
+  myBVHPrimIndexes.Append (myEntities.Extent());
+  myBndBox.Combine (theSensitive->BoundingBox());
+  myCenter.ChangeCoord() += theSensitive->CenterOfGeometry().XYZ();
+  if (myEntities.Extent() >= 2)
+  {
+    myCenter.ChangeCoord().Multiply (0.5);
   }
-  myList.Append(aSensitive);
 }
 
 //=======================================================================
 //function : Remove
-//purpose  : 
+//purpose  :
 //=======================================================================
-void Select3D_SensitiveGroup::Remove(const Handle(Select3D_SensitiveEntity)& aSensitive) 
+void Select3D_SensitiveGroup::Remove (const Handle(Select3D_SensitiveEntity)& theSensitive)
 {
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()==aSensitive){
-      myList.Remove(It);
-      return;
-    }
+  if (!myEntities.RemoveKey (theSensitive))
+  {
+    return;
   }
+
+  myBndBox.Clear();
+  myCenter = gp_Pnt (0.0, 0.0, 0.0);
+  myBVHPrimIndexes.Clear();
+  for (Standard_Integer anIdx = 1; anIdx <= myEntities.Size(); ++anIdx)
+  {
+    const Handle(Select3D_SensitiveEntity)& anEntity = myEntities.FindKey (anIdx);
+    myBndBox.Combine (anEntity->BoundingBox());
+    myCenter.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
+    myBVHPrimIndexes.Append (anIdx);
+  }
+  myCenter.ChangeCoord().Divide (static_cast<Standard_Real> (myEntities.Extent()));
 }
 
 //=======================================================================
 //function : IsIn
-//purpose  : 
+//purpose  :
 //=======================================================================
-Standard_Boolean Select3D_SensitiveGroup::IsIn(const Handle(Select3D_SensitiveEntity)& aSensitive) const
+Standard_Boolean Select3D_SensitiveGroup::IsIn (const Handle(Select3D_SensitiveEntity)& theSensitive) const
 {
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()==aSensitive)
-      return Standard_True;
-  }
-  return Standard_False;
-
+  return myEntities.Contains (theSensitive);
 }
+
 //=======================================================================
 //function : Clear
-//purpose  : 
+//purpose  :
 //=======================================================================
+
 void Select3D_SensitiveGroup::Clear()
-{myList.Clear();}
+{
+  myEntities.Clear();
+  myBndBox.Clear();
+  myCenter = gp_Pnt (0.0, 0.0, 0.0);
+  myBVHPrimIndexes.Clear();
+}
 
 //=======================================================================
-//function : Project
-//purpose  : 
+// function : NbSubElements
+// purpose  : Returns the amount of sub-entities
 //=======================================================================
-
-void Select3D_SensitiveGroup::Project(const Handle(Select3D_Projector)& aProjector) 
+Standard_Integer Select3D_SensitiveGroup::NbSubElements()
 {
-  Select3D_SensitiveEntity::Project(aProjector); // to set the field last proj...
-
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    It.Value()->Project(aProjector);
-  }
+  return myEntities.Size();
 }
 
 //=======================================================================
-//function : Areas
-//purpose  : 
+//function : GetConnected
+//purpose  :
 //=======================================================================
 
-void Select3D_SensitiveGroup::Areas(SelectBasics_ListOfBox2d& boxes) 
+Handle(Select3D_SensitiveEntity) Select3D_SensitiveGroup::GetConnected()
 {
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    It.Value()->Areas(boxes);
+  Handle(Select3D_SensitiveGroup) aNewEntity = new Select3D_SensitiveGroup (myOwnerId, myMustMatchAll);
+  Select3D_EntitySequence aConnectedEnt;
+  for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
+  {
+    aConnectedEnt.Append (anEntityIter.Value()->GetConnected());
   }
+  aNewEntity->Add (aConnectedEnt);
+  return aNewEntity;
 }
 
 //=======================================================================
-//function : GetConnected
-//purpose  : 
+//function : Matches
+//purpose  :
 //=======================================================================
-
-Handle(Select3D_SensitiveEntity) Select3D_SensitiveGroup::GetConnected(const TopLoc_Location& aLocation) 
+Standard_Boolean Select3D_SensitiveGroup::Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                   SelectBasics_PickResult& thePickResult)
 {
-  Handle(Select3D_SensitiveGroup) newgroup = new Select3D_SensitiveGroup(myOwnerId,myMustMatchAll);
-  Select3D_ListOfSensitive LL;
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    LL.Append(It.Value()->GetConnected(aLocation));
+  const Standard_Boolean toMatchAll = theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point
+                                   && myMustMatchAll;
+  const Standard_Boolean toCheckAll = theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point
+                                   && myToCheckOverlapAll;
+  if (!toMatchAll && !toCheckAll)
+  {
+    return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
   }
-  newgroup->Add(LL);
-  return newgroup;
+
+  SelectBasics_PickResult aPickResult;
+  Standard_Boolean isFailed = Standard_False;
+  for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
+  {
+    const Handle(Select3D_SensitiveEntity)& aChild = anEntityIter.Value();
+    if (!aChild->Matches (theMgr, aPickResult))
+    {
+      if (toMatchAll)
+      {
+        isFailed = Standard_True;
+        if (!toCheckAll)
+        {
+          break;
+        }
+      }
+    }
+    else
+    {
+      thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
+    }
+  }
+  if (isFailed)
+  {
+    return Standard_False;
+  }
+
+  thePickResult.SetDistToGeomCenter(distanceToCOG(theMgr));
+  return Standard_True;
 }
 
 //=======================================================================
-//function : SetLocation
-//purpose  : 
+//function : Set
+//purpose  :
 //=======================================================================
+void Select3D_SensitiveGroup::Set (const Handle(SelectBasics_EntityOwner)& theOwnerId)
+{ 
+  Select3D_SensitiveEntity::Set (theOwnerId);
+  for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
+  {
+    anEntityIter.Value()->Set (theOwnerId);
+  }
+}
 
-void Select3D_SensitiveGroup::SetLocation(const TopLoc_Location& aLoc) 
+//=======================================================================
+// function : BoundingBox
+// purpose  : Returns bounding box of the group. If location
+//            transformation is set, it will be applied
+//=======================================================================
+Select3D_BndBox3d Select3D_SensitiveGroup::BoundingBox()
 {
-  if(aLoc.IsIdentity()) return;
-
-  if(HasLocation())
-    if(aLoc == Location()) return;
-  
-  Select3D_SensitiveEntity::SetLocation(aLoc);
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()->HasLocation()){
-      if(It.Value()->Location()!=aLoc)
-       It.Value()->SetLocation(It.Value()->Location()*aLoc);
-    }
-    else
-      It.Value()->SetLocation(aLoc);
-    
+  if (myBndBox.IsValid())
+    return myBndBox;
+
+  // do not apply the transformation because sensitives AABBs
+  // are already transformed
+  for (Select3D_IndexedMapOfEntity::Iterator anEntityIter (myEntities); anEntityIter.More(); anEntityIter.Next())
+  {
+    myBndBox.Combine (anEntityIter.Value()->BoundingBox());
   }
+
+  return myBndBox;
 }
 
 //=======================================================================
-//function : ResetLocation
-//purpose  : 
+// function : CenterOfGeometry
+// purpose  : Returns center of group. If location transformation
+//            is set, it will be applied
 //=======================================================================
-void Select3D_SensitiveGroup::ResetLocation() 
+gp_Pnt Select3D_SensitiveGroup::CenterOfGeometry() const
 {
- if(!HasLocation()) return;
- for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-   if(It.Value()->HasLocation() && It.Value()->Location()!=Location())
-     It.Value()->SetLocation(It.Value()->Location()*Location().Inverted());
-   else
-     It.Value()->ResetLocation();
-   
- }
- Select3D_SensitiveEntity::ResetLocation();
+  return myCenter;
 }
 
 //=======================================================================
-//function : Matches
-//purpose  : 
+// function : Box
+// purpose  : Returns bounding box of sensitive entity with index theIdx
 //=======================================================================
-Standard_Boolean Select3D_SensitiveGroup::Matches(const Standard_Real X,
-                                                 const Standard_Real Y,
-                                                 const Standard_Real aTol,
-                                                 Standard_Real& DMin) 
+Select3D_BndBox3d Select3D_SensitiveGroup::Box (const Standard_Integer theIdx) const
 {
-  myLastRank = 0;
-  myLastTol = aTol;
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    myLastRank++;
-    if (It.Value()->Matches (X, Y, aTol, DMin))
-    {
-      myX = X; myY = Y; myLastTol = aTol;
-      // compute and validate the depth (will call ::ComputeDepth())
-      return Select3D_SensitiveEntity::Matches (X, Y, aTol, DMin);
-    }
-  }
-  // no match
-  myLastRank = 0;
-  SetLastDepth (ShortRealLast());
-  return Standard_False;
+  const Standard_Integer anElemIdx = myBVHPrimIndexes.Value (theIdx);
+  return myEntities.FindKey (anElemIdx)->BoundingBox();
 }
 
 //=======================================================================
-//function : Matches
-//purpose  :  si on doit tout matcher, on ne repond oui que si toutes
-//            les primitives repondent oui
-//=======================================================================
-Standard_Boolean Select3D_SensitiveGroup::Matches(const Standard_Real XMin,
-                                                 const Standard_Real YMin,
-                                                 const Standard_Real XMax,
-                                                 const Standard_Real YMax,
-                                                 const Standard_Real aTol) 
+// function : Center
+// purpose  : Returns geometry center of sensitive entity with index
+//            theIdx in the vector along the given axis theAxis
+//=======================================================================
+Standard_Real Select3D_SensitiveGroup::Center (const Standard_Integer theIdx,
+                                               const Standard_Integer theAxis) const
 {
-  Standard_Boolean result(Standard_True);
-  
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()->Matches(XMin,YMin,XMax,YMax,aTol)){
-      if(!myMustMatchAll)
-       return Standard_True;
-    }
-    // ca ne matches pas..
-    else {
-      if(myMustMatchAll)
-       return Standard_False;
-      else
-       result = Standard_False;
-    }
-  }
-  return result;
+  const Standard_Integer anElemIdx = myBVHPrimIndexes.Value (theIdx);
+  const gp_Pnt aCenter = myEntities.FindKey (anElemIdx)->CenterOfGeometry();
+  return theAxis == 0 ? aCenter.X() : (theAxis == 1 ? aCenter.Y() : aCenter.Z());
 }
 
 //=======================================================================
-//function : Matches
-//purpose  : 
+// function : Swap
+// purpose  : Swaps items with indexes theIdx1 and theIdx2 in the vector
 //=======================================================================
+void Select3D_SensitiveGroup::Swap (const Standard_Integer theIdx1,
+                                    const Standard_Integer theIdx2)
+{
+  const Standard_Integer anEntIdx1 = myBVHPrimIndexes.Value (theIdx1);
+  const Standard_Integer anEntIdx2 = myBVHPrimIndexes.Value (theIdx2);
 
-Standard_Boolean Select3D_SensitiveGroup::
-Matches (const TColgp_Array1OfPnt2d& aPoly,
-        const Bnd_Box2d& aBox,
-        const Standard_Real aTol)
-{ 
-  Standard_Boolean result(Standard_True);
-  
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    if(It.Value()->Matches(aPoly, aBox, aTol)){
-      if(!myMustMatchAll)
-       return Standard_True;
-    }
-    else {
-      if(myMustMatchAll)
-       return Standard_False;
-      else
-       result = Standard_False;
-    }
-  }
-  return result;
+  myBVHPrimIndexes.ChangeValue (theIdx1) = anEntIdx2;
+  myBVHPrimIndexes.ChangeValue (theIdx2) = anEntIdx1;
 }
 
-
 //=======================================================================
-//function : ComputeDepth
-//purpose  : to optimise, the minimum depth for 
-//          entities that answer YES to Matches(X,Y,...) is taken
-//          the test is started from mylastRank...
+// function : Size
+// purpose  : Returns the length of vector of sensitive entities
 //=======================================================================
-Standard_Real Select3D_SensitiveGroup::ComputeDepth(const gp_Lin& EyeLine) const
+Standard_Integer Select3D_SensitiveGroup::Size() const
+{
+  return myBVHPrimIndexes.Size();
+}
+
+// =======================================================================
+// function : overlapsElement
+// purpose  : Checks whether the entity with index theIdx overlaps the
+//            current selecting volume
+// =======================================================================
+Standard_Boolean Select3D_SensitiveGroup::overlapsElement (SelectBasics_PickResult& thePickResult,
+                                                           SelectBasics_SelectingVolumeManager& theMgr,
+                                                           Standard_Integer theElemIdx,
+                                                           Standard_Boolean )
 {
-  Standard_Integer currank = 0;
-  Standard_Real DMin, thedepth (Precision::Infinite());
-  for (Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next())
+  const Standard_Integer aSensitiveIdx = myBVHPrimIndexes.Value (theElemIdx);
+  if (myEntities.FindKey (aSensitiveIdx)->Matches (theMgr, thePickResult))
   {
-    currank++;
-    if (currank >= myLastRank)
-    {
-      // this recomputes and validates the depth for the entity
-      if (It.Value()->Matches (myX, myY, myLastTol, DMin))
-      {
-        It.Value()->ComputeDepth (EyeLine);
-        if (It.Value()->Depth() < thedepth)
-        {
-          // search for topmost entity
-          thedepth = It.Value()->Depth();
-          //myLastRank = currank; // can not do this here...
-        }
-      }
-    }
+    return Standard_True;
   }
-  return thedepth;
+
+  return Standard_False;
 }
 
-//=======================================================================
-//function : MaxBoxes
-//purpose  : 
-//=======================================================================
-Standard_Integer Select3D_SensitiveGroup::MaxBoxes() const
+// =======================================================================
+// function : elementIsInside
+// purpose  :
+// =======================================================================
+Standard_Boolean Select3D_SensitiveGroup::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
+                                                           Standard_Integer theElemIdx,
+                                                           Standard_Boolean theIsFullInside)
 {
-  Standard_Integer nbboxes(0);
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next()){
-    nbboxes+=It.Value()->MaxBoxes();
-  }
-  return nbboxes;
+  SelectBasics_PickResult aDummy;
+  return overlapsElement (aDummy, theMgr, theElemIdx, theIsFullInside);
 }
 
-void Select3D_SensitiveGroup::SetLastPrj(const Handle(Select3D_Projector)& Prj)
+// =======================================================================
+// function : distanceToCOG
+// purpose  : Calculates distance from the 3d projection of used-picked
+//            screen point to center of the geometry
+// =======================================================================
+Standard_Real Select3D_SensitiveGroup::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
 {
-  Select3D_SensitiveEntity::SetLastPrj(Prj);
-  for(Select3D_ListIteratorOfListOfSensitive It(myList);It.More();It.Next())
-    It.Value()->SetLastPrj(Prj);
+  return theMgr.DistToGeometryCenter (CenterOfGeometry());
 }