// File:        BRepBuilderAPI_Sewing.cxx
// Created:        Fri Mar 24 09:45:44 1995
// Author:        Jing Cheng MEI
//                <mei@junon>
// dcl          CCI60011 : Correction of degeneratedSection
//              Improvement of SameParameter Edge to treat case of failure in BRepLib::SameParameter
// dcl          Thu Aug 20 09:24:49 1998
//              Suppression of little faces.
// dcl          Fri Aug  7 15:27:46 1998
//                Refection of function SameParameter Edge.
//              Merge on the edge which has the less of poles.
//              Suppression of the Connected Edge function.
// dcl          Tue Jun  9 14:21:53 1998
//              Do not merge edge if they belong the same face
//              Tolerance management in VerticesAssembling
//              Tolerance management in Cutting
// dcl          Thu May 14 15:51:46 1998
//              optimization of cutting
// dcl          Thu May 7  15:51:46 1998
//              Add of cutting option
//              Add of SameParameter call


//-- lbr le 1er avril 97
//-- dpf le 10 decembre 1997 Traitement des collections de pcurve

//rln 02.02.99 BUC60449 Making compilable on NT in DEB mode 
//rln 02.02.99 BUC60449 Protection against exception on NT

#define TEST 1

#include <BRepBuilderAPI_Sewing.ixx>

#include <Bnd_Box.hxx>
#include <Bnd_Box2d.hxx>
#include <Bnd_HArray1OfBox.hxx>
#include <BndLib_Add2dCurve.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepLib.hxx>
#include <BRepTools_Quilt.hxx>
#include <BSplCLib.hxx>
#include <Extrema_ExtPC.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <GCPnts_UniformAbscissa.hxx>
#include <GCPnts_UniformDeflection.hxx>
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2d_Line.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <Geom2dAdaptor_Curve.hxx>
#include <Geom2dConvert.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <GeomLib.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
//#include <LocalAnalysis_SurfaceContinuity.hxx>
#include <Precision.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <TColgp_Array1OfVec.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_DataMapIteratorOfDataMapOfIntegerListOfInteger.hxx>
#include <TColStd_DataMapOfIntegerListOfInteger.hxx>
#include <TColStd_IndexedMapOfInteger.hxx>
#include <TColStd_ListIteratorOfListOfInteger.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TColStd_SequenceOfReal.hxx>
#include <TopAbs.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopLoc_Location.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shell.hxx>
#include <TopTools_Array1OfShape.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapIteratorOfMapOfShape.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <TopoDS_Compound.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <TColStd_MapIteratorOfMapOfInteger.hxx>
#include <BRepTools.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_OffsetSurface.hxx>
#include <BRep_PointOnCurve.hxx>
#include <BRep_ListOfPointRepresentation.hxx>
#include <BRep_TVertex.hxx>

static void SortBox (const Handle(Bnd_HArray1OfBox) hSetBoxes,
		     const Bnd_Box& aBox,
		     TColStd_ListOfInteger& listIndex)
{
  Standard_Integer i, nbBoxes = hSetBoxes->Length();
  for (i = 1; i <= nbBoxes; i++)
    if (!aBox.IsOut(hSetBoxes->Value(i)))
      listIndex.Append(i);
}

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

Handle(Geom2d_Curve) BRepBuilderAPI_Sewing::SameRange(const Handle(Geom2d_Curve)& CurvePtr,
						const Standard_Real FirstOnCurve,
						const Standard_Real LastOnCurve,
						const Standard_Real RequestedFirst,
						const Standard_Real RequestedLast) const
{
  Handle(Geom2d_Curve) NewCurvePtr;
  try {
    
    GeomLib::SameRange(Precision::PConfusion(),CurvePtr,FirstOnCurve,LastOnCurve,
		       RequestedFirst,RequestedLast,NewCurvePtr);
  }
  catch (Standard_Failure) {
#ifdef DEB
    cout << "Exception in BRepBuilderAPI_Sewing::SameRange: ";
    Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
  }
  return NewCurvePtr;
}

//=======================================================================
//function : WhichFace
//purpose  : Give the face dont ledge est le bord
//=======================================================================

TopoDS_Face BRepBuilderAPI_Sewing::WhichFace(const TopoDS_Edge& theEdg, const Standard_Integer index) const
{
  TopoDS_Shape bound = theEdg;
  if (mySectionBound.IsBound(bound)) bound = mySectionBound(bound);
  if (myBoundFaces.Contains(bound)) {
    Standard_Integer i = 1;
    TopTools_ListIteratorOfListOfShape itf(myBoundFaces.FindFromKey(bound));
    for (; itf.More(); itf.Next(), i++)
      if (i == index) return TopoDS::Face(itf.Value());
  }
  return TopoDS_Face();
}

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

static Standard_Boolean IsClosedShape(const TopoDS_Shape& theshape,
				      const TopoDS_Shape& v1, const TopoDS_Shape& v2)
{
  Standard_Real TotLength = 0.0;
  TopExp_Explorer aexp;
  for (aexp.Init(theshape,TopAbs_EDGE); aexp.More(); aexp.Next()) {
    TopoDS_Edge aedge = TopoDS::Edge(aexp.Current());
    if (aedge.IsNull()) continue;
    TopoDS_Vertex ve1,ve2;
    TopExp::Vertices(aedge,ve1,ve2);
    if (!ve1.IsSame(v1) && !ve1.IsSame(v2)) continue;
    if (BRep_Tool::Degenerated(aedge)) continue;
    Standard_Real first,last;
    Handle(Geom_Curve) c3d = BRep_Tool::Curve(TopoDS::Edge(aedge), first, last);
    if (!c3d.IsNull()) {
      GeomAdaptor_Curve cAdapt(c3d);
      Standard_Real length = GCPnts_AbscissaPoint::Length(cAdapt, first, last);
      TotLength += length;
      if (ve2.IsSame(v1) || ve2.IsSame(v2)) break;
    }
  }
  if (TotLength > 0.0) {
    gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(v1));
    gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(v2));
    return (p1.Distance(p2) < TotLength/(1.2 * PI));
  }
  return Standard_False;
}

//=======================================================================
//function : IsClosedByIsos
//purpose  : 
//=======================================================================
static Standard_Boolean IsClosedByIsos(const Handle(Geom_Surface)& thesurf,
                                       const Handle(Geom2d_Curve)& acrv2d,
                                       const Standard_Real f2d,
                                       const  Standard_Real l2d,
                                       const Standard_Boolean isUIsos) 
{
  Standard_Boolean isClosed = Standard_False;
 
  gp_Pnt2d psurf1 = (acrv2d->IsPeriodic() ? 
                     acrv2d->Value(f2d) :  acrv2d->Value(Max(f2d,acrv2d->FirstParameter())));
  gp_Pnt2d psurf2 = (acrv2d->IsPeriodic() ? 
                     acrv2d->Value(l2d) :  acrv2d->Value(Min(l2d,acrv2d->LastParameter())));
  Handle(Geom_Curve) aCrv1;
  Handle(Geom_Curve) aCrv2;
  if(isUIsos) {
    aCrv1 = thesurf->UIso(psurf1.X());
    aCrv2 = thesurf->UIso(psurf2.X());
  }
  else {
    aCrv1 = thesurf->VIso(psurf1.Y());
    aCrv2 = thesurf->VIso(psurf2.Y());
  }
  gp_Pnt p11,p1m,p12,p21,p2m,p22;
  Standard_Real af1 = aCrv1->FirstParameter();
  Standard_Real al1 = aCrv1->LastParameter();
  Standard_Real af2 = aCrv2->FirstParameter();
  Standard_Real al2 = aCrv2->LastParameter();
  aCrv1->D0(af1,p11);
  aCrv1->D0((af1+al1)*0.5,p1m);
  aCrv1->D0(al1,p12);
  aCrv2->D0(af2,p21);
  aCrv2->D0((af2+al2)*0.5,p2m);
  aCrv2->D0(al2,p22);
  isClosed = (((p11.XYZ() - p12.XYZ()).Modulus() < 
               (p11.XYZ() - p1m.XYZ()).Modulus() - Precision::Confusion()) &&
              ((p21.XYZ() - p22.XYZ()).Modulus() < 
               (p21.XYZ() - p2m.XYZ()).Modulus() - Precision::Confusion())) ;
  return isClosed;
}
//=======================================================================
//function : IsUClosedSurface
//purpose  : 
//=======================================================================

Standard_Boolean BRepBuilderAPI_Sewing::IsUClosedSurface(const Handle(Geom_Surface)& surf,
                                                   const TopoDS_Shape& theEdge,
                                                   const TopLoc_Location& theloc) const
{
  Handle(Geom_Surface) tmpsurf = surf;
  if(tmpsurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) 
    tmpsurf = Handle(Geom_RectangularTrimmedSurface)::DownCast(surf)->BasisSurface();
  else if(tmpsurf->IsKind(STANDARD_TYPE(Geom_OffsetSurface))) 
    tmpsurf = Handle(Geom_OffsetSurface)::DownCast(surf)->BasisSurface();
  else {
    Standard_Boolean isClosed = tmpsurf->IsUClosed();
    if(!isClosed) {
      Standard_Real f2d, l2d;
      Handle(Geom2d_Curve) acrv2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(theEdge), surf,theloc, f2d, l2d);
      if(!acrv2d.IsNull())
        isClosed = IsClosedByIsos(tmpsurf,acrv2d,f2d, l2d,Standard_False );
      
    }
    return isClosed;
  }
  return IsUClosedSurface(tmpsurf,theEdge,theloc);
  //return surf->IsUClosed();
}

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

Standard_Boolean BRepBuilderAPI_Sewing::IsVClosedSurface(const Handle(Geom_Surface)& surf,
                                                   const TopoDS_Shape& theEdge,
                                                   const TopLoc_Location& theloc) const
{
  Handle(Geom_Surface) tmpsurf = surf;
  if(tmpsurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) 
    tmpsurf = Handle(Geom_RectangularTrimmedSurface)::DownCast(surf)->BasisSurface();
  else if(tmpsurf->IsKind(STANDARD_TYPE(Geom_OffsetSurface))) 
    tmpsurf = Handle(Geom_OffsetSurface)::DownCast(surf)->BasisSurface();
  else {
    Standard_Boolean isClosed = tmpsurf->IsVClosed();
    if(!isClosed) {
      Standard_Real f2d, l2d;
      Handle(Geom2d_Curve) acrv2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(theEdge), surf,theloc, f2d, l2d);
      if(!acrv2d.IsNull())
        isClosed = IsClosedByIsos(tmpsurf,acrv2d,f2d, l2d,Standard_True );
    }
    return isClosed;
  }
  return IsVClosedSurface(tmpsurf,theEdge,theloc);
  //return surf->IsVClosed();
}

//=======================================================================
//function : SameParameter
//purpose  : internal use
//=======================================================================

void BRepBuilderAPI_Sewing::SameParameter(const TopoDS_Edge& edge) const
{
  try {
    
    BRepLib::SameParameter(edge);
  }
  catch (Standard_Failure) {
#ifdef DEB
    cout << "Exception in BRepBuilderAPI_Sewing::SameParameter: ";
    Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
  }
}

//=======================================================================
//function : SameParameterEdge
//purpose  : internal use
//           Merge the Sequence Of Section on one edge.
//           This function keep the curve3d,curve2d,range and parametrization
//           from the first section, and report and made sameparameter the
//           pcurves of the other function.
//           This function works when the are not more than two Pcurves
//           on a same face.
//=======================================================================

TopoDS_Edge BRepBuilderAPI_Sewing::SameParameterEdge(const TopoDS_Shape& edge,
					       const TopTools_SequenceOfShape& seqEdges,
					       const TColStd_SequenceOfInteger& seqForward,
					       TopTools_MapOfShape& mapMerged,
					       const Handle(BRepTools_ReShape)& locReShape)
{
  // Retrieve reference section
  TopoDS_Shape aTmpShape = myReShape->Apply(edge); //for porting
  TopoDS_Edge Edge1 = TopoDS::Edge(aTmpShape);
  aTmpShape = locReShape->Apply(Edge1);
  if (locReShape != myReShape) Edge1 = TopoDS::Edge(aTmpShape);
  Standard_Boolean isDone = Standard_False;

  // Create data structures for temporary merged edges
  TopTools_ListOfShape listFaces1;
  TopTools_MapOfShape MergedFaces;

  if (mySewing) {

    // Fill MergedFaces with faces of Edge1
    TopoDS_Shape bnd1 = edge;
    if (mySectionBound.IsBound(bnd1)) bnd1 = mySectionBound(bnd1);
    if (myBoundFaces.Contains(bnd1)) {
      TopTools_ListIteratorOfListOfShape itf(myBoundFaces.FindFromKey(bnd1));
      for (; itf.More(); itf.Next())
	if (MergedFaces.Add(itf.Value()))
	  listFaces1.Append(itf.Value());
    }
  }
  else {

    // Create presentation edge
    TopoDS_Vertex V1, V2;
    TopExp::Vertices(Edge1,V1,V2);
    if (myVertexNode.Contains(V1)) V1 = TopoDS::Vertex(myVertexNode.FindFromKey(V1));
    if (myVertexNode.Contains(V2)) V2 = TopoDS::Vertex(myVertexNode.FindFromKey(V2));

    TopoDS_Edge NewEdge = Edge1;
    NewEdge.EmptyCopy();

    // Add the vertices
    BRep_Builder aBuilder;
    TopoDS_Shape anEdge = NewEdge.Oriented(TopAbs_FORWARD);
    aBuilder.Add(anEdge,V1.Oriented(TopAbs_FORWARD));
    aBuilder.Add(anEdge,V2.Oriented(TopAbs_REVERSED));

    Edge1 = NewEdge;
  }

  Standard_Boolean isForward = Standard_True;

  // Merge candidate sections
  for (Standard_Integer i = 1; i <= seqEdges.Length(); i++) {

    // Retrieve candidate section
    TopoDS_Shape oedge2 = seqEdges(i);

    if (mySewing) {

      aTmpShape = myReShape->Apply(oedge2); //for porting
      TopoDS_Edge Edge2 = TopoDS::Edge(aTmpShape);
      aTmpShape = locReShape->Apply(Edge2);
      if (locReShape != myReShape) Edge2 = TopoDS::Edge(aTmpShape);

      // Calculate relative orientation
      Standard_Integer Orientation = seqForward(i);
      if (!isForward) Orientation = (Orientation? 0 : 1);

      // Retrieve faces information for the second edge
      TopoDS_Shape bnd2 = oedge2;
      if (mySectionBound.IsBound(bnd2)) bnd2 = mySectionBound(bnd2);
      if (!myBoundFaces.Contains(bnd2)) continue; // Skip floating edge
      const TopTools_ListOfShape& listFaces2 = myBoundFaces.FindFromKey(bnd2);

      Standard_Integer whichSec = 1; // Indicates on which edge the pCurve has been reported
      TopoDS_Edge NewEdge = SameParameterEdge(Edge1,Edge2,listFaces1,listFaces2,Orientation,whichSec);
      if (NewEdge.IsNull()) continue;

      // Record faces information for the temporary merged edge
      TopTools_ListIteratorOfListOfShape itf(listFaces2);
      for (; itf.More(); itf.Next())
	if (MergedFaces.Add(itf.Value()))
	  listFaces1.Append(itf.Value());

      // Record merged section orientation
      if (!Orientation && whichSec != 1)
	isForward = isForward? Standard_False : Standard_True;
      Edge1 = NewEdge;
    }

    // Append actually merged edge
    mapMerged.Add(oedge2);
    isDone = Standard_True;

    if (!myNonmanifold) break;
  }

  if (isDone) {
    // Change result orientation
    Edge1.Orientation(isForward? TopAbs_FORWARD : TopAbs_REVERSED);
  }
  else Edge1.Nullify();

  return Edge1;
}

//=======================================================================
//function : SameParameterEdge
//purpose  : internal use
//=======================================================================
static Standard_Boolean findNMVertices(const TopoDS_Edge& theEdge,
                                       TopTools_SequenceOfShape& theSeqNMVert,
                                       TColStd_SequenceOfReal& theSeqPars)
{
  TopoDS_Iterator aItV(theEdge,Standard_False);
  for( ; aItV.More(); aItV.Next()) {
    if(aItV.Value().Orientation() == TopAbs_INTERNAL || 
        aItV.Value().Orientation() == TopAbs_EXTERNAL)
    theSeqNMVert.Append(aItV.Value());
  }
  Standard_Integer nbV = theSeqNMVert.Length();
  if(!nbV)
    return Standard_False;
  Standard_Real first, last;
  Handle(Geom_Curve) c3d = BRep_Tool::Curve(theEdge,first, last);
  GeomAdaptor_Curve GAC(c3d);
  Extrema_ExtPC locProj;
  locProj.Initialize(GAC, first, last);
  gp_Pnt pfirst = GAC.Value(first), plast = GAC.Value(last);

  
  for (Standard_Integer i = 1; i <= nbV; i++) {
    TopoDS_Vertex aV = TopoDS::Vertex(theSeqNMVert.Value(i));
    gp_Pnt pt = BRep_Tool::Pnt(aV);
    
    Standard_Real distF = pfirst.Distance(pt);
    Standard_Real distL = plast.Distance(pt);
    Standard_Real apar = (distF > distL ? last : first);
    Standard_Boolean isProjected = Standard_False;
    // Project current point on curve
    locProj.Perform(pt);
    if (locProj.IsDone() && locProj.NbExt() > 0) {
	  Standard_Real distMin = Min(distF,distL);
	  Standard_Integer ind, indMin = 0;
	  for (ind = 1; ind <= locProj.NbExt(); ind++) {
	    Standard_Real dProj = locProj.Value(ind);
	    if (dProj < distMin) { 
          indMin = ind; distMin = dProj; 
        }
      }
      if(indMin) 
        apar = locProj.Point(indMin).Parameter();
         
      theSeqPars.Append(apar);  
        
    }
  }
  return Standard_True;
}

static Standard_Real ComputeToleranceVertex(Standard_Real dist, Standard_Real Tol1, Standard_Real Tol2)
{
  Standard_Real resTol =0;
  if((dist + Tol1) <= Tol2)
    resTol = Tol2;
  else if((dist + Tol2) <= Tol1)
    resTol = Tol1;
  else 
    resTol =(dist + Tol1 + Tol2)*0.5;
  return resTol;
  
}
TopoDS_Edge BRepBuilderAPI_Sewing::SameParameterEdge(const TopoDS_Edge& edgeFirst,
					       const TopoDS_Edge& edgeLast,
					       const TopTools_ListOfShape& listFacesFirst,
					       const TopTools_ListOfShape& listFacesLast,
					       const Standard_Boolean secForward, 
					       Standard_Integer& whichSec,
					       const Standard_Boolean firstCall)
{
  // Do not process floating edges
  if (!listFacesFirst.Extent() || !listFacesLast.Extent()) return TopoDS_Edge();

  // Sort input edges
  TopoDS_Edge edge1, edge2;
  if (firstCall) {
    // Take the longest edge as first
    Standard_Real f, l;
    Handle(Geom_Curve) c3d1 = BRep_Tool::Curve(TopoDS::Edge(edgeFirst), f, l);
    GeomAdaptor_Curve cAdapt1(c3d1);
    Standard_Real len1 = GCPnts_AbscissaPoint::Length(cAdapt1, f, l);
    Handle(Geom_Curve) c3d2 = BRep_Tool::Curve(TopoDS::Edge(edgeLast), f, l);
    GeomAdaptor_Curve cAdapt2(c3d2);
    Standard_Real len2 = GCPnts_AbscissaPoint::Length(cAdapt2, f, l);
    if (len1 < len2) {
      edge1 = edgeLast;
      edge2 = edgeFirst;
      whichSec = 2;
    }
    else {
      edge1 = edgeFirst;
      edge2 = edgeLast;
      whichSec = 1;
    }
  }
  else {
    if (whichSec == 1) {
      edge1 = edgeLast;
      edge2 = edgeFirst;
      whichSec = 2;
    }
    else {
      edge1 = edgeFirst;
      edge2 = edgeLast;
      whichSec = 1;
    }
  }

  Standard_Real first, last;
  BRep_Tool::Range(edge1, first, last);
  BRep_Builder aBuilder;

  //To keep NM vertices on edge
  TopTools_SequenceOfShape aSeqNMVert;
  TColStd_SequenceOfReal aSeqNMPars;
  findNMVertices(edge1,aSeqNMVert,aSeqNMPars);
  findNMVertices(edge2,aSeqNMVert,aSeqNMPars);

  // Create new edge
  TopoDS_Edge edge;
  aBuilder.MakeEdge(edge);
  edge.Orientation( edge1.Orientation());
 

  // Retrieve edge curve
  TopLoc_Location loc3d;
  Standard_Real first3d, last3d;
  Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge1, loc3d, first3d, last3d);
  if (!loc3d.IsIdentity()) {
    c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
    c3d->Transform(loc3d.Transformation());
  }
  aBuilder.UpdateEdge(edge,c3d,BRep_Tool::Tolerance(edge1));
  aBuilder.Range(edge, first, last);
  aBuilder.SameRange(edge, Standard_False); //Standard_True
  aBuilder.SameParameter(edge, Standard_False);
  // Create and add new vertices
  {
    TopoDS_Vertex V1New, V2New;

    // Retrieve original vertices from edges
    TopoDS_Vertex V11,V12,V21,V22;
    TopExp::Vertices(edge1,V11,V12);
    TopExp::Vertices(edge2,V21,V22);

    //szv: do not reshape here!!!
    //V11 = TopoDS::Vertex(myReShape->Apply(V11));
    //V12 = TopoDS::Vertex(myReShape->Apply(V12));
    //V21 = TopoDS::Vertex(myReShape->Apply(V21));
    //V22 = TopoDS::Vertex(myReShape->Apply(V22));

    gp_Pnt p11 = BRep_Tool::Pnt(V11);
    gp_Pnt p12 = BRep_Tool::Pnt(V12);
    gp_Pnt p21 = BRep_Tool::Pnt(V21); 
    gp_Pnt p22 = BRep_Tool::Pnt(V22);

    // Check if edges are closed
    Standard_Boolean isClosed1 = V11.IsSame(V12);
    Standard_Boolean isClosed2 = V21.IsSame(V22);

    //Standard_Boolean isRev = Standard_False;
    gp_Pnt pfirst;
    Standard_Real Tol1 = 0.;
    if (isClosed1 || isClosed2) {
      // at least one of the edges is closed
      if (isClosed1 && isClosed2) {
	// both edges are closed
	pfirst.SetXYZ(0.5*(p11.XYZ() + p21.XYZ()));
        gp_Vec v1 =  p21.XYZ() - p11.XYZ();
        Standard_Real d1 = v1.Magnitude();
        Tol1 = ComputeToleranceVertex(d1,BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V21));
	//Tol1 = Max(pfirst.Distance(p11),pfirst.Distance(p21));
      }
      else if (isClosed1) {
	// only first edge is closed
        gp_XYZ pt =0.5*(p21.XYZ()+ p22.XYZ());
  	    pfirst.SetXYZ(0.5*(p11.XYZ() + pt));
        gp_Vec v1 =  p22.XYZ() - p21.XYZ();
        Standard_Real d1 = v1.Magnitude();
        Tol1= ComputeToleranceVertex(d1,BRep_Tool::Tolerance(V22),BRep_Tool::Tolerance(V21));
        gp_Vec v2 =  p11.XYZ() - pt;
        Standard_Real d2 = v2.Magnitude();
        Tol1= ComputeToleranceVertex(d2,Tol1,BRep_Tool::Tolerance(V11));
	//Tol1 = Max(pfirst.Distance(p21),pfirst.Distance(p22));
	//Tol1 = Max(pfirst.Distance(p11),Tol1);
      }
      else {
	// only second edge is closed
        gp_XYZ pt = 0.5*(p11.XYZ()+ p12.XYZ());
	    pfirst.SetXYZ(0.5*(p21.XYZ() + pt));
        gp_Vec v1 =  p11.XYZ() - p12.XYZ();
        Standard_Real d1 = v1.Magnitude();
        Tol1 = ComputeToleranceVertex(d1,BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V12));
        gp_Vec v2 =  p21.XYZ() - pt;
        Standard_Real d2 = v2.Magnitude();
        Tol1 = ComputeToleranceVertex(d2,Tol1,BRep_Tool::Tolerance(V21));
	//Tol1 = Max(pfirst.Distance(p11),pfirst.Distance(p12));
	//Tol1 = Max(pfirst.Distance(p21),Tol1);
      }
      aBuilder.MakeVertex(V1New,pfirst,Tol1);
      V2New = V1New;
    }
    else {
      // both edges are open
      gp_Pnt plast;
      Standard_Real Tol2 = 0.;
      if (secForward) {
	    pfirst.SetXYZ(0.5*(p11.XYZ() + p21.XYZ()));
	    plast.SetXYZ(0.5*(p12.XYZ() + p22.XYZ()));
        gp_Vec v1 =  p21.XYZ() - p11.XYZ();
        Standard_Real d1 = v1.Magnitude();
        gp_Vec v2 =  p22.XYZ() - p12.XYZ();
        Standard_Real d2 = v2.Magnitude();
        Tol1 = ComputeToleranceVertex(d1,BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V21));
        Tol2 = ComputeToleranceVertex(d2,BRep_Tool::Tolerance(V12),BRep_Tool::Tolerance(V22));

//	Tol1 = Max(Max(pfirst.Distance(p11),pfirst.Distance(p21)),
//		   Max(BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V21)));
//	Tol2 = Max(Max(plast.Distance(p12),plast.Distance(p22)),
//		   Max(BRep_Tool::Tolerance(V12),BRep_Tool::Tolerance(V22)));
      }
      else {
	    pfirst.SetXYZ(0.5*(p11.XYZ() + p22.XYZ()));
	    plast.SetXYZ(0.5*(p12.XYZ() + p21.XYZ()));
        
        gp_Vec v1 =  p22.XYZ() - p11.XYZ();
        Standard_Real d1 = v1.Magnitude();
        gp_Vec v2 =  p21.XYZ() - p12.XYZ();
        Standard_Real d2 = v2.Magnitude();
        Tol1 = ComputeToleranceVertex(d1,BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V22));
        Tol2 = ComputeToleranceVertex(d2,BRep_Tool::Tolerance(V12),BRep_Tool::Tolerance(V21));
