// Created on: 2003-10-21
// Created by: Mikhail KLOKOV
// Copyright (c) 2003-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 <BOPAlgo_BOP.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPDS_DS.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepAlgoAPI_Section.hxx>
#include <BRepFill_TrimShellCorner.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRepTools_ReShape.hxx>
#include <GCPnts_UniformAbscissa.hxx>
#include <Geom2d_Curve.hxx>
#include <GeomLib.hxx>
#include <gp_Ax2.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt2d.hxx>
#include <IntTools_BeanFaceIntersector.hxx>
#include <IntTools_Context.hxx>
#include <IntTools_Range.hxx>
#include <IntTools_Tools.hxx>
#include <TColgp_Array1OfDir.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Wire.hxx>
#include <TopTools_Array1OfListOfShape.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <BRepExtrema_ExtCC.hxx>
#include <ShapeFix_Edge.hxx>

static TopoDS_Edge FindEdgeCloseToBisectorPlane(const TopoDS_Vertex& theVertex,
                                                TopoDS_Compound&     theComp,
                                                const gp_Ax1&        theAxis);

static Standard_Boolean FindMiddleEdges(const TopoDS_Vertex&  theVertex1,
                                        const TopoDS_Vertex&  theVertex2,
                                        const gp_Ax1&         theAxis,
                                        TopoDS_Compound&      theComp,
                                        TopTools_ListOfShape& theElist);

static Standard_Boolean FindCommonVertex(const TopoDS_Edge&   theFirstEdge,
                                         const TopoDS_Edge&   theLastEdge,
                                         const TopoDS_Vertex& theFirstVertex,
                                         const TopoDS_Vertex& theLastVertex,
                                         TopoDS_Vertex&       theCommonVertex);

static Standard_Boolean FindCommonVertex(const BOPDS_PDS&       theDS,
                                         const Standard_Integer theEIndex1,
                                         const Standard_Integer theEIndex2,
                                         const gp_Vec&          theCrossDirection,
                                         TopoDS_Vertex&         theCommonVertex,
                                         Standard_Real&         theParamOnE1,
                                         Standard_Real&         theParamOnE2);

static Standard_Boolean SplitUEdges(const Handle(TopTools_HArray2OfShape)& theUEdges,
                                    const BOPDS_PDS&                       theDS,
                                    const gp_Vec&                          theCrossDirection,
                                    TopTools_DataMapOfShapeListOfShape&    theHistMap);

static void StoreVedgeInHistMap(const Handle(TopTools_HArray1OfShape)& theVEdges,
                                const Standard_Integer                 theIndex,
                                const TopoDS_Shape&                    theNewVedge,
                                TopTools_DataMapOfShapeListOfShape&    theHistMap);

static void FindFreeVertices(const TopoDS_Shape&        theShape,
                             const TopTools_MapOfShape& theVerticesToAvoid,
                             TopTools_ListOfShape&      theListOfVertex);

static Standard_Boolean CheckAndOrientEdges(const TopTools_ListOfShape& theOrderedList,
                                            const gp_Pnt2d&             theFirstPoint,
                                            const gp_Pnt2d&             theLastPoint,
                                            const TopoDS_Face&          theFace,
                                            TopTools_ListOfShape&       theOrientedList);

static Standard_Boolean FillGap(const TopoDS_Vertex&   theFirstVertex,
                                const TopoDS_Vertex&   theLastVertex,
                                const gp_Pnt2d&        theFirstPoint,
                                const gp_Pnt2d&        theLastPoint,
                                const TopoDS_Face&     theFace,
                                const TopoDS_Compound& theSectionEdges,
                                TopTools_ListOfShape&  theOrderedList);

static Standard_Boolean FindNextEdge(const TopoDS_Vertex& theFirstVertex,
                                     const TopoDS_Vertex& theLastVertex,
                                     const TopTools_IndexedDataMapOfShapeListOfShape& theMapVE,
                                     const TopTools_MapOfShape&                       theMapToAvoid,
                                     TopTools_ListOfShape& theOrderedList);

static Standard_Boolean FindVertex(const TopoDS_Edge&                        theEdge,
                                   const Standard_Integer                    theRank,
                                   const BOPDS_PDS&                          theDS,
                                   const TopTools_DataMapOfShapeListOfShape& theHistMap,
                                   TopoDS_Vertex&                            theVertex,
                                   BOPDS_Pave&                               thePave);

static Standard_Boolean FindNextVertex(const Standard_Integer theEdgeIndex,
                                       const BOPDS_Pave&      thePrevPave,
                                       const BOPDS_PDS&       theDS,
                                       TopoDS_Vertex&         theNextVertex,
                                       BOPDS_Pave&            thePave);

static Standard_Boolean GetPave(const Standard_Integer theEdgeIndex,
                                const Standard_Boolean isFirst,
                                const BOPDS_PDS&       theDS,
                                BOPDS_Pave&            thePave);

static Standard_Boolean FindFromUEdge(const TopoDS_Edge&                        theUE1Old,
                                      const TopoDS_Edge&                        theUE2Old,
                                      const TopoDS_Edge&                        theUE1New,
                                      const TopoDS_Edge&                        theUE2New,
                                      const TopoDS_Face&                        theFace,
                                      const TopoDS_Compound&                    theSecEdges,
                                      const Standard_Integer                    theRank,
                                      const TopoDS_Edge&                        theBoundEdge,
                                      const Standard_Integer                    theBoundEdgeIndex,
                                      const BOPDS_PDS&                          theDS,
                                      const TopTools_DataMapOfShapeListOfShape& theHistMap,
                                      TopoDS_Compound&                          theSecEdgesNew,
                                      TopTools_ListOfShape&                     theListOfWireEdges,
                                      BOPDS_Pave&                               theFoundPave,
                                      Standard_Boolean&                         isOnUEdge);

static Standard_Boolean FindFromVEdge(const BOPDS_Pave&                         thePrevPave,
                                      const Standard_Boolean&                   isOnUEdge,
                                      const TopoDS_Edge&                        theUE1Old,
                                      const TopoDS_Edge&                        theUE2Old,
                                      const TopoDS_Face&                        theFace,
                                      const TopoDS_Compound&                    theSecEdges,
                                      const Standard_Integer                    theRank,
                                      const TopoDS_Edge&                        theBoundEdge,
                                      const Standard_Integer                    theBoundEdgeIndex,
                                      const BOPDS_PDS&                          theDS,
                                      const TopTools_DataMapOfShapeListOfShape& theHistMap,
                                      TopTools_ListOfShape&                     theListOfWireEdges,
                                      Standard_Boolean&                         isSectionFound);

static void RemoveEdges(const TopoDS_Compound&      theSourceComp,
                        const TopTools_ListOfShape& theListToRemove,
                        TopoDS_Compound&            theResultComp);

static Standard_Boolean FilterSectionEdges(const BOPDS_VectorOfCurve& theBCurves,
                                           const TopoDS_Face&         theSecPlane,
                                           const BOPDS_PDS&           theDS,
                                           TopoDS_Compound&           theResult);

static Standard_Boolean GetUEdges(const Standard_Integer                 theIndex,
                                  const Standard_Integer                 theRank,
                                  const Handle(TopTools_HArray2OfShape)& theUEdges,
                                  const TopoDS_Edge&                     theBoundEdge,
                                  const TopoDS_Face&                     theFace,
                                  TopoDS_Edge&                           theFirstUEdge,
                                  TopoDS_Edge&                           theSecondUEdge);

static Standard_Real ComputeAveragePlaneAndMaxDeviation(const TopoDS_Shape& aWire,
                                                        gp_Pln&             thePlane,
                                                        Standard_Boolean&   IsSingular);

static void UpdateSectionEdge(TopoDS_Edge&         theEdge,
                              const TopoDS_Vertex& theConstVertex,
                              TopoDS_Vertex&       theVertex,
                              const Standard_Real  theParam);

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

BRepFill_TrimShellCorner::BRepFill_TrimShellCorner(const Handle(TopTools_HArray2OfShape)& theFaces,
                                                   const BRepFill_TransitionStyle theTransition,
                                                   const gp_Ax2&                  theAxeOfBisPlane,
                                                   const gp_Vec& theIntPointCrossDir)
    : myTransition(theTransition),
      myAxeOfBisPlane(theAxeOfBisPlane),
      myIntPointCrossDir(theIntPointCrossDir),
      myDone(Standard_False),
      myHasSection(Standard_False)
{
  myFaces                 = new TopTools_HArray2OfShape(theFaces->LowerRow(),
                                        theFaces->UpperRow(),
                                        theFaces->LowerCol(),
                                        theFaces->UpperCol());
  myFaces->ChangeArray2() = theFaces->Array2();
}

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

void BRepFill_TrimShellCorner::AddBounds(const Handle(TopTools_HArray2OfShape)& theBounds)
{
  myBounds                 = new TopTools_HArray2OfShape(theBounds->LowerRow(),
                                         theBounds->UpperRow(),
                                         theBounds->LowerCol(),
                                         theBounds->UpperCol());
  myBounds->ChangeArray2() = theBounds->Array2();
}

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

void BRepFill_TrimShellCorner::AddUEdges(const Handle(TopTools_HArray2OfShape)& theUEdges)
{
  myUEdges                 = new TopTools_HArray2OfShape(theUEdges->LowerRow(),
                                         theUEdges->UpperRow(),
                                         theUEdges->LowerCol(),
                                         theUEdges->UpperCol());
  myUEdges->ChangeArray2() = theUEdges->Array2();
}

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

void BRepFill_TrimShellCorner::AddVEdges(const Handle(TopTools_HArray2OfShape)& theVEdges,
                                         const Standard_Integer                 theIndex)
{
  myVEdges = new TopTools_HArray1OfShape(theVEdges->LowerRow(), theVEdges->UpperRow());

  for (Standard_Integer i = theVEdges->LowerRow(); i <= theVEdges->UpperRow(); i++)
    myVEdges->SetValue(i, theVEdges->Value(i, theIndex));
}

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

void BRepFill_TrimShellCorner::Perform()
{
  Standard_Integer anIndex1, anIndex2, nF1, nF2, i, j, aNbP, aNbC;
  Standard_Boolean bhassec;

  myDone = Standard_False;
  myHistMap.Clear();

  if (myFaces->RowLength() != 2)
    return;
  Standard_Integer ii = 0, jj = 0;
  BRep_Builder     aBB;

  for (jj = myFaces->LowerCol(); jj <= myFaces->UpperCol(); jj++)
  {
    TopoDS_Shell aShell;
    aBB.MakeShell(aShell);

    for (ii = myFaces->LowerRow(); ii <= myFaces->UpperRow(); ii++)
    {
      aBB.Add(aShell, myFaces->Value(ii, jj));
    }
    aShell.Closed(BRep_Tool::IsClosed(aShell));

    if (jj == myFaces->LowerCol())
    {
      myShape1 = aShell;
    }
    else
    {
      myShape2 = aShell;
    }
  }

  Standard_Real   aMaxTol = 0.;
  TopExp_Explorer anExp(myShape1, TopAbs_VERTEX);
  for (; anExp.More(); anExp.Next())
  {
    aMaxTol = Max(aMaxTol, BRep_Tool::Tolerance(TopoDS::Vertex(anExp.Current())));
  }

  anExp.Init(myShape2, TopAbs_VERTEX);
  for (; anExp.More(); anExp.Next())
  {
    aMaxTol = Max(aMaxTol, BRep_Tool::Tolerance(TopoDS::Vertex(anExp.Current())));
  }

  Standard_Real        aFuzzy = 4. * Precision::Confusion();
  BOPAlgo_PaveFiller   aPF;
  TopTools_ListOfShape aLS;
  aLS.Append(myShape1);
  aLS.Append(myShape2);
  aPF.SetArguments(aLS);
  if (aMaxTol < 1.005 * Precision::Confusion())
  {
    aFuzzy = Max(aPF.FuzzyValue(), aFuzzy);
    aPF.SetFuzzyValue(aFuzzy);
  }
  //
  aPF.Perform();
  if (aPF.HasErrors())
  {
    return;
  }
  //
  const BOPDS_PDS& theDS = aPF.PDS();
  //
  BOPDS_VectorOfInterfFF& aFFs   = theDS->InterfFF();
  Standard_Integer        aNbFFs = aFFs.Length();

  if (!SplitUEdges(myUEdges, theDS, myIntPointCrossDir, myHistMap))
  {
    return;
  }

  for (ii = myFaces->LowerRow(); ii <= myFaces->UpperRow(); ii++)
  {
    TopoDS_Shape aF1 = myFaces->Value(ii, myFaces->LowerCol());
    TopoDS_Shape aF2 = myFaces->Value(ii, myFaces->UpperCol());
    //
    anIndex1 = theDS->Index(aF1);
    anIndex2 = theDS->Index(aF2);

    if ((anIndex1 == -1) || (anIndex2 == -1))
      continue;

    for (i = 0; i < aNbFFs; ++i)
    {
      BOPDS_InterfFF& aFFi = aFFs(i);
      aFFi.Indices(nF1, nF2);
      //
      BOPDS_VectorOfPoint& aVP       = aFFi.ChangePoints();
      aNbP                           = aVP.Length();
      const BOPDS_VectorOfCurve& aVC = aFFi.Curves();
      aNbC                           = aVC.Length();
      if (!aNbP && !aNbC)
      {
        if (!theDS->HasInterfSubShapes(nF1, nF2))
        {
          continue;
        }
      }
      //
      if ((nF1 == anIndex1) && (nF2 == anIndex2))
      {
        bhassec = Standard_False;
        //
        for (j = 0; j < aNbC; ++j)
        {
          const BOPDS_Curve&           aBCurve    = aVC(j);
          const BOPDS_ListOfPaveBlock& aSectEdges = aBCurve.PaveBlocks();
          //
          if (aSectEdges.Extent())
          {
            bhassec = Standard_True;
            break;
          }
        }

        if (!bhassec)
        {
          if (!MakeFacesNonSec(ii, theDS, anIndex1, anIndex2))
          {
            myHistMap.Clear();
            return;
          }
        }
        else
        {
          if (!MakeFacesSec(ii, theDS, anIndex1, anIndex2, i))
          {
            myHistMap.Clear();
            return;
          }
        }
        break;
      }
    }
  }
  myDone = Standard_True;
}

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

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

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

