0027202: Visualization - add sensitivity Select3D_SensitivePrimitiveArray for Graphic...
authorkgv <kgv@opencascade.com>
Wed, 20 Apr 2016 06:48:58 +0000 (09:48 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 22 Apr 2016 12:21:51 +0000 (15:21 +0300)
New class Select3D_SensitivePrimitiveArray can be initialized directly from
presentation data structures Graphic3d_Buffer defining triangulation or point set.

This class also can combine several elements into patches
to reduce BVH initialization time in at the expense of slower detection time.

AIS_PointCloud::ComputeSelection() - selection is now computed on point set using Select3D_SensitivePrimitiveArray by default.
PrsMgr_PresentableObject::Compute() - redundant default argument value has been dropped.
BVH - store BVH_Set size in local variable to simplify debugging.

13 files changed:
src/AIS/AIS_PointCloud.cxx
src/AIS/AIS_PointCloud.hxx
src/BVH/BVH_LinearBuilder.lxx
src/BVH/BVH_QueueBuilder.lxx
src/BVH/BVH_Set.lxx
src/PrsMgr/PrsMgr_PresentableObject.hxx
src/Select3D/FILES
src/Select3D/Select3D_BVHIndexBuffer.hxx [new file with mode: 0644]
src/Select3D/Select3D_SensitivePrimitiveArray.cxx [new file with mode: 0644]
src/Select3D/Select3D_SensitivePrimitiveArray.hxx [new file with mode: 0644]
src/Select3D/Select3D_SensitiveSet.cxx
src/Select3D/Select3D_SensitiveSet.hxx
src/ViewerTest/ViewerTest.cxx

index efefed7..46bc506 100644 (file)
@@ -27,6 +27,7 @@
 #include <PrsMgr_ModedPresentation.hxx>
 #include <PrsMgr_Presentations.hxx>
 #include <Select3D_SensitiveBox.hxx>
+#include <Select3D_SensitivePrimitiveArray.hxx>
 #include <SelectMgr_EntityOwner.hxx>
 #include <SelectMgr_Selection.hxx>
 #include <StdPrs_BndBox.hxx>
@@ -461,15 +462,41 @@ void AIS_PointCloud::Compute (const Handle(PrsMgr_PresentationManager3d)& /*theP
 //purpose  :
 //=======================================================================
 void AIS_PointCloud::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
-                                       const Standard_Integer             /*theMode*/)
+                                       const Standard_Integer             theMode)
 {
+  Handle(SelectMgr_EntityOwner) anOwner = new SelectMgr_EntityOwner (this);
+  switch (theMode)
+  {
+    case SM_Points:
+    {
+      const Handle(Graphic3d_ArrayOfPoints) aPoints = GetPoints();
+      if (!aPoints.IsNull()
+       && !aPoints->Attributes().IsNull())
+      {
+        Handle(Select3D_SensitivePrimitiveArray) aSensitive = new Select3D_SensitivePrimitiveArray (anOwner);
+        aSensitive->SetSensitivityFactor (8);
+        aSensitive->InitPoints (aPoints->Attributes(), aPoints->Indices(), TopLoc_Location());
+        aSensitive->BVH();
+        theSelection->Add (aSensitive);
+        return;
+      }
+      break;
+    }
+    case SM_BndBox:
+    {
+      break;
+    }
+    default:
+    {
+      return;
+    }
+  }
+
   Bnd_Box aBndBox = GetBoundingBox();
   if (aBndBox.IsVoid())
   {
     return;
   }
-
-  Handle(SelectMgr_EntityOwner) anOwner  = new SelectMgr_EntityOwner (this);
   Handle(Select3D_SensitiveBox) aSensBox = new Select3D_SensitiveBox (anOwner, aBndBox);
   theSelection->Add (aSensBox);
 }
index f9a3148..1671755 100644 (file)
@@ -53,6 +53,13 @@ public:
     DM_BndBox = 2  //!< display as bounding box,  default for highlighting
   };
 
+  //! Selection modes supported by this Point Cloud object
+  enum SelectionMode
+  {
+    SM_Points = 0, //!< detected by points
+    SM_BndBox = 2  //!< detected by bounding box
+  };
+
 public:
 
   //! Constructor.
