// File:	BRepOffset_Tool.cxx
// Created:	Mon Oct 23 14:25:07 1995
// Author:	Yves FRICAUD
//		<yfr@stylox>

#include <stdio.h>

#include <BRepOffset_Tool.ixx>

#include <BRepAlgo_Tool.hxx>

#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRepAdaptor_HSurface.hxx>

#include <BRepBndLib.hxx>

#include <Bnd_Box2d.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <BRep_Tool.hxx>
#include <BRepLib.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRepLib_MakePolygon.hxx>
#include <BRepLib_MakeFace.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRepTools.hxx>
#include <BRepTools_WireExplorer.hxx>

#include <BRepTools_Modifier.hxx>
#include <BRepTools_TrsfModification.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Curve2d.hxx>

#include <IntRes2d_IntersectionPoint.hxx>
#include <IntRes2d_IntersectionSegment.hxx>
#include <Extrema_ExtPC.hxx>

#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopAbs.hxx>
#include <Standard_ConstructionError.hxx>

#include <TopOpeBRepBuild_Builder.hxx>
#include <TopOpeBRepDS_HDataStructure.hxx>
#include <TopOpeBRepDS_CurveExplorer.hxx>
#include <TopOpeBRep_DSFiller.hxx>
#include <TopOpeBRepTool_GeomTool.hxx>
#include <TopOpeBRep_ShapeIntersector.hxx>
#include <TopOpeBRep_FacesFiller.hxx>
#include <TopOpeBRep_GeomTool.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>

#include <Geom_Surface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_OffsetSurface.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Conic.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GCPnts_QuasiUniformDeflection.hxx>

#include <GeomLib.hxx>
#include <GeomAPI.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2d_Ellipse.hxx>
#include <Geom2d_Parabola.hxx>
#include <Geom2d_Hyperbola.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>

#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dInt_GInter.hxx>

#include <GeomAdaptor_Surface.hxx>
#include <GeomProjLib.hxx>
#include <GeomInt_IntSS.hxx>
#include <ProjLib_ProjectedCurve.hxx>
#include <ProjLib_HProjectedCurve.hxx>

#include <ElSLib.hxx>
#include <ElCLib.hxx>

#include <gp.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>


#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>

#include <BRep_TEdge.hxx>
#include <Extrema_ExtPC2d.hxx>

#include <Geom_SurfaceOfLinearExtrusion.hxx>
#include <Geom_SurfaceOfRevolution.hxx>
#include <GCPnts_AbscissaPoint.hxx>

//tma: for new boolean operation
#include <TopTools_SequenceOfShape.hxx>
#include <BOPTools_DSFiller.hxx>
#include <Geom_BSplineCurve.hxx>
#include <GeomConvert_CompCurveToBSplineCurve.hxx>
#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
#include <GeomConvert_ApproxCurve.hxx>
#include <Geom2dConvert_ApproxCurve.hxx>
//#include <BRepAlgoAPI_Section.hxx>
#include <BooleanOperations_ShapesDataStructure.hxx>
#include <BOPTools_InterferencePool.hxx>
#include <BOPTools_SSInterference.hxx>
#include <BOPTools_SequenceOfCurves.hxx>
#include <BOPTools_Curve.hxx>
#include <BOPTools_ListOfPaveBlock.hxx>
#include <BOPTools_ListIteratorOfListOfPaveBlock.hxx>
#include <BOPTools_PaveBlock.hxx>
#include <BRepAlgoAPI_Section.hxx>
#include <BOPTools_SSIntersectionAttribute.hxx>
#include <BOPTools_PaveFiller.hxx>
#include <BOPTools_Tools2D.hxx>
#include <BOPTools_ListIteratorOfListOfPave.hxx>
#include <TopoDS_Compound.hxx>
#include <GCPnts_UniformAbscissa.hxx>
#include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
#include <BRep_CurveRepresentation.hxx>

#include <BRepOffset_ListOfInterval.hxx>
#include <BRepOffset_Interval.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <ShapeCustom_Curve2d.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
  

#ifdef DRAW
#include <DBRep.hxx>
#endif

#ifdef DEB       
Standard_Boolean AffichInter  = Standard_False;
static Standard_Boolean AffichExtent = Standard_False;
static Standard_Integer NbNewEdges  = 1;
static Standard_Integer NbFaces     = 1;
static Standard_Integer NbFOB       = 1;
static Standard_Integer NbFTE       = 1;
static Standard_Integer NbExtE      = 1;
//POP pour NT
//char* name = new char[100];
#endif


//=======================================================================
//function : EdgeVertices
//purpose  : 
//=======================================================================

void BRepOffset_Tool::EdgeVertices (const TopoDS_Edge&   E,
				    TopoDS_Vertex& V1, 
				    TopoDS_Vertex& V2)
{
  if (E.Orientation() == TopAbs_REVERSED) {
    TopExp::Vertices(E,V2,V1);
  }
  else {
    TopExp::Vertices(E,V1,V2);
  }
}

//=======================================================================
//function : OriEdgeInFace
//purpose  : 
//=======================================================================

TopAbs_Orientation BRepOffset_Tool::OriEdgeInFace (const TopoDS_Edge& E,
						   const TopoDS_Face& F )

{
#ifdef DEB
  TopAbs_Orientation O = 
#endif
    F.Orientation();
  TopExp_Explorer Exp;
  Exp.Init(F.Oriented(TopAbs_FORWARD),TopAbs_EDGE);

  for (; Exp.More() ;Exp.Next()) {
    if (Exp.Current().IsSame(E)) {
      return Exp.Current().Orientation();
    }
  }
  Standard_ConstructionError::Raise("BRepOffset_Tool::OriEdgeInFace");
  return E.Orientation();
}


//=======================================================================
//function : FindPeriod
//purpose  : 
//=======================================================================

static void FindPeriod (const TopoDS_Face& F,
			Standard_Real&     umin,
			Standard_Real&     umax,
			Standard_Real&     vmin,
			Standard_Real&     vmax)
{

  Bnd_Box2d B;
  TopExp_Explorer exp;
  for (exp.Init(F,TopAbs_EDGE); exp.More(); exp.Next()) {
    const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
    
    Standard_Real pf,pl;
    const Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(E,F,pf,pl);
    if (C.IsNull()) return;
    Geom2dAdaptor_Curve PC(C,pf,pl);
    Standard_Real i, nbp = 20;
    if (PC.GetType() == GeomAbs_Line) nbp = 2;
    Standard_Real step = (pl - pf) / nbp;
    gp_Pnt2d P;
    PC.D0(pf,P);
    B.Add(P);
    for (i = 2; i < nbp; i++) {
      pf += step;
      PC.D0(pf,P);
      B.Add(P);
    }
    PC.D0(pl,P);
    B.Add(P);
    B.Get(umin,vmin,umax,vmax);
  }
}

//=======================================================================
//function : PutInBounds
//purpose  : Recadre la courbe 2d dans les bounds de la face
//=======================================================================

static void PutInBounds (const TopoDS_Face&          F,
			 const TopoDS_Edge&          E,
			 Handle(Geom2d_Curve)&       C2d)
{
  Standard_Real   umin,umax,vmin,vmax;
  Standard_Real   f,l;
  BRep_Tool::Range(E,f,l);  

  TopLoc_Location L; // Recup S avec la location pour eviter la copie.
  Handle (Geom_Surface) S   = BRep_Tool::Surface(F,L);

  if (S->IsInstance(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
    S = (*(Handle_Geom_RectangularTrimmedSurface*)&S)->BasisSurface();
  }
  //---------------
  // Recadre en U.
  //---------------
  if (!S->IsUPeriodic() && !S->IsVPeriodic()) return;

  FindPeriod (F,umin,umax,vmin,vmax);

  if (S->IsUPeriodic()) {
    Standard_Real period  = S->UPeriod();
    Standard_Real eps     = period*1.e-6;
    gp_Pnt2d      Pf      = C2d->Value(f);
    gp_Pnt2d      Pl      = C2d->Value(l);
    gp_Pnt2d      Pm      = C2d->Value(0.34*f + 0.66*l);
    Standard_Real minC    = Min(Pf.X(),Pl.X()); minC = Min(minC,Pm.X());
    Standard_Real maxC    = Max(Pf.X(),Pl.X()); maxC = Max(maxC,Pm.X());
    Standard_Real du = 0.;
    if (minC< umin - eps) {
      du = (int((umin - minC)/period) + 1)*period;
    }
    if (minC > umax + eps) {
      du = -(int((minC - umax)/period) + 1)*period;
    }
    if (du != 0) {
      gp_Vec2d T1(du,0.);
      C2d->Translate(T1);
      minC += du; maxC += du;
    }
    // Ajuste au mieux la courbe dans le domaine.
    if (maxC > umax +100*eps) {
      Standard_Real d1 = maxC - umax;
      Standard_Real d2 = umin - minC + period;
      if (d2 < d1) du =-period;
      if ( du != 0.) {
	gp_Vec2d T2(du,0.);
	C2d->Translate(T2);
      }
    }
  }
  //------------------
  // Recadre en V.
  //------------------
  if (S->IsVPeriodic()) {
    Standard_Real period  = S->VPeriod();
    Standard_Real eps     = period*1.e-6;
    gp_Pnt2d      Pf      = C2d->Value(f);
    gp_Pnt2d      Pl      = C2d->Value(l);
    gp_Pnt2d      Pm      = C2d->Value(0.34*f + 0.66*l);
    Standard_Real minC    = Min(Pf.Y(),Pl.Y()); minC = Min(minC,Pm.Y());
    Standard_Real maxC    = Max(Pf.Y(),Pl.Y()); maxC = Max(maxC,Pm.Y());
    Standard_Real dv = 0.;
    if (minC< vmin - eps) {
      dv = (int((vmin - minC)/period) + 1)*period;
    }
    if (minC > vmax + eps) {
      dv = -(int((minC - vmax)/period) + 1)*period;
    }
    if (dv != 0) {
      gp_Vec2d T1(0.,dv);
      C2d->Translate(T1);
      minC += dv; maxC += dv;
    }
    // Ajuste au mieux la courbe dans le domaine.
    if (maxC > vmax +100*eps) {
      Standard_Real d1 = maxC - vmax;
      Standard_Real d2 = vmin - minC + period;
      if (d2 < d1) dv =-period;
      if ( dv != 0.) {
	gp_Vec2d T2(0.,dv);
	C2d->Translate(T2);
      }
    }
  }
}

//=======================================================================
//function : Gabarit
//purpose  : 
//=======================================================================

Standard_Real BRepOffset_Tool::Gabarit(const Handle(Geom_Curve)& aCurve)
{
  GeomAdaptor_Curve GC( aCurve );
  Bnd_Box aBox;
  BndLib_Add3dCurve::Add( GC, Precision::Confusion(), aBox );
  Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, dist;
  aBox.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax );
  dist = Max( (aXmax-aXmin), (aYmax-aYmin) );
  dist = Max( dist, (aZmax-aZmin) );
  return dist;
}

//=======================================================================
//function : BuildPCurves
//purpose  : 
//=======================================================================

static void BuildPCurves (const TopoDS_Edge&  E,
			  const TopoDS_Face&  F)
{ 
  Standard_Real   ff,ll;
  Handle (Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface (E,F,ff,ll);
  if (!C2d.IsNull()) return;

  //Standard_Real Tolerance = Max(Precision::Confusion(),BRep_Tool::Tolerance(E));
  Standard_Real Tolerance = Precision::Confusion();

  BRepAdaptor_Surface AS(F,0);
  BRepAdaptor_Curve   AC(E);

  //Try to find pcurve on a bound of BSpline or Bezier surface
  Handle( Geom_Surface ) theSurf = BRep_Tool::Surface( F );
  Handle( Standard_Type ) typS = theSurf->DynamicType();
  if (typS == STANDARD_TYPE(Geom_OffsetSurface))
    typS = (*((Handle(Geom_OffsetSurface)*)&theSurf))->BasisSurface()->DynamicType();
  if (typS == STANDARD_TYPE(Geom_BezierSurface) || typS == STANDARD_TYPE(Geom_BSplineSurface))
    {
      gp_Pnt fpoint = AC.Value( AC.FirstParameter() );
      gp_Pnt lpoint = AC.Value( AC.LastParameter() );
      TopoDS_Face theFace = BRepLib_MakeFace( theSurf );
      Standard_Real U1 = 0., U2 = 0., TolProj = 1.e-4; //1.e-5;
      TopoDS_Edge theEdge;
      TopExp_Explorer Explo;
      Explo.Init( theFace, TopAbs_EDGE );
      for (; Explo.More(); Explo.Next())
	{
	  TopoDS_Edge anEdge = TopoDS::Edge( Explo.Current() );
	  BRepAdaptor_Curve aCurve( anEdge );
	  Extrema_ExtPC fextr( fpoint, aCurve );
	  if (!fextr.IsDone() || fextr.NbExt() < 1)
	    continue;
	  Standard_Real dist, distmin = RealLast();
          Standard_Integer i;
	  for (i = 1; i <= fextr.NbExt(); i++)
	    {
	      dist = fextr.Value(i);
	      if (dist < distmin)
		{
		  distmin = dist;
		  U1 = fextr.Point(i).Parameter();
		}
	    }
	  if (distmin > TolProj)
	    continue;
	  Extrema_ExtPC lextr( lpoint, aCurve );
	  if (!lextr.IsDone() || lextr.NbExt() <1)
	    continue;
	  distmin = RealLast();
	  for (i = 1; i <= lextr.NbExt(); i++)
	    {
	      dist = lextr.Value(i);
	      if (dist < distmin)
		{
		  distmin = dist;
		  U2 = lextr.Point(i).Parameter();
		}
	    }
	  if (distmin <= TolProj)
	    {
	      theEdge = anEdge;
	      break;
	    }
	} // for (; Explo.More(); Explo.Current())
      
      if (! theEdge.IsNull())
	{
	  //Construction of pcurve
	  if (U2 < U1)
	    {
	      Standard_Real temp = U1;
	      U1 = U2;
	      U2 = temp;
	    }
	  Standard_Real f, l;
	  C2d = BRep_Tool::CurveOnSurface( theEdge, theFace, f, l );
	  C2d = new Geom2d_TrimmedCurve( C2d, U1, U2 );

	  if (theSurf->IsUPeriodic() || theSurf->IsVPeriodic())
	    PutInBounds( F, E, C2d );

	  BRep_Builder B;
	  B.UpdateEdge( E, C2d, F, BRep_Tool::Tolerance(E) );
	  BRepLib::SameRange( E );

	  return;
	}
    } // if (typS == ...

  Handle(BRepAdaptor_HSurface) HS = new BRepAdaptor_HSurface(AS);
  Handle(BRepAdaptor_HCurve)   HC = new BRepAdaptor_HCurve(AC);

  ProjLib_ProjectedCurve Proj(HS,HC,Tolerance);
  
  switch ( Proj.GetType()) {

  case GeomAbs_Line:
    C2d = new Geom2d_Line(Proj.Line());
    break;

  case GeomAbs_Circle:
    C2d = new Geom2d_Circle(Proj.Circle());
    break;

  case GeomAbs_Ellipse:
    C2d = new Geom2d_Ellipse(Proj.Ellipse());
    break;

  case GeomAbs_Parabola:
    C2d = new Geom2d_Parabola(Proj.Parabola());
    break;

  case GeomAbs_Hyperbola:
    C2d = new Geom2d_Hyperbola(Proj.Hyperbola());
    break;

  case GeomAbs_BezierCurve:
    C2d = Proj.Bezier();
    break;

  case GeomAbs_BSplineCurve:
    C2d = Proj.BSpline();
    break;
#ifndef DEB
  default:
    break;
#endif
  }

  if (AS.IsUPeriodic() || AS.IsVPeriodic()) {
    PutInBounds(F,E,C2d);
  }
  if (!C2d.IsNull()) {
    BRep_Builder    B;
    B.UpdateEdge (E,C2d,F,BRep_Tool::Tolerance(E));
  }
  else {
    Standard_ConstructionError::Raise("BRepOffset_Tool::BuildPCurves");
    cout <<"Echec ProjLib"<<endl;
  }
}

//=======================================================================
//function : OriSect
//purpose  : 
//=======================================================================

void BRepOffset_Tool::OrientSection (const TopoDS_Edge&  E,
				     const TopoDS_Face&  F1,
				     const TopoDS_Face&  F2,
				     TopAbs_Orientation& O1,
				     TopAbs_Orientation& O2) 
{
  TopLoc_Location L;
  Standard_Real   f,l;
  
  Handle (Geom_Surface) S1 = BRep_Tool::Surface(F1);
  Handle (Geom_Surface) S2 = BRep_Tool::Surface(F2);    
  Handle (Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E,F1,f,l);
  Handle (Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(E,F2,f,l); 
  Handle (Geom_Curve)   C  = BRep_Tool::Curve(E,L,f,l);

  BRepAdaptor_Curve BAcurve( E );
  GCPnts_UniformAbscissa Distribution( BAcurve, 3 );
  Standard_Real ParOnC = Distribution.Parameter(2); //0.5*(f+l);

  gp_Vec T1 = C->DN(ParOnC,1).Transformed(L.Transformation());
  if (T1.SquareMagnitude() > gp::Resolution()) {
    T1.Normalize();
  }

  gp_Pnt2d P  = C1->Value(ParOnC);
  gp_Pnt   P3;
  gp_Vec   D1U,D1V;
  
  S1->D1(P.X(),P.Y(),P3,D1U,D1V);
  gp_Vec DN1(D1U^D1V);
  if (F1.Orientation() == TopAbs_REVERSED) DN1.Reverse();
  
  P = C2->Value(ParOnC);
  S2->D1(P.X(),P.Y(),P3,D1U,D1V);
  gp_Vec DN2(D1U^D1V);
  if (F2.Orientation() == TopAbs_REVERSED) DN2.Reverse();
  
  gp_Vec        ProVec = DN2^T1;
  Standard_Real Prod  =  DN1.Dot(ProVec);
  if (Prod < 0.0) {
    O1 = TopAbs_FORWARD;
  }
  else {
    O1 = TopAbs_REVERSED;
  }
  ProVec = DN1^T1;
  Prod  =  DN2.Dot(ProVec);
  if (Prod < 0.0) {
    O2 = TopAbs_FORWARD;
  }
  else {
    O2 = TopAbs_REVERSED;
  }
  if (F1.Orientation() == TopAbs_REVERSED) O1 = TopAbs::Reverse(O1);
  if (F2.Orientation() == TopAbs_REVERSED) O2 = TopAbs::Reverse(O2);
}

//=======================================================================
//function : HasCommonShape
//purpose  : 
//=======================================================================

Standard_Boolean BRepOffset_Tool::HasCommonShapes (const TopoDS_Face& F1,
						   const TopoDS_Face& F2,
						   TopTools_ListOfShape& LE,
						   TopTools_ListOfShape& LV)
{
  Standard_Boolean Common = Standard_False;
  LE.Clear(); LV.Clear();

  TopExp_Explorer exp1;
  exp1.Init(F1,TopAbs_EDGE);

  for (; exp1.More(); exp1.Next()) {
    TopExp_Explorer exp2;
    exp2.Init(F2,TopAbs_EDGE);
    for (; exp2.More(); exp2.Next()) {
      if (exp1.Current().IsSame(exp2.Current())) {
	Common = Standard_True;
	LE.Append(exp1.Current());
      }
    }
  }
  for (exp1.Init(F1,TopAbs_VERTEX); exp1.More(); exp1.Next()) {
    TopExp_Explorer exp2;
    exp2.Init(F2,TopAbs_EDGE);
    for (exp2.Init(F2,TopAbs_VERTEX); exp2.More(); exp2.Next()) {
      if (exp1.Current().IsSame(exp2.Current())) {
	Common = Standard_True;
	LV.Append(exp1.Current());
      }
    }
  }
  return Common;
}

//=======================================================================
//function : ToSmall
//purpose  : 
//=======================================================================

static Standard_Boolean ToSmall (const Handle(Geom_Curve)& C)
{
  Standard_Real Tol = 10*Precision::Confusion();
  Standard_Real m   = (C->FirstParameter()*0.668 + C->LastParameter()*0.332); 
  gp_Pnt P1 = C->Value(C->FirstParameter());
  gp_Pnt P2 = C->Value(C->LastParameter());
  gp_Pnt P3 = C->Value(m);
  if (P1.Distance(P2) > Tol) return Standard_False;
  if (P2.Distance(P3) > Tol) return Standard_False;
  return Standard_True;
}


//=======================================================================
//function : IsOnSurface
//purpose  : 
//=======================================================================

static Standard_Boolean IsOnSurface(const Handle(Geom_Curve)&   C,
				    const Handle(Geom_Surface)& S,
				    Standard_Real               TolConf,
				    Standard_Real&              TolReached) 
{
  Standard_Real    f = C->FirstParameter();
  Standard_Real    l = C->LastParameter();
  Standard_Integer n = 5;
  Standard_Real du = (f-l)/(n-1);
  TolReached = 0.;

  gp_Pnt P;
  Standard_Real U,V;

  GeomAdaptor_Surface AS(S);

  switch ( AS.GetType()) {
  case GeomAbs_Plane:
    {
      gp_Ax3 Ax = AS.Plane().Position();
      for ( Standard_Integer i = 0; i < n; i++) {
	P = C->Value(f+i*du);
	ElSLib::PlaneParameters(Ax,P,U,V); 
	TolReached = P.Distance(ElSLib::PlaneValue(U,V,Ax));
	if ( TolReached  > TolConf)
	  return Standard_False;
      }
      break;
    }
  case GeomAbs_Cylinder:
    {
      gp_Ax3        Ax  = AS.Cylinder().Position();
      Standard_Real Rad = AS.Cylinder().Radius();
      for ( Standard_Integer i = 0; i < n; i++) {
	P = C->Value(f+i*du);
	ElSLib::CylinderParameters(Ax,Rad,P,U,V); 
	TolReached = P.Distance(ElSLib::CylinderValue(U,V,Ax,Rad));
	if ( TolReached > TolConf)
	  return Standard_False;
      }
      break;
    }
  case GeomAbs_Cone:
    {
      gp_Ax3        Ax  = AS.Cone().Position();
      Standard_Real Rad = AS.Cone().RefRadius();
      Standard_Real Alp = AS.Cone().SemiAngle();
      for ( Standard_Integer i = 0; i < n; i++) {
	P = C->Value(f+i*du);
	ElSLib::ConeParameters(Ax,Rad,Alp,P,U,V); 
	TolReached = P.Distance(ElSLib::ConeValue(U,V,Ax,Rad,Alp));
	if ( TolReached > TolConf)
	  return Standard_False;
      }
      break;
    }
  case GeomAbs_Sphere:
    {
      gp_Ax3        Ax  = AS.Sphere().Position();
      Standard_Real Rad = AS.Sphere().Radius();
      for ( Standard_Integer i = 0; i < n; i++) {
	P = C->Value(f+i*du);
	ElSLib::SphereParameters(Ax,Rad,P,U,V); 
	TolReached = P.Distance(ElSLib::SphereValue(U,V,Ax,Rad));
	if ( TolReached > TolConf)
	  return Standard_False;
      }
      break;
    }
  case GeomAbs_Torus:
    {
      gp_Ax3        Ax  = AS.Torus().Position();
      Standard_Real R1  = AS.Torus().MajorRadius();
      Standard_Real R2  = AS.Torus().MinorRadius();
      for ( Standard_Integer i = 0; i < n; i++) {
	P = C->Value(f+i*du);
	ElSLib::TorusParameters(Ax,R1,R2,P,U,V); 
	TolReached =  P.Distance(ElSLib::TorusValue(U,V,Ax,R1,R2));
	if ( TolReached > TolConf)
	  return Standard_False;
      }
      break;
    }
    
  default:
    {
      return Standard_False;
    }
  }
  
  return Standard_True;
} 


//=======================================================================
//function : PipeInter
//purpose  : 
//=======================================================================

void BRepOffset_Tool::PipeInter(const TopoDS_Face& F1,
				const TopoDS_Face& F2,
				TopTools_ListOfShape& L1,
				TopTools_ListOfShape& L2,
				const TopAbs_State    Side)
{ 
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F1);
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F2);
  }
