0028385: Improve drawing isolines (DBRep_IsoBuilder algorithm)
authoremv <emv@opencascade.com>
Mon, 27 Nov 2017 12:52:55 +0000 (15:52 +0300)
committerapn <apn@opencascade.com>
Tue, 23 Jan 2018 17:11:08 +0000 (20:11 +0300)
1. When computing the iso-lines for the face (*DBRep_IsoBuilder*) prepare the Hatching algorithm with the following elements:
a. Trimmed p-curves of edges. The trimming parameters are computed by intersection with p-curves of the neighboring edges. The trimming will be performed only if the intersection point is covered by the tolerance of common vertex.
b. 2D segments connecting the p-curves of the neighboring edges. These segments will close the 2D gaps, which are closed in 3D by the tolerance of vertices shared between edges. This will allow trimming correctly the iso-lines passing through such gaps.

2. Implementation of the additional Init() method for WireExplorer algorithm taking UV bounds of the face to avoid their repeated computation when work working with a face having multiple wires.

3. Test cases for the issue.

17 files changed:
src/BRepTools/BRepTools_WireExplorer.cxx
src/BRepTools/BRepTools_WireExplorer.hxx
src/DBRep/DBRep_IsoBuilder.cxx
src/DBRep/DBRep_IsoBuilder.hxx
src/DBRep/DBRep_IsoBuilder.lxx [deleted file]
src/DBRep/FILES
src/math/math_FunctionRoots.cxx
tests/bugs/modalg_7/bug28385_1 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_10 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_2 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_3 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_4 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_5 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_6 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_7 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_8 [new file with mode: 0644]
tests/bugs/modalg_7/bug28385_9 [new file with mode: 0644]

index 4a08658..1fe412a 100644 (file)
@@ -16,6 +16,7 @@
 
 
 #include <BRep_Tool.hxx>
+#include <BRepAdaptor_Surface.hxx>
 #include <BRepTools.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <Geom2d_Curve.hxx>
@@ -101,14 +102,50 @@ void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W)
 //purpose  : 
 //=======================================================================
 void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
