0029311: Implementation of the Oriented Bounding Boxes (OBB) functionality
[occt.git] / src / BRepBndLib / BRepBndLib.cxx
old mode 100755 (executable)
new mode 100644 (file)
index 28bc3b5..f89d559
+// Copyright (c) 1995-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.
 
-#include <BRepBndLib.ixx>
-#include <TopExp_Explorer.hxx>
-#include <BRepAdaptor_Surface.hxx>
-#include <BRepAdaptor_Curve.hxx>
-#include <BRep_Tool.hxx> 
-#include <TopoDS.hxx>
+
+#include <Bnd_Box.hxx>
 #include <BndLib_Add3dCurve.hxx>
 #include <BndLib_AddSurface.hxx>
-#include <Geom_Surface.hxx>
-#include <TopLoc_Location.hxx>
-#include <Poly_Triangulation.hxx>
-#include <Poly_PolygonOnTriangulation.hxx>
-#include <Poly_Polygon3D.hxx>
 #include <BRep_Polygon3D.hxx>
-#include <TColStd_HArray1OfInteger.hxx>
-#include <TColStd_Array1OfInteger.hxx>
-#include <TColgp_Array1OfPnt.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepBndLib.hxx>
 #include <Geom_Curve.hxx>
+#include <Geom_Surface.hxx>
 #include <GeomAdaptor_Curve.hxx>
-#include <BndLib_Add3dCurve.hxx>
-
+#include <Poly_Polygon3D.hxx>
+#include <Poly_PolygonOnTriangulation.hxx>
+#include <Poly_Triangulation.hxx>
+#include <TColgp_Array1OfPnt.hxx>
+#include <TColStd_Array1OfInteger.hxx>
+#include <TColStd_HArray1OfInteger.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopLoc_Location.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Shape.hxx>
+#include <Adaptor3d_HCurve.hxx>
+#include <Adaptor3d_HSurface.hxx>
+#include <BRepTools.hxx>
+#include <Geom_BSplineSurface.hxx>
+#include <Geom_BezierSurface.hxx>
+#include <Bnd_Box2d.hxx>
+#include <BndLib_Add2dCurve.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
+#include <ElSLib.hxx>
+#include <ElCLib.hxx>
+#include <Geom_Plane.hxx>
+#include <Extrema_ExtSS.hxx>
+#include <GeomAdaptor_Surface.hxx>
+//
+static Standard_Boolean CanUseEdges(const Adaptor3d_Surface& BS);
+//
+static void FindExactUVBounds(const TopoDS_Face F, 
+                              Standard_Real& umin, Standard_Real& umax, 
+                              Standard_Real& vmin, Standard_Real& vmax,
+                              const Standard_Real Tol, 
+                              Standard_Boolean& isNaturalRestriction);
+//
+static void AdjustFaceBox(const BRepAdaptor_Surface& BS, 
+                          const Standard_Real umin, const Standard_Real umax, 
+                          const Standard_Real vmin, const Standard_Real vmax,
+                          Bnd_Box& FaceBox,
+                          const Bnd_Box& EdgeBox, const Standard_Real Tol);
+//
+static Standard_Boolean IsModifySize(const BRepAdaptor_Surface& theBS, 
+                                     const gp_Pln& thePln, const gp_Pnt& theP,
+                                     const Standard_Real umin, const Standard_Real umax,
+                                     const Standard_Real vmin, const Standard_Real vmax,
+                                     const BRepTopAdaptor_FClass2d& theFClass,
+                                     const Standard_Real theTolU, const Standard_Real theTolV);
 
+//
 //=======================================================================
 //function : Add
 //purpose  : Add a shape bounding to a box
 //=======================================================================
