// Created on: 1994-10-03
// Created by: Bruno DUMORTIER
// Copyright (c) 1994-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#include <Bisector_Bisec.hxx>
#include <Bisector_BisecAna.hxx>
#include <Bnd_Box2d.hxx>
#include <BndLib_Add2dCurve.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAlgo_FaceRestrictor.hxx>
#include <BRepAlgo_Loop.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <MAT_Node.hxx>
#include <TopoDS_Shape.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_DataMap.hxx>
#include <gp_Pnt.hxx>
#include <NCollection_Sequence.hxx>
#include <BRepFill_Evolved.hxx>
#include <BRepFill_OffsetAncestors.hxx>
#include <BRepFill_OffsetWire.hxx>
#include <BRepFill_Pipe.hxx>
#include <BRepFill_TrimSurfaceTool.hxx>
#include <BRepLib.hxx>
#include <BRepLib_FindSurface.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeFace.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRepLProp.hxx>
#include <BRepMAT2d_BisectingLocus.hxx>
#include <BRepMAT2d_Explorer.hxx>
#include <BRepMAT2d_LinkTopoBilo.hxx>
#include <BRepSweep_Prism.hxx>
#include <BRepSweep_Revol.hxx>
#include <BRepTools.hxx>
#include <BRepTools_Modifier.hxx>
#include <BRepTools_Quilt.hxx>
#include <BRepTools_TrsfModification.hxx>
#include <BRepTools_WireExplorer.hxx>
#include <Geom2d_Circle.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAPI_ExtremaCurveCurve.hxx>
#include <Geom2dInt_GInter.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_Surface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomProjLib.hxx>
#include <gp.hxx>
#include <gp_Ax1.hxx>
#include <gp_Ax3.hxx>
#include <gp_Circ2d.hxx>
#include <gp_Dir.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Trsf.hxx>
#include <gp_Vec.hxx>
#include <gp_Vec2d.hxx>
#include <IntRes2d_IntersectionPoint.hxx>
#include <MAT2d_CutCurve.hxx>
#include <MAT_Arc.hxx>
#include <MAT_BasicElt.hxx>
#include <MAT_Graph.hxx>
#include <MAT_Side.hxx>
#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>
#include <Standard_NoSuchObject.hxx>
#include <Standard_NotImplemented.hxx>
#include <TopAbs.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Solid.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>

// #define DRAW
#ifdef DRAW
  #include <DBRep.hxx>
  #include <DrawTrSurf.hxx>
  #include <stdio.h>
static bool AffichGeom  = false;
static bool AffichEdge  = false;
static int  NbFACES     = 0;
static int  NbTRIMFACES = 0;
static int  NbVEVOS     = 0;
static int  NbPROFILS   = 0;
static int  NbEDGES     = 0;
#endif

static double BRepFill_Confusion()
{
  double Tol = 1.e-6;
  return Tol;
}

static const TopoDS_Wire PutProfilAt(const TopoDS_Wire& ProfRef,
                                     const gp_Ax3&      AxeRef,
                                     const TopoDS_Edge& E,
                                     const TopoDS_Face& F,
                                     const bool         AtStart);

static void TrimFace(const TopoDS_Face&                  Face,
                     NCollection_Sequence<TopoDS_Shape>& TheEdges,
                     NCollection_Sequence<TopoDS_Shape>& S);

static void TrimEdge(const TopoDS_Edge&                        Edge,
                     const NCollection_Sequence<TopoDS_Shape>& TheEdgesControle,
                     NCollection_Sequence<TopoDS_Shape>&       TheVer,
                     NCollection_Sequence<double>&             ThePar,
                     NCollection_Sequence<TopoDS_Shape>&       S);

static int PosOnFace(double d1, double d2, double d3);

static void ComputeIntervals(const NCollection_Sequence<TopoDS_Shape>& VonF,
                             const NCollection_Sequence<TopoDS_Shape>& VOnL,
                             const NCollection_Sequence<gp_Pnt>&       ParOnF,
                             const NCollection_Sequence<gp_Pnt>&       ParOnL,
                             const BRepFill_TrimSurfaceTool&           Trim,
                             const occ::handle<Geom2d_Curve>&          Bis,
                             const TopoDS_Vertex&                      VS,
                             const TopoDS_Vertex&                      VE,
                             NCollection_Sequence<double>&             FirstPar,
                             NCollection_Sequence<double>&             LastPar,
                             NCollection_Sequence<TopoDS_Shape>&       FirstV,
                             NCollection_Sequence<TopoDS_Shape>&       LastV);

static double DistanceToOZ(const TopoDS_Vertex& V);

static double Altitud(const TopoDS_Vertex& V);

static bool DoubleOrNotInFace(const NCollection_Sequence<TopoDS_Shape>& EC, const TopoDS_Vertex& V);

static void SimpleExpression(const Bisector_Bisec& B, occ::handle<Geom2d_Curve>& Bis);

static TopAbs_Orientation Relative(const TopoDS_Wire&   W1,
                                   const TopoDS_Wire&   W2,
                                   const TopoDS_Vertex& V,
                                   bool&                Commun);

static void CutEdge(const TopoDS_Edge&              E,
                    const TopoDS_Face&              F,
                    NCollection_List<TopoDS_Shape>& Cuts);

static void CutEdgeProf(
  const TopoDS_Edge&                                                        E,
  const occ::handle<Geom_Plane>&                                            Plane,
  const occ::handle<Geom2d_Line>&                                           Line,
  NCollection_List<TopoDS_Shape>&                                           Cuts,
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapVerRefMoved);

static int VertexFromNode(
  const occ::handle<MAT_Node>& aNode,
  const TopoDS_Edge&           E,
  const TopoDS_Vertex&         VF,
  const TopoDS_Vertex&         VL,
  NCollection_DataMap<occ::handle<MAT_Node>,
                      NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>>&
                 MapNodeVertex,
  TopoDS_Vertex& VS);

//=================================================================================================

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

//=================================================================================================

BRepFill_Evolved::BRepFill_Evolved()
    : myIsDone(false),
      mySpineType(true)
{
}

//=================================================================================================

BRepFill_Evolved::BRepFill_Evolved(const TopoDS_Wire&     Spine,
                                   const TopoDS_Wire&     Profile,
                                   const gp_Ax3&          AxeProf,
                                   const GeomAbs_JoinType Join,
                                   const bool             Solid)

    : myIsDone(false)
{
  Perform(Spine, Profile, AxeProf, Join, Solid);
}

//=================================================================================================

BRepFill_Evolved::BRepFill_Evolved(const TopoDS_Face&     Spine,
                                   const TopoDS_Wire&     Profile,
                                   const gp_Ax3&          AxeProf,
                                   const GeomAbs_JoinType Join,
                                   const bool             Solid)
    : myIsDone(false)
{
  Perform(Spine, Profile, AxeProf, Join, Solid);
}

//=================================================================================================

static bool IsVertical(const TopoDS_Edge& E)
{
  TopoDS_Vertex V1, V2;
  TopExp::Vertices(E, V1, V2);
  gp_Pnt P1 = BRep_Tool::Pnt(V1);
  gp_Pnt P2 = BRep_Tool::Pnt(V2);

  if (std::abs(P1.Y() - P2.Y()) < BRepFill_Confusion())
  {
    // It is a Line ?
    TopLoc_Location         Loc;
    double                  f, l;
    occ::handle<Geom_Curve> GC = BRep_Tool::Curve(E, Loc, f, l);
    if (GC->DynamicType() == STANDARD_TYPE(Geom_Line))
      return true;
  }
  return false;
}

//=================================================================================================

static bool IsPlanar(const TopoDS_Edge& E)
{
  TopoDS_Vertex V1, V2;
  TopExp::Vertices(E, V1, V2);
  gp_Pnt P1 = BRep_Tool::Pnt(V1);
  gp_Pnt P2 = BRep_Tool::Pnt(V2);

  if (std::abs(P1.Z() - P2.Z()) < BRepFill_Confusion())
  {
    // It is a Line ?
    TopLoc_Location         Loc;
    double                  f, l;
    occ::handle<Geom_Curve> GC = BRep_Tool::Curve(E, Loc, f, l);
    if (GC->DynamicType() == STANDARD_TYPE(Geom_Line))
      return true;
  }
  return false;
}

//=======================================================================
// function : Side
// purpose  : determine the position of the profil correspondingly to plane XOZ.
//           Return 1 : MAT_Left.
//           Return 2 : MAT_Left and Planar.
//           Return 3 : MAT_Left and Vertical.
//           Return 4 : MAT_Right.
//           Return 5 : MAT_Right and Planar.
//           Return 6 : MAT_Right and Vertical.
//=======================================================================

static int Side(const TopoDS_Wire& Profil, const double Tol)
{
  TopoDS_Vertex V1, V2;
  // Rem : it is enough to test the first edge of the Wire.
  //       ( Correctly cut in PrepareProfil)
  TopExp_Explorer Explo(Profil, TopAbs_EDGE);

  int                TheSide;
  const TopoDS_Edge& E = TopoDS::Edge(Explo.Current());

  TopExp::Vertices(E, V1, V2);
  gp_Pnt P1 = BRep_Tool::Pnt(V1);
  gp_Pnt P2 = BRep_Tool::Pnt(V2);

  if (P1.Y() < -Tol || P2.Y() < -Tol)
    TheSide = 4;
  else
    TheSide = 1;
  if (IsVertical(E))
    TheSide += 2;
  else if (IsPlanar(E))
    TheSide++;
  return TheSide;
}

//=================================================================================================

void BRepFill_Evolved::Perform(const TopoDS_Wire&     Spine,
                               const TopoDS_Wire&     Profile,
                               const gp_Ax3&          AxeProf,
                               const GeomAbs_JoinType Join,
                               const bool             Solid)
{
  mySpineType       = false;
  TopoDS_Face aFace = BRepLib_MakeFace(Spine, true);
  PrivatePerform(aFace, Profile, AxeProf, Join, Solid);
}

//=================================================================================================

void BRepFill_Evolved::Perform(const TopoDS_Face&     Spine,
                               const TopoDS_Wire&     Profile,
                               const gp_Ax3&          AxeProf,
                               const GeomAbs_JoinType Join,
                               const bool             Solid)
{
  mySpineType = true;
  PrivatePerform(Spine, Profile, AxeProf, Join, Solid);
}

//=================================================================================================

void BRepFill_Evolved::PrivatePerform(const TopoDS_Face&     Spine,
                                      const TopoDS_Wire&     Profile,
                                      const gp_Ax3&          AxeProf,
                                      const GeomAbs_JoinType Join,
                                      const bool             Solid)
{
  TopoDS_Shape aLocalShape = Spine.Oriented(TopAbs_FORWARD);
  mySpine                  = TopoDS::Face(aLocalShape);
  //  mySpine    = TopoDS::Face(Spine.Oriented(TopAbs_FORWARD));
  aLocalShape = Profile.Oriented(TopAbs_FORWARD);
  myProfile   = TopoDS::Wire(aLocalShape);
  //  myProfile  = TopoDS::Wire(Profile.Oriented(TopAbs_FORWARD));
  myJoinType = Join;
  myMap.Clear();

  if (myJoinType > GeomAbs_Arc)
  {
    throw Standard_NotImplemented();
  }

  NCollection_List<TopoDS_Shape>           WorkProf;
  TopoDS_Face                              WorkSpine;
  NCollection_List<TopoDS_Shape>::Iterator WPIte;

  //-------------------------------------------------------------------
  // Positioning of mySpine and myProfil in the workspace.
  //-------------------------------------------------------------------
  TopLoc_Location LSpine = FindLocation(mySpine);
  gp_Trsf         T;
  T.SetTransformation(AxeProf);
  TopLoc_Location LProfile(T);
  TopLoc_Location InitLS = mySpine.Location();
  TopLoc_Location InitLP = myProfile.Location();
  TransformInitWork(LSpine, LProfile);

  //------------------------------------------------------------------
  // projection of the profile and cut of the spine.
  //------------------------------------------------------------------
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> MapProf, MapSpine;

  PrepareProfile(WorkProf, MapProf);
  PrepareSpine(WorkSpine, MapSpine);

  double      Tol     = BRepFill_Confusion();
  bool        YaLeft  = false;
  bool        YaRight = false;
  TopoDS_Wire SP;

  for (WPIte.Initialize(WorkProf); WPIte.More(); WPIte.Next())
  {
    SP = TopoDS::Wire(WPIte.Value());
    if (Side(SP, Tol) < 4)
      YaLeft = true;
    else
      YaRight = true;
    if (YaLeft && YaRight)
      break;
  }

  TopoDS_Face              Face;
  BRepMAT2d_BisectingLocus Locus;

  //----------------------------------------------------------
  // Initialisation of cut volevo.
  // For each part of the profile create a volevo added to CutVevo
  //----------------------------------------------------------
  BRepFill_Evolved       CutVevo;
  TopoDS_Wire            WP;
  BRep_Builder           BB;
  BRepTools_WireExplorer WExp;

  BB.MakeWire(WP);

  for (WPIte.Initialize(WorkProf); WPIte.More(); WPIte.Next())
  {
    for (WExp.Init(TopoDS::Wire(WPIte.Value())); WExp.More(); WExp.Next())
    {
      BB.Add(WP, WExp.Current());
    }
  }
  CutVevo.SetWork(WorkSpine, WP);

  BRepTools_Quilt Glue;
  int             CSide;

  //---------------------------------
  // Construction of vevos to the left.
  //---------------------------------
  if (YaLeft)
  {
    //-----------------------------------------------------
    // Calculate the map of bisector locations at the left.
    // and links Topology -> base elements of the map.
    //-----------------------------------------------------
    BRepMAT2d_Explorer Exp(WorkSpine);
    Locus.Compute(Exp, 1, MAT_Left);
    BRepMAT2d_LinkTopoBilo Link(Exp, Locus);

    for (WPIte.Initialize(WorkProf); WPIte.More(); WPIte.Next())
    {
      SP    = TopoDS::Wire(WPIte.Value());
      CSide = Side(SP, Tol);
      //-----------------------------------------------
      // Construction and adding of elementary volevo.
      //-----------------------------------------------
      BRepFill_Evolved Vevo;
      if (CSide == 1)
      {
        Vevo.ElementaryPerform(WorkSpine, SP, Locus, Link, Join);
      }
      else if (CSide == 2)
      {
        Vevo.PlanarPerform(WorkSpine, SP, Locus, Link, Join);
      }
      else if (CSide == 3)
      {
        Vevo.VerticalPerform(WorkSpine, SP, Locus, Link, Join);
      }
      CutVevo.Add(Vevo, SP, Glue);
    }
  }

  //---------------------------------
  // Construction of vevos to the right.
  //---------------------------------
  if (YaRight)
  {
    //-----------------------------------
    // Decomposition of the face into wires.
    //-----------------------------------
    TopExp_Explorer SpineExp(WorkSpine, TopAbs_WIRE);
    for (; SpineExp.More(); SpineExp.Next())
    {
      //----------------------------------------------
      // Calculate the map to the right of the current wire.
      //----------------------------------------------
      BRepLib_MakeFace B(gp_Pln(0., 0., 1., 0.));
      TopoDS_Shape     aLocalShapeRev = SpineExp.Current().Reversed();
      B.Add(TopoDS::Wire(aLocalShapeRev));
      //      B.Add(TopoDS::Wire(SpineExp.Current().Reversed()));
      Face = B.Face();
      BRepMAT2d_Explorer Exp(Face);
      Locus.Compute(Exp, 1, MAT_Left);
      BRepMAT2d_LinkTopoBilo Link(Exp, Locus);

      for (WPIte.Initialize(WorkProf); WPIte.More(); WPIte.Next())
      {
        SP    = TopoDS::Wire(WPIte.Value());
        CSide = Side(SP, Tol);
        //-----------------------------------------------
        // Construction and adding of an elementary volevo
        //-----------------------------------------------
        BRepFill_Evolved Vevo;
        if (CSide == 4)
        {
          Vevo.ElementaryPerform(Face, SP, Locus, Link, Join);
        }
        else if (CSide == 5)
        {
          Vevo.PlanarPerform(Face, SP, Locus, Link, Join);
        }
        else if (CSide == 6)
        {
          Vevo.VerticalPerform(Face, SP, Locus, Link, Join);
        }
        CutVevo.Add(Vevo, SP, Glue);
      }
    }
  }

  if (Solid)
    CutVevo.AddTopAndBottom(Glue);

  //-------------------------------------------------------------------------
  // Gluing of regularites on parallel edges generate4d by vertices of the
  // cut of the profile.
  //-------------------------------------------------------------------------
  CutVevo.ContinuityOnOffsetEdge(WorkProf);

  //-----------------------------------------------------------------
  // construction of the shape via the quilt, ie:
  // - sharing of topologies of elementary added volevos.
  // - Orientation of faces correspondingly to each other.
  //-----------------------------------------------------------------
  TopoDS_Shape& SCV = CutVevo.ChangeShape();
  SCV               = Glue.Shells();
  //------------------------------------------------------------------------
  // Transfer of the map of generated elements and of the shape of Cutvevo
  // in myMap and repositioning in the initial space.
  //------------------------------------------------------------------------
  Transfert(CutVevo, MapProf, MapSpine, LSpine.Inverted(), InitLS, InitLP);

  // Orientation of the solid.
  if (Solid)
    MakeSolid();

  //  modified by NIZHNY-EAP Mon Jan 24 11:26:48 2000 ___BEGIN___
  BRepLib::UpdateTolerances(myShape, false);
  //  modified by NIZHNY-EAP Mon Jan 24 11:26:50 2000 ___END___
  myIsDone = true;
}

