// File:	BRepOffset_MakeOffset.cxx
// Created:	Fri Oct 27 10:30:44 1995
// Author:	Yves FRICAUD
//		<yfr@stylox>


//  Modified by skv - Tue Mar 15 16:20:43 2005
// Add methods for supporting history.

//  Modified by skv - Mon Jan 12 11:50:02 2004 OCC4455

#include <BRepOffset_MakeOffset.ixx>
#include <BRepOffset_Analyse.hxx>
#include <BRepOffset_DataMapOfShapeOffset.hxx> 
#include <BRepOffset_DataMapOfShapeMapOfShape.hxx>
#include <BRepOffset_DataMapIteratorOfDataMapOfShapeOffset.hxx>
#include <BRepOffset_DataMapIteratorOfDataMapOfShapeReal.hxx>
#include <BRepOffset_Interval.hxx>
#include <BRepOffset_ListOfInterval.hxx>
#include <BRepOffset_Offset.hxx>
#include <BRepOffset_Tool.hxx>
#include <BRepOffset_Inter2d.hxx>
#include <BRepOffset_Inter3d.hxx>
#include <BRepOffset_MakeLoops.hxx>


#include <BRepAdaptor_Surface.hxx>
#include <BRepCheck_Edge.hxx>
#include <BRepCheck_Vertex.hxx>
#include <BRepLib.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRep_TVertex.hxx>
#include <BRepTools_Quilt.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <gp_Pnt.hxx>

#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Solid.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>

#include <TopTools_MapOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_DataMapOfShapeShape.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
#include <TColStd_ListIteratorOfListOfInteger.hxx>

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

#include <TopTools_SequenceOfShape.hxx>
#include <Geom_OffsetSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <BRep_TEdge.hxx>
#include <BRepTools.hxx>
#include <gp_Cone.hxx>
#include <ElSLib.hxx>
#include <ElCLib.hxx>
#include <gp_Lin2d.hxx>
#include <GCE2d_MakeLine.hxx>
#include <Geom2d_Line.hxx>
#include <TopoDS_Iterator.hxx>
#include <BRepLib_MakeFace.hxx>
#include <Geom_Circle.hxx>

#include <BRep_PointRepresentation.hxx>
#include <BRep_ListIteratorOfListOfPointRepresentation.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>

#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Curve2d.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
#include <Geom_SphericalSurface.hxx>
#include <TopoDS_Wire.hxx>
#include <BRepTools_Substitution.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Geom2d_TrimmedCurve.hxx>


// POP pour NT
#include <stdio.h>

#ifdef DRAW

#include <DBRep.hxx>
#endif
#ifdef DEB
#include <OSD_Chronometer.hxx>

  Standard_Boolean AffichInt2d = Standard_False;       
  Standard_Boolean AffichOffC  = Standard_False;       
  Standard_Boolean ChronBuild  = Standard_False;
  Standard_Integer NbAE        = 0;
  Standard_Integer NbAF        = 0;  
  static OSD_Chronometer  Clock;
  char name[100];




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

static void DEBVerticesControl (const TopTools_MapOfShape&    NewEdges,
				      Handle(BRepAlgo_AsDes)  AsDes)
{
  Standard_Integer NVP = 0;
  Standard_Integer NVM = 0;
  Standard_Integer NVN = 0;

  TopTools_ListOfShape               LVP;
  TopTools_MapIteratorOfMapOfShape   it;
  TopTools_ListIteratorOfListOfShape it1LE ;    
  TopTools_ListIteratorOfListOfShape it2LE ;
  
  for (it.Initialize(NewEdges) ; it.More(); it.Next()) {
    const TopoDS_Edge& NE = TopoDS::Edge(it.Key());
    if (AsDes->HasDescendant(NE)) {
      for (it1LE.Initialize(AsDes->Descendant(NE)); it1LE.More(); it1LE.Next()) {
	if (AsDes->Ascendant(it1LE.Value()).Extent() < 3) {
	  LVP.Append(it1LE.Value());
	  cout <<"Vertex sur moins de 3 edges."<<endl;
#ifdef DRAW
	  if (AffichInt2d) {
	    sprintf (name,"VP_%d",NVP++);
	    DBRep::Set(name,it1LE.Value());
	  }
#endif
	}
	else if (AsDes->Ascendant(it1LE.Value()).Extent() > 3) {
	  cout <<"Vertex sur plus de 3 edges."<<endl;
#ifdef DRAW
	  if (AffichInt2d) {
	    sprintf (name,"VM_%d",NVM++);
	    DBRep::Set(name,it1LE.Value());
	  }
#endif
	  
	}
	else {
#ifdef DRAW
	  if (AffichInt2d) {
	    sprintf (name,"VN_%d",NVN++);
	    DBRep::Set(name,it1LE.Value());
	  }
#endif
	}
      }
    }
  }
  //------------------------------------------------
  // Essai de confusion des vertex pourris.
  //------------------------------------------------
  BRep_Builder B;
  TopTools_ListIteratorOfListOfShape it1(LVP);
  Standard_Real                      TolConf = 1.e-5;
  Standard_Real                      Tol     = Precision::Confusion();
  Standard_Integer                   i = 1;

  for ( ; it1.More(); it1.Next()) {
    TopoDS_Shape   V1 = it1.Value();
    gp_Pnt         P1 = BRep_Tool::Pnt(TopoDS::Vertex(V1));
    Standard_Real  distmin = Precision::Infinite();
    TopTools_ListIteratorOfListOfShape it2(LVP);
    Standard_Integer j = 1;

    for ( ; it2.More(); it2.Next()) {
      if (j > i) {
	TopoDS_Shape V2 = it2.Value();
	gp_Pnt       P2 = BRep_Tool::Pnt(TopoDS::Vertex(V2));
	if (!V1.IsSame(V2)) {
	  Standard_Real       dist    = P1.Distance(P2);
	  if (dist < distmin) distmin = dist;
	  if (dist < TolConf) {
	    Standard_Real UV2;
	    TopoDS_Edge   EWE2;
	    const TopTools_ListOfShape& EdgeWithV2 = AsDes->Ascendant(V2);
	    TopTools_ListIteratorOfListOfShape itAsDes;
	    for (itAsDes.Initialize(EdgeWithV2); itAsDes.More(); itAsDes.Next()) {
	      EWE2  = TopoDS::Edge(itAsDes.Value());
	      TopoDS_Shape aLocalShape = V2.Oriented(TopAbs_INTERNAL);
	      UV2   = BRep_Tool::Parameter(TopoDS::Vertex(aLocalShape),EWE2);
	      aLocalShape = V1.Oriented(TopAbs_INTERNAL) ;
	      B.UpdateVertex(TopoDS::Vertex(aLocalShape),UV2,EWE2,Tol);
//	      UV2   = 
//		BRep_Tool::Parameter(TopoDS::Vertex(),EWE2);
//	      B.UpdateVertex(TopoDS::Vertex(V1.Oriented(TopAbs_INTERNAL)),
//			     UV2,EWE2,Tol);
	    }
	    AsDes->Replace(V2,V1);
	  }
	}
      }
      j++;
    }
    i++;
    cout <<" distmin entre VP : "<<distmin<<endl;
  }
}  
#endif


static void UpdateTolerance (      TopoDS_Shape&        myShape,
			     const TopTools_MapOfShape& myFaces);


static Standard_Boolean FindParameter(const TopoDS_Vertex& V, 
				      const TopoDS_Edge& E,
				      Standard_Real& U)
{
  // Search the vertex in the edge

  Standard_Boolean rev = Standard_False;
  TopoDS_Shape VF;
  TopAbs_Orientation orient = TopAbs_INTERNAL;

  TopoDS_Iterator itv(E.Oriented(TopAbs_FORWARD));

  // if the edge has no vertices
  // and is degenerated use the vertex orientation
  // RLE, june 94

  if (!itv.More() && BRep_Tool::Degenerated(E)) {
    orient = V.Orientation();
  }

  while (itv.More()) {
    const TopoDS_Shape& Vcur = itv.Value();
    if (V.IsSame(Vcur)) {
      if (VF.IsNull()) {
	VF = Vcur;
      }
      else {
	rev = E.Orientation() == TopAbs_REVERSED;
	if (Vcur.Orientation() == V.Orientation()) {
	  VF = Vcur;
	}
      }
    }
    itv.Next();
  }
  
  if (!VF.IsNull()) orient = VF.Orientation();
 
  Standard_Real f,l;

  if (orient ==  TopAbs_FORWARD) {
    BRep_Tool::Range(E,f,l);
    //return (rev) ? l : f;
    U = (rev) ? l : f;
    return Standard_True;
  }
 
  else if (orient ==  TopAbs_REVERSED) {
    BRep_Tool::Range(E,f,l);
    //return (rev) ? f : l;
    U = (rev) ? f : l;
    return Standard_True;
   }

  else {
    TopLoc_Location L;
    const Handle(Geom_Curve)& C = BRep_Tool::Curve(E,L,f,l);
    L = L.Predivided(V.Location());
    if (!C.IsNull() || BRep_Tool::Degenerated(E)) {
      BRep_ListIteratorOfListOfPointRepresentation itpr
	((*((Handle(BRep_TVertex)*) &V.TShape()))->Points());

      while (itpr.More()) {
	const Handle(BRep_PointRepresentation)& pr = itpr.Value();
	if (pr->IsPointOnCurve(C,L)) {
	  Standard_Real p = pr->Parameter();
	  Standard_Real res = p;// SVV 4 nov 99 - to avoid warnings on Linux
	  if (!C.IsNull()) {
	    // Closed curves RLE 16 june 94
	    if (Precision::IsNegativeInfinite(f))
	      {
		//return pr->Parameter();//p;
		U = pr->Parameter();
		return Standard_True;
	      }
	    if (Precision::IsPositiveInfinite(l))
	      {
		//return pr->Parameter();//p;
		U = pr->Parameter();
		return Standard_True;
	      }
	    gp_Pnt Pf = C->Value(f).Transformed(L.Transformation());
	    gp_Pnt Pl = C->Value(l).Transformed(L.Transformation());
	    Standard_Real tol = BRep_Tool::Tolerance(V);
	    if (Pf.Distance(Pl) < tol) {
	      if (Pf.Distance(BRep_Tool::Pnt(V)) < tol) {
		if (V.Orientation() == TopAbs_FORWARD) res = f;//p = f;
		else                                   res = l;//p = l;
	      }
	    }
	  }
	  //return res;//p;
	  U = res;
	  return Standard_True;
	}
	itpr.Next();
      }
    }
    else {
      // no 3d curve !!
      // let us try with the first pcurve
      Handle(Geom2d_Curve) PC;
      Handle(Geom_Surface) S;
      BRep_Tool::CurveOnSurface(E,PC,S,L,f,l);
      L = L.Predivided(V.Location()); 
      BRep_ListIteratorOfListOfPointRepresentation itpr
	((*((Handle(BRep_TVertex)*) &V.TShape()))->Points());

      while (itpr.More()) {
	const Handle(BRep_PointRepresentation)& pr = itpr.Value();
	if (pr->IsPointOnCurveOnSurface(PC,S,L)) {
	  Standard_Real p = pr->Parameter();
	  // Closed curves RLE 16 june 94
	  if (PC->IsClosed()) {
	    if ((p == PC->FirstParameter()) || 
		(p == PC->LastParameter())) {
	      if (V.Orientation() == TopAbs_FORWARD) p = PC->FirstParameter();
	      else                                   p = PC->LastParameter();
	    }
	  }
	  //return p;
	  U = p;
	  return Standard_True;
	}
	itpr.Next();
      }
    }
  }
  
  //Standard_NoSuchObject::Raise("BRep_Tool:: no parameter on edge");
  return Standard_False;
}

//=======================================================================
//function : GetEdgePoints
//purpose  : gets the first, last and middle points of the edge
//=======================================================================
static void GetEdgePoints(const TopoDS_Edge& anEdge,
                                      const TopoDS_Face& aFace,
                                      gp_Pnt& fPnt, gp_Pnt& mPnt,
                                      gp_Pnt& lPnt)
{
  Standard_Real f, l;
  Handle(Geom2d_Curve) theCurve = BRep_Tool::CurveOnSurface( anEdge, aFace, f, l );
  gp_Pnt2d fPnt2d = theCurve->Value(f);
  gp_Pnt2d lPnt2d = theCurve->Value(l);
  gp_Pnt2d mPnt2d = theCurve->Value(0.5*(f + l));
  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
  fPnt = aSurf->Value(fPnt2d.X(),fPnt2d.Y());
  lPnt = aSurf->Value(lPnt2d.X(),lPnt2d.Y());
  mPnt = aSurf->Value(mPnt2d.X(), mPnt2d.Y());
}


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

BRepOffset_MakeOffset::BRepOffset_MakeOffset()
{
  myAsDes = new BRepAlgo_AsDes();
}


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

BRepOffset_MakeOffset::BRepOffset_MakeOffset(const TopoDS_Shape&    S, 
					     const Standard_Real    Offset, 
					     const Standard_Real    Tol, 
					     const BRepOffset_Mode  Mode, 
					     const Standard_Boolean Inter, 
					     const Standard_Boolean SelfInter, 
					     const GeomAbs_JoinType Join)
: 
myOffset   (Offset),
myTol      (Tol),
myShape    (S),
myMode     (Mode),
myInter    (Inter),
mySelfInter(SelfInter),
myJoin     (Join),
myDone     (Standard_False)

{
  myAsDes = new BRepAlgo_AsDes();
  MakeOffsetShape();
}


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

void BRepOffset_MakeOffset::Initialize(const TopoDS_Shape&    S, 
				       const Standard_Real    Offset, 
				       const Standard_Real    Tol, 
				       const BRepOffset_Mode  Mode,
				       const Standard_Boolean Inter,
				       const Standard_Boolean SelfInter,
				       const GeomAbs_JoinType Join)
{
  myOffset   = Offset;
  myShape    = S;
  myTol      = Tol;
  myMode     = Mode;
  myInter    = Inter;
  mySelfInter= SelfInter;
  myJoin     = Join;
  myDone     = Standard_False;
  Clear();
}


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

void BRepOffset_MakeOffset::Clear()
{
  myOffsetShape.Nullify();
  myInitOffsetFace .Clear();
  myInitOffsetEdge .Clear();
  myImageOffset    .Clear();
  myFaces          .Clear();  
  myFaceOffset     .Clear();
  myAsDes          ->Clear();
  myDone     = Standard_False;
}

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

