0027202: Visualization - add sensitivity Select3D_SensitivePrimitiveArray for Graphic...
[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
20 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePrimitiveArray, Select3D_SensitiveSet)
21
22 namespace
23 {
24
25   //! Auxiliary converter.
26   static inline gp_Pnt vecToPnt (const Graphic3d_Vec3& theVec)
27   {
28     return gp_Pnt (theVec.x(), theVec.y(), theVec.z());
29   }
30
31   //! Auxiliary converter.
32   static inline gp_Pnt vecToPnt (const Graphic3d_Vec2& theVec)
33   {
34     return gp_Pnt (theVec.x(), theVec.y(), 0.0);
35   }
36
37
38   //! Auxiliary function to find shared node between two triangles.
39   static inline bool hasSharedNode (const Standard_Integer* theTri1,
40                                     const Standard_Integer* theTri2)
41   {
42     return theTri1[0] == theTri2[0]
43         || theTri1[1] == theTri2[0]
44         || theTri1[2] == theTri2[0]
45         || theTri1[0] == theTri2[1]
46         || theTri1[1] == theTri2[1]
47         || theTri1[2] == theTri2[1]
48         || theTri1[0] == theTri2[2]
49         || theTri1[1] == theTri2[2]
50         || theTri1[2] == theTri2[2];
51   }
52
53   //! Fill in the triangle nodes indices.
54   static inline void getTriIndices (const Handle(Graphic3d_IndexBuffer)& theIndices,
55                                     const Standard_Integer theIndexOffset,
56                                     Standard_Integer* theNodes)
57   {
58     if (!theIndices.IsNull())
59     {
60       theNodes[0] = theIndices->Index (theIndexOffset + 0);
61       theNodes[1] = theIndices->Index (theIndexOffset + 1);
62       theNodes[2] = theIndices->Index (theIndexOffset + 2);
63     }
64     else
65     {
66       theNodes[0] = theIndexOffset + 0;
67       theNodes[1] = theIndexOffset + 1;
68       theNodes[2] = theIndexOffset + 2;
69     }
70   }
71
72 }
73
74 // =======================================================================
75 // function : Select3D_SensitivePrimitiveArray
76 // purpose  :
77 // =======================================================================
78 Select3D_SensitivePrimitiveArray::Select3D_SensitivePrimitiveArray (const Handle(SelectBasics_EntityOwner)& theOwnerId)
79 : Select3D_SensitiveSet (theOwnerId),
80   myPrimType (Graphic3d_TOPA_UNDEFINED),
81   myIndexLower (0),
82   myIndexUpper (0),
83   myPosOffset (Standard_Size(-1)),
84   myPatchSizeMax (1),
85   myPatchDistance (ShortRealLast()),
86   myIs3d (false),
87   myBvhIndices (new NCollection_AlignedAllocator(16)),
88   myMinDepthElem (RealLast()),
89   myMinDepthNode (RealLast()),
90   myMinDepthEdge (RealLast()),
91   myDetectedElem (-1),
92   myDetectedNode (-1),
93   myDetectedEdgeNode1 (-1),
94   myDetectedEdgeNode2 (-1),
95   myToDetectElem (true),
96   myToDetectNode (false),
97   myToDetectEdge (false)
98 {
99   //
100 }
101
102 // =======================================================================
103 // function : InitTriangulation
104 // purpose  :
105 // =======================================================================
106 bool Select3D_SensitivePrimitiveArray::InitTriangulation (const Handle(Graphic3d_Buffer)&      theVerts,
107                                                           const Handle(Graphic3d_IndexBuffer)& theIndices,
108                                                           const TopLoc_Location&               theInitLoc,
109                                                           const Standard_Integer               theIndexLower,
110                                                           const Standard_Integer               theIndexUpper,
111                                                           const bool                           theToEvalMinMax)
112 {
113   MarkDirty();
114   myPrimType = Graphic3d_TOPA_TRIANGLES;
115   myBndBox.Clear();
116   myVerts.Nullify();
117   myIndices.Nullify();
118   myIndexLower = 0;
119   myIndexUpper = 0;
120   myPosOffset = Standard_Size(-1);
121   myBvhIndices.release();
122   myIs3d = false;
123   myInitLocation = theInitLoc;
124   if (theVerts.IsNull()
125    || theVerts->NbElements == 0)
126   {
127     return false;
128   }
129
130   for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
131   {
132     const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
133     if (anAttrib.Id == Graphic3d_TOA_POS)
134     {
135       if (anAttrib.DataType == Graphic3d_TOD_VEC3
136        || anAttrib.DataType == Graphic3d_TOD_VEC4)
137       {
138         myIs3d = true;
139       }
140       else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
141       {
142         return false;
143       }
144
145       myPosOffset = theVerts->AttributeOffset (anAttribIter);
146       break;
147     }
148   }
149   if (myPosOffset == Standard_Size(-1))
150   {
151     return false;
152   }
153
154   if (!theIndices.IsNull())
155   {
156     if (theIndexLower < 0
157      || theIndexUpper >= theIndices->NbElements
158      || theIndices->NbElements == 0)
159     {
160       return false;
161     }
162   }
163   else
164   {
165     if (theIndexLower < 0
166      || theIndexUpper >= theVerts->NbElements)
167     {
168       return false;
169     }
170   }
171
172   Standard_Integer aTriFrom = theIndexLower / 3;
173   Standard_Integer aNbTris  = (theIndexUpper - theIndexLower + 1) / 3;
174   if (aNbTris < 1)
175   {
176     return false;
177   }
178   if (!myBvhIndices.Init (aNbTris, myPatchSizeMax > 1))
179   {
180     return false;
181   }
182
183   myVerts      = theVerts;
184   myIndices    = theIndices;
185   myIndexLower = theIndexLower;
186   myIndexUpper = theIndexUpper;
187   myInvInitLocation = myInitLocation.Transformation().Inverted();
188
189   Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
190   Standard_Integer  aTriNodes1[3] = { -1, -1, -1 };
191   Standard_Integer  aTriNodes2[3] = { -1, -1, -1 };
192   Standard_Integer* aTriNodesPrev = aTriNodes1;
193   Standard_Integer* aTriNodes     = aTriNodes2;
194   Standard_Integer  aPatchFrom    = 0;
195   Standard_Integer  aPatchSize    = 0;
196   if (myBvhIndices.HasPatches())
197   {
198     myBvhIndices.NbElements = 0;
199   }
200   for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
201   {
202     const Standard_Integer anIndexOffset = (aTriFrom + aTriIter) * 3;
203     getTriIndices (myIndices, anIndexOffset, aTriNodes);
204     if (myIs3d)
205     {
206       const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
207       const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
208       const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
209       aCenter += (aNode1 + aNode2 + aNode3) / 3.0;
210     }
211     else
212     {
213       const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
214       const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
215       const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
216       aCenter.xy() += (aNode1 + aNode2 + aNode3) / 3.0;
217     }
218     if (myBvhIndices.HasPatches())
219     {
220       std::swap (aTriNodes, aTriNodesPrev);
221       if (aPatchSize < myPatchSizeMax
222        && hasSharedNode (aTriNodes, aTriNodesPrev))
223       {
224         ++aPatchSize;
225         continue;
226       }
227       else
228       {
229         myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
230         aPatchFrom = aTriIter;
231         aPatchSize = 0;
232       }
233     }
234     else
235     {
236       myBvhIndices.SetIndex (aTriIter, aTriFrom + aTriIter);
237     }
238   }
239   if (aPatchSize != 0)
240   {
241     myBvhIndices.SetIndex (myBvhIndices.NbElements++, aTriFrom + aPatchFrom, aPatchSize);
242   }
243   aCenter /= float(aNbTris);
244
245   myCDG3D = vecToPnt (aCenter);
246   if (theToEvalMinMax)
247   {
248     computeBoundingBox();
249   }
250   return true;
251 }
252
253 // =======================================================================
254 // function : InitPoints
255 // purpose  :
256 // =======================================================================
257 bool Select3D_SensitivePrimitiveArray::InitPoints (const Handle(Graphic3d_Buffer)&      theVerts,
258                                                    const Handle(Graphic3d_IndexBuffer)& theIndices,
259                                                    const TopLoc_Location&               theInitLoc,
260                                                    const Standard_Integer               theIndexLower,
261                                                    const Standard_Integer               theIndexUpper,
262                                                    const bool                           theToEvalMinMax)
263 {
264   MarkDirty();
265   myPrimType = Graphic3d_TOPA_POINTS;
266   myBndBox.Clear();
267   myVerts.Nullify();
268   myIndices.Nullify();
269   myIndexLower = 0;
270   myIndexUpper = 0;
271   myPosOffset = Standard_Size(-1);
272   myBvhIndices.release();
273   myIs3d = false;
274   myInitLocation = theInitLoc;
275   if (theVerts.IsNull()
276    || theVerts->NbElements == 0)
277   {
278     return false;
279   }
280
281   for (Standard_Integer anAttribIter = 0; anAttribIter < theVerts->NbAttributes; ++anAttribIter)
282   {
283     const Graphic3d_Attribute& anAttrib = theVerts->Attribute (anAttribIter);
284     if (anAttrib.Id == Graphic3d_TOA_POS)
285     {
286       if (anAttrib.DataType == Graphic3d_TOD_VEC3
287        || anAttrib.DataType == Graphic3d_TOD_VEC4)
288       {
289         myIs3d = true;
290       }
291       else if (anAttrib.DataType != Graphic3d_TOD_VEC2)
292       {
293         return false;
294       }
295
296       myPosOffset = theVerts->AttributeOffset (anAttribIter);
297       break;
298     }
299   }
300   if (myPosOffset == Standard_Size(-1))
301   {
302     return false;
303   }
304
305   if (!theIndices.IsNull())
306   {
307     if (theIndexLower < 0
308      || theIndexUpper >= theIndices->NbElements
309      || theIndices->NbElements == 0)
310     {
311       return false;
312     }
313   }
314   else
315   {
316     if (theIndexLower < 0
317      || theIndexUpper >= theVerts->NbElements)
318     {
319       return false;
320     }
321   }
322
323   Standard_Integer aNbPoints = theIndexUpper - theIndexLower + 1;
324   if (aNbPoints < 1)
325   {
326     return false;
327   }
328   if (!myBvhIndices.Init (aNbPoints, myPatchSizeMax > 1))
329   {
330     return false;
331   }
332
333   myVerts      = theVerts;
334   myIndices    = theIndices;
335   myIndexLower = theIndexLower;
336   myIndexUpper = theIndexUpper;
337   myInvInitLocation = myInitLocation.Transformation().Inverted();
338
339   Graphic3d_Vec3 aCenter (0.0f, 0.0f, 0.0f);
340   Standard_Integer aPatchFrom = 0;
341   Standard_Integer aPatchSize = 0;
342   if (myBvhIndices.HasPatches())
343   {
344     myBvhIndices.NbElements = 0;
345   }
346   const float aPatchSize2 = myPatchDistance < ShortRealLast()
347                           ? myPatchDistance * myPatchDistance
348                           : myPatchDistance;
349   const Graphic3d_Vec3* aPnt3dPrev = NULL;
350   const Graphic3d_Vec3* aPnt3d     = NULL;
351   const Graphic3d_Vec2* aPnt2dPrev = NULL;
352   const Graphic3d_Vec2* aPnt2d     = NULL;
353   for (Standard_Integer aPointIter = 0; aPointIter < aNbPoints; ++aPointIter)
354   {
355     const Standard_Integer anIndexOffset = (theIndexLower + aPointIter);
356     const Standard_Integer aPointIndex   = !myIndices.IsNull()
357                                           ? myIndices->Index (anIndexOffset)
358                                           : anIndexOffset;
359     if (myIs3d)
360     {
361       aPnt3d = &getPosVec3 (aPointIndex);
362       aCenter += *aPnt3d;
363     }
364     else
365     {
366       aPnt2d = &getPosVec2 (aPointIndex);
367       aCenter.xy() += *aPnt2d;
368     }
369
370     if (myBvhIndices.HasPatches())
371     {
372       if (myIs3d)
373       {
374         std::swap (aPnt3d, aPnt3dPrev);
375         if (aPatchSize < myPatchSizeMax
376          && aPnt3d != NULL
377          && (*aPnt3dPrev - *aPnt3d).SquareModulus() < aPatchSize2)
378         {
379           ++aPatchSize;
380           continue;
381         }
382       }
383       else
384       {
385         std::swap (aPnt2d, aPnt2dPrev);
386         if (aPatchSize < myPatchSizeMax
387          && aPnt2d != NULL
388          && (*aPnt2dPrev - *aPnt2d).SquareModulus() < aPatchSize2)
389         {
390           ++aPatchSize;
391           continue;
392         }
393       }
394
395       myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom,
396                               aPatchSize != 0 ? aPatchSize : 1);
397       aPatchFrom = aPointIter;
398       aPatchSize = 0;
399     }
400     else
401     {
402       myBvhIndices.SetIndex (aPointIter, theIndexLower + aPointIter);
403     }
404   }
405   if (aPatchSize != 0)
406   {
407     myBvhIndices.SetIndex (myBvhIndices.NbElements++, theIndexLower + aPatchFrom, aPatchSize);
408   }
409   aCenter /= float(aNbPoints);
410
411   myCDG3D = vecToPnt (aCenter);
412   if (theToEvalMinMax)
413   {
414     computeBoundingBox();
415   }
416   return true;
417 }
418
419 // =======================================================================
420 // function : GetConnected
421 // purpose  :
422 // =======================================================================
423 Handle(Select3D_SensitiveEntity) Select3D_SensitivePrimitiveArray::GetConnected()
424 {
425   Handle(Select3D_SensitivePrimitiveArray) aNewEntity = new Select3D_SensitivePrimitiveArray (myOwnerId);
426   switch (myPrimType)
427   {
428     case Graphic3d_TOPA_POINTS:
429     {
430       aNewEntity->InitPoints        (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper);
431       break;
432     }
433     case Graphic3d_TOPA_TRIANGLES:
434     {
435       aNewEntity->InitTriangulation (myVerts, myIndices, myInitLocation, myIndexLower, myIndexUpper);
436       break;
437     }
438     default: break;
439   }
440   return aNewEntity;
441 }
442
443 // =======================================================================
444 // function : Size
445 // purpose  :
446 // =======================================================================
447 Standard_Integer Select3D_SensitivePrimitiveArray::Size() const
448 {
449   return myBvhIndices.NbElements;
450 }
451
452 // =======================================================================
453 // function : Box
454 // purpose  :
455 // =======================================================================
456 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::Box (const Standard_Integer theIdx) const
457 {
458   const Standard_Integer anElemIdx  = myBvhIndices.Index (theIdx);
459   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theIdx);
460   Select3D_BndBox3d aBox;
461   switch (myPrimType)
462   {
463     case Graphic3d_TOPA_POINTS:
464     {
465       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
466       {
467         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
468         const Standard_Integer aPointIndex   = !myIndices.IsNull()
469                                              ?  myIndices->Index (anIndexOffset)
470                                              :  anIndexOffset;
471         if (myIs3d)
472         {
473           const Graphic3d_Vec3& aPoint = getPosVec3 (aPointIndex);
474           aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), aPoint.z()));
475         }
476         else
477         {
478           const Graphic3d_Vec2& aPoint = getPosVec2 (aPointIndex);
479           aBox.Add (SelectMgr_Vec3 (aPoint.x(), aPoint.y(), 0.0));
480         }
481       }
482       break;
483     }
484     case Graphic3d_TOPA_TRIANGLES:
485     {
486       Standard_Integer aTriNodes[3];
487       if (myIs3d)
488       {
489         for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
490         {
491           const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
492           getTriIndices (myIndices, anIndexOffset, aTriNodes);
493           const Graphic3d_Vec3& aNode1 = getPosVec3 (aTriNodes[0]);
494           const Graphic3d_Vec3& aNode2 = getPosVec3 (aTriNodes[1]);
495           const Graphic3d_Vec3& aNode3 = getPosVec3 (aTriNodes[2]);
496           Graphic3d_Vec3 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
497           Graphic3d_Vec3 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
498           aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), aMinPnt.z()));
499           aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), aMaxPnt.z()));
500         }
501       }
502       else
503       {
504         for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
505         {
506           const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
507           getTriIndices (myIndices, anIndexOffset, aTriNodes);
508           const Graphic3d_Vec2& aNode1 = getPosVec2 (aTriNodes[0]);
509           const Graphic3d_Vec2& aNode2 = getPosVec2 (aTriNodes[1]);
510           const Graphic3d_Vec2& aNode3 = getPosVec2 (aTriNodes[2]);
511           Graphic3d_Vec2 aMinPnt = (aNode1.cwiseMin (aNode2)).cwiseMin (aNode3);
512           Graphic3d_Vec2 aMaxPnt = (aNode1.cwiseMax (aNode2)).cwiseMax (aNode3);
513           aBox.Add (SelectMgr_Vec3 (aMinPnt.x(), aMinPnt.y(), 0.0));
514           aBox.Add (SelectMgr_Vec3 (aMaxPnt.x(), aMaxPnt.y(), 0.0));
515         }
516       }
517       break;
518     }
519     default:
520     {
521       return aBox;
522     }
523   }
524   return aBox;
525 }
526
527 // =======================================================================
528 // function : Center
529 // purpose  :
530 // =======================================================================
531 Standard_Real Select3D_SensitivePrimitiveArray::Center (const Standard_Integer theIdx,
532                                                         const Standard_Integer theAxis) const
533 {
534   const Select3D_BndBox3d& aBox = Box (theIdx);
535   SelectMgr_Vec3 aCenter = (aBox.CornerMin() + aBox.CornerMax()) * 0.5;
536   return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
537 }
538
539 // =======================================================================
540 // function : Swap
541 // purpose  :
542 // =======================================================================
543 void Select3D_SensitivePrimitiveArray::Swap (const Standard_Integer theIdx1,
544                                              const Standard_Integer theIdx2)
545 {
546   Standard_Integer anElemIdx1 = myBvhIndices.Index (theIdx1);
547   Standard_Integer anElemIdx2 = myBvhIndices.Index (theIdx2);
548   if (myBvhIndices.HasPatches())
549   {
550     Standard_Integer aPatchSize1 = myBvhIndices.PatchSize (theIdx1);
551     Standard_Integer aPatchSize2 = myBvhIndices.PatchSize (theIdx2);
552     myBvhIndices.SetIndex (theIdx1, anElemIdx2, aPatchSize2);
553     myBvhIndices.SetIndex (theIdx2, anElemIdx1, aPatchSize1);
554   }
555   else
556   {
557     myBvhIndices.SetIndex (theIdx1, anElemIdx2);
558     myBvhIndices.SetIndex (theIdx2, anElemIdx1);
559   }
560 }
561
562 // =======================================================================
563 // function : BoundingBox
564 // purpose  :
565 // =======================================================================
566 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::BoundingBox()
567 {
568   if (!myBndBox.IsValid())
569   {
570     computeBoundingBox();
571   }
572   return applyTransformation();
573 }
574
575 // =======================================================================
576 // function : computeBoundingBox
577 // purpose  :
578 // =======================================================================
579 void Select3D_SensitivePrimitiveArray::computeBoundingBox()
580 {
581   myBndBox.Clear();
582   if (myVerts.IsNull())
583   {
584     return;
585   }
586
587   const Standard_Integer aNbVerts = myVerts->NbElements;
588   if (myIs3d)
589   {
590     for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
591     {
592       const Graphic3d_Vec3& aVert = getPosVec3 (aVertIter);
593       myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), aVert.z()));
594     }
595   }
596   else
597   {
598     for (Standard_Integer aVertIter = 0; aVertIter < aNbVerts; ++aVertIter)
599     {
600       const Graphic3d_Vec2& aVert = getPosVec2 (aVertIter);
601       myBndBox.Add (SelectMgr_Vec3 (aVert.x(), aVert.y(), 0.0));
602     }
603   }
604 }
605
606 // =======================================================================
607 // function : applyTransformation
608 // purpose  :
609 // =======================================================================
610 Select3D_BndBox3d Select3D_SensitivePrimitiveArray::applyTransformation()
611 {
612   if (!HasInitLocation())
613   {
614     return myBndBox;
615   }
616
617   Select3D_BndBox3d aBndBox;
618   for (Standard_Integer aX = 0; aX <=1; ++aX)
619   {
620     for (Standard_Integer aY = 0; aY <=1; ++aY)
621     {
622       for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
623       {
624         gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
625                                  aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
626                                  aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
627         aVertex.Transform (myInitLocation.Transformation());
628         aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
629       }
630     }
631   }
632   return aBndBox;
633 }
634
635 // =======================================================================
636 // function : Matches
637 // purpose  :
638 // =======================================================================
639 Standard_Boolean Select3D_SensitivePrimitiveArray::Matches (SelectBasics_SelectingVolumeManager& theMgr,
640                                                             SelectBasics_PickResult& thePickResult)
641 {
642   myMinDepthElem      = RealLast();
643   myMinDepthNode      = RealLast();
644   myMinDepthEdge      = RealLast();
645   myDetectedElem      = -1;
646   myDetectedNode      = -1;
647   myDetectedEdgeNode1 = -1;
648   myDetectedEdgeNode2 = -1;
649   return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
650 }
651
652 // =======================================================================
653 // function : overlapsElement
654 // purpose  :
655 // =======================================================================
656 Standard_Boolean Select3D_SensitivePrimitiveArray::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
657                                                                     Standard_Integer theElemIdx,
658                                                                     Standard_Real& theMatchDepth)
659 {
660   const Standard_Integer anElemIdx  = myBvhIndices.Index (theElemIdx);
661   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
662   Select3D_BndBox3d aBox;
663   Standard_Boolean aResult = Standard_False;
664   Standard_Real aMinDepth  = RealLast();
665   switch (myPrimType)
666   {
667     case Graphic3d_TOPA_POINTS:
668     {
669       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
670       {
671         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
672         const Standard_Integer aPointIndex   = !myIndices.IsNull()
673                                              ?  myIndices->Index (anIndexOffset)
674                                              :  anIndexOffset;
675         gp_Pnt aPoint;
676         if (myIs3d)
677         {
678           aPoint = vecToPnt (getPosVec3 (aPointIndex));
679         }
680         else
681         {
682           aPoint = vecToPnt (getPosVec2 (aPointIndex));
683         }
684
685         Standard_Real aCurrentDepth = RealLast();
686         if (myToDetectNode
687          || myToDetectElem)
688         {
689           if (theMgr.Overlaps (aPoint, aCurrentDepth))
690           {
691             if (aCurrentDepth <= myMinDepthNode)
692             {
693               myDetectedElem = myDetectedNode = aPointIndex;
694               myMinDepthElem = myMinDepthNode = aCurrentDepth;
695             }
696             aResult = Standard_True;
697           }
698         }
699         aMinDepth = Min (aMinDepth, aCurrentDepth);
700       }
701       break;
702     }
703     case Graphic3d_TOPA_TRIANGLES:
704     {
705       Graphic3d_Vec3i aTriNodes;
706       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
707       {
708         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
709         getTriIndices (myIndices, anIndexOffset, aTriNodes);
710         gp_Pnt aPnts[3];
711         if (myIs3d)
712         {
713           aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
714           aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
715           aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
716         }
717         else
718         {
719           aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
720           aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
721           aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
722         }
723
724         Standard_Real aCurrentDepth = RealLast();
725         if (myToDetectElem)
726         {
727           if (theMgr.Overlaps (aPnts[0], aPnts[1], aPnts[2], Select3D_TOS_INTERIOR, aCurrentDepth))
728           {
729             if (aCurrentDepth <= myMinDepthElem)
730             {
731               myDetectedElem = anElemIdx + anElemIter;
732               myMinDepthElem = aCurrentDepth;
733             }
734             aResult = Standard_True;
735           }
736         }
737         if (myToDetectNode)
738         {
739           for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
740           {
741             if (theMgr.Overlaps (aPnts[aNodeIter], aCurrentDepth))
742             {
743               if (aCurrentDepth <= myMinDepthNode)
744               {
745                 myDetectedNode = aTriNodes[aNodeIter];
746                 myMinDepthNode = aCurrentDepth;
747               }
748               aResult = Standard_True;
749             }
750           }
751         }
752         if (myToDetectEdge)
753         {
754           for (int aNodeIter = 0; aNodeIter < 3; ++aNodeIter)
755           {
756             int aNode1 = aNodeIter == 0 ? 2 : (aNodeIter - 1);
757             int aNode2 = aNodeIter;
758             if (theMgr.Overlaps (aPnts[aNode1], aPnts[aNode2], aCurrentDepth))
759             {
760               if (aCurrentDepth <= myMinDepthEdge)
761               {
762                 myDetectedEdgeNode1 = aTriNodes[aNode1];
763                 myDetectedEdgeNode2 = aTriNodes[aNode2];
764                 myMinDepthEdge = aCurrentDepth;
765               }
766               aResult = Standard_True;
767             }
768           }
769         }
770         aMinDepth = Min (aMinDepth, aCurrentDepth);
771       }
772       break;
773     }
774     default:
775     {
776       return Standard_False;
777     }
778   }
779
780   theMatchDepth = aMinDepth;
781   return aResult;
782 }
783
784 // =======================================================================
785 // function : distanceToCOG
786 // purpose  :
787 // =======================================================================
788 Standard_Real Select3D_SensitivePrimitiveArray::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
789 {
790   return theMgr.DistToGeometryCenter (myCDG3D);
791 }
792
793 // =======================================================================
794 // function : elementIsInside
795 // purpose  :
796 // =======================================================================
797 Standard_Boolean Select3D_SensitivePrimitiveArray::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
798                                                                     const Standard_Integer               theElemIdx)
799 {
800   const Standard_Integer anElemIdx  = myBvhIndices.Index (theElemIdx);
801   const Standard_Integer aPatchSize = myBvhIndices.PatchSize (theElemIdx);
802   switch (myPrimType)
803   {
804     case Graphic3d_TOPA_POINTS:
805     {
806       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
807       {
808         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter);
809         const Standard_Integer aPointIndex   = !myIndices.IsNull()
810                                              ?  myIndices->Index (anIndexOffset)
811                                              :  anIndexOffset;
812         gp_Pnt aPoint;
813         if (myIs3d)
814         {
815           aPoint = vecToPnt (getPosVec3 (aPointIndex));
816         }
817         else
818         {
819           aPoint = vecToPnt (getPosVec2 (aPointIndex));
820         }
821         if (!theMgr.Overlaps (aPoint))
822         {
823           return Standard_False;
824         }
825       }
826       return Standard_True;
827     }
828     case Graphic3d_TOPA_TRIANGLES:
829     {
830       Graphic3d_Vec3i aTriNodes;
831       for (Standard_Integer anElemIter = 0; anElemIter < aPatchSize; ++anElemIter)
832       {
833         const Standard_Integer anIndexOffset = (anElemIdx + anElemIter) * 3;
834         getTriIndices (myIndices, anIndexOffset, aTriNodes);
835         gp_Pnt aPnts[3];
836         if (myIs3d)
837         {
838           aPnts[0] = vecToPnt (getPosVec3 (aTriNodes[0]));
839           aPnts[1] = vecToPnt (getPosVec3 (aTriNodes[1]));
840           aPnts[2] = vecToPnt (getPosVec3 (aTriNodes[2]));
841         }
842         else
843         {
844           aPnts[0] = vecToPnt (getPosVec2 (aTriNodes[0]));
845           aPnts[1] = vecToPnt (getPosVec2 (aTriNodes[1]));
846           aPnts[2] = vecToPnt (getPosVec2 (aTriNodes[2]));
847         }
848
849         if (!theMgr.Overlaps (aPnts[0])
850          || !theMgr.Overlaps (aPnts[1])
851          || !theMgr.Overlaps (aPnts[2]))
852         {
853           return Standard_False;
854         }
855       }
856       return Standard_True;
857     }
858     default:
859     {
860       return Standard_False;
861     }
862   }
863 }