//=================================================================================================

static void IsInversed(const TopoDS_Shape& S,
                       const TopoDS_Edge&  E1,
                       const TopoDS_Edge&  E2,
                       bool*               Inverse)
{

  Inverse[0] = Inverse[1] = false;
  if (S.ShapeType() != TopAbs_EDGE)
    return;

  gp_Pnt            P;
  gp_Vec            DS, DC1, DC2;
  BRepAdaptor_Curve CS(TopoDS::Edge(S));
  if (S.Orientation() == TopAbs_FORWARD)
  {
    CS.D1(CS.FirstParameter(), P, DS);
  }
  else
  {
    CS.D1(CS.LastParameter(), P, DS);
    DS.Reverse();
  }

  if (!BRep_Tool::Degenerated(E1))
  {
    BRepAdaptor_Curve C1(TopoDS::Edge(E1));
    if (E1.Orientation() == TopAbs_FORWARD)
    {
      C1.D1(C1.FirstParameter(), P, DC1);
    }
    else
    {
      C1.D1(C1.LastParameter(), P, DC1);
      DC1.Reverse();
    }
    Inverse[0] = (DS.Dot(DC1) < 0.);
  }
  else
    Inverse[0] = true;

  if (!BRep_Tool::Degenerated(E2))
  {
    BRepAdaptor_Curve C2(TopoDS::Edge(E2));
    if (E2.Orientation() == TopAbs_FORWARD)
    {
      C2.D1(C2.FirstParameter(), P, DC2);
    }
    else
    {
      C2.D1(C2.LastParameter(), P, DC2);
      DC2.Reverse();
    }
    Inverse[1] = (DS.Dot(DC2) < 0.);
  }
  else
    Inverse[1] = true;
}

//=================================================================================================

void BRepFill_Evolved::SetWork(const TopoDS_Face& Sp, const TopoDS_Wire& Pr)
{
  mySpine   = Sp;
  myProfile = Pr;
}

//=======================================================================
// function : ConcaveSide
// purpose  : Determine if the pipes were at the side of the
//           concavity. In this case they can be closed.
//           WARNING: Not finished. Done only for circles.
//=======================================================================

static bool ConcaveSide(const TopoDS_Shape& S, const TopoDS_Face& F)
{

  if (S.ShapeType() == TopAbs_VERTEX)
    return false;

  if (S.ShapeType() == TopAbs_EDGE)
  {
    double                    f, l;
    occ::handle<Geom2d_Curve> G2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(S), F, f, l);
    occ::handle<Geom2d_Curve> G2dOC;

    Geom2dAdaptor_Curve AC(G2d, f, l);
    if (AC.GetType() == GeomAbs_Circle)
    {
      bool Direct = AC.Circle().IsDirect();
      if (S.Orientation() == TopAbs_REVERSED)
        Direct = (!Direct);
      return Direct;
    }
  }
  return false;
}

//=================================================================================================