-                                  const TopoDS_Face& F)
+                                   const TopoDS_Face& F)
 {
   myEdge = TopoDS_Edge();
   myVertex = TopoDS_Vertex();
   myMap.Clear();
   myDoubles.Clear();
 
-  if( W.IsNull() )
+  if (W.IsNull())
+    return;
+
+  Standard_Real UMin(0.0), UMax(0.0), VMin(0.0), VMax(0.0);
+  if (!F.IsNull())
+  {
+    // For the faces based on Cone, BSpline and Bezier compute the
+    // UV bounds to precise the UV tolerance values
+    const GeomAbs_SurfaceType aSurfType = BRepAdaptor_Surface(F, Standard_False).GetType();
+    if (aSurfType == GeomAbs_Cone ||
+        aSurfType == GeomAbs_BSplineSurface ||
+        aSurfType == GeomAbs_BezierSurface)
+    {
+      BRepTools::UVBounds(F, UMin, UMax, VMin, VMax);
+    }
+  }
+
+  Init(W, F, UMin, UMax, VMin, VMax);
+}
+
+//=======================================================================
+//function : Init
+//purpose  : 
+//=======================================================================
+void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
+                                   const TopoDS_Face& F,
+                                   const Standard_Real UMin,
+                                   const Standard_Real UMax,
+                                   const Standard_Real VMin,
+                                   const Standard_Real VMax)
+{
+  myEdge = TopoDS_Edge();
+  myVertex = TopoDS_Vertex();
+  myMap.Clear();
+  myDoubles.Clear();
+
+  if (W.IsNull())
     return;
 
   myFace = F;
@@ -116,142 +153,147 @@ void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
   myReverse = Standard_False;
 
   if (!myFace.IsNull())
+  {
+    BRepTools::Update(myFace);
+    TopLoc_Location aL;
+    const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(myFace, aL);
+    GeomAdaptor_Surface aGAS(aSurf);
+    TopExp_Explorer anExp(W, TopAbs_VERTEX);
+    for (; anExp.More(); anExp.Next())
     {
-      BRepTools::Update(myFace);
-      TopLoc_Location aL;  
-      const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(myFace, aL);
-      GeomAdaptor_Surface aGAS(aSurf);
-      TopExp_Explorer anExp(W, TopAbs_VERTEX);
-      for(; anExp.More(); anExp.Next())
-       {
-         const TopoDS_Vertex& aV = TopoDS::Vertex(anExp.Current());
-         dfVertToler = Max(BRep_Tool::Tolerance(aV), dfVertToler);
-       }
-      myTolU = 2. * aGAS.UResolution(dfVertToler);
-      myTolV = 2. * aGAS.VResolution(dfVertToler);
-      
-      // uresolution for cone with infinite vmin vmax is too small.
-      if(aGAS.GetType() == GeomAbs_Cone)
-       {
-         Standard_Real u1, u2, v1, v2;
-         BRepTools::UVBounds(myFace, u1, u2, v1, v2);
-         gp_Pnt aP;
-         gp_Vec aD1U, aD1V;
-         aGAS.D1(u1, v1, aP, aD1U, aD1V);
-         Standard_Real tol1, tol2, maxtol = .0005*(u2-u1);
-         Standard_Real a = aD1U.Magnitude();
-
-         if(a <= Precision::Confusion())
-           tol1 = maxtol;
-         else
-           tol1 = Min(maxtol, dfVertToler/a);
+      const TopoDS_Vertex& aV = TopoDS::Vertex(anExp.Current());
+      dfVertToler = Max(BRep_Tool::Tolerance(aV), dfVertToler);
+    }
+    if (dfVertToler < Precision::Confusion())
+    {
+      // Use tolerance of edges
+      for (TopoDS_Iterator it(W); it.More(); it.Next())
+        dfVertToler = Max(BRep_Tool::Tolerance(TopoDS::Edge(it.Value())), dfVertToler);
 
-         aGAS.D1(u1, v2, aP, aD1U, aD1V);
-         a = aD1U.Magnitude();
-         if(a <= Precision::Confusion())
-           tol2 = maxtol;
-         else
-           tol2 = Min(maxtol, dfVertToler/a);
+      if (dfVertToler < Precision::Confusion())
+        // empty wire
+        return;
+    }
+    myTolU = 2. * aGAS.UResolution(dfVertToler);
+    myTolV = 2. * aGAS.VResolution(dfVertToler);
 
-         myTolU = 2. * Max(tol1, tol2);
-       }
+    // uresolution for cone with infinite vmin vmax is too small.
+    if (aGAS.GetType() == GeomAbs_Cone)
+    {
+      gp_Pnt aP;
+      gp_Vec aD1U, aD1V;
+      aGAS.D1(UMin, VMin, aP, aD1U, aD1V);
+      Standard_Real tol1, tol2, maxtol = .0005*(UMax - UMin);
+      Standard_Real a = aD1U.Magnitude();
+
+      if (a <= Precision::Confusion())
+        tol1 = maxtol;
+      else
+        tol1 = Min(maxtol, dfVertToler / a);
 
-      if( aGAS.GetType() == GeomAbs_BSplineSurface || 
-         aGAS.GetType() == GeomAbs_BezierSurface )
-       {
-          Standard_Real maxTol = Max(myTolU, myTolV);
-          gp_Pnt aP;
-          gp_Vec aDU, aDV;
-          Standard_Real u1, u2, v1, v2;
-          BRepTools::UVBounds(myFace, u1, u2, v1, v2);
-          aGAS.D1((u2 - u1) / 2., (v2 - v1) / 2., aP, aDU, aDV);
-          Standard_Real mod = Sqrt(aDU*aDU + aDV*aDV);
-          if (mod * maxTol / dfVertToler < 1.5)
-          {
-            maxTol = 1.5 * dfVertToler / mod;
-          }
-          myTolU = maxTol;
-          myTolV = maxTol;
-        }
+      aGAS.D1(UMin, VMax, aP, aD1U, aD1V);
+      a = aD1U.Magnitude();
+      if (a <= Precision::Confusion())
+        tol2 = maxtol;
+      else
+        tol2 = Min(maxtol, dfVertToler / a);
 
-      myReverse = (myFace.Orientation() == TopAbs_REVERSED);
+      myTolU = 2. * Max(tol1, tol2);
     }
-      
+
+    if (aGAS.GetType() == GeomAbs_BSplineSurface ||
+      aGAS.GetType() == GeomAbs_BezierSurface)
+    {
+      Standard_Real maxTol = Max(myTolU, myTolV);
+      gp_Pnt aP;
+      gp_Vec aDU, aDV;
+      aGAS.D1((UMax - UMin) / 2., (VMax - VMin) / 2., aP, aDU, aDV);
+      Standard_Real mod = Sqrt(aDU*aDU + aDV*aDV);
+      if (mod > gp::Resolution())
+      {
+        if (mod * maxTol / dfVertToler < 1.5)
+        {
+          maxTol = 1.5 * dfVertToler / mod;
+        }
+        myTolU = maxTol;
+        myTolV = maxTol;
+      }
+    }
+
+    myReverse = (myFace.Orientation() == TopAbs_REVERSED);
+  }
+
   // map of vertices to know if the wire is open
   TopTools_MapOfShape vmap;
-  //  Modified by Sergey KHROMOV - Mon May 13 11:50:48 2002 Begin
   //  map of infinite edges
   TopTools_MapOfShape anInfEmap;
-  //  Modified by Sergey KHROMOV - Mon May 13 11:50:49 2002 End
 
   // list the vertices
-  TopoDS_Vertex V1,V2;
+  TopoDS_Vertex V1, V2;
   TopTools_ListOfShape empty;
 
   TopoDS_Iterator it(W);
   while (it.More())
+  {
+    const TopoDS_Edge& E = TopoDS::Edge(it.Value());
+    TopAbs_Orientation Eori = E.Orientation();
+    if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL)
     {
-      const TopoDS_Edge& E = TopoDS::Edge(it.Value());
-      TopAbs_Orientation Eori = E.Orientation();
-      if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL)
-       {
-         it.Next();
-         continue;
-       }
-      TopExp::Vertices(E,V1,V2,Standard_True);
+      it.Next();
+      continue;
+    }
+    TopExp::Vertices(E, V1, V2, Standard_True);
 