//        Tol1 = Max(Max(pfirst.Distance(p11),pfirst.Distance(p22)),
//		   Max(BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V22)));
//	Tol2 = Max(Max(plast.Distance(p12),plast.Distance(p21)),
//		   Max(BRep_Tool::Tolerance(V12),BRep_Tool::Tolerance(V21)));
      }
      //gp_Pnt pcu;
      ///c3d->D0(first3d,pcu);
      //Tol1 = Max(pfirst.Distance(pcu) + Max(BRep_Tool::Tolerance(V11),BRep_Tool::Tolerance(V22));
      aBuilder.MakeVertex(V1New,pfirst,Tol1);
      //c3d->D0(last3d,pcu);
      //Tol2 = plast.Distance(pcu);
      aBuilder.MakeVertex(V2New,plast,Tol2);
    }

    // Add the vertices in the good sense
    TopoDS_Shape anEdge = edge.Oriented(TopAbs_FORWARD);
    TopoDS_Shape aLocalEdge = V1New.Oriented(TopAbs_FORWARD); //(listNode.First()).Oriented(TopAbs_FORWARD);
    aBuilder.Add(anEdge,aLocalEdge);
    aLocalEdge = V2New.Oriented(TopAbs_REVERSED); //(listNode.Last()).Oriented(TopAbs_REVERSED);
    aBuilder.Add(anEdge,aLocalEdge);

    Standard_Integer k =1;
    for( ; k <= aSeqNMVert.Length(); k++)
      aBuilder.Add(anEdge,aSeqNMVert.Value(k));

  }

  // Retrieve second PCurves
  TopLoc_Location loc2;
  Handle(Geom_Surface) surf2;
  //Handle(Geom2d_Curve) c2d2, c2d21;
  //  Standard_Real firstOld, lastOld;

  TopTools_ListIteratorOfListOfShape itf2;
  if (whichSec == 1) itf2.Initialize(listFacesLast);
  else               itf2.Initialize(listFacesFirst);
  Standard_Boolean isResEdge = Standard_False;
  for (; itf2.More(); itf2.Next()) {
    Handle(Geom2d_Curve) c2d2, c2d21;
    Standard_Real firstOld, lastOld;
    const TopoDS_Face& fac2 = TopoDS::Face(itf2.Value());

    surf2 = BRep_Tool::Surface(fac2, loc2);
    Standard_Boolean isSeam2 = ((IsUClosedSurface(surf2,edge2,loc2) || IsVClosedSurface(surf2,edge2,loc2)) &&
				BRep_Tool::IsClosed(TopoDS::Edge(edge2),fac2));
    if (isSeam2) {
      if (!myNonmanifold) return TopoDS_Edge();
      TopoDS_Shape aTmpShape = edge2.Reversed(); //for porting
      c2d21 = BRep_Tool::CurveOnSurface(TopoDS::Edge(aTmpShape), fac2, firstOld, lastOld);
    }
    c2d2 = BRep_Tool::CurveOnSurface(edge2, fac2, firstOld, lastOld);
    if (c2d2.IsNull() && c2d21.IsNull()) continue;

    if (!c2d21.IsNull()) {
      c2d21 = Handle(Geom2d_Curve)::DownCast(c2d21->Copy());
      if (!secForward) {
	if (c2d21->IsKind(STANDARD_TYPE(Geom2d_Line)))
	  c2d21 = new Geom2d_TrimmedCurve(c2d21, firstOld, lastOld);
	Standard_Real first2d = firstOld; //c2dTmp->FirstParameter(); BUG USA60321
	Standard_Real last2d = lastOld;   //c2dTmp->LastParameter();
	firstOld = c2d21->ReversedParameter(last2d);
	lastOld = c2d21->ReversedParameter(first2d);
	c2d21->Reverse();
      }
      c2d21 = SameRange(c2d21,firstOld,lastOld,first,last);
    }

    // Make second PCurve sameRange with the 3d curve
    c2d2 = Handle(Geom2d_Curve)::DownCast(c2d2->Copy());

    if (!secForward) {
      if (c2d2->IsKind(STANDARD_TYPE(Geom2d_Line)))
	c2d2 = new Geom2d_TrimmedCurve(c2d2, firstOld, lastOld);
      Standard_Real first2d = firstOld; //c2dTmp->FirstParameter(); BUG USA60321
      Standard_Real last2d = lastOld;   //c2dTmp->LastParameter();
      firstOld = c2d2->ReversedParameter(last2d);
      lastOld = c2d2->ReversedParameter(first2d);
      c2d2->Reverse();
    }

    c2d2 = SameRange(c2d2,firstOld,lastOld,first,last);
    if (c2d2.IsNull()) continue;
    
    // Add second PCurve
    Standard_Boolean isSeam = Standard_False;
    TopAbs_Orientation Ori = TopAbs_FORWARD;
    //Handle(Geom2d_Curve) c2d1, c2d11;

    TopTools_ListIteratorOfListOfShape itf1;
    if (whichSec == 1) itf1.Initialize(listFacesFirst);
    else               itf1.Initialize(listFacesLast);
    for (; itf1.More() && !isSeam; itf1.Next()) {
      Handle(Geom2d_Curve) c2d1, c2d11;
      const TopoDS_Face& fac1 = TopoDS::Face(itf1.Value());

      TopLoc_Location loc1;
      Handle(Geom_Surface) surf1 = BRep_Tool::Surface(fac1, loc1);
      Standard_Real first2d, last2d;
      Standard_Boolean isSeam1 = ((IsUClosedSurface(surf1,edge1,loc1) || IsVClosedSurface(surf1,edge1,loc1)) &&
				  BRep_Tool::IsClosed(TopoDS::Edge(edge1),fac1));
      c2d1 = BRep_Tool::CurveOnSurface(edge1, fac1, first2d, last2d);
      Ori = edge1.Orientation();
      if (fac1.Orientation() == TopAbs_REVERSED) 
        Ori = TopAbs::Reverse(Ori);
      
      if (isSeam1) {
	if (!myNonmanifold) return TopoDS_Edge();
        TopoDS_Shape aTmpShape = edge1.Reversed(); //for porting
        c2d11 = BRep_Tool::CurveOnSurface(TopoDS::Edge(aTmpShape), fac1, first2d, last2d);
        //if(fac1.Orientation() == TopAbs_REVERSED) //
        if(Ori == TopAbs_FORWARD)
          aBuilder.UpdateEdge(edge,c2d1,c2d11,fac1,0);
        else
          aBuilder.UpdateEdge(edge,c2d11,c2d1,fac1,0);
      }
      else  aBuilder.UpdateEdge(edge,c2d1,fac1,0);
      
      if (c2d1.IsNull() && c2d11.IsNull()) continue;

      //Ori = edge1.Orientation();
      //if (fac1.Orientation() == TopAbs_REVERSED) TopAbs::Reverse(Ori);

      if (surf2 == surf1) {
	// Merge sections which are on the same face
	if (!loc2.IsDifferent(loc1)) {
	  Standard_Boolean uclosed = IsUClosedSurface(surf2,edge2,loc2);
	  Standard_Boolean vclosed = IsVClosedSurface(surf2,edge2,loc2);
	  if (uclosed || vclosed) {
	    Standard_Real pf = c2d1->FirstParameter();
//	    Standard_Real pl = c2d1->LastParameter();
	    gp_Pnt2d p1n = c2d1->Value(Max(first,pf));
//	    gp_Pnt2d p2n = c2d1->Value(Min(pl,last));
            gp_Pnt2d p21n = c2d2->Value(Max(first,c2d2->FirstParameter()));
            gp_Pnt2d p22n = c2d2->Value(Min(last,c2d2->LastParameter()));
            Standard_Real aDist = Min(p1n.Distance(p21n), p1n.Distance(p22n));
	    Standard_Real U1, U2, V1, V2;
	    surf2->Bounds(U1, U2, V1, V2);
	    isSeam = ((uclosed && aDist > 0.75*(fabs(U2-U1))) ||
		      (vclosed && aDist > 0.75*(fabs(V2-V1))));
            if( !isSeam && BRep_Tool::IsClosed(TopoDS::Edge(edge),fac1)) continue;
	  }
	}
      }
     
      isResEdge = Standard_True;
      if (isSeam) {
        if (Ori == TopAbs_FORWARD)
          aBuilder.UpdateEdge(edge, c2d1, c2d2, surf2, loc2, Precision::Confusion());
        else
          aBuilder.UpdateEdge(edge, c2d2, c2d1, surf2, loc2, Precision::Confusion());
      }
      else if (isSeam2) {
        TopAbs_Orientation InitOri  = edge2.Orientation();
         TopAbs_Orientation SecOri  = edge.Orientation();
        if (fac2.Orientation() == TopAbs_REVERSED) {
          
          InitOri = TopAbs::Reverse(InitOri);
          SecOri = TopAbs::Reverse(SecOri);
        }
        if(!secForward)
          InitOri = TopAbs::Reverse(InitOri);
        
        if (InitOri == TopAbs_FORWARD)
          aBuilder.UpdateEdge(edge, c2d2,c2d21, surf2, loc2, Precision::Confusion());
        else
          aBuilder.UpdateEdge(edge, c2d21,c2d2, surf2, loc2, Precision::Confusion());
      } 
      else {
        aBuilder.UpdateEdge(edge, c2d2, surf2, loc2, Precision::Confusion());
      }
      
    }
  }
  if(isResEdge)
  // Try to make the edge sameparameter
    SameParameter(edge);

  //  Standard_Real tolReached = BRep_Tool::Tolerance(edge);
  //if (!BRep_Tool::SameParameter(edge)) return edge; //gka ????????

  if (firstCall && (!BRep_Tool::SameParameter(edge) || !isResEdge)) {
    Standard_Integer whichSecn = whichSec;
    // Try to merge on the second section
    Standard_Boolean second_ok = Standard_True;
    TopoDS_Edge s_edge = SameParameterEdge(edgeFirst,edgeLast,listFacesFirst,listFacesLast,
					   secForward,whichSecn,Standard_False);
    //if (s_edge.IsNull()) return s_edge; // gka version for free edges
    if (s_edge.IsNull()) second_ok = Standard_False;
    else if (!BRep_Tool::SameParameter(s_edge)) second_ok = Standard_False;
    else {
      edge = s_edge;
      whichSec = whichSecn;
    }

    if (!second_ok) {

      GeomAdaptor_Curve c3dAdapt(c3d);

      // Discretize edge curve
      Standard_Integer i, j, nbp = 15;
      Standard_Real deltaT = (last3d - first3d) / (nbp + 1);
      TColgp_Array1OfPnt c3dpnt(1,nbp);
      for (i = 1; i <= nbp; i++) c3dpnt(i) = c3dAdapt.Value(first3d + i*deltaT);

      Standard_Real u, v, dist, maxTol = -1.0;
      Standard_Boolean more = Standard_True;

      for (j = 1; more; j++) {
        Handle(Geom2d_Curve) c2d2;
	BRep_Tool::CurveOnSurface(edge, c2d2, surf2, loc2, first, last, j);
	more = !c2d2.IsNull();
	if (more) {

	  deltaT = (last - first) / (nbp + 1);
	  for (i = 1; i <= nbp; i++) {
	    c2d2->Value(first + i*deltaT).Coord(u,v);
	    dist = surf2->Value(u,v).Distance(c3dpnt(i));
	    if (dist > maxTol) maxTol = dist;
	  }
	}
      }

      if (maxTol >= 0.) aBuilder.UpdateEdge(edge, maxTol);
      aBuilder.SameParameter(edge,Standard_True);
    }
  }

  BRepLib::EncodeRegularity(edge,0.01);
  Standard_Real tolEdge1 = BRep_Tool::Tolerance(edge);
  if (tolEdge1 > MaxTolerance()) edge.Nullify();
  return edge;
}

//=======================================================================
// function : EvaluateAngulars
// purpose  : internal use
//=======================================================================

void BRepBuilderAPI_Sewing::EvaluateAngulars(TopTools_SequenceOfShape& sequenceSec,
				       TColStd_Array1OfBoolean& secForward,
				       TColStd_Array1OfReal& tabAng,
				       const Standard_Integer indRef) const
{
  tabAng.Init(-1.0);

  Standard_Integer i, j, npt = 4, lengSec = sequenceSec.Length();

  TopoDS_Edge edge;
  TopoDS_Face face;
  TopLoc_Location loc;
  Standard_Real first, last;
  Handle(Geom_Curve) c3d;
  Handle(Geom2d_Curve) c2d;
  Handle(Geom_Surface) surf;
  TColgp_Array1OfVec normRef(1,npt);

  for (i = indRef; i <= lengSec; i++) {

    edge = TopoDS::Edge(sequenceSec(i));

    TopoDS_Shape bnd = edge;
    if (mySectionBound.IsBound(bnd)) bnd = mySectionBound(bnd);
    if (myBoundFaces.Contains(bnd)) {
      face = TopoDS::Face(myBoundFaces.FindFromKey(bnd).First());
      surf = BRep_Tool::Surface(face,loc);
      if (!loc.IsIdentity()) {
	surf = Handle(Geom_Surface)::DownCast(surf->Copy());
	surf->Transform(loc.Transformation());
      }
      c2d = BRep_Tool::CurveOnSurface(edge, face, first, last);
    }
    else if (i == indRef) return;
    else continue;

    c3d = BRep_Tool::Curve(edge, loc, first, last);
    if (!loc.IsIdentity()) {
      c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
      c3d->Transform(loc.Transformation());
    }

    GeomAdaptor_Curve adapt(c3d);
    GCPnts_UniformAbscissa uniAbs(adapt, npt, first, last);

    Standard_Real cumulateAngular = 0.0;
    Standard_Integer nbComputedAngle = 0;

    for (j = 1; j <= npt; j++) {
      gp_Pnt2d P;
      c2d->D0(uniAbs.Parameter((secForward(i) || i == indRef)? j : npt-j+1),P);
      gp_Vec w1, w2;
      gp_Pnt unused;
      surf->D1(P.X(), P.Y(), unused, w1, w2);
      gp_Vec n = w1^w2; // Compute the normal vector
      if (i == indRef) normRef(j) = n;
      else if ((n.Magnitude()>gp::Resolution()) && (normRef(j).Magnitude()>gp::Resolution())) {
	nbComputedAngle++;
	Standard_Real angular = n.Angle(normRef(j));
	if (angular > PI/2.) angular = PI - angular;
	cumulateAngular += angular;
      }
    }

    if (nbComputedAngle)
      tabAng(i) = cumulateAngular/((Standard_Real)nbComputedAngle);
  }
}

//=======================================================================
// function : EvaluateDistances
// purpose  : internal use
// Evaluate distance beetween edges with indice indRef and the following edges in the list
// Remarks (lengSec - indRef) must be >= 1 
//=======================================================================

void BRepBuilderAPI_Sewing::EvaluateDistances(TopTools_SequenceOfShape& sequenceSec,
					TColStd_Array1OfBoolean& secForward,
					TColStd_Array1OfReal& tabDst,
					const Standard_Integer indRef) const
{
  tabDst.Init(-1.0);

  const Standard_Integer npt = 8; // Number of points for curve discretization
  TColgp_Array1OfPnt ptsRef(1, npt), ptsSec(1, npt);

  Standard_Integer i, j, lengSec = sequenceSec.Length();
  TColgp_SequenceOfPnt seqSec;

  Handle(Geom_Curve) c3dRef;
  Standard_Real firstRef=0., lastRef=0.;

  for (i = indRef; i <= lengSec; i++) {

    // reading of the edge (attention for the first one: reference)
    const TopoDS_Edge& sec = TopoDS::Edge(sequenceSec(i));

    TopLoc_Location loc;
    Standard_Real first, last;
    Handle(Geom_Curve) c3d = BRep_Tool::Curve(sec, loc, first, last);
    if (!loc.IsIdentity()) {
      c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
      c3d->Transform(loc.Transformation());
    }

    if (i == indRef) {
      c3dRef = c3d; firstRef = first; lastRef = last;
    }

    Standard_Real dist, distFor = -1.0, distRev = -1.0;

    Standard_Real T, deltaT = (last - first) / (npt - 1);
    for (j = 1; j <= npt; j++) {

      // Uniform parameter on curve
      if (j == 1) T = first;
      else if (j == npt) T = last;
      else T = first + (j - 1) * deltaT;

      // Take point on curve
      gp_Pnt pt = c3d->Value(T);

      if (i == indRef) {
	ptsRef(j) = pt;
      }
      else {
	ptsSec(j) = pt;
	// To evaluate mutual orientation and distance
	dist = pt.Distance(ptsRef(j));
	if (distFor < dist) distFor = dist;
	dist = pt.Distance(ptsRef(npt-j+1));
	if (distRev < dist) distRev = dist;
      }
    }

    // Record mutual orientation
    Standard_Boolean isForward = (distFor < distRev); //szv debug: <=
    secForward(i) = isForward;

    dist = (isForward? distFor : distRev);
    if (dist < /*Precision::Confusion()*/ myTolerance) {
      // Section is close - record distance
      tabDst(i) = dist;
    }
    else {
      // Section is distant - record points
      for (j = 1; j <= npt; j++) seqSec.Append(ptsSec(j));
    }
  }

  // Project distant points
  Standard_Integer nbFailed = seqSec.Length();
  if (!nbFailed) return;

  TColgp_Array1OfPnt arrPnt(1, nbFailed), arrProj(1, nbFailed);
  for (i = 1; i <= nbFailed; i++) arrPnt(i) = seqSec(i); seqSec.Clear();
  TColStd_Array1OfReal arrDist(1, nbFailed), arrPara(1, nbFailed);

  ProjectPointsOnCurve(arrPnt,c3dRef,firstRef,lastRef,arrDist,arrPara,arrProj);

  // Process distant sections
  Standard_Integer idx1 = 1;
  for (i = indRef + 1; i <= lengSec; i++) {

    // Skip section if already evaluated
    if (tabDst(i) >= 0.0) continue;

    Standard_Real dist, distMax = -1.0;

    Standard_Integer idx2 = (idx1 - 1)*npt;

    for (j = 1; j <= npt; j++) {

      dist = arrDist(idx2 + j);
      // If point is not projected - stop evaluation
      if (dist < 0.0) { distMax = -1.0; break; }
      if (distMax < dist) distMax = dist;
    }

    // If section is close - record distance
    if (distMax >= 0.0) {
      if (secForward(i)) {
	dist = arrPnt(idx2+1).Distance(ptsRef(1));
	if (distMax < dist) distMax = dist;
	dist = arrPnt(idx2+npt).Distance(ptsRef(npt));
	if (distMax < dist) distMax = dist;
      }
      else {
	dist = arrPnt(idx2+1).Distance(ptsRef(npt));
	if (distMax < dist) distMax = dist;
	dist = arrPnt(idx2+npt).Distance(ptsRef(1));
	if (distMax < dist) distMax = dist;
      }

      if (distMax < myTolerance) tabDst(i) = distMax;
    }

    idx1++; // To the next distant curve
  }
}