index d822a0f..6e92028 100644 (file)
@@ -384,8 +384,8 @@ void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
                                      const BVH_Box<T, N>& theBox)
 {
   Standard_STATIC_ASSERT (N == 3 || N == 4);
-
-  if (theBVH == NULL || theSet->Size() == 0)
+  const Standard_Integer aSetSize = theSet->Size();
+  if (theBVH == NULL || aSetSize == 0)
   {
     return;
   }
@@ -405,10 +405,10 @@ void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
   const T aReverseSizeY = static_cast<T> (aDimensionY) / Max (aMinSize, aSceneMax.y() - aSceneMin.y());
   const T aReverseSizeZ = static_cast<T> (aDimensionZ) / Max (aMinSize, aSceneMax.z() - aSceneMin.z());
 
-  std::vector<BVH_EncodedLink> anEncodedLinks (theSet->Size(), BVH_EncodedLink());
+  std::vector<BVH_EncodedLink> anEncodedLinks (aSetSize, BVH_EncodedLink());
 
   // Step 1 -- Assign Morton code to each primitive
-  for (Standard_Integer aPrimIdx = 0; aPrimIdx < theSet->Size(); ++aPrimIdx)
+  for (Standard_Integer aPrimIdx = 0; aPrimIdx < aSetSize; ++aPrimIdx)
   {
     const BVH_VecNt aCenter = theSet->Box (aPrimIdx).Center();
 
@@ -456,9 +456,8 @@ void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
   // Step 3 -- Emitting BVH hierarchy from sorted Morton codes
   EmitHierachy (theBVH, 29, 0, anEncodedLinks.begin(), anEncodedLinks.end());
 
-  NCollection_Array1<Standard_Integer> aLinkMap (0, theSet->Size() - 1);
-
-  for (Standard_Integer aLinkIdx = 0; aLinkIdx < theSet->Size(); ++aLinkIdx)
+  NCollection_Array1<Standard_Integer> aLinkMap (0, aSetSize - 1);
+  for (Standard_Integer aLinkIdx = 0; aLinkIdx < aSetSize; ++aLinkIdx)
   {
     aLinkMap (anEncodedLinks[aLinkIdx].second) = aLinkIdx;
   }
@@ -466,7 +465,7 @@ void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
   // Step 4 -- Rearranging primitive list according to Morton codes (in place)
   Standard_Integer aPrimIdx = 0;
 
-  while (aPrimIdx < theSet->Size())
+  while (aPrimIdx < aSetSize)
   {
     const Standard_Integer aSortIdx = aLinkMap (aPrimIdx);
 
index 20ecff2..dadf482 100644 (file)
@@ -103,12 +103,13 @@ void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
     "Error! BVH tree to construct is NULL", );
 
   theBVH->Clear();
-  if (theSet->Size() == 0)
+  const Standard_Integer aSetSize = theSet->Size();
+  if (aSetSize == 0)
   {
     return;
   }
 
-  const Standard_Integer aRoot = theBVH->AddLeafNode (theBox, 0, theSet->Size() - 1);
+  const Standard_Integer aRoot = theBVH->AddLeafNode (theBox, 0, aSetSize - 1);
   if (theSet->Size() == 1)
   {
     return;
@@ -121,7 +122,7 @@ void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>*       theSet,
   if (myNumOfThreads > 1)
   {
     // Reserve the maximum possible number of nodes in the BVH
-    theBVH->Reserve (2 * theSet->Size() - 1);
+    theBVH->Reserve (2 * aSetSize - 1);
 
     NCollection_Vector<Handle(BVH_BuildThread)> aThreads;
 
index 3dd7e01..7453a35 100644 (file)
@@ -41,7 +41,8 @@ template<class T, int N>
 BVH_Box<T, N> BVH_Set<T, N>::Box() const
 {
   BVH_Box<T, N> aBox;
-  for (Standard_Integer anIndex = 0; anIndex < Size(); ++anIndex)
+  const Standard_Integer aSize = Size();
+  for (Standard_Integer anIndex = 0; anIndex < aSize; ++anIndex)
   {
     aBox.Combine (Box (anIndex));
   }
index 14af43a..cb2946a 100644 (file)
@@ -224,7 +224,7 @@ Standard_EXPORT virtual ~PrsMgr_PresentableObject();
   //! updates. The latter are managed by aPresentationManager.
   //! aPresentableObject has the display mode aMode;
   //! this has the default value of 0, that is, the wireframe display mode.
-  Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& aPresentationManager, const Handle(Prs3d_Presentation)& aPresentation, const Standard_Integer aMode = 0);
+  Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& aPresentationManager, const Handle(Prs3d_Presentation)& aPresentation, const Standard_Integer aMode);
   
   //! Calculates the 3D view aPresentation and its
   //! updates. The latter are managed by
@@ -262,7 +262,7 @@ Standard_EXPORT virtual ~PrsMgr_PresentableObject();
   Standard_EXPORT void Update (const Standard_Integer aMode, const Standard_Boolean ClearOther);
   
   //! High-level interface for controlling polygon offsets
-  Standard_EXPORT virtual void Fill (const Handle(PrsMgr_PresentationManager)& aPresentationManager, const Handle(PrsMgr_Presentation)& aPresentation, const Standard_Integer aMode = 0);
+  Standard_EXPORT virtual void Fill (const Handle(PrsMgr_PresentationManager)& aPresentationManager, const Handle(PrsMgr_Presentation)& aPresentation, const Standard_Integer aMode);
   
   //! Sets myCombinedParentTransform to theTransformation. Thus object receives transformation
   //! from parent node and able to derive its own.
index 354cc2b..ea12ef8 100755 (executable)
@@ -1,4 +1,5 @@
 Select3D_BndBox3d.hxx
+Select3D_BVHIndexBuffer.hxx
 Select3D_BVHPrimitiveContent.cxx
 Select3D_BVHPrimitiveContent.hxx
 Select3D_EntitySequence.hxx
@@ -25,6 +26,8 @@ Select3D_SensitivePoint.hxx
 Select3D_SensitivePoly.cxx
 Select3D_SensitivePoly.hxx
 Select3D_SensitivePoly.lxx
+Select3D_SensitivePrimitiveArray.cxx
+Select3D_SensitivePrimitiveArray.hxx
 Select3D_SensitiveSegment.cxx
 Select3D_SensitiveSegment.hxx
 Select3D_SensitiveSegment.lxx
diff --git a/src/Select3D/Select3D_BVHIndexBuffer.hxx b/src/Select3D/Select3D_BVHIndexBuffer.hxx
new file mode 100644 (file)
index 0000000..85d8240
--- /dev/null
@@ -0,0 +1,100 @@
+// Created on: 2016-02-25
+// Created by: Kirill Gavrilov
+// Copyright (c) 2016 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 _Select3D_BVHIndexBuffer_Header
+#define _Select3D_BVHIndexBuffer_Header
+
+#include <Graphic3d_Buffer.hxx>
+#include <Graphic3d_IndexBuffer.hxx>
+#include <Select3D_SensitiveSet.hxx>
+#include <TColStd_HArray1OfInteger.hxx>
+
+//! Index buffer for BVH tree.
+class Select3D_BVHIndexBuffer : public Graphic3d_Buffer
+{
+public:
+
+  //! Empty constructor.
+  Select3D_BVHIndexBuffer (const Handle(NCollection_BaseAllocator)& theAlloc)
+  : Graphic3d_Buffer (theAlloc), myHasPatches (false) {}
+
+  bool HasPatches() const { return myHasPatches; }
+
+  //! Allocates new empty index array
+  bool Init (const Standard_Integer theNbElems,
+             const bool theHasPatches)
+  {
+    release();
+    Stride = sizeof(unsigned int);
+    myHasPatches = theHasPatches;
+    if (theHasPatches)
+    {
+      Stride += sizeof(unsigned int);
+    }
+
+    NbElements   = theNbElems;
+    NbAttributes = 0;
+    if (NbElements != 0
+    && !Allocate (size_t(Stride) * size_t(NbElements)))
+    {
+      release();
+      return false;
+    }
+    return true;
+  }
+
+  //! Access index at specified position
+  Standard_Integer Index (const Standard_Integer theIndex) const
+  {
+    return Standard_Integer(*reinterpret_cast<const unsigned int* >(value (theIndex)));
+  }
+
+  //! Access index at specified position
+  Standard_Integer PatchSize (const Standard_Integer theIndex) const
+  {
+    return myHasPatches
+         ? Standard_Integer(*reinterpret_cast<const unsigned int* >(value (theIndex) + sizeof(unsigned int)))
+         : 1;
+  }
+
+  //! Change index at specified position
+  void SetIndex (const Standard_Integer theIndex,
+                 const Standard_Integer theValue)
+  {
+    *reinterpret_cast<unsigned int* >(changeValue (theIndex)) = (unsigned int )theValue;
+  }
+
+  //! Change index at specified position
+  void SetIndex (const Standard_Integer theIndex,
+                 const Standard_Integer theValue,
+                 const Standard_Integer thePatchSize)
+  {
+    *reinterpret_cast<unsigned int* >(changeValue (theIndex))                        = (unsigned int )theValue;
+    *reinterpret_cast<unsigned int* >(changeValue (theIndex) + sizeof(unsigned int)) = (unsigned int )thePatchSize;
+  }
+
+private:
+
+  bool myHasPatches;
+  
+public:
+
+  DEFINE_STANDARD_RTTI_INLINE(Select3D_BVHIndexBuffer,Graphic3d_Buffer)
+
+};
+
+DEFINE_STANDARD_HANDLE(Select3D_BVHIndexBuffer, Graphic3d_Buffer)
+
+#endif // _Select3D_BVHIndexBuffer_Header
diff --git a/src/Select3D/Select3D_SensitivePrimitiveArray.cxx b/src/Select3D/Select3D_SensitivePrimitiveArray.cxx
new file mode 100644 (file)
index 0000000..6851cf8
--- /dev/null
@@ -0,0 +1,863 @@
+// Created on: 2016-02-20
+// Created by: Kirill Gavrilov
+// Copyright (c) 2016 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_SensitivePrimitiveArray.hxx>
+
+#include <NCollection_AlignedAllocator.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
+
+namespace
+{
+
+  //! Auxiliary converter.
+  static inline gp_Pnt vecToPnt (const Graphic3d_Vec3& theVec)
+  {
+    return gp_Pnt (theVec.x(), theVec.y(), theVec.z());
+  }
+
+  //! Auxiliary converter.
+  static inline gp_Pnt vecToPnt (const Graphic3d_Vec2& theVec)
+  {
+    return gp_Pnt (theVec.x(), theVec.y(), 0.0);
+  }
+
+
+  //! Auxiliary function to find shared node between two triangles.
+  static inline bool hasSharedNode (const Standard_Integer* theTri1,
+                                    const Standard_Integer* theTri2)
+  {
+    return theTri1[0] == theTri2[0]
+        || theTri1[1] == theTri2[0]
+        || theTri1[2] == theTri2[0]
+        || theTri1[0] == theTri2[1]
+        || theTri1[1] == theTri2[1]
+        || theTri1[2] == theTri2[1]
+        || theTri1[0] == theTri2[2]
+        || theTri1[1] == theTri2[2]
+        || theTri1[2] == theTri2[2];
+  }
+
+  //! Fill in the triangle nodes indices.
+  static inline void getTriIndices (const Handle(Graphic3d_IndexBuffer)& theIndices,
+                                    const Standard_Integer theIndexOffset,
+                                    Standard_Integer* theNodes)
+  {
+    if (!theIndices.IsNull())
+    {
+      theNodes[0] = theIndices->Index (theIndexOffset + 0);
+      theNodes[1] = theIndices->Index (theIndexOffset + 1);
+      theNodes[2] = theIndices->Index (theIndexOffset + 2);
+    }
+    else
+    {
+      theNodes[0] = theIndexOffset + 0;
+      theNodes[1] = theIndexOffset + 1;
+      theNodes[2] = theIndexOffset + 2;
+    }
+  }
+
+}
+
+// =======================================================================
+// function : Select3D_SensitivePrimitiveArray
+// purpose  :
+// =======================================================================
+Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray (const Handle(SelectBasics_EntityOwner)& theOwnerId)
+: Select3D_SensitiveSet (theOwnerId),
+  myPrimType (Graphic3d_TOPA_UNDEFINED),
+  myIndexLower (0),
+  myIndexUpper (0),
+  myPosOffset (Standard_Size(-1)),
+  myPatchSizeMax (1),
+  myPatchDistance (ShortRealLast()),
+  myIs3d (false),
+  myBvhIndices (new NCollection_AlignedAllocator(16)),
+  myMinDepthElem (RealLast()),
+  myMinDepthNode (RealLast()),
+  myMinDepthEdge (RealLast()),
+  myDetectedElem (-1),
+  myDetectedNode (-1),
+  myDetectedEdgeNode1 (-1),
+  myDetectedEdgeNode2 (-1),
+  myToDetectElem (true),
+  myToDetectNode (false),
+  myToDetectEdge (false)
+{
+  //
+}
+
+// =======================================================================
+// function : InitTriangulation
+// purpose  :
+// =======================================================================
+bool Select3D_SensitivePrimitiveArray::InitTriangulation (const Handle(Graphic3d_Buffer)&      theVerts,
+                                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
+                                                          const TopLoc_Location&               theInitLoc,
+                                                          const Standard_Integer               theIndexLower,
+                                                          const Standard_Integer               theIndexUpper,
+                                                          const bool                           theToEvalMinMax)
+{
+  MarkDirty();
+  myPrimType = Graphic3d_TOPA_TRIANGLES;
+  myBndBox.Clear();
+  myVerts.Nullify();
+  myIndices.Nullify();
+  myIndexLower = 0;
+  myIndexUpper = 0;
+  myPosOffset = Standard_Size(-1);
+  myBvhIndices.release();
+  myIs3d = false;
+  myInitLocation = theInitLoc;
+  if (theVerts.IsNull()
+   || theVerts->NbElements == 0)
+  {
+    return false;
+  }
+
+  for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
+  {
+    const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
+    if (anAttrib.Id == Graphic3d_TOA_POS)
+    {
+      if (anAttrib.DataType == Graphic3d_TOD_VEC3
+       || anAttrib.DataType == Graphic3d_TOD_VEC4)
+      {
+        myIs3d = true;
+      }
+      else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
+      {
+        return false;
+      }
+
+      myPosOffset = theVerts->AttributeOffset (anAttribIter);
+      break;
+    }
+  }
+  if (myPosOffset == Standard_Size(-1))
+  {
+    return false;
+  }
+
+  if (!theIndices.IsNull())
+  {
+    if (theIndexLower < 0
+     || theIndexUpper >= theIndices->NbElements
+     || theIndices->NbElements == 0)
+    {
+      return false;
+    }
+  }
+  else
+  {
+    if (theIndexLower < 0
+     || theIndexUpper >= theVerts->NbElements)
+    {
+      return false;
+    }
+  }
+
+  Standard_Integer aTriFrom = theIndexLower / 3;
+  Standard_Integer aNbTris  = (theIndexUpper - theIndexLower + 1) / 3;
+  if (aNbTris < 1)
+  {
+    return false;
+  }
+  if (!myBvhIndices.Init (aNbTris, myPatchSizeMax > 1))
+  {
+    return false;
+  }
+
+  myVerts      = theVerts;
+  myIndices    = theIndices;
+  myIndexLower = theIndexLower;
+  myIndexUpper = theIndexUpper;
+  myInvInitLocation = myInitLocation.Transformation().Inverted();
+
+  Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
+  Standard_Integer  aTriNodes1[3] = { -1, -1, -1 };
+  Standard_Integer  aTriNodes2[3] = { -1, -1, -1 };
+  Standard_Integer* aTriNodesPrev = aTriNodes1;
+  Standard_Integer* aTriNodes     = aTriNodes2;
+  Standard_Integer  aPatchFrom    = 0;
+  Standard_Integer  aPatchSize    = 0;
+  if (myBvhIndices.HasPatches())
+  {
+    myBvhIndices.NbElements = 0;
+  }
+  for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
+  {
+    const Standard_Integer anIndexOffset = (aTriFrom + aTriIter) * 3;
+    getTriIndices (myIndices, anIndexOffset, aTriNodes);
+    if (myIs3d)
+    {
+      const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
+      const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
+      const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
+      aCenter += (aNode1 + aNode2 + aNode3) / 3.0;
+    }
+    else
+    {
+      const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
+      const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
+      const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
+      aCenter.xy() += (aNode1 + aNode2 + aNode3) / 3.0;
+    }
+    if (myBvhIndices.HasPatches())
+    {
+      std::swap (aTriNodes, aTriNodesPrev);
+      if (aPatchSize < myPatchSizeMax
+       && hasSharedNode (aTriNodes, aTriNodesPrev))
+      {
+        ++aPatchSize;
+        continue;
+      }
+      else
+      {
+        myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
+        aPatchFrom = aTriIter;
+        aPatchSize = 0;
+      }
+    }
+    else
+    {
+      myBvhIndices.SetIndex (aTriIter, aTriFrom + aTriIter);
+    }
+  }
+  if (aPatchSize != 0)
+  {
+    myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
+  }
+  aCenter /= float(aNbTris);
+
+  myCDG3D = vecToPnt (aCenter);
+  if (theToEvalMinMax)
+  {
+    computeBoundingBox();
+  }
+  return true;
+}
+
+// =======================================================================
+// function : InitPoints
+// purpose  :
+// =======================================================================
+bool Select3D_SensitivePrimitiveArray::InitPoints (const Handle(Graphic3d_Buffer)&      theVerts,
+                                                   const Handle(Graphic3d_IndexBuffer)& theIndices,
+                                                   const TopLoc_Location&               theInitLoc,
+                                                   const Standard_Integer               theIndexLower,
+                                                   const Standard_Integer               theIndexUpper,
+                                                   const bool                           theToEvalMinMax)
+{
+  MarkDirty();
+  myPrimType = Graphic3d_TOPA_POINTS;
+  myBndBox.Clear();
+  myVerts.Nullify();
+  myIndices.Nullify();
+  myIndexLower = 0;
+  myIndexUpper = 0;
+  myPosOffset = Standard_Size(-1);
+  myBvhIndices.release();
+  myIs3d = false;
+  myInitLocation = theInitLoc;
+  if (theVerts.IsNull()
+   || theVerts->NbElements == 0)
+  {
+    return false;
+  }
+
+  for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
+  {
+    const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
+    if (anAttrib.Id == Graphic3d_TOA_POS)
+    {
+      if (anAttrib.DataType == Graphic3d_TOD_VEC3
+       || anAttrib.DataType == Graphic3d_TOD_VEC4)
+      {
+        myIs3d = true;
+      }
+      else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
+      {
+        return false;
+      }
+
+      myPosOffset = theVerts->AttributeOffset (anAttribIter);
+      break;
+    }
+  }
+  if (myPosOffset == Standard_Size(-1))
+  {
+    return false;
+  }
+
+  if (!theIndices.IsNull())
+  {
+    if (theIndexLower < 0
+     || theIndexUpper >= theIndices->NbElements
+     || theIndices->NbElements == 0)
+    {
+      return false;
+    }
+  }
+  else
+  {
+    if (theIndexLower < 0
+     || theIndexUpper >= theVerts->NbElements)
+    {
+      return false;
+    }
+  }
+
+  Standard_Integer aNbPoints = theIndexUpper - theIndexLower + 1;
+  if (aNbPoints < 1)
+  {
+    return false;
+  }
+  if (!myBvhIndices.Init (aNbPoints, myPatchSizeMax > 1))
+  {
+    return false;
+  }
+
+  myVerts      = theVerts;
+  myIndices    = theIndices;
+  myIndexLower = theIndexLower;
+  myIndexUpper = theIndexUpper;
+  myInvInitLocation = myInitLocation.Transformation().Inverted();
+
+  Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
+  Standard_Integer aPatchFrom = 0;
+  Standard_Integer aPatchSize = 0;
+  if (myBvhIndices.HasPatches())
+  {
+    myBvhIndices.NbElements = 0;
+  }
+  const float aPatchSize2 = myPatchDistance < ShortRealLast()
+                          ? myPatchDistance * myPatchDistance
+                          : myPatchDistance;
+  const Graphic3d_Vec3* aPnt3dPrev = NULL;
+  const Graphic3d_Vec3* aPnt3d     = NULL;
+  const Graphic3d_Vec2* aPnt2dPrev = NULL;
+  const Graphic3d_Vec2* aPnt2d     = NULL;
+  for (Standard_Integer aPointIter = 0; aPointIter < aNbPoints; ++aPointIter)
+  {
+    const Standard_Integer anIndexOffset = (theIndexLower + aPointIter);
+    const Standard_Integer aPointIndex   = !myIndices.IsNull()
+                                          ? myIndices->Index (anIndexOffset)
+                                          : anIndexOffset;
+    if (myIs3d)
+    {
+      aPnt3d = &getPosVec3 (aPointIndex);
+      aCenter += *aPnt3d;
+    }
+    else
+    {
+      aPnt2d = &getPosVec2 (aPointIndex);
+      aCenter.xy() += *aPnt2d;
+    }
+
+    if (myBvhIndices.HasPatches())
+    {
+      if (myIs3d)
+      {
+        std::swap (aPnt3d, aPnt3dPrev);
+        if (aPatchSize < myPatchSizeMax
+         && aPnt3d != NULL
+         && (*aPnt3dPrev - *aPnt3d).SquareModulus() < aPatchSize2)
+        {
+          ++aPatchSize;
+          continue;
+        }
+      }
+      else
+      {
+        std::swap (aPnt2d, aPnt2dPrev);
+        if (aPatchSize < myPatchSizeMax
+         && aPnt2d != NULL
+         && (*aPnt2dPrev - *aPnt2d).SquareModulus() < aPatchSize2)
+        {
+          ++aPatchSize;
+          continue;
+        }
+      }
+
+      myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom,
+                              aPatchSize != 0 ? aPatchSize : 1);
+      aPatchFrom = aPointIter;
+      aPatchSize = 0;
+    }
+    else
+    {
+      myBvhIndices.SetIndex (aPointIter, theIndexLower + aPointIter);
+    }
+  }
+  if (aPatchSize != 0)
+  {
+    myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom, aPatchSize);
+  }
+  aCenter /= float(aNbPoints);
+
+  myCDG3D = vecToPnt (aCenter);
+  if (theToEvalMinMax)
+  {
+    computeBoundingBox();
+  }
+  return true;
+}
+
+// =======================================================================
+// function : GetConnected
+// purpose  :
+// =======================================================================
+Handle(Select3D_SensitiveEntity) Select3D_SensitivePrimitiveArray::GetConnected()
+{
+  Handle(Select3D_SensitivePrimitiveArray) aNewEntity = new Select3D_SensitivePrimitiveArray (myOwnerId);
+  switch (myPrimType)
+  {
+    case Graphic3d_TOPA_POINTS:
+    {
+      aNewEntity->InitPoints        (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper);
+      break;
+    }
+    case Graphic3d_TOPA_TRIANGLES:
+    {
+      aNewEntity->InitTriangulation (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper);
+      break;
+    }
+    default: break;
+  }
+  return aNewEntity;
+}
+
+// =======================================================================
+// function : Size
+// purpose  :
+// =======================================================================
+Standard_Integer Select3D_SensitivePrimitiveArray::Size() const
+{
+  return myBvhIndices.NbElements;
+}
+
+// =======================================================================
+// function : Box
+// purpose  :
+// =======================================================================
+Select3D_BndBox3d Select3D_SensitivePrimitiveArray::Box (const Standard_Integer theIdx) const
+{
+  const Standard_Integer anElemIdx  = myBvhIndices.Index (theIdx);
+  const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theIdx);
+  Select3D_BndBox3d aBox;
+  switch (myPrimType)
+  {
+    case Graphic3d_TOPA_POINTS:
+    {
+      for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+      {
+        const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
+        const Standard_Integer aPointIndex   = !myIndices.IsNull()
+                                             ?  myIndices->Index (anIndexOffset)
+                                             :  anIndexOffset;
+        if (myIs3d)
+        {
+          const Graphic3d_Vec3& aPoint = getPosVec3 (aPointIndex);
+          aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), aPoint.z()));
+        }
+        else
+        {
+          const Graphic3d_Vec2& aPoint = getPosVec2 (aPointIndex);
+          aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), 0.0));
+        }
+      }
+      break;
+    }
+    case Graphic3d_TOPA_TRIANGLES:
+    {
+      Standard_Integer aTriNodes[3];
+      if (myIs3d)
+      {
+        for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+        {
+          const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
+          getTriIndices (myIndices, anIndexOffset, aTriNodes);
+          const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
+          const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
+          const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
+          Graphic3d_Vec3 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
+          Graphic3d_Vec3 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
+          aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), aMinPnt.z()));
+          aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), aMaxPnt.z()));
+        }
+      }
+      else
+      {
+        for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+        {
+          const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
+          getTriIndices (myIndices, anIndexOffset, aTriNodes);
+          const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
+          const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
+          const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
+          Graphic3d_Vec2 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
+          Graphic3d_Vec2 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
+          aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), 0.0));
+          aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), 0.0));
+        }
+      }
+      break;
+    }
+    default:
+    {
+      return aBox;
+    }
+  }
+  return aBox;
+}
+
+// =======================================================================
+// function : Center
+// purpose  :
+// =======================================================================
+Standard_Real Select3D_SensitivePrimitiveArray::Center (const Standard_Integer theIdx,
+                                                        const Standard_Integer theAxis) const
+{
+  const Select3D_BndBox3d& aBox = Box (theIdx);
+  SelectMgr_Vec3 aCenter = (aBox.CornerMin() + aBox.CornerMax()) * 0.5;
+  return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
+}
+
+// =======================================================================
+// function : Swap
+// purpose  :
+// =======================================================================
+void Select3D_SensitivePrimitiveArray::Swap (const Standard_Integer theIdx1,
+                                             const Standard_Integer theIdx2)
+{
+  Standard_Integer anElemIdx1 = myBvhIndices.Index (theIdx1);
+  Standard_Integer anElemIdx2 = myBvhIndices.Index (theIdx2);
+  if (myBvhIndices.HasPatches())
+  {
+    Standard_Integer aPatchSize1 = myBvhIndices.PatchSize (theIdx1);
+    Standard_Integer aPatchSize2 = myBvhIndices.PatchSize (theIdx2);
+    myBvhIndices.SetIndex (theIdx1, anElemIdx2, aPatchSize2);
+    myBvhIndices.SetIndex (theIdx2, anElemIdx1, aPatchSize1);
+  }
+  else
+  {
+    myBvhIndices.SetIndex (theIdx1, anElemIdx2);
+    myBvhIndices.SetIndex (theIdx2, anElemIdx1);
+  }
+}
+
+// =======================================================================
+// function : BoundingBox
+// purpose  :
+// =======================================================================
+Select3D_BndBox3d Select3D_SensitivePrimitiveArray::BoundingBox()
+{
+  if (!myBndBox.IsValid())
+  {
+    computeBoundingBox();
+  }
+  return applyTransformation();
+}
+
+// =======================================================================
+// function : computeBoundingBox
+// purpose  :
+// =======================================================================
+void Select3D_SensitivePrimitiveArray::computeBoundingBox()
+{
+  myBndBox.Clear();
+  if (myVerts.IsNull())
+  {
+    return;
+  }
+
+  const Standard_Integer aNbVerts = myVerts->NbElements;
+  if (myIs3d)
+  {
+    for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
+    {
+      const Graphic3d_Vec3& aVert = getPosVec3 (aVertIter);
+      myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), aVert.z()));
+    }
+  }
+  else
+  {
+    for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
+    {
+      const Graphic3d_Vec2& aVert = getPosVec2 (aVertIter);
+      myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), 0.0));
+    }
+  }
+}
+
+// =======================================================================
+// function : applyTransformation
+// purpose  :
+// =======================================================================
+Select3D_BndBox3d Select3D_SensitivePrimitiveArray::applyTransformation()
+{
+  if (!HasInitLocation())
+  {
+    return myBndBox;
+  }
+
+  Select3D_BndBox3d aBndBox;
+  for (Standard_Integer aX = 0; aX <=1; ++aX)
+  {
+    for (Standard_Integer aY = 0; aY <=1; ++aY)
+    {
+      for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
+      {
+        gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
+                                 aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
+                                 aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
+        aVertex.Transform (myInitLocation.Transformation());
+        aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
+      }
+    }
+  }
+  return aBndBox;
+}
+
+// =======================================================================
+// function : Matches
+// purpose  :
+// =======================================================================
+Standard_Boolean Select3D_SensitivePrimitiveArray::Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                            SelectBasics_PickResult& thePickResult)
+{
+  myMinDepthElem      = RealLast();
+  myMinDepthNode      = RealLast();
+  myMinDepthEdge      = RealLast();
+  myDetectedElem      = -1;
+  myDetectedNode      = -1;
+  myDetectedEdgeNode1 = -1;
+  myDetectedEdgeNode2 = -1;
+  return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
+}
+
+// =======================================================================
+// function : overlapsElement
+// purpose  :
+// =======================================================================
+Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
+                                                                    Standard_Integer theElemIdx,
+                                                                    Standard_Real& theMatchDepth)
+{
+  const Standard_Integer anElemIdx  = myBvhIndices.Index (theElemIdx);
+  const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
+  Select3D_BndBox3d aBox;
+  Standard_Boolean aResult = Standard_False;
+  Standard_Real aMinDepth  = RealLast();
+  switch (myPrimType)
+  {
+    case Graphic3d_TOPA_POINTS:
+    {
+      for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+      {
+        const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
+        const Standard_Integer aPointIndex   = !myIndices.IsNull()
+                                             ?  myIndices->Index (anIndexOffset)
+                                             :  anIndexOffset;
+        gp_Pnt aPoint;
+        if (myIs3d)
+        {
+          aPoint = vecToPnt (getPosVec3 (aPointIndex));
+        }
+        else
+        {
+          aPoint = vecToPnt (getPosVec2 (aPointIndex));
+        }
+
+        Standard_Real aCurrentDepth = RealLast();
+        if (myToDetectNode
+         || myToDetectElem)
+        {
+          if (theMgr.Overlaps (aPoint, aCurrentDepth))
+          {
+            if (aCurrentDepth <= myMinDepthNode)
+            {
+              myDetectedElem = myDetectedNode = aPointIndex;
+              myMinDepthElem = myMinDepthNode = aCurrentDepth;
+            }
+            aResult = Standard_True;
+          }
+        }
+        aMinDepth = Min (aMinDepth, aCurrentDepth);
+      }
+      break;
+    }
+    case Graphic3d_TOPA_TRIANGLES:
+    {
+      Graphic3d_Vec3i aTriNodes;
+      for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+      {
+        const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
+        getTriIndices (myIndices, anIndexOffset, aTriNodes);
+        gp_Pnt aPnts[3];
+        if (myIs3d)
+        {
+          aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
+          aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
+          aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
+        }
+        else
+        {
+          aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
+          aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
+          aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
+        }
+
+        Standard_Real aCurrentDepth = RealLast();
+        if (myToDetectElem)
+        {
+          if (theMgr.Overlaps (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aCurrentDepth))
+          {
+            if (aCurrentDepth <= myMinDepthElem)
+            {
+              myDetectedElem = anElemIdx + anElemIter;
+              myMinDepthElem = aCurrentDepth;
+            }
+            aResult = Standard_True;
+          }
+        }
+        if (myToDetectNode)
+        {
+          for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
+          {
+            if (theMgr.Overlaps (aPnts[aNodeIter], aCurrentDepth))
+            {
+              if (aCurrentDepth <= myMinDepthNode)
+              {
+                myDetectedNode = aTriNodes[aNodeIter];
+                myMinDepthNode = aCurrentDepth;
+              }
+              aResult = Standard_True;
+            }
+          }
+        }
+        if (myToDetectEdge)
+        {
+          for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
+          {
+            int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
+            int aNode2 = aNodeIter;
+            if (theMgr.Overlaps (aPnts[aNode1], aPnts[aNode2], aCurrentDepth))
+            {
+              if (aCurrentDepth <= myMinDepthEdge)
+              {
+                myDetectedEdgeNode1 = aTriNodes[aNode1];
+                myDetectedEdgeNode2 = aTriNodes[aNode2];
+                myMinDepthEdge = aCurrentDepth;
+              }
+              aResult = Standard_True;
+            }
+          }
+        }
+        aMinDepth = Min (aMinDepth, aCurrentDepth);
+      }
+      break;
+    }
+    default:
+    {
+      return Standard_False;
+    }
+  }
+
+  theMatchDepth = aMinDepth;
+  return aResult;
+}
+
+// =======================================================================
+// function : distanceToCOG
+// purpose  :
+// =======================================================================
+Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
+{
+  return theMgr.DistToGeometryCenter (myCDG3D);
+}
+
+// =======================================================================
+// function : elementIsInside
+// purpose  :
+// =======================================================================
+Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
+                                                                    const Standard_Integer               theElemIdx)
+{
+  const Standard_Integer anElemIdx  = myBvhIndices.Index (theElemIdx);
+  const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
+  switch (myPrimType)
+  {
+    case Graphic3d_TOPA_POINTS:
+    {
+      for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+      {
+        const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
+        const Standard_Integer aPointIndex   = !myIndices.IsNull()
+                                             ?  myIndices->Index (anIndexOffset)
+                                             :  anIndexOffset;
+        gp_Pnt aPoint;
+        if (myIs3d)
+        {
+          aPoint = vecToPnt (getPosVec3 (aPointIndex));
+        }
+        else
+        {
+          aPoint = vecToPnt (getPosVec2 (aPointIndex));
+        }
+        if (!theMgr.Overlaps (aPoint))
+        {
+          return Standard_False;
+        }
+      }
+      return Standard_True;
+    }
+    case Graphic3d_TOPA_TRIANGLES:
+    {
+      Graphic3d_Vec3i aTriNodes;
+      for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
+      {
+        const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
+        getTriIndices (myIndices, anIndexOffset, aTriNodes);
+        gp_Pnt aPnts[3];
+        if (myIs3d)
+        {
+          aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
+          aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
+          aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
+        }
+        else
+        {
+          aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
+          aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
+          aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
+        }
+
+        if (!theMgr.Overlaps (aPnts[0])
+         || !theMgr.Overlaps (aPnts[1])
+         || !theMgr.Overlaps (aPnts[2]))
+        {
+          return Standard_False;
+        }
+      }
+      return Standard_True;
+    }
+    default:
+    {
+      return Standard_False;
+    }
+  }
+}
diff --git a/src/Select3D/Select3D_SensitivePrimitiveArray.hxx b/src/Select3D/Select3D_SensitivePrimitiveArray.hxx
new file mode 100644 (file)
index 0000000..4e858ef
--- /dev/null
@@ -0,0 +1,284 @@
+// Created on: 2016-02-20
+// Created by: Kirill Gavrilov
+// Copyright (c) 2016 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 _Select3D_SensitivePrimitiveArray_Header
+#define _Select3D_SensitivePrimitiveArray_Header
+
+#include <Graphic3d_Buffer.hxx>
+#include <Graphic3d_IndexBuffer.hxx>
+#include <Graphic3d_TypeOfPrimitiveArray.hxx>
+#include <Select3D_SensitiveSet.hxx>
+#include <Select3D_BVHIndexBuffer.hxx>
+
+//! Sensitive for triangulation or point set defined by Primitive Array.
+//! The primitives can be optionally combined into patches within BVH tree
+//! to reduce its building time in expense of extra traverse time.
+class Select3D_SensitivePrimitiveArray : public Select3D_SensitiveSet
+{
+
+public:
+
+  //! Constructs an empty sensitive object.
+  Standard_EXPORT Select3D_SensitivePrimitiveArray (const Handle(SelectBasics_EntityOwner)& theOwnerId);
+
+  //! Return patch size limit (1 by default).
+  Standard_Integer PatchSizeMax() const { return myPatchSizeMax; }
+
+  //! Assign patch size limit.
+  //! Should be set before initialization.
+  void SetPatchSizeMax (const Standard_Integer thePatchSizeMax) { myPatchSizeMax = thePatchSizeMax; }
+
+  //! Maximum allowed distance between consequential elements in patch (ShortRealLast() by default).
+  //! Has no effect on indexed triangulation.
+  float PatchDistance() const { return myPatchDistance; }
+
+  //! Assign patch distance limit.
+  //! Should be set before initialization.
+  void SetPatchDistance (const float thePatchDistMax) { myPatchDistance = thePatchDistMax; }
+
+  //! Initialize the sensitive object from triangualtion.
+  //! The sub-triangulation can be specified by arguments theIndexLower and theIndexUpper
+  //! (these are for iterating theIndices, not to restrict the actual index values!).
+  //! @param theVerts        attributes array containing Graphic3d_TOA_POS with type Graphic3d_TOD_VEC3 or Graphic3d_TOD_VEC2
+  //! @param theIndices      index array defining triangulation
+  //! @param theInitLoc      location
+  //! @param theIndexLower   the theIndices range - first value (inclusive), starting from 0 and multiple by 3
+  //! @param theIndexUpper   the theIndices range - last  value (inclusive), upto theIndices->NbElements-1 and multiple by 3
+  //! @param theToEvalMinMax compute bounding box within initialization
+  Standard_EXPORT bool InitTriangulation (const Handle(Graphic3d_Buffer)&      theVerts,
+                                          const Handle(Graphic3d_IndexBuffer)& theIndices,
+                                          const TopLoc_Location&               theInitLoc,
+                                          const Standard_Integer               theIndexLower,
+                                          const Standard_Integer               theIndexUpper,
+                                          const bool                           theToEvalMinMax = true);
+
+  //! Initialize the sensitive object from triangualtion.
+  //! @param theVerts        attributes array containing Graphic3d_TOA_POS with type Graphic3d_TOD_VEC3 or Graphic3d_TOD_VEC2
+  //! @param theIndices      index array defining triangulation
+  //! @param theInitLoc      location
+  //! @param theToEvalMinMax compute bounding box within initialization
+  bool InitTriangulation (const Handle(Graphic3d_Buffer)&      theVerts,
+                          const Handle(Graphic3d_IndexBuffer)& theIndices,
+                          const TopLoc_Location&               theInitLoc,
+                          const bool                           theToEvalMinMax = true)
+  {
+    const Standard_Integer anUpper = !theIndices.IsNull() ? (theIndices->NbElements - 1)
+                                                          : (!theVerts.IsNull() ? (theVerts->NbElements - 1) : 0);
+    return InitTriangulation (theVerts, theIndices, theInitLoc, 0, anUpper, theToEvalMinMax);
+  }
+
+  //! Initialize the sensitive object from point set.
+  //! The sub-set of points can be specified by arguments theIndexLower and theIndexUpper
+  //! (these are for iterating theIndices, not to restrict the actual index values!).
+  //! @param theVerts        attributes array containing Graphic3d_TOA_POS with type Graphic3d_TOD_VEC3 or Graphic3d_TOD_VEC2
+  //! @param theIndices      index array defining points
+  //! @param theInitLoc      location
+  //! @param theIndexLower   the theIndices range - first value (inclusive), starting from 0
+  //! @param theIndexUpper   the theIndices range - last  value (inclusive), upto theIndices->NbElements-1
+  //! @param theToEvalMinMax compute bounding box within initialization
+  Standard_EXPORT bool InitPoints (const Handle(Graphic3d_Buffer)&      theVerts,
+                                   const Handle(Graphic3d_IndexBuffer)& theIndices,
+                                   const TopLoc_Location&               theInitLoc,
+                                   const Standard_Integer               theIndexLower,
+                                   const Standard_Integer               theIndexUpper,
+                                   const bool                           theToEvalMinMax = true);
+
+  //! Initialize the sensitive object from point set.
+  //! @param theVerts        attributes array containing Graphic3d_TOA_POS with type Graphic3d_TOD_VEC3 or Graphic3d_TOD_VEC2
+  //! @param theIndices      index array to define subset of points
+  //! @param theInitLoc      location
+  //! @param theToEvalMinMax compute bounding box within initialization
+  bool InitPoints (const Handle(Graphic3d_Buffer)&      theVerts,
+                   const Handle(Graphic3d_IndexBuffer)& theIndices,
+                   const TopLoc_Location&               theInitLoc,
+                   const bool                           theToEvalMinMax = true)
+  {
+    const Standard_Integer anUpper = !theIndices.IsNull() ? (theIndices->NbElements - 1)
+                                                          : (!theVerts.IsNull() ? (theVerts->NbElements - 1) : 0);
+    return InitPoints (theVerts, theIndices, theInitLoc, 0, anUpper, theToEvalMinMax);
+  }
+
+  //! Initialize the sensitive object from point set.
+  //! @param theVerts        attributes array containing Graphic3d_TOA_POS with type Graphic3d_TOD_VEC3 or Graphic3d_TOD_VEC2
+  //! @param theInitLoc      location
+  //! @param theToEvalMinMax compute bounding box within initialization
+  bool InitPoints (const Handle(Graphic3d_Buffer)& theVerts,
+                   const TopLoc_Location&          theInitLoc,
+                   const bool                      theToEvalMinMax = true)
+  {
+    const Standard_Integer anUpper = !theVerts.IsNull() ? (theVerts->NbElements - 1) : 0;
+    return InitPoints (theVerts, Handle(Graphic3d_IndexBuffer)(), theInitLoc, 0, anUpper, theToEvalMinMax);
+  }
+
+  //! Assign new not transformed bounding box.
+  void SetMinMax (double theMinX, double theMinY, double theMinZ,
+                  double theMaxX, double theMaxY, double theMaxZ)
+  {
+    myBndBox = Select3D_BndBox3d (SelectMgr_Vec3 (theMinX, theMinY, theMinZ),
+                                  SelectMgr_Vec3 (theMaxX, theMaxY, theMaxZ));
+  }
+
+  //! Return flag indicating detection of elements (true by default).
+  bool ToDetectElements() const { return myToDetectElem; }
+
+  //! Setup detection of elements.
+  void SetDetectElements (bool theToDetect) { myToDetectElem = theToDetect; }
+
+  //! Return flag indicating detection of nodes (false by default).
+  bool ToDetectNodes() const { return myToDetectNode; }
+
+  //! Setup detection of nodes.
+  void SetDetectNodes (bool theToDetect) { myToDetectNode = theToDetect; }
+
+  //! Return flag indicating detection of edges (false by default).
+  bool ToDetectEdges() const { return myToDetectEdge; }
+
+  //! Setup detection of edges.
+  void SetDetectEdges (bool theToDetect) { myToDetectEdge = theToDetect; }
+
+  //! Return last detected element or -1 if undefined.
+  Standard_Integer LastDetectedElement() const { return myDetectedElem; }
+
+  //! Return last detected node or -1 if undefined.
+  Standard_Integer LastDetectedNode() const { return myDetectedNode; }
+
+  //! Return the first node of last detected edge or -1 if undefined.
+  Standard_Integer LastDetectedEdgeNode1() const { return myDetectedEdgeNode1; }
+
+  //! Return the second node of last detected edge or -1 if undefined.
+  Standard_Integer LastDetectedEdgeNode2() const { return myDetectedEdgeNode2; }
+
+public:
+
+  //! Checks whether the sensitive entity is overlapped by current selecting volume.
+  Standard_EXPORT virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
+                                                    SelectBasics_PickResult&             thePickResult) Standard_OVERRIDE;
+
+  Standard_EXPORT virtual Handle(Select3D_SensitiveEntity) GetConnected() Standard_OVERRIDE;
+
+  //! Returns the length of array of triangles or edges
+  Standard_EXPORT virtual Standard_Integer Size() const Standard_OVERRIDE;
+
+  //! Returns the amount of nodes in triangulation
+  virtual Standard_Integer NbSubElements() Standard_OVERRIDE
+  {
+    return myBvhIndices.NbElements;
+  }
+
+  //! Returns bounding box of triangle/edge with index theIdx
+  Standard_EXPORT virtual Select3D_BndBox3d Box (const Standard_Integer theIdx) const Standard_OVERRIDE;
+
+  //! Returns geometry center of triangle/edge with index theIdx
+  //! in array along the given axis theAxis
+  Standard_EXPORT virtual Standard_Real Center (const Standard_Integer theIdx,
+                                                const Standard_Integer theAxis) const Standard_OVERRIDE;
+
+  //! Swaps items with indexes theIdx1 and theIdx2 in array
+  Standard_EXPORT virtual void Swap (const Standard_Integer theIdx1,
+                                     const Standard_Integer theIdx2) Standard_OVERRIDE;
+
+  //! Returns bounding box of the triangulation. If location
+  //! transformation is set, it will be applied
+  Standard_EXPORT virtual Select3D_BndBox3d BoundingBox() Standard_OVERRIDE;
+
+  //! Returns center of triangulation. If location transformation
+  //! is set, it will be applied
+  virtual gp_Pnt CenterOfGeometry() const Standard_OVERRIDE
+  {
+    return myCDG3D;
+  }
+
+  //! Returns true if the shape corresponding to the entity has init location
+  virtual Standard_Boolean HasInitLocation() const Standard_OVERRIDE
+  {
+    return !myInitLocation.IsIdentity();
+  }
+
+  //! Returns inversed location transformation matrix if the shape corresponding
+  //! to this entity has init location set. Otherwise, returns identity matrix.
+  virtual gp_Trsf InvInitLocation() const Standard_OVERRIDE
+  {
+    return myInvInitLocation;
+  }
+
+protected:
+
+  //! Compute bounding box.
+  Standard_EXPORT void computeBoundingBox();
+
+  //! Inner function for transformation application to bounding
+  //! box of the triangulation
+  Standard_EXPORT Select3D_BndBox3d applyTransformation();
+
+  //! Auxiliary getter.
+  const Graphic3d_Vec3& getPosVec3 (const Standard_Integer theIndex) const
+  {
+    return *reinterpret_cast<const Graphic3d_Vec3* >(myVerts->value (theIndex) + myPosOffset);
+  }
+
+  //! Auxiliary getter.
+  const Graphic3d_Vec2& getPosVec2 (const Standard_Integer theIndex) const
+  {
+    return *reinterpret_cast<const Graphic3d_Vec2* >(myVerts->value (theIndex) + myPosOffset);
+  }
+
+  //! Checks whether the element with index theIdx overlaps the current selecting volume
+  Standard_EXPORT virtual Standard_Boolean overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
+                                                            Standard_Integer theElemIdx,
+                                                            Standard_Real& theMatchDepth) Standard_OVERRIDE;
+
+  //! Calculates distance from the 3d projection of used-picked screen point to center of the geometry
+  Standard_EXPORT virtual Standard_Real distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr) Standard_OVERRIDE;
+
+  //! Checks whether the entity with index theIdx is inside the current selecting volume
+  Standard_EXPORT virtual Standard_Boolean elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
+                                                            const Standard_Integer               theElemIdx) Standard_OVERRIDE;
+
+private:
+
+  Handle(Graphic3d_Buffer)         myVerts;              //!< source data - nodes position
+  Handle(Graphic3d_IndexBuffer)    myIndices;            //!< source data - primitive indexes
+  Graphic3d_TypeOfPrimitiveArray   myPrimType;           //!< primitives type
+  Standard_Integer                 myIndexLower;         //!< index range - first index in myIndices (inclusive)
+  Standard_Integer                 myIndexUpper;         //!< index range - last  index in myIndices (inclusive)
+  Standard_Size                    myPosOffset;          //!< offset to the position vertex attribute
+  Standard_Integer                 myPatchSizeMax;       //!< patch size limit (1 by default)
+  float                            myPatchDistance;      //!< distance between elements in patch
+  bool                             myIs3d;               //!< flag indicating that position attribute has 3 components
+  TopLoc_Location                  myInitLocation;
+  gp_Pnt                           myCDG3D;              //!< Center of the whole triangulation
+  Select3D_BVHIndexBuffer          myBvhIndices;         //!< Indexes of edges or triangles for BVH tree
+  mutable Select3D_BndBox3d        myBndBox;             //!< Bounding box of the whole triangulation
+  gp_Trsf                          myInvInitLocation;
+  Standard_Real                    myMinDepthElem;       //!< the depth of nearest detected element
+  Standard_Real                    myMinDepthNode;       //!< the depth of nearest detected node
+  Standard_Real                    myMinDepthEdge;       //!< the depth of nearest detected edge
+  Standard_Integer                 myDetectedElem;       //!< index of detected element
+  Standard_Integer                 myDetectedNode;       //!< index of detected node
+  Standard_Integer                 myDetectedEdgeNode1;  //!< index of detected edge node 1
+  Standard_Integer                 myDetectedEdgeNode2;  //!< index of detected edge node 2
+  bool                             myToDetectElem;       //!< flag to detect element
+  bool                             myToDetectNode;       //!< flag to detect node
+  bool                             myToDetectEdge;       //!< flag to detect edge
+
+public:
+
+  DEFINE_STANDARD_RTTIEXT(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
+
+};
+
+DEFINE_STANDARD_HANDLE(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
+
+#endif // _Select3D_SensitivePrimitiveArray_Header
index 73f0378..f726c73 100644 (file)
@@ -127,7 +127,7 @@ Standard_Boolean Select3D_SensitiveSet::Matches (SelectBasics_SelectingVolumeMan
         }
         else // overlap test
         {
-          Standard_Real aCurrentDepth = 0.0;
+          Standard_Real aCurrentDepth = aMinDepth;
 
           if (!overlapsElement (theMgr, anElemIdx, aCurrentDepth))
           {
index 319fd11..4100eff 100644 (file)
@@ -95,7 +95,8 @@ public:
 
 protected:
 
-  //! Checks whether the entity with index theIdx overlaps the current selecting volume
+  //! Checks whether the entity with index theIdx overlaps the current selecting volume.
+  //! @param theMatchDepth set to the current minimum depth by Select3D_SensitiveSet; should be set to the new depth when overlapping is detected
   virtual Standard_Boolean overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
                                             Standard_Integer theElemIdx,
                                             Standard_Real& theMatchDepth) = 0;
@@ -108,7 +109,7 @@ protected:
   virtual Standard_Real distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr) = 0;
 
 protected:
-  Standard_Integer myDetectedIdx;     //!< Index of detected primitive in BVH sorted primitive array, for debug purposes
+  Standard_Integer myDetectedIdx;     //!< Index of detected primitive in BVH sorted primitive array
 
 private:
 
index 13d4166..af89e21 100644 (file)
@@ -63,6 +63,7 @@
 #include <Prs3d_IsoAspect.hxx>
 #include <Prs3d_PointAspect.hxx>
 #include <Select3D_SensitiveWire.hxx>
+#include <Select3D_SensitivePrimitiveArray.hxx>
 #include <SelectMgr_EntityOwner.hxx>
 #include <StdSelect_BRepOwner.hxx>
 #include <StdSelect_ViewerSelector3d.hxx>
@@ -4508,6 +4509,14 @@ static Standard_Integer VState (Draw_Interpretor& theDI,
               << aSen->DynamicType()->Name()
               << "\n";
       }
+
+      Handle(Select3D_SensitivePrimitiveArray) aPrimArr = Handle(Select3D_SensitivePrimitiveArray)::DownCast (anEntity);
+      if (!aPrimArr.IsNull())
+      {
+        theDI << "                       Detected Element: "
+              << aPrimArr->LastDetectedElement()
+              << "\n";
+      }
     }
     return 0;
   }