0029938: Visualization - SelectMgr_ViewerSelector::PickedPoint() should return point...
[occt.git] / src / SelectMgr / SelectMgr_RectangularFrustum.cxx
index ccc4868..8d1b856 100644 (file)
@@ -24,7 +24,7 @@
 // =======================================================================
 void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegPnt1,
                                                            const gp_Pnt& theSegPnt2,
-                                                           Standard_Real& theDepth)
+                                                           SelectBasics_PickResult& thePickResult)
 {
   gp_XYZ anU = theSegPnt2.XYZ() - theSegPnt1.XYZ();
   gp_XYZ aV = myViewRayDir.XYZ();
@@ -70,17 +70,32 @@ void SelectMgr_RectangularFrustum::segmentSegmentDistance (const gp_Pnt& theSegP
   }
   aTc = (Abs (aTd) < gp::Resolution() ? 0.0 : aTn / aTd);
 
-  gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTc;
-  theDepth = myNearPickedPnt.Distance (aClosestPnt) * myScale;
+  const gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTc;
+  thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
+
+  const gp_Vec aPickedVec = aClosestPnt.XYZ() - theSegPnt1.XYZ();
+  const gp_Vec aFigureVec = theSegPnt2.XYZ()  - theSegPnt1.XYZ();
+  const Standard_Real aPickedVecMod = aPickedVec.Magnitude();
+  const Standard_Real aFigureVecMod = aFigureVec.Magnitude();
+  if (aPickedVecMod <= gp::Resolution()
+   || aFigureVecMod <= gp::Resolution())
+  {
+    thePickResult.SetPickedPoint (aClosestPnt);
+    return;
+  }
+
+  const Standard_Real aCosOfAngle = aFigureVec.Dot (aPickedVec) / (aPickedVecMod * aFigureVecMod);
+  const Standard_Real aSegPntShift = Min(aFigureVecMod, Max(0.0, aCosOfAngle * aPickedVecMod));
+  thePickResult.SetPickedPoint (theSegPnt1.XYZ() + aFigureVec.XYZ() * (aSegPntShift / aFigureVecMod));
 }
 
 // =======================================================================
 // function : segmentPlaneIntersection
 // purpose  :
 // =======================================================================
-void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePlane,
+bool SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePlane,
                                                              const gp_Pnt& thePntOnPlane,
-                                                             Standard_Real& theDepth)
+                                                             SelectBasics_PickResult& thePickResult)
 {
   gp_XYZ anU = myViewRayDir.XYZ();
   gp_XYZ aW = myNearPickedPnt.XYZ() - thePntOnPlane.XYZ();
@@ -91,25 +106,26 @@ void SelectMgr_RectangularFrustum::segmentPlaneIntersection (const gp_Vec& thePl
   {
     if (Abs (aN) < Precision::Angular())
     {
-      theDepth = DBL_MAX;
-      return;
+      thePickResult.Invalidate();
+      return false;
     }
     else
     {
-      theDepth = DBL_MAX;
-      return;
+      thePickResult.Invalidate();
+      return false;
     }
   }
 
   Standard_Real aParam = aN / aD;
   if (aParam < 0.0 || aParam > 1.0)
   {
-    theDepth = DBL_MAX;
-    return;
+    thePickResult.Invalidate();
+    return false;
   }
 
   gp_Pnt aClosestPnt = myNearPickedPnt.XYZ() + anU * aParam;
-  theDepth = myNearPickedPnt.Distance (aClosestPnt) * myScale;
+  thePickResult.SetDepth (myNearPickedPnt.Distance (aClosestPnt) * myScale);
+  return true;
 }
 
 namespace
@@ -425,7 +441,7 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& t
 // =======================================================================
 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& theBoxMin,
                                                          const SelectMgr_Vec3& theBoxMax,
-                                                         Standard_Real& theDepth)
+                                                         SelectBasics_PickResult& thePickResult)
 {
   if (!hasOverlap (theBoxMin, theBoxMax))
     return Standard_False;
@@ -435,9 +451,9 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& t
   aNearestPnt.SetY (Max (Min (myNearPickedPnt.Y(), theBoxMax.y()), theBoxMin.y()));
   aNearestPnt.SetZ (Max (Min (myNearPickedPnt.Z(), theBoxMax.z()), theBoxMin.z()));
 
-  theDepth = aNearestPnt.Distance (myNearPickedPnt);
+  thePickResult.SetDepth (aNearestPnt.Distance (myNearPickedPnt));
 
-  return isViewClippingOk (theDepth);
+  return isViewClippingOk (thePickResult);
 }
 
 // =======================================================================
