0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface
authoremv <emv@opencascade.com>
Thu, 26 Sep 2019 11:50:10 +0000 (14:50 +0300)
committerapn <apn@opencascade.com>
Thu, 24 Oct 2019 14:47:28 +0000 (17:47 +0300)
When collecting the points to build plane use the points on the curve instead of poles (in case of BSpline and Bezier curves).

Side effect changes:
Changes in Geom2dHatch_Elements are to increase the chance of correct 2d classification (by the means of Geom2dHatch_Classifier) by taking more than just one point on the edge to construct the classification ray and by checking if this ray is not tangent to the edge itself.

src/BRepLib/BRepLib_FindSurface.cxx
src/Geom2dHatch/Geom2dHatch_Elements.cxx
src/Geom2dHatch/Geom2dHatch_Elements.hxx
tests/mkface/mkplane/bug30878_1 [new file with mode: 0644]
tests/mkface/mkplane/bug30878_2 [new file with mode: 0644]
tests/offset/wire_closed_outside_0_005/D1
tests/offset/wire_unclosed_outside_0_025/B4

index ae94225..8906a82 100644 (file)
@@ -55,6 +55,7 @@
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Vertex.hxx>
 #include <TopoDS_Wire.hxx>
+#include <NCollection_Vector.hxx>
 
 //=======================================================================
 //function : Controle
@@ -174,6 +175,70 @@ BRepLib_FindSurface::BRepLib_FindSurface(const TopoDS_Shape&    S,
 {
   Init(S,Tol,OnlyPlane,OnlyClosed);
 }
+
+namespace
+{
+static void fillParams (const TColStd_Array1OfReal& theKnots,
+                        Standard_Integer theDegree,
+                        Standard_Real theParMin,
+                        Standard_Real theParMax,
+                        NCollection_Vector<Standard_Real>& theParams)
+{
+  Standard_Real aPrevPar = theParMin;
+  theParams.Append (aPrevPar);
+
+  Standard_Integer aNbP = Max (theDegree, 1);
+
+  for (Standard_Integer i = 1;
+       (i < theKnots.Length()) && (theKnots (i) < (theParMax - Precision::PConfusion())); ++i)
+  {
+    if (theKnots (i + 1) < theParMin + Precision::PConfusion())
+      continue;
+
+    Standard_Real aStep = (theKnots (i + 1) - theKnots (i)) / aNbP;
+    for (Standard_Integer k = 1; k <= aNbP ; ++k)
+    {
+      Standard_Real aPar = theKnots (i) + k * aStep;
+      if (aPar > theParMax - Precision::PConfusion())
+        break;
+
+      if (aPar > aPrevPar + Precision::PConfusion())
+      {
+        theParams.Append (aPar);
+        aPrevPar = aPar;
+      }
+    }
+  }
+  theParams.Append (theParMax);
+}
+
+static void fillPoints (const BRepAdaptor_Curve& theCurve,
+                        const NCollection_Vector<Standard_Real> theParams,
+                        TColgp_SequenceOfPnt& thePoints,
+                        TColStd_SequenceOfReal& theWeights)
+{
+  Standard_Real aDistPrev = 0., aDistNext;
+  gp_Pnt aPPrev (theCurve.Value (theParams (0))), aPNext;
+
+  for (Standard_Integer iP = 1; iP <= theParams.Length(); ++iP)
+  {
+    if (iP < theParams.Length())
+    {
+      Standard_Real aParam = theParams (iP);
+      aPNext = theCurve.Value (aParam);
+      aDistNext = aPPrev.Distance (aPNext);
+    }
+    else
+      aDistNext = 0.0;
+
+    thePoints.Append (aPPrev);
+    theWeights.Append (aDistPrev + aDistNext);
+    aDistPrev = aDistNext;
+    aPPrev = aPNext;
+  }
+}
+
+}
 //=======================================================================
 //function : Init
 //purpose  : 
@@ -282,117 +347,57 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape&    S,
     }
     Standard_Integer iNbPoints=0;
 
