SelectMgr_SelectableObject.hxx
SelectMgr_SelectableObjectSet.cxx
SelectMgr_SelectableObjectSet.hxx
-SelectMgr_SelectableObjectTrsfPersSet.cxx
-SelectMgr_SelectableObjectTrsfPersSet.hxx
SelectMgr_SelectingVolumeManager.cxx
SelectMgr_SelectingVolumeManager.hxx
SelectMgr_Selection.cxx
// purpose :
//=======================================================================
void SelectMgr_BaseFrustum::WindowSize (Standard_Integer& theWidth,
- Standard_Integer& theHeight)
+ Standard_Integer& theHeight) const
{
myBuilder->WindowSize (theWidth, theHeight);
}
const Standard_Integer theHeight);
Standard_EXPORT void WindowSize (Standard_Integer& theWidth,
- Standard_Integer& theHeight);
+ Standard_Integer& theHeight) const;
//! Passes viewport parameters to builder
Standard_EXPORT void SetViewport (const Standard_Real theX,
//! There are no default parameters, but in case if:
//! - transformation only is needed: @theScaleFactor must be initialized as any negative value;
//! - scale only is needed: @theTrsf must be set to gp_Identity.
- Standard_EXPORT virtual NCollection_Handle<SelectMgr_BaseFrustum> ScaleAndTransform (const Standard_Integer /*theScaleFactor*/,
- const gp_GTrsf& /*theTrsf*/) { return NULL; }
+ Standard_EXPORT virtual Handle(SelectMgr_BaseFrustum) ScaleAndTransform (const Standard_Integer /*theScaleFactor*/,
+ const gp_GTrsf& /*theTrsf*/) const { return NULL; }
//! SAT intersection test between defined volume and given axis-aligned box
Standard_EXPORT virtual Standard_Boolean Overlaps (const SelectMgr_Vec3& theBoxMin,
// purpose :
//=======================================================================
void SelectMgr_FrustumBuilder::WindowSize (Standard_Integer& theWidth,
- Standard_Integer& theHeight)
+ Standard_Integer& theHeight) const
{
theWidth = myWidth;
theHeight = myHeight;
Standard_EXPORT void InvalidateViewport();
Standard_EXPORT void WindowSize (Standard_Integer& theWidth,
- Standard_Integer& theHeight);
+ Standard_Integer& theHeight) const;
//! Calculates signed distance between plane with equation
//! theEq and point thePnt
// Top
theNormals[0] = theEdges[0].Crossed (theEdges[4]);
// Bottom
- theNormals[1] = theEdges[2].Crossed (theEdges[3]);
+ theNormals[1] = theEdges[2].Crossed (theEdges[0]);
// Left
theNormals[2] = theEdges[4].Crossed (theEdges[1]);
// Right
- theNormals[3] = theEdges[5].Crossed (theEdges[3]);
+ theNormals[3] = theEdges[1].Crossed (theEdges[5]);
// Near
theNormals[4] = theEdges[0].Crossed (theEdges[1]);
// Far
// purpose : Caches projection of frustum's vertices onto its plane directions
// and {i, j, k}
// =======================================================================
-void SelectMgr_RectangularFrustum::cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum)
+void SelectMgr_RectangularFrustum::cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum) const
{
if (theFrustum->myIsOrthographic)
{
// as any negative value;
// - scale only is needed: @theTrsf must be set to gp_Identity.
// =======================================================================
-NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_RectangularFrustum::ScaleAndTransform (const Standard_Integer theScaleFactor,
- const gp_GTrsf& theTrsf)
+Handle(SelectMgr_BaseFrustum) SelectMgr_RectangularFrustum::ScaleAndTransform (const Standard_Integer theScaleFactor,
+ const gp_GTrsf& theTrsf) const
{
Standard_ASSERT_RAISE (theScaleFactor > 0,
"Error! Pixel tolerance for selection should be greater than zero");
- SelectMgr_RectangularFrustum* aRes = new SelectMgr_RectangularFrustum();
+ Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum();
const Standard_Boolean isToScale = theScaleFactor != 1;
const Standard_Boolean isToTrsf = theTrsf.Form() != gp_Identity;
return aRes;
aRes->myIsOrthographic = myIsOrthographic;
- SelectMgr_RectangularFrustum* aRef = this;
+ const SelectMgr_RectangularFrustum* aRef = this;
if (isToScale)
{
// recompute base frustum characteristics from scratch
computeFrustum (aMinPnt, aMaxPnt, myBuilder, aRes->myVertices, aRes->myEdgeDirs);
- aRef = aRes;
+ aRef = aRes.get();
}
if (isToTrsf)
// compute frustum normals
computeNormals (aRes->myEdgeDirs, aRes->myPlanes);
- cacheVertexProjections (aRes);
+ cacheVertexProjections (aRes.get());
aRes->myViewClipRange = myViewClipRange;
+ aRes->myMousePos = myMousePos;
- return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
+ return aRes;
}
// =======================================================================
//! There are no default parameters, but in case if:
//! - transformation only is needed: @theScaleFactor must be initialized as any negative value;
//! - scale only is needed: @theTrsf must be set to gp_Identity.
- Standard_EXPORT virtual NCollection_Handle<SelectMgr_BaseFrustum> ScaleAndTransform (const Standard_Integer theScaleFactor,
- const gp_GTrsf& theTrsf) Standard_OVERRIDE;
+ Standard_EXPORT virtual Handle(SelectMgr_BaseFrustum) ScaleAndTransform (const Standard_Integer theScaleFactor,
+ const gp_GTrsf& theTrsf) const Standard_OVERRIDE;
// SAT Tests for different objects
private:
- void cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum);
+ void cacheVertexProjections (SelectMgr_RectangularFrustum* theFrustum) const;
private:
enum { LeftTopNear, LeftTopFar,
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-#include <Bnd_Box.hxx>
+#include <SelectMgr_SelectableObjectSet.hxx>
+#include <SelectMgr_VectorTypes.hxx>
+
#include <BVH_BinnedBuilder.hxx>
+#include <BVH_LinearBuilder.hxx>
-#include <SelectMgr_SelectableObjectSet.hxx>
+namespace
+{
+ //! Short-cut definition of indexed data map of selectable objects
+ typedef NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> ObjectsMap;
+
+ //-------------------------------------------------------------------------------------
+ // Adaptor over regular objects subset of SelectMgr_SelectableObjectSet for BVH builder
+ //-------------------------------------------------------------------------------------
+
+ //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
+ //! so the BVH builder could explicitly arrange objects in the map as necessary
+ //! to provide synchronization of indexes with constructed BVH tree.
+ class BVHBuilderAdaptorRegular : public BVH_Set<Standard_Real, 3>
+ {
+ public:
+
+ //! Construct adaptor.
+ BVHBuilderAdaptorRegular (ObjectsMap& theObjects) : myObjects (theObjects) {};
+
+ //! Returns bounding box of object with index theIndex
+ virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
+ {
+ const Handle(SelectMgr_SelectableObject)& anObject = myObjects.FindKey (theIndex + 1);
+ Bnd_Box aBox;
+ anObject->BoundingBox (aBox);
+ if (aBox.IsVoid())
+ return Select3D_BndBox3d();
+
+ return Select3D_BndBox3d (SelectMgr_Vec3 (aBox.CornerMin().X(), aBox.CornerMin().Y(), aBox.CornerMin().Z()),
+ SelectMgr_Vec3 (aBox.CornerMax().X(), aBox.CornerMax().Y(), aBox.CornerMax().Z()));
+ }
+
+ //! Returns bounding box of the whole subset.
+ virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
+ {
+ if (!myBox.IsValid())
+ {
+ myBox = BVH_Set<Standard_Real, 3>::Box();
+ }
+ return myBox;
+ }
+
+ //! Make inherited method Box() visible to avoid CLang warning
+ using BVH_Set<Standard_Real, 3>::Box;
+
+ //! Returns center of object with index theIndex in the set
+ //! along the given axis theAxis
+ virtual Standard_Real Center (const Standard_Integer theIndex,
+ const Standard_Integer theAxis) const Standard_OVERRIDE
+ {
+ const Select3D_BndBox3d aBndBox = Box (theIndex);
+
+ return (aBndBox.CornerMin()[theAxis] +
+ aBndBox.CornerMax()[theAxis]) * 0.5;
+ }
+
+ //! Returns size of objects set.
+ virtual Standard_Integer Size() const Standard_OVERRIDE
+ {
+ return myObjects.Size();
+ }
+
+ //! Swaps items with indexes theIndex1 and theIndex2 in the set
+ virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
+ {
+ myObjects.Swap (theIndex1 + 1, theIndex2 + 1);
+ }
+
+ private:
+ BVHBuilderAdaptorRegular& operator=(BVHBuilderAdaptorRegular) { return *this; }
+
+ private:
+ ObjectsMap& myObjects;
+ mutable Select3D_BndBox3d myBox;
+ };
+
+ //----------------------------------------------------------------------------------------
+ // Adaptor over persistent objects subset of SelectMgr_SelectableObjectSet for BVH builder
+ //----------------------------------------------------------------------------------------
+
+ //! This class provides direct access to fields of SelectMgr_SelectableObjectSet
+ //! so the BVH builder could explicitly arrange objects in the map as necessary
+ //! to provide synchronization of indexes with constructed BVH tree.
+ class BVHBuilderAdaptorPersistent : public BVH_Set<Standard_Real, 3>
+ {
+ public:
+
+ //! Construct adaptor.
+ //! @param theCamera, theProjectionMat, theWorldViewMat,
+ //! theWidth, theHeight [in] view properties used for computation of
+ //! bounding boxes within the world view camera space.
+ BVHBuilderAdaptorPersistent (ObjectsMap& theObjects,
+ const Handle(Graphic3d_Camera)& theCamera,
+ const Graphic3d_Mat4d& theProjectionMat,
+ const Graphic3d_Mat4d& theWorldViewMat,
+ const Standard_Integer theWidth,
+ const Standard_Integer theHeight)
+ : myObjects (theObjects)
+ {
+ myBoundings.ReSize (myObjects.Size());
+ for (Standard_Integer anI = 1; anI <= myObjects.Size(); ++anI)
+ {
+ const Handle(SelectMgr_SelectableObject)& anObject = myObjects (anI);
+
+ Bnd_Box aBoundingBox;
+ anObject->BoundingBox (aBoundingBox);
+ if (aBoundingBox.IsVoid())
+ {
+ myBoundings.Add (new Select3D_HBndBox3d());
+ }
+ else
+ {
+ anObject->TransformPersistence().Apply (
+ theCamera, theProjectionMat, theWorldViewMat, theWidth, theHeight, aBoundingBox);
+
+ const gp_Pnt aMin = aBoundingBox.CornerMin();
+ const gp_Pnt aMax = aBoundingBox.CornerMax();
+ myBoundings.Add (new Select3D_HBndBox3d (Select3D_Vec3 (aMin.X(), aMin.Y(), aMin.Z()),
+ Select3D_Vec3 (aMax.X(), aMax.Y(), aMax.Z())));
+ }
+ }
+ }
-//=======================================================================
-// function : SelectMgr_SelectableObjectSet
-// purpose : Creates new empty objects set and initializes BVH tree
-// builder to Binned builder with 1 element per list
-//=======================================================================
+ //! Returns bounding box of object with index theIndex
+ virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE
+ {
+ return *myBoundings (theIndex + 1);
+ }
+
+ //! Returns bounding box of the whole subset.
+ virtual Select3D_BndBox3d Box() const Standard_OVERRIDE
+ {
+ if (!myBox.IsValid())
+ {
+ myBox = BVH_Set<Standard_Real, 3>::Box();
+ }
+ return myBox;
+ }
+
+ //! Make inherited method Box() visible to avoid CLang warning
+ using BVH_Set<Standard_Real, 3>::Box;
+
+ //! Returns center of object with index theIndex in the set
+ //! along the given axis theAxis
+ virtual Standard_Real Center (const Standard_Integer theIndex,
+ const Standard_Integer theAxis) const Standard_OVERRIDE
+ {
+ const Select3D_BndBox3d& aBoundingBox = *myBoundings (theIndex + 1);
+
+ return (aBoundingBox.CornerMin()[theAxis] + aBoundingBox.CornerMax()[theAxis]) * 0.5;
+ }
+
+ //! Returns size of objects set.
+ virtual Standard_Integer Size() const Standard_OVERRIDE
+ {
+ return myObjects.Size();
+ }
+
+ //! Swaps items with indexes theIndex1 and theIndex2 in the set
+ virtual void Swap (const Standard_Integer theIndex1, const Standard_Integer theIndex2) Standard_OVERRIDE
+ {
+ const Standard_Integer aStructIdx1 = theIndex1 + 1;
+ const Standard_Integer aStructIdx2 = theIndex2 + 1;
+
+ myObjects.Swap (aStructIdx1, aStructIdx2);
+ myBoundings.Swap (aStructIdx1, aStructIdx2);
+ }
+
+ private:
+ BVHBuilderAdaptorPersistent& operator=(BVHBuilderAdaptorPersistent) { return *this; }
+
+ private:
+ ObjectsMap& myObjects;
+ mutable Select3D_BndBox3d myBox;
+ typedef NCollection_Shared<Select3D_BndBox3d> Select3D_HBndBox3d;
+ NCollection_IndexedMap<Handle(Select3D_HBndBox3d)> myBoundings;
+ };
+
+ static const Graphic3d_Mat4d THE_IDENTITY_MAT;
+}
+
+//=============================================================================
+// Function: Constructor
+// Purpose :
+//=============================================================================
SelectMgr_SelectableObjectSet::SelectMgr_SelectableObjectSet()
+: myLastWidth (0),
+ myLastHeight (0)
{
- myBuilder = new BVH_BinnedBuilder<Standard_Real, 3, 4> (1, 32, Standard_True);
+ myBVH[BVHSubset_2dPersistent] = new BVH_Tree<Standard_Real, 3>();
+ myBVH[BVHSubset_3dPersistent] = new BVH_Tree<Standard_Real, 3>();
+ myBVH[BVHSubset_3d] = new BVH_Tree<Standard_Real, 3>();
+
+ myBuilder[BVHSubset_2dPersistent] = new BVH_LinearBuilder<Standard_Real, 3> (1, 32);
+ myBuilder[BVHSubset_3dPersistent] = new BVH_LinearBuilder<Standard_Real, 3> (1, 32);
+ myBuilder[BVHSubset_3d] = new BVH_BinnedBuilder<Standard_Real, 3, 4> (1, 32, Standard_True);
+
+ myIsDirty[BVHSubset_2dPersistent] = Standard_False;
+ myIsDirty[BVHSubset_3dPersistent] = Standard_False;
+ myIsDirty[BVHSubset_3d] = Standard_False;
}
-//=======================================================================
-// function : Append
-// purpose : Adds new object to the set and marks BVH tree for rebuild
-//=======================================================================
+//=============================================================================
+// Function: Append
+// Purpose :
+//=============================================================================
Standard_Boolean SelectMgr_SelectableObjectSet::Append (const Handle(SelectMgr_SelectableObject)& theObject)
{
- Standard_Integer aSize = Size();
+ // get an appropriate BVH subset to insert the object into it
+ const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
- if (aSize < myObjects.Add (theObject))
+ // check that the object is excluded from other subsets
+ if (myObjects[(aSubsetIdx + 1) % BVHSubsetNb].Contains (theObject)
+ || myObjects[(aSubsetIdx + 2) % BVHSubsetNb].Contains (theObject))
{
- MarkDirty();
+ return Standard_False;
+ }
+
+ // try adding it into the appropriate object subset
+ const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
+
+ if (aSize < myObjects[aSubsetIdx].Add (theObject))
+ {
+ myIsDirty[aSubsetIdx] = Standard_True;
return Standard_True;
}
return Standard_False;
}
-//=======================================================================
-// function : Remove
-// purpose : Removes object theObject from set and marks BVH tree for
-// rebuild
-//=======================================================================
+//=============================================================================
+// Function: Remove
+// Purpose :
+//=============================================================================
Standard_Boolean SelectMgr_SelectableObjectSet::Remove (const Handle(SelectMgr_SelectableObject)& theObject)
{
- const Standard_Integer anIndex = myObjects.FindIndex (theObject);
-
- if (anIndex != 0)
+ // remove object from the first found subset
+ for (Standard_Integer aSubsetIdx = 0; aSubsetIdx < BVHSubsetNb; ++aSubsetIdx)
{
- if (anIndex != Size())
+ const Standard_Integer anIndex = myObjects[aSubsetIdx].FindIndex (theObject);
+
+ if (anIndex != 0)
{
- Swap (anIndex - 1, Size() - 1);
- }
+ const Standard_Integer aSize = myObjects[aSubsetIdx].Size();
- myObjects.RemoveLast();
+ if (anIndex != aSize)
+ {
+ myObjects[aSubsetIdx].Swap (anIndex, aSize);
+ }
- MarkDirty();
+ myObjects[aSubsetIdx].RemoveLast();
+ myIsDirty[aSubsetIdx] = Standard_True;
- return Standard_True;
+ return Standard_True;
+ }
}
return Standard_False;
}
-//=======================================================================
-// function : Box
-// purpose : Returns bounding box of object with index theIndex
-//=======================================================================
-Select3D_BndBox3d SelectMgr_SelectableObjectSet::Box (const Standard_Integer theIndex) const
+//=============================================================================
+// Function: ChangeSubset
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::ChangeSubset (const Handle(SelectMgr_SelectableObject)& theObject)
{
- const Handle(SelectMgr_SelectableObject)& anObject = GetObjectById (theIndex);
- Bnd_Box aBox;
- anObject->BoundingBox (aBox);
- if (aBox.IsVoid())
- return Select3D_BndBox3d();
-
- return Select3D_BndBox3d (SelectMgr_Vec3 (aBox.CornerMin().X(), aBox.CornerMin().Y(), aBox.CornerMin().Z()),
- SelectMgr_Vec3 (aBox.CornerMax().X(), aBox.CornerMax().Y(), aBox.CornerMax().Z()));
-}
+ // do not do anything is object is not in the map
+ const Standard_Integer aCurrSubsetIdx = currentSubset (theObject);
-//=======================================================================
-// function : Center
-// purpose : Returns center of object with index theIndex in the set
-// along the given axis theAxis
-//=======================================================================
-Standard_Real SelectMgr_SelectableObjectSet::Center (const Standard_Integer theIndex,
- const Standard_Integer theAxis) const
-{
- Select3D_BndBox3d aBndBox = Box (theIndex);
+ if (aCurrSubsetIdx < 0)
+ {
+ return;
+ }
+
+ // check whether the subset need to be changed at all
+ const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
+
+ if (aCurrSubsetIdx == aSubsetIdx)
+ {
+ return;
+ }
- return (aBndBox.CornerMin()[theAxis] +
- aBndBox.CornerMax()[theAxis]) * 0.5;
+ // replace object in the maps
+ Remove (theObject);
+ Append (theObject);
}
-//=======================================================================
-// function : Swap
-// purpose : Swaps items with indexes theIndex1 and theIndex2 in the set
-//=======================================================================
-void SelectMgr_SelectableObjectSet::Swap (const Standard_Integer theIndex1,
- const Standard_Integer theIndex2)
+//=============================================================================
+// Function: UpdateBVH
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::UpdateBVH (const Handle(Graphic3d_Camera)& theCamera,
+ const Graphic3d_Mat4d& theProjectionMat,
+ const Graphic3d_Mat4d& theWorldViewMat,
+ const Graphic3d_WorldViewProjState& theViewState,
+ const Standard_Integer theViewportWidth,
+ const Standard_Integer theViewportHeight)
{
- myObjects.Swap (theIndex1 + 1, theIndex2 + 1);
+ // -----------------------------------------
+ // check and update 3D BVH tree if necessary
+ // -----------------------------------------
+ if (!IsEmpty (BVHSubset_3d) && myIsDirty[BVHSubset_3d])
+ {
+ // construct adaptor over private fields to provide direct access for the BVH builder
+ BVHBuilderAdaptorRegular anAdaptor (myObjects[BVHSubset_3d]);
+
+ // update corresponding BVH tree data structure
+ myBuilder[BVHSubset_3d]->Build (&anAdaptor, myBVH[BVHSubset_3d].operator->(), anAdaptor.Box());
+
+ // release dirty state
+ myIsDirty[BVHSubset_3d] = Standard_False;
+ }
+
+ if (!theCamera.IsNull())
+ {
+ const Standard_Boolean isWindowSizeChanged =
+ (myLastHeight != theViewportHeight) || (myLastWidth != theViewportWidth);
+
+ // -----------------------------------------------------
+ // check and update 3D persistence BVH tree if necessary
+ // -----------------------------------------------------
+ if (!IsEmpty (BVHSubset_3dPersistent) &&
+ (myIsDirty[BVHSubset_3dPersistent] || myLastViewState.IsChanged (theViewState) || isWindowSizeChanged))
+ {
+ // construct adaptor over private fields to provide direct access for the BVH builder
+ BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_3dPersistent],
+ theCamera, theProjectionMat, theWorldViewMat, theViewportWidth, theViewportHeight);
+
+ // update corresponding BVH tree data structure
+ myBuilder[BVHSubset_3dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_3dPersistent].operator->(), anAdaptor.Box());
+ }
+
+ // -----------------------------------------------------
+ // check and update 2D persistence BVH tree if necessary
+ // -----------------------------------------------------
+ if (!IsEmpty (BVHSubset_2dPersistent) &&
+ (myIsDirty[BVHSubset_2dPersistent] || myLastViewState.IsProjectionChanged (theViewState) || isWindowSizeChanged))
+ {
+ // construct adaptor over private fields to provide direct access for the BVH builder
+ BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_2dPersistent],
+ theCamera, theProjectionMat, THE_IDENTITY_MAT, theViewportWidth, theViewportHeight);
+
+ // update corresponding BVH tree data structure
+ myBuilder[BVHSubset_2dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_2dPersistent].operator->(), anAdaptor.Box());
+ }
+
+ // release dirty state for every subset
+ myIsDirty[BVHSubset_3dPersistent] = Standard_False;
+ myIsDirty[BVHSubset_2dPersistent] = Standard_False;
+
+ // keep last view state
+ myLastViewState = theViewState;
+ }
+
+ // keep last window state
+ myLastWidth = theViewportWidth;
+ myLastHeight = theViewportHeight;
}
-//=======================================================================
-// function : Size
-// purpose : Returns size of objects set
-//=======================================================================
-Standard_Integer SelectMgr_SelectableObjectSet::Size() const
+//=============================================================================
+// Function: MarkDirty
+// Purpose :
+//=============================================================================
+void SelectMgr_SelectableObjectSet::MarkDirty()
{
- return myObjects.Size();
+ myIsDirty[BVHSubset_3d] = Standard_True;
+ myIsDirty[BVHSubset_3dPersistent] = Standard_True;
+ myIsDirty[BVHSubset_2dPersistent] = Standard_True;
}
#define _SelectMgr_SelectableObjectSet_HeaderFile
#include <BVH_PrimitiveSet.hxx>
-
-#include <Select3D_BndBox3d.hxx>
-#include <SelectMgr_SelectableObject.hxx>
-#include <SelectMgr_VectorTypes.hxx>
-
+#include <BVH_Tree.hxx>
+#include <Graphic3d_Mat4d.hxx>
+#include <Graphic3d_WorldViewProjState.hxx>
+#include <NCollection_Handle.hxx>
#include <NCollection_IndexedMap.hxx>
+#include <SelectMgr_SelectableObject.hxx>
-//! The purpose of this class is to organize all selectable objects into
-//! data structure, allowing to build BVH tree. For selectable objects
-//! binned BVH builder is used with 32 bins and 1 element per leaf.
-class SelectMgr_SelectableObjectSet : public BVH_PrimitiveSet<Standard_Real, 3>
+//! The purpose of this class is to organize all selectable objects into data structure, allowing to build
+//! set of BVH trees for each transformation persistence subclass of selectable objects. This allow to minify
+//! number of updates for BVH trees - for example 2D persistent object subclass depends only on camera's projection
+//! and the corresponding BVH tree needs to be updated when camera's projection parameters change, while another
+//! tree for non-persistent objects can be left unchanged in this case.
+class SelectMgr_SelectableObjectSet
{
public:
- //! Creates new empty objects set and initializes BVH tree
- //! builder to Binned builder with 1 element per list
+ //! This enumeration declares names for subsets of selectable objects. Each subset has independent BVH tree.
+ //! The class maintains subsets of selectable objects by their persistence flag. This allows to restric
+ //! rebuilding of the trees for particular subset when the camera change does not implicitly require it:
+ //! - BVHSubset_3d refers to the subset of normal world-space 3D objects. Associated BVH tree does not depend
+ //! on the camera's state at all.
+ //! This subset uses binned BVH builder with 32 bins and 1 element per leaf.
+ //! - BVHSubset_3dPersistent refers to the subset of 3D persistent selectable objects (rotate, pan, zoom persistence).
+ //! Associated BVH tree needs to be updated when either the camera's projection and position change.
+ //! This subset uses linear BVH builder with 32 levels of depth and 1 element per leaf.
+ //! - BVHSubset_2dPersistent refers to the subset of 2D persistent selectable objects. Associated BVH tree
+ //! needs to be updated only when camera's projection changes. Bounding volumes for this object subclass
+ //! is represented directly in eye space coordinates.
+ //! This subset uses linear BVH builder with 32 levels of depth and 1 element per leaf.
+ enum BVHSubset
+ {
+ BVHSubset_3d,
+ BVHSubset_3dPersistent,
+ BVHSubset_2dPersistent,
+ BVHSubsetNb
+ };
+
+public:
+
+ //! Class to iterate sequentually over all objects from every subset.
+ class Iterator
+ {
+ //! Short-cut definition of map iterator type
+ typedef NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)>::Iterator ObjectMapIterator;
+
+ public:
+
+ //! Default constructor without initialization.
+ Iterator() : mySet (NULL), mySubsetIdx (BVHSubsetNb) {}
+
+ //! Constructs and initializes the iterator.
+ Iterator (const SelectMgr_SelectableObjectSet& theSet) { Init (theSet); }
+
+ //! Initializes the iterator.
+ void Init (const SelectMgr_SelectableObjectSet& theSet)
+ {
+ mySet = &theSet;
+ mySubsetIdx = 0;
+ mySubsetIt = ObjectMapIterator (theSet.myObjects[mySubsetIdx]);
+ More();
+ }
+
+ //! Returns false when there is no more objects to iterate over.
+ Standard_Boolean More()
+ {
+ if (mySubsetIt.More())
+ {
+ return Standard_True;
+ }
+ else if ((mySubsetIdx == BVHSubsetNb - 1) || mySet == NULL)
+ {
+ return Standard_False;
+ }
+ mySubsetIt = ObjectMapIterator (mySet->myObjects[++mySubsetIdx]);
+ return More();
+ }
+
+ //! Steps to next selectable object in the set.
+ void Next() { mySubsetIt.Next(); }
+
+ //! Returns current object.
+ const Handle(SelectMgr_SelectableObject)& Value() const { return mySubsetIt.Value(); }
+
+ private:
+ const SelectMgr_SelectableObjectSet* mySet;
+ Standard_Integer mySubsetIdx;
+ ObjectMapIterator mySubsetIt;
+ };
+
+public:
+
+ //! Creates new empty objects set and initializes BVH tree builders for each subset.
Standard_EXPORT SelectMgr_SelectableObjectSet();
//! Releases resources of selectable object set.
virtual ~SelectMgr_SelectableObjectSet() { }
- //! Adds new object to the set and marks BVH tree for rebuild.
- //! @return true if structure added, otherwise returns false (structure already in the set).
+ //! Adds the new selectable object to the set. The selectable object is placed into one of the
+ //! predefined subsets depending on its persistence type. After adding an object, this method
+ //! marks the corresponding BVH tree for rebuild.
+ //! @return true if selectable object is added, otherwise returns false (selectable object is already in the set).
Standard_EXPORT Standard_Boolean Append (const Handle(SelectMgr_SelectableObject)& theObject);
- //! Removes object theObject from set and marks BVH tree for rebuild.
- //! @return true if structure removed, otherwise returns false (structure is not in the set).
+ //! Removes the selectable object from the set. The selectable object is removed from the subset
+ //! it has been placed into. After removing an object, this method marks the corresponding
+ //! BVH tree for rebuild.
+ //! @return true if selectable object is removed, otherwise returns false (selectable object is not in the set).
Standard_EXPORT Standard_Boolean Remove (const Handle(SelectMgr_SelectableObject)& theObject);
- //! Returns bounding box of object with index theIndex
- Standard_EXPORT virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE;
+ //! Performs necessary updates when object's persistence types changes.
+ //! This method should be called right after changing transformation persistence flags of the
+ //! objects and before updating BVH tree - to provide up-to-date state of the object set.
+ Standard_EXPORT void ChangeSubset (const Handle(SelectMgr_SelectableObject)& theObject);
- //! Make inherited method Box() visible to avoid CLang warning
- using BVH_PrimitiveSet<Standard_Real, 3>::Box;
+ //! Updates outdated BVH trees and remembers the last state of the
+ //! camera view-projection matrices and viewport (window) dimensions.
+ Standard_EXPORT void UpdateBVH (const Handle(Graphic3d_Camera)& theCamera,
+ const Graphic3d_Mat4d& theProjectionMat,
+ const Graphic3d_Mat4d& theWorldViewMat,
+ const Graphic3d_WorldViewProjState& theViewState,
+ const Standard_Integer theViewportWidth,
+ const Standard_Integer theViewportHeight);
- //! Returns center of object with index theIndex in the set
- //! along the given axis theAxis
- Standard_EXPORT virtual Standard_Real Center (const Standard_Integer theIndex,
- const Standard_Integer theAxis) const Standard_OVERRIDE;
+ //! Marks every BVH subset for update.
+ Standard_EXPORT void MarkDirty();
- //! Swaps items with indexes theIndex1 and theIndex2 in the set
- Standard_EXPORT virtual void Swap (const Standard_Integer theIndex1,
- const Standard_Integer theIndex2) Standard_OVERRIDE;
+ //! Returns true if this objects set contains theObject given.
+ Standard_Boolean Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
+ {
+ return myObjects[BVHSubset_3d].Contains (theObject)
+ || myObjects[BVHSubset_3dPersistent].Contains (theObject)
+ || myObjects[BVHSubset_2dPersistent].Contains (theObject);
+ }
- //! Returns size of objects set
- Standard_EXPORT virtual Standard_Integer Size() const Standard_OVERRIDE;
+ //! Returns true if the object set does not contain any selectable objects.
+ Standard_Boolean IsEmpty() const
+ {
+ return myObjects[BVHSubset_3d].IsEmpty()
+ && myObjects[BVHSubset_3dPersistent].IsEmpty()
+ && myObjects[BVHSubset_2dPersistent].IsEmpty();
+ }
- //! Returns object from set by theIndex given
- const Handle(SelectMgr_SelectableObject)& GetObjectById (const Standard_Integer theIndex) const
+ //! Returns true if the specified object subset is empty.
+ Standard_Boolean IsEmpty (const BVHSubset theSubset) const
{
- return myObjects.FindKey (theIndex + 1);
+ return myObjects[theSubset].IsEmpty();
}
- //! Returns true if this objects set contains theObject given
- Standard_Boolean Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
+ //! Returns object from subset theSubset by theIndex given. The method allows to get selectable object
+ //! referred by the index of an element of the subset's BVH tree.
+ const Handle(SelectMgr_SelectableObject)& GetObjectById (const BVHSubset theSubset,
+ const Standard_Integer theIndex) const
+ {
+ return myObjects[theSubset].FindKey (theIndex + 1);
+ }
+
+ //! Returns computed BVH for the theSubset given.
+ const NCollection_Handle<BVH_Tree<Standard_Real, 3> >& BVH(const BVHSubset theSubset) const
+ {
+ return myBVH[theSubset];
+ }
+
+private:
+
+ //! Returns an appropriate subset of theObject given depending on its persistence type.
+ Standard_Integer appropriateSubset (const Handle(SelectMgr_SelectableObject)& theObject)
+ {
+ if (!theObject->TransformPersistence().Flags)
+ {
+ return SelectMgr_SelectableObjectSet::BVHSubset_3d;
+ }
+ else if (theObject->TransformPersistence().Flags & Graphic3d_TMF_2d)
+ {
+ return SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent;
+ }
+ else
+ {
+ return SelectMgr_SelectableObjectSet::BVHSubset_3dPersistent;
+ }
+ }
+
+ //! Returns current subset of theObject given.
+ Standard_Integer currentSubset (const Handle(SelectMgr_SelectableObject)& theObject)
{
- return myObjects.Contains (theObject);
+ for (Standard_Integer aSubsetIdx = 0; aSubsetIdx < BVHSubsetNb; ++aSubsetIdx)
+ {
+ if (myObjects[aSubsetIdx].Contains (theObject))
+ {
+ return aSubsetIdx;
+ }
+ }
+ return -1;
}
private:
- NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> myObjects;
+ NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> myObjects[BVHSubsetNb]; //!< Map of objects for each subset
+ NCollection_Handle<BVH_Tree<Standard_Real, 3> > myBVH[BVHSubsetNb]; //!< BVH tree computed for each subset
+ NCollection_Handle<BVH_Builder<Standard_Real, 3> > myBuilder[BVHSubsetNb]; //!< Builder allocated for each subset
+ Standard_Boolean myIsDirty[BVHSubsetNb]; //!< Dirty flag for each subset
+ Graphic3d_WorldViewProjState myLastViewState; //!< Last view-projection state used for construction of BVH
+ Standard_Integer myLastWidth; //!< Last viewport's (window's) width used for construction of BVH
+ Standard_Integer myLastHeight; //!< Last viewport's (window's) height used for construction of BVH
+ friend class Iterator;
};
#endif // _SelectMgr_SelectableObjectSet_HeaderFile
+++ /dev/null
-// Created on: 2015-06-30
-// Created by: Anton POLETAEV
-// Copyright (c) 2015 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 <SelectMgr_SelectableObjectTrsfPersSet.hxx>
-
-#include <Bnd_Box.hxx>
-#include <BVH_LinearBuilder.hxx>
-#include <SelectMgr_VectorTypes.hxx>
-
-//=======================================================================
-// function : SelectMgr_SelectableObjectTrsfPersSet
-// purpose :
-//=======================================================================
-SelectMgr_SelectableObjectTrsfPersSet::SelectMgr_SelectableObjectTrsfPersSet()
-: myIsDirty (Standard_False),
- myBVH (new BVH_Tree<Standard_Real, 3>())
-{
- myBuilder = new BVH_LinearBuilder<Standard_Real, 3> (1, 32);
-}
-
-//=======================================================================
-// function : Size
-// purpose :
-//=======================================================================
-Standard_Integer SelectMgr_SelectableObjectTrsfPersSet::Size() const
-{
- return myObjects.Size();
-}
-
-//=======================================================================
-// function : Box
-// purpose :
-//=======================================================================
-Select3D_BndBox3d SelectMgr_SelectableObjectTrsfPersSet::Box (const Standard_Integer theIndex) const
-{
- return *myObjectBoxes (theIndex + 1);
-}
-
-//=======================================================================
-// function : Center
-// purpose :
-//=======================================================================
-Standard_Real SelectMgr_SelectableObjectTrsfPersSet::Center (const Standard_Integer theIndex,
- const Standard_Integer theAxis) const
-{
- const Select3D_BndBox3d& aBndBox = *myObjectBoxes (theIndex + 1);
-
- return (aBndBox.CornerMin()[theAxis] + aBndBox.CornerMax()[theAxis]) * 0.5;
-}
-
-//=======================================================================
-// function : Swap
-// purpose :
-//=======================================================================
-void SelectMgr_SelectableObjectTrsfPersSet::Swap (const Standard_Integer theIndex1,
- const Standard_Integer theIndex2)
-{
- const Standard_Integer aStructIdx1 = theIndex1 + 1;
- const Standard_Integer aStructIdx2 = theIndex2 + 1;
-
- myObjects.Swap (aStructIdx1, aStructIdx2);
- myObjectBoxes.Swap (aStructIdx1, aStructIdx2);
-}
-
-//=======================================================================
-// function : Append
-// purpose :
-//=======================================================================
-Standard_Boolean SelectMgr_SelectableObjectTrsfPersSet::Append (const Handle(SelectMgr_SelectableObject)& theObject)
-{
- Standard_Integer aSize = Size();
-
- if (aSize < myObjects.Add (theObject))
- {
- MarkDirty();
-
- return Standard_True;
- }
-
- return Standard_False;
-}
-
-//=======================================================================
-// function : Remove
-// purpose :
-//=======================================================================
-Standard_Boolean SelectMgr_SelectableObjectTrsfPersSet::Remove (const Handle(SelectMgr_SelectableObject)& theObject)
-{
- const Standard_Integer anIndex = myObjects.FindIndex (theObject);
-
- if (anIndex != 0)
- {
- myObjects.Swap (Size(), anIndex);
- myObjects.RemoveLast();
- MarkDirty();
-
- return Standard_True;
- }
-
- return Standard_False;
-}
-
-//=======================================================================
-// function : BVH
-// purpose :
-//=======================================================================
-const NCollection_Handle<BVH_Tree<Standard_Real, 3> >&
- SelectMgr_SelectableObjectTrsfPersSet::BVH (const Handle(Graphic3d_Camera)& theCamera,
- const Graphic3d_Mat4d& theProjectionMatrix,
- const Graphic3d_Mat4d& theWorldViewMatrix,
- const Standard_Integer theViewportWidth,
- const Standard_Integer theViewportHeight,
- const Graphic3d_WorldViewProjState& theWVPState)
-{
- if (!myIsDirty && (myObjectBoxesState.IsValid() && !myObjectBoxesState.IsChanged(theWVPState)))
- {
- return myBVH;
- }
-
- myObjectBoxes.ReSize (myObjects.Size());
-
- for (Standard_Integer anObjectIdx = 1; anObjectIdx <= myObjects.Size(); ++anObjectIdx)
- {
- const Handle(SelectMgr_SelectableObject)& anObject = myObjects (anObjectIdx);
-
- Bnd_Box aBoundingBox;
-
- if (anObject->TransformPersistence().Flags != 0)
- {
- anObject->BoundingBox (aBoundingBox);
- if (!aBoundingBox.IsVoid())
- {
- anObject->TransformPersistence().Apply (theCamera, theProjectionMatrix, theWorldViewMatrix, theViewportWidth, theViewportHeight, aBoundingBox);
- }
- }
-
- if (aBoundingBox.IsVoid())
- {
- myObjectBoxes.Add (new Select3D_BndBox3d());
- }
- else
- {
- gp_Pnt aMin = aBoundingBox.CornerMin();
- gp_Pnt aMax = aBoundingBox.CornerMax();
-
- myObjectBoxes.Add (new Select3D_BndBox3d (Select3D_Vec3 (aMin.X(), aMin.Y(), aMin.Z()),
- Select3D_Vec3 (aMax.X(), aMax.Y(), aMax.Z())));
- }
- }
-
- myBuilder->Build (this, myBVH.operator->(), BVH_Set<Standard_Real, 3>::Box());
-
- myObjectBoxesState = theWVPState;
- myObjectBoxes.Clear();
- myIsDirty = Standard_False;
-
- return myBVH;
-}
+++ /dev/null
-// Created on: 2015-06-30
-// Created by: Anton POLETAEV
-// Copyright (c) 2015 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.
-
-#ifndef _SelectMgr_SelectableObjectTrsfPersSet_HeaderFile
-#define _SelectMgr_SelectableObjectTrsfPersSet_HeaderFile
-
-#include <BVH_Builder.hxx>
-#include <BVH_Set.hxx>
-#include <BVH_Tree.hxx>
-#include <Graphic3d_Camera.hxx>
-#include <Graphic3d_WorldViewProjState.hxx>
-#include <NCollection_Handle.hxx>
-#include <NCollection_IndexedMap.hxx>
-#include <Select3D_BndBox3d.hxx>
-#include <SelectMgr_SelectableObject.hxx>
-
-//! Primitive set specialized for transformation persistent selectable objects.
-//! Provides built-in mechanism to invalidate tree when world view projection state changes.
-//! Due to frequent invalidation of BVH tree the choice of BVH tree builder is made
-//! in favor of BVH linear builder (quick rebuild).
-class SelectMgr_SelectableObjectTrsfPersSet : public BVH_Set<Standard_Real, 3>
-{
-private:
-
- typedef NCollection_Handle<Select3D_BndBox3d> HBndBox3d;
-
- Handle(SelectMgr_SelectableObject) EMPTY_OBJ;
-
-public:
-
- //! Creates new empty objects set and initializes BVH tree
- //! builder to Linear builder with 1 element per list.
- Standard_EXPORT SelectMgr_SelectableObjectTrsfPersSet();
-
- //! Returns size of objects set.
- Standard_EXPORT virtual Standard_Integer Size() const Standard_OVERRIDE;
-
- //! Returns bounding box of object with index theIndex.
- Standard_EXPORT virtual Select3D_BndBox3d Box (const Standard_Integer theIndex) const Standard_OVERRIDE;
-
- //! Returns center of object with index theIndex in the set along the given axis theAxis.
- Standard_EXPORT virtual Standard_Real Center (const Standard_Integer theIndex,
- const Standard_Integer theAxis) const Standard_OVERRIDE;
-
- //! Swaps items with indexes theIndex1 and theIndex2 in the set.
- Standard_EXPORT virtual void Swap (const Standard_Integer theIndex1,
- const Standard_Integer theIndex2) Standard_OVERRIDE;
-
- //! Adds new selectable object to the set.
- //! @return true if structure added, otherwise returns false (structure already in the set).
- Standard_EXPORT Standard_Boolean Append (const Handle(SelectMgr_SelectableObject)& theObject);
-
- //! Removes selectable object from set.
- //! @return true if structure removed, otherwise returns false (structure is not in the set).
- Standard_EXPORT Standard_Boolean Remove (const Handle(SelectMgr_SelectableObject)& theObject);
-
- //! Returns object from set by theIndex given.
- const Handle(SelectMgr_SelectableObject)& GetObjectById (const Standard_Integer theIndex) const
- {
- return myObjects.FindKey (theIndex + 1);
- }
-
- //! Marks object state as outdated (needs BVH rebuilding).
- void MarkDirty()
- {
- myIsDirty = Standard_True;
- }
-
- //! Returns true if this objects set contains theObject given
- Standard_Boolean Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
- {
- return myObjects.Contains (theObject);
- }
-
- //! Returns BVH tree for the given world view projection (builds it if necessary).
- Standard_EXPORT const NCollection_Handle<BVH_Tree<Standard_Real, 3> >& BVH (const Handle(Graphic3d_Camera)& theCamera,
- const Graphic3d_Mat4d& theProjectionMatrix,
- const Graphic3d_Mat4d& theWorldViewMatrix,
- const Standard_Integer theViewportWidth,
- const Standard_Integer theViewportHeight,
- const Graphic3d_WorldViewProjState& theWVPState);
-
-private:
-
- //! Marks internal object state as outdated.
- Standard_Boolean myIsDirty;
-
- //! Constructed bottom-level BVH.
- NCollection_Handle<BVH_Tree<Standard_Real, 3> > myBVH;
-
- //! Builder for bottom-level BVH.
- NCollection_Handle<BVH_Builder<Standard_Real, 3> > myBuilder;
-
- //! Set of transform persistence objects.
- NCollection_IndexedMap<Handle(SelectMgr_SelectableObject)> myObjects;
-
- //! Cached set of bounding boxes precomputed for transformation persistent selectable objects.
- //! Cache exists only during computation of BVH Tree. Bounding boxes are world view projection
- //! dependent and should by synchronized.
- NCollection_IndexedMap<HBndBox3d> myObjectBoxes;
-
- //! State of world view projection used for generation of transformation persistence bounding boxes.
- Graphic3d_WorldViewProjState myObjectBoxesState;
-};
-
-#endif
// - transformation only is needed: @theScaleFactor must be initialized
// as any negative value;
// - scale only is needed: @theTrsf must be set to gp_Identity.
+// Builder is an optional argument that represents corresponding settings for
+// re-constructing transformed frustum from scratch. Can be null if reconstruction
+// is not needed furthermore in the code.
//=======================================================================
SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::ScaleAndTransform (const Standard_Integer theScaleFactor,
- const gp_GTrsf& theTrsf)
+ const gp_GTrsf& theTrsf,
+ const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
{
SelectMgr_SelectingVolumeManager aMgr (Standard_False);
return aMgr;
aMgr.myActiveSelectionType = myActiveSelectionType;
-
aMgr.mySelectingVolumes[myActiveSelectionType / 2]
= mySelectingVolumes[myActiveSelectionType / 2]->ScaleAndTransform (theScaleFactor, theTrsf);
aMgr.myToAllowOverlap = myToAllowOverlap;
+ aMgr.mySelectingVolumes[myActiveSelectionType / 2]->SetBuilder (theBuilder);
return aMgr;
}
// function : WindowSize
// purpose :
//=======================================================================
-void SelectMgr_SelectingVolumeManager::WindowSize (Standard_Integer& theWidth, Standard_Integer& theHeight)
+void SelectMgr_SelectingVolumeManager::WindowSize (Standard_Integer& theWidth, Standard_Integer& theHeight) const
{
mySelectingVolumes[Frustum]->WindowSize (theWidth, theHeight);
}
//! There are no default parameters, but in case if:
//! - transformation only is needed: @theScaleFactor must be initialized as any negative value;
//! - scale only is needed: @theTrsf must be set to gp_Identity.
+ //! Builder is an optional argument that represents corresponding settings for re-constructing transformed
+ //! frustum from scratch. Can be null if reconstruction is not expected furthermore.
Standard_EXPORT virtual SelectMgr_SelectingVolumeManager ScaleAndTransform (const Standard_Integer theScaleFactor,
- const gp_GTrsf& theTrsf);
+ const gp_GTrsf& theTrsf,
+ const Handle(SelectMgr_FrustumBuilder)& theBuilder = NULL) const;
Standard_EXPORT virtual Standard_Integer GetActiveSelectionType() const Standard_OVERRIDE;
//! @return current world view transformation common for all selecting volumes
Standard_EXPORT const Graphic3d_Mat4d& WorldViewMatrix() const;
- Standard_EXPORT void WindowSize (Standard_Integer& theWidth, Standard_Integer& theHeight);
+ Standard_EXPORT void WindowSize (Standard_Integer& theWidth, Standard_Integer& theHeight) const;
//! @return current camera world view projection transformation state common for all selecting volumes
Standard_EXPORT const Graphic3d_WorldViewProjState& WorldViewProjState() const;
private:
enum { Frustum, FrustumSet, VolumeTypesNb }; //!< Defines the amount of available selecting volumes
- NCollection_Handle<SelectMgr_BaseFrustum> mySelectingVolumes[VolumeTypesNb]; //!< Array of selecting volumes
- Standard_Boolean myToAllowOverlap; //!< Defines if partially overlapped entities will me detected or not
+ Handle(SelectMgr_BaseFrustum) mySelectingVolumes[VolumeTypesNb]; //!< Array of selecting volumes
+ Standard_Boolean myToAllowOverlap; //!< Defines if partially overlapped entities will me detected or not
};
-#endif
+#endif
\ No newline at end of file
// purpose : Caches projection of frustum's vertices onto its plane directions
// and {i, j, k}
// =======================================================================
-void SelectMgr_TriangularFrustum::cacheVertexProjections (SelectMgr_TriangularFrustum* theFrustum)
+void SelectMgr_TriangularFrustum::cacheVertexProjections (SelectMgr_TriangularFrustum* theFrustum) const
{
for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; ++aPlaneIdx)
{
// as any negative value;
// - scale only is needed: @theTrsf must be set to gp_Identity.
//=======================================================================
-NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_TriangularFrustum::ScaleAndTransform (const Standard_Integer /*theScale*/,
- const gp_GTrsf& theTrsf)
+Handle(SelectMgr_BaseFrustum) SelectMgr_TriangularFrustum::ScaleAndTransform (const Standard_Integer /*theScale*/,
+ const gp_GTrsf& theTrsf) const
{
- SelectMgr_TriangularFrustum* aRes = new SelectMgr_TriangularFrustum();
+ Handle(SelectMgr_TriangularFrustum) aRes = new SelectMgr_TriangularFrustum();
for (Standard_Integer anIt = 0; anIt < 6; anIt++)
{
computeFrustumNormals (aRes->myEdgeDirs, aRes->myPlanes);
- cacheVertexProjections (aRes);
+ cacheVertexProjections (aRes.get());
- return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
+ return aRes;
}
//=======================================================================
const gp_Pnt2d& theP3) Standard_OVERRIDE;
//! Returns a copy of the frustum transformed according to the matrix given
- Standard_EXPORT virtual NCollection_Handle<SelectMgr_BaseFrustum> ScaleAndTransform (const Standard_Integer theScale,
- const gp_GTrsf& theTrsf) Standard_OVERRIDE;
+ Standard_EXPORT virtual Handle(SelectMgr_BaseFrustum) ScaleAndTransform (const Standard_Integer theScale,
+ const gp_GTrsf& theTrsf) const Standard_OVERRIDE;
// SAT Tests for different objects
private:
- void cacheVertexProjections (SelectMgr_TriangularFrustum* theFrustum);
+ void cacheVertexProjections (SelectMgr_TriangularFrustum* theFrustum) const;
DEFINE_STANDARD_RTTIEXT(SelectMgr_TriangularFrustum,Standard_Transient)
};
// as any negative value;
// - scale only is needed: @theTrsf must be set to gp_Identity.
// =======================================================================
-NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_TriangularFrustumSet::ScaleAndTransform (const Standard_Integer theScale,
- const gp_GTrsf& theTrsf)
+Handle(SelectMgr_BaseFrustum) SelectMgr_TriangularFrustumSet::ScaleAndTransform (const Standard_Integer theScale,
+ const gp_GTrsf& theTrsf) const
{
- SelectMgr_TriangularFrustumSet* aRes = new SelectMgr_TriangularFrustumSet();
+ Handle(SelectMgr_TriangularFrustumSet) aRes = new SelectMgr_TriangularFrustumSet();
for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next())
{
aRes->myFrustums.Append (Handle(SelectMgr_TriangularFrustum)::DownCast (anIter.Value()->ScaleAndTransform (theScale, theTrsf)));
}
- return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
+ return aRes;
}
// =======================================================================
Standard_EXPORT virtual void Build (const TColgp_Array1OfPnt2d& thePoints) Standard_OVERRIDE;
//! Returns a copy of the frustum with all sub-volumes transformed according to the matrix given
- Standard_EXPORT virtual NCollection_Handle<SelectMgr_BaseFrustum> ScaleAndTransform (const Standard_Integer theScale,
- const gp_GTrsf& theTrsf) Standard_OVERRIDE;
+ Standard_EXPORT virtual Handle(SelectMgr_BaseFrustum) ScaleAndTransform (const Standard_Integer theScale,
+ const gp_GTrsf& theTrsf) const Standard_OVERRIDE;
Standard_EXPORT virtual Standard_Boolean Overlaps (const SelectMgr_Vec3& theMinPnt,
const SelectMgr_Vec3& theMaxPnt,
}
}
+ static const Graphic3d_Mat4d THE_IDENTITY_MAT;
}
//==================================================
// 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)
const Standard_Boolean toTransform = aTrsfMtr.Form() != gp_Identity;
if (toScale && toTransform)
{
- theResMgr = mySelectingVolumeMgr.ScaleAndTransform (aScale, aTrsfMtr);
+ theResMgr = theMgr.ScaleAndTransform (aScale, aTrsfMtr, NULL);
}
else if (toScale)
{
if (!theCachedMgrs.IsBound (aScale))
{
- theCachedMgrs.Bind (aScale, mySelectingVolumeMgr.ScaleAndTransform (aScale, gp_Trsf()));
+ theCachedMgrs.Bind (aScale, theMgr.ScaleAndTransform (aScale, gp_Trsf(), NULL));
}
theResMgr = theCachedMgrs.Find (aScale);
}
else if (toTransform)
{
- theResMgr = mySelectingVolumeMgr.ScaleAndTransform (1, aTrsfMtr);
+ theResMgr = theMgr.ScaleAndTransform (1, aTrsfMtr, NULL);
}
}
// between some entity of selectable object theObject and
// current selecting volume
//=======================================================================
-void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_SelectableObject)& theObject)
+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)
{
NCollection_Handle<SelectMgr_SensitiveEntitySet>& anEntitySet =
myMapOfObjectSensitives.ChangeFind (theObject);
}
else
{
- const Graphic3d_Mat4d& aProjection = mySelectingVolumeMgr.ProjectionMatrix();
- const Graphic3d_Mat4d& aWorldView = mySelectingVolumeMgr.WorldViewMatrix();
-
- Standard_Integer aViewportWidth;
- Standard_Integer aViewportHeight;
- mySelectingVolumeMgr.WindowSize (aViewportWidth, aViewportHeight);
-
gp_GTrsf aTPers;
- Graphic3d_Mat4d aMat = theObject->TransformPersistence().Compute (mySelectingVolumeMgr.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight);
+ 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));
}
SelectMgr_SelectingVolumeManager aMgr = aInversedTrsf.Form() != gp_Identity
- ? mySelectingVolumeMgr.ScaleAndTransform (1, aInversedTrsf)
- : mySelectingVolumeMgr;
+ ? theMgr.ScaleAndTransform (1, aInversedTrsf, NULL)
+ : theMgr;
SelectMgr_FrustumCache aScaledTrnsfFrustums;
{
const Handle(SelectBasics_SensitiveEntity)& anEnt = aSensitive->BaseSensitive();
SelectMgr_SelectingVolumeManager aTmpMgr = aMgr;
- computeFrustum (anEnt, aInversedTrsf, aScaledTrnsfFrustums, aTmpMgr);
+ computeFrustum (anEnt, theMgr, aInversedTrsf, aScaledTrnsfFrustums, aTmpMgr);
checkOverlap (anEnt, aInversedTrsf, aTmpMgr);
}
}
{
mystored.Clear();
- NCollection_Handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
- for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
+ Standard_Integer aWidth;
+ Standard_Integer aHeight;
+ mySelectingVolumeMgr.WindowSize (aWidth, aHeight);
+ mySelectableObjects.UpdateBVH (mySelectingVolumeMgr.Camera(),
+ mySelectingVolumeMgr.ProjectionMatrix(),
+ mySelectingVolumeMgr.WorldViewMatrix(),
+ mySelectingVolumeMgr.WorldViewProjState(),
+ aWidth, aHeight);
+
+ for (Standard_Integer aBVHSetIt = 0; aBVHSetIt < SelectMgr_SelectableObjectSet::BVHSubsetNb; ++aBVHSetIt)
{
- const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
- if (isTrsfPers)
+ SelectMgr_SelectableObjectSet::BVHSubset aBVHSubset =
+ static_cast<SelectMgr_SelectableObjectSet::BVHSubset> (aBVHSetIt);
+
+ if (mySelectableObjects.IsEmpty (aBVHSubset))
{
- if (mySelectableObjectsTrsfPers.Size() == 0)
- {
- continue;
- }
- const Graphic3d_Mat4d& aProjection = mySelectingVolumeMgr.ProjectionMatrix();
- const Graphic3d_Mat4d& aWorldView = mySelectingVolumeMgr.WorldViewMatrix();
- const Graphic3d_WorldViewProjState& aWVPState = mySelectingVolumeMgr.WorldViewProjState();
- Standard_Integer aViewportWidth;
- Standard_Integer aViewportHeight;
- mySelectingVolumeMgr.WindowSize (aViewportWidth, aViewportHeight);
- aBVHTree = mySelectableObjectsTrsfPers.BVH (mySelectingVolumeMgr.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
+ 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 (THE_IDENTITY_MAT);
+ aBuilder->SetWindowSize (aWidth, aHeight);
+ aMgr = mySelectingVolumeMgr.ScaleAndTransform (1, aTFrustum, aBuilder);
}
else
{
- if (mySelectableObjects.Size() == 0)
- {
- continue;
- }
- aBVHTree = mySelectableObjects.BVH();
+ aMgr = mySelectingVolumeMgr;
}
+ const Handle(Graphic3d_Camera)& aCamera = mySelectingVolumeMgr.Camera();
+ const Graphic3d_Mat4d& aProjectionMat = mySelectingVolumeMgr.ProjectionMatrix();
+ const Graphic3d_Mat4d& aWorldViewMat = aBVHSubset != SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent
+ ? mySelectingVolumeMgr.WorldViewMatrix()
+ : THE_IDENTITY_MAT;
+
+ const NCollection_Handle<BVH_Tree<Standard_Real, 3> >& aBVHTree = mySelectableObjects.BVH (aBVHSubset);
+
Standard_Integer aNode = 0;
- if (!mySelectingVolumeMgr.Overlaps (aBVHTree->MinPoint (0),
- aBVHTree->MaxPoint (0)))
+ if (!aMgr.Overlaps (aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
{
continue;
}
const Standard_Integer aLeftChildIdx = aBVHTree->Child<0> (aNode);
const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
const Standard_Boolean isLeftChildIn =
- mySelectingVolumeMgr.Overlaps (aBVHTree->MinPoint (aLeftChildIdx),
- aBVHTree->MaxPoint (aLeftChildIdx));
+ aMgr.Overlaps (aBVHTree->MinPoint (aLeftChildIdx), aBVHTree->MaxPoint (aLeftChildIdx));
const Standard_Boolean isRightChildIn =
- mySelectingVolumeMgr.Overlaps (aBVHTree->MinPoint (aRightChildIdx),
- aBVHTree->MaxPoint (aRightChildIdx));
+ aMgr.Overlaps (aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
if (isLeftChildIn
&& isRightChildIn)
{
Standard_Integer anEndIdx = aBVHTree->EndPrimitive (aNode);
for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
{
- Handle(SelectMgr_SelectableObject) aSelectableObject =
- isTrsfPers ? mySelectableObjectsTrsfPers.GetObjectById (anIdx)
- : mySelectableObjects.GetObjectById (anIdx);
+ const Handle(SelectMgr_SelectableObject)& aSelectableObject =
+ mySelectableObjects.GetObjectById (aBVHSubset, anIdx);
- traverseObject (aSelectableObject);
+ traverseObject (aSelectableObject, aMgr, aCamera, aProjectionMat, aWorldViewMat, aWidth, aHeight);
}
if (aHead < 0)
{
//==================================================
Standard_Boolean SelectMgr_ViewerSelector::Contains (const Handle(SelectMgr_SelectableObject)& theObject) const
{
- return mySelectableObjects.Contains (theObject)
- || mySelectableObjectsTrsfPers.Contains (theObject);
+ return mySelectableObjects.Contains (theObject);
}
//==================================================
{
if (!myMapOfObjectSensitives.IsBound (theObject))
{
- if (!theObject->TransformPersistence().Flags)
- {
- mySelectableObjects.Append (theObject);
- }
- else
- {
- mySelectableObjectsTrsfPers.Append (theObject);
- }
-
+ mySelectableObjects.Append (theObject);
NCollection_Handle<SelectMgr_SensitiveEntitySet> anEntitySet = new SelectMgr_SensitiveEntitySet();
myMapOfObjectSensitives.Bind (theObject, anEntitySet);
}
//=======================================================================
void SelectMgr_ViewerSelector::MoveSelectableObject (const Handle(SelectMgr_SelectableObject)& theObject)
{
- if (!mySelectableObjects.Remove (theObject))
- {
- mySelectableObjectsTrsfPers.Remove (theObject);
- }
-
- if (!theObject->TransformPersistence().Flags)
- {
- mySelectableObjects.Append (theObject);
- }
- else
- {
- mySelectableObjectsTrsfPers.Append (theObject);
- }
+ mySelectableObjects.ChangeSubset (theObject);
}
//=======================================================================
{
if (myMapOfObjectSensitives.IsBound (theObject))
{
- if (!mySelectableObjects.Remove (theObject))
- {
- mySelectableObjectsTrsfPers.Remove (theObject);
- }
+ mySelectableObjects.Remove (theObject);
myMapOfObjectSensitives.UnBind (theObject);
}
}
void SelectMgr_ViewerSelector::RebuildObjectsTree (const Standard_Boolean theIsForce)
{
mySelectableObjects.MarkDirty();
- mySelectableObjectsTrsfPers.MarkDirty();
if (theIsForce)
{
- const Graphic3d_Mat4d& aProjection = mySelectingVolumeMgr.ProjectionMatrix();
- const Graphic3d_Mat4d& aWorldView = mySelectingVolumeMgr.WorldViewMatrix();
- const Graphic3d_WorldViewProjState& aWVPState = mySelectingVolumeMgr.WorldViewProjState();
- Standard_Integer aViewportWidth;
- Standard_Integer aViewportHeight;
+ Standard_Integer aViewportWidth, aViewportHeight;
mySelectingVolumeMgr.WindowSize (aViewportWidth, aViewportHeight);
- mySelectableObjects.BVH();
- mySelectableObjectsTrsfPers.BVH (mySelectingVolumeMgr.Camera(), aProjection, aWorldView, aViewportWidth, aViewportHeight, aWVPState);
+ Standard_Integer aWidth;
+ Standard_Integer aHeight;
+ mySelectingVolumeMgr.WindowSize (aWidth, aHeight);
+ mySelectableObjects.UpdateBVH (mySelectingVolumeMgr.Camera(),
+ mySelectingVolumeMgr.ProjectionMatrix(),
+ mySelectingVolumeMgr.WorldViewMatrix(),
+ mySelectingVolumeMgr.WorldViewProjState(),
+ aWidth, aHeight);
}
}
#include <SelectMgr_Selection.hxx>
#include <SelectMgr_SelectableObject.hxx>
#include <SelectMgr_SelectableObjectSet.hxx>
-#include <SelectMgr_SelectableObjectTrsfPersSet.hxx>
#include <SelectMgr_StateOfSelection.hxx>
#include <SelectMgr_ToleranceMap.hxx>
#include <Standard_OStream.hxx>
//! @return True if owner provides depth limits for sensitive clipping.
Standard_EXPORT virtual Standard_Boolean HasDepthClipping (const Handle(SelectMgr_EntityOwner)& theOwner) const;
- //! Internal function that checks if there is possible overlap
- //! between some entity of selectable object theObject and
- //! current selecting volume
- Standard_EXPORT void traverseObject (const Handle(SelectMgr_SelectableObject)& theObject);
+ //! Internal function that checks if there is possible overlap between some entity of selectable object theObject and
+ //! current selecting volume.
+ //! @param theObject [in] the selectable object for traversal.
+ //! @param theMgr [in] the (un)transformed copy of the selecting volume manager representing active selection frustum.
+ //! @param theCamera, theProjectionMat, theWorldViewMat [in] the source camera and matrices for theMgr given.
+ //! @param theViewportWidth, theViewportHeight [in] viewport (window) dimensions for evaluating
+ //! object's transformation persistence.
+ Standard_EXPORT void 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);
//! Internal function that checks if a particular sensitive
//! entity theEntity overlaps current selecting volume precisely
//! needs to be scaled and transformed for the entity and performs
//! necessary calculations
void computeFrustum (const Handle(SelectBasics_SensitiveEntity)& theEnt,
+ const SelectMgr_SelectingVolumeManager& theMgr,
const gp_GTrsf& theInvTrsf,
SelectMgr_FrustumCache& theCachedMgrs,
SelectMgr_SelectingVolumeManager& theResMgr);
SelectMgr_IndexedDataMapOfOwnerCriterion mystored;
SelectMgr_SelectingVolumeManager mySelectingVolumeMgr;
mutable SelectMgr_SelectableObjectSet mySelectableObjects;
- mutable SelectMgr_SelectableObjectTrsfPersSet mySelectableObjectsTrsfPers;
SelectMgr_ToleranceMap myTolerances;
NCollection_DataMap<Graphic3d_ZLayerId, Standard_Integer> myZLayerOrderMap;
//=======================================================================
void StdSelect_ViewerSelector3d::DisplaySensitive (const Handle(V3d_View)& theView)
{
- for (Standard_Integer anObjectIdx = 0; anObjectIdx <= mySelectableObjects.Size(); ++anObjectIdx)
- {
- const Handle (SelectMgr_SelectableObject)& anObj = mySelectableObjects.GetObjectById (anObjectIdx);
-
- Handle(Graphic3d_Structure) aStruct = new Graphic3d_Structure (theView->Viewer()->StructureManager());
-
- for (anObj->Init(); anObj->More(); anObj->Next())
- {
- if (anObj->CurrentSelection()->GetSelectionState() == SelectMgr_SOS_Activated)
- {
- computeSensitivePrs (aStruct, anObj->CurrentSelection(), anObj->Transformation(), Graphic3d_TransformPers());
- }
- }
-
- myStructs.Append (aStruct);
- }
+ SelectMgr_SelectableObjectSet::Iterator aSelectableIt (mySelectableObjects);
- for (Standard_Integer anObjectIdx = 0; anObjectIdx <= mySelectableObjectsTrsfPers.Size(); ++anObjectIdx)
+ for (; aSelectableIt.More(); aSelectableIt.Next())
{
- const Handle (SelectMgr_SelectableObject)& anObj = mySelectableObjectsTrsfPers.GetObjectById (anObjectIdx);
+ const Handle (SelectMgr_SelectableObject)& anObj = aSelectableIt.Value();
Handle(Graphic3d_Structure) aStruct = new Graphic3d_Structure (theView->Viewer()->StructureManager());
- if (anObj->TransformPersistence().Flags == 0)
- {
- continue;
- }
-
for (anObj->Init(); anObj->More(); anObj->Next())
{
if (anObj->CurrentSelection()->GetSelectionState() == SelectMgr_SOS_Activated)
{
- computeSensitivePrs (aStruct, anObj->CurrentSelection(), anObj->Transformation(), anObj->TransformPersistence());
+ computeSensitivePrs (aStruct, anObj->CurrentSelection(), anObj->Transformation(), Graphic3d_TransformPers());
}
}
--- /dev/null
+puts "========"
+puts "OCC27739"
+puts "========"
+puts ""
+##################################################################
+puts "Visualization, TKV3d - implement individual acceleration data structure for selection of 2D persistent objects"
+##################################################################
+
+# Create view
+set win_width 409
+set win_height 409
+vinit View1 w=$win_width h=$win_height
+vclear
+
+# Display several different presentation types with orthographic camera
+vcamera -ortho
+vtrihedron tri1
+box box3d 100 100 100
+box box2d 100 100 1
+box box2d_pos 100 100 1
+box box2d_loc 100 100 1
+box box_zoom 100 100 100
+
+vdisplay box3d -dispMode 1 -highMode 0
+vdisplay box2d -dispMode 1 -highMode 1 -2d
+vdisplay box2d_pos -dispMode 1 -highMode 1 -2d -trsfPersPos -1 -1
+vdisplay box2d_loc -dispMode 1 -highMode 1 -2d
+vdisplay box_zoom -dispMode 1 -highMode 0 -trsfPers zoom
+vdisplay box2d
+vsetlocation box2d_loc 100 0 0
+vsetlocation box_zoom -100 -100 100
+
+vsetmaterial box3d box2d box2d_pos box2d_loc box_zoom PLASTIC
+vsetcolor box3d GOLD
+vsetcolor box2d GREEN
+vsetcolor box2d_pos GREEN
+vsetcolor box2d_loc GREEN
+vsetcolor box_zoom RED
+vfit
+
+# ==========================================
+# Test selection for orthographic projection
+# ==========================================
+
+set test_1 {220 120}; # box2d
+set test_2 {350 150}; # box2d_pos
+set test_3 { 50 350}; # box2d_loc
+
+vmoveto {*}$test_1
+if {[vreadpixel {*}$test_1 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_1.png
+
+vmoveto {*}$test_2
+if {[vreadpixel {*}$test_2 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_2.png
+
+vmoveto {*}$test_3
+if {[vreadpixel {*}$test_3 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_3.png
+
+# =========================================
+# Test selection for perspective projection
+# =========================================
+
+vcamera -persp
+vcamera -distance 1000
+set test_1 {220 120}; # box2d
+set test_2 {350 150}; # box2d_pos
+set test_3 { 50 350}; # box2d_loc
+
+vmoveto {*}$test_1
+if {[vreadpixel {*}$test_1 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_4.png
+
+vmoveto {*}$test_2
+if {[vreadpixel {*}$test_2 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_5.png
+
+vmoveto {*}$test_3
+if {[vreadpixel {*}$test_3 name] != "CYAN1 1"} { puts "ERROR: zoom persistent box is not detected!" }
+vdump $imagedir/${casename}_6.png