//=======================================================================
//function : IsMergedClosed
//purpose  :  internal use
//=======================================================================

Standard_Boolean BRepBuilderAPI_Sewing::IsMergedClosed(const TopoDS_Edge& Edge1,
						 const TopoDS_Edge& Edge2,
						 const TopoDS_Face& face) const
{
  // Check for closed surface
  TopLoc_Location loc;
  Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc);
  Standard_Boolean isUClosed = IsUClosedSurface(surf,Edge1,loc);
  Standard_Boolean isVClosed = IsVClosedSurface(surf,Edge1,loc);
  if (!isUClosed && !isVClosed) return Standard_False;
  // Check condition on closed surface
  /*
  Standard_Real first1,last1,first2,last2;
  Handle(Geom_Curve) C3d1 = BRep_Tool::Curve(Edge1,first1,last1);
  Handle(Geom_Curve) C3d2 = BRep_Tool::Curve(Edge2,first2,last2);
  if (C3d1.IsNull() || C3d2.IsNull()) return Standard_False;
  */
  Standard_Real first2d1,last2d1,first2d2,last2d2;
  Handle(Geom2d_Curve) C2d1 = BRep_Tool::CurveOnSurface(Edge1,face,first2d1,last2d1);
  Handle(Geom2d_Curve) C2d2 = BRep_Tool::CurveOnSurface(Edge2,face,first2d2,last2d2);
  if (C2d1.IsNull() || C2d2.IsNull()) return Standard_False;
  /*
  gp_Pnt p1 = C3d1->Value(0.5*(first1 + last1));
  gp_Pnt p2 = C3d1->Value(0.5*(first2 + last2));
  Standard_Real dist = p1.Distance(p2);
  gp_Pnt2d p12d = C2d1->Value(0.5*(first2d1 + last2d1));
  gp_Pnt2d p22d = C2d1->Value(0.5*(first2d2 + last2d2));
  Standard_Real dist2d = p12d.Distance(p22d);
  GeomAdaptor_Surface Ads(BRep_Tool::Surface(face));
  Standard_Real distSurf = Max(Ads.UResolution(dist), Ads.VResolution(dist));
  return (dist2d*0.2 >= distSurf);
  */
  Standard_Integer isULongC1, isULongC2, isVLongC1, isVLongC2;
  Standard_Real SUmin, SUmax, SVmin, SVmax;
  Standard_Real C1Umin, C1Vmin, C1Umax, C1Vmax;
  Standard_Real C2Umin, C2Vmin, C2Umax, C2Vmax;
  { //szv: Use brackets to destroy local variables
    Bnd_Box2d B1, B2;
    Geom2dAdaptor_Curve aC2d1(C2d1), aC2d2(C2d2);
    BndLib_Add2dCurve::Add(aC2d1,first2d1,last2d1,Precision::PConfusion(),B1);
    BndLib_Add2dCurve::Add(aC2d2,first2d2,last2d2,Precision::PConfusion(),B2);
    B1.Get(C1Umin,C1Vmin,C1Umax,C1Vmax);
    B2.Get(C2Umin,C2Vmin,C2Umax,C2Vmax);
    Standard_Real du, dv;
    du = (C1Umax - C1Umin); dv = (C1Vmax - C1Vmin);
    isULongC1 = (dv <= du); isVLongC1 = (du <= dv);
    du = (C2Umax - C2Umin); dv = (C2Vmax - C2Vmin);
    isULongC2 = (dv <= du); isVLongC2 = (du <= dv);
    surf->Bounds(SUmin,SUmax,SVmin,SVmax);
  }
  if (isUClosed && isVLongC1 && isVLongC2) {
    // Do not merge if not overlapped by V
    Standard_Real dist = Max((C2Vmin - C1Vmax),(C1Vmin - C2Vmax));
    if (dist < 0.0) {
      Standard_Real distInner = Max((C2Umin - C1Umax),(C1Umin - C2Umax));
      Standard_Real distOuter = (SUmax - SUmin) - Max((C2Umax - C1Umin),(C1Umax - C2Umin));
      if (distOuter <= distInner) return Standard_True;
    }
  }
  if (isVClosed && isULongC1 && isULongC2) {
    // Do not merge if not overlapped by U
    Standard_Real dist = Max((C2Umin - C1Umax),(C1Umin - C2Umax));
    if (dist < 0.0) {
      Standard_Real distInner = Max((C2Vmin - C1Vmax),(C1Vmin - C2Vmax));
      Standard_Real distOuter = (SVmax - SVmin) - Max((C2Vmax - C1Vmin),(C1Vmax - C2Vmin));
      if (distOuter <= distInner) return Standard_True;
    }
  }
  return Standard_False;
}

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

void BRepBuilderAPI_Sewing::AnalysisNearestEdges(const TopTools_SequenceOfShape& sequenceSec,
                                           TColStd_SequenceOfInteger& seqIndCandidate,
                                           TColStd_SequenceOfInteger& seqOrientations,
                                           const Standard_Boolean evalDist)
{
  
  Standard_Integer workIndex = seqIndCandidate.First();
  TopoDS_Shape workedge = sequenceSec.Value(workIndex);
  TopoDS_Shape bnd = workedge;
  TopTools_ListOfShape workfaces;
  if (mySectionBound.IsBound(bnd)) bnd = mySectionBound(bnd);
  if (myBoundFaces.Contains(bnd)) 
    workfaces = myBoundFaces.FindFromKey(bnd);
  if(workfaces.IsEmpty()) return;
  TopTools_MapOfShape mapFaces;
  TopTools_ListIteratorOfListOfShape lIt;
  for (lIt.Initialize(workfaces); lIt.More(); lIt.Next())
    mapFaces.Add(lIt.Value());
  TColStd_SequenceOfInteger seqNotCandidate;
  TColStd_SequenceOfInteger seqNewForward;
  // Separates edges belonging the same face as work edge 
  // for exception of edges belonging closed faces 
  
  seqNotCandidate.Append(workIndex);
  for(Standard_Integer i = 1; i<= seqIndCandidate.Length(); ) {
    Standard_Integer index = seqIndCandidate.Value(i);
    Standard_Boolean isRemove = Standard_False;
    if(index == workIndex) {
      seqIndCandidate.Remove(i);
      seqOrientations.Remove(i);
      isRemove = Standard_True;
    }
    if(!isRemove) {
      TopoDS_Shape bnd2 = sequenceSec.Value(index);
      if (mySectionBound.IsBound(bnd2)) bnd2 = mySectionBound(bnd2);
    
      if(myBoundFaces.Contains(bnd2)) {
        const TopTools_ListOfShape& listfaces = myBoundFaces.FindFromKey(bnd2);
        Standard_Boolean isMerged = Standard_True;
        for (lIt.Initialize(listfaces); lIt.More() && isMerged; lIt.Next()) {
          if(mapFaces.Contains(lIt.Value())) {
            TopLoc_Location loc;
            Handle(Geom_Surface) surf = BRep_Tool::Surface(TopoDS::Face(lIt.Value()),loc);
            isMerged = ((IsUClosedSurface(surf,bnd2,loc) ||  IsVClosedSurface(surf,bnd2,loc)) && 
                        IsMergedClosed(TopoDS::Edge(sequenceSec.Value(index)),TopoDS::Edge(workedge),TopoDS::Face(lIt.Value())));
          }
        }
        if(!isMerged) {
          seqNotCandidate.Append(index);
          seqIndCandidate.Remove(i);
          seqOrientations.Remove(i);
          isRemove = Standard_True;
        }
      }
      else {
        seqIndCandidate.Remove(i);
        seqOrientations.Remove(i);
        isRemove = Standard_True;
      }
    }
    if(!isRemove) i++;  
  }
  if(seqIndCandidate.Length() == 0 || seqNotCandidate.Length() == 1) return;
  if(!evalDist) return;
  TColStd_Array2OfReal TotTabDist(1,seqNotCandidate.Length(),1,seqIndCandidate.Length());
  TColStd_MapOfInteger MapIndex;
  TColStd_SequenceOfInteger seqForward;
  
  // Definition and removing edges wich are not candidate for work edge 
  // ( they have other nearest edges belonging to the work face) 
  for(Standard_Integer k = 1; k<= seqNotCandidate.Length(); k++) {
    Standard_Integer index1 = seqNotCandidate.Value(k);
    TopoDS_Shape edge = sequenceSec.Value(index1);
    TopTools_SequenceOfShape tmpSeq;
    tmpSeq.Append(edge);
    for(Standard_Integer kk = 1; kk <= seqIndCandidate.Length();kk++) 
      tmpSeq.Append(sequenceSec.Value(seqIndCandidate.Value(kk)));
    
    Standard_Integer lengSec = tmpSeq.Length();
    TColStd_Array1OfBoolean tabForward(1,lengSec);
    TColStd_Array1OfReal tabDist(1,lengSec);
    for (Standard_Integer i1 = 1 ; i1 <= lengSec; i1++) 
      tabDist(i1) =-1;
    
    EvaluateDistances(tmpSeq,tabForward, tabDist,1 );
    if(k == 1) {
      for(Standard_Integer n = 1; n < lengSec; n++) {
	if(tabDist(n+1) == -1 || tabDist(n+1) > myTolerance) {
	  MapIndex.Add(n);
	  continue;
	}
	TotTabDist(k,n) = tabDist(n+1 );
	seqForward.Append(tabForward(n+1) ? 1:0);
      }
    }
    else {
      for(Standard_Integer n = 1; n < lengSec; n++) {
	if(tabDist(n) == -1 || tabDist(n) > myTolerance) continue;
	if(tabDist(n+1) < TotTabDist(1,n)) {
	  MapIndex.Add(n);
	}
      }
    }
     
  }
  for(TColStd_MapIteratorOfMapOfInteger IMap(MapIndex); IMap.More(); IMap.Next()) {
    seqIndCandidate.Remove(IMap.Key());
    seqOrientations.Remove(IMap.Key());
  }
}

//=======================================================================
//function : FindCandidates
//purpose  : internal use
//=======================================================================

Standard_Boolean BRepBuilderAPI_Sewing::FindCandidates(TopTools_SequenceOfShape& seqSections,
						 TColStd_IndexedMapOfInteger& mapReference,
						 TColStd_SequenceOfInteger& seqCandidates,
						 TColStd_SequenceOfInteger& seqOrientations)
{
  Standard_Integer i, nbSections = seqSections.Length();

  // Retrieve last reference index
  Standard_Integer indReference = mapReference(mapReference.Extent());
  Standard_Integer nbCandidates = 0;

  if (nbSections > 1) {

    TopoDS_Edge Edge1 = TopoDS::Edge(seqSections(indReference));

    // Retrieve faces for reference section
    TopTools_MapOfShape Faces1;
    { //szv: Use brackets to destroy local variables
      TopoDS_Shape bnd = Edge1;
      if (mySectionBound.IsBound(bnd)) bnd = mySectionBound(bnd);
      if (myBoundFaces.Contains(bnd)) {
	TopTools_ListIteratorOfListOfShape itf1(myBoundFaces.FindFromKey(bnd));
	for (; itf1.More(); itf1.Next()) Faces1.Add(itf1.Value());
      }
    }

    // Check merging conditions for candidates and remove unsatisfactory
    TopTools_SequenceOfShape seqSectionsNew;
    TColStd_SequenceOfInteger seqCandidatesNew;
    for (i = 1; i <= nbSections; i++) {
      if (i == indReference) {
	seqSectionsNew.Prepend(Edge1);
	seqCandidatesNew.Prepend(i);
      }
      else {
	const TopoDS_Edge& Edge2 = TopoDS::Edge(seqSections(i));
	TopoDS_Shape bnd = Edge2;
	if (mySectionBound.IsBound(bnd)) bnd = mySectionBound(bnd);
	if (myBoundFaces.Contains(bnd)) {
	  Standard_Boolean isOK = Standard_True;
	  TopTools_ListIteratorOfListOfShape itf2(myBoundFaces.FindFromKey(bnd));
	  for (; itf2.More() && isOK; itf2.Next()) {
	    const TopoDS_Face& Face2 = TopoDS::Face(itf2.Value());
	    // Check whether condition is satisfied
	    isOK = !Faces1.Contains(Face2);
	    if (!isOK) isOK = IsMergedClosed(Edge1,Edge2,Face2);
	  }
	  if (isOK) {
	    seqSectionsNew.Append(Edge2);
	    seqCandidatesNew.Append(i);
	  }
	}
      }
    }

    Standard_Integer nbSectionsNew = seqSectionsNew.Length();
    if (nbSectionsNew > 1) {

      // Evaluate distances between reference and other sections
      TColStd_Array1OfBoolean arrForward(1,nbSectionsNew);
      TColStd_Array1OfReal arrDistance(1,nbSectionsNew);
      EvaluateDistances(seqSectionsNew,arrForward,arrDistance,1);

      // Fill sequence of candidate indices sorted by distance
      for (i = 2; i <= nbSectionsNew; i++) {
	if (arrDistance(i) >= 0.0) {
	  // Reference section is connected to section #i
	  Standard_Boolean isInserted = Standard_False;
	  Standard_Integer j, ori = (arrForward(i)? 1 : 0);
	  for (j = 1; (j <= seqCandidates.Length()) && !isInserted; j++) {
	    if (arrDistance(i) <= arrDistance(seqCandidates.Value(j))) {
	      seqCandidates.InsertBefore(j,i);
	      seqOrientations.InsertBefore(j,ori);
	      isInserted = Standard_True;
	    }
	  }
	  if (!isInserted) {
	    seqCandidates.Append(i);
	    seqOrientations.Append(ori);
	  }
	}
      }

      // Replace candidate indices
      nbCandidates = seqCandidates.Length();
      for (i = 1; i <= nbCandidates; i++)
	seqCandidates(i) = seqCandidatesNew(seqCandidates(i));
    }
  }

  if (!nbCandidates) return Standard_False; // Section has no candidates to merge

  if (myNonmanifold && nbCandidates >1) {
    TColStd_SequenceOfInteger seqNewCandidates;
    TColStd_SequenceOfInteger seqOrientationsNew;
    seqCandidates.Prepend(1);
    seqOrientations.Prepend(1);
    for(Standard_Integer k = 1; k <= seqSections.Length() && seqCandidates.Length() > 1 ; k++) {
      AnalysisNearestEdges(seqSections,seqCandidates,seqOrientations,(k==1));
      if(k == 1 && !seqCandidates.Length()) return Standard_False;
      if(seqCandidates.Length()) {
        seqNewCandidates.Append(seqCandidates.First());
        seqOrientationsNew.Append(seqOrientations.First()); 
      }
    }
    seqCandidates.Prepend(seqNewCandidates);
    seqOrientations.Prepend(seqOrientationsNew);
    return Standard_True;
  }
  else {

    // For manifold case leave only one candidate from equidistant candidates
    /*Standard_Integer minIndex = seqCandidateIndex.First();
    Standard_Real minDistance = arrDistance(minIndex);

    // Find equidistant candidates
    TColStd_SequenceOfInteger seqEqDistantIndex; seqEqDistantIndex.Append(1);
    for (i = 2; i <= nbCandidates; i++) {
      Standard_Integer index = seqCandidateIndex(i);
      if (Abs(minDistance - arrDistance(index)) <= Precision::Confusion())
	seqEqDistantIndex.Append(index);
    }

    Standard_Integer eqLen = seqEqDistantIndex.Length();
    if (eqLen > 2) {

      // Fill map of faces which equidistant sections belong to
      TopTools_MapOfShape mapFace;
      for (i = 1; i <= eqLen; i++) {
	Standard_Integer index = seqEqDistantIndex.Value(i);
	if (isCandidate(index)) {
	  mapFace.Add(arrFace(index));
	}
      }

      // Non Manifold case
      // Edges are merged by pair among a face continuity C1 criterion
      if (mapFace.Extent() == eqLen) {

	tabDist.Init(-1);
	tabMinInd.Init(-1);
	min=10000000.;
	//indMin = -1;
	Standard_Integer indMin = -1;// To check if the edge can be merged.
	// Computation of distances between the edges.
	TopTools_SequenceOfShape seqSh;
	Standard_Integer nbInd = EqDistSeq.Length();
	TColStd_Array1OfBoolean tmptabForward(1,nbInd);
	seqSh.Append(sequenceSec.Value(1));
	for (j = 2; j <= EqDistSeq.Length(); j++) {
	  Standard_Integer index = EqDistSeq.Value(j);
	  tmptabForward(j) = tabForward(index);
	  seqSh.Append(sequenceSec.Value(index));
	}

	EvaluateAngulars(seqSh, tmptabForward, tabDist,1);

	for(j=2; j <= seqSh.Length(); j++) {
	  if (tabDist(j) > -1.) {  // if edge(j) is connected to edge(i)
	    if (min > tabDist(j)) {
	      min = tabDist(j);
	      indMin = j;
	    }
	  }
	}

	//  Construct minDist, tabMinInd , tabMinForward(i) = tabForward(j);
	if (indMin > 0) {
	  seqSh.Remove(indMin);
	  for(j =2; j <= tmpSeq.Length(); ) {
	    TopoDS_Shape sh = tmpSeq.Value(j);
	    Standard_Boolean isRem = Standard_False;
	    for(Standard_Integer k = 1; k<= seqSh.Length();k++) {
	      if(seqSh.Value(k) == sh) {
		isRem = Standard_True;
		break;
	      }
	    }
	    if(isRem) {
	      tmpSeq.Remove(j);
	      tabMinForward.Remove(j); // = -1;
	    } 
	    else j++;
	  }
	}
      }
    }*/

    // Find the best approved candidate
    while (nbCandidates) {
      // Retrieve first candidate
      Standard_Integer indCandidate = seqCandidates.First();
      // Candidate is approved if it is in the map
      if (mapReference.Contains(indCandidate)) break;
      // Find candidates for candidate #indCandidate
      mapReference.Add(indCandidate); // Push candidate in the map
      TColStd_SequenceOfInteger seqCandidates1, seqOrientations1;
      Standard_Boolean isFound =
	FindCandidates(seqSections,mapReference,seqCandidates1,seqOrientations1);
      mapReference.RemoveLast(); // Pop candidate from the map
      if (isFound) isFound = (seqCandidates1.Length() > 0);
      if (isFound) {
	Standard_Integer indCandidate1 = seqCandidates1.First();
	// If indReference is the best candidate for indCandidate
	// then indCandidate is the best candidate for indReference
	if (indCandidate1 == indReference) break;
	// If some other reference in the map is the best candidate for indCandidate
	// then assume that reference is the best candidate for indReference
	if (mapReference.Contains(indCandidate1)) {
	  seqCandidates.Prepend(indCandidate1);
	  nbCandidates++;
	  break;
	}
	isFound = Standard_False;
      }
      if (!isFound) {
	// Remove candidate #1
	seqCandidates.Remove(1);
	seqOrientations.Remove(1);
	nbCandidates--;
      }
    }
  }

  return (nbCandidates > 0);
}

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

BRepBuilderAPI_Sewing::BRepBuilderAPI_Sewing(const Standard_Real tolerance,
				 const Standard_Boolean optionSewing,
				 const Standard_Boolean optionAnalysis,
				 const Standard_Boolean optionCutting,
				 const Standard_Boolean optionNonmanifold)
{
  myReShape = new BRepTools_ReShape;
  Init(tolerance, optionSewing, optionAnalysis, optionCutting, optionNonmanifold);
}

//=======================================================================
//function : Init
//purpose  : Initialise Talerance, and options sewing, faceAnalysis and cutting
//=======================================================================

void BRepBuilderAPI_Sewing::Init(const Standard_Real tolerance,
			   const Standard_Boolean optionSewing,
			   const Standard_Boolean optionAnalysis,
			   const Standard_Boolean optionCutting,
			   const Standard_Boolean optionNonmanifold)
{
  // Set tolerance and Perform options
  myTolerance      = tolerance;
  mySewing         = optionSewing;
  myAnalysis       = optionAnalysis;
  myCutting        = optionCutting;
  myNonmanifold    = optionNonmanifold;
  // Set min and max tolerances
  myMinTolerance   = tolerance*1e-4; //szv: proposal
  if (myMinTolerance < Precision::Confusion()) myMinTolerance = Precision::Confusion();
  myMaxTolerance   = Precision::Infinite();
  // Set other modes
  myFaceMode           = Standard_True;
  myFloatingEdgesMode  = Standard_False;
  //myCuttingFloatingEdgesMode = Standard_False; //gka
  mySameParameterMode  = Standard_True;
  myLocalToleranceMode = Standard_False;
  mySewedShape.Nullify();
  // Load empty shape
  Load(TopoDS_Shape());
}

//=======================================================================
//function : Load
//purpose  : Loads the context shape
//=======================================================================

void BRepBuilderAPI_Sewing::Load(const TopoDS_Shape& theShape)
{
  myReShape->Clear();
  if (theShape.IsNull()) myShape.Nullify();
  else myShape = myReShape->Apply(theShape);
  mySewedShape.Nullify();
  // Nullify flags and counters
  myNbShapes = myNbEdges = myNbVertices = 0;
  // Clear all maps
  myOldShapes.Clear();
  //myOldFaces.Clear();
  myDegenerated.Clear();
  myFreeEdges.Clear();
  myMultipleEdges.Clear();
  myContigousEdges.Clear();
  myContigSecBound.Clear();
  myBoundFaces.Clear();
  myBoundSections.Clear();
  myVertexNode.Clear();
  myVertexNodeFree.Clear();
  myNodeSections.Clear();
  myCuttingNode.Clear();
  mySectionBound.Clear();
  myLittleFace.Clear();
}

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

void BRepBuilderAPI_Sewing::Add(const TopoDS_Shape& aShape)
{
  if (aShape.IsNull()) return;
  TopoDS_Shape oShape = myReShape->Apply(aShape);
  myOldShapes.Add(aShape,oShape);
  myNbShapes = myOldShapes.Extent();
}

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

#ifdef DEB
#include <OSD_Timer.hxx>
#endif