void BRepFill_Evolved::ElementaryPerform(const TopoDS_Face&              Sp,
                                         const TopoDS_Wire&              Pr,
                                         const BRepMAT2d_BisectingLocus& Locus,
                                         BRepMAT2d_LinkTopoBilo&         Link,
                                         const GeomAbs_JoinType /*Join*/)
{

#ifdef DRAW
  if (AffichEdge)
  {
    char name[100];
    Sprintf(name, "PROFIL_%d", ++NbPROFILS);
    DBRep::Set(name, Pr);
  }
#endif
  TopoDS_Shape aLocalShape = Sp.Oriented(TopAbs_FORWARD);
  mySpine                  = TopoDS::Face(aLocalShape);
  //  mySpine   = TopoDS::Face(Sp.Oriented(TopAbs_FORWARD));
  myProfile = Pr;
  myMap.Clear();

  BRep_Builder myBuilder;
  myBuilder.MakeCompound(TopoDS::Compound(myShape));

  //---------------------------------------------------------------------
  // MapNodeVertex : associate to each node of the map (key1) and
  //                 to each element of the profile (key2) a vertex (item).
  // MapBis        : a set of edges or vertexes (item) generated by
  //                 a bisectrice on a face or an edge (key) of
  //                 tubes or revolutions.
  // MapVerPar     : Map of parameters of vertices on parallel edges
  //                 the list contained in MapVerPar (E) corresponds
  //                 to parameters on E of vertices contained in  MapBis(E);
  // MapBS         : links BasicElt of the map => Topology of the spine.
  //---------------------------------------------------------------------

  NCollection_DataMap<occ::handle<MAT_Node>,
                      NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>>
    MapNodeVertex;
  NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<TopoDS_Shape>, TopTools_ShapeMapHasher>
    MapBis;
  NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<double>, TopTools_ShapeMapHasher>
    MapVerPar;

  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> EmptyMap;
  NCollection_Sequence<TopoDS_Shape>                                       EmptySeq;
  NCollection_List<TopoDS_Shape>                                           EmptyList;
  NCollection_Sequence<double>                                             EmptySeqOfReal;

  // mark of the profile.
  gp_Ax3 AxeRef(gp_Pnt(0., 0., 0.), gp_Dir(gp_Dir::D::Z), gp_Dir(gp_Dir::D::X));

  //---------------------------------------------------------------
  // Construction of revolutions and tubes.
  //---------------------------------------------------------------
  BRepTools_WireExplorer ProfExp;
  TopExp_Explorer        FaceExp;
  BRepTools_WireExplorer WireExp;

  for (FaceExp.Init(mySpine, TopAbs_WIRE); FaceExp.More(); FaceExp.Next())
  {

    for (WireExp.Init(TopoDS::Wire(FaceExp.Current())); WireExp.More(); WireExp.Next())
    {

      const TopoDS_Edge& CurrentEdge = WireExp.Current();
      TopoDS_Vertex      VFirst, VLast;
      EdgeVertices(CurrentEdge, VFirst, VLast);

      for (Link.Init(VLast); Link.More(); Link.Next())
      {
        //----------------------------.
        // Construction of a Revolution
        //----------------------------.
        MakeRevol(CurrentEdge, VLast, AxeRef);
      }

      for (Link.Init(CurrentEdge); Link.More(); Link.Next())
      {
        //------------------------.
        // Construction of a Tube
        //-------------------------
        MakePipe(CurrentEdge, AxeRef);
      }
    }
  }

#ifdef DRAW
  if (AffichEdge)
  {
    std::cout << " End Construction of geometric primitives" << std::endl;
  }
#endif

  //---------------------------------------------------
  // Construction of edges associated to bissectrices.
  //---------------------------------------------------
  occ::handle<MAT_Arc>      CurrentArc;
  occ::handle<Geom2d_Curve> Bis, PCurve1, PCurve2;
  occ::handle<Geom_Curve>   CBis;
  bool                      Reverse;
  TopoDS_Edge               CurrentEdge;
  TopoDS_Shape              S[2];
  TopoDS_Face               F[2];
  TopoDS_Edge               E[4];
  TopLoc_Location           L;
  int                       k;

  for (int i = 1; i <= Locus.Graph()->NumberOfArcs(); i++)
  {
    CurrentArc = Locus.Graph()->Arc(i);
    SimpleExpression(Locus.GeomBis(CurrentArc, Reverse), Bis);

    //------------------------------------------------------------------
    // Return elements of the spine corresponding to separate basicElts.
    //------------------------------------------------------------------
    S[0] = Link.GeneratingShape(CurrentArc->FirstElement());
    S[1] = Link.GeneratingShape(CurrentArc->SecondElement());

    bool Concave0 = ConcaveSide(S[0], mySpine);
    bool Concave1 = ConcaveSide(S[1], mySpine);

    NCollection_Sequence<TopoDS_Shape> VOnF, VOnL;
    NCollection_Sequence<gp_Pnt>       ParOnF, ParOnL;

    NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<TopoDS_Shape>, TopTools_ShapeMapHasher>
      MapSeqVer;
    NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<gp_Pnt>, TopTools_ShapeMapHasher>
      MapSeqPar;

    for (ProfExp.Init(myProfile); ProfExp.More(); ProfExp.Next())
    {
      //-----------------------------------------------
      // Return two faces separated by the bissectrice.
      //-----------------------------------------------
      F[0] = TopoDS::Face(myMap(S[0])(ProfExp.Current()).First());
      F[1] = TopoDS::Face(myMap(S[1])(ProfExp.Current()).First());

      //------------------------------------
      // Return parallel edges on each face.
      //------------------------------------
      TopoDS_Vertex VF, VL;

      EdgeVertices(ProfExp.Current(), VF, VL);

      E[0] = TopoDS::Edge(myMap(S[0])(VF).First());
      E[1] = TopoDS::Edge(myMap(S[0])(VL).First());
      E[2] = TopoDS::Edge(myMap(S[1])(VF).First());
      E[3] = TopoDS::Edge(myMap(S[1])(VL).First());

      bool Inv0[2];
      bool Inv1[2];

      Inv0[0] = Inv0[1] = Inv1[0] = Inv1[1] = false;
      if (Concave0)
        IsInversed(S[0], E[0], E[1], Inv0);
      if (Concave1)
        IsInversed(S[1], E[2], E[3], Inv1);

      //---------------------------------------------
      // Construction of geometries.
      //---------------------------------------------
      BRepFill_TrimSurfaceTool Trim(Bis, F[0], F[1], E[0], E[2], Inv0[0], Inv1[0]);
      //-----------------------------------------------------------
      // Construction of vertices corresponding to the node of the map
      //-----------------------------------------------------------
      TopoDS_Vertex         VS, VE;
      occ::handle<MAT_Node> Node1, Node2;

      if (Reverse)
      {
        Node1 = CurrentArc->SecondNode();
        Node2 = CurrentArc->FirstNode();
      }
      else
      {
        Node1 = CurrentArc->FirstNode();
        Node2 = CurrentArc->SecondNode();
      }
      //--------------------------------------------------------
      // Particular case when the node is on a vertex of the spine.
      //--------------------------------------------------------
      if (Node1->OnBasicElt())
      {
        if (S[0].ShapeType() == TopAbs_VERTEX)
        {
          Node1 = CurrentArc->FirstElement()->StartArc()->FirstNode();
        }
        else if (S[1].ShapeType() == TopAbs_VERTEX)
        {
          Node1 = CurrentArc->SecondElement()->StartArc()->FirstNode();
        }
      }
      // End of particular case.

      int StartOnF =
        VertexFromNode(Node1, TopoDS::Edge(ProfExp.Current()), VF, VL, MapNodeVertex, VS);

      int EndOnF =
        VertexFromNode(Node2, TopoDS::Edge(ProfExp.Current()), VF, VL, MapNodeVertex, VE);

      //-----------------------------------------------------------
      // Construction of vertices on edges parallel to the spine.
      //-----------------------------------------------------------
      if (!MapSeqVer.IsBound(VF))
      {
        if (Inv0[0] || Inv1[0])
        {
          ParOnF.Clear();
          VOnF.Clear();
        }
        else
        {
          Trim.IntersectWith(E[0], E[2], ParOnF);
          VOnF.Clear();
          for (int s = 1; s <= ParOnF.Length(); s++)
          {
            TopoDS_Vertex VC;
            myBuilder.MakeVertex(VC);
            VOnF.Append(VC);
          }
          if (StartOnF == 1)
          {
            VOnF.SetValue(1, VS);
          }
          if (EndOnF == 1)
          {
            VOnF.SetValue(ParOnF.Length(), VE);
          }
        }
      }
      else
      {
        ParOnF = MapSeqPar(VF);
        VOnF   = MapSeqVer(VF);
      }

      if (!MapSeqVer.IsBound(VL))
      {
        if (Inv0[1] || Inv1[1])
        {
          ParOnL.Clear();
          VOnL.Clear();
        }
        else
        {
          Trim.IntersectWith(E[1], E[3], ParOnL);
          VOnL.Clear();
          for (int s = 1; s <= ParOnL.Length(); s++)
          {
            TopoDS_Vertex VC;
            myBuilder.MakeVertex(VC);
            VOnL.Append(VC);
          }
          if (StartOnF == 3)
          {
            VOnL.SetValue(1, VS);
          }
          if (EndOnF == 3)
          {
            VOnL.SetValue(ParOnL.Length(), VE);
          }
        }
      }
      else
      {
        ParOnL = MapSeqPar(VL);
        VOnL   = MapSeqVer(VL);
      }

      //------------------------------------------------------
      // Test if the Bissectrice is not projected on the face
      //------------------------------------------------------
      if ((StartOnF == 0) && (EndOnF == 0) && VOnL.IsEmpty() && VOnF.IsEmpty())
        // No trace of the bisectrice on the face.
        continue;

      if ((StartOnF == 0) && (EndOnF == 0) && (VOnL.Length() + VOnF.Length() == 1))
        // the first or last node of the arc is on the edge
        // but the arc is not on the face.
        continue;

      //---------------------------------------------------------
      // determine the intervals of the bissectrice that are
      // projected on F[0] and F[1].
      //---------------------------------------------------------
      NCollection_Sequence<double>       LastPar, FirstPar;
      NCollection_Sequence<TopoDS_Shape> FirstV, LastV;

      ComputeIntervals(VOnF,
                       VOnL,
                       ParOnF,
                       ParOnL,
                       Trim,
                       Bis,
                       VS,
                       VE,
                       FirstPar,
                       LastPar,
                       FirstV,
                       LastV);

      for (int Ti = 1; Ti <= FirstPar.Length(); Ti++)
      {
        TopoDS_Vertex V1 = TopoDS::Vertex(FirstV.Value(Ti));
        TopoDS_Vertex V2 = TopoDS::Vertex(LastV.Value(Ti));

        GeomAbs_Shape Continuity;

        Trim.Project(FirstPar.Value(Ti), LastPar.Value(Ti), CBis, PCurve1, PCurve2, Continuity);

        //-------------------------------------
        // Coding of the edge.
        //-------------------------------------
        myBuilder.MakeEdge(CurrentEdge, CBis, BRepFill_Confusion());

        myBuilder.UpdateVertex(V1, CBis->Value(CBis->FirstParameter()), BRepFill_Confusion());
        myBuilder.UpdateVertex(V2, CBis->Value(CBis->LastParameter()), BRepFill_Confusion());

        myBuilder.Add(CurrentEdge, V1.Oriented(TopAbs_FORWARD));
        myBuilder.Add(CurrentEdge, V2.Oriented(TopAbs_REVERSED));

        myBuilder.Range(CurrentEdge, CBis->FirstParameter(), CBis->LastParameter());
        myBuilder.UpdateEdge(CurrentEdge, PCurve1, F[0], BRepFill_Confusion());
        myBuilder.UpdateEdge(CurrentEdge, PCurve2, F[1], BRepFill_Confusion());

        myBuilder.Continuity(CurrentEdge, F[0], F[1], Continuity);

#ifdef DRAW
        if (AffichEdge)
        {
          char name[100];
          Sprintf(name, "ARCEDGE_%d_%d_%d", i, vv, Ti);
          DBRep::Set(name, CurrentEdge);
        }
#endif
        //-------------------------------------------
        // Storage of the edge for each of faces.
        //-------------------------------------------
        for (k = 0; k <= 1; k++)
        {
          if (!MapBis.IsBound(F[k]))
          {
            MapBis.Bind(F[k], EmptySeq);
          }
        }
        //---------------------------------------------------------------
        // orientation of the edge depends on the direction of the skin.
        // skin => same orientation E[0] , inverted orientation E[2]
        // if contreskin it is inverted.
        //--------------------------------------------------------------
        E[0].Orientation(BRepTools::OriEdgeInFace(E[0], F[0]));
        E[2].Orientation(BRepTools::OriEdgeInFace(E[2], F[1]));

        if (DistanceToOZ(VF) < DistanceToOZ(VL))
        {
          // Skin
          MapBis(F[0]).Append(CurrentEdge.Oriented(E[0].Orientation()));
          CurrentEdge.Orientation(TopAbs::Complement(E[2].Orientation()));
          MapBis(F[1]).Append(CurrentEdge);
        }
        else
        {
          // Contreskin
          MapBis(F[1]).Append(CurrentEdge.Oriented(E[2].Orientation()));
          CurrentEdge.Orientation(TopAbs::Complement(E[0].Orientation()));
          MapBis(F[0]).Append(CurrentEdge);
        }
      }

      //----------------------------------------------
      // Storage of vertices on parallel edges.
      // fill MapBis and MapVerPar.
      // VOnF for E[0] and E[2].
      // VOnL for E[1] and E[3].
      //----------------------------------------------
      for (k = 0; k <= 2; k = k + 2)
      {
        if (!MapSeqVer.IsBound(VF))
        {
          if (!VOnF.IsEmpty())
          {
            if (!MapBis.IsBound(E[k]))
            {
              MapBis.Bind(E[k], EmptySeq);
              MapVerPar.Bind(E[k], EmptySeqOfReal);
            }
            for (int ii = 1; ii <= VOnF.Length(); ii++)
            {
              MapBis(E[k]).Append(VOnF.Value(ii));
              if (k == 0)
                MapVerPar(E[k]).Append(ParOnF.Value(ii).Y());
              else
                MapVerPar(E[k]).Append(ParOnF.Value(ii).Z());
            }
          }
        }
      }

      for (k = 1; k <= 3; k = k + 2)
      {
        if (!MapSeqVer.IsBound(VL))
        {
          if (!VOnL.IsEmpty())
          {
            if (!MapBis.IsBound(E[k]))
            {
              MapBis.Bind(E[k], EmptySeq);
              MapVerPar.Bind(E[k], EmptySeqOfReal);
            }
            for (int ii = 1; ii <= VOnL.Length(); ii++)
            {
              MapBis(E[k]).Append(VOnL.Value(ii));
              if (k == 1)
                MapVerPar(E[k]).Append(ParOnL.Value(ii).Y());
              else
                MapVerPar(E[k]).Append(ParOnL.Value(ii).Z());
            }
          }
        }
      }

      //----------------------------------------------------------------
      // Edge [1] of the current face will be Edge [0] of the next face.
      // => copy of VonL in VonF. To avoid creating the same vertices twice.
      //-----------------------------------------------------------------

      MapSeqPar.Bind(VF, ParOnF);
      MapSeqVer.Bind(VF, VOnF);
      MapSeqPar.Bind(VL, ParOnL);
      MapSeqVer.Bind(VL, VOnL);
    }
  }

#ifdef DRAW
  if (AffichEdge)
  {
    std::cout << " End of Construction of edges and vertices on bissectrices" << std::endl;
  }
#endif

  //----------------------------------
  // Construction of parallel edges.
  //----------------------------------
  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>::Iterator ite1;
  TopoDS_Shape                         CurrentProf, PrecProf;
  TopoDS_Face                          CurrentFace;
  TopoDS_Shape                         CurrentSpine;
  TopoDS_Vertex                        VCF, VCL;

  for (ite1.Initialize(myMap); ite1.More(); ite1.Next())
  {
    CurrentSpine = ite1.Key();

    for (ProfExp.Init(myProfile); ProfExp.More(); ProfExp.Next())
    {
      CurrentProf = ProfExp.Current();
      EdgeVertices(TopoDS::Edge(CurrentProf), VCF, VCL);
      CurrentEdge = TopoDS::Edge(myMap(CurrentSpine)(VCF).First());

      //-------------------------------------------------------------
      // RQ : Current Edge is oriented relatively to the face (oriented forward)
      //     generated by edge CurrentProf .
      //-------------------------------------------------------------
      if (MapBis.IsBound(CurrentEdge))
      {

        //--------------------------------------------------------
        // Find if one of two faces connected to the edge
        // belongs to volevo. The edges on this face serve
        // to eliminate certain vertices that can appear twice
        // on the parallel edge. These Vertices correspond to the
        // nodes of the map.
        //---------------------------------------------------------
        TopoDS_Shape FaceControle;
        bool         YaFace = true;

        FaceControle = myMap(CurrentSpine)(CurrentProf).First();
        if (!MapBis.IsBound(FaceControle))
        {
          YaFace = false;
          if (!PrecProf.IsNull())
          {
            FaceControle = myMap(CurrentSpine)(PrecProf).First();
            if (MapBis.IsBound(FaceControle))
            {
              YaFace = true;
            }
          }
        }

        if (YaFace)
        {
          //------------------------------------------------------------
          // No connected face in the volevo => no parallel edge.
          //------------------------------------------------------------
          NCollection_Sequence<TopoDS_Shape> aSeqOfShape;
          TrimEdge(CurrentEdge,
                   MapBis(FaceControle),
                   MapBis(CurrentEdge),
                   MapVerPar(CurrentEdge),
                   aSeqOfShape);

          for (k = 1; k <= aSeqOfShape.Length(); k++)
          {
            myMap(CurrentSpine)(VCF).Append(aSeqOfShape.Value(k));

#ifdef DRAW
            if (AffichEdge)
            {
              char name[100];
              Sprintf(name, "PAREDGE_%d_%d", ++NbEDGES, k);
              DBRep::Set(name, aSeqOfShape.Value(k));
            }
#endif
          }
        }
      }
      PrecProf = CurrentProf;
    }

    //------------------------------------------------------------
    // Construction of the parallel edge from the last vertex of myProfile.
    //------------------------------------------------------------
    CurrentEdge = TopoDS::Edge(myMap(CurrentSpine)(VCL).First());

    if (MapBis.IsBound(CurrentEdge))
    {
      bool         YaFace = true;
      TopoDS_Shape FaceControle;

      FaceControle = myMap(CurrentSpine)(CurrentProf).First();
      if (!MapBis.IsBound(FaceControle))
      {
        YaFace = false;
      }
      // the number of element of the list allows to know
      // if the edges have already been done (closed profile) .
      if (YaFace && myMap(CurrentSpine)(VCL).Extent() <= 1)
      {
        NCollection_Sequence<TopoDS_Shape> aSeqOfShape;
        TrimEdge(CurrentEdge,
                 MapBis(FaceControle),
                 MapBis(CurrentEdge),
                 MapVerPar(CurrentEdge),
                 aSeqOfShape);

        for (k = 1; k <= aSeqOfShape.Length(); k++)
        {
          myMap(CurrentSpine)(VCL).Append(aSeqOfShape.Value(k));

#ifdef DRAW
          if (AffichEdge)
          {
            char name[100];
            Sprintf(name, "PAREDGE_%d_%d", ++NbEDGES, k);
            DBRep::Set(name, aSeqOfShape.Value(k));
          }
#endif
        }
      }
    }
  }

#ifdef DRAW
  if (AffichEdge)
  {
    std::cout << " End Construction of parallel edges " << std::endl;
  }
#endif

  //-------------------------------------------------------------------
  // Cut faces by edges.
  //-------------------------------------------------------------------
  for (ite1.Initialize(myMap); ite1.More(); ite1.Next())
  {
    CurrentSpine = ite1.Key();

    for (ProfExp.Init(myProfile); ProfExp.More(); ProfExp.Next())
    {
      CurrentProf = ProfExp.Current();
      CurrentFace = TopoDS::Face(myMap(CurrentSpine)(CurrentProf).First());
      myMap(CurrentSpine)(CurrentProf).Clear();

      if (MapBis.IsBound(CurrentFace))
      {
        //----------------------------------------------------------
        // If the face does not contain edges that can limit it
        // it does not appear in volevo.
        // cut of face by edges can generate many faces.
        //
        // Add edges generated on the edges parallel to the set
        // of edges that limit the face.
        //
        //------------------------------------------------------------
        EdgeVertices(TopoDS::Edge(CurrentProf), VCF, VCL);

        NCollection_List<TopoDS_Shape>::Iterator itl;
        const NCollection_List<TopoDS_Shape>&    LF = myMap(CurrentSpine)(VCF);

        TopAbs_Orientation Ori = BRepTools::OriEdgeInFace(TopoDS::Edge(LF.First()), CurrentFace);
        for (itl.Initialize(LF), itl.Next(); itl.More(); itl.Next())
        {
          TopoDS_Edge RE = TopoDS::Edge(itl.Value());
          MapBis(CurrentFace).Append(RE.Oriented(Ori));
        }
        const NCollection_List<TopoDS_Shape>& LL = myMap(CurrentSpine)(VCL);
        Ori = BRepTools::OriEdgeInFace(TopoDS::Edge(LL.First()), CurrentFace);
        for (itl.Initialize(LL), itl.Next(); itl.More(); itl.Next())
        {
          TopoDS_Edge RE = TopoDS::Edge(itl.Value());
          MapBis(CurrentFace).Append(RE.Oriented(Ori));
        }

        // Cut of the face.
        NCollection_Sequence<TopoDS_Shape> aSeqOfShape;

        TrimFace(CurrentFace, MapBis(CurrentFace), aSeqOfShape);

        for (int ii = 1; ii <= aSeqOfShape.Length(); ii++)
        {
          myBuilder.Add(myShape, aSeqOfShape.Value(ii));
          myMap(CurrentSpine)(CurrentProf).Append(aSeqOfShape.Value(ii));
        }
      }
    }
    //-----------------------------------------------------------------
    // Removal of first edge (edge of origin) from lists of myMap
    // corresponding to vertices of the profile.
    //-----------------------------------------------------------------
    TopExp_Explorer                                        Explo(myProfile, TopAbs_VERTEX);
    NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> vmap;

    for (; Explo.More(); Explo.Next())
    {
      if (vmap.Add(Explo.Current()))
      {
        myMap(CurrentSpine)(Explo.Current()).RemoveFirst();
      }
    }
  }
  myIsDone = true;

#ifdef DRAW
  if (AffichEdge)
  {
    std::cout << " End of construction of an elementary volevo." << std::endl;
    char name[100];
    Sprintf(name, "VEVO_%d", ++NbVEVOS);
    DBRep::Set(name, myShape);
  }
#endif
}

//=================================================================================================