#endif

  Handle (Geom_Curve) CI;
  TopoDS_Edge E;
  TopAbs_Orientation O1,O2;
  L1.Clear(); L2.Clear();
  BRep_Builder B;
  Handle (Geom_Surface) S1 = BRep_Tool::Surface(F1);
  Handle (Geom_Surface) S2 = BRep_Tool::Surface(F2);  

  GeomInt_IntSS Inter (S1,S2, Precision::Confusion(),1,1,1);
  
  if (Inter.IsDone()) {
    for (Standard_Integer i = 1; i <= Inter.NbLines(); i++) {
      CI = Inter.Line(i);
      if (ToSmall(CI)) continue;
      TopoDS_Edge E = BRepLib_MakeEdge(CI);
      if (Inter.HasLineOnS1(i)) {
	Handle(Geom2d_Curve) C2 = Inter.LineOnS1(i);
	PutInBounds  (F1,E,C2);
	B.UpdateEdge (E,C2,F1,BRep_Tool::Tolerance(E));
      }
      else {
	BuildPCurves (E,F1);
      }
      if (Inter.HasLineOnS2(i)) {
	Handle(Geom2d_Curve) C2 = Inter.LineOnS2(i);
	PutInBounds  (F2,E,C2);
	B.UpdateEdge (E,C2,F2,BRep_Tool::Tolerance(E));
      }
      else {
	BuildPCurves (E,F2);
      }
      OrientSection (E,F1,F2,O1,O2);
      if (Side == TopAbs_OUT) {
	O1 = TopAbs::Reverse(O1);
	O2 = TopAbs::Reverse(O2);
      }
      L1.Append (E.Oriented(O1));
      L2.Append (E.Oriented(O2));
#ifdef DRAW
      if (AffichInter) {
    // POP pour NT
	char* name = new char[100];
	sprintf(name,"EI_%d",NbNewEdges++);	
	DBRep::Set(name,E.Oriented(O1));
      }
#endif      
    }
  }
}


//=======================================================================
//function : IsAutonomVertex
//purpose  : Checks wether a vertex is "autonom" or not
//=======================================================================

static Standard_Boolean IsAutonomVertex(const TopoDS_Shape& aVertex,
					const TopoDS_Shape& F1,
					const TopoDS_Shape& F2,
					const BooleanOperations_ShapesDataStructure& theDS,
					const BOPTools_PaveFiller& thePaveFiller)
{
  Standard_Integer i, index = theDS.ShapeIndex( aVertex, 1 );
  if (index == 0)
    {
      index = theDS.ShapeIndex( aVertex, 2 );
      if (index == 0)
	{
	  for (i = theDS.NumberOfSourceShapes()+1; i <= theDS.NumberOfInsertedShapes(); i++)
	    {
	      const TopoDS_Shape& aShape = theDS.GetShape(i);
	      if (aVertex.IsSame(aShape))
		{
		  index = i;
		  break;
		}
	    }
	}
    }
  
  Standard_Integer indF1 = theDS.ShapeIndex( F1, 1 );
  Standard_Integer indF2 = theDS.ShapeIndex( F2, 2 );

  BooleanOperations_KindOfInterference theTypeInterf;
  const BOPTools_PavePool& thePavePool = thePaveFiller.PavePool();
  BOPTools_ListIteratorOfListOfPave itpave;
  for (i = 1; i <= thePavePool.Length(); i++)
    {
      const BOPTools_ListOfPave& aPaveList = thePavePool(i).Set();
      for (itpave.Initialize( aPaveList ); itpave.More(); itpave.Next())
	{
	  BOPTools_Pave aPave = itpave.Value();
	  if (aPave.Index() == index)
	    {
	      theTypeInterf = aPave.Type();
	      if (theTypeInterf != BooleanOperations_SurfaceSurface &&
		  theTypeInterf != BooleanOperations_UnknownInterference)
		return Standard_False;
	    }
	}
    }

  BOPTools_PaveFiller * pPF = (BOPTools_PaveFiller*) &thePaveFiller;
  BOPTools_PaveFiller& thePF = *pPF;
  BOPTools_CArray1OfSSInterference& aFFs = thePF.InterfPool()->SSInterferences();
  Standard_Integer aNbFFs=aFFs.Extent();
  for (i = 1; i <= aNbFFs; i++)
    {
      BOPTools_SSInterference& aFFi = aFFs(i);

      if (aFFi.Index1() == indF1 && aFFi.Index2() == indF2)
	{
	  const BOPTools_ListOfPave& aPaveList = aFFi.NewPaveSet().Set();
	  for (itpave.Initialize( aPaveList ); itpave.More(); itpave.Next())
	    {
	      BOPTools_Pave aPave = itpave.Value();
	      if (aPave.Index() == index)
		{
		  theTypeInterf = aPave.Type();
		  if (theTypeInterf != BooleanOperations_SurfaceSurface &&
		      theTypeInterf != BooleanOperations_UnknownInterference)
		    return Standard_False;
		}
	    }
	}
    }

  return Standard_True;
}


//=======================================================================
//function : AreConnex
//purpose  : define if two shapes are connex by a vertex (vertices)
//=======================================================================

static Standard_Boolean AreConnex(const TopoDS_Wire& W1,
				  const TopoDS_Wire& W2,
				  const TopoDS_Shape& F1,
				  const TopoDS_Shape& F2,
				  const BOPTools_DSFiller* pDF)
{
  TopoDS_Vertex V11, V12, V21, V22;
  TopExp::Vertices( W1, V11, V12 );
  TopExp::Vertices( W2, V21, V22 );

  if (V11.IsSame(V21) || V11.IsSame(V22) ||
      V12.IsSame(V21) || V12.IsSame(V22))
    {
      Standard_Boolean isCV1 = V11.IsSame(V21) || V11.IsSame(V22);
      Standard_Boolean isCV2 = V12.IsSame(V21) || V12.IsSame(V22);
      if (isCV1 && !IsAutonomVertex(V11, F1, F2, pDF->DS(), pDF->PaveFiller()))
	{
	  if (!isCV2)
	    return Standard_False;
	  if (!IsAutonomVertex(V12, F1, F2, pDF->DS(), pDF->PaveFiller()))
	    return Standard_False;
	}
      if (!isCV1 && !IsAutonomVertex(V12, F1, F2, pDF->DS(), pDF->PaveFiller()))
	return Standard_False;

      TopoDS_Vertex CV = (V11.IsSame(V21) || V11.IsSame(V22))? V11 : V12;
      TopoDS_Edge E1, E2;
      TopoDS_Iterator itw( W1 );
      for (; itw.More(); itw.Next())
	{
	  E1 = TopoDS::Edge(itw.Value());
	  TopoDS_Vertex V1, V2;
	  TopExp::Vertices( E1, V1, V2 );
	  if (V1.IsSame(CV) || V2.IsSame(CV))
	    break;
	}
      itw.Initialize( W2 );
      E2 = TopoDS::Edge(itw.Value());

      Standard_Real f, l;
      Handle(Geom_Curve) C1 = BRep_Tool::Curve( E1, f, l ); 
      if (C1->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
	C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();
      
      Handle(Geom_Curve) C2 = BRep_Tool::Curve( E2, f, l );
      if (C2->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
	C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();

      if (C1->IsInstance(STANDARD_TYPE(Geom_Line)) &&
	  C2->IsInstance(STANDARD_TYPE(Geom_Line)))
	{
	  Handle(Geom_Line) L1 = *((Handle(Geom_Line)*) &C1);
	  gp_Ax1 Axis1 = L1->Position();
	  Handle(Geom_Line) L2 = *((Handle(Geom_Line)*) &C2);
	  gp_Ax1 Axis2 = L2->Position();
	  if (! Axis1.IsParallel( Axis2, Precision::Angular() ))
	    return Standard_False;
	}

      return Standard_True;
    }

  return Standard_False;
}

//=======================================================================
//function : AreClosed
//purpose  : define if two edges are connex by two vertices
//=======================================================================

static Standard_Boolean AreClosed(const TopoDS_Edge& E1,
				  const TopoDS_Edge& E2)
{
  TopoDS_Vertex V11, V12, V21, V22;
  TopExp::Vertices( E1, V11, V12 );
  TopExp::Vertices( E2, V21, V22 );

  if (V11.IsSame(V21) && V12.IsSame(V22) ||
      V11.IsSame(V22) && V12.IsSame(V21))
    return Standard_True;

  return Standard_False;
}

//=======================================================================
//function : BSplineEdges
//purpose  : 
//=======================================================================

static Standard_Boolean BSplineEdges(const TopoDS_Edge& E1,
				     const TopoDS_Edge& E2,
				     const Standard_Integer par1,
				     const Standard_Integer par2,
				     Standard_Real& angle)
{
  Standard_Real first1, last1, first2, last2, Param1, Param2;

  Handle(Geom_Curve) C1 = BRep_Tool::Curve( E1, first1, last1 ); 
  if (C1->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
    C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();

  Handle(Geom_Curve) C2 = BRep_Tool::Curve( E2, first2, last2 );
  if (C2->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
    C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();

  if (!C1->IsInstance(STANDARD_TYPE(Geom_BSplineCurve)) ||
      !C2->IsInstance(STANDARD_TYPE(Geom_BSplineCurve)))
    return Standard_False;

  Param1 = (par1 == 0)? first1 : last1;
  Param2 = (par2 == 0)? first2 : last2;

  gp_Pnt Pnt1, Pnt2;
  gp_Vec Der1, Der2;
  C1->D1( Param1, Pnt1, Der1 );
  C2->D1( Param2, Pnt2, Der2 );

  if (Der1.Magnitude() <= gp::Resolution() ||
      Der2.Magnitude() <= gp::Resolution())
    angle = PI/2.;
  else
    angle = Der1.Angle(Der2);

  return Standard_True;
}

//=======================================================================
//function : AngleWireEdge
//purpose  : 
//=======================================================================

static Standard_Real AngleWireEdge(const TopoDS_Wire& aWire,
				   const TopoDS_Edge& anEdge)
{
  TopoDS_Vertex V11, V12, V21, V22, CV;
  TopExp::Vertices( aWire,  V11, V12 );
  TopExp::Vertices( anEdge, V21, V22 );
  CV = (V11.IsSame(V21) || V11.IsSame(V22))? V11 : V12;
  TopoDS_Edge FirstEdge;
  TopoDS_Iterator itw(aWire);
  for (; itw.More(); itw.Next())
    {
      FirstEdge = TopoDS::Edge(itw.Value());
      TopoDS_Vertex v1, v2;
      TopExp::Vertices( FirstEdge, v1, v2 );
      if (v1.IsSame(CV) || v2.IsSame(CV))
	{
	  V11 = v1;
	  V12 = v2;
	  break;
	}
    }
  Standard_Real Angle;
  if (V11.IsSame(CV) && V21.IsSame(CV))
    {
      BSplineEdges( FirstEdge, anEdge, 0, 0, Angle );
      Angle = PI - Angle;
    }
  else if (V11.IsSame(CV) && V22.IsSame(CV))
    BSplineEdges( FirstEdge, anEdge, 0, 1, Angle );
  else if (V12.IsSame(CV) && V21.IsSame(CV))
    BSplineEdges( FirstEdge, anEdge, 1, 0, Angle );
  else
    {
      BSplineEdges( FirstEdge, anEdge, 1, 1, Angle );
      Angle = PI - Angle;
    }
  return Angle;
}


//=======================================================================
//function : ReconstructPCurves
//purpose  : 
//=======================================================================

static void ReconstructPCurves(const TopoDS_Edge& anEdge)
{
  Standard_Real f, l;
  Handle(Geom_Curve) C3d = BRep_Tool::Curve(anEdge, f, l);

  BRep_ListIteratorOfListOfCurveRepresentation
    itcr( (Handle(BRep_TEdge)::DownCast(anEdge.TShape()))->ChangeCurves() );
  for (; itcr.More(); itcr.Next())
    {
      Handle( BRep_CurveRepresentation ) CurveRep = itcr.Value();
      if (CurveRep->IsCurveOnSurface())
	{
	  Handle(Geom_Surface) theSurf  = CurveRep->Surface();
	  TopLoc_Location      theLoc   = CurveRep->Location();
	  theLoc = anEdge.Location() * theLoc;
	  theSurf = Handle(Geom_Surface)::DownCast
	    (theSurf->Transformed(theLoc.Transformation()));
	  Handle(Geom2d_Curve) ProjPCurve =
	    GeomProjLib::Curve2d( C3d, f, l, theSurf );
	  CurveRep->PCurve( ProjPCurve );
	}
    }
}

//=======================================================================
//function : ConcatPCurves
//purpose  : 
//=======================================================================

static Handle(Geom2d_Curve) ConcatPCurves(const TopoDS_Edge& E1,
					  const TopoDS_Edge& E2,
					  const TopoDS_Face& F,
					  const Standard_Boolean After,
					  Standard_Real& newFirst,
					  Standard_Real& newLast)
{
  Standard_Real Tol = 1.e-7;
  GeomAbs_Shape Continuity = GeomAbs_C1;
  Standard_Integer MaxDeg = 14;
  Standard_Integer MaxSeg = 16;

  Standard_Real first1, last1, first2, last2;
  Handle(Geom2d_Curve) PCurve1, PCurve2, newPCurve;

  PCurve1 = BRep_Tool::CurveOnSurface( E1, F, first1, last1 );
  if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_TrimmedCurve)))
    PCurve1 = (*((Handle(Geom2d_TrimmedCurve)*)&PCurve1))->BasisCurve();

  PCurve2 = BRep_Tool::CurveOnSurface( E2, F, first2, last2 );
  if (PCurve2->IsInstance(STANDARD_TYPE(Geom2d_TrimmedCurve)))
    PCurve2 = (*((Handle(Geom2d_TrimmedCurve)*)&PCurve2))->BasisCurve();
      
  if (PCurve1 == PCurve2)
    {
      newPCurve = PCurve1;
      newFirst  = Min( first1, first2 );
      newLast   = Max( last1, last2 );
    }
  else if (PCurve1->DynamicType() == PCurve2->DynamicType() &&
	   (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Line)) ||
	    PCurve1->IsKind(STANDARD_TYPE(Geom2d_Conic))))
    {
      newPCurve = PCurve1;
      gp_Pnt2d P1, P2;
      P1 = PCurve2->Value( first2 );
      P2 = PCurve2->Value( last2 );
      if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Line)))
	{
	  Handle(Geom2d_Line) Lin1 = *((Handle(Geom2d_Line)*) &PCurve1);
	  gp_Lin2d theLin = Lin1->Lin2d();
	  first2 = ElCLib::Parameter( theLin, P1 );
	  last2  = ElCLib::Parameter( theLin, P2 );
	}
      else if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Circle)))
	{
	  Handle(Geom2d_Circle) Circ1 = *((Handle(Geom2d_Circle)*) &PCurve1);
	  gp_Circ2d theCirc = Circ1->Circ2d();
	  first2 = ElCLib::Parameter( theCirc, P1 );
	  last2  = ElCLib::Parameter( theCirc, P2 );
	}
      else if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Ellipse)))
	{
	  Handle(Geom2d_Ellipse) Ell1 = *((Handle(Geom2d_Ellipse)*) &PCurve1);
	  gp_Elips2d theElips = Ell1->Elips2d();
	  first2 = ElCLib::Parameter( theElips, P1 );
	  last2  = ElCLib::Parameter( theElips, P2 );
	}
      else if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Parabola)))
	{
	  Handle(Geom2d_Parabola) Parab1 = *((Handle(Geom2d_Parabola)*) &PCurve1);
	  gp_Parab2d theParab = Parab1->Parab2d();
	  first2 = ElCLib::Parameter( theParab, P1 );
	  last2  = ElCLib::Parameter( theParab, P2 );
	}
      else if (PCurve1->IsInstance(STANDARD_TYPE(Geom2d_Hyperbola)))
	{
	  Handle(Geom2d_Hyperbola) Hypr1 = *((Handle(Geom2d_Hyperbola)*) &PCurve1);
	  gp_Hypr2d theHypr = Hypr1->Hypr2d();
	  first2 = ElCLib::Parameter( theHypr, P1 );
	  last2  = ElCLib::Parameter( theHypr, P2 );
	}
      newFirst  = Min( first1, first2 );
      newLast   = Max( last1, last2 );
    }
  else
    {
      Handle(Geom2d_TrimmedCurve) TC1 = new Geom2d_TrimmedCurve( PCurve1, first1, last1 );
      Handle(Geom2d_TrimmedCurve) TC2 = new Geom2d_TrimmedCurve( PCurve2, first2, last2 );
      Geom2dConvert_CompCurveToBSplineCurve Concat2d( TC1 );
      Concat2d.Add( TC2, Precision::Confusion(), After );
      newPCurve = Concat2d.BSplineCurve();
      if (newPCurve->Continuity() < GeomAbs_C1)
	{
	  Geom2dConvert_ApproxCurve Approx2d( newPCurve, Tol, Continuity, MaxSeg, MaxDeg );
	  if (Approx2d.HasResult())
	    newPCurve = Approx2d.Curve();
	}
      newFirst = newPCurve->FirstParameter();
      newLast  = newPCurve->LastParameter();
    }

  return newPCurve;
}