void BRepBuilderAPI_Sewing::Perform()
{
#ifdef DEB
  Standard_Real t_total = 0., t_analysis = 0., t_assembling = 0., t_cutting = 0., t_merging = 0.;
  OSD_Chronometer chr_total, chr_local;
  chr_total.Reset();
  chr_total.Start();
#endif

  // face analysis
  if (myAnalysis) {
#if DEB
    cout << "Begin face analysis..." << endl;
    chr_local.Reset();
    chr_local.Start();
#endif
    FaceAnalysis();
#if DEB
    chr_local.Stop();
    chr_local.Show(t_analysis);
    cout << "Face analysis finished after " << t_analysis << " s" << endl;
#endif
  }

  if (myNbShapes || !myShape.IsNull()) {

    FindFreeBoundaries();

    if (myBoundFaces.Extent()) {

#if DEB
      cout << "Begin vertices assembling..." << endl;
      chr_local.Reset();
      chr_local.Start();
#endif
      VerticesAssembling();
#if DEB
      chr_local.Stop();
      chr_local.Show(t_assembling);
      cout << "Vertices assembling finished after " << t_assembling << " s" << endl;
#endif
      if (myCutting) {
#if DEB
	cout << "Begin cutting..." << endl;
	chr_local.Reset();
	chr_local.Start();
#endif
	Cutting();
#if DEB
	chr_local.Stop();
	chr_local.Show(t_cutting);
	cout << "Cutting finished after " << t_cutting << " s" << endl;
#endif
      }
#if DEB
      cout << "Begin merging..." << endl;
      chr_local.Reset();
      chr_local.Start();
#endif
      Merging(Standard_True);
#if DEB
      chr_local.Stop();
      chr_local.Show(t_merging);
      cout << "Merging finished after " << t_merging << " s" << endl;
#endif
    }

    if (mySewing) {

#if DEB
      cout << "Creating sewed shape..." << endl;
#endif
      // examine the multiple edges if any and process sameparameter for edges if necessary
      EdgeProcessing();
      CreateSewedShape();
      if (mySameParameterMode && myFaceMode) SameParameterShape();
#if DEB
      cout << "Sewed shape created" << endl;
#endif
    }
    
    // create edge informations for output
    CreateOutputInformations();
  }
#if DEB
  chr_total.Stop();
  chr_total.Show(t_total);
  cout << "Sewing finished!" << endl;
  cout << " analysis time   : " << t_analysis << " s" << endl;
  cout << " assembling time : " << t_assembling << " s" << endl;
  cout << " cutting time    : " << t_cutting << " s" << endl;
  cout << " merging time    : " << t_merging << " s" << endl;
  cout << "Total time       : " << t_total << " s" << endl;
#endif
}

//=======================================================================
//function : SewedShape
//purpose  : give the sewed shape
//           if a null shape, reasons:
//             -- no useable input shapes : all input shapes are degenerated
//             -- has multiple edges
//=======================================================================

const TopoDS_Shape& BRepBuilderAPI_Sewing::SewedShape() const
{
  return mySewedShape;
}

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

Standard_Integer BRepBuilderAPI_Sewing::NbFreeEdges() const
{
  return myFreeEdges.Extent();
}

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

const TopoDS_Edge& BRepBuilderAPI_Sewing::FreeEdge(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbFreeEdges(), "BRepBuilderAPI_Sewing::FreeEdge");
  return TopoDS::Edge(myFreeEdges(index));
}

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

Standard_Integer BRepBuilderAPI_Sewing::NbMultipleEdges() const
{
  return myMultipleEdges.Extent();
}

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

const TopoDS_Edge& BRepBuilderAPI_Sewing::MultipleEdge(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbMultipleEdges(), "BRepBuilderAPI_Sewing::MultipleEdge");
  return TopoDS::Edge(myMultipleEdges(index));
}

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

Standard_Integer BRepBuilderAPI_Sewing::NbContigousEdges() const
{
  return myContigousEdges.Extent();
}

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

const TopoDS_Edge& BRepBuilderAPI_Sewing::ContigousEdge(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbContigousEdges(), "BRepBuilderAPI_Sewing::ContigousEdge");
  return TopoDS::Edge(myContigousEdges.FindKey(index));
}

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

const TopTools_ListOfShape& BRepBuilderAPI_Sewing::ContigousEdgeCouple(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbContigousEdges(), "BRepBuilderAPI_Sewing::ContigousEdgeCouple");
  return myContigousEdges(index);
}

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

Standard_Boolean BRepBuilderAPI_Sewing::IsSectionBound(const TopoDS_Edge& section) const
{
  if(myContigSecBound.IsBound(section)) {
    return Standard_True;
  }
  else {
    return Standard_False;
  }
}

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

const TopoDS_Edge& BRepBuilderAPI_Sewing::SectionToBoundary(const TopoDS_Edge& section) const
{
  Standard_NoSuchObject_Raise_if(!IsSectionBound(section), "BRepBuilderAPI_Sewing::SectionToBoundary");
  return TopoDS::Edge(myContigSecBound(section));
}
//=======================================================================
//function : NbDeletedFaces
//purpose  : 
//=======================================================================
 Standard_Integer BRepBuilderAPI_Sewing::NbDeletedFaces() const
{
  return myLittleFace.Extent();
}

//=======================================================================
//function : DeletedFace
//purpose  : 
//=======================================================================
const TopoDS_Face& BRepBuilderAPI_Sewing::DeletedFace(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbDeletedFaces(), "BRepBuilderAPI_Sewing::DeletedFace");
  return TopoDS::Face(myLittleFace(index));
}

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

Standard_Integer BRepBuilderAPI_Sewing::NbDegeneratedShapes() const
{
  return myDegenerated.Extent();
}

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

const TopoDS_Shape& BRepBuilderAPI_Sewing::DegeneratedShape(const Standard_Integer index) const
{
  Standard_OutOfRange_Raise_if(index < 0 || index > NbDegeneratedShapes(), "BRepBuilderAPI_Sewing::DegereratedShape");
  return myDegenerated(index);
}

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

Standard_Boolean BRepBuilderAPI_Sewing::IsDegenerated(const TopoDS_Shape& aShape) const
{
  TopoDS_Shape NewShape = myReShape->Apply(aShape);
  // Degenerated face
  if (aShape.ShapeType() == TopAbs_FACE)
    return NewShape.IsNull();
  if (NewShape.IsNull()) return Standard_False;
  // Degenerated edge
  if (NewShape.ShapeType() == TopAbs_EDGE)
    return BRep_Tool::Degenerated(TopoDS::Edge(NewShape));
  // Degenerated wire
  if (NewShape.ShapeType() == TopAbs_WIRE) {
    Standard_Boolean isDegenerated = Standard_True;
    for (TopoDS_Iterator aIt(NewShape); aIt.More() && isDegenerated; aIt.Next())
      isDegenerated = BRep_Tool::Degenerated(TopoDS::Edge(aIt.Value()));
    return isDegenerated;
  }
  return Standard_False;
}
  
//=======================================================================
//function : IsModified
//purpose  : 
//=======================================================================

Standard_Boolean BRepBuilderAPI_Sewing::IsModified(const TopoDS_Shape& aShape) const
{
  TopoDS_Shape NewShape = aShape;
  if (myOldShapes.Contains(aShape)) 
    NewShape = myOldShapes.FindFromKey(aShape);
  if(!NewShape.IsSame(aShape)) return Standard_True;
  return Standard_False;
}

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

const TopoDS_Shape& BRepBuilderAPI_Sewing::Modified(const TopoDS_Shape& aShape) const
{ 
  if (myOldShapes.Contains(aShape)) return myOldShapes.FindFromKey(aShape);
  //if (myOldFaces.Contains(aShape)) return myOldFaces.FindFromKey(aShape);
  return aShape;
}

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

Standard_Boolean BRepBuilderAPI_Sewing::IsModifiedSubShape(const TopoDS_Shape& aShape) const
{
  TopoDS_Shape NewShape = myReShape->Apply(aShape);
  if(!NewShape.IsSame(aShape)) return Standard_True;
  return Standard_False;
}

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

TopoDS_Shape BRepBuilderAPI_Sewing::ModifiedSubShape(const TopoDS_Shape& aShape) const
{ 
  return myReShape->Apply(aShape);
}

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

void BRepBuilderAPI_Sewing::Dump() const
{
  Standard_Integer i, NbBounds = myBoundFaces.Extent(), NbSections = 0;
  TopTools_MapOfShape mapVertices, mapEdges;
  for (i = 1; i <= NbBounds; i++) {
    TopoDS_Shape bound = myBoundFaces.FindKey(i);
    if (myBoundSections.IsBound(bound)) NbSections += myBoundSections(bound).Extent();
    else NbSections++;
    TopExp_Explorer aExp(myReShape->Apply(bound),TopAbs_EDGE);
    for (; aExp.More(); aExp.Next()) {
      TopoDS_Edge E = TopoDS::Edge(aExp.Current());
      mapEdges.Add(E);
      TopoDS_Vertex V1, V2;
      TopExp::Vertices(E,V1,V2);
      mapVertices.Add(V1);
      mapVertices.Add(V2);
    }
  }
  cout << " " << endl;
  cout << "                        Informations                        " << endl;
  cout << " ===========================================================" << endl;
  cout << " " << endl;
  cout << " Number of input shapes      : " << myOldShapes.Extent() << endl;
  cout << " Number of actual shapes     : " << myNbShapes << endl;
  cout << " Number of Bounds            : " << NbBounds << endl;
  cout << " Number of Sections          : " << NbSections << endl;
  cout << " Number of Edges             : " << mapEdges.Extent() << endl;
  cout << " Number of Vertices          : " << myNbVertices << endl;
  cout << " Number of Nodes             : " << mapVertices.Extent() << endl;
  cout << " Number of Free Edges        : " << myFreeEdges.Extent() << endl;
  cout << " Number of Contigous Edges   : " << myContigousEdges.Extent() << endl;
  cout << " Number of Multiple Edges    : " << myMultipleEdges.Extent() << endl;
  cout << " Number of Degenerated Edges : " << myDegenerated.Extent() << endl;
  cout << " ===========================================================" << endl;
  cout << " " << endl;
}

//=======================================================================
//function : FaceAnalysis
//purpose  : Remove
//	     Modifies:
//                      myNbShapes
//                      myOldShapes
//
//           Constructs:
//                      myDegenerated
//=======================================================================

void BRepBuilderAPI_Sewing::FaceAnalysis()
{
  if (!myShape.IsNull() && myOldShapes.IsEmpty()) {
    Add(myShape);
    myShape.Nullify();
  }

  BRep_Builder B;
  TopTools_MapOfShape SmallEdges;
  TopTools_DataMapOfShapeListOfShape GluedVertices;
  Standard_Integer i = 1;
  for (i = 1; i <= myOldShapes.Extent(); i++) {
    for (TopExp_Explorer fexp(myOldShapes(i),TopAbs_FACE); fexp.More(); fexp.Next()) {

      // Retrieve current face
      TopoDS_Shape aTmpShape = fexp.Current(); //for porting
      TopoDS_Face face = TopoDS::Face(aTmpShape);
      Standard_Integer nbEdges = 0, nbSmall = 0;

      // Build replacing face
      aTmpShape = face.EmptyCopied().Oriented(TopAbs_FORWARD); //for porting
      TopoDS_Face nface = TopoDS::Face(aTmpShape);
      Standard_Boolean isFaceChanged = Standard_False;

      TopoDS_Iterator witer(face.Oriented(TopAbs_FORWARD));
      for (; witer.More(); witer.Next()) {

	// Retrieve current wire
        aTmpShape = witer.Value(); //for porting
        if( aTmpShape.ShapeType() != TopAbs_WIRE) continue;
	TopoDS_Wire wire = TopoDS::Wire(aTmpShape);

	// Build replacing wire
        aTmpShape = wire.EmptyCopied().Oriented(TopAbs_FORWARD);
	TopoDS_Wire nwire = TopoDS::Wire(aTmpShape);
	Standard_Boolean isWireChanged = Standard_False;

	TopoDS_Iterator eiter(wire.Oriented(TopAbs_FORWARD));
	for (; eiter.More(); eiter.Next()) {

	  // Retrieve current edge
          aTmpShape = eiter.Value(); //for porting
	  TopoDS_Edge edge = TopoDS::Edge(aTmpShape);
	  nbEdges++;

	  // Process degenerated edge
	  if (BRep_Tool::Degenerated(edge)) {
	    B.Add(nwire,edge); // Old edge kept
	    myDegenerated.Add(edge);
	    nbSmall++;
	    continue;
	  }

	  Standard_Boolean isSmall = SmallEdges.Contains(edge);
	  if (!isSmall) {

	    // Check for small edge
	    Standard_Real first, last;
	    Handle(Geom_Curve) c3d = BRep_Tool::Curve(edge,first,last);
	    if (c3d.IsNull()) {
#ifdef DEB
	      cout << "Warning: Possibly small edge can be sewed: No 3D curve" << endl;
#endif
	    }
	    else {
	      // Evaluate curve compactness
	      const Standard_Integer npt = 5;
	      gp_Pnt cp((c3d->Value(first).XYZ()+c3d->Value(last).XYZ())*0.5);
	      Standard_Real dist, maxdist = 0.0;
	      Standard_Real delta = (last - first)/(npt - 1);
	      for (Standard_Integer idx = 0; idx < npt; idx++) {
		dist = cp.Distance(c3d->Value(first + idx*delta));
		if (maxdist < dist) maxdist = dist;
	      }
	      isSmall = (2.*maxdist <= MinTolerance());
	      /*try {
		GeomAdaptor_Curve cAdapt(c3d);
		Standard_Real length = GCPnts_AbscissaPoint::Length(cAdapt,first,last);
		isSmall = (length <= MinTolerance());
	      }
	      catch (Standard_Failure) {
#ifdef DEB
		cout << "Warning: Possibly small edge can be sewed: ";
		Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
	      }*/
	    }

	    if (isSmall) {

	      // Store small edge in the map
	      SmallEdges.Add(edge);

	      TopoDS_Vertex v1, v2;
	      TopExp::Vertices(edge,v1,v2);
	      TopoDS_Shape nv1 = myReShape->Apply(v1), nv2 = myReShape->Apply(v2);

	      // Store glued vertices
	      if (!nv1.IsSame(v1)) {
		TopTools_ListOfShape& vlist1 = GluedVertices(nv1);
		// First vertex was already glued
		if (!nv2.IsSame(v2)) {
		  // Merge lists of glued vertices
		  if (!nv1.IsSame(nv2)) {
		    TopTools_ListIteratorOfListOfShape liter(GluedVertices(nv2));
		    for (; liter.More(); liter.Next()) {
		      TopoDS_Shape v = liter.Value();
		      myReShape->Replace(v,nv1.Oriented(v.Orientation()));
		      vlist1.Append(v);
		    }
		    GluedVertices.UnBind(nv2);
		  }
		}
		else {
		  // Add second vertex to the existing list
		  vlist1.Append(v2);
		  myReShape->Replace(v2,nv1.Oriented(v2.Orientation()));
		}
	      }
	      else if (!nv2.IsSame(v2)) {
		// Add first vertex to the existing list
		GluedVertices(nv2).Append(v1);
		myReShape->Replace(v1,nv2.Oriented(v1.Orientation()));
	      }
	      else if (!v1.IsSame(v2)) {
		// Record new glued vertices
		TopoDS_Vertex nv;
		B.MakeVertex(nv);
		TopTools_ListOfShape vlist;
		vlist.Append(v1);
		vlist.Append(v2);
		GluedVertices.Bind(nv,vlist);
		myReShape->Replace(v1,nv.Oriented(v1.Orientation()));
		myReShape->Replace(v2,nv.Oriented(v2.Orientation()));
	      }
	    }
	  }

	  // Replace small edge
	  if (isSmall) {
#ifdef DEB
	    cout << "Warning: Small edge made degenerated by FaceAnalysis" << endl;
#endif
	    nbSmall++;
	    // Create new degenerated edge
            aTmpShape = edge.Oriented(TopAbs_FORWARD);
	    TopoDS_Edge fedge = TopoDS::Edge(aTmpShape);
	    Standard_Real pfirst, plast;
	    Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(fedge,face,pfirst,plast);
	    if (!c2d.IsNull()) {
	      TopoDS_Edge nedge;
	      B.MakeEdge(nedge);
	      B.UpdateEdge(nedge,c2d,face,Precision::Confusion());
	      B.Range(nedge,pfirst,plast);
	      B.Degenerated(nedge,Standard_True);
	      TopoDS_Vertex v1, v2;
	      TopExp::Vertices(fedge,v1,v2);
	      B.Add(nedge,myReShape->Apply(v1).Oriented(v1.Orientation()));
	      B.Add(nedge,myReShape->Apply(v2).Oriented(v2.Orientation()));
	      B.Add(nwire,nedge.Oriented(edge.Orientation()));
	      myDegenerated.Add(nedge);
	    }
	    isWireChanged = Standard_True;
	  }
	  else B.Add(nwire,edge); // Old edge kept
	}

	// Record wire in the new face
	if (isWireChanged) {
	  B.Add(nface,nwire.Oriented(wire.Orientation()));
	  isFaceChanged = Standard_True;
	}
	else B.Add(nface,wire);
      }

      // Remove small face
      if (nbSmall == nbEdges) {
#ifdef DEB
	cout << "Warning: Small face removed by FaceAnalysis" << endl;
#endif
	myLittleFace.Add(face);
	myReShape->Remove(face);
      }
      else if (isFaceChanged) {

	myReShape->Replace(face,nface.Oriented(face.Orientation()));
      }
    }
  }

  // Update glued vertices
  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape miter(GluedVertices);
  for (; miter.More(); miter.Next()) {
    TopoDS_Vertex vnew = TopoDS::Vertex(miter.Key());
    gp_XYZ coord(0.,0.,0.);
    Standard_Integer nbPoints = 0;
    const TopTools_ListOfShape& vlist = miter.Value();
    TopTools_ListIteratorOfListOfShape liter1(vlist);
    for (; liter1.More(); liter1.Next()) {
      coord += BRep_Tool::Pnt(TopoDS::Vertex(liter1.Value())).XYZ();
      nbPoints++;
    }
    if (nbPoints) {
      gp_Pnt vp(coord / nbPoints);
      Standard_Real tol = 0.0, mtol = 0.0;
      TopTools_ListIteratorOfListOfShape liter2(vlist);
      for (; liter2.More(); liter2.Next()) {
	Standard_Real vtol = BRep_Tool::Tolerance(TopoDS::Vertex(liter2.Value()));
	if (mtol < vtol) mtol = vtol;
	vtol = vp.Distance(BRep_Tool::Pnt(TopoDS::Vertex(liter2.Value())));
	if (tol < vtol) tol = vtol;
      }
      B.UpdateVertex(vnew,vp,tol+mtol);
    }
  }

  // Update input shapes
  for (i = 1; i <= myOldShapes.Extent(); i++)
    myOldShapes(i) = myReShape->Apply(myOldShapes(i));
}

//=======================================================================
//function : FindFreeBoundaries
//purpose  : Constructs :
//                      myBoundFaces     (bound = list of faces) - REFERENCE
//                      myVertexNode     (vertex = node)
//                      myVertexNodeFree (floating vertex = node)
//
//=======================================================================

void BRepBuilderAPI_Sewing::FindFreeBoundaries()
{
  // Take into account the context shape if needed
  TopTools_IndexedMapOfShape NewShapes;
  if (!myShape.IsNull()) {
    if (myOldShapes.IsEmpty()) {
      Add(myShape);
      myShape.Nullify();
    }
    else {
      TopoDS_Shape newShape = myReShape->Apply(myShape);
      if (!newShape.IsNull()) NewShapes.Add(newShape);
    }
  }
  // Create map Edge -> Faces
  TopTools_IndexedDataMapOfShapeListOfShape EdgeFaces;
  Standard_Integer i, nbShapes = myOldShapes.Extent();
  for (i = 1; i <= nbShapes; i++) {
    // Retrieve new shape
    TopoDS_Shape shape = myOldShapes(i);
    if (shape.IsNull()) continue;
    NewShapes.Add(shape);
    // Explore shape to find all boundaries
    for (TopExp_Explorer eExp(shape,TopAbs_EDGE); eExp.More(); eExp.Next()) {
      TopoDS_Shape edge = eExp.Current();
      if (!EdgeFaces.Contains(edge)) {
	TopTools_ListOfShape listFaces;
	EdgeFaces.Add(edge,listFaces);
      }
    }
  }
  // Fill map Edge -> Faces
  nbShapes = NewShapes.Extent();
   TopTools_MapOfShape mapFaces;
  for (i = 1; i <= nbShapes; i++) {
    // Explore shape to find all faces
    TopExp_Explorer fExp(NewShapes.FindKey(i),TopAbs_FACE);
    for (; fExp.More(); fExp.Next()) {
      TopoDS_Shape face = fExp.Current();
      if(mapFaces.Contains(face)) continue;
      else 
        mapFaces.Add(face);
      // Explore face to find all boundaries
      for (TopoDS_Iterator aIw(face); aIw.More(); aIw.Next()) {
        if(aIw.Value().ShapeType() != TopAbs_WIRE) continue;
        for (TopoDS_Iterator aIIe(aIw.Value()); aIIe.More(); aIIe.Next()) {
          
          TopoDS_Shape edge = aIIe.Value();
          
          if (EdgeFaces.Contains(edge)) {
            EdgeFaces.ChangeFromKey(edge).Append(face);
            //TopTools_ListOfShape& listFaces = EdgeFaces.ChangeFromKey(edge);
            //Standard_Boolean isContained = Standard_False;
            //TopTools_ListIteratorOfListOfShape itf(listFaces);
            //for (; itf.More() && !isContained; itf.Next())
            //  isContained = face.IsSame(itf.Value());
            //if (!isContained) listFaces.Append(face);
          }
        }
      }
    }
  }
  // Find free boundaries
  nbShapes = EdgeFaces.Extent();
  for (i = 1; i <= nbShapes; i++) {
    TopTools_ListOfShape& listFaces = EdgeFaces(i);
    Standard_Integer nbFaces = listFaces.Extent();
    TopoDS_Shape edge = EdgeFaces.FindKey(i);
    if(edge.Orientation() == TopAbs_INTERNAL)
          continue;
    Standard_Boolean isSeam = Standard_False;
    if (nbFaces == 1) {
      TopoDS_Face face = TopoDS::Face(listFaces.First());
      isSeam = BRep_Tool::IsClosed(TopoDS::Edge(edge),face);
      if (isSeam) {
	///Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
	//isSeam = (IsUClosedSurface(surf) || IsVClosedSurface(surf));
        //if(!isSeam) {
          Standard_Real first,last;
          Handle(Geom2d_Curve) c2dold = BRep_Tool::CurveOnSurface(TopoDS::Edge(edge),TopoDS::Face(listFaces.First()),first,last);
          Handle(Geom2d_Curve) c2d;
          BRep_Builder B;
          B.UpdateEdge(TopoDS::Edge(edge),c2d,c2d,TopoDS::Face(listFaces.First()),0);
          B.UpdateEdge(TopoDS::Edge(edge),c2dold,TopoDS::Face(listFaces.First()),0);
        //}
           isSeam = Standard_False;
      }
    }
    Standard_Boolean isBoundFloat = (myFloatingEdgesMode && !nbFaces);
    Standard_Boolean isBound = (myFaceMode && ((myNonmanifold && nbFaces) || (nbFaces == 1 && !isSeam)));
    if (isBound || isBoundFloat) {
      // Ignore degenerated edge
      if (BRep_Tool::Degenerated(TopoDS::Edge(edge))) continue;
      // Ignore edge with internal vertices
     // Standard_Integer nbVtx = 0;
     // for (TopExp_Explorer vExp(edge,TopAbs_VERTEX); vExp.More(); vExp.Next()) nbVtx++;
     // if (nbVtx != 2) continue;
      // Add to BoundFaces
      TopTools_ListOfShape listFacesCopy;
      listFacesCopy.Append(listFaces);
      myBoundFaces.Add(edge,listFacesCopy);
      // Process edge vertices
      TopoDS_Vertex vFirst, vLast;
      TopExp::Vertices(TopoDS::Edge(edge), vFirst, vLast);
      if(vFirst.IsNull() || vLast.IsNull()) continue;
      if(vFirst.Orientation() == TopAbs_INTERNAL || vLast.Orientation() == TopAbs_INTERNAL)
        continue;
      if (isBound) {
	// Add to VertexNode
	if (!myVertexNode.Contains(vFirst))
	  myVertexNode.Add(vFirst,vFirst);
	if (!myVertexNode.Contains(vLast))
	  myVertexNode.Add(vLast,vLast);
      }
      else {
	// Add to VertexNodeFree
	if (!myVertexNodeFree.Contains(vFirst))
	  myVertexNodeFree.Add(vFirst,vFirst);
	if (!myVertexNodeFree.Contains(vLast))
	  myVertexNodeFree.Add(vLast,vLast);
      }
    }
  }
}

