0031047: Modeling Algorithms - BRepExtrema_DistShapeShape gives wrong result
[occt.git] / src / BRepClass / BRepClass_Intersector.cxx
index 0f09a60..8e0cf6d 100644 (file)
@@ -22,6 +22,7 @@
 #include <BRepClass_Intersector.hxx>
 #include <ElCLib.hxx>
 #include <Extrema_ExtPC2d.hxx>
+#include <GCE2d_MakeSegment.hxx>
 #include <Geom2d_Curve.hxx>
 #include <Geom2d_Line.hxx>
 #include <Geom2dInt_GInter.hxx>
@@ -48,15 +49,225 @@ void RefineTolerance(const TopoDS_Face& aF,
                      const Standard_Real aT,
                      Standard_Real& aTolZ);
 
+static
+Standard_Boolean CheckOn(IntRes2d_IntersectionPoint& thePntInter,
+                         const TopoDS_Face& theF,
+                         const gp_Lin2d& theL,
+                         Geom2dAdaptor_Curve& theCur,
+                         Standard_Real theTolZ,
+                         Standard_Real theFin,
+                         Standard_Real theDeb);
+
+static
+void CheckSkip(Geom2dInt_GInter& theInter,
+               const gp_Lin2d& theL,
+               const BRepClass_Edge& theE,
+               const Handle(Geom2d_Curve)& theC2D,
+               const IntRes2d_Domain& theDL,
+               Geom2dAdaptor_Curve& theCur,
+               const Geom2dAdaptor_Curve& theCGA,
+               Standard_Real theFin,
+               Standard_Real theDeb,
+               Standard_Real theMaxTol,
+               gp_Pnt2d thePdeb,
+               gp_Pnt2d thePfin);
+
+
 //=======================================================================
 //function : BRepClass_Intersector
 //purpose  : 
 //=======================================================================
 
-BRepClass_Intersector::BRepClass_Intersector()
+BRepClass_Intersector::BRepClass_Intersector() : myMaxTolerance(0.1)
+{
+}
+
+//=======================================================================
+//function : CheckOn
+//purpose  :
+//=======================================================================
+Standard_Boolean CheckOn(IntRes2d_IntersectionPoint& thePntInter,
+                         const TopoDS_Face& theF,
+                         const gp_Lin2d& theL,
+                         Geom2dAdaptor_Curve& theCur,
+                         Standard_Real theTolZ,
+                         Standard_Real theFin,
+                         Standard_Real theDeb)
 {
+  Extrema_ExtPC2d anExtPC2d(theL.Location(), theCur);
+  Standard_Real aMinDist = RealLast();
+  Standard_Integer aMinInd = 0;
+  if (anExtPC2d.IsDone())
+  {
+    const Standard_Integer aNbPnts = anExtPC2d.NbExt();
+    for (Standard_Integer i = 1; i <= aNbPnts; ++i)
+    {
+      Standard_Real aDist = anExtPC2d.SquareDistance(i);
+
+      if (aDist < aMinDist)
+      {
+        aMinDist = aDist;
+        aMinInd = i;
+      }
+    }
+  }
+
+  if (aMinInd != 0) {
+    aMinDist = Sqrt(aMinDist);
+  }
+  if (aMinDist <= theTolZ) {
+    gp_Pnt2d aPntExact = (anExtPC2d.Point(aMinInd)).Value();
+    Standard_Real aPar = (anExtPC2d.Point(aMinInd)).Parameter();
+    //
+    RefineTolerance(theF, theCur, aPar, theTolZ);
+    //
+    if (aMinDist <= theTolZ) {
+      IntRes2d_Transition aTrOnLin(IntRes2d_Head);
+      IntRes2d_Position aPosOnCurve = IntRes2d_Middle;
+      if (Abs(aPar - theDeb) <= Precision::Confusion()) {
+        aPosOnCurve = IntRes2d_Head;
+      }
+      else if (Abs(aPar - theFin) <= Precision::Confusion()) {
+        aPosOnCurve = IntRes2d_End;
+      }
+      //
+      IntRes2d_Transition aTrOnCurve(aPosOnCurve);
+      thePntInter = IntRes2d_IntersectionPoint(aPntExact, 0., aPar,
+        aTrOnLin, aTrOnCurve,
+        Standard_False);
+      //
+      return Standard_True;
+    }
+  }
+  return Standard_False;
 }
 
