0031047: Modeling Algorithms - BRepExtrema_DistShapeShape gives wrong result IR-2021-07-09
authorabulyche <abulyche@opencascade.com>
Mon, 12 Apr 2021 10:13:14 +0000 (13:13 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 9 Jul 2021 16:16:14 +0000 (19:16 +0300)
Added map of edges to BrepClass_Edge
Added searching of vertices with high tolerance to BrepClass_Intersector.cxx
Added check for hitting a vertex with high tolerance
Added the creation of a segment for the correct work of the classifier

src/BRepClass/BRepClass_Edge.cxx
src/BRepClass/BRepClass_Edge.hxx
src/BRepClass/BRepClass_FaceExplorer.cxx
src/BRepClass/BRepClass_FaceExplorer.hxx
src/BRepClass/BRepClass_Intersector.cxx
src/BRepClass/BRepClass_Intersector.hxx
tests/bugs/modalg_6/bug31047 [new file with mode: 0644]

index c4cbc44..0774105 100644 (file)
 
 
 #include <BRepClass_Edge.hxx>
-#include <TopoDS_Edge.hxx>
-#include <TopoDS_Face.hxx>
+#include <NCollection_IndexedDataMap.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopExp.hxx>
 
 //=======================================================================
 //function : BRepClass_Edge
@@ -27,6 +29,37 @@ BRepClass_Edge::BRepClass_Edge()
 {
 }
 
+//=======================================================================
+//function : SetNextEdge
+//purpose  :
+//=======================================================================
+void BRepClass_Edge::SetNextEdge(const TopTools_IndexedDataMapOfShapeListOfShape& theMapVE)
+{
+  if (theMapVE.IsEmpty() || myEdge.IsNull())
+  {
+    return;
+  }
+  TopoDS_Vertex aVF, aVL;
+  TopExp::Vertices(myEdge, aVF, aVL, Standard_True);
+
+  if (aVL.IsNull() || aVL.IsSame(aVF))
+  {
+    return;
+  }
+  const TopTools_ListOfShape* aListE = theMapVE.Seek(aVL);
+  if ((*aListE).Extent() == 2)
+  {
+    for (TopTools_ListIteratorOfListOfShape anIt(*aListE); anIt.More(); anIt.Next())
+    {
+      if ((!anIt.Value().IsNull()) && (!anIt.Value().IsSame(myEdge)))
+      {
+        myNextEdge = TopoDS::Edge(anIt.Value());
+      }
+    }
+  }
+}
+
+
 //=======================================================================
 //function : BRepClass_Edge
 //purpose  : 
index 9c07502..fe742f3 100644 (file)
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
 
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
-class TopoDS_Edge;
-class TopoDS_Face;
 
 
 //! This class  is used to send  the  description of an
@@ -41,13 +40,22 @@ public:
   
   Standard_EXPORT BRepClass_Edge(const TopoDS_Edge& E, const TopoDS_Face& F);
   
-    TopoDS_Edge& Edge();
+  //! Returns the current Edge  
+  TopoDS_Edge& Edge();
 const TopoDS_Edge& Edge() const;
   
-    TopoDS_Face& Face();
+  //! Returns the Face for the current Edge
+  TopoDS_Face& Face();
 const TopoDS_Face& Face() const;
 
+  //! Returns the next Edge
+  const TopoDS_Edge& NextEdge() const
+  {
+    return myNextEdge;
+  }
 
+  //! Finds and sets the next Edge for the current
+  Standard_EXPORT void SetNextEdge(const TopTools_IndexedDataMapOfShapeListOfShape& theMapVE);
 
 
 protected:
@@ -62,7 +70,7 @@ private:
 
   TopoDS_Edge myEdge;
   TopoDS_Face myFace;
-
+  TopoDS_Edge myNextEdge;
 
 };
 
index 1c9c706..93ccbd9 100644 (file)
 #include <BRepClass_FaceExplorer.hxx>
 #include <BRepTools.hxx>
 #include <Geom2d_Curve.hxx>
-#include <gp_Lin2d.hxx>
-#include <gp_Pnt2d.hxx>
 #include <Precision.hxx>
 #include <TopoDS.hxx>
-#include <TopoDS_Face.hxx>
+#include <TopExp.hxx>
 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
 
 static const Standard_Real Probing_Start = 0.123;
@@ -311,6 +309,8 @@ Standard_Boolean  BRepClass_FaceExplorer::RejectWire
 void  BRepClass_FaceExplorer::InitEdges()
 {
   myEExplorer.Init(myWExplorer.Current(),TopAbs_EDGE);
+  myMapVE.Clear();
+  TopExp::MapShapesAndAncestors(myWExplorer.Current(), TopAbs_VERTEX, TopAbs_EDGE, myMapVE);
 }
 
 //=======================================================================
@@ -337,5 +337,6 @@ void  BRepClass_FaceExplorer::CurrentEdge(BRepClass_Edge& E,
   E.Edge() = TopoDS::Edge(myEExplorer.Current());
   E.Face() = myFace;
   Or = E.Edge().Orientation();
+  E.SetNextEdge(myMapVE);
 }
 
index bdb14b1..d075136 100644 (file)
 #include <Standard.hxx>
 #include <Standard_DefineAlloc.hxx>
 #include <Standard_Handle.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
 
+#include <TopAbs_Orientation.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopExp_Explorer.hxx>
 #include <Standard_Integer.hxx>
 #include <Standard_Real.hxx>
 #include <Standard_Boolean.hxx>
-#include <TopAbs_Orientation.hxx>
-class TopoDS_Face;
 class gp_Pnt2d;
 class gp_Lin2d;
 class BRepClass_Edge;
@@ -112,6 +112,7 @@ private:
   TopExp_Explorer myEExplorer;
   Standard_Integer myCurEdgeInd;
   Standard_Real myCurEdgePar;
+  TopTools_IndexedDataMapOfShapeListOfShape myMapVE;
 
   Standard_Real myUMin;
   Standard_Real myUMax;
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);
 }
 
index e1b1742..279b34c 100644 (file)
@@ -47,6 +47,18 @@ public:
   //! <U>.
   Standard_EXPORT void LocalGeometry (const BRepClass_Edge& E, const Standard_Real U, gp_Dir2d& T, gp_Dir2d& N, Standard_Real& C) const;
 
+  //! Returns the maximum tolerance
+  Standard_Real MaxTolerance()
+  {
+    return myMaxTolerance;
+  }
+
+  //! Sets the maximum tolerance at 
+  //! which to start checking in the intersector
+  void SetMaxTolerance(const Standard_Real theValue)
+  {
+    myMaxTolerance = theValue;
+  }
 
 
 
@@ -59,7 +71,7 @@ protected:
 private:
 
 
-
+  Standard_Real myMaxTolerance;
 
 
 };
diff --git a/tests/bugs/modalg_6/bug31047 b/tests/bugs/modalg_6/bug31047
new file mode 100644 (file)
index 0000000..dae902f
--- /dev/null
@@ -0,0 +1,17 @@
+puts "================================================================="
+puts "OCC31047: BRepExtrema_DistShapeShape gives wrong result"
+puts "================================================================="
+puts ""
+
+restore [locate_data_file bug31047.brep] f
+
+point p1 -79 -282.7
+point p2 -79 -282.6
+
+if ![regexp "IN" [b2dclassify f p1]] {
+  puts "Error: inner point p1 is classified as OUT"
+}
+
+if ![regexp "IN" [b2dclassify f p2]] {
+  puts "Error: inner point p2 is classified as OUT"
+}