void BRepOffset_MakeOffset::AddFace(const TopoDS_Face& F) {
  myFaces.Add(F);    
  //-------------
  // MAJ SD.
  //-------------
  myInitOffsetFace.SetRoot (F)  ;    
  myInitOffsetFace.Bind    (F,F);
  myImageOffset.SetRoot    (F)  ;  
}

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

void BRepOffset_MakeOffset::SetOffsetOnFace(const TopoDS_Face&  F, 
					    const Standard_Real Off)
{
  if ( myFaceOffset.IsBound(F)) myFaceOffset.UnBind(F);
  myFaceOffset.Bind(F,Off);
}

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

static void RemoveCorks (TopoDS_Shape&        S,
			 TopTools_MapOfShape& Faces)
{  
  TopoDS_Compound SS;
  BRep_Builder    B;
  B.MakeCompound (SS);
  //-----------------------------------------------------
  // Construction d un shape sans les bouchons.
  // et Orientation des bouchons comme dans le shape S.
  //-----------------------------------------------------
  TopExp_Explorer exp(S,TopAbs_FACE);
  for (; exp.More(); exp.Next()) {
    const TopoDS_Shape& Cork = exp.Current(); 
    if (!Faces.Contains(Cork)) {
      B.Add(SS,Cork);
    }
    else {
      Faces.Remove (Cork);
      Faces.Add    (Cork); // pour la remettre avec la bonne orientation.
    }
  }
  S = SS;
#ifdef DRAW
  if ( AffichOffC) 
    DBRep::Set("myInit", SS);
#endif

}

static Standard_Boolean IsConnectedShell( const TopoDS_Shape& S )
{  
  BRepTools_Quilt Glue;
  Glue.Add( S );

  TopoDS_Shape SS = Glue.Shells();
  TopExp_Explorer Explo( SS, TopAbs_SHELL );
  Explo.Next();
  if (Explo.More())
    return Standard_False;
  
  return Standard_True;
}


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

static void MakeList (TopTools_ListOfShape&      OffsetFaces,
		      const BRepAlgo_Image&    myInitOffsetFace,
		      const TopTools_MapOfShape& myFaces)
{
  TopTools_ListIteratorOfListOfShape itLOF(myInitOffsetFace.Roots());
  for ( ; itLOF.More(); itLOF.Next()) {
    const TopoDS_Shape& Root = itLOF.Value();
    if (!myFaces.Contains(Root))
      OffsetFaces.Append(myInitOffsetFace.Image(Root).First());
  }
}

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

static void EvalMax(const TopoDS_Shape& S, Standard_Real& Tol)
{
  TopExp_Explorer exp;
  for (exp.Init(S,TopAbs_VERTEX); exp.More(); exp.Next()) {
    const TopoDS_Vertex& V    = TopoDS::Vertex(exp.Current());
    Standard_Real        TolV = BRep_Tool::Tolerance(V); 
    if (TolV > Tol) Tol = TolV;
  }
  //Patch
  Tol *= 5.;
}

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

void BRepOffset_MakeOffset::MakeOffsetShape()
{  
  myDone     = Standard_False;
  //------------------------------------------
  // Constuction de myShape sans les bouchons.
  //------------------------------------------
  RemoveCorks (myShape,myFaces);
  
  if (! IsConnectedShell(myShape))
    Standard_ConstructionError::Raise("BRepOffset_MakeOffset : Incorrect set of faces to remove, the remaining shell is not connected");

  if (Abs(myOffset) < myTol) return;

  TopAbs_State       Side = TopAbs_IN;
  if (myOffset < 0.) Side = TopAbs_OUT;
  // ------------
  // Preanalyse.
  // ------------
  EvalMax(myShape,myTol);
  if (myTol > Abs(myOffset*0.5)) {
    Standard_ConstructionError::Raise("BRepOffset_MakeOffset : Tol > Offset");
  }
  Standard_Real TolAngle = 4*ASin(myTol/Abs(myOffset*0.5));
  myAnalyse.Perform(myShape,TolAngle);
  //---------------------------------------------------
  // Construction des Offset a partir de la preanalyse.
  //---------------------------------------------------  
  //----------------------------
  // MaJ de la SD Face - Offset
  //----------------------------
  UpdateFaceOffset();

  if (myJoin == GeomAbs_Arc)          
    BuildOffsetByArc();
  else if (myJoin == GeomAbs_Intersection) 
    BuildOffsetByInter();
  //-----------------
  // Auto debouclage.
  //-----------------
  // if (mySelfInter)  SelfInter(Modif);
  //-----------------
  // Intersection 3d .
  //-----------------
  BRepOffset_Inter3d Inter(myAsDes,Side,myTol);
  Intersection3D (Inter);
  //-----------------
  // Intersection2D
  //-----------------
  TopTools_MapOfShape& Modif    = Inter.TouchedFaces(); 
  TopTools_MapOfShape& NewEdges = Inter.NewEdges();

  if (!Modif.IsEmpty()) Intersection2D (Modif,NewEdges);
  //-------------------------------------------------------
  // Debouclage 2D et reconstruction des faces modifiees
  //----------------------------------------------------
  MakeLoops (Modif);
  //-----------------------------------------------------
  // Reconstuction des faces non modifie mais qui partage 
  // des edges recontruits
  //------------------------------------------------------
  if (!Modif.IsEmpty()) MakeFaces (Modif);
  //-------------------------
  // Construction des shells.
  //-------------------------
  MakeShells ();
  //--------------
  // Debouclage3d.
  //--------------
  SelectShells ();
  //----------------------------------
  // Codage ges regularites.
  //----------------------------------
  EncodeRegularity();
  //----------------------
  // Creation des solides.
  //----------------------
  MakeSolid ();

  //-----------------------------
  // MAJ Tolerance edge et Vertex
  // ----------------------------
  if (!myOffsetShape.IsNull()) {
    UpdateTolerance (myOffsetShape,myFaces);
    BRepLib::UpdateTolerances( myOffsetShape );
  }

  CorrectConicalFaces();

  myDone = Standard_True;
}



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

void BRepOffset_MakeOffset::MakeThickSolid() 
{
  //--------------------------------------------------------------
  // Construction shell parallele au shell (initial sans bouchon).
  //--------------------------------------------------------------
  MakeOffsetShape ();

  //--------------------------------------------------------------------
  // Construction d un solide avec le shell initial le shell parallele
  // limite par les bouchons.
  //--------------------------------------------------------------------
  if (!myFaces.IsEmpty()) {
    TopoDS_Solid    Res;
    TopExp_Explorer exp;
    BRep_Builder    B;
    Standard_Integer NbF = myFaces.Extent();

    B.MakeSolid(Res);

    BRepTools_Quilt Glue;
    for (exp.Init(myShape,TopAbs_FACE); exp.More(); exp.Next()) {
      NbF++;
      Glue.Add (exp.Current());
    } 
    Standard_Boolean YaResult = 0;
    if (!myOffsetShape.IsNull()) {
      for (exp.Init(myOffsetShape,TopAbs_FACE);exp.More(); exp.Next()) {
	YaResult = 1;
	Glue.Add (exp.Current().Reversed());
      }
    }
    if (YaResult == 0) {
      myDone = Standard_False;
      return;
    }
    myOffsetShape = Glue.Shells();
    for (exp.Init(myOffsetShape,TopAbs_SHELL); exp.More(); exp.Next()) {
      B.Add(Res,exp.Current());
    }
    Res.Closed(Standard_True);
    myOffsetShape = Res;

    // Test de Validite du resultat le Solide epais doit avoir 
    // plus de face que le solide initial.
        
    Standard_Integer NbOF = 0;
    for (exp.Init(myOffsetShape,TopAbs_FACE);exp.More(); exp.Next()) {
      NbOF++;
    }
    if (NbOF <= NbF) {
      myDone = Standard_False;
      return;
    }
  }

  if (myOffset > 0 ) myOffsetShape.Reverse();  

  myDone = Standard_True;
}

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

Standard_Boolean BRepOffset_MakeOffset::IsDone() const
{
  return myDone;
}

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

BRepOffset_Error BRepOffset_MakeOffset::Error() const
{
  return myError;
}

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

const TopoDS_Shape&  BRepOffset_MakeOffset::Shape() const 
{
  return myOffsetShape;
}

//=======================================================================
//function : TrimEdge
//purpose  : Trim l edge au plus large par ses descendants dans AsDes2d.
//           Range dans AsDes les deux vertex qui ont trimme l edge.
//=======================================================================

static void TrimEdge (TopoDS_Edge&                  NE,
		      const Handle(BRepAlgo_AsDes)& AsDes2d,
		            Handle(BRepAlgo_AsDes)& AsDes)
{
  Standard_Real aSameParTol = Precision::Confusion();
  
  TopoDS_Vertex V1,V2;
  Standard_Real U;
  Standard_Real UMin =  Precision::Infinite();
  Standard_Real UMax = -UMin;

  const TopTools_ListOfShape& LE = AsDes2d->Descendant(NE);
  
  if (LE.Extent() > 1) {
    TopTools_ListIteratorOfListOfShape it (LE);
    for (; it.More(); it.Next()) {
      TopoDS_Vertex V = TopoDS::Vertex(it.Value());
      if (NE.Orientation() == TopAbs_REVERSED)
	V.Reverse();
      //V.Orientation(TopAbs_INTERNAL);
      if (!FindParameter(V, NE, U))
	{
	  Standard_Real f, l;
	  Handle(Geom_Curve) theCurve = BRep_Tool::Curve(NE, f, l);
	  gp_Pnt thePoint = BRep_Tool::Pnt(V);
	  GeomAPI_ProjectPointOnCurve Projector(thePoint, theCurve);
	  if (Projector.NbPoints() == 0)
	    Standard_ConstructionError::Raise("BRepOffset_MakeOffset::TrimEdge no projection");
	  U = Projector.LowerDistanceParameter();
	}
      if (U < UMin) {
	UMin = U; V1   = V;
      }
      if (U > UMax) {
	UMax = U; V2   = V;
      }
    }
    if (V1.IsNull() || V2.IsNull()) {
      Standard_ConstructionError::Raise("BRepOffset_MakeOffset::TrimEdge");
    }
    if (!V1.IsSame(V2)) {
      NE.Free( Standard_True );
      BRep_Builder B;
      TopAbs_Orientation Or = NE.Orientation();
      NE.Orientation(TopAbs_FORWARD);
      TopoDS_Vertex VF,VL;
      TopExp::Vertices (NE,VF,VL);
      B.Remove(NE,VF);
      B.Remove(NE,VL);
      B.Add  (NE,V1.Oriented(TopAbs_FORWARD));
      B.Add  (NE,V2.Oriented(TopAbs_REVERSED));
      B.Range(NE,UMin,UMax);
      NE.Orientation(Or);
      AsDes->Add(NE,V1.Oriented(TopAbs_FORWARD));
      AsDes->Add(NE,V2.Oriented(TopAbs_REVERSED));
      BRepLib::SameParameter(NE, aSameParTol, Standard_True);
    }
  }
}

//=======================================================================
//function : BuildOffsetByInter
//purpose  : 
//=======================================================================
void BRepOffset_MakeOffset::BuildOffsetByInter()
{
#ifdef  DEB
  if ( ChronBuild) {
    cout << " CONSTRUCTION DES OFFSETS :" << endl;
    Clock.Reset();
    Clock.Start();
  }
#endif

  BRepOffset_DataMapOfShapeOffset MapSF;
  TopTools_MapOfShape             Done;
  Standard_Boolean OffsetOutside = (myOffset > 0.)? Standard_True : Standard_False;
  //--------------------------------------------------------
  // Construction des faces paralleles a des faces initiales
  //--------------------------------------------------------
  TopExp_Explorer Exp;
  TopTools_ListOfShape LF;
  TopTools_ListIteratorOfListOfShape itLF;

  BRepLib::SortFaces(myShape,LF);

  TopTools_DataMapOfShapeShape ShapeTgt;
  for (itLF.Initialize(LF); itLF.More(); itLF.Next()) {
    const TopoDS_Face&   F = TopoDS::Face(itLF.Value());
    Standard_Real CurOffset = myOffset;
    if (myFaceOffset.IsBound(F)) CurOffset = myFaceOffset(F);
    BRepOffset_Offset    OF(F,CurOffset,ShapeTgt,OffsetOutside,myJoin);
    TopTools_ListOfShape Let;
    myAnalyse.Edges(F,BRepOffset_Tangent,Let);
    TopTools_ListIteratorOfListOfShape itl(Let);
    
    for ( ; itl.More(); itl.Next()) {
      const TopoDS_Edge& Cur = TopoDS::Edge(itl.Value());
      if ( !ShapeTgt.IsBound(Cur)) {
	TopoDS_Shape aLocalShape = OF.Generated(Cur);
	const TopoDS_Edge& OTE = TopoDS::Edge(aLocalShape);
//	const TopoDS_Edge& OTE = TopoDS::Edge(OF.Generated(Cur));
	ShapeTgt.Bind(Cur,OF.Generated(Cur));
	TopoDS_Vertex V1,V2,OV1,OV2;
	TopExp::Vertices (Cur,V1,V2);
	TopExp::Vertices (OTE,OV1,OV2);      
	TopTools_ListOfShape LE;
	if (!ShapeTgt.IsBound(V1)) {
	  myAnalyse.Edges(V1,BRepOffset_Tangent,LE);
	  const TopTools_ListOfShape& LA =myAnalyse.Ancestors(V1);
	  if (LE.Extent() == LA.Extent())
	    ShapeTgt.Bind(V1,OV1);
	}
	if (!ShapeTgt.IsBound(V2)) {
	  LE.Clear();
	  myAnalyse.Edges(V2,BRepOffset_Tangent,LE);
	  const TopTools_ListOfShape& LA =myAnalyse.Ancestors(V2);
	  if (LE.Extent() == LA.Extent())
	    ShapeTgt.Bind(V2,OV2);
	}
      }
    }
    MapSF.Bind(F,OF);
  }
  //--------------------------------------------------------------------
  // MES   : Map of OffsetShape -> Extended Shapes.
  // Build : Map of Initial SS  -> OffsetShape build by Inter.
  //                               can be an edge or a compound of edges       
  //---------------------------------------------------------------------
  TopTools_DataMapOfShapeShape MES;  
  TopTools_DataMapOfShapeShape Build; 
  TopTools_ListOfShape         Failed;
  TopAbs_State                 Side = TopAbs_IN;  
  Handle(BRepAlgo_AsDes)       AsDes = new BRepAlgo_AsDes();

  //-------------------------------------------------------------------
  // Extension des faces et calcul des nouvelles edges d intersection.
  //-------------------------------------------------------------------
  Standard_Boolean  ExtentContext = 0;
  if (myOffset > 0) ExtentContext = 1;

  BRepOffset_Inter3d Inter3 (AsDes,Side,myTol);
  // Intersection entre faces paralleles
  Inter3.ConnexIntByInt(myShape,MapSF,myAnalyse,MES,Build,Failed );
  // Intersection avec les bouchons.
  Inter3.ContextIntByInt(myFaces,ExtentContext,MapSF,myAnalyse,MES,Build,Failed );


  //---------------------------------------------------------------------------------
  // Extension des edges voisines des nouvelles edges.et intersection  entre les voisins.
  //--------------------------------------------------------------------------------
  Handle(BRepAlgo_AsDes) AsDes2d = new BRepAlgo_AsDes();
  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next()) {
    const TopoDS_Face& FI = TopoDS::Face(Exp.Current());
//  Modified by skv - Mon Jan 12 11:50:02 2004 OCC4455 Begin
//    BRepOffset_Inter2d::ConnexIntByInt (FI,MapSF(FI),MES,Build,AsDes2d,myTol);
    BRepOffset_Inter2d::ConnexIntByInt (FI,MapSF(FI),MES,Build,AsDes2d,myOffset, myTol);
//  Modified by skv - Mon Jan 12 11:50:03 2004 OCC4455 End
  }
  //-----------------------------------------------------------
  // Restriction large des nouvelles edges et mise a jour AsDes.
  //------------------------------------------ ----------------
  TopTools_MapOfShape NewEdges;
  TopExp_Explorer Exp2,ExpC;
  TopoDS_Shape    NE;
  TopoDS_Edge     TNE;
  TopoDS_Face     NF;