-
-void BRepBndLib::Add(const TopoDS_Shape& S, Bnd_Box& B)
+void BRepBndLib::Add(const TopoDS_Shape& S, Bnd_Box& B, Standard_Boolean useTriangulation)
 {
   TopExp_Explorer ex;
 
   // Add the faces
-
   BRepAdaptor_Surface BS;
-  Handle(Geom_Surface) GS;
-  Handle(Poly_Triangulation) T;
-  TopLoc_Location l;
+  TopLoc_Location l, aDummyLoc;
   Standard_Integer i, nbNodes;
   BRepAdaptor_Curve BC;
 
   for (ex.Init(S,TopAbs_FACE); ex.More(); ex.Next()) {
     const TopoDS_Face& F = TopoDS::Face(ex.Current());
-    T = BRep_Tool::Triangulation(F, l);
-    if (!T.IsNull()) {
+    const Handle(Poly_Triangulation)& T = BRep_Tool::Triangulation(F, l);
+    const Handle(Geom_Surface)& GS = BRep_Tool::Surface (F, aDummyLoc);
+    if ((useTriangulation || GS.IsNull()) && !T.IsNull())
+    {
       nbNodes = T->NbNodes();
       const TColgp_Array1OfPnt& Nodes = T->Nodes();
       for (i = 1; i <= nbNodes; i++) {
-       if (l.IsIdentity()) B.Add(Nodes(i));
-       else B.Add(Nodes(i).Transformed(l));
+        if (l.IsIdentity()) B.Add(Nodes(i));
+        else B.Add(Nodes(i).Transformed(l));
       }
       //       B.Enlarge(T->Deflection());
       B.Enlarge(T->Deflection() + BRep_Tool::Tolerance(F));
-    }
-    else {
-      GS = BRep_Tool::Surface(F, l);
+    } else
+    {
       if (!GS.IsNull()) {
-       BS.Initialize(F, Standard_False);
-       if (BS.GetType() != GeomAbs_Plane) {
-         BS.Initialize(F);
-         BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
-       }
-       else {
-         // on travaille directement sur les courbes 3d.
-         TopExp_Explorer ex2(F, TopAbs_EDGE);
-         if (!ex2.More()) {
-           BS.Initialize(F);
-           BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
-         }
-         else {
-           for (;ex2.More();ex2.Next()) {
-             BC.Initialize(TopoDS::Edge(ex2.Current()));
-             BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(F), B);
-           }
-           B.Enlarge(BRep_Tool::Tolerance(F));
-         }
-       }
+        BS.Initialize(F, Standard_False);
+        if (BS.GetType() != GeomAbs_Plane) {
+          BS.Initialize(F);
+          BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
+        }
+        else {
+          // on travaille directement sur les courbes 3d.
+          TopExp_Explorer ex2(F, TopAbs_EDGE);
+          if (!ex2.More()) {
+            BS.Initialize(F);
+            BndLib_AddSurface::Add(BS, BRep_Tool::Tolerance(F), B);
+          }
+          else {
+            for (;ex2.More();ex2.Next()) {
+              BC.Initialize(TopoDS::Edge(ex2.Current()));
+              BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(F), B);
+            }
+            B.Enlarge(BRep_Tool::Tolerance(F));
+          }
+        }
       }
     }
   }
 
   // Add the edges not in faces
-
-
   Handle(TColStd_HArray1OfInteger) HIndices;
   Handle(Poly_PolygonOnTriangulation) Poly;