Standard_Boolean BRepFill_TrimShellCorner::HasSection() const
{
  return myHasSection;
}

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

void BRepFill_TrimShellCorner::Modified(const TopoDS_Shape&   theShape,
                                        TopTools_ListOfShape& theModified)
{
  theModified.Clear();

  if (myHistMap.IsBound(theShape))
  {
    theModified = myHistMap.Find(theShape);
  }
}

// ----------------------------------------------------------------------------------------------------
// function: MakeFacesNonSec
// purpose:         Updates <myHistMap> by new faces in the case when old faces do not intersect
// ----------------------------------------------------------------------------------------------------
Standard_Boolean BRepFill_TrimShellCorner::MakeFacesNonSec(const Standard_Integer theIndex,
                                                           const BOPDS_PDS&       theDS,
                                                           const Standard_Integer theFaceIndex1,
                                                           const Standard_Integer theFaceIndex2)
{
  Standard_Boolean bHasNewEdge = Standard_False;
  TopoDS_Edge      aNewEdge;

  BRep_Builder        aBB;
  const TopoDS_Shape& aE1 = myBounds->Value(theIndex, 1);
  const TopoDS_Shape& aE2 = myBounds->Value(theIndex, 2);

  // search common vertex between bounds. begin
  TopoDS_Vertex    aCommonVertex;
  Standard_Integer anIndex1 = theDS->Index(aE1);
  Standard_Integer anIndex2 = theDS->Index(aE2);
  Standard_Real    apar1 = 0., apar2 = 0.;

  Standard_Boolean bvertexfound =
    FindCommonVertex(theDS, anIndex1, anIndex2, myIntPointCrossDir, aCommonVertex, apar1, apar2);
  // search common vertex between bounds. end

  Handle(BRepTools_ReShape) aSubstitutor = new BRepTools_ReShape();

  // search common vertices between uedges. begin
  TopTools_ListOfShape aCommonVertices;
  Standard_Integer     acommonflag = 0; // 0 - no, 1 - first pair, 2 - second pair, 3 - both
  Standard_Integer     ueit = 0, eindex = 0;

  for (ueit = 1, eindex = theIndex; ueit <= 2; ueit++, eindex++)
  {
    const TopoDS_Shape& aShape1 = myUEdges->Value(eindex, myUEdges->LowerCol());
    const TopoDS_Shape& aShape2 = myUEdges->Value(eindex, myUEdges->UpperCol());
    TopoDS_Edge         aUE1    = TopoDS::Edge(aShape1);
    TopoDS_Edge         aUE2    = TopoDS::Edge(aShape2);

    if (myHistMap.IsBound(aShape1))
    {
      const TopTools_ListOfShape& lst = myHistMap.Find(aShape1);

      if (!lst.IsEmpty())
        aUE1 = TopoDS::Edge(lst.First());
    }

    if (myHistMap.IsBound(aShape2))
    {
      const TopTools_ListOfShape& lst = myHistMap.Find(aShape2);

      if (!lst.IsEmpty())
        aUE2 = TopoDS::Edge(lst.First());
    }

    if (!aShape1.IsSame(aUE1))
      aSubstitutor->Replace(aShape1.Oriented(TopAbs_FORWARD), aUE1.Oriented(TopAbs_FORWARD));

    if (!aShape2.IsSame(aUE2))
      aSubstitutor->Replace(aShape2.Oriented(TopAbs_FORWARD), aUE2.Oriented(TopAbs_FORWARD));

    TopoDS_Vertex V1 = TopExp::LastVertex(aUE1);
    TopoDS_Vertex V2 = TopExp::FirstVertex(aUE2);

    if (V1.IsSame(V2))
    {
      acommonflag = (acommonflag == 0) ? ueit : 3;
      aCommonVertices.Append(V1);
    }
  }
  // search common vertices between uedges. end

  if (bvertexfound)
  {
    if (aCommonVertices.Extent() != 1)
      return Standard_False;

    if (acommonflag == 1)
      aNewEdge = BRepLib_MakeEdge(TopoDS::Vertex(aCommonVertices.First()), aCommonVertex);
    else
      aNewEdge = BRepLib_MakeEdge(aCommonVertex, TopoDS::Vertex(aCommonVertices.First()));

    bHasNewEdge = Standard_True;
  }

  if (aCommonVertices.Extent() == 2)
  {
    aNewEdge    = BRepLib_MakeEdge(TopoDS::Vertex(aCommonVertices.First()),
                                TopoDS::Vertex(aCommonVertices.Last()));
    bHasNewEdge = Standard_True;
  }
  Standard_Integer fit = 0;

  for (fit = 1; fit <= 2; fit++)
  {
    TopoDS_Compound     aComp;
    TopTools_MapOfShape aMapV;
    aBB.MakeCompound(aComp);

    for (ueit = 1, eindex = theIndex; ueit <= 2; ueit++, eindex++)
    {
      const TopoDS_Shape& aShape = myUEdges->Value(eindex, myUEdges->LowerCol() + fit - 1);
      TopoDS_Shape        aUE    = aShape;

      if (myHistMap.IsBound(aShape))
      {
        const TopTools_ListOfShape& lst = myHistMap.Find(aShape);

        if (!lst.IsEmpty())
          aUE = TopoDS::Edge(lst.First());
      }
      const TopoDS_Shape& aV =
        (fit == 1) ? TopExp::FirstVertex(TopoDS::Edge(aUE)) : TopExp::LastVertex(TopoDS::Edge(aUE));
      aMapV.Add(aV);
      aBB.Add(aComp, aUE);
    }

    if (bHasNewEdge)
    {
      aBB.Add(aComp, aNewEdge);
      StoreVedgeInHistMap(myVEdges, theIndex, aNewEdge, myHistMap);
    }

    TopTools_ListOfShape alonevertices;
    FindFreeVertices(aComp, aMapV, alonevertices);

    if (!alonevertices.IsEmpty() && (alonevertices.Extent() != 2))
      return Standard_False;

    Standard_Integer   aFaceIndex = (fit == 1) ? theFaceIndex1 : theFaceIndex2;
    TopoDS_Shape       aFace      = theDS->Shape(aFaceIndex);
    TopAbs_Orientation aFaceOri   = aFace.Orientation();
    aFace.Orientation(TopAbs_FORWARD);

    TopExp_Explorer anExpE(aFace, TopAbs_EDGE);

    if (bHasNewEdge)
    {
      aNewEdge.Orientation(TopAbs_FORWARD);

      // Refer to BrepFill_Sweep.cxx BuildEdge Construct an edge via an iso
      gp_Pnt        P1, P2;
      Standard_Real p11, p12, p21, p22;
      P1 = BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(aNewEdge)));
      P2 = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(aNewEdge)));

      TopoDS_Edge aERef = TopoDS::Edge(fit == 1 ? aE1 : aE2);
      p11               = P1.Distance(BRep_Tool::Pnt(TopExp::FirstVertex(aERef)));
      p22               = P2.Distance(BRep_Tool::Pnt(TopExp::LastVertex(aERef)));
      p12               = P1.Distance(BRep_Tool::Pnt(TopExp::LastVertex(aERef)));
      p21               = P2.Distance(BRep_Tool::Pnt(TopExp::FirstVertex(aERef)));

      if (p11 > p12 && p22 > p21)
      {
        aNewEdge.Reverse();
      }

      // for nonPlane surface, we should add pCurve
      Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge();
      sfe->FixAddPCurve(aNewEdge, TopoDS::Face(aFace), Standard_False);
    }

    TopTools_ListOfShape aOrderedList;

    if (!alonevertices.IsEmpty())
    {
      Standard_Integer anEIndex = (fit == 1) ? anIndex1 : anIndex2;
      Standard_Boolean bfound1  = Standard_False;
      Standard_Boolean bfound2  = Standard_False;
      Standard_Real    aparam1 = 0., aparam2 = 0.;

      BOPDS_ListOfPave aLP;
      theDS->Paves(anEIndex, aLP);
      BOPDS_ListIteratorOfListOfPave aIt;
      aIt.Initialize(aLP);
      for (; aIt.More(); aIt.Next())
      {
        const BOPDS_Pave&   aPave = aIt.Value();
        const TopoDS_Shape& aV    = theDS->Shape(aPave.Index());

        if (aV.IsSame(alonevertices.First()))
        {
          if (!bfound1)
          {
            aparam1 = aPave.Parameter();
            bfound1 = Standard_True;
          }
        }

        if (aV.IsSame(alonevertices.Last()))
        {
          if (!bfound2)
          {
            aparam2 = aPave.Parameter();
            bfound2 = Standard_True;
          }
        }
      }

      if (bfound1 && bfound2)
      {
        TopoDS_Edge aNewBoundE;

        if (fit == 1)
        {
          aNewBoundE = TopoDS::Edge(aE1.EmptyCopied());
        }
        else
        {
          aNewBoundE = TopoDS::Edge(aE2.EmptyCopied());
        }
        TopoDS_Vertex aV1, aV2;

        if (aparam1 < aparam2)
        {
          aV1 = TopoDS::Vertex(alonevertices.First());
          aV2 = TopoDS::Vertex(alonevertices.Last());
        }
        else
        {
          aV1               = TopoDS::Vertex(alonevertices.Last());
          aV2               = TopoDS::Vertex(alonevertices.First());
          Standard_Real tmp = aparam1;
          aparam1           = aparam2;
          aparam2           = tmp;
        }
        aV1.Orientation(TopAbs_FORWARD);
        aV2.Orientation(TopAbs_REVERSED);
        aBB.Add(aNewBoundE, aV1);
        aBB.Add(aNewBoundE, aV2);
        aBB.Range(aNewBoundE, aparam1, aparam2);
        aNewBoundE.Orientation(TopAbs_FORWARD);

        aOrderedList.Append(aNewBoundE);

        if (bHasNewEdge)
        {
          TopExp_Explorer  anExpV(aNewEdge, TopAbs_VERTEX);
          Standard_Boolean bfoundv = Standard_False;

          for (; !bfoundv && anExpV.More(); anExpV.Next())
          {
            if (aV2.IsSame(anExpV.Current()))
              bfoundv = Standard_True;
          }

          if (bfoundv)
            aOrderedList.Append(aNewEdge);
          else
            aOrderedList.Prepend(aNewEdge);
        }
      }
      else
      {
        return Standard_False;
      }
    }
    else
    {
      if (bHasNewEdge)
      {
        aOrderedList.Append(aNewEdge);
      }
    }

    if (!aOrderedList.IsEmpty())
    {
      TopoDS_Wire aW;
      aBB.MakeWire(aW);
      TopTools_ListIteratorOfListOfShape anItE(aOrderedList);

      for (; anItE.More(); anItE.Next())
      {
        aBB.Add(aW, anItE.Value());
      }
      if (fit == 1)
        aSubstitutor->Replace(aE1.Oriented(TopAbs_FORWARD), aW);
      else
        aSubstitutor->Replace(aE2.Oriented(TopAbs_FORWARD), aW);
    }

    aSubstitutor->Apply(aFace);
    TopoDS_Shape aNewFace = aSubstitutor->Value(aFace);
    aNewFace.Orientation(aFaceOri);
    TopTools_ListOfShape atmpList;
    atmpList.Append(aNewFace);
    myHistMap.Bind(aFace, atmpList);

    anExpE.Init(aFace, TopAbs_EDGE);

    for (; anExpE.More(); anExpE.Next())
    {
      TopoDS_Shape aNewValue = aSubstitutor->Value(anExpE.Current());

      if (aNewValue.IsNull() || aNewValue.IsSame(anExpE.Current()))
        continue;

      if (myHistMap.IsBound(anExpE.Current()))
        continue;
      TopTools_ListOfShape aListOfNewEdge;
      TopExp_Explorer      anExpE2(aNewValue, TopAbs_EDGE);

      for (; anExpE2.More(); anExpE2.Next())
      {
        aListOfNewEdge.Append(anExpE2.Current());
      }
      myHistMap.Bind(anExpE.Current(), aListOfNewEdge);
    }
  }

  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// function: MakeFacesSec