//=======================================================================
//function : Glue
//purpose  : glue two edges.
//=======================================================================

static TopoDS_Edge Glue(const TopoDS_Edge& E1,
			const TopoDS_Edge& E2,
			const TopoDS_Vertex& Vfirst,
			const TopoDS_Vertex& Vlast,
			const Standard_Boolean After,
			const TopoDS_Face& F1,
			const Standard_Boolean addPCurve1,
			const TopoDS_Face& F2,
			const Standard_Boolean addPCurve2)
{
  Standard_Real Tol = 1.e-7;
  GeomAbs_Shape Continuity = GeomAbs_C1;
  Standard_Integer MaxDeg = 14;
  Standard_Integer MaxSeg = 16;

  Handle(Geom_Curve) C1, C2, newCurve;
  Handle(Geom2d_Curve) PCurve1, PCurve2, newPCurve;
  Standard_Real first1, last1, first2, last2, fparam=0., lparam=0.;
  Standard_Boolean IsCanonic = Standard_False;

  C1 = BRep_Tool::Curve( E1, first1, last1 ); 
  if (C1->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
    C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();

  C2 = BRep_Tool::Curve( E2, first2, last2 );
  if (C2->IsInstance(STANDARD_TYPE(Geom_TrimmedCurve)))
    C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();

  if (C1 == C2)
    {
      newCurve = C1;
      fparam = Min( first1, first2 );
      lparam = Max( last1, last2 );
    }
  else if (C1->DynamicType() == C2->DynamicType() &&
	   (C1->IsInstance(STANDARD_TYPE(Geom_Line)) ||
	    C1->IsKind(STANDARD_TYPE(Geom_Conic))))
    {
      IsCanonic = Standard_True;
      newCurve  = C1;
    }
  else
    {
      Handle(Geom_TrimmedCurve) TC1 = new Geom_TrimmedCurve( C1, first1, last1 );
      Handle(Geom_TrimmedCurve) TC2 = new Geom_TrimmedCurve( C2, first2, last2 );
      GeomConvert_CompCurveToBSplineCurve Concat( TC1 );
      Concat.Add( TC2, Precision::Confusion(), After );
      newCurve = Concat.BSplineCurve();
      if (newCurve->Continuity() < GeomAbs_C1)
	{
	  GeomConvert_ApproxCurve Approx3d( newCurve, Tol, Continuity, MaxSeg, MaxDeg );
	  if (Approx3d.HasResult())
	    newCurve = Approx3d.Curve();
	}
      fparam = newCurve->FirstParameter();
      lparam = newCurve->LastParameter();
    }

  TopoDS_Edge newEdge;
  BRep_Builder BB;

  if (IsCanonic)
    newEdge = BRepLib_MakeEdge( newCurve, Vfirst, Vlast );
  else
    newEdge = BRepLib_MakeEdge( newCurve, Vfirst, Vlast, fparam, lparam );

  Standard_Real newFirst, newLast;
  if (addPCurve1)
    {
      newPCurve = ConcatPCurves( E1, E2, F1, After, newFirst, newLast );
      BB.UpdateEdge( newEdge, newPCurve, F1, 0. );
      BB.Range( newEdge, F1, newFirst, newLast );
    }
  if (addPCurve2)
    {
      newPCurve = ConcatPCurves( E1, E2, F2, After, newFirst, newLast );
      BB.UpdateEdge( newEdge, newPCurve, F2, 0. );
      BB.Range( newEdge, F2, newFirst, newLast );
    }

  return newEdge;
}


//=======================================================================
//function : FindNewVerticesOnBoundsOfFace
//purpose  : 
//=======================================================================

static void FindNewVerticesOnBoundsOfFace(const BOPTools_DSFiller& pDF,
					  const TopoDS_Face& aFace,
					  const Standard_Integer iFace,
					  TopTools_DataMapOfShapeShape& VEmap)
{
  TopTools_IndexedMapOfShape OldVertices;
  TopExp::MapShapes( aFace, TopAbs_VERTEX, OldVertices );

  const BOPTools_SplitShapesPool& aPool = pDF.SplitShapesPool();

  TopExp_Explorer Explo( aFace, TopAbs_EDGE );
  for (; Explo.More(); Explo.Next())
    {
      TopoDS_Shape anEdge = Explo.Current();
      Standard_Integer eind = pDF.DS().ShapeIndex(anEdge,iFace);
      const BOPTools_ListOfPaveBlock& aSplitEdges = aPool( pDF.DS().RefEdge(eind) );
      BOPTools_ListIteratorOfListOfPaveBlock itpb( aSplitEdges );
      for (; itpb.More(); itpb.Next())
	{
	  BOPTools_PaveBlock& aPaveBlock = itpb.Value();
	  TopoDS_Shape aSplit = pDF.DS().GetShape( aPaveBlock.Edge() );
	  TopoDS_Edge aNewEdge = TopoDS::Edge(aSplit);
	  TopoDS_Vertex V1, V2;
	  TopExp::Vertices( aNewEdge, V1, V2 );
	  if (!OldVertices.Contains( V1 ))
	    VEmap.Bind( V1, anEdge );
	  if (!OldVertices.Contains( V2 ))
	    VEmap.Bind( V2, anEdge );
	}
    }
}
				   
//=======================================================================
//function : CheckIntersFF
//purpose  : 
//=======================================================================

static Standard_Boolean CheckIntersFF(const BOPTools_DSFiller& pDF,
				      const TopoDS_Edge& RefEdge,
				      const TopoDS_Face& F1,
				      const TopoDS_Face& F2,
				      TopTools_IndexedMapOfShape& TrueEdges)
{
  Standard_Boolean isEl1 = Standard_False, isEl2 = Standard_False;
  Standard_Boolean isPlane1 = Standard_False, isPlane2 = Standard_False;

  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(F1);
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
    aSurf = (*((Handle(Geom_RectangularTrimmedSurface)*)&aSurf))->BasisSurface();
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_Plane)))
    isPlane1 = Standard_True;
  else if (aSurf->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
    isEl1 = Standard_True;

  aSurf = BRep_Tool::Surface(F2);
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
    aSurf = (*((Handle(Geom_RectangularTrimmedSurface)*)&aSurf))->BasisSurface();
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_Plane)))
    isPlane2 = Standard_True;
  else if (aSurf->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
    isEl2 = Standard_True;

  if (isPlane1 || isPlane2)
    return Standard_True;

  if (isEl1 && isEl2)
    return Standard_True;

  const BooleanOperations_ShapesDataStructure& aDS = pDF.DS();
  BOPTools_InterferencePool* anIntrPool = (BOPTools_InterferencePool*)&pDF.InterfPool();
  BOPTools_CArray1OfSSInterference& aFFs = anIntrPool->SSInterferences();
  Standard_Integer aNb = aFFs.Extent();
  Standard_Integer i, j, nbe = 0;

  TopTools_SequenceOfShape Edges;
  
  for (i = 1; i <= aNb; i++)
    {
      BOPTools_SSInterference& aFFi = aFFs(i);
      BOPTools_SequenceOfCurves& aBCurves = aFFi.Curves();
      Standard_Integer aNbCurves = aBCurves.Length();
      
      for (j = 1; j <= aNbCurves; j++)
	{
	  BOPTools_Curve& aBC = aBCurves(j);
	  const BOPTools_ListOfPaveBlock& aSectEdges = aBC.NewPaveBlocks();
	  
	  BOPTools_ListIteratorOfListOfPaveBlock aPBIt(aSectEdges);
	  
	  for (; aPBIt.More(); aPBIt.Next())
	    {
	      BOPTools_PaveBlock& aPB=aPBIt.Value();
	      Standard_Integer nSect = aPB.Edge();
	      TopoDS_Edge anEdge = TopoDS::Edge(aDS.Shape(nSect));
	      Edges.Append( anEdge );
	      nbe++;
	    }
	}
    }

  if (nbe <= 1)
    return Standard_True;

  //define tangents of RefEdge on start and on end
  BRepAdaptor_Curve cref(RefEdge);
  gp_Vec RefTangFirst = cref.DN(cref.FirstParameter(), 1);
  gp_Vec RefTangLast  = cref.DN(cref.LastParameter(), 1);

  //find the start edge and take it from Edges
  TopoDS_Edge StartEdge; //, StartEonF1, StartEonF2, EndEonF1, EndEonF2;

  TopTools_DataMapOfShapeShape VEmapF1, VEmapF2;
  FindNewVerticesOnBoundsOfFace( pDF, F1, 1, VEmapF1 );
  FindNewVerticesOnBoundsOfFace( pDF, F2, 2, VEmapF2 );

  Standard_Real AngTol = 0.1;
  Standard_Boolean V1onBound = Standard_False;
  Standard_Boolean V2onBound = Standard_False;
  TopoDS_Vertex V1, V2, Vcur;
  gp_Vec TangFirst, TangLast, TangCur;
  for (i = 1; i <= Edges.Length(); i++)
    {
      StartEdge = TopoDS::Edge(Edges(i));
      TopExp::Vertices( StartEdge, V1, V2 );
      V1onBound = VEmapF1.IsBound(V1) || VEmapF2.IsBound(V1); // && ?
      V2onBound = VEmapF1.IsBound(V2) || VEmapF2.IsBound(V2); // && ?
      if (V1onBound || V2onBound)
	{
	  BRepAdaptor_Curve CE(StartEdge);
	  TangFirst = CE.DN( CE.FirstParameter(), 1 );
	  TangLast = CE.DN( CE.LastParameter(), 1 );
	  if (V1onBound)
	    {
	      if (TangFirst.IsParallel( RefTangFirst, AngTol ) ||
		  TangFirst.IsParallel( RefTangLast,  AngTol ))
		break; //start edged found
	    }
	  else if (V2onBound)
	    {
	      if (TangLast.IsParallel( RefTangLast,  AngTol ) ||
		  TangLast.IsParallel( RefTangFirst, AngTol ))
		break; //start edged found
	    }
	}
    }

  if (i > Edges.Length()) //start edged not found
    return Standard_False;

  if (V1onBound && V2onBound)
    {
      if (TangFirst.IsParallel(RefTangFirst,AngTol) && TangLast.IsParallel(RefTangLast,AngTol) ||
	  TangFirst.IsParallel(RefTangLast,AngTol)  && TangLast.IsParallel(RefTangFirst,AngTol))
	{
	  TrueEdges.Add( Edges(i) );
	  return Standard_True;
	}
      else
	return Standard_False;
    }

  //StartEonF1 = (V1onBound)? VEmapF1( V1 ) : VEmapF1( V2 );
  //StartEonF2 = (V1onBound)? VEmapF2( V1 ) : VEmapF2( V2 );

  TrueEdges.Add( Edges(i) );
  Edges.Remove(i);
  Vcur    = (V1onBound)? V2 : V1;
  TangCur = (V1onBound)? TangLast : TangFirst;
  if (V2onBound)
    TangCur.Reverse();
  
  //build the chain from StartEdge till the opposite bound of face
  for (;;)
    {
      TColStd_SequenceOfInteger Candidates;
      for (i = 1; i <= Edges.Length(); i++)
	{
	  TopoDS_Edge anEdge = TopoDS::Edge(Edges(i));
	  TopExp::Vertices( anEdge, V1, V2 );
	  if (V1.IsSame(Vcur) || V2.IsSame(Vcur))
	    Candidates.Append(i);
	}
      if (Candidates.IsEmpty())
	{
	  TrueEdges.Clear();
	  return Standard_False;
	}

      Standard_Integer minind = 1;
      if (Candidates.Length() > 1)
	{
	  Standard_Real MinAngle = RealLast();
	  for (i = 1; i <= Candidates.Length(); i++)
	    {
	      TopoDS_Edge anEdge = TopoDS::Edge(Edges(Candidates(i)));
	      TopExp::Vertices( anEdge, V1, V2 );
	      Standard_Boolean ConnectByFirst = (Vcur.IsSame(V1))? Standard_True : Standard_False;
	      BRepAdaptor_Curve CE(anEdge);
	      gp_Vec aTang = (ConnectByFirst)?
		CE.DN( CE.FirstParameter(), 1 ) : CE.DN( CE.LastParameter(), 1 );
	      if (!ConnectByFirst)
		aTang.Reverse();
	      Standard_Real anAngle = TangCur.Angle(aTang);
	      if (anAngle < MinAngle)
		{
		  MinAngle = anAngle;
		  minind = i;
		}
	    }
	}
      TopoDS_Edge CurEdge = TopoDS::Edge(Edges(Candidates(minind)));
      TrueEdges.Add( CurEdge );
      Edges.Remove(Candidates(minind));
      TopExp::Vertices( CurEdge, V1, V2 );
      Standard_Boolean ConnectByFirst = (Vcur.IsSame(V1))? Standard_True : Standard_False;
      Vcur = (ConnectByFirst)? V2 : V1;
      BRepAdaptor_Curve CE(CurEdge);
      TangCur = (ConnectByFirst)? CE.DN( CE.LastParameter(), 1 ) : CE.DN( CE.FirstParameter(), 1 );
      if (!ConnectByFirst)
	TangCur.Reverse();
      //check if Vcur is on bounds of faces
      if (VEmapF1.IsBound(Vcur) || VEmapF2.IsBound(Vcur))
	break;
    } //end of for (;;)
  
  if (TangCur.IsParallel( RefTangFirst, AngTol ) ||
      TangCur.IsParallel( RefTangLast,  AngTol ))
    return Standard_True;

  TrueEdges.Clear();
  return Standard_False;
}

//=======================================================================
//function : AssembleEdge
//purpose  : 
//=======================================================================

static TopoDS_Edge AssembleEdge(const BOPTools_DSFiller* pDF,
				const TopoDS_Face& F1,
				const TopoDS_Face& F2,
				const Standard_Boolean addPCurve1,
				const Standard_Boolean addPCurve2,
				const TopTools_SequenceOfShape& EdgesForConcat)
{
  TopoDS_Edge CurEdge = TopoDS::Edge( EdgesForConcat(1) );
  for (Standard_Integer j = 2; j <= EdgesForConcat.Length(); j++)
    {
      TopoDS_Edge anEdge = TopoDS::Edge( EdgesForConcat(j) );
      Standard_Boolean After = Standard_False;
      TopoDS_Vertex Vfirst, Vlast;
      if (AreClosed( CurEdge, anEdge ))
	{
	  TopoDS_Vertex V1, V2;
	  TopExp::Vertices( CurEdge, V1, V2 );
	  if (IsAutonomVertex( V1, F1, F2, pDF->DS(), pDF->PaveFiller() ))
	    {
	      After = Standard_False;
	      Vfirst = Vlast = V2;
	    }
	  else
	    {
	      After = Standard_True;
	      Vfirst = Vlast = V1;
	    }
	}
      else
	{
	  TopoDS_Vertex CV, V11, V12, V21, V22;
	  TopExp::CommonVertex( CurEdge, anEdge, CV );
	  TopExp::Vertices( CurEdge, V11, V12 );
	  TopExp::Vertices( anEdge,  V21, V22 );
	  if (V11.IsSame(CV) && V21.IsSame(CV))
	    {
	      Vfirst = V22;
	      Vlast  = V12;
	    }
	  else if (V11.IsSame(CV) && V22.IsSame(CV))
	    {
	      Vfirst = V21;
	      Vlast  = V12;
	    }
	  else if (V12.IsSame(CV) && V21.IsSame(CV))
	    {
	      Vfirst = V11;
	      Vlast  = V22;
	    }
	  else
	    {
	      Vfirst = V11;
	      Vlast  = V21;
	    }
	} //end of else (open wire)
      
      TopoDS_Edge NewEdge = Glue(CurEdge, anEdge,
				 Vfirst, Vlast, After,
				 F1, addPCurve1, F2, addPCurve2);
      CurEdge = NewEdge;
    } //end of for (Standard_Integer j = 2; j <= EdgesForConcat.Length(); j++)
  
  return CurEdge;
}

//=======================================================================
//function : Inter3D
//purpose  : 
//=======================================================================

