0032337: Visualization - rename Overlaps() method in selection to more self-describab...
[occt.git] / src / Select3D / Select3D_SensitiveTriangulation.cxx
1 // Created on: 1997-05-15
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1997-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <Select3D_SensitiveTriangulation.hxx>
18
19 #include <Poly.hxx>
20 #include <Poly_Connect.hxx>
21 #include <TColStd_Array1OfInteger.hxx>
22 #include <Select3D_SensitiveTriangle.hxx>
23 #include <Precision.hxx>
24 #include <Select3D_TypeOfSensitivity.hxx>
25
26 #include <algorithm>
27
28 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveTriangulation,Select3D_SensitiveSet)
29
30 namespace
31 {
32   static Standard_Integer NbOfFreeEdges (const Handle(Poly_Triangulation)& theTriangulation)
33   {
34     Standard_Integer aNbFree = 0;
35     Poly_Connect aPoly (theTriangulation);
36     Standard_Integer aTriangleNodes[3];
37     for (Standard_Integer aTrgIdx = 1; aTrgIdx <= theTriangulation->NbTriangles(); aTrgIdx++)
38     {
39       aPoly.Triangles (aTrgIdx, aTriangleNodes[0], aTriangleNodes[1], aTriangleNodes[2]);
40       for (Standard_Integer aNodeIdx = 0; aNodeIdx < 3; ++aNodeIdx)
41       {
42         if (aTriangleNodes[aNodeIdx] == 0)
43         {
44           ++aNbFree;
45         }
46       }
47     }
48     return aNbFree;
49   }
50 }
51
52 //=======================================================================
53 //function : Select3D_SensitiveTriangulation
54 //purpose  :
55 //=======================================================================
56 Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(SelectMgr_EntityOwner)& theOwnerId,
57                                                                   const Handle(Poly_Triangulation)& theTrg,
58                                                                   const TopLoc_Location& theInitLoc,
59                                                                   const Standard_Boolean theIsInterior)
60 : Select3D_SensitiveSet (theOwnerId),
61   myTriangul (theTrg),
62   myInitLocation (theInitLoc),
63   myPrimitivesNb (0)
64 {
65   myInvInitLocation = myInitLocation.Transformation().Inverted();
66   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
67   Standard_Integer aNbTriangles = 0;
68   gp_XYZ aCenter (0.0, 0.0, 0.0);
69   if (!theTrg->HasGeometry())
70   {
71     if (myTriangul->HasCachedMinMax())
72     {
73       aCenter = 0.5 * (myTriangul->CachedMinMax().CornerMin().XYZ()
74                      + myTriangul->CachedMinMax().CornerMax().XYZ());
75     }
76   }
77   else
78   {
79     aNbTriangles = myTriangul->NbTriangles();
80     myPrimitivesNb = theIsInterior ? aNbTriangles : NbOfFreeEdges (theTrg);
81     myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
82     TColStd_Array1OfInteger& aBVHPrimIdxs = myBVHPrimIndexes->ChangeArray1();
83
84     if (!theIsInterior)
85     {
86       Standard_Integer anEdgeIdx = 1;
87       myFreeEdges = new TColStd_HArray1OfInteger (1, 2 * myPrimitivesNb);
88       TColStd_Array1OfInteger& aFreeEdges = myFreeEdges->ChangeArray1();
89       Poly_Connect aPoly (myTriangul);
90       Standard_Integer aTriangle[3];
91       Standard_Integer aTrNodeIdx[3];
92       for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; aTriangleIdx++)
93       {
94         aPoly.Triangles (aTriangleIdx, aTriangle[0], aTriangle[1], aTriangle[2]);
95         myTriangul->Triangle (aTriangleIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
96         const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
97         aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
98         for (Standard_Integer aVertIdx = 0; aVertIdx < 3; aVertIdx++)
99         {
100           Standard_Integer aNextVert = (aVertIdx + 1) % 3;
101           if (aTriangle[aVertIdx] == 0)
102           {
103             aFreeEdges (anEdgeIdx)  = aTrNodeIdx[aVertIdx];
104             aFreeEdges (anEdgeIdx+1) = aTrNodeIdx[aNextVert];
105             anEdgeIdx += 2;
106           }
107         }
108       }
109     }
110     else
111     {
112       Standard_Integer aTrNodeIdx[3];
113       for (Standard_Integer aTrIdx = 1; aTrIdx <= aNbTriangles; aTrIdx++)
114       {
115         myTriangul->Triangle (aTrIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
116         const gp_Pnt aTriNodes[3] = { myTriangul->Node (aTrNodeIdx[0]), myTriangul->Node (aTrNodeIdx[1]), myTriangul->Node (aTrNodeIdx[2]) };
117         aCenter += (aTriNodes[0].XYZ() + aTriNodes[1].XYZ()+ aTriNodes[2].XYZ()) / 3.0;
118       }
119     }
120
121     if (theIsInterior)
122     {
123       for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; ++aTriangleIdx)
124       {
125         aBVHPrimIdxs(aTriangleIdx - 1) = aTriangleIdx - 1;
126       }
127     }
128     else
129     {
130       Standard_Integer aStartIdx = myFreeEdges->Lower();
131       Standard_Integer anEndIdx = myFreeEdges->Upper();
132       for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
133       {
134         aBVHPrimIdxs((aFreeEdgesIdx - aStartIdx) / 2) = (aFreeEdgesIdx - aStartIdx) / 2;
135       }
136     }
137   }
138   if (aNbTriangles != 0)
139   {
140     aCenter /= aNbTriangles;
141   }
142   myCDG3D = gp_Pnt (aCenter);
143   computeBoundingBox();
144 }
145
146 //=======================================================================
147 //function : Select3D_SensitiveTriangulation
148 //purpose  :
149 //=======================================================================
150 Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(SelectMgr_EntityOwner)& theOwnerId,
151                                                                   const Handle(Poly_Triangulation)& theTrg,
152                                                                   const TopLoc_Location& theInitLoc,
153                                                                   const Handle(TColStd_HArray1OfInteger)& theFreeEdges,
154                                                                   const gp_Pnt& theCOG,
155                                                                   const Standard_Boolean theIsInterior)
156 : Select3D_SensitiveSet (theOwnerId),
157   myTriangul (theTrg),
158   myInitLocation (theInitLoc),
159   myCDG3D (theCOG),
160   myFreeEdges (theFreeEdges),
161   myPrimitivesNb (0)
162 {
163   myInvInitLocation = myInitLocation.Transformation().Inverted();
164   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
165   if (theTrg->HasGeometry())
166   {
167     myPrimitivesNb = theIsInterior ? theTrg->NbTriangles() : theFreeEdges->Length() / 2;
168     myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
169     if (theIsInterior)
170     {
171       for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= myPrimitivesNb; ++aTriangleIdx)
172       {
173         myBVHPrimIndexes->SetValue (aTriangleIdx - 1, aTriangleIdx - 1);
174       }
175     }
176     else
177     {
178       Standard_Integer aStartIdx = myFreeEdges->Lower();
179       Standard_Integer anEndIdx = myFreeEdges->Upper();
180       for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
181       {
182         myBVHPrimIndexes->SetValue ((aFreeEdgesIdx - aStartIdx) / 2, (aFreeEdgesIdx - aStartIdx) / 2);
183       }
184     }
185   }
186 }
187
188 //=======================================================================
189 // function : Size
190 // purpose  : Returns the length of array of triangles or edges
191 //=======================================================================
192 Standard_Integer Select3D_SensitiveTriangulation::Size() const
193 {
194   return myPrimitivesNb;
195 }
196
197 //=======================================================================
198 // function : Box
199 // purpose  : Returns bounding box of triangle/edge with index theIdx
200 //=======================================================================
201 Select3D_BndBox3d Select3D_SensitiveTriangulation::Box (const Standard_Integer theIdx) const
202 {
203   Standard_Integer aPrimIdx = myBVHPrimIndexes->Value (theIdx);
204   SelectMgr_Vec3 aMinPnt (RealLast());
205   SelectMgr_Vec3 aMaxPnt (RealFirst());
206
207   if (mySensType == Select3D_TOS_INTERIOR)
208   {
209     Standard_Integer aNode1, aNode2, aNode3;
210     myTriangul->Triangle (aPrimIdx + 1).Get (aNode1, aNode2, aNode3);
211
212     const gp_Pnt aPnt1 = myTriangul->Node (aNode1);
213     const gp_Pnt aPnt2 = myTriangul->Node (aNode2);
214     const gp_Pnt aPnt3 = myTriangul->Node (aNode3);
215
216     aMinPnt = SelectMgr_Vec3 (Min (aPnt1.X(), Min (aPnt2.X(), aPnt3.X())),
217                               Min (aPnt1.Y(), Min (aPnt2.Y(), aPnt3.Y())),
218                               Min (aPnt1.Z(), Min (aPnt2.Z(), aPnt3.Z())));
219     aMaxPnt = SelectMgr_Vec3 (Max (aPnt1.X(), Max (aPnt2.X(), aPnt3.X())),
220                               Max (aPnt1.Y(), Max (aPnt2.Y(), aPnt3.Y())),
221                               Max (aPnt1.Z(), Max (aPnt2.Z(), aPnt3.Z())));
222   }
223   else
224   {
225     Standard_Integer aNodeIdx1 = myFreeEdges->Value (myFreeEdges->Lower() + aPrimIdx);
226     Standard_Integer aNodeIdx2 = myFreeEdges->Value (myFreeEdges->Lower() + aPrimIdx + 1);
227     const gp_Pnt aNode1 = myTriangul->Node (aNodeIdx1);
228     const gp_Pnt aNode2 = myTriangul->Node (aNodeIdx2);
229
230     aMinPnt = SelectMgr_Vec3 (Min (aNode1.X(), aNode2.X()),
231                               Min (aNode1.Y(), aNode2.Y()),
232                               Min (aNode1.Z(), aNode2.Z()));
233     aMaxPnt = SelectMgr_Vec3 (Max (aNode1.X(), aNode2.X()),
234                               Max (aNode1.Y(), aNode2.Y()),
235                               Max (aNode1.Z(), aNode2.Z()));
236   }
237
238   return Select3D_BndBox3d (aMinPnt, aMaxPnt);
239 }
240
241 // =======================================================================
242 // function : Matches
243 // purpose  :
244 // =======================================================================
245 Standard_Boolean Select3D_SensitiveTriangulation::Matches (SelectBasics_SelectingVolumeManager& theMgr,
246                                                            SelectBasics_PickResult& thePickResult)
247 {
248   if (myTriangul->HasGeometry())
249   {
250     return Select3D_SensitiveSet::Matches (theMgr, thePickResult);
251   }
252
253   Select3D_BndBox3d aBndBox = BoundingBox();
254   if (!aBndBox.IsValid())
255   {
256     return false;
257   }
258
259   if (!theMgr.IsOverlapAllowed()) // check for inclusion
260   {
261     bool isInside = true;
262     return theMgr.OverlapsBox (aBndBox.CornerMin(), aBndBox.CornerMax(), &isInside) && isInside;
263   }
264   if (!theMgr.OverlapsBox (aBndBox.CornerMin(), aBndBox.CornerMax(), thePickResult)) // check for overlap
265   {
266     return false;
267   }
268   thePickResult.SetDistToGeomCenter (theMgr.DistToGeometryCenter (myCDG3D));
269   return true;
270 }
271
272 //=======================================================================
273 // function : Center
274 // purpose  : Returns geometry center of triangle/edge with index theIdx
275 //            in array along the given axis theAxis
276 //=======================================================================
277 Standard_Real Select3D_SensitiveTriangulation::Center (const Standard_Integer theIdx,
278                                                        const Standard_Integer theAxis) const
279 {
280   const Select3D_BndBox3d& aBox = Box (theIdx);
281   const SelectMgr_Vec3 aCenter = (aBox.CornerMin () + aBox.CornerMax ()) * 0.5;
282   return aCenter[theAxis];
283 }
284
285 //=======================================================================
286 // function : Swap
287 // purpose  : Swaps items with indexes theIdx1 and theIdx2 in array
288 //=======================================================================
289 void Select3D_SensitiveTriangulation::Swap (const Standard_Integer theIdx1,
290                                             const Standard_Integer theIdx2)
291 {
292   Standard_Integer anElemIdx1 = myBVHPrimIndexes->Value (theIdx1);
293   Standard_Integer anElemIdx2 = myBVHPrimIndexes->Value (theIdx2);
294
295   myBVHPrimIndexes->ChangeValue (theIdx1) = anElemIdx2;
296   myBVHPrimIndexes->ChangeValue (theIdx2) = anElemIdx1;
297 }
298
299 //=======================================================================
300 // function : LastDetectedTriangle
301 // purpose  :
302 //=======================================================================
303 bool Select3D_SensitiveTriangulation::LastDetectedTriangle (Poly_Triangle& theTriangle) const
304 {
305   const Standard_Integer anIndex = LastDetectedTriangleIndex();
306   if (anIndex != -1)
307   {
308     theTriangle = myTriangul->Triangle (anIndex);
309     return true;
310   }
311   return false;
312 }
313
314 //=======================================================================
315 // function : LastDetectedTriangle
316 // purpose  :
317 //=======================================================================
318 bool Select3D_SensitiveTriangulation::LastDetectedTriangle (Poly_Triangle& theTriangle,
319                                                             gp_Pnt theTriNodes[3]) const
320 {
321   if (!LastDetectedTriangle (theTriangle))
322   {
323     return false;
324   }
325
326   theTriNodes[0] = myTriangul->Node (theTriangle.Value (1)).Transformed (myInitLocation.Transformation());;
327   theTriNodes[1] = myTriangul->Node (theTriangle.Value (2)).Transformed (myInitLocation.Transformation());;
328   theTriNodes[2] = myTriangul->Node (theTriangle.Value (3)).Transformed (myInitLocation.Transformation());;
329   return true;
330 }
331
332 //=======================================================================
333 // function : overlapsElement
334 // purpose  : Checks whether the element with index theIdx overlaps the
335 //            current selecting volume
336 //=======================================================================
337 Standard_Boolean Select3D_SensitiveTriangulation::overlapsElement (SelectBasics_PickResult& thePickResult,
338                                                                    SelectBasics_SelectingVolumeManager& theMgr,
339                                                                    Standard_Integer theElemIdx,
340                                                                    Standard_Boolean theIsFullInside)
341 {
342   if (theIsFullInside)
343   {
344     return Standard_True;
345   }
346
347   const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
348   if (mySensType == Select3D_TOS_BOUNDARY)
349   {
350     Standard_Integer aSegmStartIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 1);
351     Standard_Integer aSegmEndIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 2);
352
353     const gp_Pnt anEdgePnts[2] =
354     {
355       myTriangul->Node (aSegmStartIdx),
356       myTriangul->Node (aSegmEndIdx)
357     };
358     TColgp_Array1OfPnt anEdgePntsArr (anEdgePnts[0], 1, 2);
359     Standard_Boolean isMatched = theMgr.OverlapsPolygon (anEdgePntsArr, Select3D_TOS_BOUNDARY, thePickResult);
360     return isMatched;
361   }
362   else
363   {
364     Standard_Integer aNode1, aNode2, aNode3;
365     myTriangul->Triangle (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
366     const gp_Pnt aPnt1 = myTriangul->Node (aNode1);
367     const gp_Pnt aPnt2 = myTriangul->Node (aNode2);
368     const gp_Pnt aPnt3 = myTriangul->Node (aNode3);
369     return theMgr.OverlapsTriangle (aPnt1, aPnt2, aPnt3, Select3D_TOS_INTERIOR, thePickResult);
370   }
371 }
372
373 //==================================================
374 // Function : elementIsInside
375 // Purpose  :
376 //==================================================
377 Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
378                                                                    Standard_Integer theElemIdx,
379                                                                    Standard_Boolean theIsFullInside)
380 {
381   if (theIsFullInside)
382   {
383     return Standard_True;
384   }
385
386   const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
387   if (mySensType == Select3D_TOS_BOUNDARY)
388   {
389     const gp_Pnt aSegmPnt1 = myTriangul->Node (myFreeEdges->Value (aPrimitiveIdx * 2 + 1));
390     const gp_Pnt aSegmPnt2 = myTriangul->Node (myFreeEdges->Value (aPrimitiveIdx * 2 + 2));
391     if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
392     {
393       SelectBasics_PickResult aDummy;
394       return theMgr.OverlapsSegment (aSegmPnt1, aSegmPnt2, aDummy);
395     }
396     return theMgr.OverlapsPoint (aSegmPnt1) && theMgr.OverlapsPoint (aSegmPnt2);
397   }
398   else
399   {
400     Standard_Integer aNode1, aNode2, aNode3;
401     myTriangul->Triangle (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
402
403     const gp_Pnt aPnt1 = myTriangul->Node (aNode1);
404     const gp_Pnt aPnt2 = myTriangul->Node (aNode2);
405     const gp_Pnt aPnt3 = myTriangul->Node (aNode3);
406     if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
407     {
408       SelectBasics_PickResult aDummy;
409       return theMgr.OverlapsTriangle (aPnt1, aPnt2, aPnt3, mySensType, aDummy);
410     }
411     return theMgr.OverlapsPoint (aPnt1)
412         && theMgr.OverlapsPoint (aPnt2)
413         && theMgr.OverlapsPoint (aPnt3);
414   }
415 }
416
417 //=======================================================================
418 // function : distanceToCOG
419 // purpose  : Calculates distance from the 3d projection of used-picked
420 //            screen point to center of the geometry
421 //=======================================================================
422 Standard_Real Select3D_SensitiveTriangulation::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
423 {
424   return theMgr.DistToGeometryCenter (myCDG3D);
425 }
426
427 //=======================================================================
428 //function : GetConnected
429 //purpose  :
430 //=======================================================================
431 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::GetConnected()
432 {
433   Standard_Boolean isInterior = mySensType == Select3D_TOS_INTERIOR;
434   Handle(Select3D_SensitiveTriangulation) aNewEntity =
435     new Select3D_SensitiveTriangulation (myOwnerId, myTriangul, myInitLocation, myFreeEdges, myCDG3D, isInterior);
436
437   return aNewEntity;
438 }
439
440 //=======================================================================
441 // function : applyTransformation
442 // purpose  : Inner function for transformation application to bounding
443 //            box of the triangulation
444 //=======================================================================
445 Select3D_BndBox3d Select3D_SensitiveTriangulation::applyTransformation()
446 {
447   if (!HasInitLocation())
448     return myBndBox;
449
450   Select3D_BndBox3d aBndBox;
451   for (Standard_Integer aX = 0; aX <=1; ++aX)
452   {
453     for (Standard_Integer aY = 0; aY <=1; ++aY)
454     {
455       for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
456       {
457         gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
458                                  aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
459                                  aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
460         aVertex.Transform (myInitLocation.Transformation());
461         aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
462       }
463     }
464   }
465
466   return aBndBox;
467 }
468
469 //=======================================================================
470 // function : BoundingBox
471 // purpose  : Returns bounding box of the triangulation. If location
472 //            transformation is set, it will be applied
473 //=======================================================================
474 Select3D_BndBox3d Select3D_SensitiveTriangulation::BoundingBox()
475 {
476   if (!myBndBox.IsValid())
477   {
478     computeBoundingBox();
479   }
480   return applyTransformation();
481 }
482
483 // =======================================================================
484 // function : computeBoundingBox
485 // purpose  :
486 // =======================================================================
487 void Select3D_SensitiveTriangulation::computeBoundingBox()
488 {
489   myBndBox.Clear();
490
491   if (myTriangul->HasCachedMinMax())
492   {
493     // Use cached MeshData_Data bounding box if it exists
494     Bnd_Box aCachedBox = myTriangul->CachedMinMax();
495     myBndBox.Add (SelectMgr_Vec3 (aCachedBox.CornerMin().X(),
496                                   aCachedBox.CornerMin().Y(),
497                                   aCachedBox.CornerMin().Z()));
498     myBndBox.Add (SelectMgr_Vec3 (aCachedBox.CornerMax().X(),
499                                   aCachedBox.CornerMax().Y(),
500                                   aCachedBox.CornerMax().Z()));
501     return;
502   }
503   else if (myTriangul->HasGeometry())
504   {
505     for (Standard_Integer aNodeIdx = 1; aNodeIdx <= myTriangul->NbNodes(); ++aNodeIdx)
506     {
507       const gp_Pnt aNode = myTriangul->Node (aNodeIdx);
508       myBndBox.Add (SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z()));
509     }
510   }
511 }
512
513 //=======================================================================
514 // function : CenterOfGeometry
515 // purpose  : Returns center of triangulation. If location transformation
516 //            is set, it will be applied
517 //=======================================================================
518 gp_Pnt Select3D_SensitiveTriangulation::CenterOfGeometry() const
519 {
520   return myCDG3D;
521 }
522
523 //=======================================================================
524 // function : NbSubElements
525 // purpose  : Returns the amount of nodes in triangulation
526 //=======================================================================
527 Standard_Integer Select3D_SensitiveTriangulation::NbSubElements() const
528 {
529   return myTriangul->NbNodes();
530 }
531
532 //=======================================================================
533 //function : HasInitLocation
534 //purpose  :
535 //=======================================================================
536 Standard_Boolean Select3D_SensitiveTriangulation::HasInitLocation() const
537 {
538   return !myInitLocation.IsIdentity();
539 }
540
541 //=======================================================================
542 //function : InvInitLocation
543 //purpose  :
544 //=======================================================================
545 gp_GTrsf Select3D_SensitiveTriangulation::InvInitLocation() const
546 {
547   return myInvInitLocation;
548 }
549
550 // =======================================================================
551 // function : DumpJson
552 // purpose  :
553 // =======================================================================
554 void Select3D_SensitiveTriangulation::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
555 {
556   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
557   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
558
559   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myTriangul.get())
560   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myInitLocation)
561   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, mySensType)
562   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPrimitivesNb)
563   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
564 }