-    // Add the points with weights to the sequences
+    // Fill the parameters of the sampling points
+    NCollection_Vector<Standard_Real> aParams;
     switch (c.GetType()) 
     {
-    case GeomAbs_BezierCurve:
+      case GeomAbs_BezierCurve:
       {
-        // Put all poles for bezier
         Handle(Geom_BezierCurve) GC = c.Bezier();
-        Standard_Integer iNbPol = GC->NbPoles();
-        Standard_Real tf = GC->FirstParameter();
-        Standard_Real tl = GC->LastParameter();
-        Standard_Real r =  (dfUl - dfUf) / (tl - tf);
-        r *= iNbPol;
-        if ( iNbPol < 2 || r < 1.)
-          // Degenerate
-          continue;
-        else
-        {
-          Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol);
-          GC->Poles(aPoles->ChangeArray1());
-          gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext;
-          Standard_Real dfDistPrev = 0., dfDistNext;
-          for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++)
-          {
-            if (iPol<iNbPol)
-            {
-              aPoleNext = aPoles->Value(iPol+1);
-              dfDistNext = aPolePrev.Distance(aPoleNext);
-            }
-            else
-              dfDistNext = 0.;
-            aPoints.Append (aPolePrev);
-            aWeight.Append (dfDistPrev+dfDistNext);
-            dfDistPrev = dfDistNext;
-            aPolePrev = aPoleNext;
-          }
-        }
+        TColStd_Array1OfReal aKnots (1, 2);
+        aKnots.SetValue (1, GC->FirstParameter());
+        aKnots.SetValue (2, GC->LastParameter());
+
+        fillParams (aKnots, GC->Degree(), dfUf, dfUl, aParams);
+        break;
       }
-      break;
-    case GeomAbs_BSplineCurve:
+      case GeomAbs_BSplineCurve:
       {
-        // Put all poles for bspline
         Handle(Geom_BSplineCurve) GC = c.BSpline();
-        Standard_Integer iNbPol = GC->NbPoles();
-        Standard_Real tf = GC->FirstParameter();
-        Standard_Real tl = GC->LastParameter();
-        Standard_Real r =  (dfUl - dfUf) / (tl - tf);
-        r *= iNbPol;
-        if ( iNbPol < 2 || r < 1.)
-          // Degenerate
-          continue;
-        else
-        {
-          Handle(TColgp_HArray1OfPnt) aPoles = new (TColgp_HArray1OfPnt) (1, iNbPol);
-          GC->Poles(aPoles->ChangeArray1());
-          gp_Pnt aPolePrev = aPoles->Value(1), aPoleNext;
-          Standard_Real dfDistPrev = 0., dfDistNext;
-          for (Standard_Integer iPol=1; iPol<=iNbPol; iPol++)
-          {
-            if (iPol<iNbPol)
-            {
-              aPoleNext = aPoles->Value(iPol+1);
-              dfDistNext = aPolePrev.Distance(aPoleNext);
-            }
-            else
-              dfDistNext = 0.;
-            aPoints.Append (aPolePrev);
-            aWeight.Append (dfDistPrev+dfDistNext);
-            dfDistPrev = dfDistNext;
-            aPolePrev = aPoleNext;
-          }
-        }
+        fillParams (GC->Knots(), GC->Degree(), dfUf, dfUl, aParams);
+        break;
       }
-      break;
-
-    case GeomAbs_Line:
-    case GeomAbs_Circle:
-    case GeomAbs_Ellipse:
-    case GeomAbs_Hyperbola:
-    case GeomAbs_Parabola:
-      // Two points on straight segment, Four points on otheranalitical curves
-      iNbPoints = (c.GetType() == GeomAbs_Line ? 2 : 4);
-      Standard_FALLTHROUGH
-    default:
+      case GeomAbs_Line:
+      {
+        // Two points on a straight segment
+        aParams.Append (dfUf);
+        aParams.Append (dfUl);
+        break;
+      }
+      case GeomAbs_Circle:
+      case GeomAbs_Ellipse:
+      case GeomAbs_Hyperbola:
+      case GeomAbs_Parabola:
+        // Four points on other analytical curves
+        iNbPoints = 4;
+        Standard_FALLTHROUGH
+      default:
       { 
         // Put some points on other curves
-        if (iNbPoints==0)
-          iNbPoints = 15 + c.NbIntervals(GeomAbs_C3);
-        Standard_Real dfDelta = (dfUl-dfUf)/(iNbPoints-1);
-        Standard_Integer iPoint;
-        Standard_Real dfU;
-        gp_Pnt aPointPrev = c.Value(dfUf), aPointNext;
-        Standard_Real dfDistPrev = 0., dfDistNext;
-        for (iPoint=1, dfU=dfUf+dfDelta; 
-          iPoint<=iNbPoints; 
-          iPoint++, dfU+=dfDelta) 
-        {
-          if (iPoint<iNbPoints)
-          {
-            aPointNext = c.Value(dfU);
-            dfDistNext = aPointPrev.Distance(aPointNext);
-          }
-          else
-            dfDistNext = 0.;
-          aPoints.Append (aPointPrev);
-          aWeight.Append (dfDistPrev+dfDistNext);
-          dfDistPrev = dfDistNext;
-          aPointPrev = aPointNext;
-        }
-      } // default:
-    } // switch (c.GetType()) ...
-  } // for (ex.Init(S,TopAbs_EDGE); ex.More() && control; ex.Next()) ...
+        if (iNbPoints == 0)
+          iNbPoints = 15 + c.NbIntervals (GeomAbs_C3);
+
+        TColStd_Array1OfReal aBounds (1, 2);
+        aBounds.SetValue (1, dfUf);
+        aBounds.SetValue (2, dfUl);
+
+        fillParams (aBounds, iNbPoints - 1, dfUf, dfUl, aParams);
+      }
+    }
+
+    // Add the points with weights to the sequences
+    fillPoints (c, aParams, aPoints, aWeight);
+  }
 
   if (aPoints.Length() < 3) {
     return;
@@ -505,79 +510,33 @@ void BRepLib_FindSurface::Init(const TopoDS_Shape&    S,
       }
     }
   }