void BRepOffset_Tool::Inter3D(const TopoDS_Face& F1,
			      const TopoDS_Face& F2,
			      TopTools_ListOfShape& L1,
			      TopTools_ListOfShape& L2,
			      const TopAbs_State    Side,
			      const TopoDS_Edge&     RefEdge,
			      const Standard_Boolean IsRefEdgeDefined)
{
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F1);
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F2);
  }
#endif

  TopoDS_Face cpF1=F1; 
  TopoDS_Face cpF2=F2;
  // create 3D curves on faces
  BRepLib::BuildCurves3d(cpF1);
  BRepLib::BuildCurves3d(cpF2);
 
  BOPTools_DSFiller pDF1, pDF2;
  pDF1.SetShapes(cpF1, cpF2);
  
  pDF1.Perform();

  BOPTools_DSFiller * pDF = &pDF1;
  TopTools_IndexedMapOfShape TrueEdges;
  if (IsRefEdgeDefined && !CheckIntersFF( pDF1, RefEdge, cpF1, cpF2, TrueEdges ))
    {
      cpF1 = F2;
      cpF2 = F1;
      pDF2.SetShapes(cpF1, cpF2);
      pDF2.Perform();
      CheckIntersFF( pDF2, RefEdge, cpF1, cpF2, TrueEdges );
      pDF = &pDF2;
   }

  Standard_Boolean addPCurve1 = pDF->PaveFiller().SectionAttribute().PCurveOnS1();
  Standard_Boolean addPCurve2 = pDF->PaveFiller().SectionAttribute().PCurveOnS2();
  
  const BooleanOperations_ShapesDataStructure& aDS = pDF->DS();
  BOPTools_InterferencePool* anIntrPool = (BOPTools_InterferencePool*)& pDF->InterfPool();
  BOPTools_CArray1OfSSInterference& aFFs = anIntrPool->SSInterferences();
  Standard_Integer aNb = aFFs.Extent();
  Standard_Integer i = 0, j = 0, k;
  // Store Result
  L1.Clear(); L2.Clear();
  TopAbs_Orientation O1,O2;
  
  for (i = 1; i <= aNb; i++) {
    BOPTools_SSInterference& aFFi = aFFs(i);
    BOPTools_SequenceOfCurves& aBCurves = aFFi.Curves();
    Standard_Integer aNbCurves = aBCurves.Length();
        
    for (j = 1; j <= aNbCurves; j++) {
      BOPTools_Curve& aBC = aBCurves(j);
      const BOPTools_ListOfPaveBlock& aSectEdges = aBC.NewPaveBlocks();
      
      BOPTools_ListIteratorOfListOfPaveBlock aPBIt(aSectEdges);
      
      for (; aPBIt.More(); aPBIt.Next()) {
	BOPTools_PaveBlock& aPB=aPBIt.Value();
	Standard_Integer nSect = aPB.Edge();
        TopoDS_Edge anEdge = TopoDS::Edge(aDS.Shape(nSect));
	if (!TrueEdges.IsEmpty() && !TrueEdges.Contains(anEdge))
	  continue;
        
        Standard_Real f, l;
	const Handle(Geom_Curve)& aC3DE = BRep_Tool::Curve(anEdge, f, l);
	Handle(Geom_TrimmedCurve) aC3DETrim;
	    
	if(!aC3DE.IsNull()) 
            aC3DETrim = new Geom_TrimmedCurve(aC3DE, f, l);
        
        BRep_Builder aBB;
	Standard_Real aTolEdge = BRep_Tool::Tolerance(anEdge);
	        
        if (!BOPTools_Tools2D::HasCurveOnSurface(anEdge, cpF1)) {
          Handle(Geom2d_Curve) aC2d = aBC.Curve().FirstCurve2d();
          if(!aC3DETrim.IsNull()) {
		Handle(Geom2d_Curve) aC2dNew;
		
		if(aC3DE->IsPeriodic()) {
		  BOPTools_Tools2D::AdjustPCurveOnFace(cpF1, f, l,  aC2d, aC2dNew);
		  }
		else {
		  BOPTools_Tools2D::AdjustPCurveOnFace(cpF1, aC3DETrim, aC2d, aC2dNew); 
		  }
		aC2d = aC2dNew;
	      }
	      aBB.UpdateEdge(anEdge, aC2d, cpF1, aTolEdge);
        }
        
        if (!BOPTools_Tools2D::HasCurveOnSurface(anEdge, cpF2)) {
          Handle(Geom2d_Curve) aC2d = aBC.Curve().SecondCurve2d();
          if(!aC3DETrim.IsNull()) {
		Handle(Geom2d_Curve) aC2dNew;
		
		if(aC3DE->IsPeriodic()) {
		  BOPTools_Tools2D::AdjustPCurveOnFace(cpF2, f, l,  aC2d, aC2dNew);
		  }
		else {
		  BOPTools_Tools2D::AdjustPCurveOnFace(cpF2, aC3DETrim, aC2d, aC2dNew); 
		  }
		aC2d = aC2dNew;
	      }
	      aBB.UpdateEdge(anEdge, aC2d, cpF2, aTolEdge);
        }
         
        OrientSection (anEdge, F1, F2, O1, O2);
        if (Side == TopAbs_OUT) {
          O1 = TopAbs::Reverse(O1);
          O2 = TopAbs::Reverse(O2);
        }
        
        L1.Append (anEdge.Oriented(O1));
        L2.Append (anEdge.Oriented(O2));
        
#ifdef DRAW
        if (AffichInter) {
          char* name = new char[100];
          sprintf(name,"EI_%d",NbNewEdges++);	
          DBRep::Set(name,anEdge.Oriented(O1));
         
        }
#endif       
      }
    }
  }

  Standard_Real aSameParTol = Precision::Confusion();
  Standard_Boolean isEl1 = Standard_False, isEl2 = Standard_False;

  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(cpF1);
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
    aSurf = (*((Handle(Geom_RectangularTrimmedSurface)*)&aSurf))->BasisSurface();
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_Plane)))
    addPCurve1 = Standard_False;
  else if (aSurf->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
    isEl1 = Standard_True;

  aSurf = BRep_Tool::Surface(cpF2);
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_RectangularTrimmedSurface)))
    aSurf = (*((Handle(Geom_RectangularTrimmedSurface)*)&aSurf))->BasisSurface();
  if (aSurf->IsInstance(STANDARD_TYPE(Geom_Plane)))
    addPCurve2 = Standard_False;
  else if (aSurf->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
    isEl2 = Standard_True;

  if (L1.Extent() > 1 && (!isEl1 || !isEl2)) {
    TopTools_SequenceOfShape eseq;
    TopTools_SequenceOfShape EdgesForConcat;

    if (!TrueEdges.IsEmpty())
      {
	for (i = TrueEdges.Extent(); i >= 1; i--)
	  EdgesForConcat.Append( TrueEdges(i) );
	TopoDS_Edge theEdge =
	  AssembleEdge( pDF, cpF1, cpF2, addPCurve1, addPCurve2, EdgesForConcat );
	eseq.Append(theEdge);
      }
    else
      {
	const BOPTools_PaveFiller& thePaveFiller = pDF->PaveFiller();
	
	TopTools_SequenceOfShape wseq;
	TopTools_SequenceOfShape edges;
	TopTools_ListIteratorOfListOfShape itl(L1);
	for (; itl.More(); itl.Next())
	  edges.Append( itl.Value() );
	while (!edges.IsEmpty())
	  {
	    TopoDS_Edge anEdge = TopoDS::Edge( edges.First() );
	    TopoDS_Wire aWire = BRepLib_MakeWire( anEdge ), resWire;
	    TColStd_SequenceOfInteger Candidates;
	    for (k = 1; k <= wseq.Length(); k++)
	      {
		resWire = TopoDS::Wire(wseq(k));
		if (AreConnex( resWire, aWire, cpF1, cpF2, pDF ))
		  {
		    Candidates.Append( 1 );
		    break;
		  }
	      }
	    if (Candidates.IsEmpty())
	      {
		wseq.Append( aWire );
		edges.Remove(1);
	      }
	    else
	      {
		for (j = 2; j <= edges.Length(); j++)
		  {
		    anEdge = TopoDS::Edge( edges(j) );
		    //if (anEdge.IsSame(edges(Candidates.First())))
		    //continue;
		    aWire = BRepLib_MakeWire( anEdge );
		    if (AreConnex( resWire, aWire, cpF1, cpF2, pDF ))
		      Candidates.Append( j );
		  }
		Standard_Integer minind = 1;
		if (Candidates.Length() > 1)
		  {
		    Standard_Real MinAngle = RealLast();
		    for (j = 1; j <= Candidates.Length(); j++)
		      {
			anEdge = TopoDS::Edge( edges(Candidates(j)) );
			Standard_Real anAngle = AngleWireEdge( resWire, anEdge );
			if (anAngle < MinAngle)
			  {
			    MinAngle = anAngle;
			    minind = j;
			  }
		      }
		  }
		TopoDS_Wire NewWire = BRepLib_MakeWire( resWire, TopoDS::Edge(edges(Candidates(minind))) );
		wseq(k) = NewWire;
		edges.Remove(Candidates(minind));
	      }
	  } //end of while (!edges.IsEmpty())
	
	for (i = 1; i <= wseq.Length(); i++)
	  {
	    TopoDS_Wire aWire = TopoDS::Wire(wseq(i));
	    TopTools_SequenceOfShape EdgesForConcat;
	    if (aWire.Closed())
	      {
		TopoDS_Vertex StartVertex;
		TopoDS_Edge StartEdge;
		Standard_Boolean StartFound = Standard_False;
		TopTools_ListOfShape Elist;
		
		TopoDS_Iterator itw(aWire);
		for (; itw.More(); itw.Next())
		  {
		    TopoDS_Edge anEdge = TopoDS::Edge(itw.Value());
		    if (StartFound)
		      Elist.Append(anEdge);
		    else
		      {
			TopoDS_Vertex V1, V2;
			TopExp::Vertices( anEdge, V1, V2 );
			if (!IsAutonomVertex( V1, cpF1, cpF2, aDS, thePaveFiller ))
			  {
			    StartVertex = V2;
			    StartEdge = anEdge;
			    StartFound = Standard_True;
			  }
			else if (!IsAutonomVertex( V2, cpF1, cpF2, aDS, thePaveFiller ))
			  {
			    StartVertex = V1;
			    StartEdge = anEdge;
			    StartFound = Standard_True;
			  }
			else
			  Elist.Append(anEdge);
		      }
		  } //end of for (; itw.More(); itw.Next())
		if (!StartFound)
		  {
		    itl.Initialize(Elist);
		    StartEdge = TopoDS::Edge(itl.Value());
		    Elist.Remove(itl);
		    TopoDS_Vertex V1, V2;
		    TopExp::Vertices( StartEdge, V1, V2 );
		    StartVertex = V1;
		  }
		EdgesForConcat.Append( StartEdge );
		while (!Elist.IsEmpty())
		  {
		    for (itl.Initialize(Elist); itl.More(); itl.Next())
		      {
			TopoDS_Edge anEdge = TopoDS::Edge(itl.Value());
			TopoDS_Vertex V1, V2;
			TopExp::Vertices( anEdge, V1, V2 );
			if (V1.IsSame(StartVertex))
			  {
			    StartVertex = V2;
			    EdgesForConcat.Append( anEdge );
			    Elist.Remove(itl);
			    break;
			  }
			else if (V2.IsSame(StartVertex))
			  {
			    StartVertex = V1;
			    EdgesForConcat.Append( anEdge );
			    Elist.Remove(itl);
			    break;
			  }
		      }
		  } //end of while (!Elist.IsEmpty())
	      } //end of if (aWire.Closed())
	    else
	      {
		BRepTools_WireExplorer Wexp( aWire );
		for (; Wexp.More(); Wexp.Next())
		  EdgesForConcat.Append( Wexp.Current() );
	      }
	    
	    TopoDS_Edge theEdge =
	      AssembleEdge( pDF, cpF1, cpF2, addPCurve1, addPCurve2, EdgesForConcat );
	    eseq.Append( theEdge );
	  }
      } //end of else (when TrueEdges is empty)
    
    if (eseq.Length() < L1.Extent())
      {
	L1.Clear();
	L2.Clear();
	for (i = 1; i <= eseq.Length(); i++)
	  {
	    TopoDS_Edge anEdge = TopoDS::Edge(eseq(i));
	    BRepLib::SameParameter(anEdge, aSameParTol, Standard_True);
	    Standard_Real EdgeTol = BRep_Tool::Tolerance(anEdge);
#ifdef DEB
	    cout<<"Tolerance of glued E =      "<<EdgeTol<<endl;
#endif
	    if (EdgeTol > 1.e-2)
	      continue;

	    if (EdgeTol >= 1.e-4)
	      {
		ReconstructPCurves(anEdge);
		BRepLib::SameParameter(anEdge, aSameParTol, Standard_True);
#ifdef DEB
	        cout<<"After projection tol of E = "<<BRep_Tool::Tolerance(anEdge)<<endl;
#endif
	      }

	    OrientSection( anEdge, F1, F2, O1, O2 );
	    if (Side == TopAbs_OUT)
	      {
		O1 = TopAbs::Reverse(O1);
		O2 = TopAbs::Reverse(O2);
	      }
	    
	    L1.Append( anEdge.Oriented(O1) );
	    L2.Append( anEdge.Oriented(O2) );
	  }
      }
  } //end of if (L1.Extent() > 1)

  else
    {
      TopTools_ListIteratorOfListOfShape itl(L1);
      for (; itl.More(); itl.Next())
	{
	  const TopoDS_Edge& anEdge = TopoDS::Edge( itl.Value() );
	  BRepLib::SameParameter(anEdge, aSameParTol, Standard_True);
	}
    }
}

//=======================================================================
//function : TryProject
//purpose  : 
//=======================================================================

Standard_Boolean BRepOffset_Tool::TryProject
(const TopoDS_Face&          F1,
 const TopoDS_Face&          F2,
 const TopTools_ListOfShape& Edges,
       TopTools_ListOfShape& LInt1,
       TopTools_ListOfShape& LInt2,
 const TopAbs_State          Side,
 const Standard_Real         TolConf)
{
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F1);
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F2);
  }
#endif

  // try to find if the edges <Edges> are laying on the face F1.
  LInt1.Clear(); LInt2.Clear();
  TopTools_ListIteratorOfListOfShape it(Edges);
  Standard_Boolean     isOk = Standard_True;
  Standard_Boolean     Ok   = Standard_True;
  TopAbs_Orientation   O1,O2;
  Handle(Geom_Surface) Bouchon = BRep_Tool::Surface(F1);
  BRep_Builder B;

  for ( ; it.More(); it.Next()) {
    TopLoc_Location L;
    Standard_Real f,l;
    TopoDS_Edge CurE     = TopoDS::Edge(it.Value());
    Handle(Geom_Curve) C = BRep_Tool::Curve(CurE,L,f,l);
    if (C.IsNull()) {
      BRepLib::BuildCurve3d(CurE,BRep_Tool::Tolerance(CurE));
      C  = BRep_Tool::Curve(CurE,L,f,l);
    }
    C = new Geom_TrimmedCurve(C,f,l);
    if ( !L.IsIdentity()) C->Transform(L);
    Standard_Real TolReached;
    isOk = IsOnSurface(C,Bouchon,TolConf,TolReached);
    
    if ( isOk) {
      B.UpdateEdge(CurE,TolReached);
      BuildPCurves(CurE,F1);
      OrientSection (CurE,F1,F2,O1,O2);
      if (Side == TopAbs_OUT) {
	O1 = TopAbs::Reverse(O1);
	O2 = TopAbs::Reverse(O2);
      }
      LInt1.Append (CurE.Oriented(O1));
      LInt2.Append (CurE.Oriented(O2));
#ifdef DRAW
      if (AffichInter) {
    // POP pour NT
	char* name = new char[100];
	sprintf(name,"EI_%d",NbNewEdges++);	
	DBRep::Set(name,CurE.Oriented(O1));
      }
#endif      
    }
    else 
      Ok = Standard_False;
  }
  return Ok;
}


//=======================================================================
//function : InterOrExtent
//purpose  : 
//=======================================================================

void BRepOffset_Tool::InterOrExtent(const TopoDS_Face& F1,
				    const TopoDS_Face& F2,
				    TopTools_ListOfShape& L1,
				    TopTools_ListOfShape& L2,
				    const TopAbs_State    Side)
{
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F1);
    sprintf(name,"FF_%d",NbFaces++);
    DBRep::Set(name,F2);
  }
#endif

  Handle (Geom_Curve) CI;
  TopoDS_Edge E;
  TopAbs_Orientation O1,O2;
  L1.Clear(); L2.Clear();
  Handle (Geom_Surface) S1 = BRep_Tool::Surface(F1);
  Handle (Geom_Surface) S2 = BRep_Tool::Surface(F2);  

  if (S1->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
    Handle(Geom_RectangularTrimmedSurface) RTS ;
    RTS = *((Handle(Geom_RectangularTrimmedSurface)*) &S1);
    if (RTS->BasisSurface()->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
      S1 = RTS->BasisSurface();
    }
  }
  if (S2->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
    Handle(Geom_RectangularTrimmedSurface) RTS ;
    RTS = *((Handle(Geom_RectangularTrimmedSurface)*) &S2);
    if (RTS->BasisSurface()->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
      S2 = RTS->BasisSurface();
    }
  }

  GeomInt_IntSS Inter  (S1,S2, Precision::Confusion());

  if (Inter.IsDone()) {
    for (Standard_Integer i = 1; i <= Inter.NbLines(); i++) {
      CI = Inter.Line(i);
      
      if (ToSmall(CI)) continue;
      TopoDS_Edge E = BRepLib_MakeEdge(CI);
      BuildPCurves (E,F1);
      BuildPCurves (E,F2);
      OrientSection (E,F1,F2,O1,O2);
      if (Side == TopAbs_OUT) {
	O1 = TopAbs::Reverse(O1);
	O2 = TopAbs::Reverse(O2);
      }
      L1.Append (E.Oriented(O1));
      L2.Append (E.Oriented(O2));
#ifdef DRAW
      if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
	sprintf(name,"EI_%d",NbNewEdges++);	
	DBRep::Set(name,E.Oriented(O1));
      }
#endif      
    }
  }
}

//=======================================================================
//function : ExtentEdge
//purpose  : 
//=======================================================================