void BRepFill_Evolved::PlanarPerform(const TopoDS_Face&              Sp,
                                     const TopoDS_Wire&              Pr,
                                     const BRepMAT2d_BisectingLocus& Locus,
                                     BRepMAT2d_LinkTopoBilo&         Link,
                                     const GeomAbs_JoinType          Join)
{
  TopoDS_Shape aLocalShapeOriented = Sp.Oriented(TopAbs_FORWARD);
  mySpine                          = TopoDS::Face(aLocalShapeOriented);
  //  mySpine   = TopoDS::Face(Sp.Oriented(TopAbs_FORWARD));
  myProfile = Pr;
  myMap.Clear();

  BRep_Builder B;
  B.MakeCompound(TopoDS::Compound(myShape));

  BRepTools_WireExplorer ProfExp;
  TopExp_Explorer        Exp, exp1, exp2;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
                                                                           EmptyMap;
  NCollection_List<TopoDS_Shape>                                           EmptyList;
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> MapVP;
  BRepFill_OffsetWire                                                      Paral;

  for (ProfExp.Init(myProfile); ProfExp.More(); ProfExp.Next())
  {
    const TopoDS_Edge&       E = ProfExp.Current();
    BRepAlgo_FaceRestrictor  FR;
    BRepFill_OffsetAncestors OffAnc;

    TopoDS_Vertex V[2];
    EdgeVertices(E, V[0], V[1]);
    double Alt = Altitud(V[0]);
    double Offset[2];
    Offset[0]    = DistanceToOZ(V[0]);
    Offset[1]    = DistanceToOZ(V[1]);
    bool IsMinV1 = (Offset[0] < Offset[1]);

    for (int i = 0; i <= 1; i++)
    {
      if (!MapVP.IsBound(V[i]))
      {
        //------------------------------------------------
        // Calculate parallel lines corresponding to vertices.
        //------------------------------------------------
        Paral.PerformWithBiLo(mySpine, Offset[i], Locus, Link, Join, Alt);
        OffAnc.Perform(Paral);
        MapVP.Bind(V[i], Paral.Shape());

        //-----------------------------
        // Update myMap (.)(V[i])
        //-----------------------------
        for (Exp.Init(Paral.Shape(), TopAbs_EDGE); Exp.More(); Exp.Next())
        {
          const TopoDS_Edge&  WC = TopoDS::Edge(Exp.Current());
          const TopoDS_Shape& GS = OffAnc.Ancestor(WC);
          if (!myMap.IsBound(GS))
            myMap.Bind(GS, EmptyMap);
          if (!myMap(GS).IsBound(V[i]))
            myMap(GS).Bind(V[i], Paral.GeneratedShapes(GS));
        }
      }
      TopoDS_Shape Rest = MapVP(V[i]);

      bool ToReverse = false;
      if ((IsMinV1 && (i == 1)) || (!IsMinV1 && (i == 0)))
        ToReverse = true;

      if (!Rest.IsNull())
      {
        if (Rest.ShapeType() == TopAbs_WIRE)
        {
          if (ToReverse)
          {
            TopoDS_Shape aLocalShape = Rest.Reversed();
            TopoDS_Wire  aWire       = TopoDS::Wire(aLocalShape);
            FR.Add(aWire);
          }
          else
            FR.Add(TopoDS::Wire(Rest));
        }
        else
        {
          for (Exp.Init(Rest, TopAbs_WIRE); Exp.More(); Exp.Next())
          {
            TopoDS_Wire WCop = TopoDS::Wire(Exp.Current());
            if (ToReverse)
            {
              TopoDS_Shape aLocalShape = WCop.Reversed();
              TopoDS_Wire  bWire       = TopoDS::Wire(aLocalShape);
              //	      TopoDS_Wire bWire =   TopoDS::Wire(WCop.Reversed());
              FR.Add(bWire);
            }
            else
              FR.Add(WCop);
          }
        }
      }
    }
#ifdef DRAW
    if (AffichEdge)
    {
      NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator it(MapVP);
      int                                                                                k = 0;
      for (; it.More(); it.Next())
      {
        char name[100];
        Sprintf(name, "PARALI_%d", ++k);
        DBRep::Set(name, it.Value());
      }
    }
#endif

    //----------------------------------------------------
    // Construction of faces limited by parallels.
    // - set to the height of the support face.
    //----------------------------------------------------
    gp_Trsf T;
    T.SetTranslation(gp_Vec(0, 0, Alt));
    TopLoc_Location LT(T);
    TopoDS_Shape    aLocalShape = mySpine.Moved(LT);
    FR.Init(TopoDS::Face(aLocalShape));
    //    FR.Init(TopoDS::Face(mySpine.Moved(LT)));
    FR.Perform();

    for (; FR.More(); FR.Next())
    {
      const TopoDS_Face& F = FR.Current();
      B.Add(myShape, F);
      //---------------------------------------
      // Update myMap(.)(E)
      //---------------------------------------
      for (Exp.Init(F, TopAbs_EDGE); Exp.More(); Exp.Next())
      {
        const TopoDS_Edge& CE = TopoDS::Edge(Exp.Current());
        if (OffAnc.HasAncestor(CE))
        {
          const TopoDS_Shape& InitE = OffAnc.Ancestor(CE);
          if (!myMap.IsBound(InitE))
            myMap.Bind(InitE, EmptyMap);
          if (!myMap(InitE).IsBound(E))
            myMap(InitE).Bind(E, EmptyList);
          myMap(InitE)(E).Append(F);
        }
      }
    }
  } // End loop on profile.
}

//=================================================================================================

void BRepFill_Evolved::VerticalPerform(const TopoDS_Face&              Sp,
                                       const TopoDS_Wire&              Pr,
                                       const BRepMAT2d_BisectingLocus& Locus,
                                       BRepMAT2d_LinkTopoBilo&         Link,
                                       const GeomAbs_JoinType          Join)
{
  TopoDS_Shape aLocalShape = Sp.Oriented(TopAbs_FORWARD);
  mySpine                  = TopoDS::Face(aLocalShape);
  //  mySpine   = TopoDS::Face(Sp.Oriented(TopAbs_FORWARD));
  myProfile = Pr;
  myMap.Clear();

  BRep_Builder B;
  B.MakeCompound(TopoDS::Compound(myShape));

  BRepTools_WireExplorer   ProfExp;
  TopExp_Explorer          Exp;
  BRepFill_OffsetWire      Paral;
  BRepFill_OffsetAncestors OffAnc;
  TopoDS_Vertex            V1, V2;

  bool         First = true;
  TopoDS_Shape Base;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
    EmptyMap;

  for (ProfExp.Init(myProfile); ProfExp.More(); ProfExp.Next())
  {
    const TopoDS_Edge& E = ProfExp.Current();
    EdgeVertices(E, V1, V2);
    double Alt1 = Altitud(V1);
    double Alt2 = Altitud(V2);

    if (First)
    {
      double Offset = DistanceToOZ(V1);
      if (std::abs(Offset) < BRepFill_Confusion())
      {
        Offset = 0.;
      }
      Paral.PerformWithBiLo(mySpine, Offset, Locus, Link, Join, Alt1);
      OffAnc.Perform(Paral);
      Base = Paral.Shape();

      // MAJ myMap
      for (Exp.Init(Base, TopAbs_EDGE); Exp.More(); Exp.Next())
      {
        const TopoDS_Edge&  anEdge = TopoDS::Edge(Exp.Current());
        const TopoDS_Shape& AE     = OffAnc.Ancestor(anEdge);
        if (!myMap.IsBound(AE))
        {
          myMap.Bind(AE, EmptyMap);
        }
        if (!myMap(AE).IsBound(V1))
        {
          NCollection_List<TopoDS_Shape> L;
          myMap(AE).Bind(V1, L);
        }
        myMap(AE)(V1).Append(anEdge);
      }
      First = false;
    }

#ifdef DRAW
    if (AffichEdge)
    {
      char name[100];
      Sprintf(name, "PARALI_%d", ++NbVEVOS);
      DBRep::Set(name, Base);
    }
#endif

    BRepSweep_Prism PS(Base, gp_Vec(0, 0, Alt2 - Alt1), false);
#ifdef DRAW
    if (AffichEdge)
    {
      char name[100];
      Sprintf(name, "PRISM_%d", NbVEVOS);
      DBRep::Set(name, PS.Shape());
    }
#endif

    Base = PS.LastShape();

    for (Exp.Init(PS.Shape(), TopAbs_FACE); Exp.More(); Exp.Next())
    {
      B.Add(myShape, Exp.Current());
    }

    // MAJ myMap
    NCollection_DataMap<
      TopoDS_Shape,
      NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
      TopTools_ShapeMapHasher>::Iterator it(myMap);

    for (; it.More(); it.Next())
    {
      const NCollection_List<TopoDS_Shape>&    LOF = it.Value()(V1);
      NCollection_List<TopoDS_Shape>::Iterator itLOF(LOF);
      if (!myMap(it.Key()).IsBound(V2))
      {
        NCollection_List<TopoDS_Shape> L;
        myMap(it.Key()).Bind(V2, L);
      }

      if (!myMap(it.Key()).IsBound(E))
      {
        NCollection_List<TopoDS_Shape> L;
        myMap(it.Key()).Bind(E, L);
      }

      for (; itLOF.More(); itLOF.Next())
      {
        const TopoDS_Shape& OS = itLOF.Value();
        myMap(it.Key())(V2).Append(PS.LastShape(OS));
        myMap(it.Key())(E).Append(PS.Shape(OS));
      }
    }
  }
}

//=======================================================================
// function : Bubble
// purpose  : Order the sequence of points by growing x.
//=======================================================================

static void Bubble(NCollection_Sequence<double>& Seq)
{
  bool Invert   = true;
  int  NbPoints = Seq.Length();

  while (Invert)
  {
    Invert = false;
    for (int i = 1; i < NbPoints; i++)
    {
      if (Seq.Value(i + 1) < Seq.Value(i))
      {
        Seq.Exchange(i, i + 1);
        Invert = true;
      }
    }
  }
}

//=======================================================================
// function : PrepareProfile
// purpose  : - Projection of the profile on the working plane.
//           - Cut of the profile at the extrema of distance from profile to axis Oz.
//           - Isolate vertical and horizontal parts.
//           - Reconstruction of wires starting from cut edges.
//           New wires stored in <WorkProf> are always at the same
//           side of axis OZ or mixed with it.
//=======================================================================

void BRepFill_Evolved::PrepareProfile(
  NCollection_List<TopoDS_Shape>&                                           WorkProf,
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapProf) const
{
  // Supposedly the profile is located so that the only transformation
  // to be carried out is a projection on plane yOz.

  // initialise the projection Plane and the Line to evaluate the extrema.
  occ::handle<Geom_Plane>  Plane = new Geom_Plane(gp_Ax3(gp::YOZ()));
  occ::handle<Geom2d_Line> Line  = new Geom2d_Line(gp::OY2d());

  // Map initial vertex -> projected vertex.
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> MapVerRefMoved;

  TopoDS_Vertex                  V1, V2, VRef1, VRef2;
  TopoDS_Wire                    W;
  BRep_Builder                   B;
  NCollection_List<TopoDS_Shape> WP;
  B.MakeWire(W);
  WP.Append(W);

  BRepTools_WireExplorer Exp(myProfile);

  while (Exp.More())
  {
    NCollection_List<TopoDS_Shape> Cuts;
    bool                           NewWire = false;
    const TopoDS_Edge&             E       = TopoDS::Edge(Exp.Current());

    // Cut of the edge.
    CutEdgeProf(E, Plane, Line, Cuts, MapVerRefMoved);

    EdgeVertices(E, VRef1, VRef2);

    if (Cuts.IsEmpty())
    {
      // Neither extrema nor intersections nor vertices on the axis.
      B.Add(W, E);
      MapProf.Bind(E, E);
    }
    else
    {
      while (!Cuts.IsEmpty())
      {
        const TopoDS_Edge& NE = TopoDS::Edge(Cuts.First());
        MapProf.Bind(NE, E);
        EdgeVertices(NE, V1, V2);
        if (!MapProf.IsBound(V1))
          MapProf.Bind(V1, E);
        if (!MapProf.IsBound(V2))
          MapProf.Bind(V2, E);

        B.Add(W, NE);
        Cuts.RemoveFirst();

        if (DistanceToOZ(V2) < BRepFill_Confusion() && DistanceToOZ(V1) > BRepFill_Confusion())
        {
          // NE ends on axis OZ => new wire
          if (Cuts.IsEmpty())
          {
            // last part of the current edge
            // If it is not the last edge of myProfile
            // create a new wire.
            NewWire = true;
          }
          else
          {
            // New wire.
            B.MakeWire(W);
            WP.Append(W);
          }
        }
      }
    }
    Exp.Next();
    if (Exp.More() && NewWire)
    {
      B.MakeWire(W);
      WP.Append(W);
    }
  }

  // In the list of Wires, find edges generating plane or vertical vevo.
  NCollection_List<TopoDS_Shape>::Iterator ite;
  TopoDS_Wire                              CurW, NW;
  TopExp_Explorer                          EW;

  for (ite.Initialize(WP); ite.More(); ite.Next())
  {
    CurW         = TopoDS::Wire(ite.Value());
    bool YaModif = false;
    for (EW.Init(CurW, TopAbs_EDGE); EW.More(); EW.Next())
    {
      const TopoDS_Edge& EE = TopoDS::Edge(EW.Current());
      if (IsVertical(EE) || IsPlanar(EE))
      {
        YaModif = true;
        break;
      }
    }

    if (YaModif)
    {
      // Status = 0 for the beginning
      //          3 vertical
      //          2 horizontal
      //          1 other
      int Status = 0;

      for (EW.Init(CurW, TopAbs_EDGE); EW.More(); EW.Next())
      {
        const TopoDS_Edge& EE = TopoDS::Edge(EW.Current());
        if (IsVertical(EE))
        {
          if (Status != 3)
          {
            B.MakeWire(NW);
            WorkProf.Append(NW);
            Status = 3;
          }
        }
        else if (IsPlanar(EE))
        {
          if (Status != 2)
          {
            B.MakeWire(NW);
            WorkProf.Append(NW);
            Status = 2;
          }
        }
        else if (Status != 1)
        {
          B.MakeWire(NW);
          WorkProf.Append(NW);
          Status = 1;
        }
        B.Add(NW, EE);
      }
    }
    else
    {
      WorkProf.Append(CurW);
    }
  }

  // connect vertices modified in MapProf;
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator gilbert(
    MapVerRefMoved);
  for (; gilbert.More(); gilbert.Next())
  {
    MapProf.Bind(gilbert.Value(), gilbert.Key());
  }
}

//=================================================================================================