-      if( !V1.IsNull() )
-       {
-         if( !myMap.IsBound(V1) )
-           myMap.Bind(V1,empty);
-         myMap(V1).Append(E);
-
-         // add or remove in the vertex map
-         V1.Orientation(TopAbs_FORWARD);
-         if( !vmap.Add(V1) )
-           vmap.Remove(V1);
-       }
+    if (!V1.IsNull())
+    {
+      if (!myMap.IsBound(V1))
+        myMap.Bind(V1, empty);
+      myMap(V1).Append(E);
+
+      // add or remove in the vertex map
+      V1.Orientation(TopAbs_FORWARD);
+      if (!vmap.Add(V1))
+        vmap.Remove(V1);
+    }
 
-      if( !V2.IsNull() )
-       {
-         V2.Orientation(TopAbs_REVERSED);
-         if(!vmap.Add(V2))
-           vmap.Remove(V2);
-       }
+    if (!V2.IsNull())
+    {
+      V2.Orientation(TopAbs_REVERSED);
+      if (!vmap.Add(V2))
+        vmap.Remove(V2);
+    }
 
-      //  Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 Begin
-      if (V1.IsNull() || V2.IsNull())
-       {
-         Standard_Real aF = 0., aL = 0.;
-         BRep_Tool::Range(E, aF, aL);
-         
-         if(Eori == TopAbs_FORWARD)
-           {
-             if (aF == -Precision::Infinite())
-               anInfEmap.Add(E);
-           }
-         else
-           { // Eori == TopAbs_REVERSED
-             if (aL == Precision::Infinite())
-               anInfEmap.Add(E);
-           }
-       }
-      //  Modified by Sergey KHROMOV - Mon May 13 11:52:20 2002 End
-      it.Next();
+    if (V1.IsNull() || V2.IsNull())
+    {
+      Standard_Real aF = 0., aL = 0.;
+      BRep_Tool::Range(E, aF, aL);
+
+      if (Eori == TopAbs_FORWARD)
+      {
+        if (aF == -Precision::Infinite())
+          anInfEmap.Add(E);
+      }
+      else
+      { // Eori == TopAbs_REVERSED
+        if (aL == Precision::Infinite())
+          anInfEmap.Add(E);
+      }
     }
+    it.Next();
+  }
 
   //Construction of the set of double edges.
-  TopoDS_Iterator it2(W);  
+  TopoDS_Iterator it2(W);
   TopTools_MapOfShape emap;
   while (it2.More()) {
-    if (!emap.Add(it2.Value())) 
+    if (!emap.Add(it2.Value()))
       myDoubles.Add(it2.Value());
     it2.Next();
   }
 
   // if vmap is not empty the wire is open, let us find the first vertex
   if (!vmap.IsEmpty()) {
-    TopTools_MapIteratorOfMapOfShape itt(vmap); // skl : I change "it" to "itt"
+    TopTools_MapIteratorOfMapOfShape itt(vmap);
     while (itt.Key().Orientation() != TopAbs_FORWARD) {
       itt.Next();
       if (!itt.More()) break;
@@ -259,29 +301,26 @@ void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
     if (itt.More()) V1 = TopoDS::Vertex(itt.Key());
   }
   else {
-//  Modified by Sergey KHROMOV - Mon May 13 12:05:30 2002 Begin
-//   The wire is infinite Try to find the first vertex. It may be NULL.
+    //   The wire is infinite Try to find the first vertex. It may be NULL.
     if (!anInfEmap.IsEmpty()) {
       TopTools_MapIteratorOfMapOfShape itt(anInfEmap);
 
       for (; itt.More(); itt.Next()) {
-       TopoDS_Edge        anEdge = TopoDS::Edge(itt.Key());
-       TopAbs_Orientation anOri  = anEdge.Orientation();
-       Standard_Real      aF;
-       Standard_Real      aL;
-
-       BRep_Tool::Range(anEdge, aF, aL);
-       if ((anOri == TopAbs_FORWARD  && aF == -Precision::Infinite()) ||
-           (anOri == TopAbs_REVERSED && aL ==  Precision::Infinite())) {
-         myEdge   = anEdge;
-         myVertex = TopoDS_Vertex();
-
-         return;
-       }
+        TopoDS_Edge        anEdge = TopoDS::Edge(itt.Key());
+        TopAbs_Orientation anOri = anEdge.Orientation();
+        Standard_Real      aF;
+        Standard_Real      aL;
+
+        BRep_Tool::Range(anEdge, aF, aL);
+        if ((anOri == TopAbs_FORWARD  && aF == -Precision::Infinite()) ||
+          (anOri == TopAbs_REVERSED && aL == Precision::Infinite())) {
+          myEdge = anEdge;
+          myVertex = TopoDS_Vertex();
+
+          return;
+        }
       }
     }
-//  Modified by Sergey KHROMOV - Mon May 13 12:05:31 2002 End
-
 
     // use the first vertex in iterator
     it.Initialize(W);
@@ -289,23 +328,23 @@ void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
       const TopoDS_Edge& E = TopoDS::Edge(it.Value());
       TopAbs_Orientation Eori = E.Orientation();
       if (Eori == TopAbs_INTERNAL || Eori == TopAbs_EXTERNAL) {
-       // JYL 10-03-97 : waiting for correct processing 
-       // of INTERNAL/EXTERNAL edges
-       it.Next();
-       continue;
+        // JYL 10-03-97 : waiting for correct processing 
+        // of INTERNAL/EXTERNAL edges
+        it.Next();
+        continue;
       }
-      TopExp::Vertices(E,V1,V2,Standard_True);
+      TopExp::Vertices(E, V1, V2, Standard_True);
       break;
     }
   }
 
