1 // Created on: 2016-02-20
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2016 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Select3D_SensitivePrimitiveArray.hxx>
18 #include <NCollection_AlignedAllocator.hxx>
19 #include <OSD_Parallel.hxx>
20 #include <Standard_Atomic.hxx>
22 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
27 //! Auxiliary converter.
28 static inline gp_Pnt vecToPnt (const Graphic3d_Vec3& theVec)
30 return gp_Pnt (theVec.x(), theVec.y(), theVec.z());
33 //! Auxiliary converter.
34 static inline gp_Pnt vecToPnt (const Graphic3d_Vec2& theVec)
36 return gp_Pnt (theVec.x(), theVec.y(), 0.0);
40 //! Auxiliary function to find shared node between two triangles.
41 static inline bool hasSharedNode (const Standard_Integer* theTri1,
42 const Standard_Integer* theTri2)
44 return theTri1[0] == theTri2[0]
45 || theTri1[1] == theTri2[0]
46 || theTri1[2] == theTri2[0]
47 || theTri1[0] == theTri2[1]
48 || theTri1[1] == theTri2[1]
49 || theTri1[2] == theTri2[1]
50 || theTri1[0] == theTri2[2]
51 || theTri1[1] == theTri2[2]
52 || theTri1[2] == theTri2[2];
55 //! Fill in the triangle nodes indices.
56 static inline void getTriIndices (const Handle(Graphic3d_IndexBuffer)& theIndices,
57 const Standard_Integer theIndexOffset,
58 Standard_Integer* theNodes)
60 if (!theIndices.IsNull())
62 theNodes[0] = theIndices->Index (theIndexOffset + 0);
63 theNodes[1] = theIndices->Index (theIndexOffset + 1);
64 theNodes[2] = theIndices->Index (theIndexOffset + 2);
68 theNodes[0] = theIndexOffset + 0;
69 theNodes[1] = theIndexOffset + 1;
70 theNodes[2] = theIndexOffset + 2;
76 //! Functor for initializing groups in parallel threads.
77 struct Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray_InitFunctor
79 Select3D_SensitivePrimitiveArray_InitFunctor (Select3D_SensitivePrimitiveArray& thePrimArray,
80 Standard_Integer theDivStep,
81 Standard_Boolean theToEvalMinMax)
82 : myPrimArray (thePrimArray),
83 myDivStep (theDivStep),
84 myToEvalMinMax (theToEvalMinMax),
85 myToComputeBvh (Standard_True),
87 void operator()(const Standard_Integer& theIndex) const
89 Handle(Select3D_SensitivePrimitiveArray)& anEntity = myPrimArray.myGroups->ChangeValue (theIndex);
90 const Standard_Integer aLower = myPrimArray.myIndexLower + theIndex * myDivStep;
91 const Standard_Integer anUpper = Min (aLower + myDivStep - 1, myPrimArray.myIndexUpper);
92 anEntity = new Select3D_SensitivePrimitiveArray (myPrimArray.myOwnerId);
93 anEntity->SetPatchSizeMax (myPrimArray.myPatchSizeMax);
94 anEntity->SetPatchDistance (myPrimArray.myPatchDistance);
95 anEntity->SetDetectElements (myPrimArray.myToDetectElem);
96 anEntity->SetDetectElementMap (myPrimArray.ToDetectElementMap());
97 anEntity->SetDetectNodes (myPrimArray.myToDetectNode);
98 anEntity->SetDetectNodeMap (myPrimArray.ToDetectNodeMap());
99 anEntity->SetSensitivityFactor(myPrimArray.SensitivityFactor());
100 switch (myPrimArray.myPrimType)
102 case Graphic3d_TOPA_POINTS:
104 if (!anEntity->InitPoints (myPrimArray.myVerts, myPrimArray.myIndices, myPrimArray.myInitLocation, aLower, anUpper, myToEvalMinMax, 1))
106 Standard_Atomic_Increment (&myNbFailures);
111 case Graphic3d_TOPA_TRIANGLES:
113 if (!anEntity->InitTriangulation (myPrimArray.myVerts, myPrimArray.myIndices, myPrimArray.myInitLocation, aLower, anUpper, myToEvalMinMax, 1))
115 Standard_Atomic_Increment (&myNbFailures);
122 Standard_Atomic_Increment (&myNbFailures);
132 Standard_Boolean IsDone() const { return myNbFailures == 0; }
134 Select3D_SensitivePrimitiveArray_InitFunctor operator= (Select3D_SensitivePrimitiveArray_InitFunctor& );
136 Select3D_SensitivePrimitiveArray& myPrimArray;
137 Standard_Integer myDivStep;
138 Standard_Boolean myToEvalMinMax;
139 Standard_Boolean myToComputeBvh;
140 mutable volatile Standard_Integer myNbFailures;
143 //! Functor for computing BVH in parallel threads.
144 struct Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray_BVHFunctor
146 Select3D_SensitivePrimitiveArray_BVHFunctor (NCollection_Array1<Handle(Select3D_SensitivePrimitiveArray)>& theGroups) : myGroups (theGroups) {}
147 void operator()(const Standard_Integer& theIndex) const { myGroups.ChangeValue (theIndex)->BVH(); }
149 Select3D_SensitivePrimitiveArray_BVHFunctor operator= (Select3D_SensitivePrimitiveArray_BVHFunctor& );
151 NCollection_Array1<Handle(Select3D_SensitivePrimitiveArray)>& myGroups;
154 // =======================================================================
155 // function : Select3D_SensitivePrimitiveArray
157 // =======================================================================
158 Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray (const Handle(SelectBasics_EntityOwner)& theOwnerId)
159 : Select3D_SensitiveSet (theOwnerId),
160 myPrimType (Graphic3d_TOPA_UNDEFINED),
163 myPosOffset (Standard_Size(-1)),
165 myPatchDistance (ShortRealLast()),
167 myBvhIndices (new NCollection_AlignedAllocator(16)),
168 myMinDepthElem (RealLast()),
169 myMinDepthNode (RealLast()),
170 myMinDepthEdge (RealLast()),
173 myDetectedEdgeNode1 (-1),
174 myDetectedEdgeNode2 (-1),
175 myToDetectElem (true),
176 myToDetectNode (false),
177 myToDetectEdge (false)
182 // =======================================================================
183 // function : SetDetectElementMap
185 // =======================================================================
186 void Select3D_SensitivePrimitiveArray::SetDetectElementMap (bool theToDetect)
190 myDetectedElemMap.Nullify();
194 if (myDetectedElemMap.IsNull())
196 myDetectedElemMap = new TColStd_HPackedMapOfInteger();
200 myDetectedElemMap->ChangeMap().Clear();
204 // =======================================================================
205 // function : SetDetectNodeMap
207 // =======================================================================
208 void Select3D_SensitivePrimitiveArray::SetDetectNodeMap (bool theToDetect)
212 myDetectedNodeMap.Nullify();
216 if (myDetectedNodeMap.IsNull())
218 myDetectedNodeMap = new TColStd_HPackedMapOfInteger();
222 myDetectedNodeMap->ChangeMap().Clear();
226 // =======================================================================
227 // function : InitTriangulation
229 // =======================================================================
230 bool Select3D_SensitivePrimitiveArray::InitTriangulation (const Handle(Graphic3d_Buffer)& theVerts,
231 const Handle(Graphic3d_IndexBuffer)& theIndices,
232 const TopLoc_Location& theInitLoc,
233 const Standard_Integer theIndexLower,
234 const Standard_Integer theIndexUpper,
235 const bool theToEvalMinMax,
236 const Standard_Integer theNbGroups)
240 myPrimType = Graphic3d_TOPA_TRIANGLES;
246 myPosOffset = Standard_Size(-1);
247 myBvhIndices.release();
249 myInitLocation = theInitLoc;
250 myCDG3D.SetCoord (0.0, 0.0, 0.0);
251 if (theVerts.IsNull()
252 || theVerts->NbElements == 0)
257 for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
259 const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
260 if (anAttrib.Id == Graphic3d_TOA_POS)
262 if (anAttrib.DataType == Graphic3d_TOD_VEC3
263 || anAttrib.DataType == Graphic3d_TOD_VEC4)
267 else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
272 myPosOffset = theVerts->AttributeOffset (anAttribIter);
276 if (myPosOffset == Standard_Size(-1))
281 if (!theIndices.IsNull())
283 if (theIndexLower < 0
284 || theIndexUpper >= theIndices->NbElements
285 || theIndices->NbElements == 0)
292 if (theIndexLower < 0
293 || theIndexUpper >= theVerts->NbElements)
299 Standard_Integer aTriFrom = theIndexLower / 3;
300 Standard_Integer aNbTris = (theIndexUpper - theIndexLower + 1) / 3;
301 const bool hasGroups = (theNbGroups > 1) && (aNbTris / theNbGroups > 10);
306 if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbTris, !hasGroups && myPatchSizeMax > 1))
312 myIndices = theIndices;
313 myIndexLower = theIndexLower;
314 myIndexUpper = theIndexUpper;
315 myInvInitLocation = myInitLocation.Transformation().Inverted();
318 myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
319 const Standard_Integer aDivStep = (aNbTris / theNbGroups) * 3;
320 Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
321 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
322 if (!anInitFunctor.IsDone())
326 for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
328 Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
329 myBndBox.Combine (anEntity->BoundingBox());
330 myBvhIndices.SetIndex (aGroupIter, aGroupIter);
331 myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
333 myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
336 computeBoundingBox();
341 Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
342 Standard_Integer aTriNodes1[3] = { -1, -1, -1 };
343 Standard_Integer aTriNodes2[3] = { -1, -1, -1 };
344 Standard_Integer* aTriNodesPrev = aTriNodes1;
345 Standard_Integer* aTriNodes = aTriNodes2;
346 Standard_Integer aPatchFrom = 0;
347 Standard_Integer aPatchSize = 0;
348 if (myBvhIndices.HasPatches())
350 myBvhIndices.NbElements = 0;
352 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
354 const Standard_Integer anIndexOffset = (aTriFrom + aTriIter) * 3;
355 getTriIndices (myIndices, anIndexOffset, aTriNodes);
358 const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
359 const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
360 const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
361 aCenter += (aNode1 + aNode2 + aNode3) / 3.0;
365 const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
366 const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
367 const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
368 aCenter += Graphic3d_Vec3((aNode1 + aNode2 + aNode3) / 3.0);
370 if (myBvhIndices.HasPatches())
372 std::swap (aTriNodes, aTriNodesPrev);
373 if (aPatchSize < myPatchSizeMax
374 && hasSharedNode (aTriNodes, aTriNodesPrev))
381 myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
382 aPatchFrom = aTriIter;
388 myBvhIndices.SetIndex (aTriIter, aTriFrom + aTriIter);
393 myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
395 aCenter /= float(aNbTris);
397 myCDG3D = vecToPnt (aCenter);
400 computeBoundingBox();
405 // =======================================================================
406 // function : InitPoints
408 // =======================================================================
409 bool Select3D_SensitivePrimitiveArray::InitPoints (const Handle(Graphic3d_Buffer)& theVerts,
410 const Handle(Graphic3d_IndexBuffer)& theIndices,
411 const TopLoc_Location& theInitLoc,
412 const Standard_Integer theIndexLower,
413 const Standard_Integer theIndexUpper,
414 const bool theToEvalMinMax,
415 const Standard_Integer theNbGroups)
419 myPrimType = Graphic3d_TOPA_POINTS;
425 myPosOffset = Standard_Size(-1);
426 myBvhIndices.release();
428 myInitLocation = theInitLoc;
429 if (theVerts.IsNull()
430 || theVerts->NbElements == 0)
435 for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
437 const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
438 if (anAttrib.Id == Graphic3d_TOA_POS)
440 if (anAttrib.DataType == Graphic3d_TOD_VEC3
441 || anAttrib.DataType == Graphic3d_TOD_VEC4)
445 else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
450 myPosOffset = theVerts->AttributeOffset (anAttribIter);
454 if (myPosOffset == Standard_Size(-1))
459 if (!theIndices.IsNull())
461 if (theIndexLower < 0
462 || theIndexUpper >= theIndices->NbElements
463 || theIndices->NbElements == 0)
470 if (theIndexLower < 0
471 || theIndexUpper >= theVerts->NbElements)
477 const Standard_Integer aNbPoints = theIndexUpper - theIndexLower + 1;
478 const bool hasGroups = (theNbGroups > 1) && (aNbPoints / theNbGroups > 10);
483 if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbPoints, !hasGroups && myPatchSizeMax > 1))
489 myIndices = theIndices;
490 myIndexLower = theIndexLower;
491 myIndexUpper = theIndexUpper;
492 myInvInitLocation = myInitLocation.Transformation().Inverted();
495 myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
496 const Standard_Integer aDivStep = aNbPoints / theNbGroups;
497 Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
498 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
499 if (!anInitFunctor.IsDone())
503 for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
505 Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
506 myBndBox.Combine (anEntity->BoundingBox());
507 myBvhIndices.SetIndex (aGroupIter, aGroupIter);
508 myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
510 myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
513 computeBoundingBox();
518 Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
519 Standard_Integer aPatchFrom = 0;
520 Standard_Integer aPatchSize = 0;
521 if (myBvhIndices.HasPatches())
523 myBvhIndices.NbElements = 0;
525 const float aPatchSize2 = myPatchDistance < ShortRealLast()
526 ? myPatchDistance * myPatchDistance
528 const Graphic3d_Vec3* aPnt3dPrev = NULL;
529 const Graphic3d_Vec3* aPnt3d = NULL;
530 const Graphic3d_Vec2* aPnt2dPrev = NULL;
531 const Graphic3d_Vec2* aPnt2d = NULL;
532 for (Standard_Integer aPointIter = 0; aPointIter < aNbPoints; ++aPointIter)
534 const Standard_Integer anIndexOffset = (theIndexLower + aPointIter);
535 const Standard_Integer aPointIndex = !myIndices.IsNull()
536 ? myIndices->Index (anIndexOffset)
540 aPnt3d = &getPosVec3 (aPointIndex);
545 aPnt2d = &getPosVec2 (aPointIndex);
546 aCenter += Graphic3d_Vec3(*aPnt2d);
549 if (myBvhIndices.HasPatches())
553 std::swap (aPnt3d, aPnt3dPrev);
554 if (aPatchSize < myPatchSizeMax
556 && (*aPnt3dPrev - *aPnt3d).SquareModulus() < aPatchSize2)
564 std::swap (aPnt2d, aPnt2dPrev);
565 if (aPatchSize < myPatchSizeMax
567 && (*aPnt2dPrev - *aPnt2d).SquareModulus() < aPatchSize2)
574 myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom,
575 aPatchSize != 0 ? aPatchSize : 1);
576 aPatchFrom = aPointIter;
581 myBvhIndices.SetIndex (aPointIter, theIndexLower + aPointIter);
586 myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom, aPatchSize);
588 aCenter /= float(aNbPoints);
590 myCDG3D = vecToPnt (aCenter);
593 computeBoundingBox();
598 // =======================================================================
599 // function : GetConnected
601 // =======================================================================
602 Handle(Select3D_SensitiveEntity) Select3D_SensitivePrimitiveArray::GetConnected()
604 Handle(Select3D_SensitivePrimitiveArray) aNewEntity = new Select3D_SensitivePrimitiveArray (myOwnerId);
607 case Graphic3d_TOPA_POINTS:
609 aNewEntity->InitPoints (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
612 case Graphic3d_TOPA_TRIANGLES:
614 aNewEntity->InitTriangulation (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
622 //=======================================================================
625 //=======================================================================
626 void Select3D_SensitivePrimitiveArray::Set (const Handle(SelectBasics_EntityOwner)& theOwnerId)
628 base_type::Set (theOwnerId);
629 if (!myGroups.IsNull())
631 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
633 aGroupIter.Value()->Set (theOwnerId);
638 // =======================================================================
641 // =======================================================================
642 void Select3D_SensitivePrimitiveArray::BVH()
644 if (!myContent.IsDirty())
650 if (myGroups.IsNull())
655 Standard_Integer aNbToUpdate = 0;
656 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
658 if (aGroupIter.Value()->myContent.IsDirty())
666 Select3D_SensitivePrimitiveArray_BVHFunctor aFunctor (*myGroups);
667 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, aFunctor, aNbToUpdate <= 1);
671 // =======================================================================
674 // =======================================================================
675 Standard_Integer Select3D_SensitivePrimitiveArray::Size() const
677 return myBvhIndices.NbElements;
680 // =======================================================================
683 // =======================================================================
684 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::Box (const Standard_Integer theIdx) const
686 const Standard_Integer anElemIdx = myBvhIndices.Index (theIdx);
687 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theIdx);
688 if (!myGroups.IsNull())
690 return myGroups->Value (anElemIdx)->BoundingBox();
693 Select3D_BndBox3d aBox;
696 case Graphic3d_TOPA_POINTS:
698 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
700 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
701 const Standard_Integer aPointIndex = !myIndices.IsNull()
702 ? myIndices->Index (anIndexOffset)
706 const Graphic3d_Vec3& aPoint = getPosVec3 (aPointIndex);
707 aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), aPoint.z()));
711 const Graphic3d_Vec2& aPoint = getPosVec2 (aPointIndex);
712 aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), 0.0));
717 case Graphic3d_TOPA_TRIANGLES:
719 Standard_Integer aTriNodes[3];
722 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
724 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
725 getTriIndices (myIndices, anIndexOffset, aTriNodes);
726 const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
727 const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
728 const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
729 Graphic3d_Vec3 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
730 Graphic3d_Vec3 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
731 aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), aMinPnt.z()));
732 aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), aMaxPnt.z()));
737 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
739 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
740 getTriIndices (myIndices, anIndexOffset, aTriNodes);
741 const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
742 const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
743 const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
744 Graphic3d_Vec2 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
745 Graphic3d_Vec2 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
746 aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), 0.0));
747 aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), 0.0));
760 // =======================================================================
763 // =======================================================================
764 Standard_Real Select3D_SensitivePrimitiveArray::Center (const Standard_Integer theIdx,
765 const Standard_Integer theAxis) const
767 if (!myGroups.IsNull())
769 const Standard_Integer anElemIdx = myBvhIndices.Index (theIdx);
770 const gp_Pnt aCenter = myGroups->Value (anElemIdx)->CenterOfGeometry();
771 return theAxis == 0 ? aCenter.X() : (theAxis == 1 ? aCenter.Y() : aCenter.Z());
774 const Select3D_BndBox3d& aBox = Box (theIdx);
775 SelectMgr_Vec3 aCenter = (aBox.CornerMin() + aBox.CornerMax()) * 0.5;
776 return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
779 // =======================================================================
782 // =======================================================================
783 void Select3D_SensitivePrimitiveArray::Swap (const Standard_Integer theIdx1,
784 const Standard_Integer theIdx2)
786 Standard_Integer anElemIdx1 = myBvhIndices.Index (theIdx1);
787 Standard_Integer anElemIdx2 = myBvhIndices.Index (theIdx2);
788 if (myBvhIndices.HasPatches())
790 Standard_Integer aPatchSize1 = myBvhIndices.PatchSize (theIdx1);
791 Standard_Integer aPatchSize2 = myBvhIndices.PatchSize (theIdx2);
792 myBvhIndices.SetIndex (theIdx1, anElemIdx2, aPatchSize2);
793 myBvhIndices.SetIndex (theIdx2, anElemIdx1, aPatchSize1);
797 myBvhIndices.SetIndex (theIdx1, anElemIdx2);
798 myBvhIndices.SetIndex (theIdx2, anElemIdx1);
802 // =======================================================================
803 // function : BoundingBox
805 // =======================================================================
806 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::BoundingBox()
808 if (!myBndBox.IsValid())
810 computeBoundingBox();
812 return applyTransformation();
815 // =======================================================================
816 // function : computeBoundingBox
818 // =======================================================================
819 void Select3D_SensitivePrimitiveArray::computeBoundingBox()
822 if (!myGroups.IsNull())
824 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
826 myBndBox.Combine (aGroupIter.Value()->BoundingBox());
831 if (myVerts.IsNull())
836 const Standard_Integer aNbVerts = myVerts->NbElements;
839 for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
841 const Graphic3d_Vec3& aVert = getPosVec3 (aVertIter);
842 myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), aVert.z()));
847 for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
849 const Graphic3d_Vec2& aVert = getPosVec2 (aVertIter);
850 myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), 0.0));
855 // =======================================================================
856 // function : applyTransformation
858 // =======================================================================
859 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::applyTransformation()
861 if (!HasInitLocation())
866 Select3D_BndBox3d aBndBox;
867 for (Standard_Integer aX = 0; aX <=1; ++aX)
869 for (Standard_Integer aY = 0; aY <=1; ++aY)
871 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
873 gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
874 aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
875 aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
876 aVertex.Transform (myInitLocation.Transformation());
877 aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
884 // =======================================================================
885 // function : Matches
887 // =======================================================================
888 Standard_Boolean Select3D_SensitivePrimitiveArray::Matches (SelectBasics_SelectingVolumeManager& theMgr,
889 SelectBasics_PickResult& thePickResult)
891 if (!myDetectedElemMap.IsNull())
893 myDetectedElemMap->ChangeMap().Clear();
895 if (!myDetectedNodeMap.IsNull())
897 myDetectedNodeMap->ChangeMap().Clear();
899 myMinDepthElem = RealLast();
900 myMinDepthNode = RealLast();
901 myMinDepthEdge = RealLast();
904 myDetectedEdgeNode1 = -1;
905 myDetectedEdgeNode2 = -1;
906 const bool toDetectRange = !myDetectedElemMap.IsNull() || !myDetectedNodeMap.IsNull();
907 if (myGroups.IsNull()
908 || theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Point
911 if (!Select3D_SensitiveSet::Matches (theMgr, thePickResult))
913 return Standard_False;
916 if (!myGroups.IsNull() && myDetectedIdx != -1)
918 const Standard_Integer anIndex = myBvhIndices.Index (myDetectedIdx);
919 const Handle(Select3D_SensitivePrimitiveArray)& aLastGroup = myGroups->Value (anIndex);
920 myMinDepthElem = aLastGroup->myMinDepthElem;
921 myMinDepthNode = aLastGroup->myMinDepthNode;
922 myMinDepthEdge = aLastGroup->myMinDepthEdge;
923 myDetectedElem = aLastGroup->myDetectedElem;
924 myDetectedNode = aLastGroup->myDetectedNode;
925 myDetectedEdgeNode1 = aLastGroup->myDetectedEdgeNode1;
926 myDetectedEdgeNode2 = aLastGroup->myDetectedEdgeNode2;
928 return Standard_True;
931 Standard_Real aDepth = RealLast();
932 bool isFailed = false;
933 const bool toMatchAll = !theMgr.IsOverlapAllowed();
934 for (Standard_Integer aGroupIter = 0; aGroupIter < myBvhIndices.NbElements; ++aGroupIter)
936 const Standard_Integer anElemIdx = myBvhIndices.Index (aGroupIter);
937 SelectBasics_PickResult aMatchResult;
938 Handle(Select3D_SensitivePrimitiveArray)& aChild = myGroups->ChangeValue (anElemIdx);
939 const bool isMatched = aChild->Matches (theMgr, aMatchResult);
940 if (!myDetectedElemMap.IsNull())
942 myDetectedElemMap->ChangeMap().Unite (aChild->myDetectedElemMap->Map());
944 if (!myDetectedNodeMap.IsNull())
946 myDetectedNodeMap->ChangeMap().Unite (aChild->myDetectedNodeMap->Map());
962 if (aDepth > aMatchResult.Depth())
964 myDetectedIdx = aGroupIter;
965 aDepth = aMatchResult.Depth();
971 thePickResult = SelectBasics_PickResult (RealLast(), RealLast());
972 return Standard_False;
975 thePickResult = SelectBasics_PickResult (aDepth, theMgr.DistToGeometryCenter (CenterOfGeometry()));
976 return Standard_True;
979 // =======================================================================
980 // function : overlapsElement
982 // =======================================================================
983 Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
984 Standard_Integer theElemIdx,
985 Standard_Real& theMatchDepth)
987 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
988 if (!myGroups.IsNull())
990 SelectBasics_PickResult aResult;
991 if (myGroups->Value (anElemIdx)->Matches (theMgr, aResult))
993 theMatchDepth = aResult.Depth();
994 return Standard_True;
996 theMatchDepth = RealLast();
997 return Standard_False;
1000 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
1001 Select3D_BndBox3d aBox;
1002 Standard_Boolean aResult = Standard_False;
1003 Standard_Real aMinDepth = RealLast();
1006 case Graphic3d_TOPA_POINTS:
1008 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1010 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
1011 const Standard_Integer aPointIndex = !myIndices.IsNull()
1012 ? myIndices->Index (anIndexOffset)
1017 aPoint = vecToPnt (getPosVec3 (aPointIndex));
1021 aPoint = vecToPnt (getPosVec2 (aPointIndex));
1024 Standard_Real aCurrentDepth = RealLast();
1028 if (theMgr.Overlaps (aPoint, aCurrentDepth))
1030 if (aCurrentDepth <= myMinDepthNode)
1032 myDetectedElem = myDetectedNode = aPointIndex;
1033 myMinDepthElem = myMinDepthNode = aCurrentDepth;
1035 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1037 if (!myDetectedElemMap.IsNull())
1039 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1041 if (!myDetectedNodeMap.IsNull())
1043 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1046 aResult = Standard_True;
1049 aMinDepth = Min (aMinDepth, aCurrentDepth);
1053 case Graphic3d_TOPA_TRIANGLES:
1055 Graphic3d_Vec3i aTriNodes;
1056 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1058 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1059 const Standard_Integer anIndexOffset = aTriIndex * 3;
1060 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1064 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1065 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1066 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1070 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1071 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1072 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1075 Standard_Real aCurrentDepth = RealLast();
1078 if (theMgr.Overlaps (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aCurrentDepth))
1080 if (aCurrentDepth <= myMinDepthElem)
1082 myDetectedElem = aTriIndex;
1083 myMinDepthElem = aCurrentDepth;
1085 aResult = Standard_True;
1087 if (!myDetectedElemMap.IsNull()
1088 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1090 myDetectedElemMap->ChangeMap().Add (aTriIndex);
1095 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1097 if (theMgr.Overlaps (aPnts[aNodeIter], aCurrentDepth))
1099 if (aCurrentDepth <= myMinDepthNode)
1101 myDetectedNode = aTriNodes[aNodeIter];
1102 myMinDepthNode = aCurrentDepth;
1104 if (!myDetectedNodeMap.IsNull()
1105 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1107 myDetectedNodeMap->ChangeMap().Add (aTriNodes[aNodeIter]);
1109 aResult = Standard_True;
1115 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1117 int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
1118 int aNode2 = aNodeIter;
1119 if (theMgr.Overlaps (aPnts[aNode1], aPnts[aNode2], aCurrentDepth))
1121 if (aCurrentDepth <= myMinDepthEdge)
1123 myDetectedEdgeNode1 = aTriNodes[aNode1];
1124 myDetectedEdgeNode2 = aTriNodes[aNode2];
1125 myMinDepthEdge = aCurrentDepth;
1127 aResult = Standard_True;
1131 aMinDepth = Min (aMinDepth, aCurrentDepth);
1137 return Standard_False;
1141 theMatchDepth = aMinDepth;
1145 // =======================================================================
1146 // function : distanceToCOG
1148 // =======================================================================
1149 Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
1151 return theMgr.DistToGeometryCenter (myCDG3D);
1154 // =======================================================================
1155 // function : elementIsInside
1157 // =======================================================================
1158 Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
1159 const Standard_Integer theElemIdx)
1161 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
1162 if (!myGroups.IsNull())
1164 Standard_Real aDummy;
1165 return overlapsElement (theMgr, theElemIdx, aDummy);
1168 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
1171 case Graphic3d_TOPA_POINTS:
1173 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1175 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
1176 const Standard_Integer aPointIndex = !myIndices.IsNull()
1177 ? myIndices->Index (anIndexOffset)
1182 aPoint = vecToPnt (getPosVec3 (aPointIndex));
1186 aPoint = vecToPnt (getPosVec2 (aPointIndex));
1188 if (!theMgr.Overlaps (aPoint))
1190 return Standard_False;
1193 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1195 if (!myDetectedElemMap.IsNull())
1197 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1199 if (!myDetectedNodeMap.IsNull())
1201 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1205 return Standard_True;
1207 case Graphic3d_TOPA_TRIANGLES:
1209 Graphic3d_Vec3i aTriNodes;
1210 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1212 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1213 const Standard_Integer anIndexOffset = aTriIndex * 3;
1214 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1218 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1219 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1220 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1224 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1225 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1226 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1229 if (!theMgr.Overlaps (aPnts[0])
1230 || !theMgr.Overlaps (aPnts[1])
1231 || !theMgr.Overlaps (aPnts[2]))
1233 return Standard_False;
1236 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1238 if (!myDetectedElemMap.IsNull())
1240 myDetectedElemMap->ChangeMap().Add (aTriIndex);
1242 if (!myDetectedNodeMap.IsNull())
1244 myDetectedNodeMap->ChangeMap().Add (aTriNodes[0]);
1245 myDetectedNodeMap->ChangeMap().Add (aTriNodes[1]);
1246 myDetectedNodeMap->ChangeMap().Add (aTriNodes[2]);
1250 return Standard_True;
1254 return Standard_False;