void BRepFill_Evolved::PrepareSpine(
  TopoDS_Face&                                                              WorkSpine,
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapSpine) const
{
  BRep_Builder                             B;
  NCollection_List<TopoDS_Shape>           Cuts;
  NCollection_List<TopoDS_Shape>::Iterator IteCuts;
  TopoDS_Vertex                            V1, V2;

  TopLoc_Location                  L;
  const occ::handle<Geom_Surface>& S    = BRep_Tool::Surface(mySpine, L);
  double                           TolF = BRep_Tool::Tolerance(mySpine);
  B.MakeFace(WorkSpine, S, L, TolF);

  for (TopoDS_Iterator IteF(mySpine); IteF.More(); IteF.Next())
  {

    TopoDS_Wire NW;
    B.MakeWire(NW);
    bool IsClosed = IteF.Value().Closed();

    for (TopoDS_Iterator IteW(IteF.Value()); IteW.More(); IteW.Next())
    {

      TopoDS_Edge E = TopoDS::Edge(IteW.Value());
      EdgeVertices(E, V1, V2);
      MapSpine.Bind(V1, V1);
      MapSpine.Bind(V2, V2);
      Cuts.Clear();

      // Cut
      CutEdge(E, mySpine, Cuts);

      if (Cuts.IsEmpty())
      {
        B.Add(NW, E);
        MapSpine.Bind(E, E);
      }
      else
      {
        for (IteCuts.Initialize(Cuts); IteCuts.More(); IteCuts.Next())
        {
          const TopoDS_Edge& NE = TopoDS::Edge(IteCuts.Value());
          B.Add(NW, NE);
          MapSpine.Bind(NE, E);
          EdgeVertices(NE, V1, V2);
          if (!MapSpine.IsBound(V1))
            MapSpine.Bind(V1, E);
          if (!MapSpine.IsBound(V2))
            MapSpine.Bind(V2, E);
        }
      }
    }
    NW.Closed(IsClosed);
    B.Add(WorkSpine, NW);
  }

  // Construct curves 3D of the spine
  BRepLib::BuildCurves3d(WorkSpine);

#ifdef DRAW
  if (AffichEdge)
  {
    char name[100];
    Sprintf(name, "workspine");
    DBRep::Set(name, WorkSpine);
  }
#endif
}

//=================================================================================================

const TopoDS_Shape& BRepFill_Evolved::Top() const
{
  return myTop;
}

//=================================================================================================

const TopoDS_Shape& BRepFill_Evolved::Bottom() const
{
  return myBottom;
}

//=================================================================================================

const NCollection_List<TopoDS_Shape>& BRepFill_Evolved::GeneratedShapes(
  const TopoDS_Shape& SpineShape,
  const TopoDS_Shape& ProfShape) const
{
  if (myMap.IsBound(SpineShape) && myMap(SpineShape).IsBound(ProfShape))
  {
    return myMap(SpineShape)(ProfShape);
  }
  else
  {
    static NCollection_List<TopoDS_Shape> Empty;
    return Empty;
  }
}

//=================================================================================================

NCollection_DataMap<
  TopoDS_Shape,
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
  TopTools_ShapeMapHasher>&
  BRepFill_Evolved::Generated()
{
  return myMap;
}

//=================================================================================================

static TopAbs_Orientation Compare(const TopoDS_Edge& E1, const TopoDS_Edge& E2)
{
  TopAbs_Orientation OO = TopAbs_FORWARD;
  TopoDS_Vertex      V1[2], V2[2];
  TopExp::Vertices(E1, V1[0], V1[1]);
  TopExp::Vertices(E2, V2[0], V2[1]);
  gp_Pnt P1 = BRep_Tool::Pnt(V1[0]);
  gp_Pnt P2 = BRep_Tool::Pnt(V2[0]);
  gp_Pnt P3 = BRep_Tool::Pnt(V2[1]);
  if (P1.Distance(P3) < P1.Distance(P2))
    OO = TopAbs_REVERSED;

  return OO;
}

//=================================================================================================

void BRepFill_Evolved::Add(BRepFill_Evolved& Vevo, const TopoDS_Wire& Prof, BRepTools_Quilt& Glue)

{
  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>& MapVevo = Vevo.Generated();
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>::
    Iterator iteP;
  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>::Iterator iteS;
  TopoDS_Shape                         CurrentSpine, CurrentProf;

  if (Vevo.Shape().IsNull())
    return;

  //-------------------------------------------------
  // Find wires common to <me> and <Vevo>.
  //-------------------------------------------------

  TopExp_Explorer ExProf;
  for (ExProf.Init(Prof, TopAbs_VERTEX); ExProf.More(); ExProf.Next())
  {
    const TopoDS_Shape& VV = ExProf.Current();
    //---------------------------------------------------------------
    // Parse edges generated by VV in myMap if they existent
    // and Bind in Glue
    //---------------------------------------------------------------

    //------------------------------------------------- -------------
    // Note: the curves of of reinforced edges are in the same direction
    //          if one remains on the same edge.
    //          if one passes from left to the right they are inverted.
    //------------------------------------------------- -------------
    bool Commun = false;
    Relative(myProfile, Prof, TopoDS::Vertex(VV), Commun);

    if (Commun)
    {
      for (iteS.Initialize(myMap); iteS.More(); iteS.Next())
      {
        const TopoDS_Shape& SP = iteS.Key();
        if (iteS.Value().IsBound(VV) && MapVevo.IsBound(SP) && MapVevo(SP).IsBound(VV))
        {

          const NCollection_List<TopoDS_Shape>&    MyList   = myMap(SP)(VV);
          const NCollection_List<TopoDS_Shape>&    VevoList = Vevo.GeneratedShapes(SP, VV);
          NCollection_List<TopoDS_Shape>::Iterator MyIte(MyList);
          NCollection_List<TopoDS_Shape>::Iterator VevoIte(VevoList);
          for (; MyIte.More(); MyIte.Next(), VevoIte.Next())
          {
            const TopoDS_Edge& ME           = TopoDS::Edge(MyIte.Value());
            const TopoDS_Edge& VE           = TopoDS::Edge(VevoIte.Value());
            TopAbs_Orientation OG           = Compare(ME, VE);
            TopoDS_Shape       aLocalShape  = VE.Oriented(TopAbs_FORWARD);
            TopoDS_Shape       aLocalShape2 = ME.Oriented(OG);
            Glue.Bind(TopoDS::Edge(aLocalShape), TopoDS::Edge(aLocalShape2));
            //	    Glue.Bind(TopoDS::Edge(VE.Oriented (TopAbs_FORWARD)),
            //		      TopoDS::Edge(ME.Oriented (OG)));
          }
        }
      }
    }
  }
  Glue.Add(Vevo.Shape());

  //----------------------------------------------------------
  // Add map of elements generate in Vevo in myMap.
  //----------------------------------------------------------
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
                                 EmptyMap;
  NCollection_List<TopoDS_Shape> EmptyList;

  for (iteS.Initialize(MapVevo); iteS.More(); iteS.Next())
  {
    CurrentSpine = iteS.Key();
    for (iteP.Initialize(MapVevo(CurrentSpine)); iteP.More(); iteP.Next())
    {
      CurrentProf = iteP.Key();
      if (!myMap.IsBound(CurrentSpine))
      {
        //------------------------------------------------
        // The element of spine is not yet present .
        // => previous profile not on the border.
        //-------------------------------------------------
        myMap.Bind(CurrentSpine, EmptyMap);
      }
      if (!myMap(CurrentSpine).IsBound(CurrentProf))
      {
        myMap(CurrentSpine).Bind(CurrentProf, EmptyList);
        const NCollection_List<TopoDS_Shape>&    GenShapes = MapVevo(CurrentSpine)(CurrentProf);
        NCollection_List<TopoDS_Shape>::Iterator itl(GenShapes);
        for (; itl.More(); itl.Next())
        {
          // during Glue.Add the shared shapes are recreated.
          if (Glue.IsCopied(itl.Value()))
            myMap(CurrentSpine)(CurrentProf).Append(Glue.Copy(itl.Value()));
          else
            myMap(CurrentSpine)(CurrentProf).Append(itl.Value());
        }
      }
    }
  }
}

//=================================================================================================

TopoDS_Shape& BRepFill_Evolved::ChangeShape()
{
  return myShape;
}

//=================================================================================================

void BRepFill_Evolved::Transfert(
  BRepFill_Evolved&                                                               Vevo,
  const NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapProf,
  const NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapSpine,
  const TopLoc_Location&                                                          LS,
  const TopLoc_Location&                                                          InitLS,
  const TopLoc_Location&                                                          InitLP)
{
  //----------------------------------------------------------------
  // Transfer the shape from Vevo in myShape and Reposition shapes.
  //----------------------------------------------------------------
  myShape = Vevo.Shape();
  mySpine.Location(InitLS);
  myProfile.Location(InitLP);
  myShape.Move(LS);

  //
  // Expecting for better, the Same Parameter is forced here
  //  ( Pb Sameparameter between YaPlanar and Tuyaux
  //
  BRep_Builder    B;
  TopExp_Explorer ex(myShape, TopAbs_EDGE);
  while (ex.More())
  {
    B.SameRange(TopoDS::Edge(ex.Current()), false);
    B.SameParameter(TopoDS::Edge(ex.Current()), false);
    BRepLib::SameParameter(TopoDS::Edge(ex.Current()));
    ex.Next();
  }

  //--------------------------------------------------------------
  // Transfer of myMap of Vevo into myMap.
  //--------------------------------------------------------------
  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>::Iterator iteS;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>::
    Iterator iteP;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>
                                 EmptyMap;
  NCollection_List<TopoDS_Shape> EmptyList;
  TopoDS_Shape                   InitialSpine, InitialProf;

  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>& MapVevo = Vevo.Generated();

  for (iteS.Initialize(MapVevo); iteS.More(); iteS.Next())
  {
    InitialSpine = MapSpine(iteS.Key());
    InitialSpine.Move(LS);

    for (iteP.Initialize(MapVevo(iteS.Key())); iteP.More(); iteP.Next())
    {
      InitialProf = MapProf(iteP.Key());
      InitialProf.Location(InitLP);

      NCollection_List<TopoDS_Shape>& GenShapes =
        MapVevo.ChangeFind(iteS.Key()).ChangeFind(iteP.Key());

      NCollection_List<TopoDS_Shape>::Iterator itl;
      for (itl.Initialize(GenShapes); itl.More(); itl.Next())
      {
        itl.ChangeValue().Move(LS);
      }

      if (!myMap.IsBound(InitialSpine))
      {
        myMap.Bind(InitialSpine, EmptyMap);
      }

      if (!myMap(InitialSpine).IsBound(InitialProf))
      {
        myMap(InitialSpine).Bind(InitialProf, EmptyList);
      }
      myMap(InitialSpine)(InitialProf).Append(GenShapes);
    }
  }
  //--------------------------------------------------------------
  // Transfer of Top and Bottom of Vevo in myTop and myBottom.
  //--------------------------------------------------------------
  myTop = Vevo.Top();
  myTop.Move(LS);
  myBottom = Vevo.Bottom();
  myBottom.Move(LS);
}

//=================================================================================================

bool BRepFill_Evolved::IsDone() const
{
  return myIsDone;
}

//=================================================================================================

const TopoDS_Shape& BRepFill_Evolved::Shape() const
{
  return myShape;
}

//=================================================================================================

GeomAbs_JoinType BRepFill_Evolved::JoinType() const
{
  return myJoinType;
}

//=================================================================================================

void BRepFill_Evolved::AddTopAndBottom(BRepTools_Quilt& Glue)
{
  //  return first and last vertex of the profile.
  TopoDS_Vertex V[2];
  TopExp::Vertices(myProfile, V[0], V[1]);
  if (V[0].IsSame(V[1]))
    return;

  NCollection_List<TopoDS_Shape>::Iterator itL;
  bool                                     ToReverse = false;
  for (int i = 0; i <= 1; i++)
  {

    BRepAlgo_Loop Loop;
    // Construction of supports.
    gp_Pln      S(0., 0., 1., -Altitud(V[i]));
    TopoDS_Face F = BRepLib_MakeFace(S);
    Loop.Init(F);

    TopExp_Explorer                                        ExpSpine(mySpine, TopAbs_EDGE);
    NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> View;

    for (; ExpSpine.More(); ExpSpine.Next())
    {
      const TopoDS_Edge&                    ES                 = TopoDS::Edge(ExpSpine.Current());
      const NCollection_List<TopoDS_Shape>& L                  = GeneratedShapes(ES, V[i]);
      bool                                  ComputeOrientation = false;

      for (itL.Initialize(L); itL.More(); itL.Next())
      {
        const TopoDS_Edge& E = TopoDS::Edge(itL.Value());

        if (!ComputeOrientation)
        {
          BRepAdaptor_Curve C1(ES);
          BRepAdaptor_Curve C2(E);
          double            f, l, fs, ls;
          BRep_Tool::Range(E, f, l);
          BRep_Tool::Range(ES, fs, ls);
          double u  = 0.3 * f + 0.7 * l;
          double us = 0.3 * fs + 0.7 * ls;
          gp_Pnt P;
          gp_Vec V1, V2;
          C1.D1(us, P, V1);
          C2.D1(u, P, V2);
          ToReverse          = (V1.Dot(V2) < 0.);
          ComputeOrientation = true;
        }

        TopAbs_Orientation Or = ES.Orientation();
        if (ToReverse)
          Or = TopAbs::Reverse(Or);
        TopoDS_Shape aLocalShape = E.Oriented(Or);
        Loop.AddConstEdge(TopoDS::Edge(aLocalShape));
        //	Loop.AddConstEdge(TopoDS::Edge(E.Oriented(Or)));
      }
    }

    gp_Pnt PV    = BRep_Tool::Pnt(V[i]);
    bool   IsOut = PV.Y() < 0;

    for (ExpSpine.Init(mySpine, TopAbs_VERTEX); ExpSpine.More(); ExpSpine.Next())
    {
      const TopoDS_Vertex& ES = TopoDS::Vertex(ExpSpine.Current());
      if (View.Add(ES))
      {
        const NCollection_List<TopoDS_Shape>& L = GeneratedShapes(ES, V[i]);
        for (itL.Initialize(L); itL.More(); itL.Next())
        {
          const TopoDS_Edge& E = TopoDS::Edge(itL.Value());
          if (!BRep_Tool::Degenerated(E))
          {
            // the center of circle (ie vertex) is IN the cap if vertex IsOut
            //                                    OUT                   !IsOut
            BRepAdaptor_Curve C(E);
            double            f, l;
            BRep_Tool::Range(E, f, l);
            double u = 0.3 * f + 0.7 * l;
            gp_Pnt P = BRep_Tool::Pnt(ES);
            gp_Pnt PC;
            gp_Vec VC;
            C.D1(u, PC, VC);
            gp_Vec aPPC(P, PC);
            gp_Vec Prod = aPPC.Crossed(VC);
            if (IsOut)
            {
              ToReverse = Prod.Z() < 0.;
            }
            else
            {
              ToReverse = Prod.Z() > 0.;
            }
            TopAbs_Orientation Or = TopAbs_FORWARD;
            if (ToReverse)
              Or = TopAbs_REVERSED;
            TopoDS_Shape aLocalShape = E.Oriented(Or);
            Loop.AddConstEdge(TopoDS::Edge(aLocalShape));
            //	    Loop.AddConstEdge(TopoDS::Edge(E.Oriented(Or)));
          }
        }
      }
    }

    Loop.Perform();
    Loop.WiresToFaces();
    const NCollection_List<TopoDS_Shape>&    L = Loop.NewFaces();
    NCollection_List<TopoDS_Shape>::Iterator anIterL(L);

    // Maj of myTop and myBottom for the history
    // and addition of constructed faces.
    TopoDS_Compound Bouchon;
    BRep_Builder    B;
    B.MakeCompound(Bouchon);
    int j = 0;

    for (anIterL.Initialize(L); anIterL.More(); anIterL.Next())
    {
      j++;
      Glue.Add(anIterL.Value());
      if (j == 1 && i == 0)
        myTop = anIterL.Value();
      if (j == 1 && i == 1)
        myBottom = anIterL.Value();
      B.Add(Bouchon, anIterL.Value());
    }
    if (i == 0 && j > 1)
      myTop = Bouchon;
    if (i == 1 && j > 1)
      myBottom = Bouchon;
  }
}

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

