//===========================================================================
//function : FillSubshapes
//purpose  : 
//===========================================================================
void NMTDS_ShapesDataStructure::FillSubshapes
  (const TopoDS_Shape& aS,
   BooleanOperations_IndexedDataMapOfShapeAncestorsSuccessors& aMSA,
   BooleanOperations_IndexedDataMapOfShapeAncestorsSuccessors& aMS) const
{
  Standard_Boolean bIsNewSubShape;
  Standard_Integer aIndexSubShape, aIndex;
  BooleanOperations_AncestorsSeqAndSuccessorsSeq aASx;
  //
  aIndex=aMSA.FindIndex(aS);
  BooleanOperations_AncestorsSeqAndSuccessorsSeq& aAS=aMSA.ChangeFromIndex(aIndex);
  //
  TopoDS_Iterator anIt(aS, Standard_True);
  for(; anIt.More(); anIt.Next()) {
    const TopoDS_Shape& aSubShape = anIt.Value();
    bIsNewSubShape = Standard_False;
    if(!aMSA.Contains(aSubShape)) {
      bIsNewSubShape=!bIsNewSubShape;
      aIndexSubShape=aMSA.Add(aSubShape, aASx);
      aMS.Add(aSubShape, aASx);
    }
    else {
      aIndexSubShape=aMSA.FindIndex(aSubShape);
    }
    aAS.SetNewSuccessor(aIndexSubShape);
    aAS.SetNewOrientation(aSubShape.Orientation());
    //
    if(bIsNewSubShape && (aSubShape.ShapeType() != TopAbs_VERTEX)) {
      FillSubshapes(aSubShape, aMSA, aMS);
    }
  }
}
//=======================================================================
// function:  CommonPaveBlocks
// purpose:   get all CommonPaveBlocks
//=======================================================================
  const BOPTools_ListOfPaveBlock& NMTTools_CommonBlockAPI::CommonPaveBlocks(const Standard_Integer anE) const
{
  Standard_Integer anECurrent;
  BOPTools_ListIteratorOfListOfPaveBlock anItPB;
  //
  BOPTools_ListOfPaveBlock* pmyListOfPaveBlock=(BOPTools_ListOfPaveBlock*) &myListOfPaveBlock;
  pmyListOfPaveBlock->Clear();

  NMTTools_ListOfCommonBlock* pListOfCommonBlock=(NMTTools_ListOfCommonBlock*)myListOfCommonBlock;

  NMTTools_ListIteratorOfListOfCommonBlock anIt(*pListOfCommonBlock);
  for (; anIt.More(); anIt.Next()) {
    const NMTTools_CommonBlock& aCB=anIt.Value();
    //
    const BOPTools_ListOfPaveBlock& aLPB=aCB.PaveBlocks();
    anItPB.Initialize(aLPB);
    for (; anItPB.More(); anItPB.Next()) {
      const BOPTools_PaveBlock& aPB=anItPB.Value();
      anECurrent=aPB.OriginalEdge();
      if (anECurrent==anE) {
        pmyListOfPaveBlock->Append(aPB);
        break;
      }
    }
  }
  return myListOfPaveBlock;
}
//=======================================================================
// function:  IsCommonBlock
// purpose:
//=======================================================================
  Standard_Boolean NMTTools_CommonBlockAPI::IsCommonBlock(const BOPTools_PaveBlock& aPB) const
{
  Standard_Integer anE;
  //
  anE=aPB.OriginalEdge();
  //
  CommonPaveBlocks(anE);
  //
  BOPTools_ListIteratorOfListOfPaveBlock anIt(myListOfPaveBlock);
  for (; anIt.More(); anIt.Next()) {
    const BOPTools_PaveBlock& aPB1=anIt.Value();
    if (aPB1.IsEqual(aPB)) {
      return Standard_True;
    }
  }
  return Standard_False;
}
//=======================================================================
// function: SplitIndex
// purpose:
//=======================================================================
Standard_Integer NMTTools_PaveFiller::SplitIndex
  (const BOPTools_PaveBlock& aPBx) const
{
  Standard_Integer anOriginalEdge, anEdgeIndex=0;

  anOriginalEdge=aPBx.OriginalEdge();

  const BOPTools_ListOfPaveBlock& aLPB=mySplitShapesPool(myDS->RefEdge(anOriginalEdge));
  //
  BOPTools_ListIteratorOfListOfPaveBlock anIt(aLPB);
  for (; anIt.More(); anIt.Next()) {
    BOPTools_PaveBlock& aPB=anIt.Value();
    if (aPB.IsEqual(aPBx)) {
      anEdgeIndex=aPB.Edge();
      return anEdgeIndex;
    }
  }
  return anEdgeIndex;
}
//=======================================================================
// function: FindPave
// purpose:
//=======================================================================
Standard_Boolean NMTTools_PaveFiller::FindPave(const gp_Pnt& aP,
                                               const Standard_Real aTolPV,
                                               const BOPTools_PaveSet& aPS,
                                               BOPTools_Pave& aPave)
{
  Standard_Integer nV;
  Standard_Boolean bIsVertex=Standard_False;

  const BOPTools_ListOfPave& aLP=aPS.Set();
  BOPTools_ListIteratorOfListOfPave anIt(aLP);
  for (; anIt.More(); anIt.Next()) {
    const BOPTools_Pave& aPC=anIt.Value();
    nV=aPC.Index();
    const TopoDS_Vertex aV=TopoDS::Vertex(myDS->Shape(nV));//mpv
    bIsVertex=IntTools_Tools::IsVertex (aP, aTolPV, aV);
    if (bIsVertex) {
      aPave=aPC;
      return bIsVertex;
    }
  }
  return bIsVertex;
}
//=======================================================================
//function : Execute
//purpose  :
//=======================================================================
Standard_Integer GEOMImpl_Fillet1dDriver::Execute(TFunction_Logbook& log) const
{
  if (Label().IsNull()) return 0;
  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());

  GEOMImpl_IFillet1d aCI (aFunction);

  Handle(GEOM_Function) aRefShape = aCI.GetShape();
  TopoDS_Shape aShape = aRefShape->GetValue();
  if (aShape.IsNull())
    return 0;
  if (aShape.ShapeType() != TopAbs_WIRE)
    Standard_ConstructionError::Raise("Wrong arguments: polyline as wire must be given");

  TopoDS_Wire aWire = TopoDS::Wire(aShape);

  double rad = aCI.GetR();

  if ( rad < Precision::Confusion())
    return 0;

  // collect vertices for make fillet
  TopTools_ListOfShape aVertexList;
  TopTools_MapOfShape mapShape;
  int aLen = aCI.GetLength();
  if ( aLen > 0 ) {
    for (int ind = 1; ind <= aLen; ind++) {
      TopoDS_Shape aShapeVertex;
      if (GEOMImpl_ILocalOperations::GetSubShape
          (aWire, aCI.GetVertex(ind), aShapeVertex))
        if (mapShape.Add(aShapeVertex))
          aVertexList.Append( aShapeVertex );
    }
  } else { // get all vertices from wire
    TopExp_Explorer anExp( aWire, TopAbs_VERTEX );
    for ( ; anExp.More(); anExp.Next() ) {
      if (mapShape.Add(anExp.Current()))
        aVertexList.Append( anExp.Current() );
    }
  }
  if (aVertexList.IsEmpty())
    Standard_ConstructionError::Raise("Invalid input no vertices to make fillet");

  //INFO: this algorithm implemented in assumption that user can select both
  //  vertices of some edges to make fillet. In this case we should remember
  //  already modified initial edges to take care in next fillet step
  TopTools_DataMapOfShapeShape anEdgeToEdgeMap;

  //iterates on vertices, and make fillet on each couple of edges
  //collect result fillet edges in list
  TopTools_ListOfShape aListOfNewEdge;
  // remember relation between initial and modified map
  TopTools_IndexedDataMapOfShapeListOfShape aMapVToEdges;
  TopExp::MapShapesAndAncestors( aWire, TopAbs_VERTEX, TopAbs_EDGE, aMapVToEdges );
  TopTools_ListIteratorOfListOfShape anIt( aVertexList );
  for ( ; anIt.More(); anIt.Next() ) {
    TopoDS_Vertex aV = TopoDS::Vertex( anIt.Value() );
    if ( aV.IsNull() || !aMapVToEdges.Contains( aV ) )
      continue;
    const TopTools_ListOfShape& aVertexEdges = aMapVToEdges.FindFromKey( aV );
    if ( aVertexEdges.Extent() != 2 )
      continue; // no input data to make fillet
    TopoDS_Edge anEdge1 = TopoDS::Edge( aVertexEdges.First() );
    TopoDS_Edge anEdge2 = TopoDS::Edge( aVertexEdges.Last() );
    // check if initial edges already modified in previous fillet operation
    if ( anEdgeToEdgeMap.IsBound( anEdge1 ) ) anEdge1 = TopoDS::Edge(anEdgeToEdgeMap.Find( anEdge1 ));
    if ( anEdgeToEdgeMap.IsBound( anEdge2 ) ) anEdge2 = TopoDS::Edge(anEdgeToEdgeMap.Find( anEdge2 ));
    if ( anEdge1.IsNull() || anEdge2.IsNull() || anEdge1.IsSame( anEdge2 ) )
      continue; //no input data to make fillet

    // create plane on 2 edges
    gp_Pln aPlane;
    if ( !takePlane(anEdge1, anEdge2, aV, aPlane) )
      continue; // seems edges does not belong to same plane or parallel (fillet can not be build)

    GEOMImpl_Fillet1d aFilletAlgo(anEdge1, anEdge2, aPlane);
    if ( !aFilletAlgo.Perform(rad) )
      continue; // can not create fillet with given radius

    // take fillet result in given vertex
    TopoDS_Edge aModifE1, aModifE2;
    TopoDS_Edge aNewE = aFilletAlgo.Result(BRep_Tool::Pnt(aV), aModifE1, aModifE2);
    if (aNewE.IsNull())
      continue; // no result found

    // add  new created edges and take modified edges
    aListOfNewEdge.Append( aNewE );

    // check if face edges modified,
    // if yes, than map to original edges (from vertex-edges list), because edges can be modified before
    if (aModifE1.IsNull() || !anEdge1.IsSame( aModifE1 ))
      addEdgeRelation( anEdgeToEdgeMap, TopoDS::Edge(aVertexEdges.First()), aModifE1 );
    if (aModifE2.IsNull() || !anEdge2.IsSame( aModifE2 ))
      addEdgeRelation( anEdgeToEdgeMap, TopoDS::Edge(aVertexEdges.Last()), aModifE2 );
  }

  if ( anEdgeToEdgeMap.IsEmpty() && aListOfNewEdge.IsEmpty() ) {
    StdFail_NotDone::Raise("1D Fillet can't be computed on the given shape with the given radius");
    return 0;
  }

  // create new wire instead of original
  for ( TopExp_Explorer anExp( aWire, TopAbs_EDGE ); anExp.More(); anExp.Next() ) {
    TopoDS_Shape anEdge = anExp.Current();
    if ( !anEdgeToEdgeMap.IsBound( anEdge ) )
      aListOfNewEdge.Append( anEdge );
    else if (!anEdgeToEdgeMap.Find( anEdge ).IsNull())
      aListOfNewEdge.Append( anEdgeToEdgeMap.Find( anEdge ) );
  }

  GEOMImpl_IShapesOperations::SortShapes( aListOfNewEdge );

  BRepBuilderAPI_MakeWire aWireTool;
  aWireTool.Add( aListOfNewEdge );
  aWireTool.Build();
  if (!aWireTool.IsDone())
    return 0;

  aWire = aWireTool.Wire();
  aFunction->SetValue(aWire);
  log.SetTouched(Label());

  return 1;
}
//
//=======================================================================
// function: PerformEF
// purpose: 
//=======================================================================
  void NMTTools_PaveFiller::PerformEF() 
{
  Standard_Boolean bJustAdd;
  Standard_Integer n1, n2, anIndexIn, nE, nF, aNbEFs, aBlockLength;
  Standard_Integer aDiscretize;
  Standard_Real aTolE, aTolF, aDeflection;
  BooleanOperations_IndexedDataMapOfShapeInteger aMapVI;
  BOPTools_IDMapOfPaveBlockIMapOfInteger aMapCB;
  BOPTools_IMapOfPaveBlock aIMPBx;
  //
  myIsDone=Standard_False;
  aDeflection=0.01;
  aDiscretize=35;
  //
  BOPTools_CArray1OfESInterference& aEFs=myIP->ESInterferences();
  //
  myDSIt->Initialize(TopAbs_EDGE, TopAbs_FACE);
  //
  // BlockLength correction
  aNbEFs=myDSIt->BlockLength();
  aBlockLength=aEFs.BlockLength();
  if (aNbEFs > aBlockLength) {
    aEFs.SetBlockLength(aNbEFs);
  }
  //
  for (; myDSIt->More(); myDSIt->Next()) {
    myDSIt->Current(n1, n2, bJustAdd);
    //
    if(bJustAdd) {
      continue;
    }
    //
    anIndexIn = 0;
    //
    nE=n1; 
    nF=n2;
    if (myDS->GetShapeType(n2)==TopAbs_EDGE) {
      nE=n2; 
      nF=n1;
    }
    //
    // all Common Blocks for face nF
    NMTTools_ListOfCommonBlock aLCBF;
    CommonBlocksFace(nF, aLCBF);
    NMTTools_CommonBlockAPI aCBAPIF(aLCBF);
    //
    // Edge
    const TopoDS_Edge aE=TopoDS::Edge(myDS->Shape(nE));
    if (BRep_Tool::Degenerated(aE)){
      continue;
    }
    //
    // Face
    const TopoDS_Face aF=TopoDS::Face(myDS->Shape(nF));
    //
    TopTools_IndexedMapOfShape aME;
    TopExp::MapShapes(aF, TopAbs_EDGE, aME);
    if (aME.Contains(aE)) {
      continue;
    }
    //
    aTolF=BRep_Tool::Tolerance(aF);
    aTolE=BRep_Tool::Tolerance(aE);
    
    const Bnd_Box& aBBF=myDS->GetBoundingBox(nF); 
    //
    // Process each PaveBlock on edge nE
    BOPTools_ListOfPaveBlock& aLPB=mySplitShapesPool(myDS->RefEdge(nE));
    //
    BOPTools_ListIteratorOfListOfPaveBlock anIt(aLPB);
    for (; anIt.More(); anIt.Next()) {
      BOPTools_PaveBlock& aPB=anIt.Value();
      if (aCBAPIF.IsCommonBlock(aPB)) {
	continue;
      }
      //
      const IntTools_ShrunkRange& aShrunkRange=aPB.ShrunkRange();
      const IntTools_Range& aSR =aShrunkRange.ShrunkRange();
      const Bnd_Box& aBBE=aShrunkRange.BndBox();
      //
      if (aBBF.IsOut (aBBE)) {
	continue;
      }
      // 
      // EF
      IntTools_EdgeFace aEF;
      aEF.SetEdge (aE);
      aEF.SetFace (aF);
      aEF.SetTolE (aTolE);
      aEF.SetTolF (aTolF);
      aEF.SetDiscretize (aDiscretize);
      aEF.SetDeflection (aDeflection);
      // 
      aEF.SetContext((IntTools_PContext)&myContext);
      // 
      IntTools_Range anewSR = aSR;
      // 
      // Correction of the Shrunk Range 
      BOPTools_Tools::CorrectRange(aE, aF, aSR, anewSR);
      aEF.SetRange (anewSR);
      //
      aEF.Perform();
      //
      if (aEF.IsDone()) {
	Standard_Boolean bCoinsideFlag;
	Standard_Integer i, aNbCPrts;
	TopAbs_ShapeEnum aType;
	//
	const IntTools_SequenceOfCommonPrts& aCPrts=aEF.CommonParts();
	//
	aNbCPrts=aCPrts.Length();
	for (i=1; i<=aNbCPrts; ++i) {
	  anIndexIn=0;
	  //
	  const IntTools_CommonPrt& aCPart=aCPrts(i);
	  aType=aCPart.Type();
	  //
	  switch (aType) {
	    //
	    case TopAbs_VERTEX:  {
	      Standard_Boolean bIsOnPave1, bIsOnPave2;
	      Standard_Integer nVF;
	      Standard_Real aT, aTolToDecide; 
	      TopoDS_Vertex aNewVertex;
	      //
	      const IntTools_Range& aR=aCPart.Range1();
	      //
	      // New Vertex
	      VertexParameter(aCPart, aT);
	      BOPTools_Tools::MakeNewVertex(aE, aT, aF, aNewVertex);
	      //
	      //decide to add pave or not
	      aTolToDecide=5.e-8;
	      bIsOnPave1=IsOnPave(anewSR.First(), aR, aTolToDecide); 
	      bIsOnPave2=IsOnPave(anewSR.Last() , aR, aTolToDecide); 
	      //
	      if (!bIsOnPave1 && !bIsOnPave2) {
		nVF=CheckFacePaves(aNewVertex, nF);
		if (!nVF) {
		  // really new vertex
		  // Add Interference to the Pool
		  BOPTools_ESInterference anInterf (nE, nF, aCPart);
		  anIndexIn=aEFs.Append(anInterf);
		  anInterf.SetNewShape(0);
		  //
		  aMapVI.Add(aNewVertex, anIndexIn);
		  aIMPBx.Add(aPB);
		  //
		  myIP->Add(nE, nF, Standard_True, NMTDS_TI_EF);
		  //
		}// if (!nVF)
	      }// if (!bIsOnPave1 && !bIsOnPave2) 
	      //
	      //modified by NIZNHY-PKV Fri Apr 18 10:55:38 2008f
	      else {
		const BOPTools_Pave& aPave=(bIsOnPave1)? aPB.Pave1() : aPB.Pave2();
		nVF=aPave.Index();
		const TopoDS_Vertex& aVF=TopoDS::Vertex(myDS->Shape(nVF));
		BOPTools_Tools::UpdateVertex (aVF, aNewVertex);
	      }
	      //modified by NIZNHY-PKV Fri Apr 18 10:55:40 2008t
	      //
	    }// case TopAbs_VERTEX:
	      break;
	    //
	    case TopAbs_EDGE: {
	      bCoinsideFlag=BOPTools_Tools::IsBlockInOnFace(aPB, aF, myContext);
	      if (!bCoinsideFlag) {
		break;
	      }
	      //
	      // Fill aMapCB
	      if (aMapCB.Contains(aPB)) {
		TColStd_IndexedMapOfInteger& aMapF=aMapCB.ChangeFromKey(aPB);
		aMapF.Add(nF);
	      }
	      else {
		TColStd_IndexedMapOfInteger aMapF;
		aMapF.Add(nF);
		aMapCB.Add(aPB, aMapF);
	      }
	      //
	      aIMPBx.Add(aPB);
	      myIP->Add(nE, nF, Standard_True, NMTDS_TI_EF);
	    }// case TopAbs_EDGE:
	      break;

	    default:
	      break;
	  } // switch (aType) 
	} // for (i=1; i<=aNbCPrts; i++) 
      } //if (aEF.IsDone())
    } // for (; anIt.More(); anIt.Next()) 
  }// for (; myDSIt.More(); myDSIt.Next()) 
  //
  // Treat New vertices
  EFNewVertices(aMapVI);
  //
  // Add draft Common Blocks of EF type 
  EFCommonBlocks(aMapCB);
  //
  // Collect all CB we suspected to split by new vertices
  NMTTools_ListOfCommonBlock aLCBx;
  {
    Standard_Integer i, aNbPBx, nEx;
    BOPTools_IMapOfPaveBlock aMx;
    //
    aNbPBx=aIMPBx.Extent();
    for (i=1; i<=aNbPBx; ++i) {
      const BOPTools_PaveBlock& aPBx=aIMPBx(i);
      nEx=aPBx.OriginalEdge();
      NMTTools_ListOfCommonBlock& aLCB=myCommonBlockPool(myDS->RefEdge(nEx));
      if (aLCB.Extent()) {
	NMTTools_CommonBlockAPI aCBAPIx(aLCB);
	if (aCBAPIx.IsCommonBlock(aPBx)) {
	  NMTTools_CommonBlock& aCBx=aCBAPIx.CommonBlock(aPBx);
	  const BOPTools_PaveBlock& aPB1=aCBx.PaveBlock1();
	  if (!aMx.Contains(aPB1)){
	    aMx.Add(aPB1);
	    aLCBx.Append(aCBx);
	  }
	}
      }
    }
  }
  //
  // Split the common blocks above
  if (aLCBx.Extent()) {
    ReplaceCommonBlocks(aLCBx);
  }
  //
  myIsDone=Standard_True;
}
//=======================================================================
// function: Perform
// purpose: 
//=======================================================================
  void GEOMAlgo_WireSplitter::Perform()
{
  myErrorStatus=2;
  myNothingToDo=Standard_True;

  Standard_Integer index, i, aNb, aCntIn, aCntOut;
  Standard_Boolean anIsIn;
  Standard_Real anAngle;
  
  BOP_ListOfEdgeInfo emptyInfo;
  TopTools_ListIteratorOfListOfShape anItList;
  //
  // 1.Filling mySmartMap
  mySmartMap.Clear();

  anItList.Initialize(myEdges);
  for (; anItList.More(); anItList.Next()) {
    const TopoDS_Edge& anEdge = TopoDS::Edge(anItList.Value());
    //
    if (!BOPTools_Tools2D::HasCurveOnSurface (anEdge, myFace)) {
      continue;
    }
    //
    TopExp_Explorer anExpVerts (anEdge, TopAbs_VERTEX);
    for (; anExpVerts.More(); anExpVerts.Next()) {
      const TopoDS_Shape& aVertex= anExpVerts.Current();

      index = mySmartMap.FindIndex(aVertex);
      if (!index) {
	index=mySmartMap.Add(aVertex, emptyInfo);
      }
      
      BOP_ListOfEdgeInfo& aListOfEInfo=mySmartMap(index);

      BOP_EdgeInfo aEInfo;
      aEInfo.SetEdge(anEdge);
      
      TopAbs_Orientation anOr=aVertex.Orientation();

      if (anOr==TopAbs_FORWARD) {
	aEInfo.SetInFlag(Standard_False);
      }

      else if (anOr==TopAbs_REVERSED) {
	aEInfo.SetInFlag(Standard_True);
      }

      aListOfEInfo.Append(aEInfo);
    }
  }
  //
  aNb=mySmartMap.Extent();
  //
  // 2. myNothingToDo 
  myNothingToDo=Standard_True;
  
  for (i=1; i<=aNb; i++) {
    aCntIn=0;
    aCntOut=0;
    const BOP_ListOfEdgeInfo& aLEInfo= mySmartMap(i);
    BOP_ListIteratorOfListOfEdgeInfo anIt(aLEInfo);
    for (; anIt.More(); anIt.Next()) {
      const BOP_EdgeInfo& anEdgeInfo=anIt.Value();
      anIsIn=anEdgeInfo.IsIn();
      if (anIsIn) {
	aCntIn++;
      }
      else {
	aCntOut++;
      }
    }
    if (aCntIn!=1 || aCntOut!=1) {
      myNothingToDo=Standard_False;
      break;
    }
  }
  //
  // Each vertex has one edge In and one - Out. Good. But it is not enought
  // to consider that nothing to do with this. We must check edges on TShape
  // coinsidence. If there are such edges there is something to do with.
  // 
  if (myNothingToDo) {
    Standard_Integer aNbE, aNbMapEE;
    TopTools_IndexedDataMapOfShapeListOfShape aMapEE;
    aNbE=myEdges.Extent();
    
    anItList.Initialize(myEdges);
    for (; anItList.More(); anItList.Next()) {
      const TopoDS_Shape& aE = anItList.Value();
      
      if (!aMapEE.Contains(aE)) {
	TopTools_ListOfShape aLEx;
	aLEx.Append(aE);
	aMapEE.Add(aE, aLEx);
      }
      else {
	TopTools_ListOfShape& aLEx=aMapEE.ChangeFromKey(aE);
	aLEx.Append(aE);
      }
    }
    
    Standard_Boolean bFlag;
    bFlag=Standard_True;
    aNbMapEE=aMapEE.Extent();
    for (i=1; i<=aNbMapEE; i++) {
      const TopTools_ListOfShape& aLEx=aMapEE(i);
      aNbE=aLEx.Extent();
      if (aNbE==1) {
	// usual case
	continue;
      }
      else if (aNbE==2){
	const TopoDS_Shape& aE1=aLEx.First();
	const TopoDS_Shape& aE2=aLEx.Last();
	if (aE1.IsSame(aE2)) {
	  bFlag=Standard_False;
	  break;
	}
      }
      else {
	bFlag=Standard_False;
	break;
      }
    }
    myNothingToDo=myNothingToDo && bFlag;
  }
  // 
  //
  if (myNothingToDo) {
    myErrorStatus=0;
    return;
  }
  //
  // 3. Angles in mySmartMap
  BRepAdaptor_Surface aBAS(myFace);
  const GeomAdaptor_Surface& aGAS=aBAS.Surface();
  for (i=1; i<=aNb; i++) {
    const TopoDS_Vertex& aV=TopoDS::Vertex (mySmartMap.FindKey(i));
    const BOP_ListOfEdgeInfo& aLEInfo= mySmartMap(i);

    BOP_ListIteratorOfListOfEdgeInfo anIt(aLEInfo);
    for (; anIt.More(); anIt.Next()) {
      BOP_EdgeInfo& anEdgeInfo=anIt.Value();
      const TopoDS_Edge& aE=anEdgeInfo.Edge();
      //
      TopoDS_Vertex aVV=aV;
      //
      anIsIn=anEdgeInfo.IsIn();
      if (anIsIn) {
	//
	aVV.Orientation(TopAbs_REVERSED);
	anAngle=Angle2D (aVV, aE, myFace, aGAS, Standard_True);
      }
      // 
      else { // OUT
	//
	aVV.Orientation(TopAbs_FORWARD);
	anAngle=Angle2D (aVV, aE, myFace, aGAS, Standard_False);
      }
      anEdgeInfo.SetAngle(anAngle);
      
    }
  }
  //
  // 4. Do
  //
  Standard_Boolean anIsOut, anIsNotPassed;
  
  TopTools_SequenceOfShape aLS, aVertVa;
  TColgp_SequenceOfPnt2d aCoordVa;
  
  BOP_ListIteratorOfListOfEdgeInfo anIt;

  for (i=1; i<=aNb; i++) {
    const TopoDS_Vertex aVa=TopoDS::Vertex (mySmartMap.FindKey(i));
    const BOP_ListOfEdgeInfo& aLEInfo=mySmartMap(i);
    
    anIt.Initialize(aLEInfo);
    for (; anIt.More(); anIt.Next()) {
      BOP_EdgeInfo& anEdgeInfo=anIt.Value();
      const TopoDS_Edge& aEOuta=anEdgeInfo.Edge();
      
      anIsOut=!anEdgeInfo.IsIn();
      anIsNotPassed=!anEdgeInfo.Passed();
      
      if (anIsOut && anIsNotPassed) {
	//
	aLS.Clear();
	aVertVa.Clear();
	aCoordVa.Clear();
	//
	Path(aGAS, myFace, aVa, aEOuta, anEdgeInfo, aLS, 
	     aVertVa, aCoordVa, myShapes, mySmartMap);
      }
    }
  }
  //
  {
    Standard_Integer aNbV, aNbE;
    TopoDS_Vertex aV1, aV2;
    BOPTColStd_ListOfListOfShape aShapes;
    BOPTColStd_ListIteratorOfListOfListOfShape anItW(myShapes);
    
    for (; anItW.More(); anItW.Next()) {
      TopTools_IndexedMapOfShape aMV, aME;
      const TopTools_ListOfShape& aLE=anItW.Value();
      TopTools_ListIteratorOfListOfShape anItE(aLE);
      for (; anItE.More(); anItE.Next()) {
	const TopoDS_Edge& aE=TopoDS::Edge(anItE.Value());
	aME.Add(aE);
	TopExp::Vertices(aE, aV1, aV2);
	aMV.Add(aV1);
	aMV.Add(aV2);
      }
      aNbV=aMV.Extent();
      aNbE=aME.Extent();
      if (aNbV<=aNbE) {
	aShapes.Append(aLE);
      }
    }
    //
    myShapes.Clear();
    anItW.Initialize(aShapes);
    for (; anItW.More(); anItW.Next()) {
      const TopTools_ListOfShape& aLE=anItW.Value();
      myShapes.Append(aLE);
    }
  }
  //
  myErrorStatus=0;
}