// purpose:  Updates <myHistMap> by new faces in the case when old faces intersect each other
// ----------------------------------------------------------------------------------------------------
Standard_Boolean BRepFill_TrimShellCorner::MakeFacesSec(const Standard_Integer theIndex,
                                                        const BOPDS_PDS&       theDS,
                                                        const Standard_Integer theFaceIndex1,
                                                        const Standard_Integer theFaceIndex2,
                                                        const Standard_Integer theSSInterfIndex)
{
  const BOPDS_VectorOfInterfFF& aFFs     = theDS->InterfFF();
  const BOPDS_InterfFF&         aFFi     = aFFs(theSSInterfIndex);
  const BOPDS_VectorOfCurve&    aBCurves = aFFi.Curves();

  TopoDS_Compound aSecEdges;
  TopoDS_Face     aSecPlane;

  if (!FilterSectionEdges(aBCurves, aSecPlane, theDS, aSecEdges))
    return Standard_False;

  // Extract vertices on the intersection of correspondent U-edges
  const TopoDS_Shape& LeftE1  = myUEdges->Value(theIndex, 1);
  const TopoDS_Shape& LeftE2  = myUEdges->Value(theIndex, 2);
  const TopoDS_Shape& RightE1 = myUEdges->Value(theIndex + 1, 1);
  const TopoDS_Shape& RightE2 = myUEdges->Value(theIndex + 1, 2);

  Standard_Integer IndexOfLeftE1  = theDS->Index(LeftE1);
  Standard_Integer IndexOfLeftE2  = theDS->Index(LeftE2);
  Standard_Integer IndexOfRightE1 = theDS->Index(RightE1);
  Standard_Integer IndexOfRightE2 = theDS->Index(RightE2);

  TopoDS_Vertex FirstVertex, LastVertex;
  Standard_Real ParamOnLeftE1, ParamOnLeftE2, ParamOnRightE1, ParamOnRightE2;
  FindCommonVertex(theDS,
                   IndexOfLeftE1,
                   IndexOfLeftE2,
                   myIntPointCrossDir,
                   FirstVertex,
                   ParamOnLeftE1,
                   ParamOnLeftE2);
  FindCommonVertex(theDS,
                   IndexOfRightE1,
                   IndexOfRightE2,
                   myIntPointCrossDir,
                   LastVertex,
                   ParamOnRightE1,
                   ParamOnRightE2);

  TopoDS_Shape     SecWire;
  gp_Pln           SecPlane;
  Standard_Boolean IsSingular;
  Standard_Boolean WireFound =
    ChooseSection(aSecEdges, FirstVertex, LastVertex, SecWire, SecPlane, IsSingular);

  if (WireFound)
  {
    // aSecEdges = SecWire;
    TopoDS_Compound aComp;
    BRep_Builder    BB;
    BB.MakeCompound(aComp);
    TopExp_Explorer explo(SecWire, TopAbs_EDGE);

    for (; explo.More(); explo.Next())
      BB.Add(aComp, explo.Current());
    aSecEdges = aComp;

    StoreVedgeInHistMap(myVEdges, theIndex, SecWire, myHistMap);
  }

  TopTools_ListOfShape aCommonVertices;
  //  Standard_Integer acommonflag = 0; // 0 - no, 1 - first pair, 2 - second pair, 3 - both
  Standard_Integer          fit          = 0; //, ueit = 0, eindex = 0, i = 0;
  Handle(BRepTools_ReShape) aSubstitutor = new BRepTools_ReShape();

  for (fit = 0; fit < 2; fit++)
  {
    Standard_Integer   aFaceIndex = (fit == 0) ? theFaceIndex1 : theFaceIndex2;
    TopoDS_Face        aFace      = TopoDS::Face(theDS->Shape(aFaceIndex));
    TopAbs_Orientation aFaceOri   = aFace.Orientation();
    TopoDS_Face        aFaceF     = aFace;
    aFaceF.Orientation(TopAbs_FORWARD);
    TopoDS_Edge aBoundEdge = TopoDS::Edge(myBounds->Value(theIndex, myBounds->LowerCol() + fit));
    Standard_Integer aBoundEdgeIndex = theDS->Index(aBoundEdge);
    TopoDS_Edge      aUE1;
    TopoDS_Edge      aUE2;

    if (!GetUEdges(theIndex, fit, myUEdges, aBoundEdge, aFaceF, aUE1, aUE2))
      return Standard_False;

    TopoDS_Edge aUE1old = aUE1;
    TopoDS_Edge aUE2old = aUE2;

    if (myHistMap.IsBound(aUE1))
    {
      const TopTools_ListOfShape& lst = myHistMap.Find(aUE1);

      if (!lst.IsEmpty())
      {
        const TopoDS_Shape& anEdge = lst.First().Oriented(aUE1.Orientation());

        if (!aUE1.IsSame(anEdge))
          aSubstitutor->Replace(aUE1.Oriented(TopAbs_FORWARD), anEdge.Oriented(TopAbs_FORWARD));
        aUE1 = TopoDS::Edge(anEdge);
      }
    }

    if (myHistMap.IsBound(aUE2))
    {
      const TopTools_ListOfShape& lst = myHistMap.Find(aUE2);

      if (!lst.IsEmpty())
      {
        const TopoDS_Shape& anEdge = lst.First().Oriented(aUE2.Orientation());

        if (!aUE2.IsSame(anEdge))
          aSubstitutor->Replace(aUE2.Oriented(TopAbs_FORWARD), anEdge.Oriented(TopAbs_FORWARD));
        aUE2 = TopoDS::Edge(anEdge);
      }
    }
    TopoDS_Vertex        aPrevVertex, aNextVertex;
    TopoDS_Compound      aCompOfSecEdges = aSecEdges;
    TopTools_ListOfShape aListOfWireEdges;
    BRep_Builder         aBB;
    BOPDS_Pave           aPave1;
    Standard_Boolean     isPave1OnUEdge = Standard_True;

    if (FindFromUEdge(aUE1old,
                      aUE2old,
                      aUE1,
                      aUE2,
                      aFace,
                      aSecEdges,
                      fit,
                      aBoundEdge,
                      aBoundEdgeIndex,
                      theDS,
                      myHistMap,
                      aCompOfSecEdges,
                      aListOfWireEdges,
                      aPave1,
                      isPave1OnUEdge))
    {
      TopTools_ListOfShape aSecondListOfEdges;
      Standard_Boolean     bisSectionFound = Standard_False;

      if (!FindFromVEdge(aPave1,
                         isPave1OnUEdge,
                         aUE1old,
                         aUE2old,
                         aFace,
                         aCompOfSecEdges,
                         fit,
                         aBoundEdge,
                         aBoundEdgeIndex,
                         theDS,
                         myHistMap,
                         aSecondListOfEdges,
                         bisSectionFound))
      {
        return Standard_False;
      }

      if (!bisSectionFound && aListOfWireEdges.IsEmpty())
      {
        return Standard_False;
      }
      aListOfWireEdges.Append(aSecondListOfEdges);
    }
    else
    {
      return Standard_False;
    }

    if (!aListOfWireEdges.IsEmpty())
    {
      TopoDS_Wire aW;
      aBB.MakeWire(aW);
      TopTools_ListIteratorOfListOfShape aEIt(aListOfWireEdges);

      for (; aEIt.More(); aEIt.Next())
      {
        if (!aBoundEdge.IsSame(aEIt.Value()))
          aBB.Add(aW, aEIt.Value());
      }
      aSubstitutor->Replace(aBoundEdge.Oriented(TopAbs_FORWARD), aW);
    }

    aSubstitutor->Apply(aFace);
    TopoDS_Shape aNewFace = aSubstitutor->Value(aFace);
    aNewFace.Orientation(aFaceOri);
    TopTools_ListOfShape atmpList;
    atmpList.Append(aNewFace);
    myHistMap.Bind(aFace, atmpList);

    TopExp_Explorer anExpE(aFace, TopAbs_EDGE);

    for (; anExpE.More(); anExpE.Next())
    {
      TopoDS_Shape aNewValue = aSubstitutor->Value(anExpE.Current());

      if (aNewValue.IsNull() || aNewValue.IsSame(anExpE.Current()))
        continue;

      if (myHistMap.IsBound(anExpE.Current()))
        continue;
      TopTools_ListOfShape aListOfNewEdge;
      TopExp_Explorer      anExpE2(aNewValue, TopAbs_EDGE);

      for (; anExpE2.More(); anExpE2.Next())
      {
        aListOfNewEdge.Append(anExpE2.Current());
      }
      myHistMap.Bind(anExpE.Current(), aListOfNewEdge);
    }
  }
  return Standard_True;
}

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