@@ -445,7 +461,7 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const SelectMgr_Vec3& t
 // purpose  : Intersection test between defined volume and given point
 // =======================================================================
 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
-                                                         Standard_Real& theDepth)
+                                                         SelectBasics_PickResult& thePickResult)
 {
   if (!hasOverlap (thePnt))
     return Standard_False;
@@ -454,9 +470,10 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt,
   gp_Pnt aDetectedPnt =
     myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * (aV.Dot (myViewRayDir.XYZ()) / myViewRayDir.Dot (myViewRayDir));
 
-  theDepth = aDetectedPnt.Distance (myNearPickedPnt) * myScale;
+  thePickResult.SetDepth (aDetectedPnt.Distance (myNearPickedPnt) * myScale);
+  thePickResult.SetPickedPoint (thePnt);
 
-  return isViewClippingOk (theDepth);
+  return isViewClippingOk (thePickResult);
 }
 
 // =======================================================================
@@ -474,15 +491,14 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt)
 // =======================================================================
 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
                                                          const gp_Pnt& thePnt2,
-                                                         Standard_Real& theDepth)
+                                                         SelectBasics_PickResult& thePickResult)
 {
-  theDepth = -DBL_MAX;
   if (!hasOverlap (thePnt1, thePnt2))
     return Standard_False;
 
-  segmentSegmentDistance (thePnt1, thePnt2, theDepth);
+  segmentSegmentDistance (thePnt1, thePnt2, thePickResult);
 
-  return isViewClippingOk (theDepth);
+  return isViewClippingOk (thePickResult);
 }
 
 // =======================================================================
@@ -494,12 +510,13 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
 // =======================================================================
 Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const TColgp_Array1OfPnt& theArrayOfPnts,
                                                          Select3D_TypeOfSensitivity theSensType,
-                                                         Standard_Real& theDepth)
+                                                         SelectBasics_PickResult& thePickResult)
 {
   if (theSensType == Select3D_TOS_BOUNDARY)
   {
     Standard_Integer aMatchingSegmentsNb = -1;
-    theDepth = DBL_MAX;
+    SelectBasics_PickResult aPickResult;
+    thePickResult.Invalidate();
     const Standard_Integer aLower  = theArrayOfPnts.Lower();
     const Standard_Integer anUpper = theArrayOfPnts.Upper();
     for (Standard_Integer aPntIter = aLower; aPntIter <= anUpper; ++aPntIter)
@@ -509,9 +526,8 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const TColgp_Array1OfPn
       if (hasOverlap (aStartPnt, aEndPnt))
       {
         aMatchingSegmentsNb++;
-        Standard_Real aSegmentDepth = RealLast();
-        segmentSegmentDistance (aStartPnt, aEndPnt, aSegmentDepth);
-        theDepth = Min (theDepth, aSegmentDepth);
+        segmentSegmentDistance (aStartPnt, aEndPnt, aPickResult);
+        thePickResult = SelectBasics_PickResult::Min (thePickResult, aPickResult);
       }
     }
 
@@ -521,15 +537,16 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const TColgp_Array1OfPn
   else if (theSensType == Select3D_TOS_INTERIOR)
   {
     gp_Vec aPolyNorm (gp_XYZ (RealLast(), RealLast(), RealLast()));
-    if (!hasOverlap (theArrayOfPnts, aPolyNorm))
+    if (!hasOverlap (theArrayOfPnts, aPolyNorm)
+     || !segmentPlaneIntersection (aPolyNorm,
+                                   theArrayOfPnts.First(),
+                                   thePickResult))
+    {
       return Standard_False;
-
-    segmentPlaneIntersection (aPolyNorm,
-                              theArrayOfPnts.Value (theArrayOfPnts.Lower()),
-                              theDepth);
+    }
   }
 
-  return isViewClippingOk (theDepth);
+  return isViewClippingOk (thePickResult);
 }
 
 // =======================================================================
@@ -543,13 +560,13 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
                                                          const gp_Pnt& thePnt2,
                                                          const gp_Pnt& thePnt3,
                                                          Select3D_TypeOfSensitivity theSensType,