#ifdef DEB
  TopAbs_Orientation Or;
#endif
  
  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next()) {
    const TopoDS_Face& FI = TopoDS::Face(Exp.Current());
    NF = MapSF(FI).Face();
    if (MES.IsBound(NF)) {NF = TopoDS::Face(MES(NF));}
    TopTools_MapOfShape View;
    for (Exp2.Init(FI.Oriented(TopAbs_FORWARD),TopAbs_EDGE); Exp2.More(); Exp2.Next()) {
      const TopoDS_Edge& EI = TopoDS::Edge(Exp2.Current());
      if (View.Add(EI)) {
	if (Build.IsBound(EI)) {
	  NE = Build(EI);
	  if (NE.ShapeType() == TopAbs_EDGE) {
	    if (NewEdges.Add(NE)) {TrimEdge (TopoDS::Edge(NE),AsDes2d,AsDes);}
	  }
	  else {
	    //------------------------------------------------------------
	    // Les Intersections sont en plusieurs edges.
	    // Les morceaux sans intersections avec les voisins 
	    // sont supprimes de AsDes.
	    //------------------------------------------------------------
	    for (ExpC.Init(NE,TopAbs_EDGE); ExpC.More(); ExpC.Next()) {
	      if (NewEdges.Add(ExpC.Current())) {
		TopoDS_Edge NEC = TopoDS::Edge(ExpC.Current());
		NEC.Free(Standard_True);
		if (!AsDes2d->Descendant(NEC).IsEmpty()) {
		  TrimEdge (NEC,AsDes2d,AsDes);
		}
		else {
		  AsDes->Remove(NEC);
		}
	      }
	    }
	  }
	}
	else {
	  NE = MapSF(FI).Generated(EI);
	  //// modified by jgv, 19.12.03 for OCC4455 ////
	  NE.Orientation( EI.Orientation() );
	  ///////////////////////////////////////////////
	  if (MES.IsBound(NE)) {
	    NE = MES(NE);
	    NE.Orientation(EI.Orientation());
	    if (NewEdges.Add(NE)) {TrimEdge (TopoDS::Edge(NE),AsDes2d,AsDes);} 
	  }
	  AsDes->Add(NF,NE);
	} 
      }
    }
  }
  
  //--------------------------------- 
  // Intersection2d sur les //
  //---------------------------------  
  TopTools_ListOfShape LFE; 
  BRepAlgo_Image     IMOE;
  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next()) {
    const TopoDS_Shape& FI  = Exp.Current();
    const TopoDS_Shape& OFI = MapSF(FI).Face();
    if (MES.IsBound(OFI)) {
      const TopoDS_Face& NF = TopoDS::Face(MES(OFI));
      LFE.Append(NF);
      IMOE.SetRoot(NF);
    }
  }
  
  TopTools_ListIteratorOfListOfShape itLFE(LFE);
  for (; itLFE.More(); itLFE.Next()) {
    const TopoDS_Face& NEF = TopoDS::Face(itLFE.Value());
    BRepOffset_Inter2d::Compute(AsDes,NEF,NewEdges,myTol);
  }
  //----------------------------------------------
  // Intersections 2d sur les bouchons.
  //----------------------------------------------
  TopTools_MapIteratorOfMapOfShape itCork(myFaces);
  for (; itCork.More(); itCork.Next()) {
    const TopoDS_Face& Cork = TopoDS::Face(itCork.Key());
    BRepOffset_Inter2d::Compute(AsDes,Cork,NewEdges,myTol);
  }

  //-------------------------------
  // Debouclage des Faces etendues.
  //-------------------------------
  myMakeLoops.Build(LFE  ,AsDes,IMOE);

#ifdef DEB
  TopTools_MapOfShape COES;