Standard_Boolean BRepFill_TrimShellCorner::ChooseSection(const TopoDS_Shape&  Comp,
                                                         const TopoDS_Vertex& theFirstVertex,
                                                         const TopoDS_Vertex& theLastVertex,
                                                         TopoDS_Shape&        resWire,
                                                         gp_Pln&              resPlane,
                                                         Standard_Boolean&    IsSingular)
{
  IsSingular = Standard_False;

  Standard_Integer ind, i, j;
  BRep_Builder     BB;

  if (myTransition == BRepFill_Right && !theFirstVertex.IsNull()
      && !theLastVertex.IsNull()) // the case where section wire goes from
  // its known first vertex to its known last vertex
  {
    TopoDS_Wire NewWire;
    BB.MakeWire(NewWire);

    TopoDS_Compound OldComp;
    BB.MakeCompound(OldComp);
    TopoDS_Iterator iter(Comp);
    for (; iter.More(); iter.Next())
      BB.Add(OldComp, iter.Value());

    TopoDS_Edge FirstEdge =
      FindEdgeCloseToBisectorPlane(theFirstVertex, OldComp, myAxeOfBisPlane.Axis());
    if (FirstEdge.IsNull())
      return Standard_False;

    iter.Initialize(OldComp);
    if (!iter.More())
    {
      iter.Initialize(Comp);
      BB.Add(OldComp, iter.Value());
    }
    TopoDS_Edge LastEdge =
      FindEdgeCloseToBisectorPlane(theLastVertex, OldComp, myAxeOfBisPlane.Axis());
    if (LastEdge.IsNull())
      return Standard_False;

    if (FirstEdge.IsNull() || LastEdge.IsNull())
    {
      return Standard_False;
    }

    BB.Add(NewWire, FirstEdge);

    if (!FirstEdge.IsSame(LastEdge))
    {
      TopoDS_Vertex    aCommonVertex;
      Standard_Boolean CommonVertexExists =
        FindCommonVertex(FirstEdge, LastEdge, theFirstVertex, theLastVertex, aCommonVertex);
      if (CommonVertexExists)
        BB.Add(NewWire, LastEdge);
      else
      {
        TopoDS_Vertex Vertex1, Vertex2, V1, V2;
        TopExp::Vertices(FirstEdge, V1, V2);
        Vertex1 = (theFirstVertex.IsSame(V1)) ? V2 : V1;
        TopExp::Vertices(LastEdge, V1, V2);
        Vertex2 = (theLastVertex.IsSame(V1)) ? V2 : V1;

        TopTools_ListOfShape MiddleEdges;
        if (FindMiddleEdges(Vertex1, Vertex2, myAxeOfBisPlane.Axis(), OldComp, MiddleEdges))
        {
          TopTools_ListIteratorOfListOfShape itl(MiddleEdges);
          for (; itl.More(); itl.Next())
            BB.Add(NewWire, itl.Value());
          BB.Add(NewWire, LastEdge);
        }
        else
        {
          // trim <FirstEdge> and <LastEdge> in the points of extrema
          // these points become new vertex with centre between them
          BRepExtrema_ExtCC Extrema(FirstEdge, LastEdge);
          if (Extrema.IsDone() && Extrema.NbExt() > 0)
          {
            Standard_Integer imin = 1;
            for (i = 2; i <= Extrema.NbExt(); i++)
              if (Extrema.SquareDistance(i) < Extrema.SquareDistance(imin))
                imin = i;

            Standard_Real aMinDist         = sqrt(Extrema.SquareDistance(imin));
            Standard_Real ParamOnFirstEdge = Extrema.ParameterOnE1(imin);
            Standard_Real ParamOnLastEdge  = Extrema.ParameterOnE2(imin);
            gp_Pnt        PointOnFirstEdge = Extrema.PointOnE1(imin);
            gp_Pnt        PointOnLastEdge  = Extrema.PointOnE2(imin);
            gp_Pnt        MidPnt((PointOnFirstEdge.XYZ() + PointOnLastEdge.XYZ()) / 2);
            aCommonVertex = BRepLib_MakeVertex(MidPnt);
            BB.UpdateVertex(aCommonVertex, 1.001 * aMinDist / 2);

            UpdateSectionEdge(FirstEdge, theFirstVertex, aCommonVertex, ParamOnFirstEdge);
            UpdateSectionEdge(LastEdge, theLastVertex, aCommonVertex, ParamOnLastEdge);

            BB.Add(NewWire, LastEdge);
          }
        }
      }
    }

    resWire  = NewWire;
    resPlane = gp_Pln(myAxeOfBisPlane);
    return Standard_True;
  }

  // General case: try to find continuous section closest to bisector plane
  TopoDS_Compound OldComp;
  BRep_Builder    B;
  B.MakeCompound(OldComp);
  TopoDS_Iterator iter(Comp);
  for (; iter.More(); iter.Next())
    B.Add(OldComp, iter.Value());

  Standard_Boolean anError = Standard_False;
  // TopoDS_Wire NewWire [2];
  TopTools_SequenceOfShape Wseq;
  for (;;)
  {
    TopExp_Explorer explo(OldComp, TopAbs_EDGE);
    if (!explo.More())
      break;
    TopoDS_Edge FirstEdge = TopoDS::Edge(explo.Current());
    TopoDS_Wire NewWire   = BRepLib_MakeWire(FirstEdge);
    B.Remove(OldComp, FirstEdge);
    if (NewWire.Closed())
    {
      Wseq.Append(NewWire);
      continue;
    }

    for (;;)
    {
      TopoDS_Vertex Extremity[2];
      TopExp::Vertices(NewWire, Extremity[0], Extremity[1]);
      if (Extremity[0].IsNull() || Extremity[1].IsNull())
      {
        anError = Standard_True;
        break;
      }
      TopTools_IndexedDataMapOfShapeListOfShape VEmap;
      TopExp::MapShapesAndAncestors(OldComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap);
      TopTools_ListOfShape Vedges[2];
      for (j = 0; j < 2; j++)
        if (VEmap.Contains(Extremity[j]))
          Vedges[j] = VEmap.FindFromKey(Extremity[j]);
      if (Vedges[0].IsEmpty() && Vedges[1].IsEmpty())
        // no more edges in OldComp to continue NewWire
        break;
      Standard_Boolean Modified = Standard_False;
      for (j = 0; j < 2; j++)
      {
        if (Vedges[j].Extent() == 1)
        {
          const TopoDS_Edge& anEdge = TopoDS::Edge(Vedges[j].First());
          NewWire                   = BRepLib_MakeWire(NewWire, anEdge);
          B.Remove(OldComp, anEdge);
          Modified = Standard_True;
        }
      }
      if (!Modified) // only multiple connections
      {
        ind = (Vedges[0].IsEmpty()) ? 1 : 0;
        TopTools_SequenceOfShape           Edges;
        TopTools_ListIteratorOfListOfShape itl(Vedges[ind]);
        for (; itl.More(); itl.Next())
          Edges.Append(itl.Value());
        Standard_Integer theind       = 0;
        Standard_Real    MinDeviation = RealLast();
        for (j = 1; j <= Edges.Length(); j++)
        {
          TopoDS_Wire      aWire = BRepLib_MakeWire(NewWire, TopoDS::Edge(Edges(j)));
          gp_Pln           aPlane;
          Standard_Boolean issing;
          Standard_Real    Deviation = ComputeAveragePlaneAndMaxDeviation(aWire, aPlane, issing);
          if (Deviation < MinDeviation)
          {
            MinDeviation = Deviation;
            theind       = j;
          }
        }
        NewWire = BRepLib_MakeWire(NewWire, TopoDS::Edge(Edges(theind)));
        B.Remove(OldComp, Edges(theind));
      }
      if (NewWire.Closed())
        break;
    }
    Wseq.Append(NewWire);
    if (anError)
      break;
  }

  Standard_Real   MinAngle = RealLast();
  TopExp_Explorer Explo(OldComp, TopAbs_EDGE);
  if (!anError && !Explo.More()) // wires are built successfully and compound <OldComp> is empty
  {
    if (Wseq.Length() == 1) // only one wire => it becomes result
    {
      resWire = Wseq.First();
      ComputeAveragePlaneAndMaxDeviation(resWire, resPlane, IsSingular);
      return Standard_True;
    }
    else // we must choose the wire which average plane is closest to bisector plane
    {    //(check angle between axes)
      for (i = 1; i <= Wseq.Length(); i++)
      {
        TopoDS_Wire      aWire = TopoDS::Wire(Wseq(i));
        gp_Pln           aPln;
        Standard_Boolean issing;
        ComputeAveragePlaneAndMaxDeviation(aWire, aPln, issing);
        if (issing)
          continue;

        Standard_Real Angle = aPln.Axis().Angle(myAxeOfBisPlane.Axis());
        if (Angle > M_PI / 2)
          Angle = M_PI - Angle;

        if (Angle < MinAngle)
        {
          MinAngle = Angle;
          resWire  = aWire;
          resPlane = aPln;
        }
      }
      return Standard_True;
    }
  }
  return Standard_False;
}

// ------------------------------------------------------------------------------------------
// static function: SplitUEdges
// purpose:
// ------------------------------------------------------------------------------------------
Standard_Boolean SplitUEdges(const Handle(TopTools_HArray2OfShape)& theUEdges,
                             const BOPDS_PDS&                       theDS,
                             const gp_Vec&                          theCrossDirection,
                             TopTools_DataMapOfShapeListOfShape&    theHistMap)
{

  const BOPDS_VectorOfInterfVV& aVVs = theDS->InterfVV();

  BRep_Builder           aBB;
  Standard_Integer       ueit = 0, upRow, lowCol, upCol;
  TopTools_Array2OfShape aNewVertices(1, 2, 1, 2);
  //
  upRow  = theUEdges->UpperRow();
  lowCol = theUEdges->LowerCol();
  upCol  = theUEdges->UpperCol();
  //
  for (ueit = theUEdges->LowerRow(); ueit <= upRow; ueit++)
  {
    const TopoDS_Shape& aE1 = theUEdges->Value(ueit, lowCol);
    const TopoDS_Shape& aE2 = theUEdges->Value(ueit, upCol);

    if (theHistMap.IsBound(aE1) || theHistMap.IsBound(aE2))
      continue;

    Standard_Integer anEIndex1 = theDS->Index(aE1);
    Standard_Integer anEIndex2 = theDS->Index(aE2);

    TopoDS_Vertex    aCommonVertex;
    Standard_Real    apar1 = 0., apar2 = 0.;
    Standard_Boolean bvertexfound =
      FindCommonVertex(theDS, anEIndex1, anEIndex2, theCrossDirection, aCommonVertex, apar1, apar2);
    //
    if (!bvertexfound)
    {
      TopoDS_Vertex    V1      = TopExp::LastVertex(TopoDS::Edge(aE1));
      TopoDS_Vertex    V2      = TopExp::FirstVertex(TopoDS::Edge(aE2));
      Standard_Integer vindex1 = theDS->Index(V1);
      Standard_Integer vindex2 = theDS->Index(V2);
      Standard_Integer vvit    = 0;
      Standard_Integer aNbVVs  = aVVs.Length();

      for (vvit = 0; !bvertexfound && (vvit < aNbVVs); vvit++)
      {
        // const BOPTools_VVInterference& aVV = aVVs(vvit);
        const BOPDS_InterfVV& aVV = aVVs(vvit);

        if (((vindex1 == aVV.Index1()) && (vindex2 == aVV.Index2()))
            || ((vindex1 == aVV.Index2()) && (vindex2 == aVV.Index1())))
        {

          if (!aVV.HasIndexNew())
          {
            continue;
          }
          aCommonVertex = TopoDS::Vertex(theDS->Shape(aVV.IndexNew()));
          bvertexfound  = Standard_True;
          apar1         = BRep_Tool::Parameter(V1, TopoDS::Edge(aE1));
          apar2         = BRep_Tool::Parameter(V2, TopoDS::Edge(aE2));
        }
      }
    }

    if (bvertexfound)
    {
      TopoDS_Vertex aV1, aV2;
      Standard_Real f = 0., l = 0.;
      //
      TopoDS_Edge aNewE1 = TopoDS::Edge(aE1.EmptyCopied());
      TopExp::Vertices(TopoDS::Edge(aE1), aV1, aV2);
      aNewE1.Orientation(TopAbs_FORWARD);
      aV1.Orientation(TopAbs_FORWARD);
      aBB.Add(aNewE1, aV1);
      aCommonVertex.Orientation(TopAbs_REVERSED);
      aBB.Add(aNewE1, aCommonVertex);
      BRep_Tool::Range(TopoDS::Edge(aE1), f, l);
      aBB.Range(aNewE1, f, apar1);

      //
      TopoDS_Edge aNewE2 = TopoDS::Edge(aE2.EmptyCopied());
      TopExp::Vertices(TopoDS::Edge(aE2), aV1, aV2);
      aNewE2.Orientation(TopAbs_FORWARD);
      aCommonVertex.Orientation(TopAbs_FORWARD);
      aBB.Add(aNewE2, aCommonVertex);
      aBB.Add(aNewE2, aV2);
      BRep_Tool::Range(TopoDS::Edge(aE2), f, l);
      aBB.Range(aNewE2, apar2, l);

      TopTools_ListOfShape lst;
      lst.Append(aNewE1);
      theHistMap.Bind(aE1, lst);
      lst.Clear();
      lst.Append(aNewE2);
      theHistMap.Bind(aE2, lst);
    }
  }
  return Standard_True;
}

// ------------------------------------------------------------------------------------------
// static function: StoreVedgeInHistMap
// purpose:
// ------------------------------------------------------------------------------------------
void StoreVedgeInHistMap(const Handle(TopTools_HArray1OfShape)& theVEdges,
                         const Standard_Integer                 theIndex,
                         const TopoDS_Shape&                    theNewVshape,
                         TopTools_DataMapOfShapeListOfShape&    theHistMap)
{
  // Replace default value in the map (v-iso edge of face)
  // by intersection of two consecutive faces
  const TopoDS_Shape& aVEdge = theVEdges->Value(theIndex);

  theHistMap.Bound(aVEdge, TopTools_ListOfShape())->Append(theNewVshape);
}

