From 8b9a309b489c0778ef919f6410e26a4fd7ae00c0 Mon Sep 17 00:00:00 2001 From: kgv Date: Wed, 20 Apr 2016 09:48:58 +0300 Subject: [PATCH] 0027202: Visualization - add sensitivity Select3D_SensitivePrimitiveArray for Graphic3d_Buffer 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. --- src/AIS/AIS_PointCloud.cxx | 33 +- src/AIS/AIS_PointCloud.hxx | 7 + src/BVH/BVH_LinearBuilder.lxx | 15 +- src/BVH/BVH_QueueBuilder.lxx | 7 +- src/BVH/BVH_Set.lxx | 3 +- src/PrsMgr/PrsMgr_PresentableObject.hxx | 4 +- src/Select3D/FILES | 3 + src/Select3D/Select3D_BVHIndexBuffer.hxx | 100 ++ .../Select3D_SensitivePrimitiveArray.cxx | 863 ++++++++++++++++++ .../Select3D_SensitivePrimitiveArray.hxx | 284 ++++++ src/Select3D/Select3D_SensitiveSet.cxx | 2 +- src/Select3D/Select3D_SensitiveSet.hxx | 5 +- src/ViewerTest/ViewerTest.cxx | 9 + 13 files changed, 1315 insertions(+), 20 deletions(-) create mode 100644 src/Select3D/Select3D_BVHIndexBuffer.hxx create mode 100644 src/Select3D/Select3D_SensitivePrimitiveArray.cxx create mode 100644 src/Select3D/Select3D_SensitivePrimitiveArray.hxx diff --git a/src/AIS/AIS_PointCloud.cxx b/src/AIS/AIS_PointCloud.cxx index efefed73a2..46bc506166 100644 --- a/src/AIS/AIS_PointCloud.cxx +++ b/src/AIS/AIS_PointCloud.cxx @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -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); } diff --git a/src/AIS/AIS_PointCloud.hxx b/src/AIS/AIS_PointCloud.hxx index f9a31486ea..1671755c8c 100644 --- a/src/AIS/AIS_PointCloud.hxx +++ b/src/AIS/AIS_PointCloud.hxx @@ -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. diff --git a/src/BVH/BVH_LinearBuilder.lxx b/src/BVH/BVH_LinearBuilder.lxx index d822a0fa7e..6e92028a52 100644 --- a/src/BVH/BVH_LinearBuilder.lxx +++ b/src/BVH/BVH_LinearBuilder.lxx @@ -384,8 +384,8 @@ void BVH_LinearBuilder::Build (BVH_Set* theSet, const BVH_Box& 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::Build (BVH_Set* theSet, const T aReverseSizeY = static_cast (aDimensionY) / Max (aMinSize, aSceneMax.y() - aSceneMin.y()); const T aReverseSizeZ = static_cast (aDimensionZ) / Max (aMinSize, aSceneMax.z() - aSceneMin.z()); - std::vector anEncodedLinks (theSet->Size(), BVH_EncodedLink()); + std::vector 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::Build (BVH_Set* theSet, // Step 3 -- Emitting BVH hierarchy from sorted Morton codes EmitHierachy (theBVH, 29, 0, anEncodedLinks.begin(), anEncodedLinks.end()); - NCollection_Array1 aLinkMap (0, theSet->Size() - 1); - - for (Standard_Integer aLinkIdx = 0; aLinkIdx < theSet->Size(); ++aLinkIdx) + NCollection_Array1 aLinkMap (0, aSetSize - 1); + for (Standard_Integer aLinkIdx = 0; aLinkIdx < aSetSize; ++aLinkIdx) { aLinkMap (anEncodedLinks[aLinkIdx].second) = aLinkIdx; } @@ -466,7 +465,7 @@ void BVH_LinearBuilder::Build (BVH_Set* 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); diff --git a/src/BVH/BVH_QueueBuilder.lxx b/src/BVH/BVH_QueueBuilder.lxx index 20ecff23dd..dadf482c58 100644 --- a/src/BVH/BVH_QueueBuilder.lxx +++ b/src/BVH/BVH_QueueBuilder.lxx @@ -103,12 +103,13 @@ void BVH_QueueBuilder::Build (BVH_Set* 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::Build (BVH_Set* 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 aThreads; diff --git a/src/BVH/BVH_Set.lxx b/src/BVH/BVH_Set.lxx index 3dd7e01cc6..7453a35d2d 100644 --- a/src/BVH/BVH_Set.lxx +++ b/src/BVH/BVH_Set.lxx @@ -41,7 +41,8 @@ template BVH_Box BVH_Set::Box() const { BVH_Box 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)); } diff --git a/src/PrsMgr/PrsMgr_PresentableObject.hxx b/src/PrsMgr/PrsMgr_PresentableObject.hxx index 14af43ad60..cb2946a0d1 100644 --- a/src/PrsMgr/PrsMgr_PresentableObject.hxx +++ b/src/PrsMgr/PrsMgr_PresentableObject.hxx @@ -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. diff --git a/src/Select3D/FILES b/src/Select3D/FILES index 354cc2bf72..ea12ef8249 100755 --- a/src/Select3D/FILES +++ b/src/Select3D/FILES @@ -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 index 0000000000..85d8240c0e --- /dev/null +++ b/src/Select3D/Select3D_BVHIndexBuffer.hxx @@ -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 +#include +#include +#include + +//! 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(value (theIndex))); + } + + //! Access index at specified position + Standard_Integer PatchSize (const Standard_Integer theIndex) const + { + return myHasPatches + ? Standard_Integer(*reinterpret_cast(value (theIndex) + sizeof(unsigned int))) + : 1; + } + + //! Change index at specified position + void SetIndex (const Standard_Integer theIndex, + const Standard_Integer theValue) + { + *reinterpret_cast(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(changeValue (theIndex)) = (unsigned int )theValue; + *reinterpret_cast(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 index 0000000000..6851cf805f --- /dev/null +++ b/src/Select3D/Select3D_SensitivePrimitiveArray.cxx @@ -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 + +#include + +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 index 0000000000..4e858efe18 --- /dev/null +++ b/src/Select3D/Select3D_SensitivePrimitiveArray.hxx @@ -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 +#include +#include +#include +#include + +//! 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(myVerts->value (theIndex) + myPosOffset); + } + + //! Auxiliary getter. + const Graphic3d_Vec2& getPosVec2 (const Standard_Integer theIndex) const + { + return *reinterpret_cast(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 diff --git a/src/Select3D/Select3D_SensitiveSet.cxx b/src/Select3D/Select3D_SensitiveSet.cxx index 73f0378023..f726c73c82 100644 --- a/src/Select3D/Select3D_SensitiveSet.cxx +++ b/src/Select3D/Select3D_SensitiveSet.cxx @@ -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)) { diff --git a/src/Select3D/Select3D_SensitiveSet.hxx b/src/Select3D/Select3D_SensitiveSet.hxx index 319fd115ce..4100effba9 100644 --- a/src/Select3D/Select3D_SensitiveSet.hxx +++ b/src/Select3D/Select3D_SensitiveSet.hxx @@ -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: diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 13d4166f18..af89e21f50 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -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; } -- 2.20.1