-    
-  //
-  //  let us be more tolerant (occ415)
-  Standard_Real dfDist = RealLast();
-  Handle(Geom_Plane) aPlane;
-  //
-  if (isSolved)  {
-    //Plane normal can have two directions, direction is chosen
-    //according to direction of eigenvector
-    gp_Vec anN(aVec(1), aVec(2), aVec(3));
-    aPlane = new Geom_Plane(aBaryCenter,anN);
-    dfDist = Controle (aPoints, aPlane);
-  }
-  //
-  if (!isSolved || myTolerance < dfDist)  {
-    gp_Pnt aFirstPnt=aPoints(1);
-    for (iPoint=2; iPoint<=aPoints.Length(); iPoint++)  {
-      gp_Vec aDir(aFirstPnt,aPoints(iPoint));
-      Standard_Real dfSide=aDir.Magnitude();
-      if (dfSide<myTolerance) {
-        continue; // degeneration
-      }
-      for (Standard_Integer iP1=iPoint+1; iP1<=aPoints.Length(); iP1++) {
 
-               gp_Vec aCross = gp_Vec(aFirstPnt,aPoints(iP1)) ^ aDir ;
+  if (!isSolved)
+    return;
 
-        if (aCross.Magnitude() > dfSide*myTolerance) {
-          Handle(Geom_Plane) aPlane2 = new Geom_Plane(aBaryCenter, aCross);
-          Standard_Real dfDist2 = Controle (aPoints, aPlane2);
-          if (dfDist2 < myTolerance)  {
-            myTolReached = dfDist2;
-            mySurface = aPlane2;
-            return;
-          }
-          if (dfDist2 < dfDist)  {
-            dfDist = dfDist2;
-            aPlane = aPlane2;
-          }
-        }
-      }
-    }
-  }
-  //
-  //XXf
-  //static Standard_Real weakness = 5.0;
-  Standard_Real weakness = 5.0;
-  //XXf
-  if(dfDist <= myTolerance || (dfDist < myTolerance*weakness && Tol<0)) { 
-    //XXf 
-    //myTolReached = dfDist;
-    //XXt
+  gp_Vec aN (aVec (1), aVec (2), aVec (3));
+  Handle(Geom_Plane) aPlane = new Geom_Plane (aBaryCenter, aN);
+  myTolReached = Controle (aPoints, aPlane);
+  const Standard_Real aWeakness = 5.0;
+  if (myTolReached <= myTolerance || (Tol < 0 && myTolReached < myTolerance * aWeakness))
+  {
     mySurface = aPlane;
     //If S is wire, try to orient surface according to orientation of wire.
-    if(S.ShapeType() == TopAbs_WIRE && S.Closed())
+    if (S.ShapeType() == TopAbs_WIRE && S.Closed())
     {
-       //
-      TopoDS_Wire aW = TopoDS::Wire(S);
-      TopoDS_Face aTmpFace = BRepLib_MakeFace(mySurface, Precision::Confusion());
+      TopoDS_Wire aW = TopoDS::Wire (S);
+      TopoDS_Face aTmpFace = BRepLib_MakeFace (mySurface, Precision::Confusion());
       BRep_Builder BB;
-      BB.Add(aTmpFace, aW);
-      BRepTopAdaptor_FClass2d FClass(aTmpFace, 0.);
-      if ( FClass.PerformInfinitePoint() == TopAbs_IN ) 
+      BB.Add (aTmpFace, aW);
+      BRepTopAdaptor_FClass2d FClass (aTmpFace, 0.);
+      if (FClass.PerformInfinitePoint() == TopAbs_IN)
       {
-        gp_Dir aN = aPlane->Position().Direction();
-        aN.Reverse();
-        mySurface = new Geom_Plane(aPlane->Position().Location(), aN);
+        gp_Dir aNorm = aPlane->Position().Direction();
+        aNorm.Reverse();
+        mySurface = new Geom_Plane (aPlane->Position().Location(), aNorm);
       }
-
     }
   }
-  //XXf
-  myTolReached = dfDist;
-  //XXt
 }
 //=======================================================================
 //function : Found