// ------------------------------------------------------------------------------------------
// static function: FindFreeVertices
// purpose:
// ------------------------------------------------------------------------------------------
void FindFreeVertices(const TopoDS_Shape&        theShape,
                      const TopTools_MapOfShape& theVerticesToAvoid,
                      TopTools_ListOfShape&      theListOfVertex)
{

  theListOfVertex.Clear();
  TopTools_IndexedDataMapOfShapeListOfShape aMap;
  TopExp::MapShapesAndAncestors(theShape, TopAbs_VERTEX, TopAbs_EDGE, aMap);
  Standard_Integer i = 0;

  for (i = 1; i <= aMap.Extent(); i++)
  {
    const TopoDS_Shape& aKey = aMap.FindKey(i);

    if (theVerticesToAvoid.Contains(aKey))
      continue;
    const TopTools_ListOfShape& aList = aMap.FindFromIndex(i);

    if (aList.Extent() < 2)
    {
      theListOfVertex.Append(aKey);
    }
  }
}

// ------------------------------------------------------------------------------------------
// static function: FindCommonVertex
// purpose:
// ------------------------------------------------------------------------------------------
Standard_Boolean FindCommonVertex(const BOPDS_PDS&       theDS,
                                  const Standard_Integer theEIndex1,
                                  const Standard_Integer theEIndex2,
                                  const gp_Vec&          theCrossDirection,
                                  TopoDS_Vertex&         theCommonVertex,
                                  Standard_Real&         theParamOnE1,
                                  Standard_Real&         theParamOnE2)
{

  const BOPDS_VectorOfInterfEE& aEEs = theDS->InterfEE();

  Standard_Boolean bvertexfound = Standard_False;
  TopoDS_Vertex    aCommonVertex;
  Standard_Integer eeit = 0;

  TopoDS_Edge       theE1 = TopoDS::Edge(theDS->Shape(theEIndex1));
  TopoDS_Edge       theE2 = TopoDS::Edge(theDS->Shape(theEIndex2));
  BRepAdaptor_Curve aBC1(theE1), aBC2(theE2);

  Standard_Integer aNbEEs;
  aNbEEs = aEEs.Length();
  for (eeit = 0; eeit < aNbEEs; ++eeit)
  {
    const BOPDS_InterfEE& aEE = aEEs(eeit);

    if ((theEIndex1 == aEE.Index1() && theEIndex2 == aEE.Index2())
        || (theEIndex1 == aEE.Index2() && theEIndex2 == aEE.Index1()))
    {

      if (!aEE.HasIndexNew())
        continue;

      IntTools_CommonPrt aCP = aEE.CommonPart();
      if (aCP.Type() == TopAbs_VERTEX)
      {
        theCommonVertex = *(TopoDS_Vertex*)&theDS->Shape(aEE.IndexNew());

        if (theEIndex1 == aEE.Index1())
          IntTools_Tools::VertexParameters(aCP, theParamOnE1, theParamOnE2);
        else
          IntTools_Tools::VertexParameters(aCP, theParamOnE2, theParamOnE1);

        gp_Pnt aPt;
        gp_Vec aDirOnE1, aDirOnE2;
        gp_Dir aIntersectPointCrossDir;

        // intersect point aDirOnE1.cross(aDirOnE2) should same direction with path
        // theCrossDirection
        aBC1.D1(theParamOnE1, aPt, aDirOnE1);
        aBC2.D1(theParamOnE2, aPt, aDirOnE2);
        aIntersectPointCrossDir = aDirOnE1.Crossed(aDirOnE2);

        if (aIntersectPointCrossDir.Dot(theCrossDirection) > Precision::SquareConfusion())
        {
          bvertexfound = Standard_True;
          break;
        }
      }
    }
  }
  return bvertexfound;
}

