Logo Search packages:      
Sourcecode: opencascade version File versions  Download package

BRepOffset_MakeOffset.cxx

// 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);
      }
    }
  }
}


Generated by  Doxygen 1.6.0   Back to index