+//=======================================================================
+//function : CheckSkip
+//purpose  :
+//=======================================================================
+void CheckSkip(Geom2dInt_GInter& theInter,
+               const gp_Lin2d& theL,
+               const BRepClass_Edge& theE,
+               const Handle(Geom2d_Curve)& theC2D,
+               const IntRes2d_Domain& theDL,
+               Geom2dAdaptor_Curve& theCur,
+               const Geom2dAdaptor_Curve& theCGA,
+               Standard_Real theFin,
+               Standard_Real theDeb,
+               Standard_Real theMaxTol,
+               gp_Pnt2d thePdeb,
+               gp_Pnt2d thePfin)
+{
+  if (theE.Edge().IsNull() || theE.Face().IsNull())
+  {
+    return;
+  }
+  Standard_Boolean anIsLSkip = Standard_False;
+  TopoDS_Vertex aVl; // the last vertex of current edge 
+
+  Handle(Geom2d_Curve) aSkipC2D;
+
+  aVl = TopExp::LastVertex(theE.Edge(), Standard_True);
+  if (aVl.IsNull())
+  {
+    return;
+  }
+  const TopoDS_Edge anEl = theE.NextEdge(); // the next edge
+  if (!(BRep_Tool::Tolerance(aVl) > theMaxTol) || theE.NextEdge().IsNull())
+  {
+    return;
+  }
+  Standard_Real aLdeb = 0.0, aLfin = 0.0;
+  Handle(Geom2d_Curve) aLC2D; // the next curve
+
+  aLC2D = BRep_Tool::CurveOnSurface(theE.NextEdge(), theE.Face(), aLdeb, aLfin);
+  if (aLC2D.IsNull())
+  {
+    return;
+  }
+  Standard_Real anA, aB, aC; // coefficients of the straight line
+  Standard_Real aX1, anY1, aX2, anY2; // coordinates of the ends of edges
+  gp_Pnt2d aP1, aP2; // the ends of edges
+
+  theL.Coefficients(anA, aB, aC);
+
+  Standard_Real at1 = theFin;
+  if (theE.Edge().Orientation() != TopAbs_FORWARD)
+  {
+    at1 = theDeb;
+  }
+
+  Standard_Real at2 = aLdeb;
+  if (theE.NextEdge().Orientation() != TopAbs_FORWARD)
+  {
+    at2 = aLfin;
+  }
+
+  aP1 = theC2D->Value(at1);
+  aP2 = aLC2D->Value(at2);
+
+  // Check if points belong to DL domain
+  Standard_Real aPar1 = ElCLib::Parameter(theL, aP1);
+  Standard_Real aPar2 = ElCLib::Parameter(theL, aP2);
+
+  if (!(aPar1 > theDL.FirstParameter() && aPar1 < theDL.LastParameter()) ||
+    !(aPar2 > theDL.FirstParameter() && aPar2 < theDL.LastParameter()))
+  {
+    return;
+  }
+  aX1 = aP1.X(); anY1 = aP1.Y(); aX2 = aP2.X(); anY2 = aP2.Y();
+  Standard_Real aFV = anA * aX1 + aB * anY1 + aC;
+  Standard_Real aSV = anA * aX2 + aB * anY2 + aC;
+
+  // Check for getting into vertex with high tolerance
+  if ((aFV * aSV) >= 0)
+  {
+    anIsLSkip = Standard_False;
+  }
+  else
+  {
+    anIsLSkip = Standard_True;
+    GCE2d_MakeSegment aMkSeg(aP1, aP2);
+    if (!aMkSeg.IsDone())
+    {
+      return;
+    }
+    aSkipC2D = aMkSeg.Value();
+
+    if (aSkipC2D.IsNull() || !anIsLSkip)
+    {
+      return;
+    }
+    // if we got
+    theCur.Load(aSkipC2D);
+    if (theCur.Curve().IsNull())
+    {
+      return;
+    }
+    Standard_Real atoldeb = 1.e-5, atolfin = 1.e-5;
+
+    theDeb = theCur.FirstParameter();
+    theFin = theCur.LastParameter();
+    theCur.D0(theDeb, thePdeb);
+    theCur.D0(theFin, thePfin);
+
+    IntRes2d_Domain aDE(thePdeb, theDeb, atoldeb, thePfin, theFin, atolfin);
+    // temporary periodic domain
+    if (theCur.Curve()->IsPeriodic())
+    {
+      aDE.SetEquivalentParameters(theCur.FirstParameter(),
+        theCur.FirstParameter() +
+        theCur.Curve()->LastParameter() -
+        theCur.Curve()->FirstParameter());
+    }
+
+    theInter = Geom2dInt_GInter(theCGA, theDL, theCur, aDE,
+      Precision::PConfusion(),
+      Precision::PIntersection());
+  }
+}
 //=======================================================================
 //function : Perform
 //purpose  : 