-
-  for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE); ex.More(); ex.Next()) {
+  Handle(Poly_Triangulation) T;
+  for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE); ex.More(); ex.Next())
+  {
     const TopoDS_Edge& E = TopoDS::Edge(ex.Current());
     Handle(Poly_Polygon3D) P3d = BRep_Tool::Polygon3D(E, l);
-    if (!P3d.IsNull()) {
+    if (!P3d.IsNull())
+    {
       const TColgp_Array1OfPnt& Nodes = P3d->Nodes();
       nbNodes = P3d->NbNodes();
-      for (i = 1; i <= nbNodes; i++) {
-       if (l.IsIdentity()) B.Add(Nodes(i));
-       else B.Add(Nodes(i).Transformed(l));
+      for (i = 1; i <= nbNodes; i++)
+      {
+        if (l.IsIdentity()) B.Add(Nodes(i));
+        else B.Add(Nodes(i).Transformed(l));
       }
       //       B.Enlarge(P3d->Deflection());
       B.Enlarge(P3d->Deflection() + BRep_Tool::Tolerance(E));
     }
-    else {
+    else
+    {
       BRep_Tool::PolygonOnTriangulation(E, Poly, T, l);
-      if (!Poly.IsNull()) {
-       const TColStd_Array1OfInteger& Indices = Poly->Nodes();
-       const TColgp_Array1OfPnt& Nodes = T->Nodes();
-       nbNodes = Indices.Length();
-       for (i = 1; i <= nbNodes; i++) {
-         if (l.IsIdentity()) B.Add(Nodes(Indices(i)));
-         else B.Add(Nodes(Indices(i)).Transformed(l));
-       }
-       //      B.Enlarge(T->Deflection());
-       B.Enlarge(Poly->Deflection() + BRep_Tool::Tolerance(E));
+      if (useTriangulation && !Poly.IsNull())
+      {
+        const TColStd_Array1OfInteger& Indices = Poly->Nodes();
+        const TColgp_Array1OfPnt& Nodes = T->Nodes();
+        nbNodes = Indices.Length();
+        for (i = 1; i <= nbNodes; i++)
+        {
+          if (l.IsIdentity()) B.Add(Nodes(Indices(i)));
+          else B.Add(Nodes(Indices(i)).Transformed(l));
+        }
+        //     B.Enlarge(T->Deflection());
+        B.Enlarge(Poly->Deflection() + BRep_Tool::Tolerance(E));
       }
       else {
-       if (BRep_Tool::IsGeometric(E)) {
-         BC.Initialize(E);
-         BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(E), B);
-       }
+        if (BRep_Tool::IsGeometric(E))
+        {
+          BC.Initialize(E);
+          BndLib_Add3dCurve::Add(BC, BRep_Tool::Tolerance(E), B);
+        }
       }
     }
   }
@@ -157,3 +208,582 @@ void BRepBndLib::AddClose(const TopoDS_Shape& S, Bnd_Box& B)
   }
 }
 
+//=======================================================================
+//function : AddOptimal
+//purpose  : Add a shape bounding to a box
+//=======================================================================
+void BRepBndLib::AddOptimal(const TopoDS_Shape& S, Bnd_Box& B, 
+                            const Standard_Boolean useTriangulation, 
+                            const Standard_Boolean useShapeTolerance)
+{
+  TopExp_Explorer ex;
+
+  // Add the faces
+  BRepAdaptor_Surface BS;
+  Handle(Poly_Triangulation) T;
+  TopLoc_Location l;
+  Standard_Integer i, nbNodes;
+  BRepAdaptor_Curve BC;
+
+  for (ex.Init(S,TopAbs_FACE); ex.More(); ex.Next()) {
+    const TopoDS_Face& F = TopoDS::Face(ex.Current());
+    T = BRep_Tool::Triangulation(F, l);
+    Bnd_Box aLocBox;
+    if (useTriangulation && !T.IsNull())
+    {
+      nbNodes = T->NbNodes();
+      const TColgp_Array1OfPnt& Nodes = T->Nodes();
+      for (i = 1; i <= nbNodes; i++) {
+        if (l.IsIdentity()) aLocBox.Add(Nodes(i));
+        else aLocBox.Add(Nodes(i).Transformed(l));
+      }
+      //       B.Enlarge(T->Deflection());
+      aLocBox.Enlarge(T->Deflection() + BRep_Tool::Tolerance(F));
+      Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
+      aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
+      B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
+    } 
+    else
+    {
+      const Handle(Geom_Surface)& GS = BRep_Tool::Surface(F, l);
+      if (!GS.IsNull()) {
+        BS.Initialize(F, Standard_False);
+        if (CanUseEdges(BS)) {
+          TopExp_Explorer ex2(F, TopAbs_EDGE);
+          if (!ex2.More()) {
+            BS.Initialize(F);
+            Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
+            BndLib_AddSurface::AddOptimal(BS, Tol, aLocBox);
+          }
+          else
+          {
+            Standard_Real Tol;
+            for (;ex2.More();ex2.Next()) {
+              Bnd_Box anEBox;
+              const TopoDS_Edge& anE = TopoDS::Edge(ex2.Current());
+              if(BRep_Tool::Degenerated(anE))
+              {
+                continue;
+              }
+              BC.Initialize(anE);
+              Tol = useShapeTolerance?  BRep_Tool::Tolerance(anE) : 0.;
+              BndLib_Add3dCurve::AddOptimal(BC, Tol, anEBox);
+              aLocBox.Add(anEBox);
+            }
+          }
+        }
+        else
+        {
+          Standard_Real umin, umax, vmin, vmax;
+          Standard_Boolean isNaturalRestriction = Standard_False;
+          Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
+          FindExactUVBounds(F, umin, umax, vmin, vmax, Tol, isNaturalRestriction);
+          BndLib_AddSurface::AddOptimal(BS, umin, umax, vmin, vmax, 
+                                        Tol, aLocBox);
+          //
+          if(!isNaturalRestriction)
+          {
+            TopExp_Explorer ex2(F, TopAbs_EDGE);
+            Bnd_Box EBox;
+            for (;ex2.More();ex2.Next()) {
+              Bnd_Box anEBox;
+              const TopoDS_Edge& anE = TopoDS::Edge(ex2.Current());
+              if(BRep_Tool::Degenerated(anE))
+              {
+                continue;
+              }
+              BC.Initialize(anE);
+              Tol = useShapeTolerance?  BRep_Tool::Tolerance(anE) : 0.;
+              BndLib_Add3dCurve::AddOptimal(BC, Tol, anEBox);
+              EBox.Add(anEBox);
+            }
+            Tol = useShapeTolerance?  BRep_Tool::Tolerance(F) : 0.;
+            AdjustFaceBox(BS, umin, umax, vmin, vmax, aLocBox, EBox, 
+                          Tol);
+          }
+        }
+        Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
+        aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
+        B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
+      }
+    }
+  }
+
+  // Add the edges not in faces
+  Handle(TColStd_HArray1OfInteger) HIndices;
+  Handle(Poly_PolygonOnTriangulation) Poly;
+
+  for (ex.Init(S,TopAbs_EDGE,TopAbs_FACE); ex.More(); ex.Next())
+  {
+    const TopoDS_Edge& E = TopoDS::Edge(ex.Current());
+    Bnd_Box aLocBox;
+    Handle(Poly_Polygon3D) P3d = BRep_Tool::Polygon3D(E, l);
+    if (useTriangulation && (!P3d.IsNull()))
+    {
+      const TColgp_Array1OfPnt& Nodes = P3d->Nodes();
+      nbNodes = P3d->NbNodes();
+      for (i = 1; i <= nbNodes; i++)
+      {
+        if (l.IsIdentity()) aLocBox.Add(Nodes(i));
+        else aLocBox.Add(Nodes(i).Transformed(l));
+      }
+      Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
+      aLocBox.Enlarge(P3d->Deflection() + Tol);
+    }
+    else
+    {
+      BRep_Tool::PolygonOnTriangulation(E, Poly, T, l);
+      if (useTriangulation && !Poly.IsNull())
+      {
+        const TColStd_Array1OfInteger& Indices = Poly->Nodes();
+        const TColgp_Array1OfPnt& Nodes = T->Nodes();
+        nbNodes = Indices.Length();
+        for (i = 1; i <= nbNodes; i++)
+        {
+          if (l.IsIdentity()) aLocBox.Add(Nodes(Indices(i)));
+          else aLocBox.Add(Nodes(Indices(i)).Transformed(l));
+        }
+        Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
+        aLocBox.Enlarge(Poly->Deflection() + Tol);
+      }
+      else {
+        if (BRep_Tool::IsGeometric(E))
+        {
+          BC.Initialize(E);
+          Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(E) : 0.;
+          BndLib_Add3dCurve::AddOptimal(BC, Tol, aLocBox);
+        }
+      }
+    }
+    if (!aLocBox.IsVoid())
+    {
+      Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
+      aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
+      B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
+    }
+  }
+
+  // Add the vertices not in edges
+
+  for (ex.Init(S,TopAbs_VERTEX,TopAbs_EDGE); ex.More(); ex.Next()) {
+    Bnd_Box aLocBox;
+    const TopoDS_Vertex& aV = TopoDS::Vertex(ex.Current());
+    aLocBox.Add(BRep_Tool::Pnt(aV));
+    Standard_Real Tol = useShapeTolerance?  BRep_Tool::Tolerance(aV) : 0.;
+    aLocBox.Enlarge(Tol);
+    Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
+    aLocBox.Get(xmin, ymin, zmin, xmax, ymax, zmax);
+    B.Update(xmin, ymin, zmin, xmax, ymax, zmax);
+  }
+}
+
+//=======================================================================
+//function : CanUseEdges
+//purpose  : Define is it possible using only edges bnd boxes 
+//           to get face bnd box
+//=======================================================================
+Standard_Boolean CanUseEdges(const Adaptor3d_Surface& BS)
+{
+  GeomAbs_SurfaceType aST = BS.GetType();
+  if(aST == GeomAbs_Plane ||
+     aST == GeomAbs_Cylinder ||
+     aST == GeomAbs_Cone ||
+     aST == GeomAbs_SurfaceOfExtrusion)
+  {
+    return Standard_True;
+  }
+  else if(aST == GeomAbs_SurfaceOfRevolution)
+  {
+    const Handle(Adaptor3d_HCurve)& aBC = BS.BasisCurve();
+    if(aBC->GetType() == GeomAbs_Line)
+    {
+      return Standard_True;
+    }
+    else
+    {
+      return Standard_False;
+    }
+  }
+  else if(aST == GeomAbs_OffsetSurface)
+  {
+    const Handle(Adaptor3d_HSurface)& aS = BS.BasisSurface();
+    return CanUseEdges(aS->Surface());
+  }
+  else if(aST == GeomAbs_BSplineSurface)
+  {
+    Handle(Geom_BSplineSurface) aBSpl = BS.BSpline();
+    if((aBSpl->UDegree() == 1 && aBSpl->NbUKnots() == 2) ||
+       (aBSpl->VDegree() == 1 && aBSpl->NbVKnots() == 2))
+    {
+      return Standard_True;
+    }
+    else
+    {
+      return Standard_False;
+    }
+  }
+  else if(aST == GeomAbs_BezierSurface)
+  {
+    Handle(Geom_BezierSurface) aBz = BS.Bezier();
+    if((aBz->UDegree() == 1 ) ||
+       (aBz->VDegree() == 1 ))
+    {
+      return Standard_True;
+    }
+    else
+    {
+      return Standard_False;
+    }
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : FindExactUVBounds
+//purpose  : 
+//=======================================================================
+void FindExactUVBounds(const TopoDS_Face FF, 
+                       Standard_Real& umin, Standard_Real& umax, 
+                       Standard_Real& vmin, Standard_Real& vmax,
+                       const Standard_Real Tol, 
+                       Standard_Boolean& isNaturalRestriction)
+{
+  TopoDS_Face F = FF;
+  F.Orientation(TopAbs_FORWARD);
+  TopExp_Explorer ex(F,TopAbs_EDGE);
+  //
+  //Check Natural restriction
+  isNaturalRestriction = BRep_Tool::NaturalRestriction(F); //Can we trust this flag?
+  BRepAdaptor_Surface aBAS(F, Standard_False);
+  if(!isNaturalRestriction)
+  {
+    //Check by comparing pcurves and surface boundaries
+    umin = aBAS.FirstUParameter();
+    umax = aBAS.LastUParameter();
+    vmin = aBAS.FirstVParameter();
+    vmax = aBAS.LastVParameter();
+    Standard_Boolean isUperiodic = aBAS.IsUPeriodic(), isVperiodic = aBAS.IsVPeriodic();
+    Standard_Real aT1, aT2;
+    Standard_Real TolU = Max(aBAS.UResolution(Tol), Precision::PConfusion());
+    Standard_Real TolV = Max(aBAS.VResolution(Tol), Precision::PConfusion());
+    Standard_Integer Nu = 0, Nv = 0, NbEdges = 0;
+    gp_Vec2d Du(1, 0), Dv(0, 1);
+    gp_Pnt2d aP;
+    gp_Vec2d aV;
+    for (;ex.More();ex.Next()) {
+      NbEdges++;
+      if(NbEdges > 4)
+      {
+        break;
+      }
+      const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
+      const Handle(Geom2d_Curve) aC2D = BRep_Tool::CurveOnSurface(aE, F, aT1, aT2);
+      if (aC2D.IsNull()) 
+      {
+        break;
+      }
+      //
+      aC2D->D1((aT1 + aT2)/2., aP, aV);
+      Standard_Real magn = aV.SquareMagnitude();
+      if(magn < gp::Resolution())
+      {
+        break;
+      }
+      else
+      {
+        aV /= Sqrt(magn);
+      }
+      Standard_Real u = aP.X(), v = aP.Y();
+      if(isUperiodic)
+      {
+        ElCLib::InPeriod(u, umin, umax);
+      }
+      if(isVperiodic)
+      {
+        ElCLib::InPeriod(v, vmin, vmax);
+      }
+      //
+      if(Abs(u - umin) <= TolU || Abs(u - umax) <= TolU)
+      {
+        Standard_Real d = Dv * aV;
+        if(1. - Abs(d) <= Precision::PConfusion())
+        {
+          Nu++;
+          if(Nu > 2)
+          {
+            break;
+          }
+        }
+        else
+        {
+          break;
+        }
+      }
+      else if(Abs(v - vmin) <= TolV || Abs(v - vmax) <= TolV)
+      {
+        Standard_Real d = Du * aV;
+        if(1. - Abs(d) <= Precision::PConfusion())
+        {
+          Nv++;
+          if(Nv > 2)
+          {
+            break;
+          }
+        }
+        else
+        {
+          break;
+        }
+      }
+      else
+      {
+        break;
+      }
+    }
+    if(Nu == 2 && Nv == 2)
+    {
+      isNaturalRestriction = Standard_True;
+    }
+  }
+  //
+  if(isNaturalRestriction)
+  {
+    umin = aBAS.FirstUParameter();
+    umax = aBAS.LastUParameter();
+    vmin = aBAS.FirstVParameter();
+    vmax = aBAS.LastVParameter();
+    return;
+  }
+
+  // fill box for the given face
+  Standard_Real aT1, aT2;
+  Standard_Real TolU = Max(aBAS.UResolution(Tol), Precision::PConfusion());
+  Standard_Real TolV = Max(aBAS.VResolution(Tol), Precision::PConfusion());
+  Standard_Real TolUV = Max(TolU, TolV);
+  Bnd_Box2d aBox;
+  ex.Init(F,TopAbs_EDGE);
+  for (;ex.More();ex.Next()) {
+    const TopoDS_Edge& aE = TopoDS::Edge(ex.Current());
+    const Handle(Geom2d_Curve) aC2D = BRep_Tool::CurveOnSurface(aE, F, aT1, aT2);
+    if (aC2D.IsNull()) 
+    {
+      continue;
+    }
+    //
+    BndLib_Add2dCurve::AddOptimal(aC2D, aT1, aT2, TolUV, aBox);
+    //
+  }
+  //
+  aBox.Get(umin, vmin, umax, vmax);
+  //
+  TopLoc_Location aLoc;
+  Handle(Geom_Surface) aS = BRep_Tool::Surface(FF, aLoc);
+  Standard_Real aUmin, aUmax, aVmin, aVmax;
+  aS->Bounds(aUmin, aUmax, aVmin, aVmax);
+  if(!aS->IsUPeriodic())
+  {
+    umin = Max(aUmin, umin);
+    umax = Min(aUmax, umax);
+  }
+  else
+  {
+    if(umax - umin > aS->UPeriod())
+    {
+      Standard_Real delta = umax - umin - aS->UPeriod();
+      umin += delta/2.;
+      umax -= delta/2;
+    }
+  }
+  //
+  if(!aS->IsVPeriodic())
+  {
+    vmin = Max(aVmin, vmin);
+    vmax = Min(aVmax, vmax);
+  }
+  else
+  {
+    if(vmax - vmin > aS->VPeriod())
+    {
+      Standard_Real delta = vmax - vmin - aS->VPeriod();
+      vmin += delta/2.;
+      vmax -= delta/2;
+    }
+  }
+}
+//=======================================================================
+//function : Reorder
+//purpose  : 
+//=======================================================================
+inline void Reorder(Standard_Real& a, Standard_Real& b)
+{
+  if(a > b)
+  {
+    Standard_Real t = a;
+    a = b;
+    b = t;
+  }
+}
+//=======================================================================
+//function : IsModifySize
+//purpose  : 
+//=======================================================================
+Standard_Boolean IsModifySize(const BRepAdaptor_Surface& theBS, 
+                              const gp_Pln& thePln, const gp_Pnt& theP,
+                              const Standard_Real umin, const Standard_Real umax,
+                              const Standard_Real vmin, const Standard_Real vmax,
+                              const BRepTopAdaptor_FClass2d& theFClass,
+                              const Standard_Real theTolU, const Standard_Real theTolV)
+{
+  Standard_Real pu1 = 0, pu2, pv1 = 0, pv2;
+  ElSLib::PlaneParameters(thePln.Position(), theP, pu2, pv2);
+  Reorder(pu1, pu2);
+  Reorder(pv1, pv2);
+  Handle(Geom_Plane) aPlane = new Geom_Plane(thePln);
+  GeomAdaptor_Surface aGAPln(aPlane, pu1, pu2, pv1, pv2);
+  Extrema_ExtSS anExtr(aGAPln, theBS, pu1, pu2, pv1, pv2, umin, umax, vmin, vmax, theTolU, theTolV);
+  if(anExtr.IsDone())
+  {
+    if(anExtr.NbExt() > 0)
+    {
+      Standard_Integer i, imin = 0;;
+      Standard_Real dmin = RealLast();
+      Standard_Real uextr = 0., vextr = 0.;
+      Extrema_POnSurf P1, P2;
+      for(i = 1; i <= anExtr.NbExt(); ++i)
+      {
+        Standard_Real d = anExtr.SquareDistance(i);
+        if(d < dmin)
+        {
+          imin = i;
+          dmin = d;
+        }
+      }
+      if(imin > 0)
+      {
+        anExtr.Points(imin, P1, P2);
+        P2.Parameter(uextr, vextr);
+      }
+      else
+      {
+        return Standard_False;
+      }
+      //
+      gp_Pnt2d aP2d(uextr, vextr);
+      TopAbs_State aSt = theFClass.Perform(aP2d);
+      if(aSt == TopAbs_OUT)
+      {
+        return Standard_True;
+      }
+    }
+    else
+    {
+      return Standard_True; //extrema point seems to be out of face UV bounds
+    }
+  }
+  //
+  return Standard_False;
+}
+//
+//=======================================================================
+//function : AdjustFaceBox
+//purpose  : 
+//=======================================================================
+void AdjustFaceBox(const BRepAdaptor_Surface& BS, 
+                   const Standard_Real umin, const Standard_Real umax, 
+                   const Standard_Real vmin, const Standard_Real vmax,
+                   Bnd_Box& FaceBox,
+                   const Bnd_Box& EdgeBox, const Standard_Real Tol)
+{
+  Standard_Real fxmin, fymin, fzmin, fxmax, fymax, fzmax;
+  Standard_Real exmin, eymin, ezmin, exmax, eymax, ezmax;
+  //
+  FaceBox.Get(fxmin, fymin, fzmin, fxmax, fymax, fzmax);
+  EdgeBox.Get(exmin, eymin, ezmin, exmax, eymax, ezmax);
+  //
+  Standard_Real TolU = Max(BS.UResolution(Tol), Precision::PConfusion());
+  Standard_Real TolV = Max(BS.VResolution(Tol), Precision::PConfusion());
+  BRepTopAdaptor_FClass2d FClass(BS.Face(), Max(TolU, TolV));
+  //
+  Standard_Boolean isModified = Standard_False;
+  if(exmin > fxmin)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DX()));
+    gp_Pnt aP(fxmin, fymax, fzmax);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fxmin = exmin;
+      isModified = Standard_True;
+    }
+  }
+  if(exmax < fxmax)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DX()));
+    gp_Pnt aP(fxmax, fymin, fzmin);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fxmax = exmax;
+      isModified = Standard_True;
+    }
+  }
+  //
+  if(eymin > fymin)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DY()));
+    gp_Pnt aP(fxmax, fymin, fzmax);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fymin = eymin;
+      isModified = Standard_True;
+    }
+  }
+  if(eymax < fymax)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DY()));
+    gp_Pnt aP(fxmin, fymax, fzmin);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fymax = eymax;
+      isModified = Standard_True;
+    }
+  }
+  //
+  if(ezmin > fzmin)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmin, fymin, fzmin), gp::DZ()));
+    gp_Pnt aP(fxmax, fymax, fzmin);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fzmin = ezmin;
+      isModified = Standard_True;
+    }
+  }
+  if(ezmax < fzmax)
+  {
+    //
+    gp_Pln pl(gp_Ax3(gp_Pnt(fxmax, fymax, fzmax), gp::DZ()));
+    gp_Pnt aP(fxmin, fymin, fzmax);
+    if(IsModifySize(BS, pl, aP,
+                    umin, umax, vmin, vmax, FClass, TolU, TolV))
+    {
+      fzmax = ezmax;
+      isModified = Standard_True;
+    }
+  }
+  //
+  if(isModified)
+  {
+    FaceBox.SetVoid();
+    FaceBox.Update(fxmin, fymin, fzmin, fxmax, fymax, fzmax);
+  }
+}
+