void BRepFill_Evolved::MakeSolid()
{

  TopExp_Explorer exp(myShape, TopAbs_SHELL);
  int             ish = 0;
  TopoDS_Compound Res;
  TopoDS_Solid    Sol;
  BRep_Builder    B;
  B.MakeCompound(Res);

  for (; exp.More(); exp.Next())
  {
    const TopoDS_Shape& Sh = exp.Current();
    B.MakeSolid(Sol);
    B.Add(Sol, Sh);
    BRepClass3d_SolidClassifier SC(Sol);
    SC.PerformInfinitePoint(BRepFill_Confusion());
    if (SC.State() == TopAbs_IN)
    {
      B.MakeSolid(Sol);
      B.Add(Sol, Sh.Reversed());
    }
    B.Add(Res, Sol);
    ish++;
  }
  if (ish == 1)
  {
    myShape = Sol;
  }
  else
  {
    myShape = Res;
  }
}

//=================================================================================================

void BRepFill_Evolved::MakePipe(const TopoDS_Edge& SE, const gp_Ax3& AxeRef)
{
  BRepTools_WireExplorer ProfExp;
  TopExp_Explorer        FaceExp;

  gp_Trsf trsf;
  if (Side(myProfile, BRepFill_Confusion()) > 3)
  { // side right
    trsf.SetRotation(gp::OZ(), M_PI);
  }
  TopLoc_Location DumLoc(trsf);
  TopoDS_Shape    aLocalShape = myProfile.Moved(DumLoc);
  TopoDS_Wire     DummyProf   = PutProfilAt(TopoDS::Wire(aLocalShape), AxeRef, SE, mySpine, true);
  //  TopoDS_Wire DummyProf =
  //    PutProfilAt (TopoDS::Wire(myProfile.Moved(DumLoc)),
  //		 AxeRef,SE,
  //		 mySpine,true);

  // Copy of the profile to avoid the accumulation of
  // locations on the Edges of myProfile!

  occ::handle<BRepTools_TrsfModification> TrsfMod = new BRepTools_TrsfModification(gp_Trsf());
  BRepTools_Modifier                      Modif(DummyProf, TrsfMod);

  TopoDS_Wire GenProf = TopoDS::Wire(Modif.ModifiedShape(DummyProf));

#ifdef DRAW
  if (AffichGeom)
  {
    char name[100];
    Sprintf(name, "EVOLBASE_%d", ++NbFACES);
    DBRep::Set(name, SE);
    Sprintf(name, "EVOLPROF_%d", NbFACES);
    DBRep::Set(name, GenProf);
  }
#endif

  BRepFill_Pipe Pipe(BRepLib_MakeWire(SE), GenProf);
  // BRepFill_Pipe Pipe = BRepFill_Pipe(BRepLib_MakeWire(SE),GenProf);

#ifdef DRAW
  if (AffichGeom)
  {
    char name[100];
    Sprintf(name, "EVOL_%d", ++NbFACES);
    DBRep::Set(name, Pipe.Shape());
  }
#endif
  //---------------------------------------------
  // Arrangement of Tubes in myMap.
  //---------------------------------------------

  BRepTools_WireExplorer         GenProfExp;
  NCollection_List<TopoDS_Shape> L;
  TopoDS_Vertex                  VF, VL, VFG, VLG;
  bool                           FirstVertex = true;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> P;

  myMap.Bind(SE, P);

  for (ProfExp.Init(myProfile), GenProfExp.Init(GenProf); ProfExp.More();
       ProfExp.Next(), GenProfExp.Next())
  {

    EdgeVertices(ProfExp.Current(), VF, VL);
    EdgeVertices(GenProfExp.Current(), VFG, VLG);

    if (FirstVertex)
    {
      myMap(SE).Bind(VF, L);
      myMap(SE)(VF).Append(Pipe.Edge(SE, VFG));
      FirstVertex = false;
    }
    myMap(SE).Bind(VL, L);
    myMap(SE)(VL).Append(Pipe.Edge(SE, VLG));
    myMap(SE).Bind(ProfExp.Current(), L);
    myMap(SE)(ProfExp.Current()).Append(Pipe.Face(SE, GenProfExp.Current()));
  }
}

//=================================================================================================

void BRepFill_Evolved::MakeRevol(const TopoDS_Edge&   SE,
                                 const TopoDS_Vertex& VLast,
                                 const gp_Ax3&        AxeRef)
{
  BRepTools_WireExplorer ProfExp;
  TopExp_Explorer        FaceExp;

  gp_Trsf trsf;
  if (Side(myProfile, BRepFill_Confusion()) > 3)
  { // side right
    trsf.SetRotation(gp::OZ(), M_PI);
  }
  TopLoc_Location DumLoc(trsf);
  TopoDS_Shape    aLocalShape = myProfile.Moved(DumLoc);
  TopoDS_Wire     GenProf     = PutProfilAt(TopoDS::Wire(aLocalShape), AxeRef, SE, mySpine, false);
  //  TopoDS_Wire GenProf =
  //    PutProfilAt (TopoDS::Wire(myProfile.Moved(DumLoc)),
  //		 AxeRef,SE,
  //		 mySpine,false);

  gp_Ax1 AxeRev(BRep_Tool::Pnt(VLast), -gp::DZ());

  // Position of the sewing on the edge of the spine
  // so that the bissectrices didn't cross the sewings.
  gp_Trsf dummy;
  dummy.SetRotation(AxeRev, 1.5 * M_PI);
  TopLoc_Location DummyLoc(dummy);
  GenProf.Move(DummyLoc);

  BRepSweep_Revol Rev(GenProf, AxeRev, true);

#ifdef DRAW
  if (AffichGeom)
  {
    char name[100];
    Sprintf(name, "EVOLBASE_%d", ++NbFACES);
    DrawTrSurf::Set(name, new Geom_Line(AxeRev));
    //    DrawTrSurf::Set(name,new Geom_Line(AxeRev));
    Sprintf(name, "EVOLPROF_%d", NbFACES);
    DBRep::Set(name, GenProf);

    Sprintf(name, "EVOL_%d", NbFACES);
    DBRep::Set(name, Rev.Shape());
  }
#endif
  //--------------------------------------------
  // Arrangement of revolutions in myMap.
  //---------------------------------------------
  BRepTools_WireExplorer         GenProfExp;
  NCollection_List<TopoDS_Shape> L;
  TopoDS_Vertex                  VF, VL, VFG, VLG;
  bool                           FirstVertex = true;
  NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> R;

  myMap.Bind(VLast, R);

  for (ProfExp.Init(myProfile), GenProfExp.Init(GenProf); ProfExp.More();
       ProfExp.Next(), GenProfExp.Next())
  {

    EdgeVertices(ProfExp.Current(), VF, VL);
    EdgeVertices(GenProfExp.Current(), VFG, VLG);

    TopAbs_Orientation Or = GenProfExp.Current().Orientation();

    if (FirstVertex)
    {
      myMap(VLast).Bind(VF, L);
      const TopoDS_Shape& RV = Rev.Shape(VFG);
      //      TopAbs_Orientation OO = TopAbs::Compose(RV.Orientation(),Or);
      TopAbs_Orientation OO = RV.Orientation();
      myMap(VLast)(VF).Append(RV.Oriented(OO));
      FirstVertex = false;
    }
    myMap(VLast).Bind(ProfExp.Current(), L);
    const TopoDS_Shape& RF = Rev.Shape(GenProfExp.Current());
    TopAbs_Orientation  OO = TopAbs::Compose(RF.Orientation(), Or);

    myMap(VLast)(ProfExp.Current()).Append(RF.Oriented(OO));
    myMap(VLast).Bind(VL, L);
    const TopoDS_Shape& RV = Rev.Shape(VLG);
    //    OO = TopAbs::Compose(RV.Orientation(),Or);
    OO = RV.Orientation();
    myMap(VLast)(VL).Append(RV.Oriented(OO));
  }
}

//=================================================================================================

TopLoc_Location BRepFill_Evolved::FindLocation(const TopoDS_Face& Face) const
{
  TopLoc_Location           L;
  occ::handle<Geom_Surface> S;
  S = BRep_Tool::Surface(Face, L);

  if (!S->IsKind(STANDARD_TYPE(Geom_Plane)))
  {
    BRepLib_FindSurface FS(Face, -1, true);
    if (FS.Found())
    {
      S = FS.Surface();
      L = FS.Location();
    }
    else
      throw Standard_NoSuchObject("BRepFill_Evolved : The Face is not planar");
  }

  if (!L.IsIdentity())
    S = occ::down_cast<Geom_Surface>(S->Transformed(L.Transformation()));

  occ::handle<Geom_Plane> P    = occ::down_cast<Geom_Plane>(S);
  gp_Ax3                  Axis = P->Position();

  gp_Trsf T;
  gp_Ax3  AxeRef(gp_Pnt(0., 0., 0.), gp_Dir(gp_Dir::D::Z), gp_Dir(gp_Dir::D::X));
  T.SetTransformation(AxeRef, Axis);

  return TopLoc_Location(T);
}

//=================================================================================================

void BRepFill_Evolved::TransformInitWork(const TopLoc_Location& LS, const TopLoc_Location& LP)
{
  mySpine.Move(LS);
  myProfile.Move(LP);

#ifdef DRAW
  if (AffichEdge)
  {
    char name[100];
    Sprintf(name, "movedspine");
    TopoDS_Face SL = mySpine;
    DBRep::Set(name, SL);
    Sprintf(name, "movedprofile");
    TopoDS_Wire PL = myProfile;
    DBRep::Set(name, PL);
  }
#endif
}

//=======================================================================
// function : ContinuityOnOffsetEdge
// purpose  : Coding of regularities on edges parallel to CutVevo
//           common to left and right parts of volevo.
//=======================================================================
void BRepFill_Evolved::ContinuityOnOffsetEdge(const NCollection_List<TopoDS_Shape>&)
{
  BRepTools_WireExplorer WExp;
  NCollection_DataMap<
    TopoDS_Shape,
    NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>,
    TopTools_ShapeMapHasher>::Iterator iteS;
  TopoDS_Vertex                        VF, VL, V;
  TopoDS_Edge                          PrecE, CurE, FirstE;
  BRep_Builder                         B;

  WExp.Init(myProfile);
  FirstE = WExp.Current();
  PrecE  = FirstE;
  EdgeVertices(FirstE, VF, V);
  if (WExp.More())
    WExp.Next();

  for (; WExp.More(); WExp.Next())
  {
    CurE = WExp.Current();
    V    = WExp.CurrentVertex();

    if (DistanceToOZ(V) <= BRepFill_Confusion())
    {
      // the regularities are already coded on the edges of elementary volevos
      double            U1 = BRep_Tool::Parameter(V, CurE);
      double            U2 = BRep_Tool::Parameter(V, PrecE);
      BRepAdaptor_Curve Curve1(CurE);
      BRepAdaptor_Curve Curve2(PrecE);
      GeomAbs_Shape     Continuity = BRepLProp::Continuity(Curve1, Curve2, U1, U2);

      if (Continuity >= 1)
      {
        //-----------------------------------------------------
        // Code continuity for all edges generated by V.
        //-----------------------------------------------------
        for (iteS.Initialize(myMap); iteS.More(); iteS.Next())
        {
          const TopoDS_Shape& SP = iteS.Key();
          if (myMap(SP).IsBound(V) && myMap(SP).IsBound(CurE) && myMap(SP).IsBound(PrecE))
          {
            if (!myMap(SP)(V).IsEmpty() && !myMap(SP)(CurE).IsEmpty()
                && !myMap(SP)(PrecE).IsEmpty())
              B.Continuity(TopoDS::Edge(myMap(SP)(V).First()),
                           TopoDS::Face(myMap(SP)(CurE).First()),
                           TopoDS::Face(myMap(SP)(PrecE).First()),
                           Continuity);
          }
        }
      }
    }
    PrecE = CurE;
  }

  EdgeVertices(PrecE, V, VL);

  if (VF.IsSame(VL))
  {
    // Closed profile.
    double            U1 = BRep_Tool::Parameter(VF, CurE);
    double            U2 = BRep_Tool::Parameter(VF, FirstE);
    BRepAdaptor_Curve Curve1(CurE);
    BRepAdaptor_Curve Curve2(FirstE);
    GeomAbs_Shape     Continuity = BRepLProp::Continuity(Curve1, Curve2, U1, U2);

    if (Continuity >= 1)
    {
      //---------------------------------------------
      // Code continuity for all edges generated by V.
      //---------------------------------------------
      for (iteS.Initialize(myMap); iteS.More(); iteS.Next())
      {
        const TopoDS_Shape& SP = iteS.Key();
        if (myMap(SP).IsBound(VF) && myMap(SP).IsBound(CurE) && myMap(SP).IsBound(FirstE))
        {
          if (!myMap(SP)(VF).IsEmpty() && !myMap(SP)(CurE).IsEmpty()
              && !myMap(SP)(FirstE).IsEmpty())
            B.Continuity(TopoDS::Edge(myMap(SP)(VF).First()),
                         TopoDS::Face(myMap(SP)(CurE).First()),
                         TopoDS::Face(myMap(SP)(FirstE).First()),
                         Continuity);
        }
      }
    }
  }
}

//=======================================================================
// function : AddDegeneratedEdge
// purpose  : degenerated edges can be missing in some face
//           the missing degenerated edges have vertices corresponding
//           to node of the map.
//           Now it is enough to compare points UV of vertices
//           on edges with a certain tolerance.
//=======================================================================