index acd872b..5db9310 100644 (file)
 #include <Standard_NoSuchObject.hxx>
 #include <TColStd_MapIntegerHasher.hxx>
 #include <TopAbs_Orientation.hxx>
+#include <Precision.hxx>
+
+static const Standard_Real Probing_Start = 0.123;
+static const Standard_Real Probing_End = 0.8;
+static const Standard_Real Probing_Step = 0.2111;
 
 Geom2dHatch_Elements::Geom2dHatch_Elements(const Geom2dHatch_Elements& )
 {
@@ -41,6 +46,7 @@ Geom2dHatch_Elements::Geom2dHatch_Elements()
   NumWire = 0;
   NumEdge = 0;
   myCurEdge = 1;
+  myCurEdgePar = Probing_Start;
 }
 
 void Geom2dHatch_Elements::Clear()
@@ -102,7 +108,7 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P,
                                                     Standard_Real& Par)
 {
   myCurEdge = 1;
-
+  myCurEdgePar = Probing_Start;
   return OtherSegment(P, L, Par);
 }
 
@@ -111,43 +117,91 @@ Standard_Boolean Geom2dHatch_Elements::Segment(const gp_Pnt2d& P,
 //purpose  : 
 //=======================================================================
 
-Standard_Boolean Geom2dHatch_Elements::OtherSegment(const gp_Pnt2d& P, 
-                                                         gp_Lin2d& L, 
-                                                         Standard_Real& Par)
+Standard_Boolean Geom2dHatch_Elements::OtherSegment (const gp_Pnt2d& P, 
+                                                     gp_Lin2d& L, 
+                                                     Standard_Real& Par)
 {
   Geom2dHatch_DataMapIteratorOfMapOfElements Itertemp;
   Standard_Integer                        i;
   
-  for(  Itertemp.Initialize(myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++) { 
+  for (Itertemp.Initialize (myMap), i = 1; Itertemp.More(); Itertemp.Next(), i++)
+  {
     if (i < myCurEdge)
       continue;
 
     void *ptrmyMap = (void *)(&myMap);
-    Geom2dHatch_Element& Item=((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind(Itertemp.Key());
+    Geom2dHatch_Element& Item = ((Geom2dHatch_MapOfElements*)ptrmyMap)->ChangeFind (Itertemp.Key());
     Geom2dAdaptor_Curve& E = Item.ChangeCurve();
-    TopAbs_Orientation Or= Item.Orientation();
-    gp_Pnt2d P2 = E.Value
-      ((E.FirstParameter() + E.LastParameter()) *0.5);
-    if ((Or == TopAbs_FORWARD) ||
-       (Or == TopAbs_REVERSED)) {
-      gp_Vec2d V(P,P2);
-      Par = V.Magnitude();
-      if (Par >= gp::Resolution()) {
-       L = gp_Lin2d(P,V);
-       myCurEdge++;
-       return Standard_True;
+    TopAbs_Orientation Or = Item.Orientation();
+    if (Or == TopAbs_FORWARD || Or == TopAbs_REVERSED)
+    {
+      Standard_Real aFPar = E.FirstParameter(), aLPar = E.LastParameter();
+      if (Precision::IsNegativeInfinite (aFPar))
+      {
+        if (Precision::IsPositiveInfinite (aLPar))
+        {
+          aFPar = -1.;
+          aLPar = 1.;
+        }
+        else
+          aFPar = aLPar - 1.;
+      }
+      else if (Precision::IsPositiveInfinite (aLPar))
+        aLPar = aFPar + 1.;
+
+      for (; myCurEdgePar < Probing_End; myCurEdgePar += Probing_Step)
+      {
+        Standard_Real aParam = myCurEdgePar * aFPar + (1. - myCurEdgePar) * aLPar;
+        gp_Vec2d aTanVec;
+        gp_Pnt2d aPOnC;
+        E.D1 (aParam, aPOnC, aTanVec);
+        gp_Vec2d aLinVec (P, aPOnC);
+        Par = aLinVec.SquareMagnitude();
+        if (Par > Precision::SquarePConfusion())
+        {
+          gp_Dir2d aLinDir (aLinVec);
+          Standard_Real aTanMod = aTanVec.SquareMagnitude();
+          if (aTanMod < Precision::SquarePConfusion())
+            continue;
+
+          aTanVec /= Sqrt (aTanMod);
+          Standard_Real aSinA = aTanVec.Crossed (aLinDir);
+          if (Abs (aSinA) < 0.001)
+          {
+            // too small angle - line and edge may be considered
+            // as tangent which is bad for classifier
+            if (myCurEdgePar + Probing_Step < Probing_End)
+              continue;
+          }
+
+          L = gp_Lin2d (P, aLinDir);
+
+          aPOnC = E.Value (aFPar);
+          if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion())
+          {
+            aPOnC = E.Value (aLPar);
+            if (L.SquareDistance (aPOnC) > Precision::SquarePConfusion())
+            {
+              myCurEdgePar += Probing_Step;
+              if (myCurEdgePar >= Probing_End)
+              {
+                myCurEdge++;
+                myCurEdgePar = Probing_Start;
+              }
+              Par = Sqrt (Par);
+              return Standard_True;
+            }
+          }
+        }
       }
     }
-  }
-
-  if (i == myCurEdge + 1) {
-    Par = RealLast();
-    L = gp_Lin2d(P,gp_Dir2d(1,0));
     myCurEdge++;
-
-    return Standard_True;
+    myCurEdgePar = Probing_Start;
   }
 
+  Par = RealLast();
+  L = gp_Lin2d (P, gp_Dir2d (1, 0));
+
   return Standard_False;
 }
 
index 5ef0623..3b7f486 100644 (file)
@@ -114,7 +114,7 @@ private:
   Standard_Integer NumWire;
   Standard_Integer NumEdge;
   Standard_Integer myCurEdge;
-
+  Standard_Real myCurEdgePar;
 
 };
 
diff --git a/tests/mkface/mkplane/bug30878_1 b/tests/mkface/mkplane/bug30878_1
new file mode 100644 (file)
index 0000000..c966de4
--- /dev/null
@@ -0,0 +1,22 @@
+puts "============="
+puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface"
+puts "============="
+
+brestore [locate_data_file bug30878_wire.brep] w
+
+# build the face on the original wire
+mkplane result w 1
+
+checkprops result -s 69458.1
+
+# reduce the tolerance
+settolerance w 0.7
+
+# build face again
+mkplane result w 1
+
+checkprops result -s 69458.1
+
+set MaxFTol 0.7
+set MaxETol 0.7
+set MaxVTol 0.7
diff --git a/tests/mkface/mkplane/bug30878_2 b/tests/mkface/mkplane/bug30878_2
new file mode 100644 (file)
index 0000000..4429354
--- /dev/null
@@ -0,0 +1,11 @@
+puts "REQUIRED ALL: Error. mkplane has been finished with \"Not Planar\" status."
+puts "REQUIRED ALL: Error : The mkface can not be built."
+
+puts "============="
+puts "0030878: Modeling Algorithms - BRepLib_MakeFace produces face with abnormal surface"
+puts "============="
+
+brestore [locate_data_file bug30878_wire2.brep] w
+
+mkplane result w 1
+
index 0f54d31..897db82 100644 (file)
@@ -1,9 +1,9 @@
-puts "TODO OCC23068 ALL: Error : big tolerance of shape result"
-puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2"
-#puts "TODO OCC24255 ALL: An exception was caught" 
-#puts "TODO OCC24255 ALL: Error: Offset is not done."
-#puts "TODO OCC24255 ALL: Error : The offset cannot be built."
+#puts "TODO OCC23068 ALL: Error : big tolerance of shape result"
+#puts "TODO OCC23068 ALL: Faulty shapes in variables faulty_1 to faulty_2"
 #puts "TODO OCC23068 ALL: Error : The resulting shape is WRONG"
+puts "TODO OCC31005 ALL: Error: Offset is not done"
+puts "TODO OCC31005 ALL: Error: The command cannot be built"
+puts "TODO OCC31005 ALL: Error : The offset cannot be built"
 
 restore [locate_data_file offset_wire_041.brep] s
 
index 0fbddbf..a6dc794 100644 (file)
@@ -1,4 +1,6 @@
-puts "TODO OCC25109 ALL: Faulty shapes in variables"
+puts "TODO OCC31005 ALL: Faulty shapes in variables"
+puts "TODO OCC31005 ALL: Error : The length of result shape is"
+puts "TODO OCC31005 ALL: Error : The resulting shape is WRONG"
 
 restore [locate_data_file case_3_wire2.brep] s