-                                                         Standard_Real& theDepth)
+                                                         SelectBasics_PickResult& thePickResult)
 {
   if (theSensType == Select3D_TOS_BOUNDARY)
   {
     const gp_Pnt aPntsArrayBuf[4] = { thePnt1, thePnt2, thePnt3, thePnt1 };
     const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 4);
-    return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, theDepth);
+    return Overlaps (aPntsArray, Select3D_TOS_BOUNDARY, thePickResult);
   }
   else if (theSensType == Select3D_TOS_INTERIOR)
   {
@@ -568,16 +585,15 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
       // handle degenerated triangles: in this case, there is no possible way to detect overlap correctly.
       if (aTriangleNormal.SquareMagnitude() < gp::Resolution())
       {
-        theDepth = std::numeric_limits<Standard_Real>::max();
         return Standard_False;
       }
 
       // handle the case when triangle normal and selecting frustum direction are orthogonal: for this case, overlap
       // is detected correctly, and distance to triangle's plane can be measured as distance to its arbitrary vertex.
       const gp_XYZ aDiff = myNearPickedPnt.XYZ() - thePnt1.XYZ();
-      theDepth = aTriangleNormal.Dot (aDiff) * myScale;
-
-      return isViewClippingOk (theDepth);
+      thePickResult.SetDepth (aTriangleNormal.Dot (aDiff) * myScale);
+      thePickResult.SetPickedPoint (thePnt1);
+      return isViewClippingOk (thePickResult);
     }
 
     gp_XYZ anEdge = (thePnt1.XYZ() - myNearPickedPnt.XYZ()) * (1.0 / anAlpha);
@@ -589,20 +605,18 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
     Standard_Real anU = aVec.Dot (aTrEdges[2]);
     Standard_Real aV  = aVec.Dot (aTrEdges[0]);
 
-    Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
-
+    const Standard_Boolean isInterior = (aTime >= 0.0) && (anU >= 0.0) && (aV >= 0.0) && (anU + aV <= 1.0);
+    const gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime;
     if (isInterior)
     {
-      gp_Pnt aDetectedPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime;
-      theDepth = myNearPickedPnt.Distance (aDetectedPnt) * myScale;
-
-      return isViewClippingOk (theDepth);
+      thePickResult.SetDepth (myNearPickedPnt.Distance (aPtOnPlane) * myScale);
+      thePickResult.SetPickedPoint (aPtOnPlane);
+      return isViewClippingOk (thePickResult);
     }
 
     gp_Pnt aPnts[3] = {thePnt1, thePnt2, thePnt3};
     Standard_Real aMinDist = RealLast();
     Standard_Integer aNearestEdgeIdx = -1;
-    gp_Pnt aPtOnPlane = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aTime;
     for (Standard_Integer anEdgeIdx = 0; anEdgeIdx < 3; ++anEdgeIdx)
     {
       gp_XYZ aW = aPtOnPlane.XYZ() - aPnts[anEdgeIdx].XYZ();
@@ -614,10 +628,10 @@ Standard_Boolean SelectMgr_RectangularFrustum::Overlaps (const gp_Pnt& thePnt1,
         aNearestEdgeIdx = anEdgeIdx;
       }
     }
-    segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], theDepth);
+    segmentSegmentDistance (aPnts[aNearestEdgeIdx], aPnts[(aNearestEdgeIdx + 1) % 3], thePickResult);
   }
 
-  return isViewClippingOk (theDepth);
+  return isViewClippingOk (thePickResult);
 }
 
 // =======================================================================
@@ -757,10 +771,10 @@ void SelectMgr_RectangularFrustum::SetViewClipping (const Handle(Graphic3d_Seque
 // function : isViewClippingOk
 // purpose  :
 // =======================================================================
-Standard_Boolean SelectMgr_RectangularFrustum::isViewClippingOk (const Standard_Real theDepth) const
+Standard_Boolean SelectMgr_RectangularFrustum::isViewClippingOk (const SelectBasics_PickResult& thePickResult) const
 {
   return !myIsViewClipEnabled
-      || !myViewClipRange.IsClipped (theDepth);
+      || !myViewClipRange.IsClipped (thePickResult.Depth());
 }
 
 // =======================================================================