// ----------------------------------------------------------------------------------------------------
// static function: GetUEdges
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean GetUEdges(const Standard_Integer                 theIndex,
                           const Standard_Integer                 theRank,
                           const Handle(TopTools_HArray2OfShape)& theUEdges,
                           const TopoDS_Edge&                     theBoundEdge,
                           const TopoDS_Face&                     theFace,
                           TopoDS_Edge&                           theFirstUEdge,
                           TopoDS_Edge&                           theSecondUEdge)
{
  const TopoDS_Shape& aUE1 = theUEdges->Value(theIndex, theUEdges->LowerCol() + theRank);
  const TopoDS_Shape& aUE2 = theUEdges->Value(theIndex + 1, theUEdges->LowerCol() + theRank);

  TopoDS_Face aFace = theFace;
  aFace.Orientation(TopAbs_FORWARD);
  TopoDS_Edge     E1, E2;
  TopExp_Explorer anExp(aFace, TopAbs_EDGE);

  for (; anExp.More(); anExp.Next())
  {
    if (E1.IsNull() && aUE1.IsSame(anExp.Current()))
    {
      E1 = TopoDS::Edge(anExp.Current());
    }
    else if (E2.IsNull() && aUE2.IsSame(anExp.Current()))
    {
      E2 = TopoDS::Edge(anExp.Current());
    }
  }

  if (E1.IsNull() || E2.IsNull())
    return Standard_False;

  Standard_Real        f, l;
  Handle(Geom2d_Curve) C1 = BRep_Tool::CurveOnSurface(E1, aFace, f, l);

  if (C1.IsNull())
    return Standard_False;
  gp_Pnt2d             PU1 = (theRank == 0) ? C1->Value(l) : C1->Value(f);
  Handle(Geom2d_Curve) C2  = BRep_Tool::CurveOnSurface(theBoundEdge, aFace, f, l);

  if (C2.IsNull())
    return Standard_False;
  BRep_Tool::Range(theBoundEdge, f, l);
  gp_Pnt2d            pf = C2->Value(f);
  TopoDS_Vertex       aV = (theRank == 0) ? TopExp::LastVertex(E1) : TopExp::FirstVertex(E1);
  Standard_Real       aTolerance = BRep_Tool::Tolerance(aV);
  BRepAdaptor_Surface aBAS(aFace, Standard_False);

  if (pf.Distance(PU1) > aBAS.UResolution(aTolerance))
  {
    TopoDS_Edge atmpE = E1;
    E1                = E2;
    E2                = atmpE;
  }
  theFirstUEdge  = E1;
  theSecondUEdge = E2;
  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// static function: FillGap
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FillGap(const TopoDS_Vertex&   theFirstVertex,
                         const TopoDS_Vertex&   theLastVertex,
                         const gp_Pnt2d&        theFirstPoint,
                         const gp_Pnt2d&        theLastPoint,
                         const TopoDS_Face&     theFace,
                         const TopoDS_Compound& theSectionEdges,
                         TopTools_ListOfShape&  theOrderedList)
{

  TopTools_IndexedDataMapOfShapeListOfShape aMap;
  TopExp::MapShapesAndAncestors(theSectionEdges, TopAbs_VERTEX, TopAbs_EDGE, aMap);

  if (aMap.IsEmpty())
  {
    return Standard_False;
  }

  if (!aMap.Contains(theFirstVertex) || !aMap.Contains(theLastVertex))
  {
    return Standard_False;
  }
  TopTools_ListOfShape aListOfEdge;
  //  Standard_Integer i = 0;
  //  TopoDS_Vertex aCurVertex = theFirstVertex;
  TopTools_MapOfShape aMapToAvoid;

  if (FindNextEdge(theFirstVertex, theLastVertex, aMap, aMapToAvoid, aListOfEdge))
  {
    if (!aListOfEdge.IsEmpty())
    {
      return CheckAndOrientEdges(aListOfEdge, theFirstPoint, theLastPoint, theFace, theOrderedList);
    }
  }
  return Standard_False;
}

// ----------------------------------------------------------------------------------------------------
// static function: FindNextEdge
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FindNextEdge(const TopoDS_Vertex&                             theFirstVertex,
                              const TopoDS_Vertex&                             theLastVertex,
                              const TopTools_IndexedDataMapOfShapeListOfShape& theMapVE,
                              const TopTools_MapOfShape&                       theMapToAvoid,
                              TopTools_ListOfShape&                            theOrderedList)
{
  TopoDS_Vertex       aCurVertex = theFirstVertex;
  TopTools_MapOfShape aMapToAvoid;
  aMapToAvoid = theMapToAvoid;
  TopTools_ListOfShape aListOfEdge;
  Standard_Integer     i = 0;

  for (i = 1; i <= theMapVE.Extent(); i++)
  {
    if (!theMapVE.Contains(aCurVertex))
      break;
    const TopTools_ListOfShape& lste    = theMapVE.FindFromKey(aCurVertex);
    Standard_Boolean            befound = Standard_False;

    TopTools_ListIteratorOfListOfShape anIt(lste);

    for (; anIt.More(); anIt.Next())
    {
      TopoDS_Shape  anEdge         = anIt.Value();
      TopoDS_Vertex aSaveCurVertex = aCurVertex;

      if (!aMapToAvoid.Contains(anEdge))
      {
        TopoDS_Vertex V1, V2;
        TopExp::Vertices(TopoDS::Edge(anEdge), V1, V2);

        if (!aCurVertex.IsSame(V1))
        {
          aCurVertex = V1;
        }
        else if (!aCurVertex.IsSame(V2))
        {
          aCurVertex = V2;
        }
        aMapToAvoid.Add(anEdge);
        befound = Standard_True;
        aListOfEdge.Append(anEdge);

        if (!aCurVertex.IsSame(theLastVertex))
        {
          TopTools_ListOfShape aListtmp;

          if (!FindNextEdge(aCurVertex, theLastVertex, theMapVE, aMapToAvoid, aListtmp))
          {
            aListOfEdge.Clear();
            aCurVertex = aSaveCurVertex;
            continue;
          }
          else
          {
            aListOfEdge.Append(aListtmp);
            theOrderedList.Append(aListOfEdge);
            return Standard_True;
          }
        }
        break;
      }
    }

    if (aCurVertex.IsSame(theLastVertex))
      break;

    if (!befound)
    {
      return Standard_False;
    }
  }

  if (aCurVertex.IsSame(theLastVertex))
  {
    theOrderedList.Append(aListOfEdge);
    return Standard_True;
  }
  return Standard_False;
}

// ----------------------------------------------------------------------------------------------------
// static function: CheckAndOrientEdges
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean CheckAndOrientEdges(const TopTools_ListOfShape& theOrderedList,
                                     const gp_Pnt2d&             theFirstPoint,
                                     const gp_Pnt2d&             theLastPoint,
                                     const TopoDS_Face&          theFace,
                                     TopTools_ListOfShape&       theOrientedList)
{
  TopTools_ListIteratorOfListOfShape anIt(theOrderedList);

  if (!anIt.More())
    return Standard_True;

  Standard_Real f, l;
  TopoDS_Edge   aEPrev = TopoDS::Edge(anIt.Value());
  anIt.Next();

  Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(aEPrev, theFace, f, l);
  TopoDS_Vertex        Vf, Vl;
  TopExp::Vertices(aEPrev, Vf, Vl);
  BRepAdaptor_Surface aBAS(theFace, Standard_False);

  Standard_Real aTolerance1 = (Vf.IsNull()) ? Precision::Confusion() : BRep_Tool::Tolerance(Vf);
  Standard_Real aTolerance2 = (Vl.IsNull()) ? Precision::Confusion() : BRep_Tool::Tolerance(Vl);
  Standard_Real utol        = aBAS.UResolution(aTolerance1);
  Standard_Real vtol        = aBAS.VResolution(aTolerance1);
  aTolerance1               = (utol > vtol) ? utol : vtol;
  utol                      = aBAS.UResolution(aTolerance2);
  vtol                      = aBAS.VResolution(aTolerance2);
  aTolerance2               = (utol > vtol) ? utol : vtol;

  gp_Pnt2d         ap          = aCurve->Value(f);
  Standard_Boolean bFirstFound = Standard_False;
  Standard_Boolean bLastFound  = Standard_False;

  if (ap.Distance(theFirstPoint) < aTolerance1)
  {
    if (theOrientedList.IsEmpty())
      theOrientedList.Append(aEPrev.Oriented(TopAbs_FORWARD));
    bFirstFound = Standard_True;
  }
  else if (ap.Distance(theLastPoint) < aTolerance1)
  {
    if (theOrientedList.IsEmpty())
      theOrientedList.Append(aEPrev.Oriented(TopAbs_REVERSED));
    bLastFound = Standard_True;
  }
  ap = aCurve->Value(l);

  if (ap.Distance(theLastPoint) < aTolerance2)
  {
    if (theOrientedList.IsEmpty())
      theOrientedList.Append(aEPrev.Oriented(TopAbs_FORWARD));
    bLastFound = Standard_True;
  }
  else if (ap.Distance(theFirstPoint) < aTolerance2)
  {
    if (theOrientedList.IsEmpty())
      theOrientedList.Append(aEPrev.Oriented(TopAbs_REVERSED));
    bFirstFound = Standard_True;
  }

  if (!theOrientedList.IsEmpty())
    aEPrev = TopoDS::Edge(theOrientedList.Last());

  for (; anIt.More(); anIt.Next())
  {
    const TopoDS_Edge& aE = TopoDS::Edge(anIt.Value());
    TopoDS_Vertex      aV11, aV12;
    TopExp::Vertices(aEPrev, aV11, aV12, Standard_True);
    TopoDS_Vertex aV21, aV22;
    TopExp::Vertices(aE, aV21, aV22, Standard_False);

    TopAbs_Orientation anOri =
      (aV12.IsSame(aV21) || aV11.IsSame(aV22)) ? TopAbs_FORWARD : TopAbs_REVERSED;
    theOrientedList.Append(aE.Oriented(anOri));
    aEPrev = TopoDS::Edge(theOrientedList.Last());

    aTolerance1 = (aV21.IsNull()) ? Precision::Confusion() : BRep_Tool::Tolerance(aV21);
    aTolerance2 = (aV22.IsNull()) ? Precision::Confusion() : BRep_Tool::Tolerance(aV22);
    utol        = aBAS.UResolution(aTolerance1);
    vtol        = aBAS.VResolution(aTolerance1);
    aTolerance1 = (utol > vtol) ? utol : vtol;
    utol        = aBAS.UResolution(aTolerance2);
    vtol        = aBAS.VResolution(aTolerance2);
    aTolerance2 = (utol > vtol) ? utol : vtol;
    aCurve      = BRep_Tool::CurveOnSurface(aE, theFace, f, l);
    ap          = aCurve->Value(f);

    if (ap.Distance(theFirstPoint) < aTolerance1)
    {
      bFirstFound = Standard_True;
    }
    else if (ap.Distance(theLastPoint) < aTolerance1)
    {
      bLastFound = Standard_True;
    }
    ap = aCurve->Value(l);

    if (ap.Distance(theFirstPoint) < aTolerance2)
    {
      bFirstFound = Standard_True;
    }
    else if (ap.Distance(theLastPoint) < aTolerance2)
    {
      bLastFound = Standard_True;
    }
  }

  return bFirstFound && bLastFound;
}

// ----------------------------------------------------------------------------------------------------
// static function: FindVertex
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FindVertex(const TopoDS_Edge&                        theEdge,
                            const Standard_Integer                    theRank,
                            const BOPDS_PDS&                          theDS,
                            const TopTools_DataMapOfShapeListOfShape& theHistMap,
                            TopoDS_Vertex&                            theVertex,
                            BOPDS_Pave&                               thePave)
{

  if (!theHistMap.IsBound(theEdge))
    return Standard_False;

  const TopTools_ListOfShape& lst = theHistMap.Find(theEdge);

  if (lst.IsEmpty())
    return Standard_False;

  TopoDS_Edge   aNewEdge = TopoDS::Edge(lst.First());
  Standard_Real f, l;
  BRep_Tool::Range(aNewEdge, f, l);

  if (theRank == 0)
  {
    thePave.SetParameter(l);
    theVertex = TopExp::LastVertex(aNewEdge);
  }
  else
  {
    thePave.SetParameter(f);
    theVertex = TopExp::FirstVertex(aNewEdge);
  }
  Standard_Integer anIndex = theDS->Index(theVertex);
  if (anIndex == -1)
  {
    Standard_Integer i, i1, i2;
    i1 = theDS->NbSourceShapes();
    i2 = theDS->NbShapes();
    for (i = i1; i < i2; ++i)
    {
      const TopoDS_Shape& aSx = theDS->Shape(i);
      if (aSx.IsSame(theVertex))
      {
        anIndex = i;
        break;
      }
    }
  }

  thePave.SetIndex(anIndex);

  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// static function: FindNextVertex
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FindNextVertex(const Standard_Integer theEdgeIndex,
                                const BOPDS_Pave&      thePrevPave,
                                const BOPDS_PDS&       theDS,
                                TopoDS_Vertex&         theNextVertex,
                                BOPDS_Pave&            thePave)
{

  Standard_Boolean               bTakePave, bFound;
  BOPDS_Pave                     aTmpPave;
  BOPDS_ListIteratorOfListOfPave aItP;
  //
  BOPDS_Pave anullpave;
  bFound    = Standard_False;
  bTakePave = thePrevPave.IsEqual(anullpave);

  BOPDS_ListOfPave aLP;
  theDS->Paves(theEdgeIndex, aLP);
  aItP.Initialize(aLP);
  for (; aItP.More(); aItP.Next())
  {
    aTmpPave = aItP.Value();
    //
    if (bTakePave)
    {
      if (theDS->IsNewShape(aTmpPave.Index()))
      {
        theNextVertex = *(TopoDS_Vertex*)&theDS->Shape(aTmpPave.Index());
        thePave       = aTmpPave;
        bFound        = Standard_True;
        break;
      }
    }
    //
    else if (aTmpPave.IsEqual(thePrevPave))
    {
      bTakePave = Standard_True;
    }
  }

  return bFound;
}

// ----------------------------------------------------------------------------------------------------
// static function: GetPave
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean GetPave(const Standard_Integer theEdgeIndex,
                         const Standard_Boolean isFirst,
                         const BOPDS_PDS&       theDS,
                         BOPDS_Pave&            thePave)
{

  Handle(BOPDS_PaveBlock) aPB;
  BOPDS_ListOfPave        aLP;

  theDS->Paves(theEdgeIndex, aLP);
  if (!aLP.Extent())
  {
    return Standard_False;
  }
  //
  if (isFirst)
  {
    thePave = aLP.First();
  }
  else
  {
    thePave = aLP.Last();
  }

  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// static function: FindFromUEdge
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FindFromUEdge(const TopoDS_Edge&                        theUE1Old,
                               const TopoDS_Edge&                        theUE2Old,
                               const TopoDS_Edge&                        theUE1New,
                               const TopoDS_Edge&                        theUE2New,
                               const TopoDS_Face&                        theFace,
                               const TopoDS_Compound&                    theSecEdges,
                               const Standard_Integer                    theRank,
                               const TopoDS_Edge&                        theBoundEdge,
                               const Standard_Integer                    theBoundEdgeIndex,
                               const BOPDS_PDS&                          theDS,
                               const TopTools_DataMapOfShapeListOfShape& theHistMap,
                               TopoDS_Compound&                          theSecEdgesNew,
                               TopTools_ListOfShape&                     theListOfWireEdges,
                               BOPDS_Pave&                               theFoundPave,
                               Standard_Boolean&                         isOnUEdge)
{
  theFoundPave.SetIndex(0);
  theFoundPave.SetParameter(0.);
  isOnUEdge = Standard_True;

  TopoDS_Face aFaceF = theFace;
  aFaceF.Orientation(TopAbs_FORWARD);
  TopoDS_Vertex        aPrevVertex, aNextVertex;
  TopoDS_Compound      aCompOfSecEdges = theSecEdges;
  TopTools_ListOfShape aListOfWireEdges;
  //  BRep_Builder aBB;

  BOPDS_Pave    aPave1, aPave2;
  Standard_Real f = 0., l = 0.;
  gp_Pnt2d      p1, p2;
  TopoDS_Vertex aFirstV, aLastV;
  BOPDS_Pave    atmpPave;

  if (!FindVertex(theUE1Old, theRank, theDS, theHistMap, aPrevVertex, atmpPave))
  {
    return Standard_True;
  }

  if (aPrevVertex.IsNull())
  {
    return Standard_False;
  }

  aFirstV                        = aPrevVertex;
  Standard_Boolean     bSecFound = Standard_False;
  Handle(Geom2d_Curve) aC1       = BRep_Tool::CurveOnSurface(theUE1New, aFaceF, f, l);
  p1                             = (theRank == 0) ? aC1->Value(l) : aC1->Value(f);
  BOPDS_Pave       afoundpave;
  BOPDS_ListOfPave aLP;
  theDS->Paves(theBoundEdgeIndex, aLP);
  Standard_Integer nbpave = aLP.Extent();
  Standard_Integer pit    = 0;

  while (FindNextVertex(theBoundEdgeIndex, aPave1, theDS, aNextVertex, aPave2) && (pit < nbpave))
  {
    aLastV                   = aNextVertex;
    Handle(Geom2d_Curve) aC2 = BRep_Tool::CurveOnSurface(theBoundEdge, aFaceF, f, l);
    p2                       = aC2->Value(aPave2.Parameter());
    TopTools_ListOfShape aOrderedList;

    if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
    {
      // remove found edges...
      TopoDS_Compound aComp;
      RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
      aCompOfSecEdges = aComp;
      aListOfWireEdges.Append(aOrderedList);
      afoundpave = aPave2;
      isOnUEdge  = Standard_False;
      bSecFound  = Standard_True;
      break;
    }
    aPrevVertex = aNextVertex;
    aPave1      = aPave2;
    pit++;
  }

  if (!bSecFound && FindVertex(theUE2Old, theRank, theDS, theHistMap, aNextVertex, aPave2))
  {
    aLastV                   = aNextVertex;
    Handle(Geom2d_Curve) aC2 = BRep_Tool::CurveOnSurface(theUE2New, aFaceF, f, l);
    p2                       = aC2->Value(aPave2.Parameter());
    TopTools_ListOfShape aOrderedList;

    if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
    {
      // remove found edges...
      TopoDS_Compound aComp;

      RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
      aCompOfSecEdges = aComp;
      aListOfWireEdges.Append(aOrderedList);
      afoundpave = aPave2;
      bSecFound  = Standard_True;
      isOnUEdge  = Standard_True;
    }
  }

  if (bSecFound)
  {
    theFoundPave       = afoundpave;
    theListOfWireEdges = aListOfWireEdges;
    theSecEdgesNew     = aCompOfSecEdges;
  }
  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// static function: FindFromVEdge
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FindFromVEdge(const BOPDS_Pave&                         thePrevPave,
                               const Standard_Boolean&                   isOnUEdge,
                               const TopoDS_Edge&                        theUE1Old,
                               const TopoDS_Edge&                        theUE2Old,
                               const TopoDS_Face&                        theFace,
                               const TopoDS_Compound&                    theSecEdges,
                               const Standard_Integer                    theRank,
                               const TopoDS_Edge&                        theBoundEdge,
                               const Standard_Integer                    theBoundEdgeIndex,
                               const BOPDS_PDS&                          theDS,
                               const TopTools_DataMapOfShapeListOfShape& theHistMap,
                               TopTools_ListOfShape&                     theListOfWireEdges,
                               Standard_Boolean&                         isSectionFound)
{

  theListOfWireEdges.Clear();
  isSectionFound = Standard_False;
  //
  TopoDS_Face aFaceF = theFace;
  aFaceF.Orientation(TopAbs_FORWARD);
  TopoDS_Vertex        aPrevVertex, aNextVertex;
  TopoDS_Compound      aCompOfSecEdges = theSecEdges;
  TopTools_ListOfShape aListOfWireEdges;
  //  BRep_Builder aBB;

  BOPDS_Pave aPave1, aPave2;

  if (isOnUEdge)
  {
    TopoDS_Vertex atmpVertex;
    BOPDS_Pave    aPaveOfE2;

    if (FindVertex(theUE2Old, theRank, theDS, theHistMap, atmpVertex, aPaveOfE2))
    {
      if (thePrevPave.IsEqual(aPaveOfE2))
        return Standard_True;
    }
  }

  Standard_Real        f = 0., l = 0.;
  gp_Pnt2d             p1(0., 0.), p2(0., 0.);
  TopoDS_Vertex        aFirstV, aLastV;
  Handle(Geom2d_Curve) aC1       = BRep_Tool::CurveOnSurface(theUE1Old, aFaceF, f, l);
  Handle(Geom2d_Curve) aC2       = BRep_Tool::CurveOnSurface(theBoundEdge, aFaceF, f, l);
  Standard_Boolean     bSecFound = Standard_False;

  aPave1 = thePrevPave;

  if (isOnUEdge)
  {
    BOPDS_Pave atmpPave;

    if (!GetPave(theBoundEdgeIndex, Standard_True, theDS, atmpPave))
    {
      return Standard_False;
    }
    aPave1 = atmpPave;
  }
  p1          = aC2->Value(aPave1.Parameter());
  aPrevVertex = TopoDS::Vertex(theDS->Shape(aPave1.Index()));

  BOPDS_ListOfPave aLP;
  theDS->Paves(theBoundEdgeIndex, aLP);
  Standard_Integer             nbpave = aLP.Extent();
  Standard_Integer             pit    = 0;
  TopTools_Array1OfListOfShape anArrayOfListOfSec(1, nbpave);

  // by pairs non continuously. begin
  Standard_Integer      k            = 0;
  BOPDS_Pave            aFirstPave   = aPave1;
  TopoDS_Vertex         aFirstVertex = aPrevVertex;
  gp_Pnt2d              apfirst      = p1;
  BOPDS_ListOfPave      aFirstPaves, aLastPaves;
  TColStd_ListOfInteger aListOfFlags;
  Standard_Integer      apaircounter = 1;

  for (k = 0; k < nbpave; k++)
  {
    aPave1                  = aFirstPave;
    p1                      = apfirst;
    aPrevVertex             = aFirstVertex;
    Standard_Boolean bfound = Standard_False;
    pit                     = 0;

    while (FindNextVertex(theBoundEdgeIndex, aPave1, theDS, aNextVertex, aPave2) && (pit < nbpave))
    {
      aFirstV = aPrevVertex;
      aLastV  = aNextVertex;
      p2      = aC2->Value(aPave2.Parameter());

      TopTools_ListOfShape aOrderedList;

      if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
      {
        TopoDS_Compound aComp;
        RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
        aCompOfSecEdges = aComp;

        anArrayOfListOfSec(apaircounter++).Append(aOrderedList);
        aFirstPaves.Append(aFirstPave);
        aLastPaves.Append(aPave2);
        aListOfFlags.Append(1);
        aFirstPave   = aPave2;
        aFirstVertex = aNextVertex;
        apfirst      = p2;
        aPrevVertex  = aNextVertex;
        bSecFound    = Standard_True;
        bfound       = Standard_True;
      }
      aPave1 = aPave2;
      pit++;
    }

    if (FindVertex(theUE2Old, theRank, theDS, theHistMap, aNextVertex, aPave2))
    {
      aFirstV                  = aPrevVertex;
      aLastV                   = aNextVertex;
      Handle(Geom2d_Curve) aC3 = BRep_Tool::CurveOnSurface(theUE2Old, aFaceF, f, l);
      p2                       = aC3->Value(aPave2.Parameter());

      TopTools_ListOfShape aOrderedList;

      if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
      {
        TopoDS_Compound aComp;
        RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
        aCompOfSecEdges = aComp;
        anArrayOfListOfSec(apaircounter++).Append(aOrderedList);
        aFirstPaves.Append(aFirstPave);
        aLastPaves.Append(aPave2);
        aListOfFlags.Append(0);
        bSecFound = Standard_True;
        break;
      }
    }

    if (!bfound)
    {
      if (!FindNextVertex(theBoundEdgeIndex, aFirstPave, theDS, aNextVertex, aPave2))
      {
        break;
      }
      aFirstPave   = aPave2;
      apfirst      = aC2->Value(aPave2.Parameter());
      aFirstVertex = aNextVertex;
    }
  }
  // by pairs non continuously. end

  // by pairs continuously. begin
  aPave1 = thePrevPave;

  if (isOnUEdge)
  {
    BOPDS_Pave atmpPave;

    if (!GetPave(theBoundEdgeIndex, Standard_True, theDS, atmpPave))
    {
      return Standard_False;
    }
    aPave1 = atmpPave;
  }
  p1          = aC2->Value(aPave1.Parameter());
  aPrevVertex = TopoDS::Vertex(theDS->Shape(aPave1.Index()));

  pit = 0;

  while (FindNextVertex(theBoundEdgeIndex, aPave1, theDS, aNextVertex, aPave2) && (pit < nbpave))
  {
    aFirstV = aPrevVertex;
    aLastV  = aNextVertex;
    p2      = aC2->Value(aPave2.Parameter());

    Standard_Boolean                    bisinside  = Standard_False;
    Standard_Integer                    apbindex   = 0;
    Standard_Integer                    apbcounter = 1;
    BOPDS_ListIteratorOfListOfPaveBlock aPBIt;
    BOPDS_ListIteratorOfListOfPave      aPIt1, aPIt2;
    TColStd_ListIteratorOfListOfInteger aFlagIt;

    for (aPIt1.Initialize(aFirstPaves),
         aPIt2.Initialize(aLastPaves),
         aFlagIt.Initialize(aListOfFlags);
         aPIt1.More() && aPIt2.More() && aFlagIt.More();
         aPIt1.Next(), aPIt2.Next(), aFlagIt.Next(), apbcounter++)
    {

      Standard_Boolean bfin = Standard_False;
      Standard_Boolean blin = Standard_False;

      if (aPave1.IsEqual(aPIt1.Value()))
      {
        bfin = Standard_True;
      }
      else
      {
        bfin = (aPave1.Parameter() > aPIt1.Value().Parameter());
      }

      if (aFlagIt.Value())
      {
        if (aPave2.IsEqual(aPIt2.Value()))
        {
          blin = Standard_True;
        }
        else
        {
          blin = (aPave2.Parameter() < aPIt2.Value().Parameter());
        }
      }
      else
      {
        if ((aPave2.Index() == aPIt2.Value().Index()) && (aPave2.Index() > 0))
        {
          Handle(Geom2d_Curve) pc = BRep_Tool::CurveOnSurface(theUE2Old, aFaceF, f, l);
          gp_Pnt2d             p3 = pc->Value(aPIt2.Value().Parameter());
          TopoDS_Vertex        aV = TopoDS::Vertex(theDS->Shape(aPave2.Index()));
          BRepAdaptor_Surface  aBAS(aFaceF, Standard_False);
          Standard_Real        aTolerance = BRep_Tool::Tolerance(aV);
          Standard_Real        utol       = aBAS.UResolution(aTolerance);
          Standard_Real        vtol       = aBAS.VResolution(aTolerance);
          aTolerance                      = (utol > vtol) ? utol : vtol;

          if (p2.Distance(p3) < aTolerance)
            blin = Standard_True;
        }
      }

      if (bfin && blin)
      {
        apbindex  = apbcounter;
        bisinside = Standard_True;
        break;
      }
    }

    if (!bisinside)
    {

      TopTools_ListOfShape aOrderedList;

      if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
      {
        TopoDS_Compound aComp;
        RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
        aCompOfSecEdges = aComp;
        aListOfWireEdges.Append(aOrderedList);

        bSecFound = Standard_True;
      }
      else
      {
        TopoDS_Edge aESplit;
        // get split
        aPBIt.Initialize(theDS->PaveBlocks(theBoundEdgeIndex));

        for (; aPBIt.More(); aPBIt.Next())
        {
          const Handle(BOPDS_PaveBlock)& aPB1 = aPBIt.Value();
          if (aPB1->OriginalEdge() == theBoundEdgeIndex && aPB1->Pave1().IsEqual(aPave1)
              && aPB1->Pave2().IsEqual(aPave2))
          {
            if (aPB1->Edge() > 0)
            {
              aESplit = *(TopoDS_Edge*)&theDS->Shape(aPB1->Edge());
              break;
            }
          }
        }

        if (!aESplit.IsNull())
        {
          aListOfWireEdges.Append(aESplit);
        }
      }
    }
    else
    {
      if (apbindex > 0)
      {
        TopTools_ListOfShape& aListOfSec = anArrayOfListOfSec(apbindex);
        aListOfWireEdges.Append(aListOfSec);
      }
    }
    aPave1      = aPave2;
    aPrevVertex = aNextVertex;
    p1          = p2;
    pit++;
  }

  if (FindVertex(theUE2Old, theRank, theDS, theHistMap, aNextVertex, aPave2))
  {
    aFirstV                  = aPrevVertex;
    aLastV                   = aNextVertex;
    Handle(Geom2d_Curve) aC3 = BRep_Tool::CurveOnSurface(theUE2Old, aFaceF, f, l);
    p2                       = aC3->Value(aPave2.Parameter());

    Standard_Boolean                    bisinside  = Standard_False;
    Standard_Integer                    apbindex   = 0;
    Standard_Integer                    apbcounter = 1;
    BOPDS_ListIteratorOfListOfPaveBlock aPBIt;
    BOPDS_ListIteratorOfListOfPave      aPIt1, aPIt2;
    TColStd_ListIteratorOfListOfInteger aFlagIt;

    for (aPIt1.Initialize(aFirstPaves),
         aPIt2.Initialize(aLastPaves),
         aFlagIt.Initialize(aListOfFlags);
         aPIt1.More() && aPIt2.More() && aFlagIt.More();
         aPIt1.Next(), aPIt2.Next(), aFlagIt.Next(), apbcounter++)
    {

      Standard_Boolean bfin = Standard_False;
      Standard_Boolean blin = Standard_False;

      if (aPave1.IsEqual(aPIt1.Value()))
      {
        bfin = Standard_True;
      }
      else
      {
        bfin = (aPave1.Parameter() > aPIt1.Value().Parameter());
      }

      if (aFlagIt.Value())
      {
        if (aPave2.IsEqual(aPIt2.Value()))
        {
          blin = Standard_True;
        }
        else
        {
          blin = (aPave2.Parameter() < aPIt2.Value().Parameter());
        }
      }
      else
      {
        blin = Standard_True;
      }

      if (bfin && blin)
      {
        apbindex  = apbcounter;
        bisinside = Standard_True;
        break;
      }
    }

    if (!bisinside)
    {

      TopTools_ListOfShape aOrderedList;

      if (FillGap(aFirstV, aLastV, p1, p2, aFaceF, aCompOfSecEdges, aOrderedList))
      {
        TopoDS_Compound aComp;
        RemoveEdges(aCompOfSecEdges, aOrderedList, aComp);
        aCompOfSecEdges = aComp;
        aListOfWireEdges.Append(aOrderedList);

        bSecFound = Standard_True;
      }
      else
      {
        // add split
        TopoDS_Edge aESplit;
        // get split
        if (!GetPave(theBoundEdgeIndex, Standard_False, theDS, aPave2))
          return Standard_False;
        //
        aPBIt.Initialize(theDS->PaveBlocks(theBoundEdgeIndex));
        for (; aPBIt.More(); aPBIt.Next())
        {
          const Handle(BOPDS_PaveBlock)& aPB1 = aPBIt.Value();
          if (aPB1->OriginalEdge() == theBoundEdgeIndex && aPB1->Pave1().IsEqual(aPave1)
              && aPB1->Pave2().IsEqual(aPave2))
          {
            if (aPB1->Edge() > 0)
            {
              aESplit = *(TopoDS_Edge*)&theDS->Shape(aPB1->Edge());
              break;
            }
          }
        }

        if (!aESplit.IsNull())
        {
          aListOfWireEdges.Append(aESplit);
        }
      }
    }
    else
    {
      if (apbindex > 0)
      {
        TopTools_ListOfShape& aListOfSec = anArrayOfListOfSec(apbindex);
        aListOfWireEdges.Append(aListOfSec);
      }
    }
  }
  else
  {
    // add split
    TopoDS_Edge aESplit;
    // get split
    if (!GetPave(theBoundEdgeIndex, Standard_False, theDS, aPave2))
      return Standard_False;

    BOPDS_ListIteratorOfListOfPaveBlock aPBIt;
    aPBIt.Initialize(theDS->PaveBlocks(theBoundEdgeIndex));
    for (; aPBIt.More(); aPBIt.Next())
    {
      const Handle(BOPDS_PaveBlock)& aPB1 = aPBIt.Value();
      if (aPB1->OriginalEdge() == theBoundEdgeIndex && aPB1->Pave1().IsEqual(aPave1)
          && aPB1->Pave2().IsEqual(aPave2))
      {
        if (aPB1->Edge() > 0)
        {
          aESplit = *(TopoDS_Edge*)&theDS->Shape(aPB1->Edge());
          break;
        }
      }
    }

    if (!aESplit.IsNull())
    {
      aListOfWireEdges.Append(aESplit);
    }
  }

  // by pairs continuously. end
  theListOfWireEdges = aListOfWireEdges;
  isSectionFound     = bSecFound;
  return Standard_True;
}

// ----------------------------------------------------------------------------------------------------
// static function: RemoveEdges
// purpose:
// ----------------------------------------------------------------------------------------------------
void RemoveEdges(const TopoDS_Compound&      theSourceComp,
                 const TopTools_ListOfShape& theListToRemove,
                 TopoDS_Compound&            theResultComp)
{
  BRep_Builder    aBB;
  TopoDS_Compound aComp;
  aBB.MakeCompound(aComp);
  TopExp_Explorer anExp(theSourceComp, TopAbs_EDGE);

  for (; anExp.More(); anExp.Next())
  {
    Standard_Boolean                   bfound = Standard_False;
    TopTools_ListIteratorOfListOfShape anIt(theListToRemove);

    for (; !bfound && anIt.More(); anIt.Next())
    {
      bfound = anExp.Current().IsSame(anIt.Value());
    }

    if (!bfound)
    {
      aBB.Add(aComp, anExp.Current());
    }
  }
  theResultComp = aComp;
}

// ----------------------------------------------------------------------------------------------------
// static function: FilterSectionEdges
// purpose:
// ----------------------------------------------------------------------------------------------------
Standard_Boolean FilterSectionEdges(const BOPDS_VectorOfCurve& theBCurves,
                                    const TopoDS_Face&         theSecPlane,
                                    const BOPDS_PDS&           theDS,
                                    TopoDS_Compound&           theResult)
{

  theResult.Nullify();

  BRep_Builder aBB;
  aBB.MakeCompound(theResult);
  Standard_Integer                    aNbCurves = theBCurves.Length();
  Standard_Integer                    cit       = 0;
  BOPDS_ListIteratorOfListOfPaveBlock aPBIt;

  for (cit = 0; cit < aNbCurves; ++cit)
  {
    const BOPDS_Curve&           aBCurve    = theBCurves(cit);
    const BOPDS_ListOfPaveBlock& aSectEdges = aBCurve.PaveBlocks();

    aPBIt.Initialize(aSectEdges);
    for (; aPBIt.More(); aPBIt.Next())
    {
      const Handle(BOPDS_PaveBlock)& aPB      = aPBIt.Value();
      Standard_Integer               nSect    = aPB->Edge();
      const TopoDS_Shape&            aS       = theDS->Shape(nSect);
      TopoDS_Edge                    anEdge   = TopoDS::Edge(aS);
      Standard_Boolean               bAddEdge = Standard_True;

      if (!theSecPlane.IsNull())
      {
        IntTools_BeanFaceIntersector anIntersector(anEdge, theSecPlane);
        Standard_Real                f = 0., l = 0.;
        BRep_Tool::Range(anEdge, f, l);
        anIntersector.SetBeanParameters(f, l);
        //
        Handle(IntTools_Context) aContext = new IntTools_Context;
        anIntersector.SetContext(aContext);
        //
        anIntersector.Perform();

        if (anIntersector.IsDone())
        {
          bAddEdge           = Standard_False;
          Standard_Integer r = 0;

          for (r = 1; r <= anIntersector.Result().Length(); r++)
          {
            const IntTools_Range& aRange = anIntersector.Result().Value(r);

            if (((aRange.First() - f) < Precision::PConfusion())
                && ((l - aRange.Last()) < Precision::PConfusion()))
            {
              bAddEdge = Standard_True;
              break;
            } // if(((aRange.First() - f) < Precision::PConfusion()) &&
          } // for(r = 1; r <= anIntersector.Result().Length(); r++) {
        } // if(anIntersector.IsDone()) {
      } // if(!theSecPlane.IsNull()) {

      if (bAddEdge)
      {
        aBB.Add(theResult, aS);
      }
    } // for (; aPBIt.More(); aPBIt.Next()) {
  } // for(cit = 0; cit < aNbCurves; ++cit) {

  return Standard_True;
}

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

static Standard_Real ComputeAveragePlaneAndMaxDeviation(const TopoDS_Shape& aWire,
                                                        gp_Pln&             thePlane,
                                                        Standard_Boolean&   IsSingular)
{
  Standard_Integer N      = 40;
  Standard_Integer nedges = aWire.NbChildren();

  TColgp_Array1OfPnt Pnts(1, nedges * N);
  Standard_Integer   ind = 1, i;
  for (TopoDS_Iterator iter(aWire); iter.More(); iter.Next())
  {
    const TopoDS_Edge&     anEdge = TopoDS::Edge(iter.Value());
    BRepAdaptor_Curve      aCurve(anEdge);
    GCPnts_UniformAbscissa Distribution(aCurve, N + 1);
    for (i = 1; i <= N; i++)
    {
      Standard_Real par = Distribution.Parameter(i);
      Pnts(ind++)       = aCurve.Value(par);
    }
  }

  gp_Ax2 Axe;
  GeomLib::AxeOfInertia(Pnts, Axe, IsSingular);
  if (IsSingular)
    return -1;

  thePlane                   = gp_Pln(Axe);
  Standard_Real MaxDeviation = 0;
  for (i = 1; i <= Pnts.Length(); i++)
  {
    Standard_Real dist = thePlane.Distance(Pnts(i));
    if (dist > MaxDeviation)
      MaxDeviation = dist;
  }
  return MaxDeviation;
}

static void UpdateSectionEdge(TopoDS_Edge&         theEdge,
                              const TopoDS_Vertex& theConstVertex,
                              TopoDS_Vertex&       theVertex,
                              const Standard_Real  theParam)
{
  TopoDS_Edge F_Edge = theEdge;
  F_Edge.Orientation(TopAbs_FORWARD);

  TopAbs_Orientation OrOfVertex;
  TopoDS_Vertex      V1, V2, AnotherVertex;
  TopExp::Vertices(F_Edge, V1, V2);
  if (theConstVertex.IsSame(V1))
  {
    // OrOfConst = TopAbs_FORWARD;
    OrOfVertex    = TopAbs_REVERSED;
    AnotherVertex = V2;
  }
  else
  {
    // OrOfConst = TopAbs_REVERSED;
    OrOfVertex    = TopAbs_FORWARD;
    AnotherVertex = V1;
  }

  BRep_Builder  BB;
  Standard_Real fpar, lpar;
  BRep_Tool::Range(F_Edge, fpar, lpar);
  if (OrOfVertex == TopAbs_FORWARD)
    fpar = theParam;
  else
    lpar = theParam;
  BB.Range(F_Edge, fpar, lpar);

  F_Edge.Free(Standard_True);
  BB.Remove(F_Edge, AnotherVertex);
  theVertex.Orientation(OrOfVertex);
  BB.Add(F_Edge, theVertex);
}

// Finds the edge connected to <theVertex> in the compound <theComp>
// that is closest to bisector plane angularly.
// Removes found edge from <theComp>
//<theAxis> is the axis of bisector plane
static TopoDS_Edge FindEdgeCloseToBisectorPlane(const TopoDS_Vertex& theVertex,
                                                TopoDS_Compound&     theComp,
                                                const gp_Ax1&        theAxis)
{
  TopTools_IndexedDataMapOfShapeListOfShape VEmap;
  TopExp::MapShapesAndAncestors(theComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap);

  TopoDS_Edge MinEdge;
  if (!VEmap.Contains(theVertex))
    return MinEdge;

  BRep_Builder BB;

  const TopTools_ListOfShape& Edges = VEmap.FindFromKey(theVertex);
  if (Edges.Extent() == 1)
    MinEdge = TopoDS::Edge(Edges.First());
  else
  {
    TopTools_ListIteratorOfListOfShape itl(Edges);
    Standard_Real                      MinAngle = RealLast();
    for (; itl.More(); itl.Next())
    {
      const TopoDS_Edge& anEdge = TopoDS::Edge(itl.Value());
      TopoDS_Wire        aWire;
      BB.MakeWire(aWire);
      BB.Add(aWire, anEdge);
      gp_Pln           aPln;
      Standard_Boolean issing;
      ComputeAveragePlaneAndMaxDeviation(aWire, aPln, issing);
      Standard_Real anAngle;
      if (issing) // edge is a segment of line
      {
        //<anAngle> is angle between <anEdge> and its projection on bisector plane
        BRepAdaptor_Curve BAcurve(anEdge);
        gp_Pnt            FirstPnt = BAcurve.Value(BAcurve.FirstParameter());
        gp_Pnt            LastPnt  = BAcurve.Value(BAcurve.LastParameter());
        gp_Vec            EdgeVec(FirstPnt, LastPnt);
        gp_Ax1            EdgeAxis(FirstPnt, EdgeVec);
        anAngle = EdgeAxis.Direction().Angle(theAxis.Direction());
        if (anAngle > M_PI / 2)
          anAngle = M_PI - anAngle;
        anAngle = M_PI / 2 - anAngle;
      }
      else
      {
        anAngle = aPln.Axis().Angle(theAxis);
        if (anAngle > M_PI / 2)
          anAngle = M_PI - anAngle;
      }

      if (anAngle < MinAngle)
      {
        MinAngle = anAngle;
        MinEdge  = anEdge;
      }
    }
  } // else (more than one edge)

  BB.Remove(theComp, MinEdge);
  return MinEdge;
}

static Standard_Boolean FindMiddleEdges(const TopoDS_Vertex&  theVertex1,
                                        const TopoDS_Vertex&  theVertex2,
                                        const gp_Ax1&         theAxis,
                                        TopoDS_Compound&      theComp,
                                        TopTools_ListOfShape& theElist)
{
  TopTools_IndexedDataMapOfShapeListOfShape VEmap;
  TopExp::MapShapesAndAncestors(theComp, TopAbs_VERTEX, TopAbs_EDGE, VEmap);
  if (VEmap.IsEmpty())
    return Standard_False;

  if (!VEmap.Contains(theVertex1) || !VEmap.Contains(theVertex2))
    return Standard_False;

  TopoDS_Vertex CurVertex = theVertex1;
  for (;;)
  {
    TopoDS_Edge CurEdge;

    CurEdge = FindEdgeCloseToBisectorPlane(CurVertex, theComp, theAxis);
    if (CurEdge.IsNull())
      return Standard_False;

    TopoDS_Vertex V1, V2;
    TopExp::Vertices(CurEdge, V1, V2);
    CurVertex = (V1.IsSame(CurVertex)) ? V2 : V1;

    theElist.Append(CurEdge);
    if (CurVertex.IsSame(theVertex2))
      return Standard_True;
  }
}

static Standard_Boolean FindCommonVertex(const TopoDS_Edge&   theFirstEdge,
                                         const TopoDS_Edge&   theLastEdge,
                                         const TopoDS_Vertex& theFirstVertex,
                                         const TopoDS_Vertex& theLastVertex,
                                         TopoDS_Vertex&       theCommonVertex)
{
  if (!theFirstVertex.IsSame(theLastVertex))
  {
    Standard_Boolean CommonVertexExists =
      TopExp::CommonVertex(theFirstEdge, theLastEdge, theCommonVertex);
    return CommonVertexExists;
  }

  TopoDS_Vertex V1, V2, V3, V4;
  TopExp::Vertices(theFirstEdge, V1, V2);
  TopExp::Vertices(theLastEdge, V3, V4);

  if (V1.IsSame(theFirstVertex))
  {
    if (V2.IsSame(V3) || V2.IsSame(V4))
    {
      theCommonVertex = V2;
      return Standard_True;
    }
  }
  else
  {
    if (V1.IsSame(V3) || V1.IsSame(V4))
    {
      theCommonVertex = V1;
      return Standard_True;
    }
  }

  return Standard_False;
}