static void ExtentEdge(const TopoDS_Face& F,
		       const TopoDS_Face& EF,
		       const TopoDS_Edge& E,
		       TopoDS_Edge&       NE)
{
  BRepAdaptor_Curve CE(E);
  GeomAbs_CurveType Type = CE.GetType();
  TopoDS_Shape aLocalEdge = E.EmptyCopied();
  NE = TopoDS::Edge(aLocalEdge); 
//  NE = TopoDS::Edge(E.EmptyCopied()); 

  if (Type == GeomAbs_Line || Type == GeomAbs_Circle || Type == GeomAbs_Ellipse || 
      Type == GeomAbs_Hyperbola || Type == GeomAbs_Parabola) {
    return;
  }
  // Extension en tangence jusqu'au bord de la surface.
  Standard_Real   PMax = 1.e2;
  TopLoc_Location L;
  Handle(Geom_Surface) S = BRep_Tool::Surface(F,L);
  Standard_Real umin,umax,vmin,vmax;

  S->Bounds(umin,umax,vmin,vmax);
  umin = Max(umin,-PMax);vmin = Max(vmin,-PMax);
  umax = Min(umax, PMax);vmax = Min(vmax, PMax);

 
  Standard_Real f,l;
  Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E,F,f,l);

  //calcul point cible . ie point d'intersection du prolongement tangent et des bords.
  gp_Pnt2d P;
  gp_Vec2d Tang;
  C2d->D1(CE.FirstParameter(),P,Tang);
  Standard_Real tx,ty,tmin;
  tx = ty = Precision::Infinite();
  if (Abs(Tang.X()) > Precision::Confusion())
    tx = Min (Abs((umax - P.X())/Tang.X()), Abs((umin - P.X())/Tang.X()));
  if (Abs(Tang.Y()) > Precision::Confusion())
    ty = Min (Abs((vmax - P.Y())/Tang.Y()), Abs((vmin - P.Y())/Tang.Y()));
  tmin = Min (tx,ty);
  Tang = tmin*Tang;
  gp_Pnt2d  PF2d (P.X() - Tang.X(),P.Y() - Tang.Y());

  C2d->D1(CE.LastParameter(),P,Tang);
  tx = ty = Precision::Infinite();
  if (Abs(Tang.X()) > Precision::Confusion())
    tx = Min (Abs((umax - P.X())/Tang.X()), Abs((umin - P.X())/Tang.X()));
  if (Abs(Tang.Y()) > Precision::Confusion())
    ty = Min (Abs((vmax - P.Y())/Tang.Y()), Abs((vmin - P.Y())/Tang.Y()));
  tmin = Min (tx,ty);
  Tang = tmin*Tang;
  gp_Pnt2d  PL2d (P.X() + Tang.X(),P.Y() + Tang.Y());

  Handle(Geom_Curve) CC = GeomAPI::To3d(C2d,gp_Pln(gp::XOY()));
  gp_Pnt PF(PF2d.X(),PF2d.Y(),0.);
  gp_Pnt PL(PL2d.X(),PL2d.Y(),0.);

  Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(CC);
  if (ExtC.IsNull()) return;

  GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
  GeomLib::ExtendCurveToPoint(ExtC,PL,1,1); 

  Handle(Geom2d_Curve) CNE2d = GeomAPI::To2d(ExtC,gp_Pln(gp::XOY()));

  //Construction de la nouvelle arrete;
  BRep_Builder B;
  B.MakeEdge(NE);
//  B.UpdateEdge (NE,CNE2d,F,BRep_Tool::Tolerance(E));
  B.UpdateEdge (NE,CNE2d,EF,BRep_Tool::Tolerance(E));
  B.Range (NE,CNE2d->FirstParameter(), CNE2d->LastParameter());
  NE.Orientation(E.Orientation());
#ifdef DRAW
  if (AffichExtent) {
    char* name = new char[100];
    sprintf (name,"F_%d",NbExtE);
    DBRep::Set(name,EF);
    sprintf (name,"OE_%d",NbExtE);
    DBRep::Set (name,E);
    sprintf (name,"ExtE_%d",NbExtE++);
    DBRep::Set(name,NE);
  }
#endif
}

//=======================================================================
//function : ProjectVertexOnEdge
//purpose  : 
//=======================================================================

static Standard_Boolean  ProjectVertexOnEdge(TopoDS_Vertex&     V,
					     const TopoDS_Edge& E,
					     Standard_Real      TolConf)
{ 
#ifdef DRAW
  if (AffichExtent) {
    DBRep::Set("V",V); 
    DBRep::Set("E",E);
  }
#endif
  BRep_Builder    B;
  Standard_Real   f,l;
#ifndef DEB
  Standard_Real U = 0.;
#else
  Standard_Real U;
#endif
  TopLoc_Location L;
  Standard_Boolean found = Standard_False;

  gp_Pnt            P = BRep_Tool::Pnt  (V);  
  BRepAdaptor_Curve C = BRepAdaptor_Curve(E);
  f = C.FirstParameter(); l = C.LastParameter();

  if (V.Orientation() == TopAbs_FORWARD) {
    if (Abs(f) < Precision::Infinite()) { 
      gp_Pnt PF = C.Value (f);
      if (PF.IsEqual(P,TolConf)) {
	U = f;
	found = Standard_True;
      }
    }
  }
  if (V.Orientation() == TopAbs_REVERSED) {
    if (!found && Abs(l) < Precision::Infinite()) {
      gp_Pnt PL = C.Value (l);
      if (PL.IsEqual(P,TolConf)) {
	U = l;
	found = Standard_True;
      }
    }
  }
  if (!found) {
    Extrema_ExtPC Proj(P,C);
    if (Proj.IsDone() && Proj.NbExt() > 0) {
      Standard_Real Dist,DistMin = Proj.Value(1);
      U = Proj.Point(1).Parameter();
      for (Standard_Integer i = 2; i <= Proj.NbExt(); i++) {
	Dist = Proj.Value(i);
	if (Dist < DistMin) {
	  DistMin = Dist;
	  U = Proj.Point(i).Parameter();
	}
      }
      found = Standard_True;
    }
  }

#ifdef DEB
  if (AffichExtent) {
    Standard_Real Dist = P.Distance(C.Value(U));
    if (Dist > TolConf) {
      cout << " ProjectVertexOnEdge :distance vertex edge :"<<Dist<<endl;
    }
    if (U < f - Precision::Confusion() || 
	U > l + Precision::Confusion()) {
      cout << " ProjectVertexOnEdge : hors borne :"<<endl;
      cout << " f = "<<f<<" l ="<<l<< " U ="<<U<<endl;
    }
  }
  if (!found) {
    cout <<"BRepOffset_Tool::ProjectVertexOnEdge Parameter no found"<<endl;
    if (Abs(f) < Precision::Infinite() && 
	Abs(l) < Precision::Infinite()) {
#ifdef DRAW
      DBRep::Set("E",E);
#endif
    }
  }    
#endif 
  if (found) {
    TopoDS_Shape aLocalShape = E.Oriented(TopAbs_FORWARD);
    TopoDS_Edge EE = TopoDS::Edge(aLocalShape);
    aLocalShape = V.Oriented(TopAbs_INTERNAL);
//    TopoDS_Edge EE = TopoDS::Edge(E.Oriented(TopAbs_FORWARD));
    B.UpdateVertex(TopoDS::Vertex(aLocalShape),
		   U,EE,BRep_Tool::Tolerance(E));
    
  }
  return found;
}

//=======================================================================
//function : Inter2d					
//purpose  : 
//=======================================================================

void BRepOffset_Tool::Inter2d (const TopoDS_Face&    F,
			       const TopoDS_Edge&    E1,
			       const TopoDS_Edge&    E2,
			       TopTools_ListOfShape& LV,
			       const Standard_Real   TolConf) 
{
#ifdef DRAW
  if (AffichExtent) {
    DBRep::Set("E1",E1); 
    DBRep::Set("E2",E2);
    DBRep::Set("F",F);
  }
#endif
  BRep_Builder  B;
  Standard_Real fl1[2],fl2[2];
  LV.Clear();
  
  // Si l edge a ete etendu les pcurves ne sont pas forcement 
  // a jour.
  BuildPCurves(E1,F);
  BuildPCurves(E2,F);
  

  // Construction des curves 3d si elles n existent pas 
  // utile pour coder correctement les parametres des vertex 
  // d intersection sur les edges.
  //TopLoc_Location L;
  //Standard_Real   f,l;
  //Handle(Geom_Curve) C3d1 = BRep_Tool::Curve(E1,L,f,l);
  //if (C3d1.IsNull()) {
  //  BRepLib::BuildCurve3d(E1,BRep_Tool::Tolerance(E1));
  //}
  //Handle(Geom_Curve) C3d2 = BRep_Tool::Curve(E2,L,f,l);
  //if (C3d2.IsNull()) {
  //  BRepLib::BuildCurve3d(E2,BRep_Tool::Tolerance(E2));
  //}
  
  Standard_Integer NbPC1 = 1, NbPC2 = 1;
  if (BRep_Tool::IsClosed(E1,F)) NbPC1++;
  if (BRep_Tool::IsClosed(E2,F)) NbPC2++;
  
  Handle(Geom_Surface) S  = BRep_Tool::Surface(F);
  Handle(Geom2d_Curve) C1, C2;
  Standard_Boolean YaSol = Standard_False;
  Standard_Integer itry  = 0;

  while (!YaSol && itry < 2) {
    for ( Standard_Integer i = 1; i <= NbPC1 ; i++) {
	TopoDS_Shape aLocalEdge = E1.Reversed();
      if (i == 1)  C1 = BRep_Tool::CurveOnSurface(E1,F,fl1[0],fl1[1]);
      else         C1 = BRep_Tool::CurveOnSurface(TopoDS::Edge(aLocalEdge),
						  F,fl1[0],fl1[1]);
//      if (i == 1)  C1 = BRep_Tool::CurveOnSurface(E1,F,fl1[0],fl1[1]);
//     else         C1 = BRep_Tool::CurveOnSurface(TopoDS::Edge(E1.Reversed()),
//						  F,fl1[0],fl1[1]);
      for ( Standard_Integer j = 1; j <= NbPC2; j++ ) {
	TopoDS_Shape aLocalEdge = E2.Reversed();
	if (j == 1)  C2 = BRep_Tool::CurveOnSurface(E2,F,fl2[0],fl2[1]);
	else         C2 = BRep_Tool::CurveOnSurface(TopoDS::Edge(aLocalEdge),
						    F,fl2[0],fl2[1]);
//	if (j == 1)  C2 = BRep_Tool::CurveOnSurface(E2,F,fl2[0],fl2[1]);
//	else         C2 = BRep_Tool::CurveOnSurface(TopoDS::Edge(E2.Reversed()),
//						    F,fl2[0],fl2[1]);
#ifdef DEB
	if (C1.IsNull() || C2.IsNull()) {
	  cout <<"Inter2d : Pas de pcurve"<<endl;
#ifdef DRAW
	  DBRep::Set("E1",E1); 
	  DBRep::Set("E2",E2);
	  DBRep::Set("F",F);
#endif
	  return;
	}
#endif
#ifndef DEB
	Standard_Real    U1 = 0.,U2 = 0.;
#else
	Standard_Real    U1,U2;
#endif
	gp_Pnt2d         P2d;	
	if (itry == 1) {
	  fl1[0] = C1->FirstParameter(); fl1[1] = C1->LastParameter();
	  fl2[0] = C2->FirstParameter(); fl2[1] = C2->LastParameter();
	}
	Geom2dAdaptor_Curve   AC1(C1,fl1[0],fl1[1]);
	Geom2dAdaptor_Curve   AC2(C2,fl2[0],fl2[1]);

	if (itry == 0) {
	  gp_Pnt2d P1[2],P2[2];
	  P1[0] = C1->Value(fl1[0]); P1[1] = C1->Value(fl1[1]);
	  P2[0] = C2->Value(fl2[0]); P2[1] = C2->Value(fl2[1]);

	  Standard_Integer i1 ;
	  for ( i1 = 0; i1 < 2; i1++) {
	    for (Standard_Integer i2 = 0; i2 < 2; i2++) {
	      if (Abs(fl1[i1]) < Precision::Infinite() &&
		  Abs(fl2[i2]) < Precision::Infinite()   ) {
		if (P1[i1].IsEqual(P2[i2],TolConf)) {
		  YaSol = Standard_True;
		  U1  = fl1[i1]; U2 = fl2[i2];
		  P2d = C1->Value(U1);
		}
	      }
	    }
	  }
	  if (!YaSol)
	    for (i1 = 0; i1 < 2; i1++)
	      {
		Extrema_ExtPC2d extr( P1[i1], AC2 );
		if (extr.IsDone() && extr.NbExt() > 0)
		  {
		    Standard_Real Dist, DistMin = extr.Value(1);
		    Standard_Integer IndexMin = 1;
		    for (Standard_Integer ind = 2; ind <= extr.NbExt(); ind++)
		      {
			Dist = extr.Value(ind);
			if (Dist < DistMin)
			  {
			    DistMin = Dist;
			    IndexMin = ind;
			  }
		      }
		    if (DistMin <= Precision::Confusion())
		      {
			YaSol = Standard_True;
			P2d = P1[i1];
			U1 = fl1[i1];
			U2 = (extr.Point(IndexMin)).Parameter();
			break;
		      }
		  }
	      }
	  if (!YaSol)
	    for (Standard_Integer i2 = 0; i2 < 2; i2++)
	      {
		Extrema_ExtPC2d extr( P2[i2], AC1 );
		if (extr.IsDone() && extr.NbExt() > 0)
		  {
		    Standard_Real Dist, DistMin = extr.Value(1);
		    Standard_Integer IndexMin = 1;
		    for (Standard_Integer ind = 2; ind <= extr.NbExt(); ind++)
		      {
			Dist = extr.Value(ind);
			if (Dist < DistMin)
			  {
			    DistMin = Dist;
			    IndexMin = ind;
			  }
		      }
		    if (DistMin <= Precision::Confusion())
		      {
			YaSol = Standard_True;
			P2d = P2[i2];
			U2 = fl2[i2];
			U1 = (extr.Point(IndexMin)).Parameter();
			break;
		      }
		  }
	      }
	}
	
	if (!YaSol) {
	  Geom2dInt_GInter Inter (AC1,AC2,TolConf,TolConf);
	  
	  if (!Inter.IsEmpty() && Inter.NbPoints() > 0) {
	    YaSol = Standard_True;
	    U1  = Inter.Point(1).ParamOnFirst();
	    U2  = Inter.Point(1).ParamOnSecond();
	    P2d = Inter.Point(1).Value();
	  }
	  else if (!Inter.IsEmpty() && Inter.NbSegments() > 0) {
	    YaSol = Standard_True;
	    IntRes2d_IntersectionSegment Seg = Inter.Segment(1);
	    IntRes2d_IntersectionPoint IntP1 = Seg.FirstPoint();
	    IntRes2d_IntersectionPoint IntP2 = Seg.LastPoint();
	    Standard_Real U1on1 = IntP1.ParamOnFirst();
	    Standard_Real U1on2 = IntP2.ParamOnFirst();
	    Standard_Real U2on1 = IntP1.ParamOnSecond();
	    Standard_Real U2on2 = IntP2.ParamOnSecond();
#ifdef DEB
	    cout << " BRepOffset_Tool::Inter2d SEGMENT d intersection" << endl;
	    cout << "     ===> Parametres sur Curve1 : ";
	    cout << U1on1 << " " << U1on2 << endl;
	    cout << "     ===> Parametres sur Curve2 : ";
	    cout << U2on1 << " " << U2on2 << endl;
#endif
	    U1 = (U1on1 + U1on2)/2.;
	    U2 = (U2on1 + U2on2)/2.;
	    gp_Pnt2d P2d1 = C1->Value(U1);
	    gp_Pnt2d P2d2 = C2->Value(U2);
	    P2d.SetX( (P2d1.X() + P2d2.X()) / 2.);
	    P2d.SetY( (P2d1.Y() + P2d2.Y()) / 2.);
	  }
	}
	if (YaSol) {
	  gp_Pnt        P   = S->Value(P2d.X(),P2d.Y());
	  TopoDS_Vertex V = BRepLib_MakeVertex(P);
	  V.Orientation(TopAbs_INTERNAL);
	  TopoDS_Shape aLocalEdge = E1.Oriented(TopAbs_FORWARD);
	  B.UpdateVertex(V,U1,TopoDS::Edge(aLocalEdge),TolConf);
	  aLocalEdge = E2.Oriented(TopAbs_FORWARD);
	  B.UpdateVertex(V,U2,TopoDS::Edge(aLocalEdge),TolConf);
//	  B.UpdateVertex(V,U1,TopoDS::Edge(E1.Oriented(TopAbs_FORWARD)),TolConf);
//	  B.UpdateVertex(V,U2,TopoDS::Edge(E2.Oriented(TopAbs_FORWARD)),TolConf);
	  LV.Append(V);
	}
      }
    }
    itry++;
  }

  if (LV.Extent() > 1) {
    //------------------------------------------------
    // garde seulement les vertex les plus proches du 
    //debut et de la fin. 
    //------------------------------------------------
    TopTools_ListIteratorOfListOfShape it(LV);
    TopoDS_Vertex         VF,VL;
    Standard_Real         UMin =  Precision::Infinite();
    Standard_Real         UMax = -Precision::Infinite();
    Standard_Real         U;

    for ( ; it.More(); it.Next()) {
      TopoDS_Vertex CV = TopoDS::Vertex(it.Value());
      TopoDS_Shape aLocalEdge = E1.Oriented(TopAbs_FORWARD);
      U = BRep_Tool::Parameter(CV,TopoDS::Edge(aLocalEdge));
//      U = BRep_Tool::Parameter(CV,TopoDS::Edge(E1.Oriented(TopAbs_FORWARD)));
      if ( U < UMin) {
	VF = CV; UMin = U;
      }
      if ( U > UMax) {
	VL = CV; UMax = U;
      }
    }
    LV.Clear();LV.Append(VF); LV.Append(VL);
  }

#ifdef DEB
  if (!YaSol) {
    cout <<"Inter2d : Pas de solution"<<endl;
#ifdef DRAW
    DBRep::Set("E1",E1); 
    DBRep::Set("E2",E2);
    DBRep::Set("F",F);
#endif
  }
#endif    
}

//=======================================================================
//function : SelectEdge
//purpose  : 
//=======================================================================

static void SelectEdge (const TopoDS_Face& F,
			const TopoDS_Face& EF,
			const TopoDS_Edge& E,
			TopTools_ListOfShape& LInt)
{
 //------------------------------------------------------------
  // detrompeur sur les intersections sur les faces periodiques
  //------------------------------------------------------------
   TopTools_ListIteratorOfListOfShape it(LInt);
  Standard_Real dU = 1.0e100;
  TopoDS_Edge   GE;

  Standard_Real Fst, Lst, tmp;
  BRep_Tool::Range(E, Fst, Lst);
  BRepAdaptor_Curve  Ad1(E);
 
  gp_Pnt PFirst = Ad1.Value( Fst );  
  gp_Pnt PLast  = Ad1.Value( Lst );  

  //----------------------------------------------------------------------
  // Selection de l edge qui couvre le plus le domaine de l edge initiale.
  //---------------------------------------------------------------------- 
  for (; it.More(); it.Next()) {
    const TopoDS_Edge& EI = TopoDS::Edge(it.Value());

    BRep_Tool::Range(EI, Fst, Lst);
    BRepAdaptor_Curve  Ad2(EI);
    gp_Pnt P1 = Ad2.Value(Fst);
    gp_Pnt P2 = Ad2.Value(Lst);
       
    tmp = P1.Distance(PFirst) + P2.Distance(PLast);
    if( tmp <= dU ) {
      dU = tmp;
      GE = EI;
    } 

  }
  LInt.Clear(); 
  LInt.Append(GE);
}


