0030422: Random behaviour of BRepAdaptor_CompCurve
[occt.git] / src / BRepTools / BRepTools_WireExplorer.cxx
index 49e4e4e..be98890 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>
@@ -62,7 +63,10 @@ static Standard_Real GetNextParamOnPC(const Handle(Geom2d_Curve)& aPC,
 //function : BRepTools_WireExplorer
 //purpose  : 
 //=======================================================================
-BRepTools_WireExplorer::BRepTools_WireExplorer() 
+BRepTools_WireExplorer::BRepTools_WireExplorer()
+: myReverse(Standard_False),
+  myTolU(0.0),
+  myTolV(0.0)
 {
 }
 
@@ -101,14 +105,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,162 +156,190 @@ void  BRepTools_WireExplorer::Init(const TopoDS_Wire& W,
   myReverse = Standard_False;
 
   if (!myFace.IsNull())
+  {
+    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);
-         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
+  TopTools_IndexedMapOfShape vmap;
   //  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);
+      Standard_Integer currsize = vmap.Extent(), 
+                       ind = vmap.Add(V1);
+      if (currsize >= ind)
+      {
+        vmap.RemoveKey(V1);
+      }
+    }
 
-      if( !V2.IsNull() )
-       {
-         V2.Orientation(TopAbs_REVERSED);
-         if(!vmap.Add(V2))
-           vmap.Remove(V2);
-       }
+    if (!V2.IsNull())
+    {
+      V2.Orientation(TopAbs_REVERSED);
+      Standard_Integer currsize = vmap.Extent(),
+                       ind = vmap.Add(V2);
+      if (currsize >= ind)
+      {
+        vmap.RemoveKey(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"
-    while (itt.Key().Orientation() != TopAbs_FORWARD) {
-      itt.Next();
-      if (!itt.More()) break;
+    //TopTools_MapIteratorOfMapOfShape itt(vmap);
+    //while (itt.Key().Orientation() != TopAbs_FORWARD) {
+    //  itt.Next();
+    //  if (!itt.More()) break;
+    //}
+    //if (itt.More()) V1 = TopoDS::Vertex(itt.Key());
+    Standard_Integer ind = 0;
+    for (ind = 1; ind <= vmap.Extent(); ++ind)
+    {
+      if (vmap(ind).Orientation() == TopAbs_FORWARD)
+      {
+        V1 = TopoDS::Vertex(vmap(ind));
+        break;
+      }
     }
-    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);
@@ -279,23 +347,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);
 
 }
 
@@ -452,6 +520,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.
@@ -598,6 +672,13 @@ const TopoDS_Edge&  BRepTools_WireExplorer::Current()const
 //=======================================================================
 TopAbs_Orientation BRepTools_WireExplorer::Orientation() const
 {
+  if (myVertex.IsNull()
+  && !myEdge.IsNull())
+  {
+    // infinite edge
+    return TopAbs_FORWARD;
+  }
+
   TopoDS_Iterator it(myEdge,Standard_False);
   while (it.More()) {
     if (myVertex.IsSame(it.Value()))