static void AddDegeneratedEdge(TopoDS_Face& F, TopoDS_Wire& W)
{
  TopLoc_Location           L;
  occ::handle<Geom_Surface> S = BRep_Tool::Surface(F, L);
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
  {
    occ::handle<Geom_Surface> SB =
      occ::down_cast<Geom_RectangularTrimmedSurface>(S)->BasisSurface();
    if (SB->DynamicType() == STANDARD_TYPE(Geom_Plane))
    {
      return;
    }
  }

  if (S->DynamicType() == STANDARD_TYPE(Geom_Plane))
  {
    return;
  }

  BRep_Builder B;
  double       TolConf = 1.e-4;

  bool Change = true;

  while (Change)
  {
    Change = false;
    BRepTools_WireExplorer WE(W, F);
    gp_Pnt2d               PF, PrevP, P1, P2;
    TopoDS_Vertex          VF, V1, V2;

    for (; WE.More(); WE.Next())
    {
      const TopoDS_Edge& CE = WE.Current();
      EdgeVertices(CE, V1, V2);
      if (CE.Orientation() == TopAbs_REVERSED)
        BRep_Tool::UVPoints(CE, F, P2, P1);
      else
        BRep_Tool::UVPoints(CE, F, P1, P2);
      if (VF.IsNull())
      {
        VF = V1;
        PF = P1;
      }
      else
      {
        if (!P1.IsEqual(PrevP, TolConf))
        {
          // degenerated edge to be inserted.
          Change = true;
          gp_Vec2d                         V(PrevP, P1);
          occ::handle<Geom2d_Line>         C2d = new Geom2d_Line(PrevP, gp_Dir2d(V));
          double                           f = 0, l = PrevP.Distance(P1);
          occ::handle<Geom2d_TrimmedCurve> CT = new Geom2d_TrimmedCurve(C2d, f, l);
          TopoDS_Edge                      NE = BRepLib_MakeEdge(C2d, S);
          B.Degenerated(NE, true);
          B.Add(NE, V1.Oriented(TopAbs_FORWARD));
          B.Add(NE, V1.Oriented(TopAbs_REVERSED));
          B.Range(NE, f, l);
          B.Add(W, NE);
          break;
        }
      }
      PrevP = P2;
    }
    if (!Change && VF.IsSame(V2))
    { // closed
      if (!PF.IsEqual(P2, TolConf))
      {
        // Degenerated edge to be inserted.
        Change = true;
        gp_Vec2d                         V(P2, PF);
        occ::handle<Geom2d_Line>         C2d = new Geom2d_Line(P2, gp_Dir2d(V));
        double                           f = 0, l = P2.Distance(PF);
        occ::handle<Geom2d_TrimmedCurve> CT = new Geom2d_TrimmedCurve(C2d, f, l);
        TopoDS_Edge                      NE = BRepLib_MakeEdge(C2d, S);
        B.Degenerated(NE, true);
        B.Add(NE, VF.Oriented(TopAbs_FORWARD));
        B.Add(NE, VF.Oriented(TopAbs_REVERSED));
        B.Range(NE, f, l);
        B.Add(W, NE);
      }
    }
  }
}

//=================================================================================================

void TrimFace(const TopoDS_Face&                  Face,
              NCollection_Sequence<TopoDS_Shape>& TheEdges,
              NCollection_Sequence<TopoDS_Shape>& S)
{

#ifdef DRAW
  int NB = TheEdges.Length();
  if (AffichEdge)
  {
    char name[100];
    std::cout << " TrimFace " << ++NbTRIMFACES;
    std::cout << " : " << NB << " edges within the restriction" << std::endl;
    for (int j = 1; j <= NB; j++)
    {
      Sprintf(name, "TRIMEDGE_%d_%d", NbTRIMFACES, j);
      DBRep::Set(name, TopoDS::Edge(TheEdges.Value(j)));
    }
  }
#endif

  //--------------------------------------
  // Creation of wires limiting faces.
  //--------------------------------------
  BRep_Builder TheBuilder;

  int         NbEdges;
  bool        NewWire = true;
  bool        AddEdge = false;
  TopoDS_Wire GoodWire;

  while (!TheEdges.IsEmpty())
  {

    BRepLib_MakeWire MWire(TopoDS::Edge(TheEdges.First()));
    GoodWire = MWire.Wire();
    TheEdges.Remove(1);
    NbEdges = TheEdges.Length();
    NewWire = false;

    while (!NewWire)
    {
      AddEdge = false;

      for (int i = 1; i <= NbEdges && !AddEdge; i++)
      {
        const TopoDS_Edge& E = TopoDS::Edge(TheEdges.Value(i));
        if (BRep_Tool::Degenerated(E))
        {
          TheEdges.Remove(i);
          AddEdge  = true;
          NbEdges  = TheEdges.Length();
          GoodWire = MWire.Wire();
        }
        else
        {
          MWire.Add(E);
          if (MWire.Error() == BRepLib_WireDone)
          {
            // the connection is successful
            // it is removed from the sequence and one restarts from the beginning.
            TheEdges.Remove(i);
            AddEdge  = true;
            NbEdges  = TheEdges.Length();
            GoodWire = MWire.Wire();
          }
        }
      }
      NewWire = (!AddEdge);
    }
    TopoDS_Shape aLocalShape = Face.EmptyCopied();
    TopoDS_Face  FaceCut     = TopoDS::Face(aLocalShape);
    //    TopoDS_Face FaceCut = TopoDS::Face(Face.EmptyCopied());
    FaceCut.Orientation(TopAbs_FORWARD);
    BRepTools::Update(FaceCut);
    AddDegeneratedEdge(FaceCut, GoodWire);
    TheBuilder.Add(FaceCut, GoodWire);
    FaceCut.Orientation(Face.Orientation());
    S.Append(FaceCut);
  }
}

//=================================================================================================

const TopoDS_Wire PutProfilAt(const TopoDS_Wire& ProfRef,
                              const gp_Ax3&      AxeRef,
                              const TopoDS_Edge& E,
                              const TopoDS_Face& F,
                              const bool         AtStart)
{
  gp_Vec2d                  D1;
  gp_Pnt2d                  P;
  TopoDS_Wire               Prof;
  occ::handle<Geom2d_Curve> C2d;
  double                    First, Last;

  C2d = BRep_Tool::CurveOnSurface(E, F, First, Last);
  if (C2d.IsNull())
  {
    throw Standard_ConstructionError("ConstructionError in PutProfilAt");
  }

  if (E.Orientation() == TopAbs_REVERSED)
  {
    if (!AtStart)
      C2d->D1(First, P, D1);
    else
      C2d->D1(Last, P, D1);
    D1.Reverse();
  }
  else
  {
    if (!AtStart)
      C2d->D1(Last, P, D1);
    else
      C2d->D1(First, P, D1);
  }
  gp_Pnt P3d(P.X(), P.Y(), 0.);
  gp_Vec V3d(D1.X(), D1.Y(), 0.);

  gp_Ax3  Ax(P3d, gp::DZ(), V3d);
  gp_Trsf Trans;
  Trans.SetTransformation(Ax, AxeRef);
  TopoDS_Shape aLocalShape = ProfRef.Moved(TopLoc_Location(Trans));
  Prof                     = TopoDS::Wire(aLocalShape);
  //  Prof = TopoDS::Wire(ProfRef.Moved(TopLoc_Location(Trans)));
  return Prof;
}

//=================================================================================================

void TrimEdge(const TopoDS_Edge&                        Edge,
              const NCollection_Sequence<TopoDS_Shape>& TheEdgesControle,
              NCollection_Sequence<TopoDS_Shape>&       TheVer,
              NCollection_Sequence<double>&             ThePar,
              NCollection_Sequence<TopoDS_Shape>&       S)
{
  bool         Change = true;
  BRep_Builder TheBuilder;
  S.Clear();
  //------------------------------------------------------------
  // Parse two sequences depending on the parameter on the edge.
  //------------------------------------------------------------
  while (Change)
  {
    Change = false;
    for (int i = 1; i < ThePar.Length(); i++)
    {
      if (ThePar.Value(i) > ThePar.Value(i + 1))
      {
        ThePar.Exchange(i, i + 1);
        TheVer.Exchange(i, i + 1);
        Change = true;
      }
    }
  }

  //----------------------------------------------------------
  // If a vertex is not in the proofing point, it is removed.
  //----------------------------------------------------------
  if (!BRep_Tool::Degenerated(Edge))
  {
    for (int k = 1; k <= TheVer.Length(); k++)
    {
      if (DoubleOrNotInFace(TheEdgesControle, TopoDS::Vertex(TheVer.Value(k))))
      {
        TheVer.Remove(k);
        ThePar.Remove(k);
        k--;
      }
    }
  }

  //-------------------------------------------------------------------
  // Processing of double vertices for non-degenerated edges.
  // If a vertex_double appears twice in the edges of control,
  // the vertex is eliminated .
  // otherwise its only representation is preserved.
  //-------------------------------------------------------------------
  if (!BRep_Tool::Degenerated(Edge))
  {
    for (int k = 1; k < TheVer.Length(); k++)
    {
      if (TheVer.Value(k).IsSame(TheVer.Value(k + 1)))
      {
        TheVer.Remove(k + 1);
        ThePar.Remove(k + 1);
        if (DoubleOrNotInFace(TheEdgesControle, TopoDS::Vertex(TheVer.Value(k))))
        {
          TheVer.Remove(k);
          ThePar.Remove(k);
          //	  k--;
        }
        k--;
      }
    }
  }

  //-----------------------------------------------------------
  // Creation of edges.
  // the number of vertices should be even. The edges to be created leave
  // from a vertex with uneven index i to vertex i+1;
  //-----------------------------------------------------------
  for (int k = 1; k < TheVer.Length(); k = k + 2)
  {
    TopoDS_Shape aLocalShape = Edge.EmptyCopied();
    TopoDS_Edge  NewEdge     = TopoDS::Edge(aLocalShape);
    //    TopoDS_Edge NewEdge = TopoDS::Edge(Edge.EmptyCopied());

    if (NewEdge.Orientation() == TopAbs_REVERSED)
    {
      TheBuilder.Add(NewEdge, TheVer.Value(k).Oriented(TopAbs_REVERSED));
      TheBuilder.Add(NewEdge, TheVer.Value(k + 1).Oriented(TopAbs_FORWARD));
    }
    else
    {
      TheBuilder.Add(NewEdge, TheVer.Value(k).Oriented(TopAbs_FORWARD));
      TheBuilder.Add(NewEdge, TheVer.Value(k + 1).Oriented(TopAbs_REVERSED));
    }
    TheBuilder.Range(NewEdge, ThePar.Value(k), ThePar.Value(k + 1));
    //  modified by NIZHNY-EAP Wed Dec 22 12:09:48 1999 ___BEGIN___
    BRepLib::UpdateTolerances(NewEdge, false);
    //  modified by NIZHNY-EAP Wed Dec 22 13:34:19 1999 ___END___
    S.Append(NewEdge);
  }
}

//=================================================================================================

void ComputeIntervals(const NCollection_Sequence<TopoDS_Shape>& VOnF,
                      const NCollection_Sequence<TopoDS_Shape>& VOnL,
                      const NCollection_Sequence<gp_Pnt>&       ParOnF,
                      const NCollection_Sequence<gp_Pnt>&       ParOnL,
                      const BRepFill_TrimSurfaceTool&           Trim,
                      const occ::handle<Geom2d_Curve>&          Bis,
                      const TopoDS_Vertex&                      VS,
                      const TopoDS_Vertex&                      VE,
                      NCollection_Sequence<double>&             FirstPar,
                      NCollection_Sequence<double>&             LastPar,
                      NCollection_Sequence<TopoDS_Shape>&       FirstV,
                      NCollection_Sequence<TopoDS_Shape>&       LastV)
{
  int          IOnF = 1, IOnL = 1;
  double       U1 = 0., U2;
  TopoDS_Shape V1, V2;

  if (!VS.IsNull())
  {
    U1 = Bis->FirstParameter();
    V1 = VS;
  }
  while (IOnF <= VOnF.Length() || IOnL <= VOnL.Length())
  {
    //---------------------------------------------------------
    // Return the smallest parameter on the bissectrice
    // corresponding to the current positions IOnF,IOnL.
    //---------------------------------------------------------
    if (IOnL > VOnL.Length()
        || (IOnF <= VOnF.Length() && ParOnF.Value(IOnF).X() < ParOnL.Value(IOnL).X()))
    {

      U2 = ParOnF.Value(IOnF).X();
      V2 = VOnF.Value(IOnF);
      IOnF++;
    }
    else
    {
      U2 = ParOnL.Value(IOnL).X();
      V2 = VOnL.Value(IOnL);
      IOnL++;
    }
    //---------------------------------------------------------------------
    // When V2 and V1 are different the medium point P of the
    // interval is tested compared to the face. If P is in the face the interval
    // is valid.
    //---------------------------------------------------------------------
    if (!V1.IsNull() && !V2.IsSame(V1))
    {
      gp_Pnt2d P = Bis->Value((U2 + U1) * 0.5);
      if (Trim.IsOnFace(P))
      {
        FirstPar.Append(U1);
        LastPar.Append(U2);
        FirstV.Append(V1);
        LastV.Append(V2);
      }
    }
    U1 = U2;
    V1 = V2;
  }

  if (!VE.IsNull())
  {
    U2 = Bis->LastParameter();
    V2 = VE;
    if (!V2.IsSame(V1))
    {
      gp_Pnt2d P = Bis->Value((U2 + U1) * 0.5);
      if (Trim.IsOnFace(P))
      {
        FirstPar.Append(U1);
        LastPar.Append(U2);
        FirstV.Append(V1);
        LastV.Append(V2);
      }
    }
  }
}

//=======================================================================
// function : Relative
// purpose  : Commun is true if two wires have V in common
//           return FORWARD if the wires near the vertex are at
//           the same side. otherwise REVERSED.
//=======================================================================
static TopAbs_Orientation Relative(const TopoDS_Wire&   W1,
                                   const TopoDS_Wire&   W2,
                                   const TopoDS_Vertex& V,
                                   bool&                Commun)
{
  TopExp_Explorer Exp;
  TopoDS_Edge     E1, E2;
  TopoDS_Vertex   V1, V2;

  for (Exp.Init(W1, TopAbs_EDGE); Exp.More(); Exp.Next())
  {
    const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
    TopExp::Vertices(E, V1, V2);
    if (V1.IsSame(V) || V2.IsSame(V))
    {
      E1 = E;
      break;
    }
  }
  for (Exp.Init(W2, TopAbs_EDGE); Exp.More(); Exp.Next())
  {
    const TopoDS_Edge& E = TopoDS::Edge(Exp.Current());
    TopExp::Vertices(E, V1, V2);
    if (V1.IsSame(V) || V2.IsSame(V))
    {
      E2 = E;
      break;
    }
  }

  if (E1.IsNull() || E2.IsNull())
  {
    Commun = false;
    return TopAbs_FORWARD;
  }
  Commun = true;

  TopoDS_Wire WW1 = BRepLib_MakeWire(E1);
  TopoDS_Wire WW2 = BRepLib_MakeWire(E2);
  double      Tol = BRepFill_Confusion();
  if (Side(WW1, Tol) < 4 && Side(WW2, Tol) < 4) // two to the left
    return TopAbs_FORWARD;
  if (Side(WW1, Tol) > 4 && Side(WW2, Tol) > 4) // two to the right
    return TopAbs_FORWARD;

  return TopAbs_REVERSED;
}