-  if (V1.IsNull() ) return;
+  if (V1.IsNull()) return;
   if (!myMap.IsBound(V1)) return;
-  
+
   TopTools_ListOfShape& l = myMap(V1);
   myEdge = TopoDS::Edge(l.First());
   l.RemoveFirst();
-  myVertex = TopExp::FirstVertex (myEdge, Standard_True);
+  myVertex = TopExp::FirstVertex(myEdge, Standard_True);
 
 }
 
@@ -462,6 +501,12 @@ void  BRepTools_WireExplorer::Next()
       aPCurve->D0(dfMPar, PRefm);
       // Get vector from PRef to PRefm
       gp_Vec2d anERefDir(PRef,PRefm);
+      if (anERefDir.SquareMagnitude() < gp::Resolution())
+      {
+        myEdge = TopoDS_Edge();
+        return;
+      }
+
       // Search the list of edges looking for the edge having hearest
       // 2D point of connected vertex to current one and smallest angle.
       // First process all degenerated edges, then - all others.
index 00b3eef..f04ff22 100644 (file)
@@ -77,6 +77,17 @@ public:
   //! previous in the parametric representation of <F>.
   Standard_EXPORT void Init (const TopoDS_Wire& W, const TopoDS_Face& F);
   
+  //! Initializes an exploration of the wire <W>.
+  //! F is used to select the edge connected to the
+  //! previous in the parametric representation of <F>.
+  //! <UMIn>, <UMax>, <VMin>, <VMax> - the UV bounds of the face <F>.
+  Standard_EXPORT void Init(const TopoDS_Wire& W,
+                            const TopoDS_Face& F,
+                            const Standard_Real UMin,
+                            const Standard_Real UMax,
+                            const Standard_Real VMin,
+                            const Standard_Real VMax);
+
   //! Returns True if there  is a current  edge.
   Standard_EXPORT Standard_Boolean More() const;
   
index e8f4611..3db716a 100644 (file)
@@ -16,7 +16,9 @@
 
 
 #include <BRep_Tool.hxx>
+#include <BRepAdaptor_Surface.hxx>
 #include <BRepTools.hxx>
+#include <BRepTools_WireExplorer.hxx>
 #include <DBRep_Face.hxx>
 #include <DBRep_IsoBuilder.hxx>
 #include <Geom2d_Curve.hxx>
 #include <HatchGen_Domain.hxx>
 #include <Precision.hxx>
 #include <TopAbs_ShapeEnum.hxx>
+#include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #include <TopoDS_Face.hxx>
+#include <TopoDS_Wire.hxx>
 
-//  Modified by Sergey KHROMOV - Thu Nov  9 12:08:37 2000
-static Standard_Real IntersectorConfusion = 1.e-10 ; // -8 ;
-static Standard_Real IntersectorTangency  = 1.e-10 ; // -8 ;
-//  Modified by Sergey KHROMOV - Thu Nov  9 12:08:38 2000
+#include <NCollection_IndexedDataMap.hxx>
+#include <TopTools_OrientedShapeMapHasher.hxx>
+
+// Providing consistency with intersection tolerance for the linear curves
+static Standard_Real IntersectorConfusion = Precision::PConfusion();
+static Standard_Real IntersectorTangency  = Precision::PConfusion();
 static Standard_Real HatcherConfusion2d   = 1.e-8 ;
 static Standard_Real HatcherConfusion3d   = 1.e-8 ;
 