//=======================================================================
//function : Init
//purpose  : 
//=======================================================================

static void MakeFace(const Handle(Geom_Surface)& S,
		     const Standard_Real Um,
		     const Standard_Real UM,
		     const Standard_Real Vm,
		     const Standard_Real VM,
		     const Standard_Boolean isVminDegen,
		     const Standard_Boolean isVmaxDegen,
		     TopoDS_Face&        F)
{
  Standard_Real UMin = Um;
  Standard_Real UMax = UM;
  Standard_Real VMin = Vm;
  Standard_Real VMax = VM;
  Standard_Real epsilon = Precision::Confusion();

  Standard_Real umin,umax,vmin,vmax;
  S->Bounds(umin,umax,vmin,vmax);


  // compute infinite flags
  Standard_Boolean umininf = Precision::IsNegativeInfinite(UMin);
  Standard_Boolean umaxinf = Precision::IsPositiveInfinite(UMax);
  Standard_Boolean vmininf = Precision::IsNegativeInfinite(VMin);
  Standard_Boolean vmaxinf = Precision::IsPositiveInfinite(VMax);
  
  // closed flag
  Standard_Boolean IsSuclosed = S->IsUClosed(), IsSvclosed = S->IsVClosed();
  if (S->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
    {
      Handle(Geom_Surface) BasisSurf = (*((Handle(Geom_OffsetSurface)*)&S))->BasisSurface();
      IsSuclosed = BasisSurf->IsUClosed();
      IsSvclosed = BasisSurf->IsVClosed();
    }

  Standard_Boolean uclosed = 
    IsSuclosed && 
      Abs(UMin - umin) < epsilon && 
	Abs(UMax - umax) < epsilon;
  
  Standard_Boolean vclosed = 
    IsSvclosed && 
      Abs(VMin - vmin) < epsilon && 
	Abs(VMax - vmax) < epsilon;
  
  // degenerated flags (for cones)
  Standard_Boolean vmindegen = isVminDegen, vmaxdegen = isVmaxDegen;
  Handle(Geom_Surface) theSurf = S;
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
    theSurf = (*(Handle_Geom_RectangularTrimmedSurface*)&S)->BasisSurface();
  if (theSurf->DynamicType() == STANDARD_TYPE(Geom_ConicalSurface))
    {
      Handle(Geom_ConicalSurface) ConicalS = *((Handle(Geom_ConicalSurface)*) &theSurf);
      gp_Cone theCone = ConicalS->Cone();
      gp_Pnt theApex = theCone.Apex();
      Standard_Real Uapex, Vapex;
      ElSLib::Parameters( theCone, theApex, Uapex, Vapex );
      if (Abs(VMin - Vapex) <= Precision::Confusion())
	vmindegen = Standard_True;
      if (Abs(VMax - Vapex) <= Precision::Confusion())
	vmaxdegen = Standard_True;
    }
  
  // compute vertices
  BRep_Builder B;
  Standard_Real tol = Precision::Confusion();
  
  TopoDS_Vertex V00,V10,V11,V01;
  
  if (!umininf) {
    if (!vmininf) B.MakeVertex(V00,S->Value(UMin,VMin),tol);
    if (!vmaxinf) B.MakeVertex(V01,S->Value(UMin,VMax),tol);
  }
  if (!umaxinf) {
    if (!vmininf) B.MakeVertex(V10,S->Value(UMax,VMin),tol);
    if (!vmaxinf) B.MakeVertex(V11,S->Value(UMax,VMax),tol);
  }

  if (uclosed) {
    V10 = V00;
    V11 = V01;
  }

  if (vclosed) {
    V01 = V00;
    V11 = V10;
  }

  if (vmindegen)
    V10 = V00;
  if (vmaxdegen)
    V11 = V01;

  // make the lines
  Handle(Geom2d_Line) Lumin,Lumax,Lvmin,Lvmax;
  if (!umininf)
    Lumin = new Geom2d_Line(gp_Pnt2d(UMin,0),gp_Dir2d(0,1));
  if (!umaxinf)
    Lumax = new Geom2d_Line(gp_Pnt2d(UMax,0),gp_Dir2d(0,1));
  if (!vmininf)
    Lvmin = new Geom2d_Line(gp_Pnt2d(0,VMin),gp_Dir2d(1,0));
  if (!vmaxinf)
    Lvmax = new Geom2d_Line(gp_Pnt2d(0,VMax),gp_Dir2d(1,0));
  
  Handle(Geom_Curve) Cumin,Cumax,Cvmin,Cvmax;
  Standard_Real TolApex = 1.e-5;
  //Standard_Boolean hasiso = ! S->IsKind(STANDARD_TYPE(Geom_OffsetSurface));
  Standard_Boolean hasiso = S->IsKind(STANDARD_TYPE(Geom_ElementarySurface));
  if (hasiso) {
    if (!umininf)
      Cumin = S->UIso(UMin);
    if (!umaxinf)
      Cumax = S->UIso(UMax);
    if (!vmininf)
      {
	Cvmin = S->VIso(VMin);
	if (BRepOffset_Tool::Gabarit( Cvmin ) <= TolApex)
	  vmindegen = Standard_True;
      }
    if (!vmaxinf)
      {
	Cvmax = S->VIso(VMax);
	if (BRepOffset_Tool::Gabarit( Cvmax ) <= TolApex)
	  vmaxdegen = Standard_True;
      }
  }

  // make the face
  B.MakeFace(F,S,tol);

  // make the edges
  TopoDS_Edge eumin,eumax,evmin,evmax;

  if (!umininf) {
    if (hasiso)
      B.MakeEdge(eumin,Cumin,tol);
    else
      B.MakeEdge(eumin);
    if (uclosed) 
      B.UpdateEdge(eumin,Lumax,Lumin,F,tol);
    else
      B.UpdateEdge(eumin,Lumin,F,tol);
    if (!vmininf) {
      V00.Orientation(TopAbs_FORWARD);
      B.Add(eumin,V00);
    }
    if (!vmaxinf) {
      V01.Orientation(TopAbs_REVERSED);
      B.Add(eumin,V01);
    }
    B.Range(eumin,VMin,VMax);
  }

  if (!umaxinf) {
    if (uclosed)
      eumax = eumin;
    else {
      if (hasiso)
	B.MakeEdge(eumax,Cumax,tol);
      else
	B.MakeEdge(eumax);
      B.UpdateEdge(eumax,Lumax,F,tol);
      if (!vmininf) {
	V10.Orientation(TopAbs_FORWARD);
	B.Add(eumax,V10);
      }
      if (!vmaxinf) {
	V11.Orientation(TopAbs_REVERSED);
	B.Add(eumax,V11);
      }
      B.Range(eumax,VMin,VMax);
    }
  }

  if (!vmininf) {
    if (hasiso && !vmindegen)
      B.MakeEdge(evmin,Cvmin,tol);
    else
      B.MakeEdge(evmin);
    if (vclosed)
      B.UpdateEdge(evmin,Lvmin,Lvmax,F,tol);
    else
      B.UpdateEdge(evmin,Lvmin,F,tol);
    if (!umininf) {
      V00.Orientation(TopAbs_FORWARD);
      B.Add(evmin,V00);
    }
    if (!umaxinf) {
      V10.Orientation(TopAbs_REVERSED);
      B.Add(evmin,V10);
    }
    B.Range(evmin,UMin,UMax);
    if (vmindegen)
      B.Degenerated(evmin, Standard_True);
  }

  if (!vmaxinf) {
    if (vclosed)
      evmax = evmin;
    else {
      if (hasiso && !vmaxdegen)
	B.MakeEdge(evmax,Cvmax,tol);
      else
	B.MakeEdge(evmax);
      B.UpdateEdge(evmax,Lvmax,F,tol);
      if (!umininf) {
	V01.Orientation(TopAbs_FORWARD);
	B.Add(evmax,V01);
      }
      if (!umaxinf) {
	V11.Orientation(TopAbs_REVERSED);
	B.Add(evmax,V11);
      }
      B.Range(evmax,UMin,UMax);
      if (vmaxdegen)
	B.Degenerated(evmax, Standard_True);
    }
  }

  // make the wires and add them to the face
  eumin.Orientation(TopAbs_REVERSED);
  evmax.Orientation(TopAbs_REVERSED);
  
  TopoDS_Wire W;

  if (!umininf && !umaxinf && vmininf && vmaxinf) {
    // two wires in u
    B.MakeWire(W);
    B.Add(W,eumin);
    B.Add(F,W);
    B.MakeWire(W);
    B.Add(W,eumax);
    B.Add(F,W);
    F.Closed(uclosed);
  }
    
  else if (umininf && umaxinf && !vmininf && !vmaxinf) {
    // two wires in v
    B.MakeWire(W);
    B.Add(W,evmin);
    B.Add(F,W);
    B.MakeWire(W);
    B.Add(W,evmax);
    B.Add(F,W);
    F.Closed(vclosed);
  }
    
  else if (!umininf || !umaxinf || !vmininf || !vmaxinf) {
    // one wire
    B.MakeWire(W);
    if (!umininf) B.Add(W,eumin);
    if (!vmininf) B.Add(W,evmin);
    if (!umaxinf) B.Add(W,eumax);
    if (!vmaxinf) B.Add(W,evmax);
    B.Add(F,W);
    W.Closed(!umininf && !umaxinf && !vmininf && !vmaxinf);
    F.Closed(uclosed && vclosed);
  }
}

//=======================================================================
//function : EnLargeGeometry
//purpose  : 
//=======================================================================

static Standard_Boolean EnlargeGeometry(Handle(Geom_Surface)& S,
					Standard_Real&        U1,
					Standard_Real&        U2,
					Standard_Real&        V1,
					Standard_Real&        V2,
					Standard_Boolean&     IsV1degen,
					Standard_Boolean&     IsV2degen,
					const Standard_Real   uf1,
					const Standard_Real   uf2,
					const Standard_Real   vf1,
					const Standard_Real   vf2,
					const Standard_Boolean GlobalEnlargeU,
					const Standard_Boolean GlobalEnlargeVfirst,
					const Standard_Boolean GlobalEnlargeVlast)
{
  const Standard_Real coeff = 4.;
  const Standard_Real TolApex = 1.e-5;

  Standard_Boolean SurfaceChange = Standard_False;
  if ( S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
    Handle(Geom_Surface) BS = (*((Handle(Geom_RectangularTrimmedSurface)*)&S))->BasisSurface();
    EnlargeGeometry(BS,U1,U2,V1,V2,IsV1degen,IsV2degen,
		    uf1,uf2,vf1,vf2,GlobalEnlargeU,GlobalEnlargeVfirst,GlobalEnlargeVlast);
    if (!GlobalEnlargeVfirst)
      V1 = vf1;
    if (!GlobalEnlargeVlast)
      V2 = vf2;
    if (!GlobalEnlargeVfirst || !GlobalEnlargeVlast)
      //(*((Handle(Geom_RectangularTrimmedSurface)*)&S))->SetTrim( U1, U2, V1, V2 );
      S = new Geom_RectangularTrimmedSurface( BS, U1, U2, V1, V2 );
    else
      S = BS;
    SurfaceChange = Standard_True;
  }
  else if (S->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface)) {
    Handle(Geom_Surface) Surf = (*((Handle(Geom_OffsetSurface)*)&S))->BasisSurface();
    SurfaceChange = EnlargeGeometry(Surf,U1,U2,V1,V2,IsV1degen,IsV2degen,
				    uf1,uf2,vf1,vf2,GlobalEnlargeU,GlobalEnlargeVfirst,GlobalEnlargeVlast);
    Handle(Geom_OffsetSurface)::DownCast(S)->SetBasisSurface(Surf);
  }
  else if (S->DynamicType() == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion) ||
	   S->DynamicType() == STANDARD_TYPE(Geom_SurfaceOfRevolution))
    {
      Standard_Real du=0., dv=0.;
      Handle( Geom_Curve ) uiso, viso, uiso1, uiso2, viso1, viso2;
      Standard_Real u1, u2, v1, v2;
      Standard_Boolean enlargeU = GlobalEnlargeU, enlargeV = Standard_True;
      Standard_Boolean enlargeUfirst = enlargeU, enlargeUlast = enlargeU;
      Standard_Boolean enlargeVfirst = GlobalEnlargeVfirst, enlargeVlast = GlobalEnlargeVlast;
      S->Bounds( u1, u2, v1, v2 );
      if (Precision::IsInfinite(u1) || Precision::IsInfinite(u2))
	{
	  du = uf2-uf1;
	  u1 = uf1-du;
	  u2 = uf2+du;
	  enlargeU = Standard_False;
	}
      else if (S->IsUClosed())
	enlargeU = Standard_False;
      else
	{
	  viso = S->VIso( vf1 );
	  GeomAdaptor_Curve gac( viso );
	  du = GCPnts_AbscissaPoint::Length( gac ) / coeff;
	  uiso1 = S->UIso( uf1 );
	  uiso2 = S->UIso( uf2 );
	  if (BRepOffset_Tool::Gabarit( uiso1 ) <= TolApex)
	    enlargeUfirst = Standard_False;
	  if (BRepOffset_Tool::Gabarit( uiso2 ) <= TolApex)
	    enlargeUlast = Standard_False;
	}
      if (Precision::IsInfinite(v1) || Precision::IsInfinite(v2))
	{
	  dv = vf2-vf1;
	  v1 = vf1-dv;
	  v2 = vf2+dv;
	  enlargeV = Standard_False;
	}
      else if (S->IsVClosed())
	enlargeV = Standard_False;
      else
	{
	  uiso = S->UIso( uf1 );
	  GeomAdaptor_Curve gac( uiso );
	  dv = GCPnts_AbscissaPoint::Length( gac ) / coeff;
	  viso1 = S->VIso( vf1 );
	  viso2 = S->VIso( vf2 );
	  if (BRepOffset_Tool::Gabarit( viso1 ) <= TolApex)
	    {
	      enlargeVfirst = Standard_False;
	      IsV1degen = Standard_True;
	    }
	  if (BRepOffset_Tool::Gabarit( viso2 ) <= TolApex)
	    {
	      enlargeVlast = Standard_False;
	      IsV2degen = Standard_True;
	    }
	}
      S = new Geom_RectangularTrimmedSurface( S, u1, u2, v1, v2 );
      if (enlargeU)
	{
	  if (enlargeUfirst)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), du, 1, Standard_True, Standard_False );
	  if (enlargeUlast)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), du, 1, Standard_True, Standard_True );
	}
      if (enlargeV)
	{
	  if (enlargeVfirst)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), dv, 1, Standard_False, Standard_False );
	  if (enlargeVlast)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), dv, 1, Standard_False, Standard_True );
	}
      S->Bounds( U1, U2, V1, V2 );
      SurfaceChange = Standard_True;
    }
  else if (S->DynamicType() == STANDARD_TYPE(Geom_BezierSurface) ||
	   S->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface))
    {
      Standard_Boolean enlargeU = GlobalEnlargeU, enlargeV = Standard_True;
      Standard_Boolean enlargeUfirst = enlargeU, enlargeUlast = enlargeU;
      Standard_Boolean enlargeVfirst = GlobalEnlargeVfirst, enlargeVlast = GlobalEnlargeVlast;
      if (S->IsUClosed())
	enlargeU = Standard_False;
      if (S->IsVClosed())
	enlargeV = Standard_False;

      Standard_Real duf = uf2-uf1, dvf = vf2-vf1;
      Standard_Real u1, u2, v1, v2;
      S->Bounds( u1, u2, v1, v2 );

      Standard_Real du=0., dv=0.;
      Handle( Geom_Curve ) uiso, viso, uiso1, uiso2, viso1, viso2;
      GeomAdaptor_Curve gac;
      if (enlargeU)
	{
	  viso = S->VIso( v1 );
	  gac.Load( viso );
	  du = GCPnts_AbscissaPoint::Length( gac ) / coeff;
	  uiso1 = S->UIso( u1 );
	  uiso2 = S->UIso( u2 );
	  if (BRepOffset_Tool::Gabarit( uiso1 ) <= TolApex)
	    enlargeUfirst = Standard_False;
	  if (BRepOffset_Tool::Gabarit( uiso2 ) <= TolApex)
	    enlargeUlast = Standard_False;
	}
      if (enlargeV)
	{
	  uiso = S->UIso( u1 );
	  gac.Load( uiso );
	  dv = GCPnts_AbscissaPoint::Length( gac ) / coeff;
	  viso1 = S->VIso( v1 );
	  viso2 = S->VIso( v2 );
	  if (BRepOffset_Tool::Gabarit( viso1 ) <= TolApex)
	    {
	      enlargeVfirst = Standard_False;
	      IsV1degen = Standard_True;
	    }
	  if (BRepOffset_Tool::Gabarit( viso2 ) <= TolApex)
	    {
	      enlargeVlast = Standard_False;
	      IsV2degen = Standard_True;
	    }
	}

      if (enlargeU)
	{
	  if (enlargeUfirst && uf1-u1 < duf)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), du, 1, Standard_True, Standard_False );
	  if (enlargeUlast && u2-uf2 < duf)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), du, 1, Standard_True, Standard_True );
	}
      if (enlargeV)
	{
	  if (enlargeVfirst && vf1-v1 < dvf)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), dv, 1, Standard_False, Standard_False );
	  if (enlargeVlast && v2-vf2 < dvf)
	    GeomLib::ExtendSurfByLength( *((Handle(Geom_BoundedSurface)*)&S), dv, 1, Standard_False, Standard_True );
	}

      S->Bounds( U1, U2, V1, V2 );
      SurfaceChange = Standard_True;
    }
//  else if (S->DynamicType() == STANDARD_TYPE(Geom_BezierSurface) ||
//	   S->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
//    S->Bounds(U1,U2,V1,V2);
//  }
  else { 
    Standard_Real UU1,UU2,VV1,VV2;
    S->Bounds(UU1,UU2,VV1,VV2);
    // Pas d extension au dela des bornes de la surface.
    U1 = Max(UU1,U1);    
    V1 = Max(VV1,V1);
    U2 = Min(UU2,U2);    
    V2 = Min(VV2,V2);
  }
  return SurfaceChange;
}

//=======================================================================
//function : UpDatePCurve
//purpose  :  Mise a jour des pcurves de F sur la surface de de BF.
//            F and BF has to be FORWARD,
//=======================================================================