//=======================================================================
//function : VerticesAssembling
//purpose  : Modifies :
//                      myVertexNode     (nodes glued)
//                      myVertexNodeFree (nodes glued)
//                      myNodeSections   (lists of sections merged for glued nodes)
//
//=======================================================================

static Standard_Boolean CreateNewNodes(const TopTools_IndexedDataMapOfShapeShape& NodeNearestNode,
				       const TopTools_IndexedDataMapOfShapeListOfShape& NodeVertices,
				       TopTools_IndexedDataMapOfShapeShape& aVertexNode,
				       TopTools_DataMapOfShapeListOfShape& aNodeEdges)
{
  Standard_Integer i, nbNearest = NodeNearestNode.Extent();

  // Create new nodes
  BRep_Builder B;
  TopTools_DataMapOfShapeShape OldNodeNewNode;
  TopTools_DataMapOfShapeListOfShape NewNodeOldNodes;
  for (i = 1; i <= nbNearest; i++) {
    // Retrieve a pair of nodes to merge
    TopoDS_Shape oldnode1 = NodeNearestNode.FindKey(i);
    TopoDS_Shape oldnode2 = NodeNearestNode(i);
    // Second node should also be in the map
    if (!NodeNearestNode.Contains(oldnode2)) continue;
    // Get new node for old node #1
    if (OldNodeNewNode.IsBound(oldnode1)) {
      TopoDS_Shape newnode1 = OldNodeNewNode(oldnode1);
      if (OldNodeNewNode.IsBound(oldnode2)) {
	TopoDS_Shape newnode2 = OldNodeNewNode(oldnode2);
	if (!newnode1.IsSame(newnode2)) {
	  // Change data for new node #2
	  TopTools_ListOfShape& lnode1 = NewNodeOldNodes(newnode1);
	  TopTools_ListIteratorOfListOfShape itn(NewNodeOldNodes(newnode2));
	  for (; itn.More(); itn.Next()) {
	    TopoDS_Shape node2 = itn.Value();
	    lnode1.Append(node2);
	    OldNodeNewNode(node2) = newnode1;
	  }
	  NewNodeOldNodes.UnBind(newnode2);
	}
      }
      else {
	// Old node #2 is not bound - add to old node #1
	OldNodeNewNode.Bind(oldnode2,newnode1);
	NewNodeOldNodes(newnode1).Append(oldnode2);
      }
    }
    else {
      if (OldNodeNewNode.IsBound(oldnode2)) {
	// Old node #1 is not bound - add to old node #2
	TopoDS_Shape newnode2 = OldNodeNewNode(oldnode2);
	OldNodeNewNode.Bind(oldnode1,newnode2);
	NewNodeOldNodes(newnode2).Append(oldnode1);
      }
      else {
	// Nodes are not bound - create new node
	TopoDS_Vertex newnode;
	B.MakeVertex(newnode);
	OldNodeNewNode.Bind(oldnode1,newnode);
	OldNodeNewNode.Bind(oldnode2,newnode);
	TopTools_ListOfShape lnodes;
	lnodes.Append(oldnode1);
	lnodes.Append(oldnode2);
	NewNodeOldNodes.Bind(newnode,lnodes);
      }
    }
  }

  // Stop if no new nodes created
  if (!NewNodeOldNodes.Extent()) return Standard_False;

  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape iter1(NewNodeOldNodes);
  for (; iter1.More(); iter1.Next()) {
    const TopoDS_Vertex& newnode = TopoDS::Vertex(iter1.Key());
    // Calculate new node center point
    gp_XYZ theCoordinates(0.,0.,0.);
    TopTools_ListOfShape lvert; // Accumulate node vertices
    TopTools_MapOfShape medge;
    TopTools_ListOfShape ledge; // Accumulate node edges
    // Iterate on old nodes
    TopTools_ListIteratorOfListOfShape itn(iter1.Value());
    for (; itn.More(); itn.Next()) {
      const TopoDS_Shape& oldnode = itn.Value();
      // Iterate on node vertices
      TopTools_ListIteratorOfListOfShape itv(NodeVertices.FindFromKey(oldnode));
      for (; itv.More(); itv.Next()) {
	TopoDS_Vertex vertex = TopoDS::Vertex(itv.Value());
	// Change node for vertex
	aVertexNode.ChangeFromKey(vertex) = newnode;
	// Accumulate coordinates
	theCoordinates += BRep_Tool::Pnt(vertex).XYZ();
	lvert.Append(vertex);
      }
      // Iterate on node edges
      const TopTools_ListOfShape& edges = aNodeEdges(oldnode);
      TopTools_ListIteratorOfListOfShape ite(edges);
      for (; ite.More(); ite.Next()) {
	TopoDS_Shape edge = ite.Value();
	if (!medge.Contains(edge)) { medge.Add(edge); ledge.Append(edge); }
      }
      // Unbind old node edges
      aNodeEdges.UnBind(oldnode);
    }
    // Bind new node edges
    aNodeEdges.Bind(newnode,ledge);
    gp_Pnt center(theCoordinates / lvert.Extent());
    // Calculate new node tolerance
    Standard_Real toler = 0.0;
    TopTools_ListIteratorOfListOfShape itv(lvert);
    for (; itv.More(); itv.Next()) {
      const TopoDS_Vertex& vertex = TopoDS::Vertex(itv.Value());
      Standard_Real t = center.Distance(BRep_Tool::Pnt(vertex)) + BRep_Tool::Tolerance(vertex);
      if (toler < t) toler = t;
    }
    // Update new node parameters
    B.UpdateVertex(newnode,center,toler);
  }

  return Standard_True;
}

static Standard_Integer IsMergedVertices(const TopoDS_Shape& face1,
					 const TopoDS_Shape& e1, const TopoDS_Shape& e2,
					 const TopoDS_Shape& vtx1, const TopoDS_Shape& vtx2)
{
  //Case of floating edges
  if (face1.IsNull())
    return (!IsClosedShape(e1,vtx1,vtx2));

  // Find wires containing given edges
  TopoDS_Shape wire1, wire2;
  TopExp_Explorer itw(face1,TopAbs_WIRE);
  for (; itw.More() && (wire1.IsNull() || wire2.IsNull()); itw.Next()) {
    TopoDS_Iterator ite(itw.Current(),Standard_False);
    for (; ite.More() && (wire1.IsNull() || wire2.IsNull()); ite.Next()) {
      if (wire1.IsNull() && e1.IsSame(ite.Value())) wire1 = itw.Current();
      if (wire2.IsNull() && e2.IsSame(ite.Value())) wire2 = itw.Current();
    }
  }
  Standard_Integer Status = 0;
  if (!wire1.IsNull() && !wire2.IsNull()) {
    if (wire1.IsSame(wire2)) {
      for (TopoDS_Iterator aIte(wire1,Standard_False); aIte.More(); aIte.Next()) {
	TopoDS_Vertex ve1,ve2;
	TopExp::Vertices(TopoDS::Edge(aIte.Value()),ve1,ve2);
	if ((ve1.IsSame(vtx1) && ve2.IsSame(vtx2)) ||
	    (ve2.IsSame(vtx1) && ve1.IsSame(vtx2)))
	  return (IsClosedShape(aIte.Value(),vtx1,vtx2)? 0 : 1);
      }
      if (IsClosedShape(wire1,vtx1,vtx2)) {
	TopoDS_Vertex V1, V2;
	TopExp::Vertices(TopoDS::Wire(wire1),V1,V2);
	Standard_Boolean isEndVertex = ((V1.IsSame(vtx1) && V2.IsSame(vtx2)) ||
					(V2.IsSame(vtx1) && V1.IsSame(vtx2)));
	if (!isEndVertex) Status = 1;
      }
      else Status = 1;
    }
    else Status = -1;
  }
  return Status;
}

static Standard_Boolean GlueVertices(TopTools_IndexedDataMapOfShapeShape& aVertexNode,
				     TopTools_DataMapOfShapeListOfShape& aNodeEdges,
				     const TopTools_IndexedDataMapOfShapeListOfShape& aBoundFaces,
				     const Standard_Real Tolerance)
{
  Standard_Integer i, nbVertices = aVertexNode.Extent();
  // Create map of node -> vertices
  TopTools_IndexedDataMapOfShapeListOfShape NodeVertices;
  for (i = 1; i <= nbVertices; i++) {
    TopoDS_Shape vertex = aVertexNode.FindKey(i);
    TopoDS_Vertex node = TopoDS::Vertex(aVertexNode(i));
    if (NodeVertices.Contains(node)) {
      NodeVertices.ChangeFromKey(node).Append(vertex);
    }
    else {
      TopTools_ListOfShape vlist;
      vlist.Append(vertex);
      NodeVertices.Add(node,vlist);
    }
  }
  Standard_Integer nbNodes = NodeVertices.Extent();
#ifdef DEB
  cout << "Glueing " << nbNodes << " nodes..." << endl;
#endif
  // Create array of boxes with nodes
  Handle(Bnd_HArray1OfBox) hSetBoxes = new Bnd_HArray1OfBox(1,nbNodes);
  Bnd_Box aBox;
  Standard_Real eps = Tolerance*0.5;
  for (i = 1; i <= nbNodes; i++) {
    gp_Pnt pt = BRep_Tool::Pnt(TopoDS::Vertex(NodeVertices.FindKey(i)));
    aBox.Set(pt);
    aBox.Enlarge(eps);
    hSetBoxes->SetValue(i,aBox);
  }
  // Merge nearest nodes
  TopTools_IndexedDataMapOfShapeShape NodeNearestNode;
  for (i = 1; i <= nbNodes; i++) {
    TopoDS_Vertex node1 = TopoDS::Vertex(NodeVertices.FindKey(i));
    // Find near nodes
    TColStd_ListOfInteger listIndex;
    SortBox(hSetBoxes,hSetBoxes->Value(i),listIndex);
    if (listIndex.IsEmpty()) continue;
    // Retrieve list of edges for the first node
    const TopTools_ListOfShape& ledges1 = aNodeEdges(node1);
    // Explore list of near nodes and fill the sequence of glued nodes
    TopTools_SequenceOfShape SeqNodes;
    TopTools_ListOfShape listNodesSameEdge;
    gp_Pnt pt1 = BRep_Tool::Pnt(node1);
    TColStd_ListIteratorOfListOfInteger iter1(listIndex);
    for (; iter1.More(); iter1.Next()) {
      TopoDS_Vertex node2 = TopoDS::Vertex(NodeVertices.FindKey(iter1.Value()));
      if (node1 == node2) continue;
      // Retrieve list of edges for the second node
      const TopTools_ListOfShape& ledges2 = aNodeEdges(node2);
      // Check merging condition for the pair of nodes
      Standard_Integer Status = 0, isSameEdge = Standard_False;
      // Explore edges of the first node
      TopTools_ListIteratorOfListOfShape Ie1(ledges1);
      for (; Ie1.More() && !Status && !isSameEdge; Ie1.Next()) {
	const TopoDS_Shape& e1 = Ie1.Value();
	// Obtain real vertex from edge
	TopoDS_Shape v1 = node1;
	{ //szv: Use brackets to destroy local variables
	  TopoDS_Vertex ov1, ov2;
	  TopExp::Vertices(TopoDS::Edge(e1),ov1,ov2);
	  if (aVertexNode.Contains(ov1)) {
	    if (node1.IsSame(aVertexNode.FindFromKey(ov1))) v1 = ov1;
	  }
	  if (aVertexNode.Contains(ov2)) {
	    if (node1.IsSame(aVertexNode.FindFromKey(ov2))) v1 = ov2;
	  }
	}
	// Create map of faces for e1
	TopTools_MapOfShape Faces1;
	const TopTools_ListOfShape& lfac1 = aBoundFaces.FindFromKey(e1);
	if (lfac1.Extent()) {
	  TopTools_ListIteratorOfListOfShape itf(lfac1);
	  for (; itf.More(); itf.Next())
	    if (!itf.Value().IsNull())
	      Faces1.Add(itf.Value());
	}
	// Explore edges of the second node
        TopTools_ListIteratorOfListOfShape Ie2(ledges2);
	for (; Ie2.More() && !Status && !isSameEdge; Ie2.Next()) {
	  const TopoDS_Shape& e2 = Ie2.Value();
	  // Obtain real vertex from edge
	  TopoDS_Shape v2 = node2;
	  { //szv: Use brackets to destroy local variables
	    TopoDS_Vertex ov1, ov2;
	    TopExp::Vertices(TopoDS::Edge(e2),ov1,ov2);
	    if (aVertexNode.Contains(ov1)) {
	      if (node2.IsSame(aVertexNode.FindFromKey(ov1))) v2 = ov1;
	    }
	    if (aVertexNode.Contains(ov2)) {
	      if (node2.IsSame(aVertexNode.FindFromKey(ov2))) v2 = ov2;
	    }
	  }
	  // Explore faces for e2
	  const TopTools_ListOfShape& lfac2 = aBoundFaces.FindFromKey(e2);
	  if (lfac2.Extent()) {
	    TopTools_ListIteratorOfListOfShape itf(lfac2);
	    for (; itf.More() && !Status && !isSameEdge; itf.Next()) {
	      // Check merging conditions for the same face
	      if (Faces1.Contains(itf.Value())) {
		Standard_Integer stat = IsMergedVertices(itf.Value(),e1,e2,v1,v2);
		if (stat == 1) isSameEdge = Standard_True;
		else Status = stat;
	      }
	    }
	  }
          else if (Faces1.IsEmpty() && e1 == e2) {
            Standard_Integer stat = IsMergedVertices(TopoDS_Face(),e1,e1,v1,v2);
            if (stat == 1) isSameEdge = Standard_True;
            else Status = stat;
            break;
          }
	}
      }
      if (Status) continue;
      if (isSameEdge) listNodesSameEdge.Append(node2);
      // Append near node to the sequence
      gp_Pnt pt2 = BRep_Tool::Pnt(node2);
      Standard_Real dist = pt1.Distance(pt2);
      if (dist < Tolerance) {
	Standard_Boolean isIns = Standard_False;
	for (Standard_Integer kk = 1; kk <= SeqNodes.Length() && !isIns; kk++) {
	  gp_Pnt pt = BRep_Tool::Pnt(TopoDS::Vertex(SeqNodes.Value(kk)));
	  if (dist < pt1.Distance(pt)) {
	    SeqNodes.InsertBefore(kk,node2);
	    isIns = Standard_True;
	  }
	}
	if (!isIns) SeqNodes.Append(node2);
      }
    }
    if (SeqNodes.Length()) {
      // Remove nodes near to some other from the same edge
      if (listNodesSameEdge.Extent()) {
	TopTools_ListIteratorOfListOfShape lInt(listNodesSameEdge);
	for (; lInt.More(); lInt.Next()) {
	  const TopoDS_Vertex& n2 = TopoDS::Vertex(lInt.Value());
	  gp_Pnt p2 = BRep_Tool::Pnt(n2);
	  for (Standard_Integer k = 1; k <= SeqNodes.Length(); ) {
	    const TopoDS_Vertex& n1 = TopoDS::Vertex(SeqNodes.Value(k));
	    if (n1 != n2) {
	      gp_Pnt p1 = BRep_Tool::Pnt(n1);
	      if (p2.Distance(p1) >= pt1.Distance(p1)) { k++; continue; }
	    }
	    SeqNodes.Remove(k);
	  }
	}
      }
      // Bind nearest node if at least one exists
      if (SeqNodes.Length())
	NodeNearestNode.Add(node1,SeqNodes.First());
    }
  }

  // Create new nodes for chained nearest nodes
  if (NodeNearestNode.IsEmpty()) return Standard_False;
  hSetBoxes.Nullify();

  return CreateNewNodes(NodeNearestNode,NodeVertices,aVertexNode,aNodeEdges);
}

void BRepBuilderAPI_Sewing::VerticesAssembling()
{
  Standard_Integer nbVert = myVertexNode.Extent();
  Standard_Integer nbVertFree = myVertexNodeFree.Extent();
  if (nbVert || nbVertFree) {
    // Fill map node -> sections
    Standard_Integer i;
    for (i = 1; i <= myBoundFaces.Extent(); i++) {
      TopoDS_Shape bound = myBoundFaces.FindKey(i);
      for (TopoDS_Iterator itv(bound,Standard_False); itv.More(); itv.Next()) {
	TopoDS_Shape node = itv.Value();
	if (myNodeSections.IsBound(node))
	  myNodeSections(node).Append(bound);
	else {
	  TopTools_ListOfShape lbnd;
	  lbnd.Append(bound);
	  myNodeSections.Bind(node,lbnd);
	}
      }
    }
    // Glue vertices
    if (nbVert) {
#ifdef DEB
      cout << "Assemble " << nbVert << " vertices on faces..." << endl;
#endif
      while (GlueVertices(myVertexNode,myNodeSections,myBoundFaces,myTolerance));
    }
    if (nbVertFree) {
#ifdef DEB
      cout << "Assemble " << nbVertFree << " vertices on floating edges..." << endl;
#endif
      while (GlueVertices(myVertexNodeFree,myNodeSections,myBoundFaces,myTolerance));
    }
  }
}

//=======================================================================
//function : replaceNMVertices
//purpose  : internal use (static)
//=======================================================================
static void replaceNMVertices(const TopoDS_Edge& theEdge, 
                              const TopoDS_Vertex& theV1,
                              const TopoDS_Vertex& theV2,
                              const Handle(BRepTools_ReShape)& theReShape)
{
  //To keep NM vertices on edge
  TopTools_SequenceOfShape aSeqNMVert;
  TColStd_SequenceOfReal aSeqNMPars;
  Standard_Boolean hasNMVert = findNMVertices(theEdge,aSeqNMVert,aSeqNMPars);
  if(!hasNMVert)
    return;
  Standard_Real first, last;
  BRep_Tool::Range(theEdge, first, last);
  TopLoc_Location aLoc;
  Handle(Geom_Curve) c3d = BRep_Tool::Curve(theEdge,aLoc,first, last);
  if(c3d.IsNull())
    return;
  TopTools_SequenceOfShape aEdVert;
  TColStd_SequenceOfReal aEdParams;
  Standard_Boolean isCopyEdge = Standard_False;
  Standard_Integer i =1, nb = aSeqNMPars.Length();
    
  for( ; i <= nb;i++) {
    Standard_Real apar = aSeqNMPars.Value(i);
    if(fabs(apar - first) <= Precision::PConfusion()) {
      theReShape->Replace(aSeqNMVert.Value(i),theV1);
      continue;
    }
    if(fabs(apar - last) <= Precision::PConfusion()) {
      theReShape->Replace(aSeqNMVert.Value(i),theV2);
      continue;
    }
    TopoDS_Shape aV = aSeqNMVert.Value(i);
    Standard_Integer j =1;
    for( ; j <= aEdParams.Length();j++) {
      Standard_Real apar2 = aEdParams.Value(j);
      if(fabs(apar - apar2) <= Precision::PConfusion()) {
        theReShape->Replace(aV,aEdVert.Value(j));
        break;
      }
      else if(apar < apar2) {
        TopoDS_Shape anewV = aV.EmptyCopied();
        aEdVert.InsertBefore(j,anewV);
        aEdParams.InsertBefore(j,apar);
        BRep_ListOfPointRepresentation& alistrep = 
          (*((Handle(BRep_TVertex)*)&anewV.TShape()))->ChangePoints();
        Handle(BRep_PointOnCurve) aPRep = new BRep_PointOnCurve(apar,c3d,aLoc);
        alistrep.Append(aPRep);
        theReShape->Replace(aV,anewV);
        break;
      }
    }
    if (j > aEdParams.Length()) {
      TopoDS_Shape anewV = aV.EmptyCopied();
      aEdVert.Append(anewV);
      aEdParams.Append(apar);
      BRep_ListOfPointRepresentation& alistrep = 
        (*((Handle(BRep_TVertex)*) &anewV.TShape()))->ChangePoints();
      Handle(BRep_PointOnCurve) aPRep = new BRep_PointOnCurve(apar,c3d,aLoc);
      alistrep.Append(aPRep);
      theReShape->Replace(aV,anewV);
    }
  }
  
  Standard_Integer newnb = aEdParams.Length();
  if(newnb < nb) {
    
    TopoDS_Shape anewEdge = theEdge.EmptyCopied();
    TopAbs_Orientation anOri = theEdge.Orientation();
    anewEdge.Orientation(TopAbs_FORWARD);
    BRep_Builder aB;
    aB.Add(anewEdge,theV1);
    aB.Add(anewEdge,theV2);
    
    for( i =1; i <= aEdVert.Length();i++) 
      aB.Add(anewEdge,aEdVert.Value(i));
    anewEdge.Orientation(anOri);
    theReShape->Replace(theEdge,anewEdge);
  }
 
}

