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(SelectMgr_EntityOwner)& theOwnerId)
159 : Select3D_SensitiveSet (theOwnerId),
161 myPosStride (Standard_Size(-1)),
162 myPrimType (Graphic3d_TOPA_UNDEFINED),
166 myPatchDistance (ShortRealLast()),
168 myBvhIndices (new NCollection_AlignedAllocator(16)),
169 myMinDepthElem (RealLast()),
170 myMinDepthNode (RealLast()),
171 myMinDepthEdge (RealLast()),
174 myDetectedEdgeNode1 (-1),
175 myDetectedEdgeNode2 (-1),
176 myToDetectElem (true),
177 myToDetectNode (false),
178 myToDetectEdge (false)
183 // =======================================================================
184 // function : SetDetectElementMap
186 // =======================================================================
187 void Select3D_SensitivePrimitiveArray::SetDetectElementMap (bool theToDetect)
191 myDetectedElemMap.Nullify();
195 if (myDetectedElemMap.IsNull())
197 myDetectedElemMap = new TColStd_HPackedMapOfInteger();
201 myDetectedElemMap->ChangeMap().Clear();
205 // =======================================================================
206 // function : SetDetectNodeMap
208 // =======================================================================
209 void Select3D_SensitivePrimitiveArray::SetDetectNodeMap (bool theToDetect)
213 myDetectedNodeMap.Nullify();
217 if (myDetectedNodeMap.IsNull())
219 myDetectedNodeMap = new TColStd_HPackedMapOfInteger();
223 myDetectedNodeMap->ChangeMap().Clear();
227 // =======================================================================
228 // function : InitTriangulation
230 // =======================================================================
231 bool Select3D_SensitivePrimitiveArray::InitTriangulation (const Handle(Graphic3d_Buffer)& theVerts,
232 const Handle(Graphic3d_IndexBuffer)& theIndices,
233 const TopLoc_Location& theInitLoc,
234 const Standard_Integer theIndexLower,
235 const Standard_Integer theIndexUpper,
236 const bool theToEvalMinMax,
237 const Standard_Integer theNbGroups)
241 myPrimType = Graphic3d_TOPA_TRIANGLES;
248 myPosStride = Standard_Size(-1);
249 myBvhIndices.release();
251 myInitLocation = theInitLoc;
252 myCDG3D.SetCoord (0.0, 0.0, 0.0);
253 if (theVerts.IsNull()
254 || theVerts->NbElements == 0)
259 Standard_Integer aPosAttribIndex = 0;
260 myPosData = theVerts->AttributeData (Graphic3d_TOA_POS, aPosAttribIndex, myPosStride);
261 if (myPosData == NULL)
266 const Graphic3d_Attribute& anAttrib = theVerts->Attribute (aPosAttribIndex);
267 myIs3d = anAttrib.DataType == Graphic3d_TOD_VEC3
268 || anAttrib.DataType == Graphic3d_TOD_VEC4;
269 if (!myIs3d && anAttrib.DataType != Graphic3d_TOD_VEC2)
275 if (!theIndices.IsNull())
277 if (theIndexLower < 0
278 || theIndexUpper >= theIndices->NbElements
279 || theIndices->NbElements == 0)
286 if (theIndexLower < 0
287 || theIndexUpper >= theVerts->NbElements)
293 Standard_Integer aTriFrom = theIndexLower / 3;
294 Standard_Integer aNbTris = (theIndexUpper - theIndexLower + 1) / 3;
295 const bool hasGroups = (theNbGroups > 1) && (aNbTris / theNbGroups > 10);
300 if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbTris, !hasGroups && myPatchSizeMax > 1))
306 myIndices = theIndices;
307 myIndexLower = theIndexLower;
308 myIndexUpper = theIndexUpper;
309 myInvInitLocation = myInitLocation.Transformation().Inverted();
312 myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
313 const Standard_Integer aDivStep = (aNbTris / theNbGroups) * 3;
314 Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
315 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
316 if (!anInitFunctor.IsDone())
320 for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
322 Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
323 myBndBox.Combine (anEntity->BoundingBox());
324 myBvhIndices.SetIndex (aGroupIter, aGroupIter);
325 myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
327 myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
330 computeBoundingBox();
335 Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
336 Standard_Integer aTriNodes1[3] = { -1, -1, -1 };
337 Standard_Integer aTriNodes2[3] = { -1, -1, -1 };
338 Standard_Integer* aTriNodesPrev = aTriNodes1;
339 Standard_Integer* aTriNodes = aTriNodes2;
340 Standard_Integer aPatchFrom = 0;
341 Standard_Integer aPatchSize = 0;
342 if (myBvhIndices.HasPatches())
344 myBvhIndices.NbElements = 0;
346 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
348 const Standard_Integer anIndexOffset = (aTriFrom + aTriIter) * 3;
349 getTriIndices (myIndices, anIndexOffset, aTriNodes);
352 const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
353 const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
354 const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
355 aCenter += (aNode1 + aNode2 + aNode3) / 3.0;
359 const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
360 const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
361 const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
362 aCenter += Graphic3d_Vec3((aNode1 + aNode2 + aNode3) / 3.0);
364 if (myBvhIndices.HasPatches())
366 std::swap (aTriNodes, aTriNodesPrev);
367 if (aPatchSize < myPatchSizeMax
368 && hasSharedNode (aTriNodes, aTriNodesPrev))
375 myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
376 aPatchFrom = aTriIter;
382 myBvhIndices.SetIndex (aTriIter, aTriFrom + aTriIter);
387 myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
389 aCenter /= float(aNbTris);
391 myCDG3D = vecToPnt (aCenter);
394 computeBoundingBox();
399 // =======================================================================
400 // function : InitPoints
402 // =======================================================================
403 bool Select3D_SensitivePrimitiveArray::InitPoints (const Handle(Graphic3d_Buffer)& theVerts,
404 const Handle(Graphic3d_IndexBuffer)& theIndices,
405 const TopLoc_Location& theInitLoc,
406 const Standard_Integer theIndexLower,
407 const Standard_Integer theIndexUpper,
408 const bool theToEvalMinMax,
409 const Standard_Integer theNbGroups)
413 myPrimType = Graphic3d_TOPA_POINTS;
420 myPosStride = Standard_Size(-1);
421 myBvhIndices.release();
423 myInitLocation = theInitLoc;
424 if (theVerts.IsNull()
425 || theVerts->NbElements == 0)
430 Standard_Integer aPosAttribIndex = 0;
431 myPosData = theVerts->AttributeData (Graphic3d_TOA_POS, aPosAttribIndex, myPosStride);
432 if (myPosData == NULL)
437 const Graphic3d_Attribute& anAttrib = theVerts->Attribute (aPosAttribIndex);
438 myIs3d = anAttrib.DataType == Graphic3d_TOD_VEC3
439 || anAttrib.DataType == Graphic3d_TOD_VEC4;
440 if (!myIs3d && anAttrib.DataType != Graphic3d_TOD_VEC2)
446 if (!theIndices.IsNull())
448 if (theIndexLower < 0
449 || theIndexUpper >= theIndices->NbElements
450 || theIndices->NbElements == 0)
457 if (theIndexLower < 0
458 || theIndexUpper >= theVerts->NbElements)
464 const Standard_Integer aNbPoints = theIndexUpper - theIndexLower + 1;
465 const bool hasGroups = (theNbGroups > 1) && (aNbPoints / theNbGroups > 10);
470 if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbPoints, !hasGroups && myPatchSizeMax > 1))
476 myIndices = theIndices;
477 myIndexLower = theIndexLower;
478 myIndexUpper = theIndexUpper;
479 myInvInitLocation = myInitLocation.Transformation().Inverted();
482 myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
483 const Standard_Integer aDivStep = aNbPoints / theNbGroups;
484 Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
485 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
486 if (!anInitFunctor.IsDone())
490 for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
492 Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
493 myBndBox.Combine (anEntity->BoundingBox());
494 myBvhIndices.SetIndex (aGroupIter, aGroupIter);
495 myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
497 myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
500 computeBoundingBox();
505 Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
506 Standard_Integer aPatchFrom = 0;
507 Standard_Integer aPatchSize = 0;
508 if (myBvhIndices.HasPatches())
510 myBvhIndices.NbElements = 0;
512 const float aPatchSize2 = myPatchDistance < ShortRealLast()
513 ? myPatchDistance * myPatchDistance
515 const Graphic3d_Vec3* aPnt3dPrev = NULL;
516 const Graphic3d_Vec3* aPnt3d = NULL;
517 const Graphic3d_Vec2* aPnt2dPrev = NULL;
518 const Graphic3d_Vec2* aPnt2d = NULL;
519 for (Standard_Integer aPointIter = 0; aPointIter < aNbPoints; ++aPointIter)
521 const Standard_Integer anIndexOffset = (theIndexLower + aPointIter);
522 const Standard_Integer aPointIndex = !myIndices.IsNull()
523 ? myIndices->Index (anIndexOffset)
527 aPnt3d = &getPosVec3 (aPointIndex);
532 aPnt2d = &getPosVec2 (aPointIndex);
533 aCenter += Graphic3d_Vec3(*aPnt2d);
536 if (myBvhIndices.HasPatches())
540 std::swap (aPnt3d, aPnt3dPrev);
541 if (aPatchSize < myPatchSizeMax
543 && (*aPnt3dPrev - *aPnt3d).SquareModulus() < aPatchSize2)
551 std::swap (aPnt2d, aPnt2dPrev);
552 if (aPatchSize < myPatchSizeMax
554 && (*aPnt2dPrev - *aPnt2d).SquareModulus() < aPatchSize2)
561 myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom,
562 aPatchSize != 0 ? aPatchSize : 1);
563 aPatchFrom = aPointIter;
568 myBvhIndices.SetIndex (aPointIter, theIndexLower + aPointIter);
573 myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom, aPatchSize);
575 aCenter /= float(aNbPoints);
577 myCDG3D = vecToPnt (aCenter);
580 computeBoundingBox();
585 // =======================================================================
586 // function : GetConnected
588 // =======================================================================
589 Handle(Select3D_SensitiveEntity) Select3D_SensitivePrimitiveArray::GetConnected()
591 Handle(Select3D_SensitivePrimitiveArray) aNewEntity = new Select3D_SensitivePrimitiveArray (myOwnerId);
594 case Graphic3d_TOPA_POINTS:
596 aNewEntity->InitPoints (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
599 case Graphic3d_TOPA_TRIANGLES:
601 aNewEntity->InitTriangulation (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
609 //=======================================================================
612 //=======================================================================
613 void Select3D_SensitivePrimitiveArray::Set (const Handle(SelectMgr_EntityOwner)& theOwnerId)
615 base_type::Set (theOwnerId);
616 if (!myGroups.IsNull())
618 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
620 aGroupIter.Value()->Set (theOwnerId);
625 // =======================================================================
628 // =======================================================================
629 void Select3D_SensitivePrimitiveArray::BVH()
631 if (!myContent.IsDirty())
637 if (myGroups.IsNull())
642 Standard_Integer aNbToUpdate = 0;
643 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
645 if (aGroupIter.Value()->myContent.IsDirty())
653 Select3D_SensitivePrimitiveArray_BVHFunctor aFunctor (*myGroups);
654 OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, aFunctor, aNbToUpdate <= 1);
658 // =======================================================================
661 // =======================================================================
662 Standard_Integer Select3D_SensitivePrimitiveArray::Size() const
664 return myBvhIndices.NbElements;
667 // =======================================================================
670 // =======================================================================
671 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::Box (const Standard_Integer theIdx) const
673 const Standard_Integer anElemIdx = myBvhIndices.Index (theIdx);
674 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theIdx);
675 if (!myGroups.IsNull())
677 return myGroups->Value (anElemIdx)->BoundingBox();
680 Select3D_BndBox3d aBox;
683 case Graphic3d_TOPA_POINTS:
685 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
687 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
688 const Standard_Integer aPointIndex = !myIndices.IsNull()
689 ? myIndices->Index (anIndexOffset)
693 const Graphic3d_Vec3& aPoint = getPosVec3 (aPointIndex);
694 aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), aPoint.z()));
698 const Graphic3d_Vec2& aPoint = getPosVec2 (aPointIndex);
699 aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), 0.0));
704 case Graphic3d_TOPA_TRIANGLES:
706 Standard_Integer aTriNodes[3];
709 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
711 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
712 getTriIndices (myIndices, anIndexOffset, aTriNodes);
713 const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
714 const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
715 const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
716 Graphic3d_Vec3 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
717 Graphic3d_Vec3 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
718 aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), aMinPnt.z()));
719 aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), aMaxPnt.z()));
724 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
726 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
727 getTriIndices (myIndices, anIndexOffset, aTriNodes);
728 const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
729 const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
730 const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
731 Graphic3d_Vec2 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
732 Graphic3d_Vec2 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
733 aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), 0.0));
734 aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), 0.0));
747 // =======================================================================
750 // =======================================================================
751 Standard_Real Select3D_SensitivePrimitiveArray::Center (const Standard_Integer theIdx,
752 const Standard_Integer theAxis) const
754 if (!myGroups.IsNull())
756 const Standard_Integer anElemIdx = myBvhIndices.Index (theIdx);
757 const gp_Pnt aCenter = myGroups->Value (anElemIdx)->CenterOfGeometry();
758 return theAxis == 0 ? aCenter.X() : (theAxis == 1 ? aCenter.Y() : aCenter.Z());
761 const Select3D_BndBox3d& aBox = Box (theIdx);
762 SelectMgr_Vec3 aCenter = (aBox.CornerMin() + aBox.CornerMax()) * 0.5;
763 return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
766 // =======================================================================
769 // =======================================================================
770 void Select3D_SensitivePrimitiveArray::Swap (const Standard_Integer theIdx1,
771 const Standard_Integer theIdx2)
773 Standard_Integer anElemIdx1 = myBvhIndices.Index (theIdx1);
774 Standard_Integer anElemIdx2 = myBvhIndices.Index (theIdx2);
775 if (myBvhIndices.HasPatches())
777 Standard_Integer aPatchSize1 = myBvhIndices.PatchSize (theIdx1);
778 Standard_Integer aPatchSize2 = myBvhIndices.PatchSize (theIdx2);
779 myBvhIndices.SetIndex (theIdx1, anElemIdx2, aPatchSize2);
780 myBvhIndices.SetIndex (theIdx2, anElemIdx1, aPatchSize1);
784 myBvhIndices.SetIndex (theIdx1, anElemIdx2);
785 myBvhIndices.SetIndex (theIdx2, anElemIdx1);
789 // =======================================================================
790 // function : BoundingBox
792 // =======================================================================
793 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::BoundingBox()
795 if (!myBndBox.IsValid())
797 computeBoundingBox();
799 return applyTransformation();
802 // =======================================================================
803 // function : computeBoundingBox
805 // =======================================================================
806 void Select3D_SensitivePrimitiveArray::computeBoundingBox()
809 if (!myGroups.IsNull())
811 for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
813 myBndBox.Combine (aGroupIter.Value()->BoundingBox());
818 if (myVerts.IsNull())
823 const Standard_Integer aNbVerts = myVerts->NbElements;
826 for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
828 const Graphic3d_Vec3& aVert = getPosVec3 (aVertIter);
829 myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), aVert.z()));
834 for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
836 const Graphic3d_Vec2& aVert = getPosVec2 (aVertIter);
837 myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), 0.0));
842 // =======================================================================
843 // function : applyTransformation
845 // =======================================================================
846 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::applyTransformation()
848 if (!HasInitLocation())
853 Select3D_BndBox3d aBndBox;
854 for (Standard_Integer aX = 0; aX <=1; ++aX)
856 for (Standard_Integer aY = 0; aY <=1; ++aY)
858 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
860 gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
861 aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
862 aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
863 aVertex.Transform (myInitLocation.Transformation());
864 aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
871 // =======================================================================
872 // function : Matches
874 // =======================================================================
875 Standard_Boolean Select3D_SensitivePrimitiveArray::Matches (SelectBasics_SelectingVolumeManager& theMgr,
876 SelectBasics_PickResult& thePickResult)
878 if (!myDetectedElemMap.IsNull())
880 myDetectedElemMap->ChangeMap().Clear();
882 if (!myDetectedNodeMap.IsNull())
884 myDetectedNodeMap->ChangeMap().Clear();
886 myMinDepthElem = RealLast();
887 myMinDepthNode = RealLast();
888 myMinDepthEdge = RealLast();
891 myDetectedEdgeNode1 = -1;
892 myDetectedEdgeNode2 = -1;
893 const bool toDetectRange = !myDetectedElemMap.IsNull() || !myDetectedNodeMap.IsNull();
894 if (myGroups.IsNull()
895 || theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Point
898 if (!matches (theMgr, thePickResult, toDetectRange))
900 return Standard_False;
903 if (!myGroups.IsNull() && myDetectedIdx != -1)
905 const Standard_Integer anIndex = myBvhIndices.Index (myDetectedIdx);
906 const Handle(Select3D_SensitivePrimitiveArray)& aLastGroup = myGroups->Value (anIndex);
907 myMinDepthElem = aLastGroup->myMinDepthElem;
908 myMinDepthNode = aLastGroup->myMinDepthNode;
909 myMinDepthEdge = aLastGroup->myMinDepthEdge;
910 myDetectedElem = aLastGroup->myDetectedElem;
911 myDetectedNode = aLastGroup->myDetectedNode;
912 myDetectedEdgeNode1 = aLastGroup->myDetectedEdgeNode1;
913 myDetectedEdgeNode2 = aLastGroup->myDetectedEdgeNode2;
915 return Standard_True;
918 SelectBasics_PickResult aPickResult;
919 bool hasResults = false;
920 for (Standard_Integer aGroupIter = 0; aGroupIter < myBvhIndices.NbElements; ++aGroupIter)
922 const Standard_Integer anElemIdx = myBvhIndices.Index (aGroupIter);
923 Handle(Select3D_SensitivePrimitiveArray)& aChild = myGroups->ChangeValue (anElemIdx);
924 if (aChild->Matches (theMgr, aPickResult))
927 if (!myDetectedElemMap.IsNull())
929 myDetectedElemMap->ChangeMap().Unite (aChild->myDetectedElemMap->Map());
931 if (!myDetectedNodeMap.IsNull())
933 myDetectedNodeMap->ChangeMap().Unite (aChild->myDetectedNodeMap->Map());
935 if (thePickResult.Depth() > aPickResult.Depth())
937 myDetectedIdx = aGroupIter;
938 thePickResult = aPickResult;
944 return Standard_False;
946 thePickResult.SetDistToGeomCenter(theMgr.DistToGeometryCenter(CenterOfGeometry()));
947 return Standard_True;
950 // =======================================================================
951 // function : overlapsElement
953 // =======================================================================
954 Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_PickResult& thePickResult,
955 SelectBasics_SelectingVolumeManager& theMgr,
956 Standard_Integer theElemIdx,
957 Standard_Boolean theIsFullInside)
959 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
960 if (!myGroups.IsNull())
962 return myGroups->Value (anElemIdx)->Matches (theMgr, thePickResult);
965 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
966 Select3D_BndBox3d aBox;
967 Standard_Boolean aResult = Standard_False;
968 SelectBasics_PickResult aPickResult;
971 case Graphic3d_TOPA_POINTS:
973 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
975 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
976 const Standard_Integer aPointIndex = !myIndices.IsNull()
977 ? myIndices->Index (anIndexOffset)
982 aPoint = vecToPnt (getPosVec3 (aPointIndex));
986 aPoint = vecToPnt (getPosVec2 (aPointIndex));
992 if (theIsFullInside || theMgr.Overlaps (aPoint, aPickResult))
994 if (aPickResult.Depth() <= myMinDepthNode)
996 myDetectedElem = myDetectedNode = aPointIndex;
997 myMinDepthElem = myMinDepthNode = aPickResult.Depth();
999 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1001 if (!myDetectedElemMap.IsNull())
1003 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1005 if (!myDetectedNodeMap.IsNull())
1007 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1010 aResult = Standard_True;
1013 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1017 case Graphic3d_TOPA_TRIANGLES:
1019 Graphic3d_Vec3i aTriNodes;
1020 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1022 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1023 const Standard_Integer anIndexOffset = aTriIndex * 3;
1024 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1028 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1029 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1030 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1034 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1035 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1036 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1041 if (theIsFullInside || theMgr.Overlaps (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aPickResult))
1043 if (aPickResult.Depth() <= myMinDepthElem)
1045 myDetectedElem = aTriIndex;
1046 myMinDepthElem = aPickResult.Depth();
1048 aResult = Standard_True;
1049 if (!myDetectedElemMap.IsNull()
1050 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1052 myDetectedElemMap->ChangeMap().Add(aTriIndex);
1058 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1060 if (theIsFullInside || theMgr.Overlaps (aPnts[aNodeIter], aPickResult))
1062 if (aPickResult.Depth() <= myMinDepthNode)
1064 myDetectedNode = aTriNodes[aNodeIter];
1065 myMinDepthNode = aPickResult.Depth();
1067 if (!myDetectedNodeMap.IsNull()
1068 && theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1070 myDetectedNodeMap->ChangeMap().Add (aTriNodes[aNodeIter]);
1072 aResult = Standard_True;
1078 for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1080 int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
1081 int aNode2 = aNodeIter;
1082 if (theIsFullInside || theMgr.Overlaps (aPnts[aNode1], aPnts[aNode2], aPickResult))
1084 if (aPickResult.Depth() <= myMinDepthEdge)
1086 myDetectedEdgeNode1 = aTriNodes[aNode1];
1087 myDetectedEdgeNode2 = aTriNodes[aNode2];
1088 myMinDepthEdge = aPickResult.Depth();
1090 aResult = Standard_True;
1094 thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1100 return Standard_False;
1107 // =======================================================================
1108 // function : distanceToCOG
1110 // =======================================================================
1111 Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
1113 return theMgr.DistToGeometryCenter (myCDG3D);
1116 // =======================================================================
1117 // function : elementIsInside
1119 // =======================================================================
1120 Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
1121 Standard_Integer theElemIdx,
1122 Standard_Boolean theIsFullInside)
1124 const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
1125 if (!myGroups.IsNull())
1127 SelectBasics_PickResult aDummy;
1128 return myGroups->Value (anElemIdx)->Matches (theMgr, aDummy);
1131 const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
1134 case Graphic3d_TOPA_POINTS:
1136 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1138 const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
1139 const Standard_Integer aPointIndex = !myIndices.IsNull()
1140 ? myIndices->Index (anIndexOffset)
1145 aPoint = vecToPnt (getPosVec3 (aPointIndex));
1149 aPoint = vecToPnt (getPosVec2 (aPointIndex));
1151 if (!theIsFullInside && !theMgr.Overlaps (aPoint))
1153 return Standard_False;
1156 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1158 if (!myDetectedElemMap.IsNull())
1160 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1162 if (!myDetectedNodeMap.IsNull())
1164 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1168 return Standard_True;
1170 case Graphic3d_TOPA_TRIANGLES:
1172 Graphic3d_Vec3i aTriNodes;
1173 for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1175 const Standard_Integer aTriIndex = anElemIdx + anElemIter;
1176 const Standard_Integer anIndexOffset = aTriIndex * 3;
1177 getTriIndices (myIndices, anIndexOffset, aTriNodes);
1181 aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1182 aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1183 aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1187 aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1188 aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1189 aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1192 if (!theIsFullInside && ( !theMgr.Overlaps (aPnts[0])
1193 || !theMgr.Overlaps (aPnts[1])
1194 || !theMgr.Overlaps (aPnts[2])))
1196 return Standard_False;
1199 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
1201 if (!myDetectedElemMap.IsNull())
1203 myDetectedElemMap->ChangeMap().Add (aTriIndex);
1205 if (!myDetectedNodeMap.IsNull())
1207 myDetectedNodeMap->ChangeMap().Add (aTriNodes[0]);
1208 myDetectedNodeMap->ChangeMap().Add (aTriNodes[1]);
1209 myDetectedNodeMap->ChangeMap().Add (aTriNodes[2]);
1213 return Standard_True;
1217 return Standard_False;
1222 // =======================================================================
1223 // function : DumpJson
1225 // =======================================================================
1226 void Select3D_SensitivePrimitiveArray::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1228 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1229 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
1231 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPosStride)
1232 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPrimType)
1233 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIndexLower)
1234 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIndexUpper)
1235 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPatchSizeMax)
1236 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPatchDistance)
1237 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIs3d)
1238 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myInitLocation)
1239 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
1241 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthElem)
1242 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthNode)
1243 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthEdge)
1245 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedElem)
1246 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedNode)
1247 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedEdgeNode1)
1248 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedEdgeNode2)
1249 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectElem)
1250 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectNode)
1251 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectEdge)