-// 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());
}