//=======================================================================
//function : ReplaceEdge
//purpose  : internal use (static)
//=======================================================================

static void ReplaceEdge(const TopoDS_Shape& oldEdge,
			const TopoDS_Shape& theNewShape,
			const Handle(BRepTools_ReShape)& aReShape)
{
  TopoDS_Shape oldShape = aReShape->Apply(oldEdge);
  TopoDS_Shape newShape = aReShape->Apply(theNewShape);
  if (oldShape.IsSame(newShape)|| aReShape->IsRecorded(newShape)) return;
  

  aReShape->Replace(oldShape,newShape);
  TopoDS_Vertex V1old,V2old,V1new,V2new;
  TopExp::Vertices(TopoDS::Edge(oldShape),V1old,V2old);
  TopAbs_Orientation Orold = oldShape.Orientation();
  TopAbs_Orientation Ornew = Orold;
  if (newShape.ShapeType() == TopAbs_EDGE) {
    TopoDS_Edge aEn = TopoDS::Edge(newShape);
    TopExp::Vertices(aEn,V1new,V2new);
    Ornew = aEn.Orientation();
    replaceNMVertices(aEn,V1new,V2new,aReShape);
  }
  else if (newShape.ShapeType() == TopAbs_WIRE) {
    for (TopExp_Explorer aex(newShape,TopAbs_EDGE); aex.More(); aex.Next()) {
      TopoDS_Edge ed = TopoDS::Edge(aex.Current());
      Ornew = ed.Orientation();
      TopoDS_Vertex aV1,aV2;
      TopExp::Vertices(ed,aV1,aV2);
      replaceNMVertices(ed,aV1,aV2,aReShape);
      if (V1new.IsNull()) 
        V1new = aV1;
      V2new =aV2;
    }
  }
  
  V1new.Orientation(V1old.Orientation());
  V2new.Orientation(V2old.Orientation());
  if (V1old.IsSame(V2old) && !V1old.IsSame(V1new)&& !aReShape->IsRecorded(V1new)) {
    aReShape->Replace(V1old,V1new);
    return;
  }
  if (Orold == Ornew) {
    V1new.Orientation(V1old.Orientation());
    V2new.Orientation(V2old.Orientation());
    if (!V1old.IsSame(V1new) && !V1old.IsSame(V2new)&& !aReShape->IsRecorded(V1new))
      aReShape->Replace(V1old,V1new);
    if (!V2old.IsSame(V2new) && !V2old.IsSame(V1new)&& !aReShape->IsRecorded(V2new))
      aReShape->Replace(V2old,V2new);
  }
  else {
    V1new.Orientation(V2old.Orientation());
    V2new.Orientation(V1old.Orientation());
    if (!V1old.IsSame(V2new) && !V1old.IsSame(V1new)&& !aReShape->IsRecorded(V2new)) 
      aReShape->Replace(V1old,V2new);
    if (!V2old.IsSame(V2new) && !V2old.IsSame(V1new)&& !aReShape->IsRecorded(V1new))
      aReShape->Replace(V2old,V1new);
  }
}

//=======================================================================
//function : Merging
//purpose  : Modifies :
//                   myHasFreeBound
//
//=======================================================================

void BRepBuilderAPI_Sewing::Merging(const Standard_Boolean /* firstTime */)
{
  BRep_Builder B;
//  TopTools_MapOfShape MergedEdges;
  for (Standard_Integer i = 1; i <= myBoundFaces.Extent(); i++) {

    TopoDS_Shape bound = myBoundFaces.FindKey(i);

    // If bound was already merged - continue
    if (myMergedEdges.Contains(bound)) continue;

    if (!myBoundFaces(i).Extent()) {
      // Merge free edge - only vertices
      TopoDS_Vertex no1, no2;
      TopExp::Vertices(TopoDS::Edge(bound),no1,no2);
      TopoDS_Shape nno1 = no1, nno2 = no2;
      if (myVertexNodeFree.Contains(no1))
	nno1 = myVertexNodeFree.FindFromKey(no1);
      if (myVertexNodeFree.Contains(no2))
	nno2 = myVertexNodeFree.FindFromKey(no2);
      if (!no1.IsSame(nno1)) {
        nno1.Orientation(no1.Orientation());
	myReShape->Replace(no1,nno1);
      }
      if (!no2.IsSame(nno2)) {
        nno2.Orientation(no2.Orientation());
	myReShape->Replace(no2,nno2);
      }
      myMergedEdges.Add(bound);
      continue;
    }

    // Check for previous splitting, build replacing wire
    TopoDS_Wire BoundWire;
    Standard_Boolean isPrevSplit = Standard_False;
    Standard_Boolean hasCuttingSections = myBoundSections.IsBound(bound);
    if (hasCuttingSections) {
      B.MakeWire(BoundWire);
      BoundWire.Orientation(bound.Orientation());
      // Iterate on cutting sections
      TopTools_ListIteratorOfListOfShape its(myBoundSections(bound));
      for (; its.More(); its.Next()) {
	TopoDS_Shape section = its.Value();
	B.Add(BoundWire,section);
	if (myMergedEdges.Contains(section)) isPrevSplit = Standard_True;
      }
    }

    // Merge with bound
    TopTools_DataMapOfShapeShape MergedWithBound;
    if (!isPrevSplit) {
      // Obtain sequence of edges merged with bound
      TopTools_SequenceOfShape seqMergedWithBound;
      TColStd_SequenceOfInteger seqMergedWithBoundOri;
      if (MergedNearestEdges(bound,seqMergedWithBound,seqMergedWithBoundOri)) {
	// Store bound in the map
	MergedWithBound.Bind(bound,bound);
	// Iterate on edges merged with bound
	Standard_Integer ii = 1;
	while (ii <= seqMergedWithBound.Length()) {
	  TopoDS_Shape iedge = seqMergedWithBound.Value(ii);
	  // Remove edge if recorded as merged
	  Standard_Boolean isRejected = (myMergedEdges.Contains(iedge) || MergedWithBound.IsBound(iedge));
	  if (!isRejected) {
	    if (myBoundSections.IsBound(iedge)) {
	      // Edge is splitted - check sections
	      TopTools_ListIteratorOfListOfShape lit(myBoundSections(iedge));
	      for (; lit.More() && !isRejected; lit.Next()) {
		const TopoDS_Shape& sec = lit.Value();
		// Remove edge (bound) if at least one of its sections already merged
		isRejected = (myMergedEdges.Contains(sec) || MergedWithBound.IsBound(sec));
	      }
	    }
	    if (!isRejected) {
	      if (mySectionBound.IsBound(iedge)) {
		// Edge is a section - check bound
		const TopoDS_Shape& bnd = mySectionBound(iedge);
		// Remove edge (section) if its bound already merged
		isRejected = (myMergedEdges.Contains(bnd) || MergedWithBound.IsBound(bnd));
	      }
	    }
	  }
	  // To the next merged edge
	  if (isRejected) {
	    // Remove rejected edge
	    seqMergedWithBound.Remove(ii);
	    seqMergedWithBoundOri.Remove(ii);
	  }
	  else {
	    // Process accepted edge
	    MergedWithBound.Bind(iedge,iedge);
	    ii++;
	  }
	}
	Standard_Integer nbMerged = seqMergedWithBound.Length();
	if (nbMerged) {
	  // Create same parameter edge
	  TopTools_MapOfShape ActuallyMerged;
	  TopoDS_Edge MergedEdge = SameParameterEdge(bound,seqMergedWithBound,
						     seqMergedWithBoundOri,
						     ActuallyMerged,myReShape);
	  Standard_Boolean isForward = Standard_False;
	  if (!MergedEdge.IsNull()) isForward = (MergedEdge.Orientation() == TopAbs_FORWARD);
	  // Process actually merged edges
	  Standard_Integer nbActuallyMerged = 0;
	  for (ii = 1; ii <= nbMerged; ii++) {
	    TopoDS_Shape iedge = seqMergedWithBound(ii);
	    if (ActuallyMerged.Contains(iedge)) {
	      nbActuallyMerged++;
	      // Record merged edge in the map
	      TopAbs_Orientation orient = iedge.Orientation();
	      if (!isForward) orient = TopAbs::Reverse(orient);
	      if (!seqMergedWithBoundOri(ii)) orient = TopAbs::Reverse(orient);
	      MergedWithBound.ChangeFind(iedge) = MergedEdge.Oriented(orient);
	    }
	    else MergedWithBound.UnBind(iedge);
	  }
	  if (nbActuallyMerged) {
	    // Record merged bound in the map
	    TopAbs_Orientation orient = bound.Orientation();
	    if (!isForward) orient = TopAbs::Reverse(orient);
	    MergedWithBound.ChangeFind(bound) = MergedEdge.Oriented(orient);
	  }
	  nbMerged = nbActuallyMerged;
	}
	// Remove bound from the map if not finally merged
	if (!nbMerged) MergedWithBound.UnBind(bound);
      }
    }
    Standard_Boolean isMerged = MergedWithBound.Extent();

    // Merge with cutting sections
    Handle(BRepTools_ReShape) SectionsReShape = new BRepTools_ReShape;
    TopTools_DataMapOfShapeShape MergedWithSections;
    if (hasCuttingSections) {
      // Iterate on cutting sections
      TopTools_ListIteratorOfListOfShape its(myBoundSections(bound));
      for (; its.More(); its.Next()) {
	// Retrieve cutting section
	TopoDS_Shape section = its.Value();
	// Skip section if already merged
	if (myMergedEdges.Contains(section)) continue;
	// Merge cutting section
	TopTools_SequenceOfShape seqMergedWithSection;
	TColStd_SequenceOfInteger seqMergedWithSectionOri;
	if (MergedNearestEdges(section,seqMergedWithSection,seqMergedWithSectionOri)) {
	  // Store section in the map
	  MergedWithSections.Bind(section,section);
	  // Iterate on edges merged with section
	  Standard_Integer ii = 1;
	  while (ii <= seqMergedWithSection.Length()) {
	    TopoDS_Shape iedge = seqMergedWithSection.Value(ii);
	    // Remove edge if recorded as merged
	    Standard_Boolean isRejected = (myMergedEdges.Contains(iedge) || MergedWithSections.IsBound(iedge));
	    if (!isRejected) {
	      if (myBoundSections.IsBound(iedge)) {
		// Edge is splitted - check sections
		TopTools_ListIteratorOfListOfShape lit(myBoundSections(iedge));
		for (; lit.More() && !isRejected; lit.Next()) {
		  const TopoDS_Shape& sec = lit.Value();
		  // Remove edge (bound) if at least one of its sections already merged
		  isRejected = (myMergedEdges.Contains(sec) || MergedWithSections.IsBound(sec));
		}
	      }
	      if (!isRejected) {
		if (mySectionBound.IsBound(iedge)) {
		  // Edge is a section - check bound
		  const TopoDS_Shape& bnd = mySectionBound(iedge);
		  // Remove edge (section) if its bound already merged
		  isRejected = (myMergedEdges.Contains(bnd) || MergedWithSections.IsBound(bnd));
		}
	      }
	    }
	    // To the next merged edge
	    if (isRejected) {
	      // Remove rejected edge
	      seqMergedWithSection.Remove(ii);
	      seqMergedWithSectionOri.Remove(ii);
	    }
	    else {
	      // Process accepted edge
	      MergedWithSections.Bind(iedge,iedge);
	      ii++;
	    }
	  }
	  Standard_Integer nbMerged = seqMergedWithSection.Length();
	  if (nbMerged) {
	    // Create same parameter edge
	    TopTools_MapOfShape ActuallyMerged;
	    TopoDS_Edge MergedEdge = SameParameterEdge(section,seqMergedWithSection,
						       seqMergedWithSectionOri,
						       ActuallyMerged,SectionsReShape);
	    Standard_Boolean isForward = Standard_False;
	    if (!MergedEdge.IsNull()) isForward = (MergedEdge.Orientation() == TopAbs_FORWARD);
	    // Process actually merged edges
	    Standard_Integer nbActuallyMerged = 0;
	    for (ii = 1; ii <= nbMerged; ii++) {
	      TopoDS_Shape iedge = seqMergedWithSection(ii);
	      if (ActuallyMerged.Contains(iedge)) {
		nbActuallyMerged++;
		// Record merged edge in the map
		TopAbs_Orientation orient = iedge.Orientation();
		if (!isForward) orient = TopAbs::Reverse(orient);
		if (!seqMergedWithSectionOri(ii)) orient = TopAbs::Reverse(orient);
		TopoDS_Shape oedge = MergedEdge.Oriented(orient);
		MergedWithSections.ChangeFind(iedge) = oedge;
		ReplaceEdge(myReShape->Apply(iedge),oedge,SectionsReShape);
	      }
	      else MergedWithSections.UnBind(iedge);
	    }
	    if (nbActuallyMerged) {
	      // Record merged section in the map
	      TopAbs_Orientation orient = section.Orientation();
	      if (!isForward) orient = TopAbs::Reverse(orient);
	      TopoDS_Shape oedge = MergedEdge.Oriented(orient);
	      MergedWithSections.ChangeFind(section) = oedge;
	      ReplaceEdge(myReShape->Apply(section),oedge,SectionsReShape);
	    }
	    nbMerged = nbActuallyMerged;
	  }
	  // Remove section from the map if not finally merged
	  if (!nbMerged) MergedWithSections.UnBind(section);
	}
	else if (isMerged) {
	  // Reject merging of sections
	  MergedWithSections.Clear();
	  break;
	}
      }
    }
    Standard_Boolean isMergedSplit = MergedWithSections.Extent();

    if (!isMerged && !isMergedSplit) {
      // Nothing was merged in this iteration
      if (isPrevSplit) {
	// Replace previously splitted bound
	myReShape->Replace(myReShape->Apply(bound),myReShape->Apply(BoundWire));
      }
//      else if (hasCuttingSections) {
//	myBoundSections.UnBind(bound); //szv: are you sure ???
//      }
      continue;
    }

    // Set splitting flag
    Standard_Boolean isSplitted = ((!isMerged && isMergedSplit) || isPrevSplit);

    // Choose between bound and sections merging
    if (isMerged && isMergedSplit && !isPrevSplit) {
      // Fill map of merged cutting sections
      TopTools_MapOfShape MapSplitEdges;
      TopTools_DataMapIteratorOfDataMapOfShapeShape itm;
      for (itm.Initialize(MergedWithSections); itm.More(); itm.Next()) {
	TopoDS_Shape edge = itm.Key();
	MapSplitEdges.Add(edge);
      }
      // Iterate on edges merged with bound
      for (itm.Initialize(MergedWithBound); itm.More(); itm.Next()) {
	// Retrieve edge merged with bound
	TopoDS_Shape edge = itm.Key();
	// Remove edge from the map
	if (MapSplitEdges.Contains(edge)) MapSplitEdges.Remove(edge);
	if (myBoundSections.IsBound(edge)) {
	  // Edge has cutting sections
	  TopTools_ListIteratorOfListOfShape its(myBoundSections(edge));
	  for (; its.More(); its.Next()) {
	    TopoDS_Shape sec = its.Value();
	    // Remove section from the map
	    if (MapSplitEdges.Contains(sec)) MapSplitEdges.Remove(sec);
	  }
	}
      }
      // Calculate section merging tolerance
      Standard_Real MinSplitTol = RealLast();
      TopTools_MapIteratorOfMapOfShape im(MapSplitEdges);
      for (; im.More(); im.Next()) {
        TopoDS_Edge edge = TopoDS::Edge(MergedWithSections(im.Key()));
	MinSplitTol = Min(MinSplitTol,BRep_Tool::Tolerance(edge));
      }
      // Calculate bound merging tolerance
      TopoDS_Edge BoundEdge = TopoDS::Edge(MergedWithBound(bound));
      Standard_Real BoundEdgeTol = BRep_Tool::Tolerance(BoundEdge);
      isSplitted = ((MinSplitTol < BoundEdgeTol+MinTolerance()) || myNonmanifold);
      isSplitted = (!MapSplitEdges.IsEmpty() && isSplitted);
    }

    if (isSplitted) {
      // Merging of cutting sections
      //myMergedEdges.Add(bound);
      myReShape->Replace(myReShape->Apply(bound),myReShape->Apply(BoundWire));
      TopTools_DataMapIteratorOfDataMapOfShapeShape itm(MergedWithSections);
      for (; itm.More(); itm.Next()) {
	TopoDS_Shape oldedge = itm.Key();
	TopoDS_Shape newedge = SectionsReShape->Apply(itm.Value());
	ReplaceEdge(myReShape->Apply(oldedge),newedge,myReShape);
	myMergedEdges.Add(oldedge);
        if (myBoundSections.IsBound(oldedge)) myBoundSections.UnBind(oldedge);
       
      }
    }
    else {
      // Merging of initial bound
      TopTools_DataMapIteratorOfDataMapOfShapeShape itm(MergedWithBound);
      //myMergedEdges.Add(bound);
      for (; itm.More(); itm.Next()) {
	TopoDS_Shape oldedge = itm.Key();
	TopoDS_Shape newedge = itm.Value();
	ReplaceEdge(myReShape->Apply(oldedge),newedge,myReShape);
	myMergedEdges.Add(oldedge);
        if (myBoundSections.IsBound(oldedge)) myBoundSections.UnBind(oldedge);
      }
      if (myBoundSections.IsBound(bound)) myBoundSections.UnBind(bound);
      if(!myMergedEdges.Contains(bound))
          myMergedEdges.Add(bound);
    }
  }

  myNbVertices = myVertexNode.Extent() + myVertexNodeFree.Extent();
  myNodeSections.Clear();
  myVertexNode.Clear();
  myVertexNodeFree.Clear();
  myCuttingNode.Clear();
}

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

Standard_Boolean BRepBuilderAPI_Sewing::MergedNearestEdges(const TopoDS_Shape& edge,
						     TopTools_SequenceOfShape& SeqMergedEdge,
						     TColStd_SequenceOfInteger& SeqMergedOri)
{
  // Retrieve edge nodes
  TopoDS_Vertex no1, no2;
  TopExp::Vertices(TopoDS::Edge(edge),no1,no2);
  TopoDS_Shape nno1 = no1, nno2 = no2;
  Standard_Boolean isNode1 = myVertexNode.Contains(no1);
  Standard_Boolean isNode2 = myVertexNode.Contains(no2);
  if (isNode1) nno1 = myVertexNode.FindFromKey(no1);
  if (isNode2) nno2 = myVertexNode.FindFromKey(no2);

  // Fill map of nodes connected to the node #1
  TopTools_MapOfShape mapVert1;
  mapVert1.Add(nno1);
  if (myCuttingNode.IsBound(nno1)) {
    TopTools_ListIteratorOfListOfShape ilv(myCuttingNode(nno1));
    for (; ilv.More(); ilv.Next()) {
      TopoDS_Shape v1 = ilv.Value();
      mapVert1.Add(v1);
      if (!isNode1 && myCuttingNode.IsBound(v1)) {
	TopTools_ListIteratorOfListOfShape ilvn(myCuttingNode(v1));
	for (; ilvn.More(); ilvn.Next()) {
	  TopoDS_Shape vn = ilvn.Value();
	  mapVert1.Add(vn);
	}
      }
    }
  }

  // Fill map of nodes connected to the node #2
  TopTools_MapOfShape mapVert2;
  mapVert2.Add(nno2);
  if (myCuttingNode.IsBound(nno2)) {
    TopTools_ListIteratorOfListOfShape ilv(myCuttingNode(nno2));
    for (; ilv.More(); ilv.Next()) {
      TopoDS_Shape v1 = ilv.Value();
      mapVert2.Add(v1);
      if (!isNode2 && myCuttingNode.IsBound(v1)) {
	TopTools_ListIteratorOfListOfShape ilvn(myCuttingNode(v1));
	for (; ilvn.More(); ilvn.Next()) {
	  TopoDS_Shape vn = ilvn.Value();
	  mapVert2.Add(vn);
	}
      }
    }
  }

  // Find all possible contigous edges
  TopTools_SequenceOfShape seqEdges;
  seqEdges.Append(edge);
  TopTools_MapOfShape mapEdges;
  mapEdges.Add(edge);
  for (TopTools_MapIteratorOfMapOfShape imv1(mapVert1); imv1.More(); imv1.Next()) {
    TopoDS_Shape node1 = imv1.Key();
    if (!myNodeSections.IsBound(node1)) continue;
    TopTools_ListIteratorOfListOfShape ilsec(myNodeSections(node1));
    for (; ilsec.More(); ilsec.Next()) {
      TopoDS_Shape sec = ilsec.Value();
      if (sec.IsSame(edge)) continue;
      // Retrieve section nodes
      TopoDS_Vertex vs1, vs2;
      TopExp::Vertices(TopoDS::Edge(sec),vs1,vs2);
      TopoDS_Shape vs1n = vs1, vs2n = vs2;
      if (myVertexNode.Contains(vs1)) vs1n = myVertexNode.FindFromKey(vs1);
      if (myVertexNode.Contains(vs2)) vs2n = myVertexNode.FindFromKey(vs2);
      if ((mapVert1.Contains(vs1n) && mapVert2.Contains(vs2n)) ||
	  (mapVert1.Contains(vs2n) && mapVert2.Contains(vs1n)))
	if (mapEdges.Add(sec)) {
	  // Check for rejected cutting
	  Standard_Boolean isRejected = Standard_False;
	  if (mySectionBound.IsBound(sec)) {
	    const TopoDS_Shape& bnd = mySectionBound(sec);
	    isRejected = !myBoundSections.IsBound(bnd);
	  }
	  if (!isRejected) seqEdges.Append(sec);
	}
    }
  }
  mapEdges.Clear();

  Standard_Boolean success = Standard_False;

  Standard_Integer nbSection = seqEdges.Length();
  if (nbSection > 1) {
    // Find the longest edge CCI60011
    Standard_Integer i, indRef = 1;
    if (myNonmanifold) {
      Standard_Real lenRef = 0.;
      for (i = 1; i <= nbSection; i++) {
	Standard_Real f, l;
	Handle(Geom_Curve) c3d = BRep_Tool::Curve(TopoDS::Edge(seqEdges(i)), f, l);
	GeomAdaptor_Curve cAdapt(c3d);
	Standard_Real len = GCPnts_AbscissaPoint::Length(cAdapt, f, l);
	if (len > lenRef) { indRef = i; lenRef = len; }
      }
      if (indRef != 1) {
	TopoDS_Shape longEdge = seqEdges(indRef);
	seqEdges(indRef) = seqEdges(1);
	seqEdges(1) = longEdge;
      }
    }

    // Find merging candidates
    TColStd_SequenceOfInteger seqForward;
    TColStd_SequenceOfInteger seqCandidates;
    TColStd_IndexedMapOfInteger mapReference;
    mapReference.Add(1); // Add index of reference section
    if (FindCandidates(seqEdges,mapReference,seqCandidates,seqForward)) {
      Standard_Integer nbCandidates = seqCandidates.Length();
      // Check if reference section is merged reversed
      Standard_Boolean toReverse = Standard_False;
      if (indRef != 1) {
	// Find reference edge in candidates
	Standard_Boolean isFound = Standard_False;
	for (i = 1; i <= nbCandidates && !isFound; i++) {
	  isFound = (seqCandidates(i) == indRef);
	  if (isFound) {
	    // Record orientation
	    toReverse = !seqForward(i);
	    // Restore first edge
	    seqCandidates(i) = 1;
	    seqForward(i) = 1;
	  }
	}
	// Fail if reference is not in candidates
	if (!isFound) return Standard_False;
      }
      // Record candidate sections
      for (i = 1; i <= nbCandidates; i++) {
	// Retrieve merged edge
	TopoDS_Shape iedge = seqEdges(seqCandidates(i));
	Standard_Integer ori =
	  ((seqForward(i) && toReverse) || (!seqForward(i) && !toReverse))? 0 : 1;
	SeqMergedEdge.Append(iedge);
	SeqMergedOri.Append(ori);
	if (!myNonmanifold) break;
      }
      success = nbCandidates;
    }
  }

  return success;
}

//=======================================================================
//function : Cutting
//purpose  : Modifies :
//                     myBoundSections
//                     myNodeSections
//                     myCuttingNode
//=======================================================================

void BRepBuilderAPI_Sewing::Cutting()
{
  Standard_Integer i, nbVertices = myVertexNode.Extent();
  if (!nbVertices) return;
  // Create a sort box with vertices
  Standard_Real eps = myTolerance*0.5;
  Handle(Bnd_HArray1OfBox) hSetBoxes = new Bnd_HArray1OfBox(1,nbVertices);
  for (i = 1; i <= nbVertices; i++) {
    gp_Pnt pt = BRep_Tool::Pnt(TopoDS::Vertex(myVertexNode.FindKey(i)));
    Bnd_Box aBox;
    aBox.Set(pt);
    aBox.Enlarge(eps);
    hSetBoxes->ChangeValue(i) = aBox;
  }
  Handle(Geom_Curve) c3d;
  TopLoc_Location loc;
  Standard_Real first, last;
  // Iterate on all boundaries
  Standard_Integer nbBounds = myBoundFaces.Extent();
  for (i = 1; i <= nbBounds; i++) {
    const TopoDS_Edge& bound = TopoDS::Edge(myBoundFaces.FindKey(i));
    // Do not cut floating edges
    if (!myBoundFaces(i).Extent()) continue;
    // Create cutting sections
    TopTools_ListOfShape listSections;
    { //szv: Use brackets to destroy local variables
      // Obtain bound curve
      c3d = BRep_Tool::Curve(bound, loc, first, last);
      if (!loc.IsIdentity()) {
	c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
	c3d->Transform(loc.Transformation());
      }
      // Obtain candidate vertices
      TopoDS_Vertex V1, V2;
      TopTools_IndexedMapOfShape CandidateVertices;
      { //szv: Use brackets to destroy local variables
	// Create bounding box around curve
	Bnd_Box aGlobalBox;
	GeomAdaptor_Curve adptC(c3d,first,last);
	BndLib_Add3dCurve::Add(adptC,myTolerance,aGlobalBox);
	// Sort vertices to find candidates
	TColStd_ListOfInteger listIndex;
	SortBox(hSetBoxes,aGlobalBox,listIndex);
	// Skip bound if no node is in the boundind box
	if (!listIndex.Extent()) continue;
	// Retrieve bound nodes
	TopExp::Vertices(bound,V1,V2);
	const TopoDS_Shape& Node1 = myVertexNode.FindFromKey(V1);
	const TopoDS_Shape& Node2 = myVertexNode.FindFromKey(V2);
	// Fill map of candidate vertices
	TColStd_ListIteratorOfListOfInteger itl(listIndex);
	for (; itl.More(); itl.Next()) {
	  const Standard_Integer index = itl.Value();
	  const TopoDS_Shape& Node = myVertexNode.FindFromIndex(index);
	  if (!Node.IsSame(Node1) && !Node.IsSame(Node2)) {
	    TopoDS_Shape vertex = myVertexNode.FindKey(index);
	    CandidateVertices.Add(vertex);
	  }
	}
      }
      Standard_Integer nbCandidates = CandidateVertices.Extent();
      if (!nbCandidates) continue;
      // Project vertices on curve
      TColStd_Array1OfReal arrPara(1,nbCandidates), arrDist(1,nbCandidates);
      TColgp_Array1OfPnt arrPnt(1,nbCandidates), arrProj(1,nbCandidates);
      for (Standard_Integer j = 1; j <= nbCandidates; j++)
	arrPnt(j) = BRep_Tool::Pnt(TopoDS::Vertex(CandidateVertices(j)));
      ProjectPointsOnCurve(arrPnt,c3d,first,last,arrDist,arrPara,arrProj);
      // Create cutting nodes
      TopTools_SequenceOfShape seqNode;
      TColStd_SequenceOfReal seqPara;
      CreateCuttingNodes(CandidateVertices,bound,
			 V1,V2,arrDist,arrPara,arrProj,seqNode,seqPara);
      if (!seqPara.Length()) continue;
      // Create cutting sections
      CreateSections(bound, seqNode, seqPara, listSections);
    }
    if (listSections.Extent() > 1) {
      // modification of maps:
      //                     myBoundSections
      TopTools_ListIteratorOfListOfShape its(listSections);
      for (; its.More(); its.Next()) {
	TopoDS_Shape section = its.Value();
	// Iterate on section vertices
	for (TopoDS_Iterator itv(section); itv.More(); itv.Next()) {
	  TopoDS_Shape vertex = itv.Value();
	  // Convert vertex to node
	  if (myVertexNode.Contains(vertex))
	    vertex = TopoDS::Vertex(myVertexNode.FindFromKey(vertex));
	  // Update node sections
	  if (myNodeSections.IsBound(vertex))
	    myNodeSections.ChangeFind(vertex).Append(section);
	  else {
	    TopTools_ListOfShape lsec;
	    lsec.Append(section);
	    myNodeSections.Bind(vertex,lsec);
	  }
	}
	// Store bound for section
	mySectionBound.Bind(section,bound);
      }
      // Store splitted bound
      myBoundSections.Bind(bound,listSections);
    }
  }
#ifdef DEB
  cout << "From " << nbBounds << " bounds " << myBoundSections.Extent()
       << " were cut into " << mySectionBound.Extent() << " sections" << endl;
#endif
}

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

static void GetSeqEdges(const TopoDS_Shape& edge,
			TopTools_SequenceOfShape& seqEdges,
			TopTools_DataMapOfShapeListOfShape& VertEdge)
{
  Standard_Integer numV = 0;
  for (TopoDS_Iterator Iv(edge,Standard_False); Iv.More(); Iv.Next()) {
    TopoDS_Vertex V1 = TopoDS::Vertex(Iv.Value());
    numV++;
    if (VertEdge.IsBound(V1)) {
      const TopTools_ListOfShape& listEdges = VertEdge.Find(V1);
      for (TopTools_ListIteratorOfListOfShape lIt(listEdges); lIt.More(); lIt.Next()) {
	TopoDS_Shape edge1 = lIt.Value();
	if (edge1.IsSame(edge)) continue;
	Standard_Boolean isContained = Standard_False;
	Standard_Integer i, index = 1;
	for (i = 1; i <= seqEdges.Length() && !isContained; i++) {
	  isContained = seqEdges.Value(i).IsSame(edge1);
	  if (!isContained && seqEdges.Value(i).IsSame(edge)) index = i;
	}
	if (!isContained) {
	  if (numV == 1) seqEdges.InsertBefore(index,edge1);
	  else seqEdges.InsertAfter(index,edge1);
	  GetSeqEdges(edge1,seqEdges,VertEdge);
	}
      }
    }
  }
}

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

void BRepBuilderAPI_Sewing::GetFreeWires(TopTools_MapOfShape& MapFreeEdges, TopTools_SequenceOfShape& seqWires)
{
  TopTools_DataMapOfShapeListOfShape VertEdge;
  TopTools_MapIteratorOfMapOfShape itMap(MapFreeEdges);
  TopTools_SequenceOfShape seqFreeEdges;
  for (; itMap.More(); itMap.Next()) {
    TopoDS_Shape edge = itMap.Key();
    seqFreeEdges.Append(edge);
    for (TopoDS_Iterator Iv(edge,Standard_False); Iv.More(); Iv.Next()) {
      TopoDS_Vertex V1 = TopoDS::Vertex(Iv.Value());
      if (VertEdge.IsBound(V1))
	VertEdge.ChangeFind(V1).Append(edge);
      else {
	TopTools_ListOfShape ls;
	ls.Append(edge);
	VertEdge.Bind(V1,ls);
      }
    }
  }
  BRep_Builder B;
  Standard_Integer i, j;
  for (i = 1; i <= seqFreeEdges.Length(); i++) {
    TopTools_SequenceOfShape seqEdges;
    TopoDS_Shape edge = seqFreeEdges.Value(i);
    if (!MapFreeEdges.Contains(edge)) continue;
    seqEdges.Append(edge);
    GetSeqEdges(edge,seqEdges,VertEdge);
    TopoDS_Wire wire;
    B.MakeWire(wire);
    for (j = 1; j <= seqEdges.Length(); j++) {
      B.Add(wire,seqEdges.Value(j));
      MapFreeEdges.Remove(seqEdges.Value(j));
    }
    seqWires.Append(wire);
    if (MapFreeEdges.IsEmpty()) break;
  }
}

//=======================================================================
//function :  IsDegeneratedWire
//purpose  :  internal use
//=======================================================================

static Standard_Boolean IsDegeneratedWire(const TopoDS_Shape& wire)
{
  if (wire.ShapeType() != TopAbs_WIRE) return Standard_False;
  // Get maximal vertices tolerance
  TopoDS_Vertex V1,V2;
  //TopExp::Vertices(TopoDS::Wire(wire),V1,V2);
  //Standard_Real tol = Max(BRep_Tool::Tolerance(V1),BRep_Tool::Tolerance(V2));
  Standard_Real wireLength = 0.0;
  TopLoc_Location loc;
  Standard_Real first, last;
  Standard_Integer nume = 0;
  Standard_Integer isSmall = 0;
  for (TopoDS_Iterator aIt(wire,Standard_False); aIt.More(); aIt.Next()) {
    nume++;
    TopoDS_Shape edge = aIt.Value();
    TopoDS_Vertex Ve1,Ve2;
    TopExp::Vertices(TopoDS::Edge(edge),Ve1,Ve2);
    if(nume == 1) {
       V1 = Ve1;
       V2 = Ve2;
    }
    else {
      if(Ve1.IsSame(V1))
         V1 = Ve2;
      else if(Ve1.IsSame(V2))
        V2 = Ve2;
      if(Ve2.IsSame(V1))
         V1 = Ve1;
      else if(Ve2.IsSame(V2))
        V2 = Ve1;
    }
    Handle(Geom_Curve) c3d = BRep_Tool::Curve(TopoDS::Edge(aIt.Value()),loc,first,last);
    if (!c3d.IsNull()) {
      c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
      if (!loc.IsIdentity()) {
        //c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
	c3d->Transform(loc.Transformation());
      }
      gp_Pnt pfirst = c3d->Value(first);
      gp_Pnt plast = c3d->Value(last);
      gp_Pnt pmid = c3d->Value((first +last)*0.5);
      Standard_Real length =0;
      if(pfirst.Distance(plast) > pfirst.Distance(pmid)) {
        length = pfirst.Distance(plast);
      }
      else {
        GeomAdaptor_Curve cAdapt(c3d);
        length = GCPnts_AbscissaPoint::Length(cAdapt, first, last);
      }
      Standard_Real tole = BRep_Tool::Tolerance(Ve1)+BRep_Tool::Tolerance(Ve2);
      if(length <= tole) isSmall++;
      wireLength += length;
    }
  }
  if(isSmall == nume) return Standard_True;
  Standard_Real tol = BRep_Tool::Tolerance(V1)+BRep_Tool::Tolerance(V2);//Max(BRep_Tool::Tolerance(V1),BRep_Tool::Tolerance(V2));
  if (wireLength > tol) return Standard_False;
  return Standard_True;
}

//=======================================================================
//function :  DegeneratedSection
//purpose  :  internal use
//            create a new degenerated edge if the section is degenerated
//=======================================================================

static TopoDS_Edge DegeneratedSection(const TopoDS_Shape& section, const TopoDS_Shape& face)
{
  // Return if section is already degenerated
  if (BRep_Tool::Degenerated(TopoDS::Edge(section))) return TopoDS::Edge(section);

  // Retrieve edge curve
  TopLoc_Location loc;
  Standard_Real first, last;
  Handle(Geom_Curve) c3d = BRep_Tool::Curve(TopoDS::Edge(section), loc, first, last);
  if (c3d.IsNull()) { //gka
    BRep_Builder aB;
    TopoDS_Edge edge1 = TopoDS::Edge(section);
    aB.Degenerated(edge1, Standard_True);
    return edge1;
  }
  if (!loc.IsIdentity()) {
    c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
    c3d->Transform(loc.Transformation());
  }

  // Test if the new edge is degenerated
  TopoDS_Vertex v1,v2;
  TopExp::Vertices(TopoDS::Edge(section),v1,v2);
  //Standard_Real tol = Max(BRep_Tool::Tolerance(v1),BRep_Tool::Tolerance(v2));
  //tol = Max(tolerance,tol);

  gp_Pnt p1, p2, p3;
  p1 = BRep_Tool::Pnt(v1);
  p3 = BRep_Tool::Pnt(v2);
  c3d->D0(0.5*(first + last),p2);

  //Standard_Boolean isDegenerated = Standard_False;
  //if (p1.Distance(p3) < tol) {
    //GeomAdaptor_Curve cAdapt(c3d);
    //Standard_Real length = GCPnts_AbscissaPoint::Length(cAdapt, first, last);
    //isDegenerated =  Standard_True; //(length < tol);
  //}

  TopoDS_Edge edge;
  //if (!isDegenerated) return edge;

  // processing
  BRep_Builder aBuilder;
  edge = TopoDS::Edge(section);
  edge.EmptyCopy();
  if (v1.IsSame(v2)) {      
    TopoDS_Shape anEdge = edge.Oriented(TopAbs_FORWARD);
    aBuilder.Add(anEdge, v1.Oriented(TopAbs_FORWARD));
    aBuilder.Add(anEdge, v2.Oriented(TopAbs_REVERSED));
  }
  else {
    TopoDS_Vertex newVertex;
    if (p1.Distance(p3) < BRep_Tool::Tolerance(v1))
      newVertex = v1;
    else if (p1.Distance(p3) < BRep_Tool::Tolerance(v2))
      newVertex = v2;
    else {
      Standard_Real d1 = BRep_Tool::Tolerance(v1) + p2.Distance(p1);
      Standard_Real d2 = BRep_Tool::Tolerance(v2) + p2.Distance(p3);
      Standard_Real newTolerance = Max(d1,d2);
      aBuilder.MakeVertex(newVertex, p2, newTolerance);
    }
    TopoDS_Shape anEdge = edge.Oriented(TopAbs_FORWARD);
    aBuilder.Add(anEdge, newVertex.Oriented(TopAbs_FORWARD));
    aBuilder.Add(anEdge, newVertex.Oriented(TopAbs_REVERSED));
  }

  BRep_Tool::Range(TopoDS::Edge(section), first, last);
  TopoDS_Shape anEdge = edge.Oriented(TopAbs_FORWARD);
  aBuilder.Range(TopoDS::Edge(anEdge), first, last);
  aBuilder.Degenerated(edge, Standard_True);
  Handle(Geom_Curve) aC3dNew;
  if (!face.IsNull()) {
    Standard_Real af,al;
    Handle(Geom2d_Curve) aC2dt = BRep_Tool::CurveOnSurface(TopoDS::Edge(section),TopoDS::Face(face),af,al);
    aBuilder.UpdateEdge(edge,aC3dNew,0);
    Handle(Geom2d_Curve) aC2dn = BRep_Tool::CurveOnSurface(edge,TopoDS::Face(face),af,al);
    if (aC2dn.IsNull())
      aBuilder.UpdateEdge(edge,aC2dt,TopoDS::Face(face),0);
  }

  return edge;
}

//=======================================================================
//function : EdgeProcessing
//purpose  : modifies :
//                       myNbEdges
//                       myHasMultipleEdge
//                       myHasFreeBound
//           . if multiple edge
//              - length < 100.*myTolerance -> several free edge
//           . if no multiple edge
//              - make the contigous edges sameparameter
//=======================================================================

void BRepBuilderAPI_Sewing::EdgeProcessing()
{
  // constructs sectionEdge
  TopTools_MapOfShape MapFreeEdges;
  TopTools_DataMapOfShapeShape EdgeFace;
  for (Standard_Integer i = 1; i <= myBoundFaces.Extent(); i++) {
    const TopoDS_Shape& bound = myBoundFaces.FindKey(i);
    const TopTools_ListOfShape& listFaces = myBoundFaces(i);
    if (listFaces.Extent() == 1) {
      if (myBoundSections.IsBound(bound)) {
	TopTools_ListIteratorOfListOfShape liter(myBoundSections(bound));
	for (; liter.More(); liter.Next()) {
	  if (!myMergedEdges.Contains(liter.Value())) { //myReShape->IsRecorded(liter.Value())) {
	    TopoDS_Shape edge = myReShape->Apply(liter.Value());
	    if (!MapFreeEdges.Contains(edge)) {
	      TopoDS_Shape face = listFaces.First();
	      EdgeFace.Bind(edge,face);
	      MapFreeEdges.Add(edge);
	    }
	  }
	}
      }
      else {
	if (!myMergedEdges.Contains(bound)) {
	  TopoDS_Shape edge = myReShape->Apply(bound);
	  if (!MapFreeEdges.Contains(edge)) {
	    TopoDS_Shape face = listFaces.First();
	    EdgeFace.Bind(edge,face);
	    MapFreeEdges.Add(edge);
	  }
	}
      }
    }
  }

  if (!MapFreeEdges.IsEmpty()) {
    TopTools_SequenceOfShape seqWires;
    GetFreeWires(MapFreeEdges,seqWires);
    for (Standard_Integer j = 1; j <= seqWires.Length(); j++) {
      TopoDS_Wire wire = TopoDS::Wire(seqWires.Value(j));
      if (!IsDegeneratedWire(wire)) continue;
      for (TopoDS_Iterator Ie(wire,Standard_False); Ie.More(); Ie.Next()) {
        TopoDS_Shape aTmpShape = myReShape->Apply(Ie.Value()); //for porting
	TopoDS_Edge edge = TopoDS::Edge(aTmpShape);
	TopoDS_Shape face;
	if (EdgeFace.IsBound(edge))
	  face = EdgeFace.Find(edge);
	TopoDS_Shape degedge = DegeneratedSection(edge,face);
	if (degedge.IsNull()) continue;
	if (!degedge.IsSame(edge))
	  ReplaceEdge(edge,degedge,myReShape);
	if (BRep_Tool::Degenerated(TopoDS::Edge(degedge)))
	  myDegenerated.Add(degedge);
      }
    }
  }
  myMergedEdges.Clear();
}

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

void BRepBuilderAPI_Sewing::CreateSewedShape()
{
  // ---------------------
  // create the new shapes
  // ---------------------
  BRepTools_Quilt aQuilt;
  Standard_Boolean isLocal = !myShape.IsNull();
  if (isLocal) {
    // Local sewing
    TopoDS_Shape ns = myReShape->Apply(myShape);
    aQuilt.Add(ns);
  }
  Standard_Integer i;
  for (i = 1; i <= myOldShapes.Extent(); i++) {
    TopoDS_Shape sh = myOldShapes(i);
    if (!sh.IsNull()) {
      sh = myReShape->Apply(sh);
      myOldShapes(i) = sh;
      if (!isLocal) aQuilt.Add(sh);
    }
  }
  TopoDS_Shape aNewShape = aQuilt.Shells();
  Standard_Integer numsh = 0;

  TopTools_IndexedMapOfShape OldShells;

  BRep_Builder aB;
  TopoDS_Compound aComp;
  aB.MakeCompound(aComp);
  for (TopoDS_Iterator aExpSh(aNewShape,Standard_False); aExpSh.More(); aExpSh.Next()) {
    TopoDS_Shape sh = aExpSh.Value();
    Standard_Boolean hasEdges = Standard_False;
    if (sh.ShapeType() == TopAbs_SHELL) {
      if (myNonmanifold)
	hasEdges = !OldShells.Contains(sh);
      else {
	TopoDS_Shape face;
	Standard_Integer numf = 0;
	for (TopExp_Explorer aExpF(sh,TopAbs_FACE); aExpF.More() && (numf < 2); aExpF.Next()) {
	  face = aExpF.Current();
	  numf++;
	}
	if (numf == 1) aB.Add(aComp,face);
	else if (numf > 1) aB.Add(aComp,sh);
	if (numf) numsh++;
      }
    }
    else if (sh.ShapeType() == TopAbs_FACE) {
      if (myNonmanifold) {
	TopoDS_Shell ss;
	aB.MakeShell(ss);
	aB.Add(ss,sh);
	sh = ss;
	hasEdges = Standard_True;
      }
      else { aB.Add(aComp,sh); numsh++; }
    }
    else { aB.Add(aComp,sh); numsh++; }
    if (hasEdges) OldShells.Add(sh);
  }
  // Process collected shells
  if (myNonmanifold) {
    Standard_Integer nbOldShells = OldShells.Extent();
    if (nbOldShells == 1) {
      // Single shell - check for single face
      TopoDS_Shape sh = OldShells.FindKey(1);
      TopoDS_Shape face;
      Standard_Integer numf = 0;
      for (TopExp_Explorer aExpF(sh,TopAbs_FACE); aExpF.More() && (numf < 2); aExpF.Next()) {
	face = aExpF.Current();
	numf++;
      }
      if (numf == 1) aB.Add(aComp,face);
      else if (numf > 1) aB.Add(aComp,sh);
      if (numf) numsh++;
    }
    else if (nbOldShells) {
      // Several shells should be merged
      TColStd_MapOfInteger IndexMerged;
      while (IndexMerged.Extent() < nbOldShells) {
	TopoDS_Shell NewShell;
	TopTools_MapOfShape NewEdges;
	for (i = 1; i <= nbOldShells; i++) {
	  if (IndexMerged.Contains(i)) continue;
	  TopoDS_Shell shell = TopoDS::Shell(OldShells.FindKey(i));
	  if (NewShell.IsNull()) {
            BRep_Builder aB;
            aB.MakeShell(NewShell);
            TopoDS_Iterator aItSS(shell) ;
            for( ; aItSS.More(); aItSS.Next())
              aB.Add(NewShell,aItSS.Value())
;
	    // Fill map of edges
	    for (TopExp_Explorer eexp(shell,TopAbs_EDGE); eexp.More(); eexp.Next()) {
	      TopoDS_Shape edge = eexp.Current();
	      NewEdges.Add(edge);
	    }
	    IndexMerged.Add(i);
	  }
	  else {
	    Standard_Boolean hasSharedEdge = Standard_False;
	    TopExp_Explorer eexp(shell,TopAbs_EDGE);
	    for (; eexp.More() && !hasSharedEdge; eexp.Next())
	      hasSharedEdge = NewEdges.Contains(eexp.Current());
	    if (hasSharedEdge) {
	      // Add edges to the map
	      for (TopExp_Explorer eexp1(shell,TopAbs_EDGE); eexp1.More(); eexp1.Next()) {
		TopoDS_Shape edge = eexp1.Current();
		NewEdges.Add(edge);
	      }
	      // Add faces to the shell
	      for (TopExp_Explorer fexp(shell,TopAbs_FACE); fexp.More(); fexp.Next()) {
		TopoDS_Shape face = fexp.Current();
		aB.Add(NewShell,face);
	      }
	      IndexMerged.Add(i);
	    }
	  }
	}
	// Process new shell
	TopoDS_Shape face;
	Standard_Integer numf = 0;
	TopExp_Explorer aExpF(NewShell,TopAbs_FACE);
	for (; aExpF.More() && (numf < 2); aExpF.Next()) {
	  face = aExpF.Current();
	  numf++;
	}
	if (numf == 1) aB.Add(aComp,face);
	else if (numf > 1) aB.Add(aComp,NewShell);
	if (numf) numsh++;
      }
    }
  }
  if (numsh == 1) {
    // Extract single component
    TopoDS_Iterator aIt(aComp,Standard_False);
    mySewedShape = aIt.Value();
  }
  else
    mySewedShape = aComp;
}

