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