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 (!matches (theMgr, thePickResult, toDetectRange))
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 SelectBasics_PickResult aPickResult;
932 bool hasResults = false;
933 for (Standard_Integer aGroupIter = 0; aGroupIter < myBvhIndices.NbElements; ++aGroupIter)
935 const Standard_Integer anElemIdx = myBvhIndices.Index (aGroupIter);
936 Handle(Select3D_SensitivePrimitiveArray)& aChild = myGroups->ChangeValue (anElemIdx);
937 if (aChild->Matches (theMgr, aPickResult))
940 if (!myDetectedElemMap.IsNull())
942 myDetectedElemMap->ChangeMap().Unite (aChild->myDetectedElemMap->Map());
944 if (!myDetectedNodeMap.IsNull())
946 myDetectedNodeMap->ChangeMap().Unite (aChild->myDetectedNodeMap->Map());
948 if (thePickResult.Depth() > aPickResult.Depth())
950 myDetectedIdx = aGroupIter;
951 thePickResult = aPickResult;
957 return Standard_False;
959 thePickResult.SetDistToGeomCenter(theMgr.DistToGeometryCenter(CenterOfGeometry()));
960 return Standard_True;
963 // =======================================================================
964 // function : overlapsElement
966 // =======================================================================
967 Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_PickResult& thePickResult,
968 SelectBasics_SelectingVolumeManager& theMgr,
969 Standard_Integer theElemIdx,
970 Standard_Boolean theIsFullInside)
972 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
973 if (!myGroups.IsNull())
975 return myGroups->Value (anElemIdx)->Matches (theMgr, thePickResult);
978 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
979 Select3D_BndBox3d aBox;
980 Standard_Boolean aResult = Standard_False;
981 SelectBasics_PickResult aPickResult;
984 case Graphic3d_TOPA_POINTS:
986 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
988 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
989 const Standard_Integer aPointIndex = !myIndices.IsNull()
990 ? myIndices->Index (anIndexOffset)
995 aPoint = vecToPnt (getPosVec3 (aPointIndex));
999 aPoint = vecToPnt (getPosVec2 (aPointIndex));
1005 if (theIsFullInside || theMgr.Overlaps (aPoint, aPickResult))
1007 if (aPickResult.Depth() <= myMinDepthNode)
1009 myDetectedElem = myDetectedNode = aPointIndex;
1010 myMinDepthElem = myMinDepthNode = aPickResult.Depth();
1012 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1014 if (!myDetectedElemMap.IsNull())
1016 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1018 if (!myDetectedNodeMap.IsNull())
1020 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1023 aResult = Standard_True;
1026 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1030 case Graphic3d_TOPA_TRIANGLES:
1032 Graphic3d_Vec3i aTriNodes;
1033 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1035 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1036 const Standard_Integer anIndexOffset = aTriIndex * 3;
1037 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1041 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1042 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1043 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1047 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1048 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1049 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1054 if (theIsFullInside || theMgr.Overlaps (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aPickResult))
1056 if (aPickResult.Depth() <= myMinDepthElem)
1058 myDetectedElem = aTriIndex;
1059 myMinDepthElem = aPickResult.Depth();
1061 aResult = Standard_True;
1063 if (!myDetectedElemMap.IsNull()
1064 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1066 myDetectedElemMap->ChangeMap().Add (aTriIndex);
1071 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1073 if (theIsFullInside || theMgr.Overlaps (aPnts[aNodeIter], aPickResult))
1075 if (aPickResult.Depth() <= myMinDepthNode)
1077 myDetectedNode = aTriNodes[aNodeIter];
1078 myMinDepthNode = aPickResult.Depth();
1080 if (!myDetectedNodeMap.IsNull()
1081 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1083 myDetectedNodeMap->ChangeMap().Add (aTriNodes[aNodeIter]);
1085 aResult = Standard_True;
1091 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1093 int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
1094 int aNode2 = aNodeIter;
1095 if (theIsFullInside || theMgr.Overlaps (aPnts[aNode1], aPnts[aNode2], aPickResult))
1097 if (aPickResult.Depth() <= myMinDepthEdge)
1099 myDetectedEdgeNode1 = aTriNodes[aNode1];
1100 myDetectedEdgeNode2 = aTriNodes[aNode2];
1101 myMinDepthEdge = aPickResult.Depth();
1103 aResult = Standard_True;
1107 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1113 return Standard_False;
1120 // =======================================================================
1121 // function : distanceToCOG
1123 // =======================================================================
1124 Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
1126 return theMgr.DistToGeometryCenter (myCDG3D);
1129 // =======================================================================
1130 // function : elementIsInside
1132 // =======================================================================
1133 Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
1134 Standard_Integer theElemIdx,
1135 Standard_Boolean theIsFullInside)
1137 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
1138 if (!myGroups.IsNull())
1140 SelectBasics_PickResult aDummy;
1141 return myGroups->Value (anElemIdx)->Matches (theMgr, aDummy);
1144 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
1147 case Graphic3d_TOPA_POINTS:
1149 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1151 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
1152 const Standard_Integer aPointIndex = !myIndices.IsNull()
1153 ? myIndices->Index (anIndexOffset)
1158 aPoint = vecToPnt (getPosVec3 (aPointIndex));
1162 aPoint = vecToPnt (getPosVec2 (aPointIndex));
1164 if (!theIsFullInside && !theMgr.Overlaps (aPoint))
1166 return Standard_False;
1169 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1171 if (!myDetectedElemMap.IsNull())
1173 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1175 if (!myDetectedNodeMap.IsNull())
1177 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1181 return Standard_True;
1183 case Graphic3d_TOPA_TRIANGLES:
1185 Graphic3d_Vec3i aTriNodes;
1186 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1188 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1189 const Standard_Integer anIndexOffset = aTriIndex * 3;
1190 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1194 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1195 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1196 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1200 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1201 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1202 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1205 if (!theIsFullInside && ( !theMgr.Overlaps (aPnts[0])
1206 || !theMgr.Overlaps (aPnts[1])
1207 || !theMgr.Overlaps (aPnts[2])))
1209 return Standard_False;
1212 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1214 if (!myDetectedElemMap.IsNull())
1216 myDetectedElemMap->ChangeMap().Add (aTriIndex);
1218 if (!myDetectedNodeMap.IsNull())
1220 myDetectedNodeMap->ChangeMap().Add (aTriNodes[0]);
1221 myDetectedNodeMap->ChangeMap().Add (aTriNodes[1]);
1222 myDetectedNodeMap->ChangeMap().Add (aTriNodes[2]);
1226 return Standard_True;
1230 return Standard_False;