//=======================================================================
//function : CreateOutputInformations
//purpose  : constructs :
//                       myEdgeSections
//                       mySectionBound
//                       myNbFreeEdges
//                       myNbContigousEdges
//                       myNbMultipleEdges
//                       myNbDegenerated
//=======================================================================

void BRepBuilderAPI_Sewing::CreateOutputInformations()
{
  // Construct edgeSections
  Standard_Integer i;
  //TopTools_DataMapOfShapeListOfShape edgeSections;
  TopTools_IndexedDataMapOfShapeListOfShape edgeSections; //use index map for regulating free edges
  for (i = 1; i <= myBoundFaces.Extent(); i++) {
    const TopoDS_Shape& bound = myBoundFaces.FindKey(i);
    TopTools_ListOfShape lsect;
    if (myBoundSections.IsBound(bound)) lsect = myBoundSections(bound);
    TopExp_Explorer aExp(myReShape->Apply(bound),TopAbs_EDGE);
    for (; aExp.More(); aExp.Next()) {
      TopoDS_Shape sec = bound, edge = aExp.Current();
      TopTools_ListIteratorOfListOfShape aI(lsect);
      for (; aI.More(); aI.Next()) {
	const TopoDS_Shape& section = aI.Value();
	if (edge.IsSame(myReShape->Apply(section))) { sec = section; break; }
      }
      if (edgeSections.Contains(edge))
	 edgeSections.ChangeFromKey(edge).Append(sec);
      else {
 	TopTools_ListOfShape listSec;
	listSec.Append(sec);
	edgeSections.Add(edge,listSec);
      }
    }
  }

  // Fill maps of Free, Contigous and Multiple edges
  //TopTools_DataMapIteratorOfDataMapOfShapeListOfShape iter2(edgeSections);
  for (i = 1; i <= edgeSections.Extent(); i++) {
    const TopoDS_Shape& edge = edgeSections.FindKey(i);
    const TopTools_ListOfShape& listSection = edgeSections(i);
    if (listSection.Extent() == 1) {
      if (BRep_Tool::Degenerated(TopoDS::Edge(edge)))
	myDegenerated.Add(edge);
      else
	myFreeEdges.Add(edge);
    }
    else if (listSection.Extent() == 2) {
      myContigousEdges.Add(edge,listSection);
    }
    else {
      myMultipleEdges.Add(edge);
    }
  }

  // constructs myContigSectBound
  TopTools_DataMapOfShapeListOfShape aEdgeMap; //gka
  for (i = 1; i <= myBoundFaces.Extent(); i++) {
    TopoDS_Shape bound = myBoundFaces.FindKey(i);
    if (myBoundSections.IsBound(bound)) {
      TopTools_ListIteratorOfListOfShape iter(myBoundSections(bound));
      for (; iter.More(); iter.Next()) {
	TopoDS_Shape section = iter.Value();
        if(!myMergedEdges.Contains(section)) continue;
	//if (!myReShape->IsRecorded(section)) continue; // section is free
	TopoDS_Shape nedge = myReShape->Apply(section);
	if (nedge.IsNull()) continue; //szv debug
	if (!bound.IsSame(section))
	  if (myContigousEdges.Contains(nedge))
	    myContigSecBound.Bind(section, bound);
      }
    }
  }
}

//=======================================================================
//function : ProjectPointsOnCurve
//purpose  : internal use
//=======================================================================

void BRepBuilderAPI_Sewing::ProjectPointsOnCurve(const TColgp_Array1OfPnt& arrPnt,
					   const Handle(Geom_Curve)& c3d,
					   const Standard_Real first,
					   const Standard_Real last,
					   TColStd_Array1OfReal& arrDist,
					   TColStd_Array1OfReal& arrPara,
					   TColgp_Array1OfPnt& arrProj) const
{
  arrDist.Init(-1.0);

  GeomAdaptor_Curve GAC(c3d);
  Extrema_ExtPC locProj;
  locProj.Initialize(GAC, first, last);
  gp_Pnt pfirst = GAC.Value(first), plast = GAC.Value(last);

  for (Standard_Integer i1 = 1; i1 <= arrPnt.Length(); i1++) {
    gp_Pnt pt = arrPnt(i1);
    Standard_Real worktol = myTolerance;
    Standard_Real distF = pfirst.Distance(pt);
    Standard_Real distL = plast.Distance(pt);
    Standard_Boolean isProjected = Standard_False;
    try {
      
      // Project current point on curve
      locProj.Perform(pt);
      if (locProj.IsDone() && locProj.NbExt() > 0) {
	Standard_Real distMin = Min(distF,distL);
	Standard_Integer ind, indMin = 0;
	for (ind = 1; ind <= locProj.NbExt(); ind++) {
	  Standard_Real dProj = locProj.Value(ind);
	  if (dProj < distMin) { indMin = ind; distMin = dProj; }
	}
	if (indMin) {
	  isProjected = Standard_True;
	  Extrema_POnCurv pOnC = locProj.Point(indMin);
	  Standard_Real paramProj = pOnC.Parameter();
	  gp_Pnt ptProj = GAC.Value(paramProj);
	  Standard_Real distProj = ptProj.Distance(pt);
	  if (!locProj.IsMin(indMin)) {
	    if (Min(distF,distL) < distMin) {
	      if (distF < distL) {
		paramProj = first;
		distProj = distF;
		ptProj = pfirst;
	      }
	      else {
		paramProj = last;
		distProj = distL;
		ptProj = plast;
	      }
	    }
	  }
	  if (distProj < worktol) {
	    arrDist(i1) = distProj;
	    arrPara(i1) = paramProj;
	    arrProj(i1) = ptProj;
	  }
	}
      }
    }
    catch (Standard_Failure) {
      worktol = MinTolerance();
#ifdef DEB
      cout << "Exception in BRepBuilderAPI_Sewing::ProjectPointsOnCurve: ";
      Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
    }
    if (!isProjected) {
      if (Min(distF,distL) < worktol) {
	if (distF < distL) {
	  arrDist(i1) = distF;
	  arrPara(i1) = first;
	  arrProj(i1) = pfirst;
	}
	else {
	  arrDist(i1) = distL;
	  arrPara(i1) = last;
	  arrProj(i1) = plast;
	}
      }
    }
  }
}

//=======================================================================
//function : CreateCuttingNodes
//purpose  : internal use
//=======================================================================

void BRepBuilderAPI_Sewing::CreateCuttingNodes(const TopTools_IndexedMapOfShape& MapVert,
					 const TopoDS_Shape& bound,
					 const TopoDS_Shape& vfirst,
					 const TopoDS_Shape& vlast,
					 const TColStd_Array1OfReal& arrDist,
					 const TColStd_Array1OfReal& arrPara,
					 const TColgp_Array1OfPnt& arrPnt,
					 TopTools_SequenceOfShape& seqVert,
					 TColStd_SequenceOfReal& seqPara)
{
  Standard_Integer i, j, nbProj = MapVert.Extent();

  // Reorder projections by distance
  TColStd_SequenceOfInteger seqOrderedIndex;
  { //szv: Use brackets to destroy local variables
    TColStd_SequenceOfReal seqOrderedDistance;
    for (i = 1; i <= nbProj; i++) {
      Standard_Real distProj = arrDist(i);
      if (distProj < 0.0) continue; // Skip vertex if not projected
      Standard_Boolean isInserted = Standard_False;
      for (j = 1; j <= seqOrderedIndex.Length() && !isInserted; j++) {
	isInserted = (distProj < seqOrderedDistance(j));
	if (isInserted) {
	  seqOrderedIndex.InsertBefore(j,i);
	  seqOrderedDistance.InsertBefore(j,distProj);
	}
      }
      if (!isInserted) {
	seqOrderedIndex.Append(i);
	seqOrderedDistance.Append(distProj);
      }
    }
  }
  nbProj = seqOrderedIndex.Length();
  if (!nbProj) return;

  BRep_Builder aBuilder;

  // Insert two initial vertices (to be removed later)
  TColStd_SequenceOfReal seqDist;
  TColgp_SequenceOfPnt seqPnt;
  { //szv: Use brackets to destroy local variables
    // Retrieve bound curve
    TopLoc_Location loc;
    Standard_Real first,last;
    Handle(Geom_Curve) c3d = BRep_Tool::Curve(TopoDS::Edge(bound), loc, first, last);
    if (!loc.IsIdentity()) {
      c3d = Handle(Geom_Curve)::DownCast(c3d->Copy());
      c3d->Transform(loc.Transformation());
    }
    GeomAdaptor_Curve GAC(c3d);
    seqVert.Prepend(vfirst); seqVert.Append(vlast);
    seqPara.Prepend(first); seqPara.Append(last);
    seqDist.Prepend(-1.0); seqDist.Append(-1.0);
    seqPnt.Prepend(GAC.Value(first)); seqPnt.Append(GAC.Value(last));
  }

  TopTools_DataMapOfShapeShape NodeCuttingVertex;
  for (i = 1; i <= nbProj; i++) {

    const Standard_Integer index = seqOrderedIndex(i);
    Standard_Real disProj = arrDist(index);
    gp_Pnt pntProj = arrPnt(index);

    // Skip node if already bound to cutting vertex
    TopoDS_Shape node = myVertexNode.FindFromKey(MapVert(index));
    if (NodeCuttingVertex.IsBound(node)) continue;

    // Find the closest vertex
    Standard_Integer indexMin = 1;
    Standard_Real dist, distMin = pntProj.Distance(seqPnt(1));
    for (j = 2; j <= seqPnt.Length(); j++) {
      dist = pntProj.Distance(seqPnt(j));
      if (dist < distMin) { distMin = dist; indexMin = j; }
    }

    // Check if current point is close to one of the existent
    if (distMin <= Max(disProj*0.1,MinTolerance())) {
      // Check distance if close
      Standard_Real jdist = seqDist.Value(indexMin);
      if (jdist < 0.0) {
	// Bind new cutting node (end vertex only)
	seqDist.SetValue(indexMin,disProj);
	TopoDS_Shape cvertex = seqVert.Value(indexMin);
	NodeCuttingVertex.Bind(node,cvertex);
      }
      else {
	// Bind secondary cutting nodes
	NodeCuttingVertex.Bind(node,TopoDS_Vertex());
      }
    }
    else {
      // Build new cutting vertex
      TopoDS_Vertex cvertex;
      aBuilder.MakeVertex(cvertex, pntProj, Precision::Confusion());
      // Bind new cutting vertex
      NodeCuttingVertex.Bind(node,cvertex);
      // Insert cutting vertex in the sequences
      Standard_Real parProj = arrPara(index);
      for (j = 2; j <= seqPara.Length(); j++) {
	if (parProj <= seqPara.Value(j)) {
	  seqVert.InsertBefore(j,cvertex);
	  seqPara.InsertBefore(j,parProj);
	  seqDist.InsertBefore(j,disProj);
	  seqPnt.InsertBefore (j,pntProj);
	  break;
	}
      }
    }
  }

  // filling map for cutting nodes
  TopTools_DataMapIteratorOfDataMapOfShapeShape mit(NodeCuttingVertex);
  for (; mit.More(); mit.Next()) {
    TopoDS_Shape cnode = mit.Value();
    // Skip secondary nodes
    if (cnode.IsNull()) continue;
    // Obtain vertex node
    TopoDS_Shape node = mit.Key();
    if (myVertexNode.Contains(cnode)) {
      // This is an end vertex
      cnode = myVertexNode.FindFromKey(cnode);
    }
    else {
      // Create link: cutting vertex -> node
      TopTools_ListOfShape ls;
      ls.Append(node);
      myCuttingNode.Bind(cnode,ls);
    }
    // Create link: node -> cutting vertex
    if (myCuttingNode.IsBound(node)) {
      myCuttingNode.ChangeFind(node).Append(cnode);
    }
    else {
      TopTools_ListOfShape ls;
      ls.Append(cnode);
      myCuttingNode.Bind(node,ls);
    }
  }

  // Remove two initial vertices
  seqVert.Remove(1); seqVert.Remove(seqVert.Length());
  seqPara.Remove(1); seqPara.Remove(seqPara.Length());
}

//=======================================================================
//function : CreateSections
//purpose  : internal use
//=======================================================================

void BRepBuilderAPI_Sewing::CreateSections(const TopoDS_Shape& section,
				     const TopTools_SequenceOfShape& seqNode,
				     const TColStd_SequenceOfReal& seqPara,
				     TopTools_ListOfShape& listEdge)
{
  const TopoDS_Edge& sec = TopoDS::Edge(section);
//  TopAbs_Orientation aInitOr = sec.Orientation();

  
//To keep NM vertices on edge
  TopTools_SequenceOfShape aSeqNMVert;
  TColStd_SequenceOfReal aSeqNMPars;
  Standard_Boolean hasNMVert = findNMVertices(sec,aSeqNMVert,aSeqNMPars);
  BRep_Builder aBuilder;

  Standard_Real first, last;
  BRep_Tool::Range(sec, first, last);

  // Create cutting sections
  Standard_Real par1, par2;
  TopoDS_Shape V1, V2;
  Standard_Integer i, len = seqPara.Length() + 1;
  for (i = 1; i <= len; i++) {

    TopoDS_Edge edge = sec;
    edge.EmptyCopy();

    if (i == 1) {
      par1 = first;
      par2 = seqPara(i);
      V1 = TopExp::FirstVertex(sec);
      V2 = seqNode(i);
    }
    else if (i == len) {
      par1 = seqPara(i-1);
      par2 = last;
      V1 = seqNode(i-1);
      V2 = TopExp::LastVertex(sec);
    }
    else {
      par1 = seqPara(i-1);
      par2 = seqPara(i);
      V1 = seqNode(i-1);
      V2 = seqNode(i);
    }

    TopoDS_Shape aTmpShape = edge.Oriented(TopAbs_FORWARD);
    TopoDS_Edge aTmpEdge = TopoDS::Edge (aTmpShape); // for porting
    aTmpShape = V1.Oriented(TopAbs_FORWARD);
    aBuilder.Add(aTmpEdge, aTmpShape);
    aTmpShape = V2.Oriented(TopAbs_REVERSED);
    aBuilder.Add(aTmpEdge, aTmpShape);
    aBuilder.Range(aTmpEdge, par1, par2);
//    if(aInitOr == TopAbs_REVERSED)
//      listEdge.Prepend(edge);
//    else
    
    Standard_Integer k =1;
    for( ; k <=  aSeqNMPars.Length() ; k++) {
      Standard_Real apar = aSeqNMPars.Value(k);
      if(apar >= par1 && apar <= par2) {
        aBuilder.Add(aTmpEdge,aSeqNMVert.Value(k));
        aSeqNMVert.Remove(k);
        aSeqNMPars.Remove(k);
        k--;
      }
     }
     listEdge.Append(edge);
  }

  const TopTools_ListOfShape& listFaces = myBoundFaces.FindFromKey(sec);
  if (!listFaces.Extent()) return;

  Standard_Real tolEdge = BRep_Tool::Tolerance(sec);

  // Add cutting pcurves
  TopTools_ListIteratorOfListOfShape itf(listFaces);
  for (; itf.More(); itf.Next()) {

    const TopoDS_Face& fac = TopoDS::Face(itf.Value());
    
    // Retrieve curve on surface
    Standard_Real first2d=0., last2d=0.,first2d1=0,last2d1=0.;
    Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(sec, fac, first2d, last2d);
    if (c2d.IsNull()) continue;

    Standard_Boolean isSeam = BRep_Tool::IsClosed(sec,fac);

    // Convert pcurve to BSpline
    Handle(Geom2d_BSplineCurve) c2dBSP,c2dBSP1;
    if (c2d->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
      c2dBSP = Handle(Geom2d_BSplineCurve)::DownCast(c2d);
    }
    else {
      if (first > (c2d->FirstParameter() + Precision::PConfusion()) ||
	  last < (c2d->LastParameter() - Precision::PConfusion())) {
	Handle(Geom2d_TrimmedCurve) TC = new Geom2d_TrimmedCurve(c2d, first, last);
	c2dBSP = Geom2dConvert::CurveToBSplineCurve(TC);
      }
      else c2dBSP = Geom2dConvert::CurveToBSplineCurve(c2d);
    }
    if (c2dBSP.IsNull()) continue;
    //gka fix for bug OCC12203 21.04.06 addition second curve for seam edges
    if(isSeam)
    {
      TopoDS_Edge secRev = TopoDS::Edge(sec.Reversed());
      
      Handle(Geom2d_Curve) c2d1 = BRep_Tool::CurveOnSurface(secRev, fac, first2d1, last2d1);
      if (c2d1.IsNull()) continue;
      if (c2d1->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
        c2dBSP1 = Handle(Geom2d_BSplineCurve)::DownCast(c2d1);
      }
      else {
        if (first > (c2d1->FirstParameter() + Precision::PConfusion()) ||
            last < (c2d1->LastParameter() - Precision::PConfusion())) {
          Handle(Geom2d_TrimmedCurve) TC = new Geom2d_TrimmedCurve(c2d1, first, last);
          c2dBSP1 = Geom2dConvert::CurveToBSplineCurve(TC);
        }
        else c2dBSP1 = Geom2dConvert::CurveToBSplineCurve(c2d);
      
      }
    }

    first2d = c2dBSP->FirstParameter();
    last2d = c2dBSP->LastParameter();
    if(!c2dBSP1.IsNull()) {
      first2d1 = c2dBSP1->FirstParameter();
      last2d1 = c2dBSP1->LastParameter();
    }
      
    // Update cutting sections
    Handle(Geom2d_Curve) c2dNew,c2d1New;
    TopTools_ListIteratorOfListOfShape ite(listEdge);
    for (; ite.More(); ite.Next()) {

      // Retrieve cutting section
      const TopoDS_Edge& edge = TopoDS::Edge(ite.Value());
      BRep_Tool::Range(edge, par1, par2);

      // Cut BSpline pcurve
      try {
        
	c2dNew = Handle(Geom2d_Curve)::DownCast(c2dBSP->Copy());
	Handle(Geom2d_BSplineCurve)::DownCast(c2dNew)->Segment(Max(first2d,par1),Min(par2,last2d));
        if(!c2dBSP1.IsNull()) {
          c2d1New = Handle(Geom2d_Curve)::DownCast(c2dBSP1->Copy());
          Handle(Geom2d_BSplineCurve)::DownCast(c2d1New)->Segment(Max(first2d1,par1),Min(par2,last2d1));
        }
      }
      catch (Standard_Failure) {
#ifdef DEB
	cout << "Exception in CreateSections: segment [" << par1 << "," << par2 << "]: ";
	Standard_Failure::Caught()->Print(cout); cout << endl;
#endif
	Handle(Geom2d_TrimmedCurve) c2dT = new Geom2d_TrimmedCurve(c2dNew,Max(first2d,par1),Min(par2,last2d));
	c2dNew = c2dT;
      }
              

      if(!isSeam && c2d1New.IsNull())
        aBuilder.UpdateEdge(edge, c2dNew, fac, tolEdge);
      else {
        TopAbs_Orientation Ori = edge.Orientation();
        if(fac.Orientation() == TopAbs_REVERSED)
          Ori = TopAbs::Reverse(Ori);
        
        if(Ori == TopAbs_FORWARD)
          aBuilder.UpdateEdge(edge, c2dNew,c2d1New ,fac, tolEdge);
        else
          aBuilder.UpdateEdge(edge, c2d1New,c2dNew ,fac, tolEdge);
      }
    }
  }
}
		
//=======================================================================
//function : SameParameterShape
//purpose  : 
//=======================================================================

void BRepBuilderAPI_Sewing::SameParameterShape()
{
  if (!mySameParameterMode) return;
  TopExp_Explorer exp(mySewedShape, TopAbs_EDGE);
  // Le flag sameparameter est a false pour chaque edge cousue
  for (; exp.More(); exp.Next()) {
    const TopoDS_Edge& sec = TopoDS::Edge(exp.Current());
    try {
      
      BRepLib::SameParameter(sec, BRep_Tool::Tolerance(sec));
    }
    catch (Standard_Failure) {
#ifdef DEB
      cout << "Fail: BRepBuilderAPI_Sewing::SameParameterShape exception in BRepLib::SameParameter" << endl;
#endif
      continue;
    }
  }
}