static void UpdatePCurves (const TopoDS_Face& F,
			         TopoDS_Face& BF)
{
  Standard_Real   f,l;
  Standard_Integer i;
  BRep_Builder    B;
  TopTools_IndexedMapOfShape Emap;
  Handle(Geom2d_Curve) NullPCurve;

  TopExp::MapShapes( F, TopAbs_EDGE, Emap );
  
  for (i = 1; i <= Emap.Extent(); i++)
    {
      TopoDS_Edge CE = TopoDS::Edge( Emap(i) );
      CE.Orientation( TopAbs_FORWARD );
      Handle(Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface( CE, F, f, l );
      if (!C2.IsNull())
	{
	  if (BRep_Tool::IsClosed( CE, F ))
	    {
	      CE.Reverse();
	      Handle(Geom2d_Curve) C2R = BRep_Tool::CurveOnSurface( CE, F, f, l );
	      B.UpdateEdge( CE, NullPCurve, NullPCurve, F, BRep_Tool::Tolerance(CE) );
	      B.UpdateEdge( CE, C2, C2R, BF, BRep_Tool::Tolerance(CE) );
	    }
	  else
	    {
	      B.UpdateEdge( CE, NullPCurve, F, BRep_Tool::Tolerance(CE) );
	      B.UpdateEdge( CE, C2, BF, BRep_Tool::Tolerance(CE) );
	    }

	  B.Range(CE,f,l);
	}
    }
}

//=======================================================================
//function :CompactUVBounds
//purpose  : 
//=======================================================================

static void CompactUVBounds (const TopoDS_Face& F,
				 Standard_Real& UMin,
				 Standard_Real& UMax,
				 Standard_Real& VMin,
				 Standard_Real& VMax)
{
  // Calcul serre pour que les bornes ne couvrent pas plus d une periode
  Standard_Real U1,U2;
  Standard_Real N = 33;
  Bnd_Box2d B;
  
  TopExp_Explorer exp;	
  for (exp.Init(F, TopAbs_EDGE); exp.More(); exp.Next()) {
    const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
    BRepAdaptor_Curve2d C(E,F);
    BRep_Tool::Range(E,U1,U2);
    gp_Pnt2d P;
    Standard_Real U  = U1;
    Standard_Real DU = (U2-U1)/(N-1);
    for (Standard_Integer j=1;j<N;j++) {
      C.D0(U,P);
      U+=DU;
      B.Add(P);
    }
    C.D0(U2,P);
    B.Add(P);
  }
  B.Get(UMin,VMin,UMax,VMax);
}

//=======================================================================
//function : CheckBounds
//purpose  : 
//=======================================================================

void BRepOffset_Tool::CheckBounds(const TopoDS_Face& F,
				  const BRepOffset_Analyse& Analyse,
				  Standard_Boolean& enlargeU,
				  Standard_Boolean& enlargeVfirst,
				  Standard_Boolean& enlargeVlast)
{
  enlargeU = Standard_True;
  enlargeVfirst = Standard_True; enlargeVlast = Standard_True;

  Standard_Integer Ubound = 0, Vbound = 0;
  Standard_Real Ufirst = RealLast(), Ulast = RealFirst();
  Standard_Real Vfirst = RealLast(), Vlast = RealFirst();

  Standard_Real UF1,UF2,VF1,VF2;
  CompactUVBounds(F,UF1,UF2,VF1,VF2);

  Handle(Geom_Surface) theSurf = BRep_Tool::Surface(F);
  if (theSurf->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
    theSurf = (*((Handle(Geom_RectangularTrimmedSurface)*)&theSurf))->BasisSurface();

  if (theSurf->DynamicType() == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion) ||
      theSurf->DynamicType() == STANDARD_TYPE(Geom_SurfaceOfRevolution) ||
      theSurf->DynamicType() == STANDARD_TYPE(Geom_BezierSurface) ||
      theSurf->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface))
    {
      TopExp_Explorer Explo(F, TopAbs_EDGE);
      for (; Explo.More(); Explo.Next())
	{
	  const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current());
	  const BRepOffset_ListOfInterval& L = Analyse.Type(anEdge);
	  if (!L.IsEmpty() || BRep_Tool::Degenerated(anEdge))
	    {
	      BRepOffset_Type OT = L.First().Type();
	      if (OT == BRepOffset_Tangent || BRep_Tool::Degenerated(anEdge))
		{
		  Standard_Real fpar, lpar;
		  Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, F, fpar, lpar);
		  if (aCurve->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
		    aCurve = (*((Handle(Geom2d_TrimmedCurve)*)&aCurve))->BasisCurve();
		  
		  Handle(Geom2d_Line) theLine;
		  if (aCurve->DynamicType() == STANDARD_TYPE(Geom2d_Line))
		    theLine = *((Handle(Geom2d_Line)*)&aCurve);
		  else if (aCurve->DynamicType() == STANDARD_TYPE(Geom2d_BezierCurve) ||
			   aCurve->DynamicType() == STANDARD_TYPE(Geom2d_BSplineCurve))
		    {
		      Standard_Real newFpar, newLpar, deviation;
		      theLine = ShapeCustom_Curve2d::ConvertToLine2d(aCurve, fpar, lpar, Precision::Confusion(),
								     newFpar, newLpar, deviation);
		    }

		  if (!theLine.IsNull())
		    {
		      gp_Dir2d theDir = theLine->Direction();
		      if (theDir.IsParallel( gp::DX2d(), Precision::Angular() ))
			{
			  Vbound++;
			  if (BRep_Tool::Degenerated(anEdge))
			    {
			      if (Abs(theLine->Location().Y() - VF1) <= Precision::Confusion())
				enlargeVfirst = Standard_False;
			      else //theLine->Location().Y() is near VF2
				enlargeVlast  = Standard_False;
			    }
			  else
			    {
			      if (theLine->Location().Y() < Vfirst)
				Vfirst = theLine->Location().Y();
			      if (theLine->Location().Y() > Vlast)
				Vlast  = theLine->Location().Y();
			    }
			}
		      else if (theDir.IsParallel( gp::DY2d(), Precision::Angular() ))
			{
			  Ubound++;
			  if (theLine->Location().X() < Ufirst)
			    Ufirst = theLine->Location().X();
			  if (theLine->Location().X() > Ulast)
			    Ulast  = theLine->Location().X();
			}
		    }
		}
	    }
	}
    }

  if (Ubound >= 2 || Vbound >= 2)
    {
      if (Ubound >= 2 &&
	  Abs(UF1-Ufirst) <= Precision::Confusion() &&
	  Abs(UF2-Ulast)  <= Precision::Confusion())
	enlargeU = Standard_False;
      if (Vbound >= 2 &&
	  Abs(VF1-Vfirst) <= Precision::Confusion() &&
	  Abs(VF2-Vlast)  <= Precision::Confusion())
	{
	  enlargeVfirst = Standard_False;
	  enlargeVlast  = Standard_False;
	}
    }
}

//=======================================================================
//function : EnLargeFace
//purpose  : 
//=======================================================================

Standard_Boolean BRepOffset_Tool::EnLargeFace 
(const TopoDS_Face&       F,
 TopoDS_Face&             BF,
 const Standard_Boolean   CanExtentSurface,
 const Standard_Boolean   UpdatePCurve,
 const Standard_Boolean   enlargeU,
 const Standard_Boolean   enlargeVfirst,
 const Standard_Boolean   enlargeVlast)
{
  //---------------------------
  // extension de la geometrie.
  //---------------------------
  TopLoc_Location       L;
  Handle (Geom_Surface) S = BRep_Tool::Surface(F,L);
  Standard_Real         UU1,VV1,UU2,VV2;
  Standard_Boolean      isVV1degen = Standard_False, isVV2degen = Standard_False;
  Standard_Real         US1,VS1,US2,VS2;
  Standard_Real         UF1,VF1,UF2,VF2;
  Standard_Real         infini = 1.e8;
  Standard_Boolean      SurfaceChange = Standard_False;

  if (S->IsUPeriodic() || S->IsVPeriodic()) {
    // Calcul serre pour que les bornes ne couvre pas plus d une periode
    CompactUVBounds(F,UF1,UF2,VF1,VF2);					       
  }
  else {
    BRepTools::UVBounds(F,UF1,UF2,VF1,VF2);
  }

  S->Bounds            (US1,US2,VS1,VS2);
  UU1 = VV1 = - infini;
  UU2 = VV2 =   infini;
  
  if (CanExtentSurface) {
    SurfaceChange = EnlargeGeometry( S, UU1, UU2, VV1, VV2, isVV1degen, isVV2degen, UF1, UF2, VF1, VF2,
				     enlargeU, enlargeVfirst, enlargeVlast );
  }
  else {
    UU1 = Max(US1,UU1); UU2 = Min(UU2,US2); 
    VV1 = Max(VS1,VV1); VV2 = Min(VS2,VV2);
  }

  if (S->IsUPeriodic()) {
    Standard_Real    Period = S->UPeriod(); 
    Standard_Real    Delta  = Period - (UF2 - UF1);
    Standard_Real    alpha  = 0.1;
    UU1 = UF1 - alpha*Delta; UU2 = UF2 + alpha*Delta;
    if ((UU2 - UU1) > Period) {
      UU2 = UU1 + Period;
    }
  }
  if (S->IsVPeriodic()) {
    Standard_Real    Period = S->VPeriod(); 
    Standard_Real    Delta  = Period - (VF2 - VF1);
    Standard_Real    alpha  = 0.1;
    VV1 = VF1 - alpha*Delta; VV2 = VF2 + alpha*Delta;
    if ((VV2 - VV1) > Period) {
      VV2 = VV1 + Period;
    }
  }

  //Special treatment for conical surfaces
  Handle(Geom_Surface) theSurf = S;
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
    theSurf = (*(Handle_Geom_RectangularTrimmedSurface*)&S)->BasisSurface();
  if (theSurf->DynamicType() == STANDARD_TYPE(Geom_ConicalSurface))
    {
      Handle(Geom_ConicalSurface) ConicalS = *((Handle(Geom_ConicalSurface)*) &theSurf);
      gp_Cone theCone = ConicalS->Cone();
      gp_Pnt theApex = theCone.Apex();
      Standard_Real Uapex, Vapex;
      ElSLib::Parameters( theCone, theApex, Uapex, Vapex );
      if (VV1 < Vapex && Vapex < VV2)
	{
	  //consider that VF1 and VF2 are on the same side from apex
	  Standard_Real TolApex = 1.e-5;
	  if (Vapex - VF1 >= TolApex ||
	      Vapex - VF2 >= TolApex)   //if (VF1 < Vapex || VF2 < Vapex)
	    VV2 = Vapex;
	  else
	    VV1 = Vapex;
	}
    }

  if (!enlargeU)
    {
      UU1 = UF1; UU2 = UF2;
    }
  if (!enlargeVfirst)
    VV1 = VF1;
  if (!enlargeVlast)
    VV2 = VF2;

  MakeFace(S,UU1,UU2,VV1,VV2,isVV1degen,isVV2degen,BF);
  BF.Location(L);
/*
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
    BRep_Builder B;
    //----------------------------------------------------------------
    // utile pour les bouchons on ne doit pas changer leur geometrie.
    // (Ce que fait BRepLib_MakeFace si S est restreinte).
    // On remet S et on update les pcurves.
    //----------------------------------------------------------------
    TopExp_Explorer exp;
    exp.Init(BF,TopAbs_EDGE);
    Standard_Real f=0.,l=0.;
    for (; exp.More(); exp.Next()) {
      TopoDS_Edge   CE  = TopoDS::Edge(exp.Current());
      Handle(Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(CE,BF,f,l); 
      B.UpdateEdge (CE,C2,S,L,BRep_Tool::Tolerance(CE));
    }    
    B.UpdateFace(BF,S,L,BRep_Tool::Tolerance(F)); 
  }
*/  
  if (SurfaceChange && UpdatePCurve) {
    TopoDS_Shape aLocalFace = F.Oriented(TopAbs_FORWARD);
    UpdatePCurves(TopoDS::Face(aLocalFace),BF);
    //UpdatePCurves(TopoDS::Face(F.Oriented(TopAbs_FORWARD)),BF);
    BRep_Builder BB;
    BB.UpdateFace( F, S, L, BRep_Tool::Tolerance(F) );
  }

  BF.Orientation(F.Orientation());
  return SurfaceChange;
}

//=======================================================================
//function : TryParameter
//purpose  : 
//=======================================================================

static Standard_Boolean TryParameter (const TopoDS_Edge& OE,
				      TopoDS_Vertex&     V,
				      const TopoDS_Edge& NE,
				      Standard_Real      TolConf)
{
  BRepAdaptor_Curve OC(OE);
  BRepAdaptor_Curve NC(NE);
  Standard_Real Of = OC.FirstParameter(); Standard_Real Ol = OC.LastParameter();
  Standard_Real Nf = NC.FirstParameter(); Standard_Real Nl = NC.LastParameter();
#ifndef DEB
  Standard_Real U = 0.;
#else
  Standard_Real U;
#endif
  gp_Pnt           P  = BRep_Tool::Pnt(V);
  Standard_Boolean OK = Standard_False;

  if (P.Distance(OC.Value(Of)) < TolConf) {
    if (Of > Nf && Of < Nl  && P.Distance(NC.Value(Of)) < TolConf) {
      OK = Standard_True;
      U    = Of;
    }
  }
  if (P.Distance(OC.Value(Ol)) < TolConf) {
    if (Ol > Nf && Ol < Nl  && P.Distance(NC.Value(Ol)) < TolConf) {
      OK = Standard_True;
      U    = Ol;
    }
  }
  if (OK) {
    BRep_Builder B;
    TopoDS_Shape aLocalShape = NE.Oriented(TopAbs_FORWARD);
    TopoDS_Edge EE = TopoDS::Edge(aLocalShape);
//    TopoDS_Edge EE = TopoDS::Edge(NE.Oriented(TopAbs_FORWARD));
    aLocalShape = V.Oriented(TopAbs_INTERNAL);
    B.UpdateVertex(TopoDS::Vertex(aLocalShape),
		   U,NE,BRep_Tool::Tolerance(NE));
//    B.UpdateVertex(TopoDS::Vertex(V.Oriented(TopAbs_INTERNAL)),
//		   U,NE,BRep_Tool::Tolerance(NE));
  }
  return OK;  
}

//=======================================================================
//function : 
//purpose  : 
//=======================================================================

void BRepOffset_Tool::MapVertexEdges (const TopoDS_Shape& S,
				      TopTools_DataMapOfShapeListOfShape& MEV)
{
  TopExp_Explorer      exp;
  exp.Init(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE);
  TopTools_MapOfShape  DejaVu;
  for ( ; exp.More(); exp.Next()) {
    const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
    if (DejaVu.Add(E)) {
      TopoDS_Vertex     V1,V2;
      TopExp::Vertices (E,V1,V2);
      if (!MEV.IsBound(V1)) {
	TopTools_ListOfShape empty;
	MEV.Bind(V1,empty);
      }
      MEV(V1).Append(E);
      if (!V1.IsSame(V2)) {
	if (!MEV.IsBound(V2)) {
	  TopTools_ListOfShape empty;
	  MEV.Bind(V2,empty);
	}
	MEV(V2).Append(E);
      }
    }
  }
}

//=======================================================================
//function : 
//purpose  : 
//=======================================================================

void BRepOffset_Tool::BuildNeighbour (const TopoDS_Wire& W,
				      const TopoDS_Face& F,
				      TopTools_DataMapOfShapeShape& NOnV1,
				      TopTools_DataMapOfShapeShape& NOnV2)
{
  TopoDS_Vertex V1,V2,VP1,VP2,FV1,FV2;
  TopoDS_Edge   CurE,FirstE,PrecE;
  BRepTools_WireExplorer         wexp;
  
  TopoDS_Shape aLocalFace = F.Oriented(TopAbs_FORWARD);
  TopoDS_Shape aLocalWire = W.Oriented(TopAbs_FORWARD);
  wexp.Init(TopoDS::Wire(aLocalWire),TopoDS::Face(aLocalFace));
//  wexp.Init(TopoDS::Wire(W.Oriented(TopAbs_FORWARD)),
//	    TopoDS::Face(F.Oriented(TopAbs_FORWARD)));
  CurE = FirstE = PrecE = wexp.Current();
  TopExp::Vertices(CurE,V1,V2);
  FV1 = VP1 = V1; FV2 = VP2 = V2;
  wexp.Next();
  while (wexp.More()) {
    CurE = wexp.Current();
    TopExp::Vertices(CurE,V1,V2);
    if (V1.IsSame(VP1)) { NOnV1.Bind(PrecE,CurE); NOnV1.Bind(CurE,PrecE);}
    if (V1.IsSame(VP2)) { NOnV2.Bind(PrecE,CurE); NOnV1.Bind(CurE,PrecE);}
    if (V2.IsSame(VP1)) { NOnV1.Bind(PrecE,CurE); NOnV2.Bind(CurE,PrecE);}
    if (V2.IsSame(VP2)) { NOnV2.Bind(PrecE,CurE); NOnV2.Bind(CurE,PrecE);}
    PrecE = CurE;
    VP1 = V1; VP2 = V2;
    wexp.Next();
  }
  if (V1.IsSame(FV1)) { NOnV1.Bind(FirstE,CurE); NOnV1.Bind(CurE,FirstE);}
  if (V1.IsSame(FV2)) { NOnV2.Bind(FirstE,CurE); NOnV1.Bind(CurE,FirstE);}
  if (V2.IsSame(FV1)) { NOnV1.Bind(FirstE,CurE); NOnV2.Bind(CurE,FirstE);}
  if (V2.IsSame(FV2)) { NOnV2.Bind(FirstE,CurE); NOnV2.Bind(CurE,FirstE);}
}

//=======================================================================
//function : ExtentFace
//purpose  : 
//=======================================================================

void BRepOffset_Tool::ExtentFace (const TopoDS_Face&            F,
				  TopTools_DataMapOfShapeShape& ConstShapes,
				  TopTools_DataMapOfShapeShape& ToBuild,
				  const TopAbs_State            Side,
				  const Standard_Real           TolConf,
				  TopoDS_Face&                  NF)
{
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FTE_%d",NbFTE++);
    DBRep::Set(name,F);
  }
#endif
  
  TopExp_Explorer                    exp,exp2;
  TopTools_DataMapOfShapeShape       Build;
  TopTools_DataMapOfShapeShape       Extent;
  TopoDS_Edge                        FirstE,PrecE,CurE,NE;
  BRep_Builder B;
  TopoDS_Face  EF;

  // Construction de la boite englobante de la face a etendre et des bouchons pour
  // limiter les extensions.
  //Bnd_Box ContextBox;
  //BRepBndLib::Add(F,B);
  //TopTools_DataMapIteratorOfDataMapOfShape itTB(ToBuild);
  //for (; itTB.More(); itTB.Next()) {
  //BRepBndLib::Add(TopBuild.Value(), ContextBox);
  //}

   
  Standard_Boolean SurfaceChange;
  SurfaceChange = EnLargeFace (F,EF,Standard_True);

  TopoDS_Shape aLocalShape = EF.EmptyCopied();
  NF = TopoDS::Face(aLocalShape);
