1 // Copyright (c) 2021 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13 
14 #include <SelectMgr_AxisIntersector.hxx>
15 
16 #include <Bnd_Range.hxx>
17 #include <BVH_Tools.hxx>
18 #include <Precision.hxx>
19 #include <SelectBasics_PickResult.hxx>
20 #include <SelectMgr_ViewClipRange.hxx>
21 
22 // =======================================================================
23 // function : Constructor
24 // purpose  :
25 // =======================================================================
SelectMgr_AxisIntersector()26 SelectMgr_AxisIntersector::SelectMgr_AxisIntersector()
27 {
28   //
29 }
30 
31 // =======================================================================
32 // function : ~SelectMgr_AxisIntersector
33 // purpose  :
34 // =======================================================================
~SelectMgr_AxisIntersector()35 SelectMgr_AxisIntersector::~SelectMgr_AxisIntersector()
36 {
37   //
38 }
39 
40 // =======================================================================
41 // function : Init
42 // purpose  :
43 // =======================================================================
Init(const gp_Ax1 & theAxis)44 void SelectMgr_AxisIntersector::Init (const gp_Ax1& theAxis)
45 {
46   mySelectionType = SelectMgr_SelectionType_Point;
47   myAxis = theAxis;
48 }
49 
50 // =======================================================================
51 // function : Build
52 // purpose  :
53 // =======================================================================
Build()54 void SelectMgr_AxisIntersector::Build()
55 {
56 }
57 
58 //=======================================================================
59 // function : SetCamera
60 // purpose  :
61 //=======================================================================
SetCamera(const Handle (Graphic3d_Camera)&)62 void SelectMgr_AxisIntersector::SetCamera (const Handle(Graphic3d_Camera)&)
63 {
64 }
65 
66 // =======================================================================
67 // function : ScaleAndTransform
68 // purpose  :
69 // =======================================================================
Handle(SelectMgr_BaseIntersector)70 Handle(SelectMgr_BaseIntersector) SelectMgr_AxisIntersector::ScaleAndTransform (const Standard_Integer theScaleFactor,
71                                                                                 const gp_GTrsf& theTrsf,
72                                                                                 const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
73 {
74   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
75     "Error! SelectMgr_AxisIntersector::ScaleAndTransform() should be called after selection axis initialization");
76 
77   (void )theScaleFactor;
78   (void )theBuilder;
79   if (theTrsf.Form() == gp_Identity)
80   {
81     return new SelectMgr_AxisIntersector();
82   }
83 
84   gp_Pnt aTransformedLoc = myAxis.Location();
85   theTrsf.Transforms (aTransformedLoc.ChangeCoord());
86   gp_XYZ aTransformedDir = myAxis.Direction().XYZ();
87   gp_GTrsf aTrsf = theTrsf;
88   aTrsf.SetTranslationPart (gp_XYZ(0., 0., 0.));
89   aTrsf.Transforms (aTransformedDir);
90 
91   Handle(SelectMgr_AxisIntersector) aRes = new SelectMgr_AxisIntersector();
92   aRes->myAxis = gp_Ax1(aTransformedLoc, gp_Dir(aTransformedDir));
93   aRes->mySelectionType = mySelectionType;
94   return aRes;
95 }
96 
97 // =======================================================================
98 // function : hasIntersection
99 // purpose  :
100 // =======================================================================
hasIntersection(const SelectMgr_Vec3 & theBoxMin,const SelectMgr_Vec3 & theBoxMax,Standard_Real & theTimeEnter,Standard_Real & theTimeLeave) const101 Standard_Boolean SelectMgr_AxisIntersector::hasIntersection (const SelectMgr_Vec3& theBoxMin,
102                                                              const SelectMgr_Vec3& theBoxMax,
103                                                              Standard_Real& theTimeEnter,
104                                                              Standard_Real& theTimeLeave) const
105 {
106   const gp_Pnt& anAxisLoc = myAxis.Location();
107   const gp_Dir& anAxisDir = myAxis.Direction();
108   BVH_Ray<Standard_Real, 3> aRay(SelectMgr_Vec3(anAxisLoc.X(), anAxisLoc.Y(), anAxisLoc.Z()),
109                                  SelectMgr_Vec3(anAxisDir.X(), anAxisDir.Y(), anAxisDir.Z()));
110   if (!BVH_Tools<Standard_Real, 3>::RayBoxIntersection (aRay, theBoxMin, theBoxMax, theTimeEnter, theTimeLeave))
111   {
112     return Standard_False;
113   }
114   return Standard_True;
115 }
116 
117 // =======================================================================
118 // function : hasIntersection
119 // purpose  :
120 // =======================================================================
hasIntersection(const gp_Pnt & thePnt,Standard_Real & theDepth) const121 Standard_Boolean SelectMgr_AxisIntersector::hasIntersection (const gp_Pnt& thePnt,
122                                                              Standard_Real& theDepth) const
123 {
124   const gp_Pnt& anAxisLoc = myAxis.Location();
125   const gp_Dir& anAxisDir = myAxis.Direction();
126 
127   // Check that vectors are co-directed (thePnt lies on this axis)
128   gp_Dir aDirToPnt(thePnt.XYZ() - anAxisLoc.XYZ());
129   if (!anAxisDir.IsEqual (aDirToPnt, Precision::Angular()))
130   {
131     return Standard_False;
132   }
133   theDepth = anAxisLoc.Distance (thePnt);
134   return Standard_True;
135 }
136 
137 // =======================================================================
138 // function : raySegmentDistance
139 // purpose  :
140 // =======================================================================
raySegmentDistance(const gp_Pnt & theSegPnt1,const gp_Pnt & theSegPnt2,SelectBasics_PickResult & thePickResult) const141 Standard_Boolean SelectMgr_AxisIntersector::raySegmentDistance (const gp_Pnt& theSegPnt1,
142                                                                 const gp_Pnt& theSegPnt2,
143                                                                 SelectBasics_PickResult& thePickResult) const
144 {
145   const gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ();
146   const gp_XYZ aV = myAxis.Direction().XYZ();
147   const gp_XYZ aW = theSegPnt1.XYZ() - myAxis.Location().XYZ();
148 
149   const gp_XYZ anUVNormVec = aV.Crossed (anU);
150   const Standard_Real anUVNormVecMod = anUVNormVec.Modulus();
151   if (anUVNormVecMod <= Precision::Confusion())
152   {
153     // Lines have no intersection
154     thePickResult.Invalidate();
155     return false;
156   }
157 
158   const gp_XYZ anUWNormVec = aW.Crossed (anU);
159   const Standard_Real anUWNormVecMod = anUWNormVec.Modulus();
160   if (anUWNormVecMod <= Precision::Confusion())
161   {
162     // Lines have no intersection
163     thePickResult.Invalidate();
164     return false;
165   }
166 
167   const Standard_Real aParam = anUWNormVec.Dot (anUVNormVec) / anUVNormVec.SquareModulus();
168   if (aParam < 0.0)
169   {
170     // Intersection is out of axis start point
171     thePickResult.Invalidate();
172     return false;
173   }
174 
175   const gp_XYZ anIntersectPnt = myAxis.Location().XYZ() + aV * aParam;
176   if ((anIntersectPnt - theSegPnt1.XYZ()).Modulus() +
177       (anIntersectPnt - theSegPnt2.XYZ()).Modulus() >
178        anU.Modulus() + Precision::Confusion())
179   {
180     // Intersection point doesn't lie on the segment
181     thePickResult.Invalidate();
182     return false;
183   }
184 
185   thePickResult.SetDepth (myAxis.Location().Distance (anIntersectPnt));
186   thePickResult.SetPickedPoint (anIntersectPnt);
187   return true;
188 }
189 
190 // =======================================================================
191 // function : rayPlaneIntersection
192 // purpose  :
193 // =======================================================================
rayPlaneIntersection(const gp_Vec & thePlane,const gp_Pnt & thePntOnPlane,SelectBasics_PickResult & thePickResult) const194 bool SelectMgr_AxisIntersector::rayPlaneIntersection (const gp_Vec& thePlane,
195                                                       const gp_Pnt& thePntOnPlane,
196                                                       SelectBasics_PickResult& thePickResult) const
197 {
198   gp_XYZ anU = myAxis.Direction().XYZ();
199   gp_XYZ aW = myAxis.Location().XYZ() - thePntOnPlane.XYZ();
200   Standard_Real aD = thePlane.Dot (anU);
201   Standard_Real aN = -thePlane.Dot (aW);
202 
203   if (Abs (aD) < Precision::Confusion())
204   {
205     thePickResult.Invalidate();
206     return false;
207   }
208 
209   Standard_Real aParam = aN / aD;
210   if (aParam < 0.0)
211   {
212     thePickResult.Invalidate();
213     return false;
214   }
215 
216   gp_Pnt aClosestPnt = myAxis.Location().XYZ() + anU * aParam;
217   thePickResult.SetDepth (myAxis.Location().Distance (aClosestPnt));
218   thePickResult.SetPickedPoint (aClosestPnt);
219   return true;
220 }
221 
222 // =======================================================================
223 // function : OverlapsBox
224 // purpose  :
225 // =======================================================================
OverlapsBox(const SelectMgr_Vec3 & theBoxMin,const SelectMgr_Vec3 & theBoxMax,Standard_Boolean * theInside) const226 Standard_Boolean SelectMgr_AxisIntersector::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
227                                                          const SelectMgr_Vec3& theBoxMax,
228                                                          Standard_Boolean*     theInside) const
229 {
230   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
231     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
232 
233   (void )theInside;
234   Standard_Real aTimeEnter, aTimeLeave;
235   if (!hasIntersection (theBoxMin, theBoxMax, aTimeEnter, aTimeLeave))
236   {
237     return Standard_False;
238   }
239   if (theInside != NULL)
240   {
241     *theInside &= (aTimeEnter >= 0.0);
242   }
243   return Standard_True;
244 }
245 
246 // =======================================================================
247 // function : OverlapsBox
248 // purpose  :
249 // =======================================================================
OverlapsBox(const SelectMgr_Vec3 & theBoxMin,const SelectMgr_Vec3 & theBoxMax,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const250 Standard_Boolean SelectMgr_AxisIntersector::OverlapsBox (const SelectMgr_Vec3& theBoxMin,
251                                                          const SelectMgr_Vec3& theBoxMax,
252                                                          const SelectMgr_ViewClipRange& theClipRange,
253                                                          SelectBasics_PickResult& thePickResult) const
254 {
255   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
256     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
257 
258   Standard_Real aTimeEnter, aTimeLeave;
259   if (!hasIntersection (theBoxMin, theBoxMax, aTimeEnter, aTimeLeave))
260   {
261     return Standard_False;
262   }
263 
264   Standard_Real aDepth = 0.0;
265   Bnd_Range aRange(Max (aTimeEnter, 0.0), aTimeLeave);
266   aRange.GetMin (aDepth);
267 
268   if (!theClipRange.GetNearestDepth (aRange, aDepth))
269   {
270     return Standard_False;
271   }
272 
273   thePickResult.SetDepth (aDepth);
274 
275   return Standard_True;
276 }
277 
278 // =======================================================================
279 // function : OverlapsPoint
280 // purpose  :
281 // =======================================================================
OverlapsPoint(const gp_Pnt & thePnt,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const282 Standard_Boolean SelectMgr_AxisIntersector::OverlapsPoint (const gp_Pnt& thePnt,
283                                                            const SelectMgr_ViewClipRange& theClipRange,
284                                                            SelectBasics_PickResult& thePickResult) const
285 {
286   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
287     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
288 
289   Standard_Real aDepth = 0.0;
290   if (!hasIntersection (thePnt, aDepth))
291   {
292     return Standard_False;
293   }
294 
295   thePickResult.SetDepth (aDepth);
296   thePickResult.SetPickedPoint (thePnt);
297 
298   return !theClipRange.IsClipped (thePickResult.Depth());
299 }
300 
301 // =======================================================================
302 // function : OverlapsPoint
303 // purpose  :
304 // =======================================================================
OverlapsPoint(const gp_Pnt & thePnt) const305 Standard_Boolean SelectMgr_AxisIntersector::OverlapsPoint (const gp_Pnt& thePnt) const
306 {
307   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
308     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
309 
310   Standard_Real aDepth = 0.0;
311   return hasIntersection (thePnt, aDepth);
312 }
313 
314 // =======================================================================
315 // function : OverlapsSegment
316 // purpose  :
317 // =======================================================================
OverlapsSegment(const gp_Pnt & thePnt1,const gp_Pnt & thePnt2,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const318 Standard_Boolean SelectMgr_AxisIntersector::OverlapsSegment (const gp_Pnt& thePnt1,
319                                                              const gp_Pnt& thePnt2,
320                                                              const SelectMgr_ViewClipRange& theClipRange,
321                                                              SelectBasics_PickResult& thePickResult) const
322 {
323   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
324     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
325 
326   if (!raySegmentDistance (thePnt1, thePnt2, thePickResult))
327   {
328     return Standard_False;
329   }
330 
331   return !theClipRange.IsClipped (thePickResult.Depth());
332 }
333 
334 // =======================================================================
335 // function : OverlapsPolygon
336 // purpose  :
337 // =======================================================================
OverlapsPolygon(const TColgp_Array1OfPnt & theArrayOfPnts,Select3D_TypeOfSensitivity theSensType,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const338 Standard_Boolean SelectMgr_AxisIntersector::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts,
339                                                              Select3D_TypeOfSensitivity theSensType,
340                                                              const SelectMgr_ViewClipRange& theClipRange,
341                                                              SelectBasics_PickResult& thePickResult) const
342 {
343   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
344     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
345 
346   if (theSensType == Select3D_TOS_BOUNDARY)
347   {
348     Standard_Integer aMatchingSegmentsNb = -1;
349     SelectBasics_PickResult aPickResult;
350     thePickResult.Invalidate();
351     const Standard_Integer aLower  = theArrayOfPnts.Lower();
352     const Standard_Integer anUpper = theArrayOfPnts.Upper();
353     for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
354     {
355       const gp_Pnt& aStartPnt = theArrayOfPnts.Value (aPntIter);
356       const gp_Pnt& aEndPnt   = theArrayOfPnts.Value (aPntIter == anUpper ? aLower : (aPntIter + 1));
357       if (raySegmentDistance (aStartPnt, aEndPnt, aPickResult))
358       {
359         aMatchingSegmentsNb++;
360         thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
361       }
362     }
363 
364     if (aMatchingSegmentsNb == -1)
365     {
366       return Standard_False;
367     }
368   }
369   else if (theSensType == Select3D_TOS_INTERIOR)
370   {
371     Standard_Integer aStartIdx = theArrayOfPnts.Lower();
372     const gp_XYZ& aPnt1 = theArrayOfPnts.Value (aStartIdx).XYZ();
373     const gp_XYZ& aPnt2 = theArrayOfPnts.Value (aStartIdx + 1).XYZ();
374     const gp_XYZ& aPnt3 = theArrayOfPnts.Value (aStartIdx + 2).XYZ();
375     const gp_XYZ aVec1 = aPnt1 - aPnt2;
376     const gp_XYZ aVec2 = aPnt3 - aPnt2;
377     gp_Vec aPolyNorm = aVec2.Crossed (aVec1);
378     if (aPolyNorm.Magnitude() <= Precision::Confusion())
379     {
380       // treat degenerated polygon as point
381       return OverlapsPoint (theArrayOfPnts.First(), theClipRange, thePickResult);
382     }
383     else if (!rayPlaneIntersection (aPolyNorm, theArrayOfPnts.First(), thePickResult))
384     {
385       return Standard_False;
386     }
387   }
388 
389   return !theClipRange.IsClipped (thePickResult.Depth());
390 }
391 
392 // =======================================================================
393 // function : OverlapsTriangle
394 // purpose  :
395 // =======================================================================
OverlapsTriangle(const gp_Pnt & thePnt1,const gp_Pnt & thePnt2,const gp_Pnt & thePnt3,Select3D_TypeOfSensitivity theSensType,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const396 Standard_Boolean SelectMgr_AxisIntersector::OverlapsTriangle (const gp_Pnt& thePnt1,
397                                                               const gp_Pnt& thePnt2,
398                                                               const gp_Pnt& thePnt3,
399                                                               Select3D_TypeOfSensitivity theSensType,
400                                                               const SelectMgr_ViewClipRange& theClipRange,
401                                                               SelectBasics_PickResult& thePickResult) const
402 {
403   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
404     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
405 
406   if (theSensType == Select3D_TOS_BOUNDARY)
407   {
408     const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 };
409     const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4);
410     return OverlapsPolygon (aPntsArray, Select3D_TOS_BOUNDARY, theClipRange, thePickResult);
411   }
412   else if (theSensType == Select3D_TOS_INTERIOR)
413   {
414     gp_Vec aTriangleNormal (gp_XYZ (RealLast(), RealLast(), RealLast()));
415     const gp_XYZ aTrEdges[3] = { thePnt2.XYZ() - thePnt1.XYZ(),
416                                  thePnt3.XYZ() - thePnt2.XYZ(),
417                                  thePnt1.XYZ() - thePnt3.XYZ() };
418     aTriangleNormal = aTrEdges[2].Crossed (aTrEdges[0]);
419 	  if (aTriangleNormal.SquareMagnitude() < gp::Resolution())
420     {
421       // consider degenerated triangle as point or segment
422       return aTrEdges[0].SquareModulus() > gp::Resolution()
423            ? OverlapsSegment (thePnt1, thePnt2, theClipRange, thePickResult)
424            : (aTrEdges[1].SquareModulus() > gp::Resolution()
425             ? OverlapsSegment (thePnt2, thePnt3, theClipRange, thePickResult)
426             : OverlapsPoint (thePnt1, theClipRange, thePickResult));
427     }
428 
429     const gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
430     const Standard_Real anAlpha = aTriangleNormal.XYZ().Dot (myAxis.Direction().XYZ());
431     if (Abs (anAlpha) < gp::Resolution())
432     {
433       // handle the case when triangle normal and selecting frustum direction are orthogonal
434       SelectBasics_PickResult aPickResult;
435       thePickResult.Invalidate();
436       for (Standard_Integer anEdgeIter = 0; anEdgeIter < 3; ++anEdgeIter)
437       {
438         const gp_Pnt& aStartPnt = aPnts[anEdgeIter];
439         const gp_Pnt& anEndPnt  = aPnts[anEdgeIter < 2 ? anEdgeIter + 1 : 0];
440         if (raySegmentDistance (aStartPnt, anEndPnt, aPickResult))
441         {
442           thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
443         }
444       }
445       thePickResult.SetSurfaceNormal (aTriangleNormal);
446       return thePickResult.IsValid()
447          && !theClipRange.IsClipped (thePickResult.Depth());
448     }
449 
450     // check if intersection point belongs to triangle's interior part
451     const gp_XYZ anEdge = (thePnt1.XYZ() - myAxis.Location().XYZ()) * (1.0 / anAlpha);
452 
453     const Standard_Real aTime = aTriangleNormal.Dot (anEdge);
454     const gp_XYZ aVec = myAxis.Direction().XYZ().Crossed (anEdge);
455     const Standard_Real anU = aVec.Dot (aTrEdges[2]);
456     const Standard_Real aV  = aVec.Dot (aTrEdges[0]);
457 
458     const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
459     const gp_Pnt aPtOnPlane = myAxis.Location().XYZ() + myAxis.Direction().XYZ() * aTime;
460     if (isInterior)
461     {
462       thePickResult.SetDepth (myAxis.Location().Distance (aPtOnPlane));
463       thePickResult.SetPickedPoint (aPtOnPlane);
464       thePickResult.SetSurfaceNormal (aTriangleNormal);
465       return !theClipRange.IsClipped (thePickResult.Depth());
466     }
467 
468     Standard_Real aMinDist = RealLast();
469     Standard_Integer aNearestEdgeIdx1 = -1;
470     for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
471     {
472       gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ();
473       Standard_Real aCoef = aTrEdges[anEdgeIdx].Dot (aW) / aTrEdges[anEdgeIdx].Dot (aTrEdges[anEdgeIdx]);
474       Standard_Real aDist = aPtOnPlane.Distance (aPnts[anEdgeIdx].XYZ() + aCoef * aTrEdges[anEdgeIdx]);
475       if (aDist < aMinDist)
476       {
477         aMinDist = aDist;
478         aNearestEdgeIdx1 = anEdgeIdx;
479       }
480     }
481     Standard_Integer aNearestEdgeIdx2 = (aNearestEdgeIdx1 + 1) % 3;
482     const gp_Vec aVec12 (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2]);
483     if (aVec12.SquareMagnitude() > gp::Resolution()
484      && myAxis.Direction().IsParallel (aVec12, Precision::Angular()))
485     {
486       aNearestEdgeIdx2 = aNearestEdgeIdx1 == 0 ? 2 : aNearestEdgeIdx1 - 1;
487     }
488     if (raySegmentDistance (aPnts[aNearestEdgeIdx1], aPnts[aNearestEdgeIdx2], thePickResult))
489     {
490       thePickResult.SetSurfaceNormal (aTriangleNormal);
491     }
492   }
493 
494   return thePickResult.IsValid()
495      && !theClipRange.IsClipped (thePickResult.Depth());
496 }
497 
498 //=======================================================================
499 // function : OverlapsSphere
500 // purpose  :
501 //=======================================================================
OverlapsSphere(const gp_Pnt & theCenter,const Standard_Real theRadius,Standard_Boolean * theInside) const502 Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
503                                                             const Standard_Real theRadius,
504                                                             Standard_Boolean* theInside) const
505 {
506   Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
507     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
508   (void )theInside;
509   Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
510   if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
511   {
512     return Standard_False;
513   }
514   if (theInside != NULL)
515   {
516     *theInside &= (aTimeEnter >= 0.0);
517   }
518   return Standard_True;
519 }
520 
521 //=======================================================================
522 // function : OverlapsSphere
523 // purpose  :
524 //=======================================================================
OverlapsSphere(const gp_Pnt & theCenter,const Standard_Real theRadius,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const525 Standard_Boolean SelectMgr_AxisIntersector::OverlapsSphere (const gp_Pnt& theCenter,
526                                                             const Standard_Real theRadius,
527                                                             const SelectMgr_ViewClipRange& theClipRange,
528                                                             SelectBasics_PickResult& thePickResult) const
529 {
530   Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
531     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
532   Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
533   if (!RaySphereIntersection (theCenter, theRadius, myAxis.Location(), myAxis.Direction(), aTimeEnter, aTimeLeave))
534   {
535     return Standard_False;
536   }
537 
538   Standard_Real aDepth = 0.0;
539   Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
540   aRange.GetMin (aDepth);
541   if (!theClipRange.GetNearestDepth (aRange, aDepth))
542   {
543     return Standard_False;
544   }
545 
546   thePickResult.SetDepth (aDepth);
547   return Standard_True;
548 }
549 
550 //=======================================================================
551 // function : OverlapsCylinder
552 // purpose  :
553 //=======================================================================
OverlapsCylinder(const Standard_Real theBottomRad,const Standard_Real theTopRad,const Standard_Real theHeight,const gp_Trsf & theTrsf,const SelectMgr_ViewClipRange & theClipRange,SelectBasics_PickResult & thePickResult) const554 Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
555                                                               const Standard_Real theTopRad,
556                                                               const Standard_Real theHeight,
557                                                               const gp_Trsf& theTrsf,
558                                                               const SelectMgr_ViewClipRange& theClipRange,
559                                                               SelectBasics_PickResult& thePickResult) const
560 {
561   Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
562     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
563   Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
564   gp_Trsf aTrsfInv = theTrsf.Inverted();
565   gp_Pnt  aLoc     = myAxis.Location() .Transformed (aTrsfInv);
566   gp_Dir  aRayDir  = myAxis.Direction().Transformed (aTrsfInv);
567   if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
568   {
569     return false;
570   }
571 
572   Standard_Real aDepth = 0.0;
573   Bnd_Range aRange (Max (aTimeEnter, 0.0), aTimeLeave);
574   aRange.GetMin (aDepth);
575   if (!theClipRange.GetNearestDepth (aRange, aDepth))
576   {
577     return false;
578   }
579   thePickResult.SetDepth (aDepth);
580   return true;
581 }
582 
583 //=======================================================================
584 // function : OverlapsCylinder
585 // purpose  :
586 //=======================================================================
OverlapsCylinder(const Standard_Real theBottomRad,const Standard_Real theTopRad,const Standard_Real theHeight,const gp_Trsf & theTrsf,Standard_Boolean * theInside) const587 Standard_Boolean SelectMgr_AxisIntersector::OverlapsCylinder (const Standard_Real theBottomRad,
588                                                               const Standard_Real theTopRad,
589                                                               const Standard_Real theHeight,
590                                                               const gp_Trsf& theTrsf,
591                                                               Standard_Boolean* theInside)  const
592 {
593   Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point,
594     "Error! SelectMgr_AxisIntersector::Overlaps() should be called after selection axis initialization");
595   Standard_Real aTimeEnter = 0.0, aTimeLeave = 0.0;
596   gp_Trsf aTrsfInv = theTrsf.Inverted();
597   gp_Pnt  aLoc     = myAxis.Location() .Transformed (aTrsfInv);
598   gp_Dir  aRayDir  = myAxis.Direction().Transformed (aTrsfInv);
599   if (!RayCylinderIntersection (theBottomRad, theTopRad, theHeight, aLoc, aRayDir, aTimeEnter, aTimeLeave))
600   {
601     return false;
602   }
603   if (theInside != NULL)
604   {
605     *theInside &= (aTimeEnter >= 0.0);
606   }
607   return true;
608 }
609 
610 //=======================================================================
611 // function : GetNearPnt
612 // purpose  :
613 //=======================================================================
GetNearPnt() const614 const gp_Pnt& SelectMgr_AxisIntersector::GetNearPnt() const
615 {
616   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
617     "Error! SelectMgr_AxisIntersector::GetNearPnt() should be called after selection axis initialization");
618 
619   return myAxis.Location();
620 }
621 
622 //=======================================================================
623 // function : GetFarPnt
624 // purpose  :
625 //=======================================================================
GetFarPnt() const626 const gp_Pnt& SelectMgr_AxisIntersector::GetFarPnt() const
627 {
628   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
629     "Error! SelectMgr_AxisIntersector::GetFarPnt() should be called after selection axis initialization");
630 
631   static gp_Pnt anInfPnt(RealLast(), RealLast(), RealLast());
632   return anInfPnt;
633 }
634 
635 //=======================================================================
636 // function : GetViewRayDirection
637 // purpose  :
638 //=======================================================================
GetViewRayDirection() const639 const gp_Dir& SelectMgr_AxisIntersector::GetViewRayDirection() const
640 {
641   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
642     "Error! SelectMgr_AxisIntersector::GetViewRayDirection() should be called after selection axis initialization");
643 
644   return myAxis.Direction();
645 }
646 
647 // =======================================================================
648 // function : DistToGeometryCenter
649 // purpose  :
650 // =======================================================================
DistToGeometryCenter(const gp_Pnt & theCOG) const651 Standard_Real SelectMgr_AxisIntersector::DistToGeometryCenter (const gp_Pnt& theCOG) const
652 {
653   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
654     "Error! SelectMgr_AxisIntersector::DistToGeometryCenter() should be called after selection axis initialization");
655 
656   return theCOG.Distance (myAxis.Location());
657 }
658 
659 // =======================================================================
660 // function : DetectedPoint
661 // purpose  :
662 // =======================================================================
DetectedPoint(const Standard_Real theDepth) const663 gp_Pnt SelectMgr_AxisIntersector::DetectedPoint (const Standard_Real theDepth) const
664 {
665   Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
666     "Error! SelectMgr_AxisIntersector::DetectedPoint() should be called after selection axis initialization");
667 
668   return myAxis.Location().XYZ() + myAxis.Direction().XYZ() * theDepth;
669 }
670 
671 //=======================================================================
672 //function : DumpJson
673 //purpose  :
674 //=======================================================================
DumpJson(Standard_OStream & theOStream,Standard_Integer theDepth) const675 void SelectMgr_AxisIntersector::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
676 {
677   OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_AxisIntersector)
678   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_BaseIntersector)
679 
680   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAxis)
681 }
682