@@ -86,53 +297,17 @@ void  BRepClass_Intersector::Perform(const gp_Lin2d& L,
   //
   // Case of "ON": direct check of belonging to edge
   // taking into account the tolerance
-  Extrema_ExtPC2d anExtPC2d(L.Location(), C);
-  Standard_Real MinDist = RealLast(), aDist;
-  Standard_Integer MinInd = 0, i;
-  if (anExtPC2d.IsDone())
-  {
-    const Standard_Integer aNbPnts = anExtPC2d.NbExt();
-    for (i = 1; i <= aNbPnts; ++i)
-    {
-      aDist = anExtPC2d.SquareDistance(i);
-
-      if (aDist < MinDist)
-      {
-        MinDist = aDist;
-        MinInd = i;
-      }
-    }
-  }
+  Standard_Boolean aStatusOn = Standard_False;
+  IntRes2d_IntersectionPoint aPntInter;
 
-  if (MinInd) {
-    MinDist = sqrt(MinDist);
-  }
-  if (MinDist <= aTolZ) {
-    gp_Pnt2d pnt_exact = (anExtPC2d.Point(MinInd)).Value();
-    Standard_Real par = (anExtPC2d.Point(MinInd)).Parameter();
-    //
-    RefineTolerance(F, C, par, aTolZ);
-    //
-    if (MinDist <= aTolZ) {
-      IntRes2d_Transition tr_on_lin(IntRes2d_Head);
-      IntRes2d_Position pos_on_curve = IntRes2d_Middle;
-      if (Abs(par - deb) <= Precision::Confusion()) {
-        pos_on_curve = IntRes2d_Head;
-      }
-      else if (Abs(par - fin) <= Precision::Confusion()) {
-        pos_on_curve = IntRes2d_End;
-      }
-      //
-      IntRes2d_Transition tr_on_curve(pos_on_curve);
-      IntRes2d_IntersectionPoint pnt_inter(pnt_exact, 0., par,
-        tr_on_lin, tr_on_curve, 
-        Standard_False);
-      //
-      Append(pnt_inter);
-      done = Standard_True;
-      return;
-    }
+  aStatusOn = CheckOn(aPntInter, F, L, C, aTolZ, fin, deb);
+  if (aStatusOn)
+  {
+    Append(aPntInter);
+    done = Standard_True;
+    return;
   }
+  
   //  
   gp_Pnt2d pdeb,pfin;
   C.D0(deb,pdeb);
@@ -163,6 +338,15 @@ void  BRepClass_Intersector::Perform(const gp_Lin2d& L,
     Precision::PConfusion(),
     Precision::PIntersection());
   //
+  // The check is for hitting the intersector to
+  // a vertex with high tolerance
+  if (Inter.IsEmpty()) 
+  {
+    CheckSkip(Inter, L, E, aC2D, DL, 
+      C, CGA, fin, deb, MaxTolerance(), pdeb, pfin);
+  }
+
+ // 
   SetValues(Inter);
 }