//  NF = TopoDS::Face(EF.EmptyCopied());
  NF.Orientation(TopAbs_FORWARD);

  if (SurfaceChange) {
    //------------------------------------------------
    // Mise a jour des pcurves sur la surface de base.
    //------------------------------------------------
    TopoDS_Face Fforward = F;
    Fforward.Orientation(TopAbs_FORWARD);
    TopTools_IndexedMapOfShape Emap;
    TopExp::MapShapes( Fforward, TopAbs_EDGE, Emap );
    Standard_Real f,l;
    for (Standard_Integer i = 1; i <= Emap.Extent(); i++) {
      TopoDS_Edge   CE  = TopoDS::Edge( Emap(i) );
      CE.Orientation(TopAbs_FORWARD);
      TopoDS_Edge   Ecs; //patch
      Handle(Geom2d_Curve) C2 = BRep_Tool::CurveOnSurface(CE,Fforward,f,l);
      if (!C2.IsNull()) {
	if (ConstShapes.IsBound(CE)) {
	  Ecs = TopoDS::Edge(ConstShapes(CE));
	  BRep_Tool::Range(Ecs,f,l);
	}
	if (BRep_Tool::IsClosed(CE,Fforward))  {
	  TopoDS_Shape aLocalShape = CE.Reversed();
	  Handle(Geom2d_Curve) C2R = 
	    BRep_Tool::CurveOnSurface(TopoDS::Edge(aLocalShape),Fforward,f,l);
//	  Handle(Geom2d_Curve) C2R = 
//	    BRep_Tool::CurveOnSurface(TopoDS::Edge(CE.Reversed()),F,f,l);
	  B.UpdateEdge (CE,C2,C2R,EF,BRep_Tool::Tolerance(CE));
	  if (! Ecs.IsNull())
	    B.UpdateEdge (Ecs,C2,C2R,EF,BRep_Tool::Tolerance(CE));
	}
	else {
	  B.UpdateEdge (CE,C2,EF,BRep_Tool::Tolerance(CE));
	  if (! Ecs.IsNull())
	    B.UpdateEdge (Ecs,C2,EF,BRep_Tool::Tolerance(CE));
	}
	B.Range(CE,f,l);
	if (! Ecs.IsNull())
	  B.Range(Ecs,f,l);
      }
    }
  }
  
  for (exp.Init(F.Oriented(TopAbs_FORWARD),TopAbs_WIRE); 
       exp.More();
       exp.Next()) {
    const TopoDS_Wire& W = TopoDS::Wire(exp.Current());
    TopTools_DataMapOfShapeListOfShape MVE; // Vertex -> Edges incidentes.
    TopTools_DataMapOfShapeShape       NOnV1;
    TopTools_DataMapOfShapeShape       NOnV2;

    MapVertexEdges (W,MVE);
    BuildNeighbour (W,F,NOnV1,NOnV2);
    
    TopTools_ListOfShape LInt1,LInt2;
    TopoDS_Face          StopFace;
    //------------------------------------------------
    // Construction edges
    //------------------------------------------------
    for (exp2.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp2.More(); exp2.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp2.Current());
      if (ConstShapes.IsBound(E)) ToBuild.UnBind(E);
      if (ToBuild.IsBound(E)) {
	TopTools_ListOfShape LOE;
	LOE.Append(E);
	BRepOffset_Tool::TryProject (TopoDS::Face(ToBuild(E)),
				     EF,LOE,LInt2,LInt1,Side,TolConf);
	if (!LInt1.IsEmpty()) 
	  ToBuild.UnBind(E);
      }
    }

    for (exp2.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp2.More(); exp2.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp2.Current());
      if (ConstShapes.IsBound(E)) ToBuild.UnBind(E);
      if (ToBuild.IsBound(E)) {
	EnLargeFace(TopoDS::Face(ToBuild(E)),StopFace,Standard_False);
	BRepOffset_Tool::Inter3D (EF,StopFace,LInt1,LInt2,Side,E,Standard_True);
	if (LInt1.Extent() > 1) { 
	  // l intersection est en plusieurs edges (franchissement de couture)
	  SelectEdge (F,EF,E,LInt1);
	}
	NE = TopoDS::Edge(LInt1.First());
	Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*) &NE.TShape());
	TE->Tolerance( TE->Tolerance()*10. ); //????
	if (NE.Orientation() == E.Orientation()) {
	  Build.Bind(E,NE.Oriented(TopAbs_FORWARD));
	}
	else {
	  Build.Bind(E,NE.Oriented(TopAbs_REVERSED));
	}
	const TopoDS_Edge& EOnV1 = TopoDS::Edge(NOnV1(E));
	if (!ToBuild    .IsBound(EOnV1) && 
	    !ConstShapes.IsBound(EOnV1) && 
	    !Build      .IsBound(EOnV1)) {
	  ExtentEdge (F,EF,EOnV1,NE);
	  Build.Bind (EOnV1,NE.Oriented(TopAbs_FORWARD));
	}
	const TopoDS_Edge& EOnV2 = TopoDS::Edge(NOnV2(E));
	if (!ToBuild    .IsBound(EOnV2) && 
	    !ConstShapes.IsBound(EOnV2) && 
	    !Build      .IsBound(EOnV2)) {
	  ExtentEdge (F,EF,EOnV2,NE);
	  Build.Bind (EOnV2,NE.Oriented (TopAbs_FORWARD));
	}
      }
    }

    //------------------------------------------------
    // Construction Vertex.
    //------------------------------------------------
    TopTools_ListOfShape LV;
    Standard_Real        f,l;
    TopoDS_Edge          ERef;
    TopoDS_Vertex        V1,V2;

    for (exp2.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp2.More(); exp2.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp2.Current());
      TopExp::Vertices (E,V1,V2);
      BRep_Tool::Range (E,f,l);
      TopoDS_Vertex V;
      if (Build.IsBound(E)) {
	const TopoDS_Edge& NEOnV1 = TopoDS::Edge(NOnV1(E));
	if (Build.IsBound(NEOnV1) && 
	    (ToBuild.IsBound(E) || ToBuild.IsBound(NEOnV1))) {
	  if (E.IsSame(NEOnV1)) 
	    V = TopExp::FirstVertex(TopoDS::Edge(Build(E)));
	  else {
	    //---------------
	    // intersection.
	    //---------------
	    if (!Build.IsBound(V1)) {
	      Inter2d (EF,TopoDS::Edge(Build(E)),
		       TopoDS::Edge(Build(NEOnV1)),LV,/*TolConf*/Precision::Confusion());
	      if (Build(E).Orientation() == TopAbs_FORWARD) {
		V = TopoDS::Vertex(LV.First());
	      }
	      else {
		V = TopoDS::Vertex(LV.Last());
	      }
	    }
	    else {
	      V = TopoDS::Vertex(Build(V1));
	      if (MVE (V1).Extent() > 2) {
		V.Orientation(TopAbs_FORWARD);
		if (Build(E).Orientation() == TopAbs_REVERSED)
		  V.Orientation(TopAbs_REVERSED);
		ProjectVertexOnEdge(V,TopoDS::Edge(Build(E)),TolConf);
	      }
	    }
	  }
	}
	else {
	  //------------
	  //projection
	  //------------
	  V = V1;
	  if (ConstShapes.IsBound(V1)) V = TopoDS::Vertex(ConstShapes(V1));
	  V.Orientation(TopAbs_FORWARD);
	  if (Build(E).Orientation() == TopAbs_REVERSED)
	    V.Orientation(TopAbs_REVERSED);
	  if (!TryParameter    (E,V,TopoDS::Edge(Build(E)),TolConf))
	    ProjectVertexOnEdge(V,TopoDS::Edge(Build(E)),TolConf);
	}
	ConstShapes.Bind(V1,V);
	Build.Bind      (V1,V);
	const TopoDS_Edge& NEOnV2 = TopoDS::Edge(NOnV2(E));
	if (Build.IsBound(NEOnV2) && 
	    (ToBuild.IsBound(E) || ToBuild.IsBound(NEOnV2))) {
	  if (E.IsSame(NEOnV2)) 
	    V = TopExp::LastVertex(TopoDS::Edge(Build(E)));
	  else {
	    //--------------
	    // intersection.
	    //---------------
	    if (!Build.IsBound(V2)) {
	      Inter2d (EF,TopoDS::Edge(Build(E)),
		       TopoDS::Edge(Build(NEOnV2)),LV,/*TolConf*/Precision::Confusion());
	      if (Build(E).Orientation() == TopAbs_FORWARD) {
		V = TopoDS::Vertex(LV.Last());
	      }
	      else {
		V = TopoDS::Vertex(LV.First());
	      }
	    }
	    else {
	      V = TopoDS::Vertex(Build(V2));
	      if (MVE (V2).Extent() > 2) {
		V.Orientation(TopAbs_REVERSED);
		if (Build(E).Orientation() == TopAbs_REVERSED)
		  V.Orientation(TopAbs_FORWARD);
		ProjectVertexOnEdge(V,TopoDS::Edge(Build(E)),TolConf);
	      }
	    }
	  }
	}
	else {
	  //------------
	  //projection
	  //------------
	  V = V2;
	  if (ConstShapes.IsBound(V2))  V = TopoDS::Vertex(ConstShapes(V2));
	  V.Orientation(TopAbs_REVERSED);	
	  if (Build(E).Orientation() == TopAbs_REVERSED)
	    V.Orientation(TopAbs_FORWARD);
	  if (!TryParameter (E,V,TopoDS::Edge(Build(E)),TolConf))
	    ProjectVertexOnEdge(V,TopoDS::Edge(Build(E)),TolConf);
	}
	ConstShapes.Bind(V2,V);
	Build.Bind(V2,V);
      }
    }
    
    TopoDS_Wire        NW;
    TopoDS_Vertex      NV1,NV2;
    TopAbs_Orientation Or;
    Standard_Real      U1,U2;
    Standard_Real      eps = Precision::Confusion();

#ifdef DEB
    TopLoc_Location    L;
#endif
    B.MakeWire(NW);

    //-----------------
    // Reconstruction.
    //-----------------
    for (exp2.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp2.More(); exp2.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp2.Current());
      TopExp::Vertices (E,V1,V2);
      if (Build.IsBound(E)) {
	NE = TopoDS::Edge(Build(E));
	BRep_Tool::Range(NE,f,l);
	Or = NE.Orientation();
	//-----------------------------------------------------
	// Copy pour virer les vertex deja sur la nouvelle edge.
	//-----------------------------------------------------
	NV1 = TopoDS::Vertex(ConstShapes(V1));
	NV2 = TopoDS::Vertex(ConstShapes(V2));

	TopoDS_Shape aLocalVertex = NV1.Oriented(TopAbs_INTERNAL);
	TopoDS_Shape aLocalEdge   = NE.Oriented(TopAbs_INTERNAL);
	
	U1 = BRep_Tool::Parameter(TopoDS::Vertex(aLocalVertex),
				  TopoDS::Edge  (aLocalEdge));
	aLocalVertex = NV2.Oriented(TopAbs_INTERNAL);	
	aLocalEdge   = NE.Oriented(TopAbs_FORWARD);
	U2 = BRep_Tool::Parameter
	  (TopoDS::Vertex(aLocalVertex),TopoDS::Edge  (aLocalEdge));
//	U1 = BRep_Tool::Parameter
//	  (TopoDS::Vertex(NV1.Oriented(TopAbs_INTERNAL)),
//	   TopoDS::Edge  (NE .Oriented(TopAbs_FORWARD)));
//	U2 = BRep_Tool::Parameter
//	  (TopoDS::Vertex(NV2.Oriented(TopAbs_INTERNAL)),
//	   TopoDS::Edge  (NE.Oriented(TopAbs_FORWARD)));
	aLocalEdge = NE.EmptyCopied();
	NE = TopoDS::Edge(aLocalEdge);
	NE.Orientation(TopAbs_FORWARD);
	if (NV1.IsSame(NV2))
	  {
	    //--------------
	    // edge ferme.
	    //--------------
	    if (Or == TopAbs_FORWARD) {U1 = f; U2 = l;}
	    else                      {U1 = l; U2 = f;}
	    if (Or == TopAbs_FORWARD)
	      {
		if (U1 > U2)
		  {
		    if (Abs(U1-l) < eps) U1 = f;
		    if (Abs(U2-f) < eps) U2 = l;	    
		  }
		TopoDS_Shape aLocalVertex = NV1.Oriented(TopAbs_FORWARD );
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
		aLocalVertex = NV2.Oriented(TopAbs_REVERSED);
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_FORWARD )));
//		B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_REVERSED)));
		B.Range(NE,U1,U2);
		ConstShapes.Bind(E,NE);
		NE.Orientation(E.Orientation());
	      }
	    else
	      {
		if (U2 > U1)
		  {
		    if (Abs(U2-l) < eps) U2 = f;
		    if (Abs(U1-f) < eps) U1 = l;	    
		  }
		TopoDS_Shape aLocalVertex = NV2.Oriented(TopAbs_FORWARD );
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
		aLocalVertex = NV1.Oriented(TopAbs_REVERSED);
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_FORWARD )));
//		B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_REVERSED)));
		B.Range(NE,U2,U1);
		ConstShapes.Bind(E,NE.Oriented(TopAbs_REVERSED));
		NE.Orientation(TopAbs::Reverse(E.Orientation()));
	      }
	  }
	else
	  {
	    //-------------------
	    // edge is not ferme.
	    //-------------------
	    if (Or == TopAbs_FORWARD) {
	      if (U1 > U2) {
		TopoDS_Shape aLocalVertex = NV2.Oriented(TopAbs_FORWARD );
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
		aLocalVertex = NV1.Oriented(TopAbs_REVERSED);
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_FORWARD )));
//		B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_REVERSED)));
		B.Range(NE,U2,U1);
	      }
	      else
		{
		  TopoDS_Shape aLocalVertex = NV1.Oriented(TopAbs_FORWARD );
		  B.Add (NE,TopoDS::Vertex(aLocalVertex));
		  aLocalVertex = NV2.Oriented(TopAbs_REVERSED);
		  B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		  B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_FORWARD )));
//		  B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_REVERSED)));
		  B.Range(NE,U1,U2);
		}
	      ConstShapes.Bind(E,NE);
	      NE.Orientation(E.Orientation());
	    }
	    else {
	      if (U2 > U1) {
		TopoDS_Shape aLocalVertex = NV1.Oriented(TopAbs_FORWARD );
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
		aLocalVertex = NV2.Oriented(TopAbs_REVERSED);
		B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_FORWARD )));
//		B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_REVERSED)));
		B.Range(NE,U1,U2);
		ConstShapes.Bind(E,NE);
		NE.Orientation(E.Orientation());
	      }
	      else
		{
		  TopoDS_Shape aLocalVertex = NV2.Oriented(TopAbs_FORWARD );
		  B.Add (NE,TopoDS::Vertex(aLocalVertex));
		  aLocalVertex = NV1.Oriented(TopAbs_REVERSED);
		  B.Add (NE,TopoDS::Vertex(aLocalVertex));
//		  B.Add (NE,TopoDS::Vertex(NV2.Oriented(TopAbs_FORWARD )));
//		  B.Add (NE,TopoDS::Vertex(NV1.Oriented(TopAbs_REVERSED)));
		  B.Range(NE,U2,U1);
		  ConstShapes.Bind(E,NE.Oriented(TopAbs_REVERSED));
		  NE.Orientation(TopAbs::Reverse(E.Orientation()));
		}
	    }
	  }
	Build.UnBind(E);
      } // Build.IsBound(E)
      else if (ConstShapes.IsBound(E)) { // !Build.IsBound(E)
	NE = TopoDS::Edge(ConstShapes(E));	
	BuildPCurves(NE,NF);
	Or = NE.Orientation();
	if (Or == TopAbs_REVERSED) {
	  NE.Orientation(TopAbs::Reverse(E.Orientation()));
	}
	else {
	  NE.Orientation(E.Orientation());
	}
      }
      else {
	NE = E;
	ConstShapes.Bind(E,NE.Oriented(TopAbs_FORWARD));
      }
      B.Add(NW,NE);
    }
    B.Add(NF,NW.Oriented(W.Orientation()));
  }
  NF.Orientation(F.Orientation());
  BRepTools::Update(NF); // Maj des UVPoints
  
#ifdef DRAW
  if (AffichInter) {
    // POP pour NT
    char* name = new char[100];
    sprintf(name,"FOB_%d",NbFOB++);
    DBRep::Set(name,NF);
  }
#endif
}
  

//=======================================================================
//function : Deboucle3D
//purpose  : 
//=======================================================================

TopoDS_Shape BRepOffset_Tool::Deboucle3D(const TopoDS_Shape& S,
					 const TopTools_MapOfShape& Boundary)
{
  return BRepAlgo_Tool::Deboucle3D(S,Boundary);
}

//=======================================================================
//function : IsInOut
//purpose  : 
//=======================================================================

static Standard_Boolean IsInOut (BRepTopAdaptor_FClass2d& FC,
				 Geom2dAdaptor_Curve      AC,
				 const TopAbs_State&      S )
{
 Standard_Real Def = 100*Precision::Confusion();
 GCPnts_QuasiUniformDeflection QU(AC,Def);
 
 for (Standard_Integer i = 1; i <= QU.NbPoints(); i++) {
   gp_Pnt2d P = AC.Value(QU.Parameter(i));
   if (FC.Perform(P) != S) {
     return Standard_False;
     break;
   } 
 }
 return Standard_True;
}
				  
//=======================================================================
//function : CorrectOrientation
//purpose  : 
//=======================================================================

void BRepOffset_Tool::CorrectOrientation(const TopoDS_Shape&        SI,
					 const TopTools_MapOfShape& NewEdges,
					 Handle(BRepAlgo_AsDes)&    AsDes,
					 BRepAlgo_Image&            InitOffset,
					 const Standard_Real        Offset)
{

  TopExp_Explorer exp;
  exp.Init(SI,TopAbs_FACE);
  Standard_Real   f=0.,l=0.;

  for (; exp.More(); exp.Next()) {

    const TopoDS_Face&          FI  = TopoDS::Face(exp.Current());
    const TopTools_ListOfShape& LOF = InitOffset.Image(FI);
    TopTools_ListIteratorOfListOfShape it(LOF);
    for (; it.More(); it.Next()) {
      const TopoDS_Face&    OF   = TopoDS::Face(it.Value());
      TopTools_ListOfShape& LOE = AsDes->ChangeDescendant(OF);
      TopTools_ListIteratorOfListOfShape itE(LOE);

      Standard_Boolean YaInt = Standard_False;
      for (; itE.More(); itE.Next()) {
	const TopoDS_Edge& OE = TopoDS::Edge(itE.Value());
	if (NewEdges.Contains(OE)) {YaInt = Standard_True; break;}
      }
      if (YaInt) {
	TopoDS_Shape aLocalFace = FI.Oriented(TopAbs_FORWARD);
	BRepTopAdaptor_FClass2d FC (TopoDS::Face(aLocalFace),
				    Precision::Confusion());
//	BRepTopAdaptor_FClass2d FC (TopoDS::Face(FI.Oriented(TopAbs_FORWARD)),
//				    Precision::Confusion());
	for (itE.Initialize(LOE); itE.More(); itE.Next()) {
	  TopoDS_Shape&   OE   = itE.Value();
	  if (NewEdges.Contains(OE)) {
	    Handle(Geom2d_Curve) CO2d = 
	      BRep_Tool::CurveOnSurface(TopoDS::Edge(OE),OF,f,l);
	    Geom2dAdaptor_Curve  AC(CO2d,f,l);
	    
	    if (Offset > 0) {
	      if (IsInOut(FC,AC,TopAbs_OUT)) OE.Reverse();
	    }
//	    else {
//	      if (IsInOut(FC,AC,TopAbs_IN)) OE.Reverse();	    
//	    }
	  }
	}
      }
    }
  }

}