@@ -97,8 +103,10 @@ Geom2dHatch_Hatcher (Geom2dHatch_Intersector (IntersectorConfusion,
   }
 
   //-----------------------------------------------------------------------
-  // Retreiving the edges and loading them into the hatcher.
+  // Retrieving the edges and its p-curves for further trimming
+  // and loading them into the hatcher
   //-----------------------------------------------------------------------
+  DataMapOfEdgePCurve anEdgePCurveMap;
 
   TopExp_Explorer ExpEdges;
   for (ExpEdges.Init (TopologicalFace, TopAbs_EDGE); ExpEdges.More(); ExpEdges.Next())
@@ -126,7 +134,7 @@ Geom2dHatch_Hatcher (Geom2dHatch_Intersector (IntersectorConfusion,
     if (Abs(PCurve->FirstParameter()-U1)<= Precision::PConfusion()
       && Abs(PCurve->LastParameter()-U2)<= Precision::PConfusion())
     {
-      AddElement (PCurve, TopologicalEdge.Orientation());
+      anEdgePCurveMap.Add(TopologicalEdge, PCurve);
     }
     else
     {
@@ -140,7 +148,6 @@ Geom2dHatch_Hatcher (Geom2dHatch_Intersector (IntersectorConfusion,
             U1 - TrimPCurve->BasisCurve()->LastParameter()  > Precision::PConfusion() ||
             U2 - TrimPCurve->BasisCurve()->LastParameter()  > Precision::PConfusion())
           {
-            AddElement (PCurve, TopologicalEdge.Orientation());
 #ifdef OCCT_DEBUG
             cout << "DBRep_IsoBuilder TrimPCurve : parameters out of range\n";
             cout << "    U1(" << U1 << "), Umin(" << PCurve->FirstParameter()
@@ -189,11 +196,20 @@ Geom2dHatch_Hatcher (Geom2dHatch_Intersector (IntersectorConfusion,
       // if U1 and U2 coincide-->do nothing
       if (Abs (U1 - U2) <= Precision::PConfusion()) continue;
       Handle (Geom2d_TrimmedCurve) TrimPCurve = new Geom2d_TrimmedCurve (PCurve, U1, U2);
-      Geom2dAdaptor_Curve aGAC (TrimPCurve);
-      AddElement (aGAC, TopologicalEdge.Orientation());
+      anEdgePCurveMap.Add(TopologicalEdge, TrimPCurve);
     }
   }
 
+  // Fill the gaps between 2D curves, and trim the intersecting ones.
+  FillGaps(TopologicalFace, anEdgePCurveMap);
+
+  // Load trimmed curves to the hatcher
+  Standard_Integer aNbE = anEdgePCurveMap.Extent();
+  for (Standard_Integer iE = 1; iE <= aNbE; ++iE)
+  {
+    AddElement(Geom2dAdaptor_Curve(anEdgePCurveMap(iE)),
+               anEdgePCurveMap.FindKey(iE).Orientation());
+  }
   //-----------------------------------------------------------------------
   // Loading and trimming the hatchings.
   //-----------------------------------------------------------------------
@@ -327,3 +343,299 @@ void DBRep_IsoBuilder::LoadIsos (const Handle(DBRep_Face)& Face) const
     }
   }
 }
+
+//=======================================================================
+// Function : FillGaps
+// Purpose  : 
+//=======================================================================
+void DBRep_IsoBuilder::FillGaps(const TopoDS_Face& theFace,
+                                DataMapOfEdgePCurve& theEdgePCurveMap)
+{
+  
+  // Get surface of the face for getting the 3D points from 2D coordinates
+  // of the p-curves bounds
+  BRepAdaptor_Surface aBASurf(theFace, Standard_False);
+
+  // Analyze each wire of the face separately
+  TopoDS_Iterator aItW(theFace);
+  for (; aItW.More(); aItW.Next())
+  {
+    const TopoDS_Shape& aW = aItW.Value();
+    if (aW.ShapeType() != TopAbs_WIRE)
+      continue;
+
+    // Use WireExplorer to iterate on edges of the wire
+    // to get the pairs of connected edges.
+    // Using WireExplorer will also allow avoiding treatment
+    // of the internal wires.
+    BRepTools_WireExplorer aWExp;
+    aWExp.Init(TopoDS::Wire(aW), theFace, myUMin, myUMax, myVMin, myVMax);
+    if (!aWExp.More())
+      continue;
+
+    // Check the number of edges in the wire, not to
+    // miss the wires containing one edge only
+    Standard_Boolean SingleEdge = Standard_True;
+    {
+      TopoDS_Iterator itE(aW);
+      if (!itE.More())
+        continue;
+      itE.Next();
+      SingleEdge = !itE.More();
+    }
+
+    TopoDS_Edge aPrevEdge, aCurrEdge;
+
+    // Get first edge and its p-curve
+    aCurrEdge = aWExp.Current();
+
+    // Ensure analysis of the pair of first and last edges
+    TopoDS_Edge aFirstEdge = aCurrEdge;
+    Standard_Real bStop = Standard_False;
+
+    // Iterate on all other edges
+    while (!bStop)
+    {
+      // Iteration to the next edge
+      aPrevEdge = aCurrEdge;
+      aWExp.Next();
+      // Get the current edge for analysis
+      if (aWExp.More())
+      {
+        aCurrEdge = aWExp.Current();
+      }
+      else
+      {
+        aCurrEdge = aFirstEdge;
+        bStop = Standard_True;
+      }
+
+      if (aPrevEdge.IsEqual(aCurrEdge) && !SingleEdge)
+        continue;
+
+      // Get p-curves
+      Handle(Geom2d_Curve)* pPC1 = theEdgePCurveMap.ChangeSeek(aPrevEdge);
+      Handle(Geom2d_Curve)* pPC2 = theEdgePCurveMap.ChangeSeek(aCurrEdge);
+      if (!pPC1 || !pPC2)
+        continue;
+
+      Handle(Geom2d_Curve)& aPrevC2d = *pPC1;
+      Handle(Geom2d_Curve)& aCurrC2d = *pPC2;
+
+      // Get p-curves parameters
+      Standard_Real fp, lp, fc, lc;
+      fp = aPrevC2d->FirstParameter();
+      lp = aPrevC2d->LastParameter();
+      fc = aCurrC2d->FirstParameter();
+      lc = aCurrC2d->LastParameter();
+
+      // Get common vertex to check if the gap between two edges is closed
+      // by the tolerance value of this vertex.
+      // Take into account the orientation of the edges to obtain the correct
+      // parameter of the vertex on edges.
+
+      // Get vertex on the previous edge
+      TopoDS_Vertex aCVOnPrev = TopExp::LastVertex(aPrevEdge, Standard_True);
+      if (aCVOnPrev.IsNull())
+        continue;
+
+      // Get parameter of the vertex on the previous edge
+      Standard_Real aTPrev = BRep_Tool::Parameter(aCVOnPrev, aPrevEdge);
+      if (aTPrev < fp)
+        aTPrev = fp;
+      else if (aTPrev > lp)
+        aTPrev = lp;
+
+      // Get vertex on the current edge
+      TopoDS_Vertex aCVOnCurr = TopExp::FirstVertex(aCurrEdge, Standard_True);
+      if (aCVOnCurr.IsNull() || !aCVOnPrev.IsSame(aCVOnCurr))
+        continue;
+
+      // Get parameter of the vertex on the current edge
+      Standard_Real aTCurr = BRep_Tool::Parameter(aCVOnCurr, aCurrEdge);
+      if (aTCurr < fc)
+        aTCurr = fc;
+      else if (aTCurr > lc)
+        aTCurr = lc;
+
+      // Get bounding points on the edges corresponding to the current vertex
+      gp_Pnt2d aPrevP2d = aPrevC2d->Value(aTPrev),
+               aCurrP2d = aCurrC2d->Value(aTCurr);
+
+      // Check if the vertex covers these bounding points by its tolerance
+      Standard_Real aTolV2 = BRep_Tool::Tolerance(aCVOnPrev);
+      gp_Pnt aPV = BRep_Tool::Pnt(aCVOnPrev);
+      // There is no need to check the distance if the tolerance
+      // of vertex is infinite (like in the test case sewing/tol_1/R2)
+      if (aTolV2 < Precision::Infinite())
+      {
+        aTolV2 *= aTolV2;
+
+        // Convert bounding point on previous edge into 3D
+        gp_Pnt aPrevPS = aBASurf.Value(aPrevP2d.X(), aPrevP2d.Y());
+
+        // Check if the vertex closes the gap
+        if (aPV.SquareDistance(aPrevPS) > aTolV2)
+          continue;
+
+        // Convert bounding point on current edge into 3D
+        gp_Pnt aCurrPS = aBASurf.Value(aCurrP2d.X(), aCurrP2d.Y());
+
+        // Check if the vertex closes the gap
+        if (aPV.SquareDistance(aCurrPS) > aTolV2)
+          continue;
+      }
+
+      // Create the segment
+      gp_Vec2d aV2d(aPrevP2d, aCurrP2d);
+      Standard_Real aSegmLen = aV2d.Magnitude();
+      // Do not add too small segments
+      Standard_Boolean bAddSegment = (aSegmLen > Precision::PConfusion());
+      // Check for periodic surfaces
+      if (bAddSegment)
+      {
+        if (aBASurf.IsUPeriodic())
+          bAddSegment = aSegmLen < aBASurf.UPeriod() / 4.;
+
+        if (bAddSegment && aBASurf.IsVPeriodic())
+          bAddSegment = aSegmLen < aBASurf.VPeriod() / 4.;
+      }
+
+      // Check that p-curves do not interfere near the vertex.
+      // And, if they do interfere, avoid creation of the segment.
+      if (bAddSegment && !aPrevEdge.IsEqual(aCurrEdge))
+      {
+        Geom2dAdaptor_Curve aPrevGC(aPrevC2d, fp, lp), aCurrGC(aCurrC2d, fc, lc);
+        Geom2dInt_GInter anInter(aPrevGC, aCurrGC, Precision::PConfusion(), Precision::PConfusion());
+        if (anInter.IsDone() && !anInter.IsEmpty())
+        {
+          // Collect intersection points
+          NCollection_List<IntRes2d_IntersectionPoint> aLPInt;
+          // Get bounding points from segments
+          Standard_Integer iP, aNbInt = anInter.NbSegments();
+          for (iP = 1; iP <= aNbInt; ++iP)
+          {
+            aLPInt.Append(anInter.Segment(iP).FirstPoint());
+            aLPInt.Append(anInter.Segment(iP).LastPoint());
+          }
+          // Get intersection points
+          aNbInt = anInter.NbPoints();
+          for (iP = 1; iP <= aNbInt; ++iP)
+            aLPInt.Append(anInter.Point(iP));
+
+          // Analyze the points and find the one closest to the current vertex
+          Standard_Boolean bPointFound = Standard_False;
+          Standard_Real aTPrevClosest = 0., aTCurrClosest = 0.;
+          Standard_Real aDeltaPrev = ::RealLast(), aDeltaCurr = ::RealLast();
+
+          NCollection_List<IntRes2d_IntersectionPoint>::Iterator aItLPInt(aLPInt);
+          for (; aItLPInt.More(); aItLPInt.Next())
+          {
+            const IntRes2d_IntersectionPoint& aPnt = aItLPInt.Value();
+            const Standard_Real aTIntPrev = aPnt.ParamOnFirst();
+            const Standard_Real aTIntCurr = aPnt.ParamOnSecond();
+            // Check if the intersection point is in range
+            if (aTIntPrev < fp || aTIntPrev > lp ||
+                aTIntCurr < fc || aTIntCurr > lc)
+            {
+              continue;
+            }
+
+            Standard_Real aDelta1 = Abs(aTIntPrev - aTPrev);
+            Standard_Real aDelta2 = Abs(aTIntCurr - aTCurr);
+            if (aDelta1 < aDeltaPrev || aDelta2 < aDeltaCurr)
+            {
+              aTPrevClosest = aTIntPrev;
+              aTCurrClosest = aTIntCurr;
+              aDeltaPrev = aDelta1;
+              aDeltaCurr = aDelta2;
+              bPointFound = Standard_True;
+            }
+          }
+
+          if (bPointFound)
+          {
+            // Check the number of common vertices between edges.
+            // If on the other end, there is also a common vertex,
+            // check where the intersection point is located. It might
+            // be closer to the other vertex than to the current one.
+            // And here we just need to close the gap, avoiding the trimming.
+            // If the common vertex is only one, do not create the segment,
+            // as we have the intersection of the edges and trimmed the 2d curves.
+            Standard_Integer aNbCV = 0;
+            for (TopoDS_Iterator it1(aPrevEdge); it1.More(); it1.Next())
+            {
+              for (TopoDS_Iterator it2(aCurrEdge); it2.More(); it2.Next())
+              {
+                if (it1.Value().IsSame(it2.Value()))
+                  ++aNbCV;
+              }
+            }
+
+            // Trim PCurves only if the intersection belongs to current parameter
+            Standard_Boolean bTrim = (aNbCV == 1 ||
+                                      (Abs(aTPrev - aTPrevClosest) < (lp - fp) / 2. ||
+                                       Abs(aTCurr - aTCurrClosest) < (lc - fc) / 2.));
+
+            if (bTrim)
+            {
+              // Check that the intersection point is covered by vertex tolerance
+              gp_Pnt2d aPInt = aPrevC2d->Value(aTPrevClosest);
+              const gp_Pnt aPOnS = aBASurf.Value(aPInt.X(), aPInt.Y());
+              if (aTolV2 > Precision::Infinite() || aPOnS.SquareDistance(aPV) < aTolV2)
+              {
+                Standard_Real f, l;
+
+                // Trim the curves with found parameters
+
+                // Prepare trimming parameters for previous curve
+                if (Abs(fp - aTPrev) < Abs(lp - aTPrev))
+                {
+                  f = aTPrevClosest;
+                  l = lp;
+                }
+                else
+                {
+                  f = fp;
+                  l = aTPrevClosest;
+                }
+
+                // Trim previous p-curve
+                if (l - f > Precision::PConfusion())
+                  aPrevC2d = new Geom2d_TrimmedCurve(aPrevC2d, f, l);
+
+                // Prepare trimming parameters for current p-curve
+                if (Abs(fc - aTCurr) < Abs(lc - aTCurr))
+                {
+                  f = aTCurrClosest;
+                  l = lc;
+                }
+                else
+                {
+                  f = fc;
+                  l = aTCurrClosest;
+                }
+
+                // Trim current p-curve
+                if (l - f > Precision::PConfusion())
+                  aCurrC2d = new Geom2d_TrimmedCurve(aCurrC2d, f, l);
+
+                // Do not create the segment, as we performed the trimming
+                // to the intersection point.
+                bAddSegment = Standard_False;
+              }
+            }
+          }
+        }
+      }
+
+      if (bAddSegment)
+      {
+        // Add segment to the hatcher to trim the iso-lines
+        Handle(Geom2d_Line) aLine = new Geom2d_Line(aPrevP2d, aV2d);
+        Handle(Geom2d_TrimmedCurve) aLineSegm = new Geom2d_TrimmedCurve(aLine, 0.0, aSegmLen);
+        AddElement(Geom2dAdaptor_Curve(aLineSegm), TopAbs_FORWARD);
+      }
+    }
+  }
+}
index 856ec8d..7fa19c0 100644 (file)
 #include <TColStd_Array1OfInteger.hxx>
 #include <Standard_Integer.hxx>
 #include <Geom2dHatch_Hatcher.hxx>
+#include <NCollection_IndexedDataMap.hxx>
 class TopoDS_Face;
 class DBRep_Face;
-
+class TopoDS_Shape;
+class TopTools_OrientedShapeMapHasher;
 
 //! Creation of isoparametric curves.
 class DBRep_IsoBuilder  : public Geom2dHatch_Hatcher
@@ -42,19 +44,30 @@ public:
   Standard_EXPORT DBRep_IsoBuilder(const TopoDS_Face& TopologicalFace, const Standard_Real Infinite, const Standard_Integer NbIsos);
   
   //! Returns the total number of domains.
-    Standard_Integer NbDomains() const;
+  Standard_Integer NbDomains() const
+  {
+    return myNbDom;
+  }
   
   //! Loading of the isoparametric curves in the
   //! Data Structure of a drawable face.
   Standard_EXPORT void LoadIsos (const Handle(DBRep_Face)& Face) const;
 
-
-
-
 protected:
 
+  typedef NCollection_IndexedDataMap
+    <TopoDS_Shape, Handle(Geom2d_Curve), TopTools_OrientedShapeMapHasher>
+      DataMapOfEdgePCurve;
 
-
+  //! Adds to the hatcher the 2D segments connecting the p-curves
+  //! of the neighboring edges to close the 2D gaps which are
+  //! closed in 3D by the tolerance of vertices shared between edges.
+  //! It will allow trimming correctly the iso-lines passing through
+  //! such gaps.
+  //! The method also trims the intersecting 2D curves of the face,
+  //! forbidding the iso-lines beyond the face boundaries.
+  Standard_EXPORT void FillGaps(const TopoDS_Face& theFace,
+                                DataMapOfEdgePCurve& theEdgePCurveMap);
 
 
 private:
@@ -76,10 +89,4 @@ private:
 };
 
 
-#include <DBRep_IsoBuilder.lxx>
-
-
-
-
-
 #endif // _DBRep_IsoBuilder_HeaderFile
diff --git a/src/DBRep/DBRep_IsoBuilder.lxx b/src/DBRep/DBRep_IsoBuilder.lxx
deleted file mode 100644 (file)
index 3a06a18..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Created on: 1994-03-25
-// Created by: Jean Marc LACHAUME
-// Copyright (c) 1994-1999 Matra Datavision
-// Copyright (c) 1999-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-//=======================================================================
-// Function : NbDomains
-// Purpose  : Returns the total number of domains.
-//=======================================================================
-
-inline Standard_Integer DBRep_IsoBuilder::NbDomains () const
-{
-  return myNbDom ;
-}
index 98f36e2..3f042dd 100755 (executable)
@@ -14,7 +14,6 @@ DBRep_HideData.hxx
 DBRep_HideData.lxx
 DBRep_IsoBuilder.cxx
 DBRep_IsoBuilder.hxx
-DBRep_IsoBuilder.lxx
 DBRep_ListIteratorOfListOfEdge.hxx
 DBRep_ListIteratorOfListOfFace.hxx
 DBRep_ListIteratorOfListOfHideData.hxx
index a6bb20c..7d565be 100644 (file)
@@ -444,7 +444,7 @@ math_FunctionRoots::math_FunctionRoots(math_FunctionWithDerivative& F,
           //-- Find minimum of the function |F| between x0 and x3
           //-- by searching for the zero of the function derivative
           DerivFunction aDerF(F);
-          math_BracketedRoot aBR(aDerF, x0, x3, EpsX);
+          math_BracketedRoot aBR(aDerF, x0, x3, _EpsX);
           if (aBR.IsDone())
           {
             aSolX1 = aBR.Root();
diff --git a/tests/bugs/modalg_7/bug28385_1 b/tests/bugs/modalg_7/bug28385_1
new file mode 100644 (file)
index 0000000..0ca3bec
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_face.brep] face
+
+checkview -display face -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_10 b/tests/bugs/modalg_7/bug28385_10
new file mode 100644 (file)
index 0000000..8a2bacf
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_two_circ_face_gap.brep] face
+
+smallview
+isos face 50
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug28385_2 b/tests/bugs/modalg_7/bug28385_2
new file mode 100644 (file)
index 0000000..a1b7536
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_planar_face.brep] face
+
+checkview -display face -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_3 b/tests/bugs/modalg_7/bug28385_3
new file mode 100644 (file)
index 0000000..2f3243d
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_two_lines_face.brep] face
+
+checkview -display face -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_4 b/tests/bugs/modalg_7/bug28385_4
new file mode 100644 (file)
index 0000000..feb48f3
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_circ_face.brep] face
+
+smallview
+don face; fit
+isos face 50
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug28385_5 b/tests/bugs/modalg_7/bug28385_5
new file mode 100644 (file)
index 0000000..c3ac19c
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_circ_face_hole.brep] face
+
+smallview
+isos face 50
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
diff --git a/tests/bugs/modalg_7/bug28385_6 b/tests/bugs/modalg_7/bug28385_6
new file mode 100644 (file)
index 0000000..27836bf
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_step4_A8_face.brep] face
+
+checkview -display face -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_7 b/tests/bugs/modalg_7/bug28385_7
new file mode 100644 (file)
index 0000000..77ee2a3
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_27170_face.brep] face
+
+checkview -display face -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_8 b/tests/bugs/modalg_7/bug28385_8
new file mode 100644 (file)
index 0000000..7a8544e
--- /dev/null
@@ -0,0 +1,12 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_bug763_faces.brep] faces
+
+checkview -display faces -2d -path ${imagedir}/${test_image}-2d.png
diff --git a/tests/bugs/modalg_7/bug28385_9 b/tests/bugs/modalg_7/bug28385_9
new file mode 100644 (file)
index 0000000..21d26b2
--- /dev/null
@@ -0,0 +1,16 @@
+puts "========"
+puts "OCC28385"
+puts "========"
+puts ""
+#################################################
+# Improve drawing isolines (DBRep_IsoBuilder algorithm)
+#################################################
+
+
+restore [locate_data_file bug28385_two_circ_face.brep] face
+
+smallview
+isos face 50
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png