//=======================================================================
// function : IsOnFace
// purpose  : Return the position of the point defined by d1
//           in the face defined by d2 d3.
//
//           0 : the point is out of the face.
//           1 : the point is on edge corresponding to d2.
//           2 : the point is inside the face.
//           3 : the point is on edge corresponding to d3.
//=======================================================================

int PosOnFace(double d1, double d2, double d3)
{
  if (std::abs(d1 - d2) <= BRepFill_Confusion())
    return 1;
  if (std::abs(d1 - d3) <= BRepFill_Confusion())
    return 3;

  if (d2 < d3)
  {
    if (d1 > (d2 + BRepFill_Confusion()) && d1 < (d3 - BRepFill_Confusion()))
      return 2;
  }
  else
  {
    if (d1 > (d3 + BRepFill_Confusion()) && d1 < (d2 - BRepFill_Confusion()))
      return 2;
  }
  return 0;
}

//=======================================================================
// function : DoubleOrNotInFace
// purpose  : Return True if V appears zero or two times in the sequence
//           of edges EC
//=======================================================================

bool DoubleOrNotInFace(const NCollection_Sequence<TopoDS_Shape>& EC, const TopoDS_Vertex& V)
{
  bool Vu = false;

  for (int i = 1; i <= EC.Length(); i++)
  {
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(TopoDS::Edge(EC.Value(i)), V1, V2);
    if (V1.IsSame(V))
    {
      if (Vu)
        return true;
      else
        Vu = true;
    }
    if (V2.IsSame(V))
    {
      if (Vu)
        return true;
      else
        Vu = true;
    }
  }
  if (Vu)
    return false;
  else
    return true;
}

//=================================================================================================

double DistanceToOZ(const TopoDS_Vertex& V)
{
  gp_Pnt PV3d = BRep_Tool::Pnt(V);
  return std::abs(PV3d.Y());
}

//=================================================================================================

double Altitud(const TopoDS_Vertex& V)
{
  gp_Pnt PV3d = BRep_Tool::Pnt(V);
  return PV3d.Z();
}

//=================================================================================================

void SimpleExpression(const Bisector_Bisec& B, occ::handle<Geom2d_Curve>& Bis)
{
  Bis = B.Value();

  occ::handle<Standard_Type> BT = Bis->DynamicType();
  if (BT == STANDARD_TYPE(Geom2d_TrimmedCurve))
  {
    occ::handle<Geom2d_TrimmedCurve> TrBis  = occ::down_cast<Geom2d_TrimmedCurve>(Bis);
    occ::handle<Geom2d_Curve>        BasBis = TrBis->BasisCurve();
    BT                                      = BasBis->DynamicType();
    if (BT == STANDARD_TYPE(Bisector_BisecAna))
    {
      Bis = occ::down_cast<Bisector_BisecAna>(BasBis)->Geom2dCurve();
      Bis = new Geom2d_TrimmedCurve(Bis, TrBis->FirstParameter(), TrBis->LastParameter());
    }
  }
}

//=======================================================================
// function : CutEdgeProf
// purpose  : Projection and Cut of an edge at extrema of distance to axis OZ.
//=======================================================================

void CutEdgeProf(
  const TopoDS_Edge&                                                        E,
  const occ::handle<Geom_Plane>&                                            Plane,
  const occ::handle<Geom2d_Line>&                                           Line,
  NCollection_List<TopoDS_Shape>&                                           Cuts,
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>& MapVerRefMoved)
{
  Cuts.Clear();

  double                         f, l;
  occ::handle<Geom_Curve>        C;
  occ::handle<Geom_TrimmedCurve> CT;
  occ::handle<Geom2d_Curve>      C2d;
  TopLoc_Location                L;

  // Return the curve associated to each Edge
  C  = BRep_Tool::Curve(E, L, f, l);
  CT = new Geom_TrimmedCurve(C, f, l);
  CT->Transform(L.Transformation());

  // project it in the plane and return the associated PCurve
  gp_Dir Normal = Plane->Pln().Axis().Direction();
  C             = GeomProjLib::ProjectOnPlane(CT, Plane, Normal, false);
  C2d           = GeomProjLib::Curve2d(C, Plane);

  // Calculate the extrema with the straight line
  NCollection_Sequence<double> Seq;

  double U1 = -Precision::Infinite();
  double U2 = Precision::Infinite();
  f         = C2d->FirstParameter();
  l         = C2d->LastParameter();

  Bnd_Box2d           B;
  Geom2dAdaptor_Curve AC2d(C2d);
  BndLib_Add2dCurve::Add(AC2d, BRepFill_Confusion(), B);
  double xmin, xmax;
  B.Get(xmin, U1, xmax, U2);

  //  modified by NIZHNY-EAP Wed Feb  2 16:32:37 2000 ___BEGIN___
  // no sense if C2 is normal to Line or really is a point
  if (U1 != U2)
  {
    Geom2dAPI_ExtremaCurveCurve Extrema(Line, C2d, U1 - 1., U2 + 1., f, l);

    int i, Nb = Extrema.NbExtrema();
    for (i = 1; i <= Nb; i++)
    {
      Extrema.Parameters(i, U1, U2);
      Seq.Append(U2);
    }
  }
  //  modified by NIZHNY-EAP Wed Feb  2 16:33:05 2000 ___END___

  // On calcule les intersection avec Oy.
  Geom2dAdaptor_Curve ALine(Line);
  constexpr double    Tol  = Precision::Intersection();
  double              TolC = 0.;

  Geom2dInt_GInter Intersector(ALine, AC2d, TolC, Tol);
  int              i, Nb = Intersector.NbPoints();

  for (i = 1; i <= Nb; i++)
  {
    Seq.Append(Intersector.Point(i).ParamOnSecond());
  }

  // Compute the new edges.
  BRep_Builder  Builder;
  TopoDS_Vertex VV, Vf, Vl, VRf, VRl;
  TopExp::Vertices(E, VRf, VRl);

  if (!MapVerRefMoved.IsBound(VRf))
  {
    Builder.MakeVertex(Vf, C->Value(f), BRep_Tool::Tolerance(VRf));
    MapVerRefMoved.Bind(VRf, Vf);
  }
  else
  {
    Vf = TopoDS::Vertex(MapVerRefMoved(VRf));
  }

  if (!MapVerRefMoved.IsBound(VRl))
  {
    Builder.MakeVertex(Vl, C->Value(l), BRep_Tool::Tolerance(VRl));
    MapVerRefMoved.Bind(VRl, Vl);
  }
  else
  {
    Vl = TopoDS::Vertex(MapVerRefMoved(VRl));
  }

  if (!Seq.IsEmpty())
  {

    Bubble(Seq);

    bool Empty = false;

    double CurParam = f;
    double Param;

    while (!Empty)
    {
      Param = Seq.First();
      Seq.Remove(1);
      Empty = Seq.IsEmpty();
      if (std::abs(Param - CurParam) > BRepFill_Confusion()
          && std::abs(Param - l) > BRepFill_Confusion())
      {

        VV = BRepLib_MakeVertex(C->Value(Param));

        TopoDS_Edge EE = BRepLib_MakeEdge(C, Vf, VV);
        EE.Orientation(E.Orientation());
        if (EE.Orientation() == TopAbs_FORWARD)
          Cuts.Append(EE);
        else
          Cuts.Prepend(EE);

        // reinitialize
        CurParam = Param;
        Vf       = VV;
      }
    }
  }

  TopoDS_Edge EE = BRepLib_MakeEdge(C, Vf, Vl);
  EE.Orientation(E.Orientation());
  if (EE.Orientation() == TopAbs_FORWARD)
    Cuts.Append(EE);
  else
    Cuts.Prepend(EE);
}

//=======================================================================
// function : CutEdge
// purpose  : Cut an edge at the extrema of curves and at points of inflexion.
//           Closed circles are also cut in two.
//           If <Cuts> are empty the edge is not modified.
//           The first and the last vertex of the original edge
//           belong to the first and last parts respectively.
//=======================================================================
void CutEdge(const TopoDS_Edge& E, const TopoDS_Face& F, NCollection_List<TopoDS_Shape>& Cuts)
{
  Cuts.Clear();
  MAT2d_CutCurve                   Cuter;
  double                           f, l;
  occ::handle<Geom2d_Curve>        C2d;
  occ::handle<Geom2d_TrimmedCurve> CT2d;

  TopoDS_Vertex V1, V2, VF, VL;
  TopExp::Vertices(E, V1, V2);
  BRep_Builder B;

  C2d  = BRep_Tool::CurveOnSurface(E, F, f, l);
  CT2d = new Geom2d_TrimmedCurve(C2d, f, l);

  if (CT2d->BasisCurve()->IsKind(STANDARD_TYPE(Geom2d_Circle)) && BRep_Tool::IsClosed(E))
  {
    //---------------------------
    // Cut closed circle.
    //---------------------------
    double   m1 = (2 * f + l) / 3.;
    double   m2 = (f + 2 * l) / 3.;
    gp_Pnt2d P1 = CT2d->Value(m1);
    gp_Pnt2d P2 = CT2d->Value(m2);

    TopoDS_Vertex VL1          = BRepLib_MakeVertex(gp_Pnt(P1.X(), P1.Y(), 0.));
    TopoDS_Vertex VL2          = BRepLib_MakeVertex(gp_Pnt(P2.X(), P2.Y(), 0.));
    TopoDS_Shape  aLocalShape1 = E.EmptyCopied();
    TopoDS_Shape  aLocalShape2 = E.EmptyCopied();
    TopoDS_Shape  aLocalShape3 = E.EmptyCopied();
    TopoDS_Edge   FE           = TopoDS::Edge(aLocalShape1);
    TopoDS_Edge   ME           = TopoDS::Edge(aLocalShape2);
    TopoDS_Edge   LE           = TopoDS::Edge(aLocalShape3);
    //    TopoDS_Edge FE = TopoDS::Edge(E.EmptyCopied());
    //   TopoDS_Edge ME = TopoDS::Edge(E.EmptyCopied());
    //    TopoDS_Edge LE = TopoDS::Edge(E.EmptyCopied());

    FE.Orientation(TopAbs_FORWARD);
    ME.Orientation(TopAbs_FORWARD);
    LE.Orientation(TopAbs_FORWARD);

    B.Add(FE, V1);
    B.Add(FE, VL1.Oriented(TopAbs_REVERSED));
    B.Range(FE, f, m1);

    B.Add(ME, VL1.Oriented(TopAbs_FORWARD));
    B.Add(ME, VL2.Oriented(TopAbs_REVERSED));
    B.Range(ME, m1, m2);

    B.Add(LE, VL2.Oriented(TopAbs_FORWARD));
    B.Add(LE, V2);
    B.Range(LE, m2, l);

    Cuts.Append(FE.Oriented(E.Orientation()));
    Cuts.Append(ME.Oriented(E.Orientation()));
    Cuts.Append(LE.Oriented(E.Orientation()));
    //--------
    // Return.
    //--------
    return;
  }

  //-------------------------
  // Cut of the curve.
  //-------------------------
  Cuter.Perform(CT2d);

  if (Cuter.UnModified())
  {
    //-----------------------------
    // edge not modified => return.
    //-----------------------------
    return;
  }
  else
  {
    //------------------------
    // Creation of cut edges.
    //------------------------
    VF = V1;

    for (int k = 1; k <= Cuter.NbCurves(); k++)
    {
      occ::handle<Geom2d_TrimmedCurve> CC = Cuter.Value(k);
      if (k == Cuter.NbCurves())
      {
        VL = V2;
      }
      else
      {
        gp_Pnt2d P = CC->Value(CC->LastParameter());
        VL         = BRepLib_MakeVertex(gp_Pnt(P.X(), P.Y(), 0.));
      }
      TopoDS_Shape aLocalShape = E.EmptyCopied();
      TopoDS_Edge  NE          = TopoDS::Edge(aLocalShape);
      //      TopoDS_Edge NE = TopoDS::Edge(E.EmptyCopied());
      NE.Orientation(TopAbs_FORWARD);
      B.Add(NE, VF.Oriented(TopAbs_FORWARD));
      B.Add(NE, VL.Oriented(TopAbs_REVERSED));
      B.Range(NE, CC->FirstParameter(), CC->LastParameter());
      Cuts.Append(NE.Oriented(E.Orientation()));
      VF = VL;
    }
  }
}

//=======================================================================
// function : VertexFromNode
// purpose  : Test if the position of aNode correspondingly to the distance to OZ
//           of vertices VF and VL. returns Status.
//           if Status is different from 0 Returned
//           the vertex corresponding to aNode is created.
//=======================================================================

int VertexFromNode(
  const occ::handle<MAT_Node>& aNode,
  const TopoDS_Edge&           E,
  const TopoDS_Vertex&         VF,
  const TopoDS_Vertex&         VL,
  NCollection_DataMap<occ::handle<MAT_Node>,
                      NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>>&
                 MapNodeVertex,
  TopoDS_Vertex& VN)
{
  TopoDS_Shape                                                             ShapeOnNode;
  NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> EmptyMap;
  int                                                                      Status = 0;
  BRep_Builder                                                             B;

  if (!aNode->Infinite())
  {
    Status = PosOnFace(aNode->Distance(), DistanceToOZ(VF), DistanceToOZ(VL));
  }
  if (Status == 2)
    ShapeOnNode = E;
  else if (Status == 1)
    ShapeOnNode = VF;
  else if (Status == 3)
    ShapeOnNode = VL;

  if (!ShapeOnNode.IsNull())
  {
    //-------------------------------------------------
    // the vertex will correspond to a node of the map
    //-------------------------------------------------
    if (MapNodeVertex.IsBound(aNode) && MapNodeVertex(aNode).IsBound(ShapeOnNode))
    {
      VN = TopoDS::Vertex(MapNodeVertex(aNode)(ShapeOnNode));
    }
    else
    {
      B.MakeVertex(VN);
      if (!MapNodeVertex.IsBound(aNode))
      {
        MapNodeVertex.Bind(aNode, EmptyMap);
      }
      MapNodeVertex(aNode).Bind(ShapeOnNode, VN);
    }
  }
  return Status;
}
