0032337: Visualization - rename Overlaps() method in selection to more self-describab...
[occt.git] / src / Select3D / Select3D_SensitivePrimitiveArray.cxx
1 // Created on: 2016-02-20
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2016 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Select3D_SensitivePrimitiveArray.hxx>
17
18 #include <OSD_Parallel.hxx>
19 #include <Standard_Atomic.hxx>
20
21 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
22
23 namespace
24 {
25
26   //! Auxiliary converter.
27   static inline gp_Pnt vecToPnt (const Graphic3d_Vec3& theVec)
28   {
29     return gp_Pnt (theVec.x(), theVec.y(), theVec.z());
30   }
31
32   //! Auxiliary converter.
33   static inline gp_Pnt vecToPnt (const Graphic3d_Vec2& theVec)
34   {
35     return gp_Pnt (theVec.x(), theVec.y(), 0.0);
36   }
37
38
39   //! Auxiliary function to find shared node between two triangles.
40   static inline bool hasSharedNode (const Standard_Integer* theTri1,
41                                     const Standard_Integer* theTri2)
42   {
43     return theTri1[0] == theTri2[0]
44         || theTri1[1] == theTri2[0]
45         || theTri1[2] == theTri2[0]
46         || theTri1[0] == theTri2[1]
47         || theTri1[1] == theTri2[1]
48         || theTri1[2] == theTri2[1]
49         || theTri1[0] == theTri2[2]
50         || theTri1[1] == theTri2[2]
51         || theTri1[2] == theTri2[2];
52   }
53
54   //! Fill in the triangle nodes indices.
55   static inline void getTriIndices (const Handle(Graphic3d_IndexBuffer)& theIndices,
56                                     const Standard_Integer theIndexOffset,
57                                     Standard_Integer* theNodes)
58   {
59     if (!theIndices.IsNull())
60     {
61       theNodes[0] = theIndices->Index (theIndexOffset + 0);
62       theNodes[1] = theIndices->Index (theIndexOffset + 1);
63       theNodes[2] = theIndices->Index (theIndexOffset + 2);
64     }
65     else
66     {
67       theNodes[0] = theIndexOffset + 0;
68       theNodes[1] = theIndexOffset + 1;
69       theNodes[2] = theIndexOffset + 2;
70     }
71   }
72
73 }
74
75 //! Functor for initializing groups in parallel threads.
76 struct Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray_InitFunctor
77 {
78   Select3D_SensitivePrimitiveArray_InitFunctor (Select3D_SensitivePrimitiveArray& thePrimArray,
79                                                 Standard_Integer theDivStep,
80                                                 Standard_Boolean theToEvalMinMax)
81   : myPrimArray (thePrimArray),
82     myDivStep (theDivStep),
83     myToEvalMinMax (theToEvalMinMax),
84     myToComputeBvh (Standard_True),
85     myNbFailures (0) {}
86   void operator()(const Standard_Integer& theIndex) const
87   {
88     Handle(Select3D_SensitivePrimitiveArray)& anEntity = myPrimArray.myGroups->ChangeValue (theIndex);
89     const Standard_Integer aLower  = myPrimArray.myIndexLower + theIndex * myDivStep;
90     const Standard_Integer anUpper = Min (aLower + myDivStep - 1, myPrimArray.myIndexUpper);
91     anEntity = new Select3D_SensitivePrimitiveArray (myPrimArray.myOwnerId);
92     anEntity->SetPatchSizeMax     (myPrimArray.myPatchSizeMax);
93     anEntity->SetPatchDistance    (myPrimArray.myPatchDistance);
94     anEntity->SetDetectElements   (myPrimArray.myToDetectElem);
95     anEntity->SetDetectElementMap (myPrimArray.ToDetectElementMap());
96     anEntity->SetDetectNodes      (myPrimArray.myToDetectNode);
97     anEntity->SetDetectNodeMap    (myPrimArray.ToDetectNodeMap());
98     anEntity->SetSensitivityFactor(myPrimArray.SensitivityFactor());
99     switch (myPrimArray.myPrimType)
100     {
101       case Graphic3d_TOPA_POINTS:
102       {
103         if (!anEntity->InitPoints (myPrimArray.myVerts, myPrimArray.myIndices, myPrimArray.myInitLocation, aLower, anUpper, myToEvalMinMax, 1))
104         {
105           Standard_Atomic_Increment (&myNbFailures);
106           return;
107         }
108         break;
109       }
110       case Graphic3d_TOPA_TRIANGLES:
111       {
112         if (!anEntity->InitTriangulation (myPrimArray.myVerts, myPrimArray.myIndices, myPrimArray.myInitLocation, aLower, anUpper, myToEvalMinMax, 1))
113         {
114           Standard_Atomic_Increment (&myNbFailures);
115           return;
116         }
117         break;
118       }
119       default:
120       {
121         Standard_Atomic_Increment (&myNbFailures);
122         return;
123       }
124     }
125
126     if (myToComputeBvh)
127     {
128       anEntity->BVH();
129     }
130   }
131   Standard_Boolean IsDone() const { return myNbFailures == 0; }
132 private:
133   Select3D_SensitivePrimitiveArray_InitFunctor operator= (Select3D_SensitivePrimitiveArray_InitFunctor& );
134 private:
135   Select3D_SensitivePrimitiveArray& myPrimArray;
136   Standard_Integer                  myDivStep;
137   Standard_Boolean                  myToEvalMinMax;
138   Standard_Boolean                  myToComputeBvh;
139   mutable volatile Standard_Integer myNbFailures;
140 };
141
142 //! Functor for computing BVH in parallel threads.
143 struct Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray_BVHFunctor
144 {
145   Select3D_SensitivePrimitiveArray_BVHFunctor (NCollection_Array1<Handle(Select3D_SensitivePrimitiveArray)>& theGroups) : myGroups (theGroups) {}
146   void operator()(const Standard_Integer& theIndex) const { myGroups.ChangeValue (theIndex)->BVH(); }
147 private:
148   Select3D_SensitivePrimitiveArray_BVHFunctor operator= (Select3D_SensitivePrimitiveArray_BVHFunctor& );
149 private:
150   NCollection_Array1<Handle(Select3D_SensitivePrimitiveArray)>& myGroups;
151 };
152
153 // =======================================================================
154 // function : Select3D_SensitivePrimitiveArray
155 // purpose  :
156 // =======================================================================
157 Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray (const Handle(SelectMgr_EntityOwner)& theOwnerId)
158 : Select3D_SensitiveSet (theOwnerId),
159   myPosData (NULL),
160   myPosStride (Standard_Size(-1)),
161   myPrimType (Graphic3d_TOPA_UNDEFINED),
162   myIndexLower (0),
163   myIndexUpper (0),
164   myPatchSizeMax (1),
165   myPatchDistance (ShortRealLast()),
166   myIs3d (false),
167   myBvhIndices (Graphic3d_Buffer::DefaultAllocator()),
168   myMinDepthElem (RealLast()),
169   myMinDepthNode (RealLast()),
170   myMinDepthEdge (RealLast()),
171   myDetectedElem (-1),
172   myDetectedNode (-1),
173   myDetectedEdgeNode1 (-1),
174   myDetectedEdgeNode2 (-1),
175   myToDetectElem (true),
176   myToDetectNode (false),
177   myToDetectEdge (false)
178 {
179   //
180 }
181
182 // =======================================================================
183 // function : SetDetectElementMap
184 // purpose  :
185 // =======================================================================
186 void Select3D_SensitivePrimitiveArray::SetDetectElementMap (bool theToDetect)
187 {
188   if (!theToDetect)
189   {
190     myDetectedElemMap.Nullify();
191     return;
192   }
193
194   if (myDetectedElemMap.IsNull())
195   {
196     myDetectedElemMap = new TColStd_HPackedMapOfInteger();
197   }
198   else
199   {
200     myDetectedElemMap->ChangeMap().Clear();
201   }
202 }
203
204 // =======================================================================
205 // function : SetDetectNodeMap
206 // purpose  :
207 // =======================================================================
208 void Select3D_SensitivePrimitiveArray::SetDetectNodeMap (bool theToDetect)
209 {
210   if (!theToDetect)
211   {
212     myDetectedNodeMap.Nullify();
213     return;
214   }
215
216   if (myDetectedNodeMap.IsNull())
217   {
218     myDetectedNodeMap = new TColStd_HPackedMapOfInteger();
219   }
220   else
221   {
222     myDetectedNodeMap->ChangeMap().Clear();
223   }
224 }
225
226 // =======================================================================
227 // function : InitTriangulation
228 // purpose  :
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)
237 {
238   MarkDirty();
239   myGroups.Nullify();
240   myPrimType = Graphic3d_TOPA_TRIANGLES;
241   myBndBox.Clear();
242   myVerts.Nullify();
243   myIndices.Nullify();
244   myIndexLower = 0;
245   myIndexUpper = 0;
246   myPosData = NULL;
247   myPosStride = Standard_Size(-1);
248   myBvhIndices.release();
249   myIs3d = false;
250   myInitLocation = theInitLoc;
251   myCDG3D.SetCoord (0.0, 0.0, 0.0);
252   if (theVerts.IsNull()
253    || theVerts->NbElements == 0)
254   {
255     return false;
256   }
257
258   Standard_Integer aPosAttribIndex = 0;
259   myPosData = theVerts->AttributeData (Graphic3d_TOA_POS, aPosAttribIndex, myPosStride);
260   if (myPosData == NULL)
261   {
262     return false;
263   }
264
265   const Graphic3d_Attribute& anAttrib = theVerts->Attribute (aPosAttribIndex);
266   myIs3d = anAttrib.DataType == Graphic3d_TOD_VEC3
267         || anAttrib.DataType == Graphic3d_TOD_VEC4;
268   if (!myIs3d && anAttrib.DataType != Graphic3d_TOD_VEC2)
269   {
270     myPosData = NULL;
271     return false;
272   }
273
274   if (!theIndices.IsNull())
275   {
276     if (theIndexLower < 0
277      || theIndexUpper >= theIndices->NbElements
278      || theIndices->NbElements == 0)
279     {
280       return false;
281     }
282   }
283   else
284   {
285     if (theIndexLower < 0
286      || theIndexUpper >= theVerts->NbElements)
287     {
288       return false;
289     }
290   }
291
292   Standard_Integer aTriFrom = theIndexLower / 3;
293   Standard_Integer aNbTris  = (theIndexUpper - theIndexLower + 1) / 3;
294   const bool hasGroups = (theNbGroups > 1) && (aNbTris / theNbGroups > 10);
295   if (aNbTris < 1)
296   {
297     return false;
298   }
299   if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbTris, !hasGroups && myPatchSizeMax > 1))
300   {
301     return false;
302   }
303
304   myVerts      = theVerts;
305   myIndices    = theIndices;
306   myIndexLower = theIndexLower;
307   myIndexUpper = theIndexUpper;
308   myInvInitLocation = myInitLocation.Transformation().Inverted();
309   if (hasGroups)
310   {
311     myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
312     const Standard_Integer aDivStep = (aNbTris / theNbGroups) * 3;
313     Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
314     OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
315     if (!anInitFunctor.IsDone())
316     {
317       return false;
318     }
319     for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
320     {
321       Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
322       myBndBox.Combine (anEntity->BoundingBox());
323       myBvhIndices.SetIndex (aGroupIter, aGroupIter);
324       myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
325     }
326     myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
327     if (theToEvalMinMax)
328     {
329       computeBoundingBox();
330     }
331     return true;
332   }
333
334   Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
335   Standard_Integer  aTriNodes1[3] = { -1, -1, -1 };
336   Standard_Integer  aTriNodes2[3] = { -1, -1, -1 };
337   Standard_Integer* aTriNodesPrev = aTriNodes1;
338   Standard_Integer* aTriNodes     = aTriNodes2;
339   Standard_Integer  aPatchFrom    = 0;
340   Standard_Integer  aPatchSize    = 0;
341   if (myBvhIndices.HasPatches())
342   {
343     myBvhIndices.NbElements = 0;
344   }
345   for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
346   {
347     const Standard_Integer anIndexOffset = (aTriFrom + aTriIter) * 3;
348     getTriIndices (myIndices, anIndexOffset, aTriNodes);
349     if (myIs3d)
350     {
351       const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
352       const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
353       const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
354       aCenter += (aNode1 + aNode2 + aNode3) / 3.0;
355     }
356     else
357     {
358       const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
359       const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
360       const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
361       aCenter += Graphic3d_Vec3((aNode1 + aNode2 + aNode3) / 3.0);
362     }
363     if (myBvhIndices.HasPatches())
364     {
365       std::swap (aTriNodes, aTriNodesPrev);
366       if (aPatchSize < myPatchSizeMax
367        && hasSharedNode (aTriNodes, aTriNodesPrev))
368       {
369         ++aPatchSize;
370         continue;
371       }
372       else
373       {
374         myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
375         aPatchFrom = aTriIter;
376         aPatchSize = 0;
377       }
378     }
379     else
380     {
381       myBvhIndices.SetIndex (aTriIter, aTriFrom + aTriIter);
382     }
383   }
384   if (aPatchSize != 0)
385   {
386     myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
387   }
388   aCenter /= float(aNbTris);
389
390   myCDG3D = vecToPnt (aCenter);
391   if (theToEvalMinMax)
392   {
393     computeBoundingBox();
394   }
395   return true;
396 }
397
398 // =======================================================================
399 // function : InitPoints
400 // purpose  :
401 // =======================================================================
402 bool Select3D_SensitivePrimitiveArray::InitPoints (const Handle(Graphic3d_Buffer)&      theVerts,
403                                                    const Handle(Graphic3d_IndexBuffer)& theIndices,
404                                                    const TopLoc_Location&               theInitLoc,
405                                                    const Standard_Integer               theIndexLower,
406                                                    const Standard_Integer               theIndexUpper,
407                                                    const bool                           theToEvalMinMax,
408                                                    const Standard_Integer               theNbGroups)
409 {
410   MarkDirty();
411   myGroups.Nullify();
412   myPrimType = Graphic3d_TOPA_POINTS;
413   myBndBox.Clear();
414   myVerts.Nullify();
415   myIndices.Nullify();
416   myIndexLower = 0;
417   myIndexUpper = 0;
418   myPosData = NULL;
419   myPosStride = Standard_Size(-1);
420   myBvhIndices.release();
421   myIs3d = false;
422   myInitLocation = theInitLoc;
423   if (theVerts.IsNull()
424    || theVerts->NbElements == 0)
425   {
426     return false;
427   }
428
429   Standard_Integer aPosAttribIndex = 0;
430   myPosData = theVerts->AttributeData (Graphic3d_TOA_POS, aPosAttribIndex, myPosStride);
431   if (myPosData == NULL)
432   {
433     return false;
434   }
435
436   const Graphic3d_Attribute& anAttrib = theVerts->Attribute (aPosAttribIndex);
437   myIs3d = anAttrib.DataType == Graphic3d_TOD_VEC3
438         || anAttrib.DataType == Graphic3d_TOD_VEC4;
439   if (!myIs3d && anAttrib.DataType != Graphic3d_TOD_VEC2)
440   {
441     myPosData = NULL;
442     return false;
443   }
444
445   if (!theIndices.IsNull())
446   {
447     if (theIndexLower < 0
448      || theIndexUpper >= theIndices->NbElements
449      || theIndices->NbElements == 0)
450     {
451       return false;
452     }
453   }
454   else
455   {
456     if (theIndexLower < 0
457      || theIndexUpper >= theVerts->NbElements)
458     {
459       return false;
460     }
461   }
462
463   const Standard_Integer aNbPoints = theIndexUpper - theIndexLower + 1;
464   const bool hasGroups = (theNbGroups > 1) && (aNbPoints / theNbGroups > 10);
465   if (aNbPoints < 1)
466   {
467     return false;
468   }
469   if (!myBvhIndices.Init (hasGroups ? theNbGroups : aNbPoints, !hasGroups && myPatchSizeMax > 1))
470   {
471     return false;
472   }
473
474   myVerts      = theVerts;
475   myIndices    = theIndices;
476   myIndexLower = theIndexLower;
477   myIndexUpper = theIndexUpper;
478   myInvInitLocation = myInitLocation.Transformation().Inverted();
479   if (hasGroups)
480   {
481     myGroups = new Select3D_PrimArraySubGroupArray (0, theNbGroups - 1);
482     const Standard_Integer aDivStep = aNbPoints / theNbGroups;
483     Select3D_SensitivePrimitiveArray_InitFunctor anInitFunctor (*this, aDivStep, theToEvalMinMax);
484     OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, anInitFunctor);
485     if (!anInitFunctor.IsDone())
486     {
487       return false;
488     }
489     for (Standard_Integer aGroupIter = 0; aGroupIter < theNbGroups; ++aGroupIter)
490     {
491       Handle(Select3D_SensitivePrimitiveArray)& anEntity = myGroups->ChangeValue (aGroupIter);
492       myBndBox.Combine (anEntity->BoundingBox());
493       myBvhIndices.SetIndex (aGroupIter, aGroupIter);
494       myCDG3D.ChangeCoord() += anEntity->CenterOfGeometry().XYZ();
495     }
496     myCDG3D.ChangeCoord().Divide (static_cast<Standard_Real> (myGroups->Size()));
497     if (theToEvalMinMax)
498     {
499       computeBoundingBox();
500     }
501     return true;
502   }
503
504   Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
505   Standard_Integer aPatchFrom = 0;
506   Standard_Integer aPatchSize = 0;
507   if (myBvhIndices.HasPatches())
508   {
509     myBvhIndices.NbElements = 0;
510   }
511   const float aPatchSize2 = myPatchDistance < ShortRealLast()
512                           ? myPatchDistance * myPatchDistance
513                           : myPatchDistance;
514   const Graphic3d_Vec3* aPnt3dPrev = NULL;
515   const Graphic3d_Vec3* aPnt3d     = NULL;
516   const Graphic3d_Vec2* aPnt2dPrev = NULL;
517   const Graphic3d_Vec2* aPnt2d     = NULL;
518   for (Standard_Integer aPointIter = 0; aPointIter < aNbPoints; ++aPointIter)
519   {
520     const Standard_Integer anIndexOffset = (theIndexLower + aPointIter);
521     const Standard_Integer aPointIndex   = !myIndices.IsNull()
522                                           ? myIndices->Index (anIndexOffset)
523                                           : anIndexOffset;
524     if (myIs3d)
525     {
526       aPnt3d = &getPosVec3 (aPointIndex);
527       aCenter += *aPnt3d;
528     }
529     else
530     {
531       aPnt2d = &getPosVec2 (aPointIndex);
532       aCenter += Graphic3d_Vec3(*aPnt2d);
533     }
534
535     if (myBvhIndices.HasPatches())
536     {
537       if (myIs3d)
538       {
539         std::swap (aPnt3d, aPnt3dPrev);
540         if (aPatchSize < myPatchSizeMax
541          && aPnt3d != NULL
542          && (*aPnt3dPrev - *aPnt3d).SquareModulus() < aPatchSize2)
543         {
544           ++aPatchSize;
545           continue;
546         }
547       }
548       else
549       {
550         std::swap (aPnt2d, aPnt2dPrev);
551         if (aPatchSize < myPatchSizeMax
552          && aPnt2d != NULL
553          && (*aPnt2dPrev - *aPnt2d).SquareModulus() < aPatchSize2)
554         {
555           ++aPatchSize;
556           continue;
557         }
558       }
559
560       myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom,
561                               aPatchSize != 0 ? aPatchSize : 1);
562       aPatchFrom = aPointIter;
563       aPatchSize = 0;
564     }
565     else
566     {
567       myBvhIndices.SetIndex (aPointIter, theIndexLower + aPointIter);
568     }
569   }
570   if (aPatchSize != 0)
571   {
572     myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom, aPatchSize);
573   }
574   aCenter /= float(aNbPoints);
575
576   myCDG3D = vecToPnt (aCenter);
577   if (theToEvalMinMax)
578   {
579     computeBoundingBox();
580   }
581   return true;
582 }
583
584 // =======================================================================
585 // function : GetConnected
586 // purpose  :
587 // =======================================================================
588 Handle(Select3D_SensitiveEntity) Select3D_SensitivePrimitiveArray::GetConnected()
589 {
590   Handle(Select3D_SensitivePrimitiveArray) aNewEntity = new Select3D_SensitivePrimitiveArray (myOwnerId);
591   switch (myPrimType)
592   {
593     case Graphic3d_TOPA_POINTS:
594     {
595       aNewEntity->InitPoints        (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
596       break;
597     }
598     case Graphic3d_TOPA_TRIANGLES:
599     {
600       aNewEntity->InitTriangulation (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper, true, !myGroups.IsNull() ? myGroups->Size() : 1);
601       break;
602     }
603     default: break;
604   }
605   return aNewEntity;
606 }
607
608 //=======================================================================
609 //function : Set
610 //purpose  :
611 //=======================================================================
612 void Select3D_SensitivePrimitiveArray::Set (const Handle(SelectMgr_EntityOwner)& theOwnerId)
613 {
614   base_type::Set (theOwnerId);
615   if (!myGroups.IsNull())
616   {
617     for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
618     {
619       aGroupIter.Value()->Set (theOwnerId);
620     }
621   }
622 }
623
624 // =======================================================================
625 // function : BVH
626 // purpose  :
627 // =======================================================================
628 void Select3D_SensitivePrimitiveArray::BVH()
629 {
630   if (!myContent.IsDirty())
631   {
632     return;
633   }
634
635   base_type::BVH();
636   if (myGroups.IsNull())
637   {
638     return;
639   }
640
641   Standard_Integer aNbToUpdate = 0;
642   for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
643   {
644     if (aGroupIter.Value()->myContent.IsDirty())
645     {
646       ++aNbToUpdate;
647     }
648   }
649
650   if (aNbToUpdate > 0)
651   {
652     Select3D_SensitivePrimitiveArray_BVHFunctor aFunctor (*myGroups);
653     OSD_Parallel::For (myGroups->Lower(), myGroups->Upper() + 1, aFunctor, aNbToUpdate <= 1);
654   }
655 }
656
657 // =======================================================================
658 // function : Size
659 // purpose  :
660 // =======================================================================
661 Standard_Integer Select3D_SensitivePrimitiveArray::Size() const
662 {
663   return myBvhIndices.NbElements;
664 }
665
666 // =======================================================================
667 // function : Box
668 // purpose  :
669 // =======================================================================
670 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::Box (const Standard_Integer theIdx) const
671 {
672   const Standard_Integer anElemIdx  = myBvhIndices.Index (theIdx);
673   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theIdx);
674   if (!myGroups.IsNull())
675   {
676     return myGroups->Value (anElemIdx)->BoundingBox();
677   }
678
679   Select3D_BndBox3d aBox;
680   switch (myPrimType)
681   {
682     case Graphic3d_TOPA_POINTS:
683     {
684       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
685       {
686         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
687         const Standard_Integer aPointIndex   = !myIndices.IsNull()
688                                              ?  myIndices->Index (anIndexOffset)
689                                              :  anIndexOffset;
690         if (myIs3d)
691         {
692           const Graphic3d_Vec3& aPoint = getPosVec3 (aPointIndex);
693           aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), aPoint.z()));
694         }
695         else
696         {
697           const Graphic3d_Vec2& aPoint = getPosVec2 (aPointIndex);
698           aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), 0.0));
699         }
700       }
701       break;
702     }
703     case Graphic3d_TOPA_TRIANGLES:
704     {
705       Standard_Integer aTriNodes[3];
706       if (myIs3d)
707       {
708         for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
709         {
710           const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
711           getTriIndices (myIndices, anIndexOffset, aTriNodes);
712           const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
713           const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
714           const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
715           Graphic3d_Vec3 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
716           Graphic3d_Vec3 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
717           aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), aMinPnt.z()));
718           aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), aMaxPnt.z()));
719         }
720       }
721       else
722       {
723         for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
724         {
725           const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
726           getTriIndices (myIndices, anIndexOffset, aTriNodes);
727           const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
728           const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
729           const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
730           Graphic3d_Vec2 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
731           Graphic3d_Vec2 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
732           aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), 0.0));
733           aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), 0.0));
734         }
735       }
736       break;
737     }
738     default:
739     {
740       return aBox;
741     }
742   }
743   return aBox;
744 }
745
746 // =======================================================================
747 // function : Center
748 // purpose  :
749 // =======================================================================
750 Standard_Real Select3D_SensitivePrimitiveArray::Center (const Standard_Integer theIdx,
751                                                         const Standard_Integer theAxis) const
752 {
753   if (!myGroups.IsNull())
754   {
755     const Standard_Integer anElemIdx = myBvhIndices.Index (theIdx);
756     const gp_Pnt aCenter = myGroups->Value (anElemIdx)->CenterOfGeometry();
757     return theAxis == 0 ? aCenter.X() : (theAxis == 1 ? aCenter.Y() : aCenter.Z());
758   }
759
760   const Select3D_BndBox3d& aBox = Box (theIdx);
761   SelectMgr_Vec3 aCenter = (aBox.CornerMin() + aBox.CornerMax()) * 0.5;
762   return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
763 }
764
765 // =======================================================================
766 // function : Swap
767 // purpose  :
768 // =======================================================================
769 void Select3D_SensitivePrimitiveArray::Swap (const Standard_Integer theIdx1,
770                                              const Standard_Integer theIdx2)
771 {
772   Standard_Integer anElemIdx1 = myBvhIndices.Index (theIdx1);
773   Standard_Integer anElemIdx2 = myBvhIndices.Index (theIdx2);
774   if (myBvhIndices.HasPatches())
775   {
776     Standard_Integer aPatchSize1 = myBvhIndices.PatchSize (theIdx1);
777     Standard_Integer aPatchSize2 = myBvhIndices.PatchSize (theIdx2);
778     myBvhIndices.SetIndex (theIdx1, anElemIdx2, aPatchSize2);
779     myBvhIndices.SetIndex (theIdx2, anElemIdx1, aPatchSize1);
780   }
781   else
782   {
783     myBvhIndices.SetIndex (theIdx1, anElemIdx2);
784     myBvhIndices.SetIndex (theIdx2, anElemIdx1);
785   }
786 }
787
788 // =======================================================================
789 // function : BoundingBox
790 // purpose  :
791 // =======================================================================
792 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::BoundingBox()
793 {
794   if (!myBndBox.IsValid())
795   {
796     computeBoundingBox();
797   }
798   return applyTransformation();
799 }
800
801 // =======================================================================
802 // function : computeBoundingBox
803 // purpose  :
804 // =======================================================================
805 void Select3D_SensitivePrimitiveArray::computeBoundingBox()
806 {
807   myBndBox.Clear();
808   if (!myGroups.IsNull())
809   {
810     for (Select3D_PrimArraySubGroupArray::Iterator aGroupIter (*myGroups); aGroupIter.More(); aGroupIter.Next())
811     {
812       myBndBox.Combine (aGroupIter.Value()->BoundingBox());
813     }
814     return;
815   }
816
817   if (myVerts.IsNull())
818   {
819     return;
820   }
821
822   const Standard_Integer aNbVerts = myVerts->NbElements;
823   if (myIs3d)
824   {
825     for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
826     {
827       const Graphic3d_Vec3& aVert = getPosVec3 (aVertIter);
828       myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), aVert.z()));
829     }
830   }
831   else
832   {
833     for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
834     {
835       const Graphic3d_Vec2& aVert = getPosVec2 (aVertIter);
836       myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), 0.0));
837     }
838   }
839 }
840
841 // =======================================================================
842 // function : applyTransformation
843 // purpose  :
844 // =======================================================================
845 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::applyTransformation()
846 {
847   if (!HasInitLocation())
848   {
849     return myBndBox;
850   }
851
852   Select3D_BndBox3d aBndBox;
853   for (Standard_Integer aX = 0; aX <=1; ++aX)
854   {
855     for (Standard_Integer aY = 0; aY <=1; ++aY)
856     {
857       for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
858       {
859         gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
860                                  aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
861                                  aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
862         aVertex.Transform (myInitLocation.Transformation());
863         aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
864       }
865     }
866   }
867   return aBndBox;
868 }
869
870 // =======================================================================
871 // function : Matches
872 // purpose  :
873 // =======================================================================
874 Standard_Boolean Select3D_SensitivePrimitiveArray::Matches (SelectBasics_SelectingVolumeManager& theMgr,
875                                                             SelectBasics_PickResult& thePickResult)
876 {
877   if (!myDetectedElemMap.IsNull())
878   {
879     myDetectedElemMap->ChangeMap().Clear();
880   }
881   if (!myDetectedNodeMap.IsNull())
882   {
883     myDetectedNodeMap->ChangeMap().Clear();
884   }
885   myMinDepthElem      = RealLast();
886   myMinDepthNode      = RealLast();
887   myMinDepthEdge      = RealLast();
888   myDetectedElem      = -1;
889   myDetectedNode      = -1;
890   myDetectedEdgeNode1 = -1;
891   myDetectedEdgeNode2 = -1;
892   const bool toDetectRange = !myDetectedElemMap.IsNull() || !myDetectedNodeMap.IsNull();
893   if (myGroups.IsNull()
894    || theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Point
895    || !toDetectRange)
896   {
897     if (!matches (theMgr, thePickResult, toDetectRange))
898     {
899       return Standard_False;
900     }
901
902     if (!myGroups.IsNull() && myDetectedIdx != -1)
903     {
904       const Standard_Integer anIndex = myBvhIndices.Index (myDetectedIdx);
905       const Handle(Select3D_SensitivePrimitiveArray)& aLastGroup = myGroups->Value (anIndex);
906       myMinDepthElem      = aLastGroup->myMinDepthElem;
907       myMinDepthNode      = aLastGroup->myMinDepthNode;
908       myMinDepthEdge      = aLastGroup->myMinDepthEdge;
909       myDetectedElem      = aLastGroup->myDetectedElem;
910       myDetectedNode      = aLastGroup->myDetectedNode;
911       myDetectedEdgeNode1 = aLastGroup->myDetectedEdgeNode1;
912       myDetectedEdgeNode2 = aLastGroup->myDetectedEdgeNode2;
913     }
914     return Standard_True;
915   }
916
917   SelectBasics_PickResult aPickResult;
918   bool hasResults = false;
919   for (Standard_Integer aGroupIter = 0; aGroupIter < myBvhIndices.NbElements; ++aGroupIter)
920   {
921     const Standard_Integer anElemIdx = myBvhIndices.Index (aGroupIter);
922     Handle(Select3D_SensitivePrimitiveArray)& aChild = myGroups->ChangeValue (anElemIdx);
923     if (aChild->Matches (theMgr, aPickResult))
924     {
925       hasResults = true;
926       if (!myDetectedElemMap.IsNull())
927       {
928         myDetectedElemMap->ChangeMap().Unite (aChild->myDetectedElemMap->Map());
929       }
930       if (!myDetectedNodeMap.IsNull())
931       {
932         myDetectedNodeMap->ChangeMap().Unite (aChild->myDetectedNodeMap->Map());
933       }
934       if (thePickResult.Depth() > aPickResult.Depth())
935       {
936         myDetectedIdx = aGroupIter;
937         thePickResult = aPickResult;
938       }
939     }
940   }
941   if (!hasResults)
942   {
943     return Standard_False;
944   }
945   thePickResult.SetDistToGeomCenter(theMgr.DistToGeometryCenter(CenterOfGeometry()));
946   return Standard_True;
947 }
948
949 // =======================================================================
950 // function : overlapsElement
951 // purpose  :
952 // =======================================================================
953 Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_PickResult& thePickResult,
954                                                                     SelectBasics_SelectingVolumeManager& theMgr,
955                                                                     Standard_Integer theElemIdx,
956                                                                     Standard_Boolean theIsFullInside)
957 {
958   const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
959   if (!myGroups.IsNull())
960   {
961     return myGroups->Value (anElemIdx)->Matches (theMgr, thePickResult);
962   }
963
964   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
965   Select3D_BndBox3d aBox;
966   Standard_Boolean aResult = Standard_False;
967   SelectBasics_PickResult aPickResult;
968   switch (myPrimType)
969   {
970     case Graphic3d_TOPA_POINTS:
971     {
972       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
973       {
974         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
975         const Standard_Integer aPointIndex   = !myIndices.IsNull()
976                                              ?  myIndices->Index (anIndexOffset)
977                                              :  anIndexOffset;
978         gp_Pnt aPoint;
979         if (myIs3d)
980         {
981           aPoint = vecToPnt (getPosVec3 (aPointIndex));
982         }
983         else
984         {
985           aPoint = vecToPnt (getPosVec2 (aPointIndex));
986         }
987
988         if (myToDetectNode
989          || myToDetectElem)
990         {
991           if (theIsFullInside || theMgr.OverlapsPoint (aPoint, aPickResult))
992           {
993             if (aPickResult.Depth() <= myMinDepthNode)
994             {
995               myDetectedElem = myDetectedNode = aPointIndex;
996               myMinDepthElem = myMinDepthNode = aPickResult.Depth();
997             }
998             if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
999             {
1000               if (!myDetectedElemMap.IsNull())
1001               {
1002                 myDetectedElemMap->ChangeMap().Add (aPointIndex);
1003               }
1004               if (!myDetectedNodeMap.IsNull())
1005               {
1006                 myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1007               }
1008             }
1009             aResult = Standard_True;
1010           }
1011         }
1012         thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1013       }
1014       break;
1015     }
1016     case Graphic3d_TOPA_TRIANGLES:
1017     {
1018       Graphic3d_Vec3i aTriNodes;
1019       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1020       {
1021         const Standard_Integer aTriIndex     = anElemIdx + anElemIter;
1022         const Standard_Integer anIndexOffset = aTriIndex * 3;
1023         getTriIndices (myIndices, anIndexOffset, aTriNodes);
1024         gp_Pnt aPnts[3];
1025         if (myIs3d)
1026         {
1027           aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1028           aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1029           aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1030         }
1031         else
1032         {
1033           aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1034           aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1035           aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1036         }
1037
1038         if (myToDetectElem)
1039         {
1040           if (theIsFullInside || theMgr.OverlapsTriangle (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aPickResult))
1041           {
1042             if (aPickResult.Depth() <= myMinDepthElem)
1043             {
1044               myDetectedElem = aTriIndex;
1045               myMinDepthElem = aPickResult.Depth();
1046             }
1047             aResult = Standard_True;
1048             if (!myDetectedElemMap.IsNull()
1049               && theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
1050             {
1051               myDetectedElemMap->ChangeMap().Add(aTriIndex);
1052             }
1053           }
1054         }
1055         if (myToDetectNode)
1056         {
1057           for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1058           {
1059             if (theIsFullInside || theMgr.OverlapsPoint (aPnts[aNodeIter], aPickResult))
1060             {
1061               if (aPickResult.Depth() <= myMinDepthNode)
1062               {
1063                 myDetectedNode = aTriNodes[aNodeIter];
1064                 myMinDepthNode = aPickResult.Depth();
1065               }
1066               if (!myDetectedNodeMap.IsNull()
1067                 && theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
1068               {
1069                 myDetectedNodeMap->ChangeMap().Add (aTriNodes[aNodeIter]);
1070               }
1071               aResult = Standard_True;
1072             }
1073           }
1074         }
1075         if (myToDetectEdge)
1076         {
1077           for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
1078           {
1079             int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
1080             int aNode2 = aNodeIter;
1081             if (theIsFullInside || theMgr.OverlapsSegment (aPnts[aNode1], aPnts[aNode2], aPickResult))
1082             {
1083               if (aPickResult.Depth() <= myMinDepthEdge)
1084               {
1085                 myDetectedEdgeNode1 = aTriNodes[aNode1];
1086                 myDetectedEdgeNode2 = aTriNodes[aNode2];
1087                 myMinDepthEdge = aPickResult.Depth();
1088               }
1089               aResult = Standard_True;
1090             }
1091           }
1092         }
1093         thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
1094       }
1095       break;
1096     }
1097     default:
1098     {
1099       return Standard_False;
1100     }
1101   }
1102
1103   return aResult;
1104 }
1105
1106 // =======================================================================
1107 // function : distanceToCOG
1108 // purpose  :
1109 // =======================================================================
1110 Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
1111 {
1112   return theMgr.DistToGeometryCenter (myCDG3D);
1113 }
1114
1115 // =======================================================================
1116 // function : elementIsInside
1117 // purpose  :
1118 // =======================================================================
1119 Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
1120                                                                     Standard_Integer theElemIdx,
1121                                                                     Standard_Boolean theIsFullInside)
1122 {
1123   const Standard_Integer anElemIdx = myBvhIndices.Index (theElemIdx);
1124   if (!myGroups.IsNull())
1125   {
1126     SelectBasics_PickResult aDummy;
1127     return myGroups->Value (anElemIdx)->Matches (theMgr, aDummy);
1128   }
1129
1130   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
1131   switch (myPrimType)
1132   {
1133     case Graphic3d_TOPA_POINTS:
1134     {
1135       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1136       {
1137         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
1138         const Standard_Integer aPointIndex   = !myIndices.IsNull()
1139                                              ?  myIndices->Index (anIndexOffset)
1140                                              :  anIndexOffset;
1141         gp_Pnt aPoint;
1142         if (myIs3d)
1143         {
1144           aPoint = vecToPnt (getPosVec3 (aPointIndex));
1145         }
1146         else
1147         {
1148           aPoint = vecToPnt (getPosVec2 (aPointIndex));
1149         }
1150         if (!theIsFullInside && !theMgr.OverlapsPoint (aPoint))
1151         {
1152           return Standard_False;
1153         }
1154
1155         if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
1156         {
1157           if (!myDetectedElemMap.IsNull())
1158           {
1159             myDetectedElemMap->ChangeMap().Add (aPointIndex);
1160           }
1161           if (!myDetectedNodeMap.IsNull())
1162           {
1163             myDetectedNodeMap->ChangeMap().Add (aPointIndex);
1164           }
1165         }
1166       }
1167       return Standard_True;
1168     }
1169     case Graphic3d_TOPA_TRIANGLES:
1170     {
1171       Graphic3d_Vec3i aTriNodes;
1172       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
1173       {
1174         const Standard_Integer aTriIndex     = anElemIdx + anElemIter;
1175         const Standard_Integer anIndexOffset = aTriIndex * 3;
1176         getTriIndices (myIndices, anIndexOffset, aTriNodes);
1177         gp_Pnt aPnts[3];
1178         if (myIs3d)
1179         {
1180           aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
1181           aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
1182           aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
1183         }
1184         else
1185         {
1186           aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
1187           aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
1188           aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
1189         }
1190
1191         if (!theIsFullInside && (   !theMgr.OverlapsPoint (aPnts[0])
1192                                  || !theMgr.OverlapsPoint (aPnts[1])
1193                                  || !theMgr.OverlapsPoint (aPnts[2])))
1194         {
1195           return Standard_False;
1196         }
1197
1198         if (theMgr.GetActiveSelectionType() != SelectMgr_SelectionType_Point)
1199         {
1200           if (!myDetectedElemMap.IsNull())
1201           {
1202             myDetectedElemMap->ChangeMap().Add (aTriIndex);
1203           }
1204           if (!myDetectedNodeMap.IsNull())
1205           {
1206             myDetectedNodeMap->ChangeMap().Add (aTriNodes[0]);
1207             myDetectedNodeMap->ChangeMap().Add (aTriNodes[1]);
1208             myDetectedNodeMap->ChangeMap().Add (aTriNodes[2]);
1209           }
1210         }
1211       }
1212       return Standard_True;
1213     }
1214     default:
1215     {
1216       return Standard_False;
1217     }
1218   }
1219 }
1220
1221 // =======================================================================
1222 // function : DumpJson
1223 // purpose  :
1224 // =======================================================================
1225 void Select3D_SensitivePrimitiveArray::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1226 {
1227   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1228   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
1229
1230   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPosStride)
1231   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPrimType)
1232   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIndexLower)
1233   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIndexUpper)
1234   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPatchSizeMax)
1235   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPatchDistance)
1236   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIs3d)
1237   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myInitLocation)
1238   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
1239
1240   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthElem)
1241   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthNode)
1242   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinDepthEdge)
1243
1244   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedElem)
1245   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedNode)
1246   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedEdgeNode1)
1247   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDetectedEdgeNode2)
1248   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectElem)
1249   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectNode)
1250   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToDetectEdge)
1251 }