#endif
  //---------------------------
  // MAJ SD. pour les faces //
  //---------------------------
  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next()) {
    const TopoDS_Shape& FI   = Exp.Current();
    myInitOffsetFace.SetRoot(FI);
    TopoDS_Face  OF  = MapSF(FI).Face();
    if (MES.IsBound(OF)) {
      OF = TopoDS::Face(MES(OF));
      if (IMOE.HasImage(OF)) {
	const TopTools_ListOfShape& LOFE = IMOE.Image(OF);
	myInitOffsetFace.Bind(FI,LOFE);
	for (itLF.Initialize(LOFE); itLF.More(); itLF.Next()) {
	  const TopoDS_Shape& OFE =  itLF.Value();
	  myImageOffset.SetRoot(OFE);
#ifdef DRAW
	  if (AffichInt2d) {
	    sprintf(name,"AF_%d",NbAF++);
	    DBRep::Set(name,OFE);
	  }
#endif
	  TopTools_MapOfShape View;
	  for (Exp2.Init(OFE.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	       Exp2.More(); Exp2.Next()) {
	    const TopoDS_Edge& COE = TopoDS::Edge(Exp2.Current());
	    
	    myAsDes->Add (OFE,COE);
#ifdef DRAW
	    if (AffichInt2d) {
	      sprintf(name,"AE_%d",NbAE++);
	      DBRep::Set(name,COE);
	      COES.Add(COE);
	    }
#endif
	    if (View.Add(COE)){
	      if (!myAsDes->HasDescendant(COE)) {
		TopoDS_Vertex CV1,CV2;
		TopExp::Vertices(COE,CV1,CV2);
		if (!CV1.IsNull()) myAsDes->Add(COE,CV1.Oriented(TopAbs_FORWARD));
		if (!CV2.IsNull()) myAsDes->Add(COE,CV2.Oriented(TopAbs_REVERSED));	
	      }
	    }
	  }
	}
      }
      else {
	myInitOffsetFace.Bind(FI,OF);
	myImageOffset.SetRoot(OF);
#ifdef DRAW 
	if (AffichInt2d) {
	  sprintf(name,"AF_%d",NbAF++);
	  DBRep::Set(name,OF);
	}
#endif
	const TopTools_ListOfShape& LE = AsDes->Descendant(OF);
	for (itLF.Initialize(LE) ; itLF.More(); itLF.Next()) {
	  const TopoDS_Edge& OE = TopoDS::Edge(itLF.Value());
	  if (IMOE.HasImage(OE)) {
	    const TopTools_ListOfShape& LOE = IMOE.Image(OE);
	    TopTools_ListIteratorOfListOfShape itLOE(LOE);
	    for (; itLOE.More(); itLOE.Next()) {
	      TopoDS_Shape aLocalShape = itLOE.Value().Oriented(OE.Orientation());
	      const TopoDS_Edge& COE = TopoDS::Edge(aLocalShape);
//	      const TopoDS_Edge& COE = TopoDS::Edge(itLOE.Value().Oriented(OE.Orientation()));
	      myAsDes->Add(OF,COE);
#ifdef DRAW
	      if (AffichInt2d) {
		sprintf(name,"AE_%d",NbAE++);
		DBRep::Set(name,COE);
		COES.Add(COE);
	      }
#endif
	      
	      if (!myAsDes->HasDescendant(COE)) {
		TopoDS_Vertex CV1,CV2;
		TopExp::Vertices(COE,CV1,CV2);
 		if (!CV1.IsNull()) myAsDes->Add(COE,CV1.Oriented(TopAbs_FORWARD));
		if (!CV2.IsNull()) myAsDes->Add(COE,CV2.Oriented(TopAbs_REVERSED));	
	      }
	    }
	  }
	  else {
	    myAsDes->Add(OF,OE);
#ifdef DRAW
	    if (AffichInt2d) {
	      sprintf(name,"AE_%d",NbAE++);
	      DBRep::Set(name,OE);
	      COES.Add(OE);
	    }
#endif

	    const TopTools_ListOfShape& LV = AsDes->Descendant(OE);
	    myAsDes->Add(OE,LV);
	  }
	}
      }
    }
    else {
      myInitOffsetFace.Bind(FI,OF);
      myImageOffset.SetRoot(OF);
      TopTools_MapOfShape View;
      for (Exp2.Init(OF.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	   Exp2.More(); Exp2.Next()) {

	const TopoDS_Edge& COE = TopoDS::Edge(Exp2.Current());
	myAsDes->Add (OF,COE);
#ifdef DRAW
	if (AffichInt2d) {
	  sprintf(name,"AE_%d",NbAE++);
	  DBRep::Set(name,COE);
	  COES.Add(COE);
	}
#endif
	
	if (View.Add(Exp2.Current())) {
	  if (!myAsDes->HasDescendant(COE)) {
	    TopoDS_Vertex CV1,CV2;
	    TopExp::Vertices(COE,CV1,CV2);
	    if (!CV1.IsNull()) myAsDes->Add(COE,CV1.Oriented(TopAbs_FORWARD));
	    if (!CV2.IsNull()) myAsDes->Add(COE,CV2.Oriented(TopAbs_REVERSED));	
	  }
	}
      } 
    }
  }
  //  Modified by skv - Tue Mar 15 16:20:43 2005
  // Add methods for supporting history.
  TopTools_MapOfShape aMapEdges;

  for (Exp.Init(myShape,TopAbs_FACE) ; Exp.More(); Exp.Next()) {
    const TopoDS_Shape& aFaceRef = Exp.Current();

    Exp2.Init(aFaceRef.Oriented(TopAbs_FORWARD), TopAbs_EDGE);

    for (; Exp2.More(); Exp2.Next()) {
      const TopoDS_Shape& anEdgeRef = Exp2.Current();

      if (aMapEdges.Add(anEdgeRef)) {
	myInitOffsetEdge.SetRoot(anEdgeRef);
	if (Build.IsBound(anEdgeRef)) {
	  TopoDS_Shape aNewShape = Build(anEdgeRef);

	  if (aNewShape.ShapeType() == TopAbs_EDGE) {
	    if (IMOE.HasImage(aNewShape)) {
	      const TopTools_ListOfShape& aListNewE = IMOE.Image(aNewShape);

	      myInitOffsetEdge.Bind (anEdgeRef, aListNewE);
	    } else
	      myInitOffsetEdge.Bind (anEdgeRef, aNewShape);
	  } else { // aNewShape != TopAbs_EDGE
	    TopTools_ListOfShape aListNewEdge;

	    for (ExpC.Init(aNewShape, TopAbs_EDGE); ExpC.More(); ExpC.Next()) {
	      const TopoDS_Shape &aResEdge = ExpC.Current();

	      if (IMOE.HasImage(aResEdge)) {
		const TopTools_ListOfShape& aListNewE = IMOE.Image(aResEdge);
		TopTools_ListIteratorOfListOfShape aNewEIter(aListNewE);

		for (; aNewEIter.More(); aNewEIter.Next())
		  aListNewEdge.Append(aNewEIter.Value());
	      } else
		aListNewEdge.Append(aResEdge);
	    }

	    myInitOffsetEdge.Bind (anEdgeRef, aListNewEdge);
	  }
	} else {
	  // Free boundary.
	  TopoDS_Shape aNewEdge = MapSF(aFaceRef).Generated(anEdgeRef);

	  if (MES.IsBound(aNewEdge))
	    aNewEdge = MES(aNewEdge);

	  if (IMOE.HasImage(aNewEdge)) {
	    const TopTools_ListOfShape& aListNewE = IMOE.Image(aNewEdge);

	    myInitOffsetEdge.Bind (anEdgeRef, aListNewE);
	  } else
	    myInitOffsetEdge.Bind (anEdgeRef, aNewEdge);
	}
      }
    }
  }
//  Modified by skv - Tue Mar 15 16:20:43 2005

  //---------------------------
  // MAJ SD. pour les bouchons
  //---------------------------
  TopTools_MapOfShape View; 
  for (itCork.Initialize(myFaces); itCork.More(); itCork.Next()) {
    const TopoDS_Shape& Cork = itCork.Key();
    const TopTools_ListOfShape& LE = AsDes->Descendant(Cork);
    for (itLF.Initialize(LE) ; itLF.More(); itLF.Next()) {
      const TopoDS_Edge& OE = TopoDS::Edge(itLF.Value());
      if (IMOE.HasImage(OE)) {
	const TopTools_ListOfShape& LOE = IMOE.Image(OE);
  	TopTools_ListIteratorOfListOfShape itLOE(LOE);
	for (; itLOE.More(); itLOE.Next()) {
	  const TopoDS_Edge& COE = TopoDS::Edge(itLOE.Value());
	  myAsDes->Add(Cork,COE.Oriented(OE.Orientation())) ;
#ifdef DRAW
	  if (AffichInt2d) {
	    sprintf(name,"AE_%d",NbAE++);
	    DBRep::Set(name,COE);
	    COES.Add(COE);
	  }
#endif
	  
	  if (!myAsDes->HasDescendant(COE)) {
	    TopoDS_Vertex CV1,CV2;
	    TopExp::Vertices(COE,CV1,CV2);
	    if (!CV1.IsNull()) myAsDes->Add(COE,CV1.Oriented(TopAbs_FORWARD));
	    if (!CV2.IsNull()) myAsDes->Add(COE,CV2.Oriented(TopAbs_REVERSED));	  
	  }
	}
      }
      else {
	myAsDes->Add(Cork,OE);
	if (AsDes->HasDescendant(OE)) {
	  myAsDes->Add(OE,AsDes->Descendant(OE));
	}
#ifdef DRAW
	if (AffichInt2d) {
	  sprintf(name,"AE_%d",NbAE++);
	  DBRep::Set(name,OE);
	  COES.Add(OE);
	}
#endif
      }
    }
  }
  
#ifdef DEB
  DEBVerticesControl (COES,myAsDes);
  if ( ChronBuild) Clock.Show();
#endif
}


//=======================================================================
//function : BuildOffsetByArc
//purpose  : 
//=======================================================================
void BRepOffset_MakeOffset::BuildOffsetByArc()
{
#ifdef  DEB
  if ( ChronBuild) {
    cout << " CONSTRUCTION DES OFFSETS :" << endl;
    Clock.Reset();
    Clock.Start();
  }
#endif

  BRepOffset_DataMapOfShapeOffset MapSF;
  TopTools_MapOfShape             Done;
  Standard_Boolean OffsetOutside = (myOffset > 0.)? Standard_True : Standard_False;
  //--------------------------------------------------------
  // Construction des faces paralleles a des faces initiales
  //--------------------------------------------------------
  TopExp_Explorer Exp;
  TopTools_ListOfShape LF;
  TopTools_ListIteratorOfListOfShape itLF;

  BRepLib::SortFaces(myShape,LF);

  TopTools_DataMapOfShapeShape EdgeTgt;
  for (itLF.Initialize(LF); itLF.More(); itLF.Next()) {
    const TopoDS_Face&   F = TopoDS::Face(itLF.Value());
    Standard_Real CurOffset = myOffset;
    if (myFaceOffset.IsBound(F)) CurOffset = myFaceOffset(F);
    BRepOffset_Offset    OF(F,CurOffset,EdgeTgt,OffsetOutside,myJoin);
    TopTools_ListOfShape Let;
    myAnalyse.Edges(F,BRepOffset_Tangent,Let);
    TopTools_ListIteratorOfListOfShape itl(Let);
    
    for ( ; itl.More(); itl.Next()) {
      const TopoDS_Edge& Cur = TopoDS::Edge(itl.Value());
      if ( !EdgeTgt.IsBound(Cur)) {
	TopoDS_Shape aLocalShape = OF.Generated(Cur);
	const TopoDS_Edge& OTE = TopoDS::Edge(aLocalShape);
//	const TopoDS_Edge& OTE = TopoDS::Edge(OF.Generated(Cur));
	EdgeTgt.Bind(Cur,OF.Generated(Cur));
	TopoDS_Vertex V1,V2,OV1,OV2;
	TopExp::Vertices (Cur,V1,V2);
	TopExp::Vertices (OTE,OV1,OV2);      
	TopTools_ListOfShape LE;
	if (!EdgeTgt.IsBound(V1)) {
	  myAnalyse.Edges(V1,BRepOffset_Tangent,LE);
	  const TopTools_ListOfShape& LA =myAnalyse.Ancestors(V1);
	  if (LE.Extent() == LA.Extent())
	    EdgeTgt.Bind(V1,OV1);
	}
	if (!EdgeTgt.IsBound(V2)) {
	  LE.Clear();
	  myAnalyse.Edges(V2,BRepOffset_Tangent,LE);
	  const TopTools_ListOfShape& LA =myAnalyse.Ancestors(V2);
	  if (LE.Extent() == LA.Extent())
	      EdgeTgt.Bind(V2,OV2);
	}
      }
    }
    MapSF.Bind(F,OF);
  }
  //--------------------------------------------------------
  // Construction des tuyaux sur arete.
  //--------------------------------------------------------
  BRepOffset_Type    OT = BRepOffset_Convex;
  if (myOffset < 0.) OT = BRepOffset_Concave; 
   
  for (Exp.Init(myShape,TopAbs_EDGE); Exp.More(); Exp.Next()) {
    const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
    if (Done.Add(E)) {
      const TopTools_ListOfShape& Anc = myAnalyse.Ancestors(E);
      if (Anc.Extent() == 2) {
	const BRepOffset_ListOfInterval& L = myAnalyse.Type(E);
	if (!L.IsEmpty() && L.First().Type() == OT) {
	  Standard_Real CurOffset = myOffset;
	  if ( myFaceOffset.IsBound(Anc.First()))
	    CurOffset = myFaceOffset(Anc.First());
	  TopoDS_Shape aLocalShape = MapSF(Anc.First()).Generated(E);
	  TopoDS_Edge EOn1 = TopoDS::Edge(aLocalShape);
	  aLocalShape = MapSF(Anc.Last()).Generated(E);
	  TopoDS_Edge EOn2 = TopoDS::Edge(aLocalShape);
//	  TopoDS_Edge EOn1 = TopoDS::Edge(MapSF(Anc.First()).Generated(E));
//	  TopoDS_Edge EOn2 = TopoDS::Edge(MapSF(Anc.Last()) .Generated(E));
	  // find if exits tangent edges in the original shape
	  TopoDS_Edge E1f, E1l;
	  TopoDS_Vertex V1f, V1l;
	  TopExp::Vertices(E,V1f,V1l);
	  TopTools_ListOfShape TangE;
	  myAnalyse.TangentEdges(E,V1f,TangE);
	  // find if the pipe on the tangent edges are soon created.
	  TopTools_ListIteratorOfListOfShape itl(TangE);
	  Standard_Boolean Find = Standard_False;
	  for ( ; itl.More() && !Find; itl.Next()) {
	    if ( MapSF.IsBound(itl.Value())) {
	      TopoDS_Shape aLocalShape = MapSF(itl.Value()).Generated(V1f);
	      E1f  = TopoDS::Edge(aLocalShape);
//	      E1f  = TopoDS::Edge(MapSF(itl.Value()).Generated(V1f));
	      Find = Standard_True;
	    }
	  }
	  TangE.Clear();
	  myAnalyse.TangentEdges(E,V1l,TangE);
	  // find if the pipe on the tangent edges are soon created.
	  itl.Initialize(TangE);
	  Find = Standard_False;
	  for ( ; itl.More() && !Find; itl.Next()) {
	    if ( MapSF.IsBound(itl.Value())) {
	      TopoDS_Shape aLocalShape = MapSF(itl.Value()).Generated(V1l);
	      E1l  = TopoDS::Edge(aLocalShape);
//	      E1l  = TopoDS::Edge(MapSF(itl.Value()).Generated(V1l));
	      Find = Standard_True;
	    }
	  }
	  BRepOffset_Offset OF (E,EOn1,EOn2,CurOffset,E1f, E1l);
	  MapSF.Bind(E,OF);
	}
      }
      else {
	// ----------------------
	// bord libre.
	// ----------------------
	TopoDS_Shape aLocalShape = MapSF(Anc.First()).Generated(E);
	TopoDS_Edge EOn1 = TopoDS::Edge(aLocalShape);
///	TopoDS_Edge EOn1 = TopoDS::Edge(MapSF(Anc.First()).Generated(E));
        myInitOffsetEdge.SetRoot(E); // skv: supporting history.
	myInitOffsetEdge.Bind (E,EOn1);      
      }
    }
  }

  //--------------------------------------------------------
  // Construction des shperes sur vertex.
  //--------------------------------------------------------
  Done.Clear();
  TopTools_ListIteratorOfListOfShape it;

  for (Exp.Init(myShape,TopAbs_VERTEX); Exp.More(); Exp.Next()) {
    const TopoDS_Vertex& V = TopoDS::Vertex (Exp.Current());
    if (Done.Add(V)) {
      const TopTools_ListOfShape& LA = myAnalyse.Ancestors(V);
      TopTools_ListOfShape LE;
      myAnalyse.Edges(V,OT,LE);

      if (LE.Extent() >= 3 && LE.Extent() == LA.Extent()) {
	TopTools_ListOfShape LOE;
	//--------------------------------------------------------
	// Recuperation des edges connexes sur les tuyaux.
	//--------------------------------------------------------
	for (it.Initialize(LE) ; it.More(); it.Next()) {
	  LOE.Append(MapSF(it.Value()).Generated(V).Reversed());
	}
	//----------------------
	// construction sphere.
	//-----------------------
	const TopTools_ListOfShape& LLA = myAnalyse.Ancestors(LA.First());
	const TopoDS_Shape& FF = LLA.First();
	Standard_Real CurOffset = myOffset;
	if ( myFaceOffset.IsBound(FF))
	  CurOffset = myFaceOffset(FF);
	
	BRepOffset_Offset OF(V,LOE,CurOffset);
	MapSF.Bind(V,OF);
      }
      //--------------------------------------------------------------
      // Traitemnet particulier si V est sur au moins un bord libre.
      //-------------------------------------------------------------
      TopTools_ListOfShape LBF;
      myAnalyse.Edges(V,BRepOffset_FreeBoundary,LBF);
      if (!LBF.IsEmpty()) {	
	Standard_Boolean First = Standard_True;
	for (it.Initialize(LE) ; it.More(); it.Next()) {
	  if (First) {
	    myInitOffsetEdge.SetRoot(V); // skv: supporting history.
	    myInitOffsetEdge.Bind(V,MapSF(it.Value()).Generated(V));
	    First = Standard_False;
	  }
	  else {
	    myInitOffsetEdge.Add(V,MapSF(it.Value()).Generated(V));
	  }
	} 
      }
    }
  }

  //------------------------------------------------------------
  // Extension des faces paralleles jusq au contexte.
  // Les faces etendues sont rangees en SD et Supprime de MapSF.
  //------------------------------------------------------------
  if (!myFaces.IsEmpty()) ToContext (MapSF);

  //------------------------------------------------------
  // MAJ SD.
  //------------------------------------------------------
  BRepOffset_Type    RT = BRepOffset_Concave;
  if (myOffset < 0.) RT = BRepOffset_Convex;
  BRepOffset_DataMapIteratorOfDataMapOfShapeOffset It(MapSF);
#ifdef DEB
  Standard_Integer MapSFNb = MapSF.Extent();
#endif
  for ( ; It.More(); It.Next()) {
    const TopoDS_Shape& SI = It.Key(); 
    const BRepOffset_Offset& SF = It.Value();
    if (SF.Status() == BRepOffset_Reversed ||
	SF.Status() == BRepOffset_Degenerated ) {
      //------------------------------------------------
      // Les faces degenerees ou retournees ne sont pas 
      // stockes.
      //------------------------------------------------
      continue; 
    }	

    const TopoDS_Face&  OF = It.Value().Face();
    myInitOffsetFace.Bind    (SI,OF);      
    myInitOffsetFace.SetRoot (SI);      // Initial<-> Offset
    myImageOffset.SetRoot    (OF);      // FaceOffset racine des images
    
    if (SI.ShapeType() == TopAbs_FACE) {
      for (Exp.Init(SI.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	   Exp.More(); Exp.Next()) {
	//--------------------------------------------------------------------
	// A chaque face // on associe les edges qui la restreignent
	// Les edges qui ne genere pas de tuyaux ou qui ne sont pas tangentes
	// a deux faces sont supprimees.
	//--------------------------------------------------------------------
	const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
	const BRepOffset_ListOfInterval& L  = myAnalyse.Type(E);
	if (!L.IsEmpty() && L.First().Type() != RT) {
	  TopAbs_Orientation OO  = E.Orientation();
	  TopoDS_Shape aLocalShape = It.Value().Generated(E);
	  TopoDS_Edge        OE  = TopoDS::Edge(aLocalShape);
//	  TopoDS_Edge        OE  = TopoDS::Edge(It.Value().Generated(E));
	  myAsDes->Add (OF,OE.Oriented(OO));
	}
      }
    }
    else {
      for (Exp.Init(OF.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	   Exp.More(); Exp.Next()) {
	myAsDes->Add (OF,Exp.Current());
      }
    }
  }

#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}



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

void BRepOffset_MakeOffset::SelfInter(TopTools_MapOfShape& Modif)
{
#ifdef DEB
  if ( ChronBuild) {
    cout << " AUTODEBOUCLAGE:" << endl;
    Clock.Reset();
    Clock.Start();
  }    
#endif  

  Standard_NotImplemented::Raise();

#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}


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

void BRepOffset_MakeOffset::ToContext (BRepOffset_DataMapOfShapeOffset& MapSF)
{
  TopTools_DataMapOfShapeShape        Created;   
  TopTools_DataMapOfShapeShape        MEF;
  TopTools_MapOfShape                 FacesToBuild;
  TopTools_MapIteratorOfMapOfShape    it(myFaces); 
  TopTools_ListIteratorOfListOfShape  itl;
  TopExp_Explorer                     exp;

//  TopAbs_State       Side = TopAbs_IN;  
//  if (myOffset < 0.) Side = TopAbs_OUT;

  TopAbs_State       Side = TopAbs_OUT; 
 
  for (; it.More(); it.Next()) {
    const TopoDS_Face& CF = TopoDS::Face(it.Key());
    for (exp.Init(CF.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp.More(); exp.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
      if (!myAnalyse.HasAncestor(E)) {
	//----------------------------------------------------------------
	// Les edges des faces de contexte qui ne sont pas dans le shape
	// initiales peuvent apparaitre dans le resultat.
	//----------------------------------------------------------------
	//myAsDes->Add(CF,E);
      }  
    }
  }
  //--------------------------------------------------------
  // Determination des edges et des faces a reconstruire par 
  // intersection.
  //---------------------------------------------------------
  for ( it.Initialize(myFaces); it.More(); it.Next()) {
    const TopoDS_Face& CF = TopoDS::Face(it.Key());
    for (exp.Init(CF.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	 exp.More(); exp.Next()) {
      const TopoDS_Edge& E = TopoDS::Edge(exp.Current()); 
      if (myAnalyse.HasAncestor(E)) {
	const TopTools_ListOfShape& LEA = myAnalyse.Ancestors(E);
	for (itl.Initialize(LEA); itl.More(); itl.Next()) {
	  const BRepOffset_Offset& OF = MapSF(itl.Value());
	  FacesToBuild.Add(itl.Value());
	  MEF.Bind(OF.Generated(E),CF);
	}
 	TopoDS_Vertex V[2];
	TopExp::Vertices(E,V[0],V[1]);
	for (Standard_Integer i = 0; i < 2; i++) {
	  const TopTools_ListOfShape& LVA =  myAnalyse.Ancestors(V[i]);
	  for ( itl.Initialize(LVA); itl.More(); itl.Next()) {
	    const TopoDS_Edge& EV = TopoDS::Edge(itl.Value());
	    if (MapSF.IsBound(EV)) {
	      const BRepOffset_Offset& OF = MapSF(EV);
	      FacesToBuild.Add(EV);
	      MEF.Bind(OF.Generated(V[i]),CF);
	    }
	  }
	}
      }
    }
  }
  //---------------------------
  // Reconstruction des faces.
  //---------------------------
  TopoDS_Face        F,NF;
  BRepOffset_Type    RT = BRepOffset_Concave;
  if (myOffset < 0.) RT = BRepOffset_Convex;
  TopoDS_Shape       OE,NE;
  TopAbs_Orientation Or;

  for (it.Initialize(FacesToBuild); it.More(); it.Next()) {
    const TopoDS_Shape& S   = it.Key();
    BRepOffset_Offset   BOF;
    BOF = MapSF(S);
    F = TopoDS::Face(BOF.Face());
    BRepOffset_Tool::ExtentFace(F,Created,MEF,Side,myTol,NF);
    MapSF.UnBind(S);
    //--------------
    // MAJ SD.
    //--------------
    myInitOffsetFace.Bind    (S,NF);      
    myInitOffsetFace.SetRoot (S);      // Initial<-> Offset
    myImageOffset.SetRoot    (NF);

    if (S.ShapeType() == TopAbs_FACE) {
      for (exp.Init(S.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	   exp.More(); exp.Next()) {
	
	const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
	const BRepOffset_ListOfInterval& L  = myAnalyse.Type(E);
	OE = BOF.Generated(E);
	Or = E.Orientation();
	OE.Orientation(Or);
	if (!L.IsEmpty() && L.First().Type() != RT) {
	  if (Created.IsBound(OE)) {
	    NE = Created(OE); 
	    if (NE.Orientation() == TopAbs_REVERSED) 
	      NE.Orientation(TopAbs::Reverse(Or));
	    else
	      NE.Orientation(Or);
	    myAsDes->Add(NF,NE);
	  }
	  else {
	    myAsDes->Add(NF,OE);
	  }
	}
      }
    }
    else {
      //------------------
      // Tuyau
      //---------------------
      for (exp.Init(NF.Oriented(TopAbs_FORWARD),TopAbs_EDGE); 
	   exp.More(); exp.Next()) {
	myAsDes->Add (NF,exp.Current());
      }
    }    
    MapSF.UnBind(S);
  }

  //----------------
  // MAJ bords libre
  //----------------
  TopTools_DataMapIteratorOfDataMapOfShapeShape itc;
  for (itc.Initialize(Created); itc.More(); itc.Next()) {
    OE = itc.Key();
    NE = itc.Value();
    if (myInitOffsetEdge.IsImage(OE)) {
      TopoDS_Shape E = myInitOffsetEdge.ImageFrom (OE);
      Or = myInitOffsetEdge.Image(E).First().Orientation();
      if (NE.Orientation() == TopAbs_REVERSED) 
	NE.Orientation(TopAbs::Reverse(Or));
      else
	NE.Orientation(Or);
      myInitOffsetEdge.Remove(OE);
      myInitOffsetEdge.Bind(E,NE);
    }
  }
}


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

void BRepOffset_MakeOffset::UpdateFaceOffset()
{
  TopTools_MapOfShape M;
  BRepOffset_DataMapOfShapeReal CopiedMap;
  CopiedMap.Assign(myFaceOffset);
  BRepOffset_DataMapIteratorOfDataMapOfShapeReal it(CopiedMap);

  BRepOffset_Type    RT = BRepOffset_Convex;
  if (myOffset < 0.) RT = BRepOffset_Concave;

  for ( ; it.More(); it.Next()) {
    const TopoDS_Face& F = TopoDS::Face(it.Key());
    Standard_Real CurOffset = CopiedMap(F);
    if ( !M.Add(F)) continue;
    TopoDS_Compound Co;
    BRep_Builder Build;
    Build.MakeCompound(Co);
    TopTools_MapOfShape Dummy;
    Build.Add(Co,F);
    if (myJoin == GeomAbs_Arc)
      myAnalyse.AddFaces(F,Co,Dummy,BRepOffset_Tangent,RT);
    else   
      myAnalyse.AddFaces(F,Co,Dummy,BRepOffset_Tangent);

    TopExp_Explorer exp(Co,TopAbs_FACE);
    for (; exp.More(); exp.Next()) {
      const TopoDS_Face& FF = TopoDS::Face(exp.Current());
      if ( !M.Add(FF)) continue;
      if ( myFaceOffset.IsBound(FF))
	myFaceOffset.UnBind(FF);
      myFaceOffset.Bind(FF,CurOffset);
    }
  }
}

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

void BRepOffset_MakeOffset::CorrectConicalFaces()
{
  TopTools_SequenceOfShape Cones;
  TopTools_SequenceOfShape Circs;
  TopTools_SequenceOfShape Seams;
  Standard_Real TolApex = 1.e-5;

  Standard_Integer i;

  TopTools_DataMapOfShapeListOfShape FacesOfCone;
  //TopTools_DataMapOfShapeShape DegEdges;
  TopExp_Explorer Explo( myOffsetShape, TopAbs_FACE );
  if (myJoin == GeomAbs_Arc)
    {
      for (; Explo.More(); Explo.Next())
	{
	  TopoDS_Face aFace = TopoDS::Face( Explo.Current() );
	  Handle(Geom_Surface) aSurf = BRep_Tool::Surface( aFace );
	  //if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
	  //aSurf = (Handle(Geom_OffsetSurface)::DownCast(aSurf))->BasisSurface(); //???
	  
	  TopTools_IndexedMapOfShape Emap;
	  TopExp::MapShapes( aFace, TopAbs_EDGE, Emap );
	  for (i = 1; i <= Emap.Extent(); i++)
	    {
	      TopoDS_Edge anEdge = TopoDS::Edge( Emap(i) );
	      //Standard_Real f, l;
	      //Handle(Geom_Curve) theCurve = BRep_Tool::Curve( anEdge, f, l );
	      //Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*) &anEdge.TShape());
	      if (BRep_Tool::Degenerated(anEdge))
		{
		  //Check wether anEdge is a really degenerated edge or not
		  BRepAdaptor_Curve BACurve(anEdge, aFace);
		  gp_Pnt Pfirst, Plast, Pmid;
		  Pfirst = BACurve.Value(BACurve.FirstParameter());
		  Plast  = BACurve.Value(BACurve.LastParameter());
		  Pmid   = BACurve.Value((BACurve.FirstParameter()+BACurve.LastParameter())/2.);
		  if (Pfirst.Distance(Plast) <= TolApex &&
		      Pfirst.Distance(Pmid)  <= TolApex)
		    continue;
		  //Cones.Append( aFace );
		  //Circs.Append( anEdge );
		  //TopoDS_Vertex Vdeg = TopExp::FirstVertex( anEdge );
		  TopoDS_Edge OrEdge = 
		    TopoDS::Edge( myInitOffsetEdge.Root( anEdge) );
		  TopoDS_Vertex VF = TopExp::FirstVertex( OrEdge );
		  if ( FacesOfCone.IsBound(VF) )
		    {
		      //add a face to the existing list
		      TopTools_ListOfShape& aFaces = FacesOfCone.ChangeFind(VF);
		      aFaces.Append (aFace);
		      //DegEdges.Bind(aFace, anEdge);
		    }
		  else
		    {
		      //the vertex is not in the map => create a new key and items
		      TopTools_ListOfShape aFaces;
		      aFaces.Append (aFace);
		      FacesOfCone.Bind(VF, aFaces);
		      //DegEdges.Bind(aFace, anEdge);
		    }
		}
	    } //for (i = 1; i <= Emap.Extent(); i++)
	} //for (; fexp.More(); fexp.Next())
    } //if (myJoin == GeomAbs_Arc)

  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape Cone(FacesOfCone);
  BRep_Builder BB;
  TopLoc_Location L;
  for (; Cone.More(); Cone.Next() ) {
    gp_Sphere theSphere;
    Handle(Geom_SphericalSurface) aSphSurf;
    TopoDS_Wire SphereWire;
    BB.MakeWire(SphereWire);
    TopoDS_Vertex anApex = TopoDS::Vertex(Cone.Key());
    const TopTools_ListOfShape& Faces = Cone.Value(); //FacesOfCone(anApex);
    TopTools_ListIteratorOfListOfShape itFaces(Faces);
    Standard_Boolean isFirstFace = Standard_True;
    gp_Pnt FirstPoint;
    TopoDS_Vertex theFirstVertex, CurFirstVertex;
    for (; itFaces.More(); itFaces.Next())
      {
	TopoDS_Face aFace = TopoDS::Face(itFaces.Value()); //TopoDS::Face(Faces.First());
	TopoDS_Edge DegEdge; // = TopoDS::Edge(DegEdges(aFace));
	for (Explo.Init(aFace, TopAbs_EDGE); Explo.More(); Explo.Next())
	  {
	    DegEdge = TopoDS::Edge(Explo.Current());
	    if (BRep_Tool::Degenerated(DegEdge))
	      {
		TopoDS_Edge OrEdge = TopoDS::Edge( myInitOffsetEdge.Root( DegEdge) );
		TopoDS_Vertex VF = TopExp::FirstVertex( OrEdge );
		if (VF.IsSame(anApex))
		  break;
	      }
	  }
	TopoDS_Shape aLocalDegShape = DegEdge.Oriented(TopAbs_FORWARD);
	TopoDS_Edge CurEdge = TopoDS::Edge(aLocalDegShape);
	BB.Degenerated(CurEdge, Standard_False);
	BB.SameRange(CurEdge, Standard_False);
	BB.SameParameter(CurEdge, Standard_False);
	gp_Pnt fPnt, lPnt, mPnt;
	GetEdgePoints(CurEdge, aFace, fPnt, mPnt, lPnt);
	Standard_Real f, l;
	BRep_Tool::Range(CurEdge, f, l);
	if (isFirstFace)
	  {
	    gp_Vec aVec1(fPnt, mPnt);
	    gp_Vec aVec2(fPnt, lPnt);
	    gp_Vec aNorm = aVec1.Crossed(aVec2);
	    gp_Pnt theApex = BRep_Tool::Pnt(anApex);
	    gp_Vec ApexToFpnt(theApex, fPnt);
	    gp_Vec Ydir = aNorm ^ ApexToFpnt;
	    gp_Vec Xdir = Ydir ^ aNorm;
	    //Xdir.Rotate(gp_Ax1(theApex, aNorm), -f);
	    gp_Ax2 anAx2(theApex, gp_Dir(aNorm), gp_Dir(Xdir));
	    theSphere.SetRadius(myOffset);
	    theSphere.SetPosition(gp_Ax3(anAx2) /*gp_Ax3(theApex, gp_Dir(aNorm))*/);
	    aSphSurf = new Geom_SphericalSurface(theSphere);
	    FirstPoint = fPnt;
	    theFirstVertex = BRepLib_MakeVertex(fPnt);
	    CurFirstVertex = theFirstVertex;
	  }

	TopoDS_Vertex v1, v2, FirstVert, EndVert;
	TopExp::Vertices(CurEdge, v1, v2);
	FirstVert = CurFirstVertex;
	if (lPnt.Distance(FirstPoint) <= Precision::Confusion())
	  EndVert = theFirstVertex;
	else
	  EndVert = BRepLib_MakeVertex(lPnt);
	CurEdge.Free( Standard_True );
	BB.Remove(CurEdge, v1);
	BB.Remove(CurEdge, v2);
	BB.Add(CurEdge, FirstVert.Oriented(TopAbs_FORWARD));
	BB.Add(CurEdge, EndVert.Oriented(TopAbs_REVERSED));
	//take the curve from sphere an put it to the edge
	Standard_Real Uf, Vf, Ul, Vl;
	ElSLib::Parameters( theSphere, fPnt, Uf, Vf );
	ElSLib::Parameters( theSphere, lPnt, Ul, Vl );
	if (Abs(Ul) <= Precision::Confusion())
	  Ul = 2.*PI;
	Handle(Geom_Curve) aCurv = aSphSurf->VIso(Vf);
	/*
	if (!isFirstFace)
	  {
	    gp_Circ aCircle = (Handle(Geom_Circle)::DownCast(aCurv))->Circ();
	    if (Abs(Uf - f) > Precision::Confusion())
	      {
		aCircle.Rotate(aCircle.Axis(), f - Uf);
		aCurv = new Geom_Circle(aCircle);
	      }
	  }
	*/
	Handle(Geom_TrimmedCurve) aTrimCurv = new Geom_TrimmedCurve(aCurv, Uf, Ul);
	BB.UpdateEdge(CurEdge, aTrimCurv, Precision::Confusion());
	BB.Range(CurEdge, Uf, Ul, Standard_True);
	Handle(Geom2d_Line) theLin2d = new Geom2d_Line( gp_Pnt2d( 0., Vf ), gp::DX2d() );
	Handle(Geom2d_TrimmedCurve) theTrimLin2d = new Geom2d_TrimmedCurve(theLin2d, Uf, Ul);
	BB.UpdateEdge(CurEdge, theTrimLin2d, aSphSurf, L, Precision::Confusion());
	BB.Range(CurEdge, aSphSurf, L, Uf, Ul);
	BRepLib::SameParameter(CurEdge);
	BB.Add(SphereWire, CurEdge);
	//Modifying correspondent edges in aFace: substitute vertices common with CurEdge
	BRepAdaptor_Curve2d BAc2d(CurEdge, aFace);
	gp_Pnt2d fPnt2d, lPnt2d;
	fPnt2d = BAc2d.Value(BAc2d.FirstParameter());
	lPnt2d = BAc2d.Value(BAc2d.LastParameter());
	TopTools_IndexedMapOfShape Emap;
	TopExp::MapShapes(aFace, TopAbs_EDGE, Emap);
	TopoDS_Edge EE [2];
	Standard_Integer j = 0, k;
	for (k = 1; k <= Emap.Extent(); k++)
	  {
	    const TopoDS_Edge& anEdge = TopoDS::Edge(Emap(k));
	    if (!BRep_Tool::Degenerated(anEdge))
	      {
		TopoDS_Vertex V1, V2;
		TopExp::Vertices(anEdge, V1, V2);
		if (V1.IsSame(v1) || V2.IsSame(v1))
		  EE[j++] = anEdge;
	      }
	  }
	for (k = 0; k < j; k++)
	  {
	    TopoDS_Shape aLocalShape = EE[k].Oriented(TopAbs_FORWARD);
	    TopoDS_Edge Eforward = TopoDS::Edge(aLocalShape);
	    Eforward.Free(Standard_True);
	    TopoDS_Vertex V1, V2;
	    TopExp::Vertices( Eforward, V1, V2 );
	    BRepAdaptor_Curve2d EEc( Eforward, aFace );
	    gp_Pnt2d p2d1, p2d2;
	    p2d1 = EEc.Value(EEc.FirstParameter());
	    p2d2 = EEc.Value(EEc.LastParameter());
	    if (V1.IsSame(v1))
	      {
		TopoDS_Vertex NewV = (p2d1.Distance(fPnt2d) <= Precision::Confusion())?
		  FirstVert : EndVert;
		BB.Remove( Eforward, V1 );
		BB.Add( Eforward, NewV.Oriented(TopAbs_FORWARD) );
	      }
	    else
	      {
		TopoDS_Vertex NewV = (p2d2.Distance(fPnt2d) <= Precision::Confusion())?
		  FirstVert : EndVert;
		BB.Remove( Eforward, V2 );
		BB.Add( Eforward, NewV.Oriented(TopAbs_REVERSED) );
	      }
	  }

	isFirstFace = Standard_False;
	CurFirstVertex = EndVert;
      }
    //Building new spherical face
    Standard_Real Ufirst = RealLast(), Ulast = RealFirst();
    gp_Pnt2d p2d1, p2d2;
    TopTools_ListOfShape EdgesOfWire;
    TopoDS_Iterator itw(SphereWire);
    for (; itw.More(); itw.Next())
      {
	const TopoDS_Edge& anEdge = TopoDS::Edge(itw.Value());
	EdgesOfWire.Append(anEdge);
	Standard_Real f, l;
	Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(anEdge, aSphSurf, L, f, l);
	p2d1 = aC2d->Value(f);
	p2d2 = aC2d->Value(l);
	if (p2d1.X() < Ufirst)
	  Ufirst = p2d1.X();
	if (p2d1.X() > Ulast)
	  Ulast = p2d1.X();
	if (p2d2.X() < Ufirst)
	  Ufirst = p2d2.X();
	if (p2d2.X() > Ulast)
	  Ulast = p2d2.X();
      }
    TopTools_ListOfShape NewEdges;
    TopoDS_Edge FirstEdge;
    TopTools_ListIteratorOfListOfShape itl(EdgesOfWire);
    for (; itl.More(); itl.Next())
      {
	FirstEdge = TopoDS::Edge(itl.Value());
	Standard_Real f, l;
	Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(FirstEdge, aSphSurf, L, f, l);
	p2d1 = aC2d->Value(f);
	p2d2 = aC2d->Value(l);
	if (Abs(p2d1.X() - Ufirst) <= Precision::Confusion())
	  {
	    EdgesOfWire.Remove(itl);
	    break;
	  }
      }
    NewEdges.Append(FirstEdge);
    TopoDS_Vertex Vf1, CurVertex;
    TopExp::Vertices(FirstEdge, Vf1, CurVertex);
    itl.Initialize(EdgesOfWire);
    while (itl.More())
      {
	const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
	TopoDS_Vertex V1, V2;
	TopExp::Vertices(anEdge, V1, V2);
	if (V1.IsSame(CurVertex) || V2.IsSame(CurVertex))
	  {
	    NewEdges.Append(anEdge);
	    CurVertex = (V1.IsSame(CurVertex))? V2 : V1;
	    EdgesOfWire.Remove(itl);
	  }
	else
	  itl.Next();
      }

    Standard_Real Vfirst, Vlast;
    if (p2d1.Y() > 0.)
      {
	Vfirst = p2d1.Y(); Vlast = PI/2.;
      }
    else
      {
	Vfirst = -PI/2.; Vlast = p2d1.Y();
      }
    TopoDS_Face NewSphericalFace = BRepLib_MakeFace(aSphSurf, Ufirst, Ulast, Vfirst, Vlast);
    TopoDS_Edge OldEdge;
    for (Explo.Init(NewSphericalFace, TopAbs_EDGE); Explo.More(); Explo.Next())
      {
	OldEdge = TopoDS::Edge(Explo.Current());
	if (!BRep_Tool::Degenerated(OldEdge))
	  {
	    BRepAdaptor_Curve2d BAc2d(OldEdge, NewSphericalFace);
	    p2d1 = BAc2d.Value(BAc2d.FirstParameter());
	    p2d2 = BAc2d.Value(BAc2d.LastParameter());
	    if (Abs(p2d1.X() - Ufirst) <= Precision::Confusion() &&
		Abs(p2d2.X() - Ulast)  <= Precision::Confusion())
	      break;
	  }
      }
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(OldEdge, V1, V2);
    TopTools_ListOfShape LV1, LV2;
    LV1.Append(Vf1);
    LV2.Append(CurVertex);
    BRepTools_Substitution theSubstitutor;
    theSubstitutor.Substitute(V1, LV1);
    if (!V1.IsSame(V2))
      theSubstitutor.Substitute(V2, LV2);
    theSubstitutor.Substitute(OldEdge, NewEdges);
    theSubstitutor.Build(NewSphericalFace);
    if (theSubstitutor.IsCopied(NewSphericalFace))
      {
	const TopTools_ListOfShape& listSh = theSubstitutor.Copy(NewSphericalFace);
	NewSphericalFace = TopoDS::Face(listSh.First());
      }

    //Adding NewSphericalFace to the shell
    Explo.Init( myOffsetShape, TopAbs_SHELL );
    TopoDS_Shape theShell = Explo.Current();
    theShell.Free( Standard_True );
    BB.Add( theShell, NewSphericalFace );
  }

  Explo.Init( myOffsetShape, TopAbs_SHELL );

  if (Explo.More()) {
    TopoDS_Shape theShell = Explo.Current();
    theShell.Closed( Standard_True );
  }

/*
  //Reconstructing
  BRep_Builder BB;
  for (i = 1; i <= Cones.Length(); i++)
    {
      TopoDS_Face Cone = TopoDS::Face( Cones(i) );
      TopoDS_Edge Circ = TopoDS::Edge( Circs(i) );
      TopoDS_Edge Seam = TopoDS::Edge( Seams(i) );
      if (Circ.IsNull()) //case 1 with big offset
	{
	  //ExtraFace is absent
	  
	  Handle(Geom_Surface) aSurf = BRep_Tool::Surface( Cone ), OffSurf = aSurf;

	  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
	    aSurf = (Handle(Geom_OffsetSurface)::DownCast(aSurf))->BasisSurface();
	  gp_Cone theCone = (Handle(Geom_ConicalSurface)::DownCast(aSurf))->Cone();
	  gp_Pnt apex = theCone.Apex();
	  Standard_Real Uapex, Vapex;
	  ElSLib::Parameters( theCone, apex, Uapex, Vapex );
	  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
	    apex = OffSurf->Value( Uapex, Vapex );

	  //Making new degenerated edge
	  Handle(Geom2d_Line) theLine = GCE2d_MakeLine( gp_Pnt2d( 0., Vapex ), gp_Pnt2d( 2.*PI, Vapex ) );
	  TopoDS_Edge NewEdge;
	  BB.MakeEdge( NewEdge );
	  NewEdge.Orientation(TopAbs_FORWARD);
	  BB.UpdateEdge( NewEdge, theLine, Cone, Precision::Confusion() );
	  BB.Range( NewEdge, 0., 2.*PI );
	  BB.SameParameter( NewEdge, Standard_True );
	  BB.SameRange( NewEdge, Standard_True );
	  BB.Degenerated( NewEdge, Standard_True );
	  TopoDS_Vertex Apex = BRepLib_MakeVertex( apex );
	  BB.Add( NewEdge, Apex.Oriented(TopAbs_FORWARD) );
	  BB.Add( NewEdge, Apex.Oriented(TopAbs_REVERSED) );

	  //Reconstructing Seam
	  Standard_Real f, l, par, cpar;
	  Handle(Geom2d_Curve) theCurve = BRep_Tool::CurveOnSurface( Seam, Cone, f, l );
	  gp_Lin2d aLine = (Handle(Geom2d_Line)::DownCast(theCurve))->Lin2d();
	  par = ElCLib::Parameter( aLine, gp_Pnt2d( Uapex, Vapex ) );
	  TopoDS_Shape aLocalShape = Seam.Oriented(TopAbs_FORWARD);
	  TopoDS_Vertex cver = TopExp::LastVertex( TopoDS::Edge(aLocalShape) );
	  cpar = BRep_Tool::Parameter( cver, Seam, Cone );
	  if (Abs(f-cpar) < Abs(l-cpar))
	    BB.Range( Seam, par, l );
	  else
	    BB.Range( Seam, f, par );
	  Seam.Free( Standard_True );
	  TopoDS_Shape cver1;
	  TopoDS_Iterator iter( Seam );
	  for (; iter.More(); iter.Next())
	    {
	      cver1 = iter.Value();
	      if (cver1.IsSame(cver))
		break;
	    }
	  BB.Remove( Seam, cver1 );
	  if (Abs(f-cpar) < Abs(l-cpar))
	    BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_FORWARD) ) );
	  else
	    BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_REVERSED) ) );

	  //Adding NewEdge into Cone
	  TopoDS_Shape theWire;
	  for (fexp.Init( Cone, TopAbs_WIRE ); fexp.More(); fexp.Next())
	    {
	      theWire = fexp.Current();
	      Standard_Boolean found = Standard_False;
	      for (iter.Initialize( theWire ); iter.More(); iter.Next())
		{
		  if (Seam.IsSame( iter.Value() ))
		    {
		      found = Standard_True;
		      break;
		    }
		}
	      if (found)
		break;
	    }
	  theWire.Free( Standard_True );
	  NewEdge.Orientation( TopAbs::Compose(theWire.Orientation(),TopAbs_REVERSED) );
	  BB.Add( theWire, NewEdge );
	} //end of case 1 with big offset
      else
	{
	  Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*) &Circ.TShape());
	  if (! TE->Degenerated()) //case 1
	    {
	      //Find ExtraFace
	      TopoDS_Face ExtraFace;
	      for (fexp.Init( myOffsetShape, TopAbs_FACE ); fexp.More(); fexp.Next())
		{
		  ExtraFace = TopoDS::Face( fexp.Current() );
		  if (ExtraFace.IsSame( Cone ))
		    continue;
		  Standard_Boolean found = Standard_False;
		  TopExp_Explorer eexp( ExtraFace, TopAbs_EDGE );
		  for (; eexp.More(); eexp.Next())
		    if (Circ.IsSame( eexp.Current() ))
		      {
			found = Standard_True;
			break;
		      }
		  if (found)
		    break;
		}
	      
	      Handle(Geom_Surface) aSurf = BRep_Tool::Surface( Cone ), OffSurf = aSurf;
	      if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		aSurf = (Handle(Geom_OffsetSurface)::DownCast(aSurf))->BasisSurface();
	      gp_Cone theCone = (Handle(Geom_ConicalSurface)::DownCast(aSurf))->Cone();
	      gp_Pnt apex = theCone.Apex();
	      Standard_Real Uapex, Vapex;
	      ElSLib::Parameters( theCone, apex, Uapex, Vapex );
	      if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		apex = OffSurf->Value( Uapex, Vapex );
	      
	      //Making new degenerated edge
	      Handle(Geom2d_Line) theLine = GCE2d_MakeLine( gp_Pnt2d( 0., Vapex ), gp_Pnt2d( 2.*PI, Vapex ) );
	      TopoDS_Edge NewEdge;
	      BB.MakeEdge( NewEdge );
	      NewEdge.Orientation(TopAbs_FORWARD);
	      BB.UpdateEdge( NewEdge, theLine, Cone, BRep_Tool::Tolerance( Circ ) );
	      BB.Range( NewEdge, 0., 2.*PI );
	      BB.SameParameter( NewEdge, Standard_True );
	      BB.SameRange( NewEdge, Standard_True );
	      BB.Degenerated( NewEdge, Standard_True );
	      TopoDS_Vertex Apex = BRepLib_MakeVertex( apex );
	      BB.Add( NewEdge, Apex.Oriented(TopAbs_FORWARD) );
	      BB.Add( NewEdge, Apex.Oriented(TopAbs_REVERSED) );
	      
	      TopoDS_Vertex cver = TopExp::FirstVertex( Circ );
	      
	      //Reconstructing Seam
	      Standard_Real f, l, par, cpar;
	      Handle(Geom2d_Curve) theCurve = BRep_Tool::CurveOnSurface( Seam, Cone, f, l );
	      gp_Lin2d aLine = (Handle(Geom2d_Line)::DownCast(theCurve))->Lin2d();
	      par = ElCLib::Parameter( aLine, gp_Pnt2d( Uapex, Vapex ) );
	      cpar = BRep_Tool::Parameter( cver, Seam, Cone );
	      if (Abs(f-cpar) < Abs(l-cpar))
		BB.Range( Seam, par, l );
	      else
		BB.Range( Seam, f, par );
	      Seam.Free( Standard_True );
	      TopoDS_Shape cver1;
	      TopoDS_Iterator iter( Seam );
	      for (; iter.More(); iter.Next())
		{
		  cver1 = iter.Value();
		  if (cver1.IsSame(cver))
		    break;
		}
	      BB.Remove( Seam, cver1 );
	      if (Abs(f-cpar) < Abs(l-cpar))
		BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_FORWARD) ) );
	      else
		BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_REVERSED) ) );
	      
	      //Removing ExtraFace from the shell
	      fexp.Init( myOffsetShape, TopAbs_SHELL );
	      TopoDS_Shape theShell = fexp.Current();
	      theShell.Free( Standard_True );
	      TopoDS_Shape ExtraFace1;
	      for (iter.Initialize( theShell ); iter.More(); iter.Next())
		{
		  ExtraFace1 = iter.Value();
		  if (ExtraFace1.IsSame(ExtraFace))
		    break;
		}
	      BB.Remove( theShell, ExtraFace1 );
	      
	      //Substitute Circ by NewEdge in Cone
	      TopoDS_Shape theWire;
	      TopoDS_Shape Circ1;
	      for (fexp.Init( Cone, TopAbs_WIRE ); fexp.More(); fexp.Next())
		{
		  theWire = fexp.Current();
		  Standard_Boolean found = Standard_False;
		  for (iter.Initialize( theWire ); iter.More(); iter.Next())
		    {
		      Circ1 = iter.Value();
		      if (Circ1.IsSame(Circ))
			{
			  found = Standard_True;
			  break;
			}
		    }
		  if (found)
		    break;
		}
	      TopAbs_Orientation Or = Circ1.Orientation();
	      theWire.Free( Standard_True );
	      BB.Remove( theWire, Circ1 );
	      BB.Add( theWire, NewEdge.Oriented(Or) );
	    } //end of case 1
	  else // Circ is degenerated
	    {
	      if (myOffset > 0. && myJoin == GeomAbs_Arc) //case 2
		{
		  TopoDS_Vertex cver = TopExp::FirstVertex( Circ );
		  
		  TopoDS_Face OrCone = TopoDS::Face( myInitOffsetFace.Root( Cone ) );
		  Handle(Geom_Surface) aSurf = BRep_Tool::Surface( OrCone ), OffSurf = aSurf;
		  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		    aSurf = (Handle(Geom_OffsetSurface)::DownCast(aSurf))->BasisSurface();
		  gp_Cone theCone = (Handle(Geom_ConicalSurface)::DownCast(aSurf))->Cone();
		  gp_Pnt apex = theCone.Apex();
		  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		    {
		      Standard_Real Uapex, Vapex;
		      ElSLib::Parameters( theCone, apex, Uapex, Vapex );
		      apex = OffSurf->Value( Uapex, Vapex );
		    }

		  Standard_Real f, l;
		  Handle(Geom_Curve) ccur = BRep_Tool::Curve( Circ, f, l );
		  gp_Ax2 Axe2 = (Handle(Geom_Circle)::DownCast(ccur))->Circ().Position();
		  gp_Ax3 Axe3( Axe2 );
		  Axe3.SetLocation( apex );
		  gp_Sphere theSphere( Axe3, myOffset );

		  gp_Pnt OrPnt = BRep_Tool::Pnt(cver);
		  Standard_Real Uor, Vor;
		  ElSLib::Parameters( theSphere, OrPnt, Uor, Vor );
		  TopoDS_Face NewFace;
		  if (Vor > 0.)
		    NewFace = BRepLib_MakeFace( theSphere, 0., 2.*PI, Vor, PI/2. );
		  else
		    NewFace = BRepLib_MakeFace( theSphere, 0., 2.*PI, -PI/2., Vor );
		  
		  //Updating the bound of NewFace
		  TopoDS_Edge Bound;
		  TopExp_Explorer eexp( NewFace, TopAbs_EDGE );
		  for (; eexp.More(); eexp.Next())
		    {
		      Bound = TopoDS::Edge( eexp.Current() );
		      Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*) &Bound.TShape());
		      if (!TE->Degenerated() && !BRepTools::IsReallyClosed( Bound, NewFace ))
			break;
		    }
		  Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( Circ, Cone, f, l );
		  BB.UpdateEdge( Bound, pcurve, Cone, BRep_Tool::Tolerance(Circ) );
		  TopoDS_Vertex bver = TopExp::FirstVertex( Bound );
		  BB.UpdateVertex( bver, BRep_Tool::Tolerance(cver) );
		  
		  //Updating cver in Seam
		  TopoDS_Vertex cver1;
		  TopoDS_Iterator iter( Seam );
		  for (; iter.More(); iter.Next())
		    {
		      cver1 = TopoDS::Vertex( iter.Value() );
		      if (cver1.IsSame(cver))
			break;
		    }
		  TopAbs_Orientation Or = cver1.Orientation();
		  Seam.Free( Standard_True );
		  BB.Remove( Seam, cver1 );
		  BB.Add( Seam, bver.Oriented(Or) );
		  
		  //Substitute Circ by Bound in Cone
		  TopoDS_Shape theWire;
		  TopoDS_Shape Circ1;
		  for (fexp.Init( Cone, TopAbs_WIRE ); fexp.More(); fexp.Next())
		    {
		      theWire = fexp.Current();
		      Standard_Boolean found = Standard_False;
		      for (iter.Initialize( theWire ); iter.More(); iter.Next())
			{
			  Circ1 = iter.Value();
			  if (Circ1.IsSame(Circ))
			    {
			      found = Standard_True;
			      break;
			    }
			}
		      if (found)
			break;
		    }
		  Or = Circ1.Orientation();
		  theWire.Free( Standard_True );
		  BB.Remove( theWire, Circ1 );
		  BB.Add( theWire, Bound.Oriented(Or) );
		  
		  //Adding NewFace to the shell
		  fexp.Init( myOffsetShape, TopAbs_SHELL );
		  TopoDS_Shape theShell = fexp.Current();
		  theShell.Free( Standard_True );
		  BB.Add( theShell, NewFace );
		  
		  theShell.Closed( Standard_True );
		} //end of case 2
	      else // if ((myOffset > 0. && myJoin == GeomAbs_Intersection) || myOffset < 0.) //case 3, 4
		{
		  Handle(Geom_Surface) aSurf = BRep_Tool::Surface( Cone ), OffSurf = aSurf;
		  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		    aSurf = (Handle(Geom_OffsetSurface)::DownCast(aSurf))->BasisSurface();
		  gp_Cone theCone = (Handle(Geom_ConicalSurface)::DownCast(aSurf))->Cone();
		  gp_Pnt apex = theCone.Apex();
		  Standard_Real Uapex, Vapex;
		  ElSLib::Parameters( theCone, apex, Uapex, Vapex );
		  if (aSurf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface))
		    apex = OffSurf->Value( Uapex, Vapex );
		  
		  //Making new degenerated edge
		  Handle(Geom2d_Line) theLine = GCE2d_MakeLine( gp_Pnt2d( 0., Vapex ), gp_Pnt2d( 2.*PI, Vapex ) );
		  TopoDS_Edge NewEdge;
		  BB.MakeEdge( NewEdge );
		  NewEdge.Orientation(TopAbs_FORWARD);
		  BB.UpdateEdge( NewEdge, theLine, Cone, BRep_Tool::Tolerance( Circ ) );
		  BB.Range( NewEdge, 0., 2.*PI );
		  BB.SameParameter( NewEdge, Standard_True );
		  BB.SameRange( NewEdge, Standard_True );
		  BB.Degenerated( NewEdge, Standard_True );
		  TopoDS_Vertex Apex = BRepLib_MakeVertex( apex );
		  BB.Add( NewEdge, Apex.Oriented(TopAbs_FORWARD) );
		  BB.Add( NewEdge, Apex.Oriented(TopAbs_REVERSED) );
		  
		  TopoDS_Vertex cver = TopExp::FirstVertex( Circ );
		  
		  //Reconstructing Seam
		  Standard_Real f, l, par, cpar;
		  Handle(Geom2d_Curve) theCurve = BRep_Tool::CurveOnSurface( Seam, Cone, f, l );
		  gp_Lin2d aLine = (Handle(Geom2d_Line)::DownCast(theCurve))->Lin2d();
		  par = ElCLib::Parameter( aLine, gp_Pnt2d( Uapex, Vapex ) );
		  cpar = BRep_Tool::Parameter( cver, Seam, Cone );
		  if (Abs(f-cpar) < Abs(l-cpar))
		    BB.Range( Seam, par, l );
		  else
		    BB.Range( Seam, f, par );
		  Seam.Free( Standard_True );
		  TopoDS_Shape cver1;
		  TopoDS_Iterator iter( Seam );
		  for (; iter.More(); iter.Next())
		    {
		      cver1 = iter.Value();
		      if (cver1.IsSame(cver))
			break;
		    }
		  BB.Remove( Seam, cver1 );
		  if (Abs(f-cpar) < Abs(l-cpar))
		    BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_FORWARD) ) );
		  else
		    BB.Add( Seam, Apex.Oriented( TopAbs::Compose(Seam.Orientation(),TopAbs_REVERSED) ) );
		  
		  //Substitute Circ by NewEdge in Cone
		  TopoDS_Shape theWire;
		  TopoDS_Shape Circ1;
		  for (fexp.Init( Cone, TopAbs_WIRE ); fexp.More(); fexp.Next())
		    {
		      theWire = fexp.Current();
		      Standard_Boolean found = Standard_False;
		      for (iter.Initialize( theWire ); iter.More(); iter.Next())
			{
			  Circ1 = iter.Value();
			  if (Circ1.IsSame(Circ))
			    {
			      found = Standard_True;
			      break;
			    }
			}
		      if (found)
			break;
		    }
		  TopAbs_Orientation Or = Circ1.Orientation();
		  theWire.Free( Standard_True );
		  BB.Remove( theWire, Circ1 );
		  BB.Add( theWire, NewEdge.Oriented(Or) );
		  
		  fexp.Init( myOffsetShape, TopAbs_SHELL );
		  TopoDS_Shape theShell = fexp.Current();
		  theShell.Closed( Standard_True );
		} //end of case 3, 4
	    }
	} //else (! Circ.IsNull())
    }
*/

  Standard_Integer            NbShell = 0;
  TopoDS_Compound             NC;
  TopoDS_Shape                S1;
  BB.MakeCompound (NC);
  
  for (Explo.Init(myOffsetShape,TopAbs_SHELL); Explo.More(); Explo.Next()) {
    const TopoDS_Shell& Sh = TopoDS::Shell(Explo.Current());
    NbShell++;
    if (Sh.Closed()) {
      TopoDS_Solid  Sol;
      BB.MakeSolid  (Sol);
      BB.Add        (Sol,Sh);
      Sol.Closed(Standard_True);
      BB.Add (NC,Sol);
      if (NbShell == 1) S1 = Sol;
    }
    else {
      BB.Add (NC,Sh);
      if (NbShell == 1) S1 = Sh;
    }
  }
  if (NbShell == 1) myOffsetShape = S1;
  else              myOffsetShape = NC;
}


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

void BRepOffset_MakeOffset::Intersection3D(BRepOffset_Inter3d& Inter)
{
#ifdef DEB
  if (ChronBuild) {
    cout << " INTERSECTION 3D:" << endl;
    Clock.Reset();
    Clock.Start();  
  }
#endif
  TopTools_ListOfShape OffsetFaces;  // liste des faces // crees.
  MakeList (OffsetFaces,myInitOffsetFace,myFaces);

  if (!myFaces.IsEmpty()) {     
    Standard_Boolean InSide = (myOffset < 0.); // PROVISOIRE 
    // il faut calculer Inside en tenant compte de la concavite ou convexite des arretes
    // entre le bouchon et la piece.

    if (myJoin == GeomAbs_Arc) 
      Inter.ContextIntByArc (myFaces,InSide,myAnalyse,myInitOffsetFace,myInitOffsetEdge);
  }
  if (myInter) {
    //-------------
    //Complet.
    //-------------
    Inter.CompletInt (OffsetFaces,myInitOffsetFace);
    TopTools_MapOfShape& NewEdges = Inter.NewEdges();
    if (myJoin == GeomAbs_Intersection) {
      BRepOffset_Tool::CorrectOrientation (myShape,NewEdges,myAsDes,myInitOffsetFace,myOffset);
    }
  }
  else {
    //--------------------------------
    // Seulememt entre face voisines.
    //--------------------------------
    Inter.ConnexIntByArc(OffsetFaces,myShape,myAnalyse,myInitOffsetFace);
  }
#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}

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

void BRepOffset_MakeOffset::Intersection2D(const TopTools_MapOfShape& Modif,
					   const TopTools_MapOfShape& NewEdges)
{
#ifdef DEB
  if (ChronBuild) {
    cout << " INTERSECTION 2D:" << endl;
    Clock.Reset();
    Clock.Start();  
  }
#endif
  //-----------------------------------------------------------
  // calcul des intersections2d sur les faces touchees par les 
  // intersection3d
  //---------------------------------------------------------
  TopTools_MapIteratorOfMapOfShape it(Modif);
  //-----------------------------------------------
  // Intersection des edges 2 a 2.
  //-----------------------------------------------
  for ( it.Initialize(Modif); it.More(); it.Next()) {
    const TopoDS_Face&                 F  = TopoDS::Face(it.Key());
    BRepOffset_Inter2d::Compute(myAsDes,F,NewEdges,myTol);
  }

#ifdef DEB
  if (AffichInt2d) {
    DEBVerticesControl (NewEdges,myAsDes);
  }
  if ( ChronBuild) Clock.Show();
#endif
}


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

void BRepOffset_MakeOffset::MakeLoops(TopTools_MapOfShape& Modif)
{
#ifdef DEB
  if (ChronBuild) {
     cout << " DEBOUCLAGE 2D:" << endl;
     Clock.Reset();
     Clock.Start(); 
  }
#endif
  TopTools_MapIteratorOfMapOfShape    it(Modif);
  TopTools_ListOfShape                LF,LC;
  //-----------------------------------------
  // debouclage des faces // modifiees.
  //-----------------------------------------
  for (; it.More(); it.Next()) { 
    if (!myFaces.Contains(it.Key())) LF.Append(it.Key());
  }
  myMakeLoops.Build(LF,myAsDes,myImageOffset);

  //-----------------------------------------
  // debouclage des bouchons.
  //-----------------------------------------
  for (it.Initialize(myFaces); it.More(); it.Next()) { 
    LC.Append(it.Key());
  }
  Standard_Boolean   InSide = 1;
  if (myOffset > 0 ) InSide = 0;
  myMakeLoops.BuildOnContext(LC,myAnalyse,myAsDes,myImageOffset,InSide);

#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}

//=======================================================================
//function : MakeFaces
//purpose  : Reconstruction des faces topologiquement inchangees qui
//           partage des edges qui ont ete reconstruites.
//=======================================================================

void BRepOffset_MakeOffset::MakeFaces(TopTools_MapOfShape& Modif)
{
#ifdef DEb
  if (ChronBuild) {  
    cout << " RECONSTRUCTION DES FACES:" << endl;
    Clock.Reset();
    Clock.Start();
  }
#endif
  TopTools_ListIteratorOfListOfShape itr;
  const TopTools_ListOfShape& Roots = myInitOffsetFace.Roots();
  TopTools_ListOfShape        LOF;
  //----------------------------------
  // Boucle sur toutes les faces //.
  //----------------------------------
  for (itr.Initialize(Roots); itr.More(); itr.Next()) {
    TopoDS_Face F = TopoDS::Face(myInitOffsetFace.Image(itr.Value()).First());
    LOF.Append(F);
  }
  myMakeLoops.BuildFaces(LOF,myAsDes,myImageOffset);
  
#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}

//=======================================================================
//function : UpdateInitOffset
//purpose  : mis a jour et purge de myInitOffset 
//=======================================================================

static void UpdateInitOffset (BRepAlgo_Image&         myInitOffset,
			      BRepAlgo_Image&         myImageOffset,
			      const TopoDS_Shape&     myOffsetShape,
			      const TopAbs_ShapeEnum &theShapeType) // skv
{
  BRepAlgo_Image NIOF;
  const TopTools_ListOfShape& Roots = myInitOffset.Roots();
  TopTools_ListIteratorOfListOfShape it(Roots);
  for (; it.More(); it.Next()) {
    NIOF.SetRoot (it.Value());    
  }
  for (it.Initialize(Roots); it.More(); it.Next()) {
    const TopoDS_Shape& SI = it.Value();
    TopTools_ListOfShape LI;
    TopTools_ListOfShape L1;
    myInitOffset.LastImage(SI,L1);
    TopTools_ListIteratorOfListOfShape itL1(L1);
    for (; itL1.More(); itL1.Next()) {
      const TopoDS_Shape& O1 = itL1.Value();
      TopTools_ListOfShape L2;
      myImageOffset.LastImage(O1,L2);
      LI.Append(L2);
    }
    NIOF.Bind(SI,LI);
  }
//  Modified by skv - Mon Apr  4 18:17:27 2005 Begin
//  Supporting history.
//   NIOF.Filter(myOffsetShape,TopAbs_FACE);
  NIOF.Filter(myOffsetShape, theShapeType);
//  Modified by skv - Mon Apr  4 18:17:27 2005 End
  myInitOffset = NIOF;
}

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

void BRepOffset_MakeOffset::MakeShells ()
{
#ifdef DEB
  if (ChronBuild) {  
    cout << " RECONSTRUCTION DES SHELLS:" << endl;
    Clock.Reset();
    Clock.Start();
  }
#endif
  BRepTools_Quilt Glue;
  const TopTools_ListOfShape& R = myImageOffset.Roots();
  TopTools_ListIteratorOfListOfShape it(R);

  for ( ; it.More(); it.Next()) {
    TopTools_ListOfShape Image;
    myImageOffset.LastImage(it.Value(),Image);
    TopTools_ListIteratorOfListOfShape it2(Image);
    for ( ; it2.More(); it2.Next()) {
      Glue.Add(it2.Value());
    }
  }
  myOffsetShape = Glue.Shells();
}

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

void BRepOffset_MakeOffset::MakeSolid ()
{
 if (myOffsetShape.IsNull()) return;

//  Modified by skv - Mon Apr  4 18:17:27 2005 Begin
//  Supporting history.
  UpdateInitOffset (myInitOffsetFace,myImageOffset,myOffsetShape, TopAbs_FACE);
  UpdateInitOffset (myInitOffsetEdge,myImageOffset,myOffsetShape, TopAbs_EDGE);
//  Modified by skv - Mon Apr  4 18:17:27 2005 End
  TopExp_Explorer             exp;
  BRep_Builder                B;
  Standard_Integer            NbShell = 0;
  TopoDS_Compound             NC;
  TopoDS_Shape                S1;
  B.MakeCompound (NC);

  for (exp.Init(myOffsetShape,TopAbs_SHELL); exp.More(); exp.Next()) {
    const TopoDS_Shell& Sh = TopoDS::Shell(exp.Current());
    NbShell++;
    if (Sh.Closed()) {
      TopoDS_Solid  Sol;
      B.MakeSolid  (Sol);
      B.Add        (Sol,Sh);
      Sol.Closed(Standard_True);
      B.Add (NC,Sol);
      if (NbShell == 1) S1 = Sol;
    }
    else {
      B.Add (NC,Sh);
      if (NbShell == 1) S1 = Sh;
    }
  }
  if (NbShell == 1) myOffsetShape = S1;
  else              myOffsetShape = NC;
}

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

void BRepOffset_MakeOffset::SelectShells ()
{  
  TopTools_MapOfShape FreeEdges;
  TopExp_Explorer exp(myShape,TopAbs_EDGE);
  //-------------------------------------------------------------
  // FreeEdges ensemble des edges qui peuvent etre bord libre dans 
  // le shell parallele
  // 1 - les bord libres de myShape .
  //-------------------------------------------------------------
  for ( ; exp.More(); exp.Next()) {
    const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
    const TopTools_ListOfShape& LA = myAnalyse.Ancestors(E);
    if (LA.Extent() < 2) {
      if (myAnalyse.Type(E).First().Type() == BRepOffset_FreeBoundary) {
	FreeEdges.Add(E);                       
      }
    }  
  }
  // myShape a des bords libres et il n y a pas de bouchons.
  // pas de debouclage3d.
  if (!FreeEdges.IsEmpty() && myFaces.IsEmpty()) return;

  myOffsetShape = BRepOffset_Tool::Deboucle3D(myOffsetShape,FreeEdges);
}

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

const BRepAlgo_Image& BRepOffset_MakeOffset::OffsetFacesFromShapes() const
{
  return myInitOffsetFace;
}

//  Modified by skv - Tue Mar 15 16:20:43 2005 Begin

//=======================================================================
//function : GetJoinType
//purpose  : Query offset join type.
//=======================================================================

GeomAbs_JoinType BRepOffset_MakeOffset::GetJoinType() const
{
  return myJoin;
}

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

const BRepAlgo_Image& BRepOffset_MakeOffset::OffsetEdgesFromShapes() const
{
  return myInitOffsetEdge;
}

//  Modified by skv - Tue Mar 15 16:20:43 2005 End

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

const TopTools_MapOfShape& BRepOffset_MakeOffset::ClosingFaces () const
{
  return myFaces;
}



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

void BRepOffset_MakeOffset::EncodeRegularity ()
{
#ifdef DEB
  if (ChronBuild) {  
    cout << " CODAGE DES REGULARITES:" << endl;
    Clock.Reset();
    Clock.Start();
  }
#endif

  if (myOffsetShape.IsNull()) return;
  // recherche des edges G1 dans le resultat
  TopExp_Explorer exp(myOffsetShape,TopAbs_EDGE);

  BRep_Builder B;
  TopTools_MapOfShape MS;

  for ( ; exp.More(); exp.Next()) {
    TopoDS_Edge OE  = TopoDS::Edge(exp.Current());
    BRepLib::BuildCurve3d(OE,myTol);
    TopoDS_Edge ROE = OE;
    
    if ( !MS.Add(OE)) continue;
      
    if ( myImageOffset.IsImage(OE)) 
      ROE = TopoDS::Edge(myImageOffset.Root(OE));

    const TopTools_ListOfShape& LofOF    = myAsDes->Ascendant(ROE);
    
    if (LofOF.Extent() != 2) {
#ifdef DEB
      if ( Standard_False)
	cout << " Edge partage par " << LofOF.Extent() << " Faces" << endl;
#endif
      continue;
    }

    const TopoDS_Face& F1 = TopoDS::Face(LofOF.First());
    const TopoDS_Face& F2 = TopoDS::Face(LofOF.Last() );
    
    if ( F1.IsNull() || F2.IsNull()) 
      continue;
   
    const TopoDS_Shape& Root1 = myInitOffsetFace.Root(F1);
    const TopoDS_Shape& Root2 = myInitOffsetFace.Root(F2);

    TopAbs_ShapeEnum Type1 = Root1.ShapeType();
    TopAbs_ShapeEnum Type2 = Root2.ShapeType();
 
    if (F1.IsSame(F2)) {      
      if (BRep_Tool::IsClosed(OE,F1)) {
	// Debug provisoire pour le Bench.
	// Voir avec YFR.
	// En mode intersection, les aretes ne sont pas codees dans myInitOffsetEdge
	// on gere donc au cas par cas.
	// Remarque DUB; Pour les parties cachees, il FAUT coder CN 
	//  les Surf Analytiques.
	if (myJoin == GeomAbs_Intersection) {
	  BRepAdaptor_Surface BS(F1,Standard_False);
	  GeomAbs_SurfaceType SType = BS.GetType();
	  if (SType == GeomAbs_Cylinder ||
	      SType == GeomAbs_Cone     ||
	      SType == GeomAbs_Sphere   ||
	      SType == GeomAbs_Torus      ) {
	    B.Continuity(OE,F1,F1,GeomAbs_CN);
	  }
	  else {
	    // Voir YFR : MaJ de myInitOffsetFace
	  }
	}
	else if (myInitOffsetEdge.IsImage(ROE)) {
	  if ( Type1 == TopAbs_FACE && Type2 == TopAbs_FACE) {
	    const TopoDS_Face& FRoot = TopoDS::Face(Root1);
	    const TopoDS_Edge& EI = TopoDS::Edge(myInitOffsetEdge.ImageFrom(ROE));
	    GeomAbs_Shape Conti = BRep_Tool::Continuity(EI,FRoot,FRoot);
	    if (Conti == GeomAbs_CN) {
	      B.Continuity(OE,F1,F1,GeomAbs_CN);
	    }
	    else if ( Conti > GeomAbs_C0) {
	      B.Continuity(OE,F1,F1,GeomAbs_G1);
	    }
	  }
	}
      }
      continue;
    }


    // on code les regularites G1 entre :
    //    - sphere et tuyau : une root est un vertex, l'autre un edge 
    //                        et le vertex est inclus dans l'edge
    //    - face et tuyau   : une root est une face, l'autre un edge 
    //                        et l'edge est inclus dans la face
    //    - face et face    : si les 2 faces root sont tangentes dans 
    //                        le shape initial, elles le seront dans 
    //                        le shape offset
    //    - tuyau et tuyau  : si les 2 edges generant les tuyaux sont
    //                        tangents, les 2 tuyaux le seront.
    if ( Type1 == TopAbs_EDGE && Type2 == TopAbs_VERTEX) {
      TopoDS_Vertex V1,V2;
      TopExp::Vertices(TopoDS::Edge(Root1), V1, V2);
      if ( V1.IsSame(Root2) || V2.IsSame(Root2)) {
	B.Continuity(OE,F1,F2,GeomAbs_G1);
      }
    }
    else if ( Type1 == TopAbs_VERTEX && Type2 == TopAbs_EDGE) {
      TopoDS_Vertex V1,V2;
      TopExp::Vertices(TopoDS::Edge(Root2), V1, V2);
      if ( V1.IsSame(Root1) || V2.IsSame(Root1)) {
	B.Continuity(OE,F1,F2,GeomAbs_G1);
      }
    }
    else if ( Type1 == TopAbs_FACE && Type2 == TopAbs_EDGE) {
      TopExp_Explorer exp2(Root1,TopAbs_EDGE);
      for ( ; exp2.More(); exp2.Next()) {
	if ( exp2.Current().IsSame(Root2)) {
	  B.Continuity(OE,F1,F2,GeomAbs_G1);
	  break;
	}
      }
    }
    else if ( Type1 == TopAbs_EDGE && Type2 == TopAbs_FACE) {
      TopExp_Explorer exp2(Root2,TopAbs_EDGE);
      for ( ; exp2.More(); exp2.Next()) {
	if ( exp2.Current().IsSame(Root1)) {
	  B.Continuity(OE,F1,F2,GeomAbs_G1);
	  break;
	}
      }
    }
    else if ( Type1 == TopAbs_FACE && Type2 == TopAbs_FACE) {
      // si les 2 faces root sont tangentes dans le shape initial,
      // elles le seront dans le shape offset
      TopTools_ListOfShape LE,LV;
      BRepOffset_Tool::HasCommonShapes(TopoDS::Face(Root1),
				       TopoDS::Face(Root2),
				       LE,LV);
      if ( LE.Extent() == 1) { 
	const TopoDS_Edge& Ed = TopoDS::Edge(LE.First());
	if ( myAnalyse.HasAncestor(Ed)) {
	  const BRepOffset_ListOfInterval& LI = myAnalyse.Type(Ed);
	  if (LI.Extent()       == 1   && 
	      LI.First().Type() == BRepOffset_Tangent) {
	    B.Continuity(OE,F1,F2,GeomAbs_G1);
	  }
	}
      }
    }
    else if ( Type1 == TopAbs_EDGE && Type2 == TopAbs_EDGE) {
      TopTools_ListOfShape LV;
      TopExp_Explorer exp1,exp2;
      for (exp1.Init(Root1,TopAbs_VERTEX); exp1.More(); exp1.Next()) {
	TopExp_Explorer exp2(F2,TopAbs_EDGE);
	for (exp2.Init(Root2,TopAbs_VERTEX); exp2.More(); exp2.Next()) {
	  if (exp1.Current().IsSame(exp2.Current())) {
	    LV.Append(exp1.Current());
	  }
	}
      }
      if ( LV.Extent() == 1) {
	TopTools_ListOfShape LEdTg;
	myAnalyse.TangentEdges(TopoDS::Edge(Root1),
			       TopoDS::Vertex(LV.First()),
			       LEdTg);
	TopTools_ListIteratorOfListOfShape it(LEdTg);
	for (; it.More(); it.Next()) {
	  if ( it.Value().IsSame(Root2)) {
	    B.Continuity(OE,F1,F2,GeomAbs_G1);
	    break;
	  }
	}
      }
    }
  }

#ifdef DEB
  if ( ChronBuild) Clock.Show();
#endif
}



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

static void UpdateTolerance (TopoDS_Shape& S,
			     const TopTools_MapOfShape& Faces)
{
  BRep_Builder B;
  TopTools_MapOfShape View;
  TopoDS_Vertex V[2];

  // Les edges des bouchons ne sont pas modifiees.
  TopTools_MapIteratorOfMapOfShape it;
  for (it.Initialize(Faces); it.More(); it.Next()) {
    const TopoDS_Shape& F = it.Key();
    TopExp_Explorer Exp;
    for (Exp.Init(F,TopAbs_EDGE); Exp.More(); Exp.Next()) {
      View.Add(Exp.Current());
    }
  }
  
  TopExp_Explorer Exp;
  for (Exp.Init(S,TopAbs_EDGE); Exp.More(); Exp.Next()) {
    TopoDS_Edge E = TopoDS::Edge(Exp.Current());
    if (View.Add(E)) {
      Handle(BRepCheck_Edge) EdgeCorrector = new BRepCheck_Edge(E);
      Standard_Real    Tol = EdgeCorrector->Tolerance();
      B.UpdateEdge (E,Tol);
      
      // Update the vertices.
      TopExp::Vertices(E,V[0],V[1]);
     
      for (Standard_Integer i = 0 ; i <=1 ; i++) {
	if (View.Add(V[i])) {
	  Handle(BRep_TVertex) TV = Handle(BRep_TVertex)::DownCast(V[i].TShape());
	  TV->Tolerance(0.);
	  Handle(BRepCheck_Vertex) VertexCorrector = new BRepCheck_Vertex(V[i]);
	  B.UpdateVertex (V[i],VertexCorrector->Tolerance());
	  // on profite de l occasion pour purger le vertex.
	  (TV->ChangePoints()).Clear();
	}
	B.UpdateVertex(V[i],Tol);
      }
    }
  }
}

