//=======================================================================
// function: FillSameDomainFaces
// purpose:
//=======================================================================
void GEOMAlgo_Builder::FillSameDomainFaces()
{
  Standard_Boolean bIsSDF, bHasImage1, bHasImage2, bForward;
  Standard_Integer i, j, aNbFF, nF1, nF2, aNbPBInOn, aNbC, aNbSE;
  Standard_Integer aNbF1, aNbF2, i2s, aNbSD;
  TopTools_MapOfShape aMFence;
  TopTools_ListOfShape aLX1, aLX2;
  TopTools_ListIteratorOfListOfShape aItF1, aItF2;
  NMTTools_ListOfCoupleOfShape aLCS;
  //
  const NMTDS_ShapesDataStructure& aDS=*myPaveFiller->DS();
  NMTTools_PaveFiller* pPF=myPaveFiller;
  NMTDS_InterfPool* pIP=pPF->IP();
  BOPTools_CArray1OfSSInterference& aFFs=pIP->SSInterferences();
  const Handle(IntTools_Context)& aCtx= pPF->Context();
  //
  //
  //mySameDomainShapes.Clear();
  //
  // 1. For each FF find among images of faces
  //    all pairs of same domain faces (SDF) [=> aLCS]
  aNbFF=aFFs.Extent();
  for (i=1; i<=aNbFF; ++i) {
    BOPTools_SSInterference& aFF=aFFs(i);
    aFF.Indices(nF1, nF2);
    //
    const TopoDS_Face& aF1=TopoDS::Face(aDS.Shape(nF1));
    const TopoDS_Face& aF2=TopoDS::Face(aDS.Shape(nF2));
    //
    // if there are no in/on 2D split parts the faces nF1, nF2
    // can not be SDF
    const BOPTools_ListOfPaveBlock& aLPBInOn=aFF.PaveBlocks();
    aNbPBInOn=aLPBInOn.Extent();
    //
    //===
    const TColStd_ListOfInteger& aLSE=aFF.SharedEdges();
    aNbSE=aLSE.Extent();
    if (!aNbPBInOn && !aNbSE) {
      continue;
    }
    //===
    //
    // if there is at least one section edge between faces nF1, nF2
    // they can not be SDF
    BOPTools_SequenceOfCurves& aSC=aFF.Curves();
    aNbC=aSC.Length();
    if (aNbC) {
      continue;
    }
    //
    // the faces are suspected to be SDF.
    // Try to find SDF among images of nF1, nF2
    aMFence.Clear();
    //
    //--------------------------------------------------------
    bHasImage1=mySplitFaces.HasImage(aF1);
    bHasImage2=mySplitFaces.HasImage(aF2);
    //
    aLX1.Clear();
    if (!bHasImage1) {
      aLX1.Append(aF1);
    }
    //
    aLX2.Clear();
    if (!bHasImage2) {
      aLX2.Append(aF2);
    }
    //
    const TopTools_ListOfShape& aLF1r=(bHasImage1)? mySplitFaces.Image(aF1) : aLX1;
    const TopTools_ListOfShape& aLF2r=(bHasImage2)? mySplitFaces.Image(aF2) : aLX2;
    //
    TopTools_DataMapOfIntegerShape aMIS;
    TColStd_ListIteratorOfListOfInteger aItLI;
    NMTDS_BoxBndTreeSelector aSelector;
    NMTDS_BoxBndTree aBBTree;
    NCollection_UBTreeFiller <Standard_Integer, Bnd_Box> aTreeFiller(aBBTree);
    //
    aNbF1=aLF1r.Extent();
    aNbF2=aLF2r.Extent();
    bForward=(aNbF1<aNbF2);
    //
    const TopTools_ListOfShape& aLF1=bForward ? aLF1r : aLF2r;
    const TopTools_ListOfShape& aLF2=bForward ? aLF2r : aLF1r;
    //
    // 1. aTreeFiller
    aItF2.Initialize(aLF2);
    for (i2s=1; aItF2.More(); aItF2.Next(), ++i2s) {
      Bnd_Box aBoxF2s;
      //
      const TopoDS_Face& aF2s=*((TopoDS_Face*)(&aItF2.Value()));
      //
      BRepBndLib::Add(aF2s, aBoxF2s);
      //
      aMIS.Bind(i2s, aF2s);
      //
      aTreeFiller.Add(i2s, aBoxF2s);
    }//for (i2s=1; aItF2.More(); aItF2.Next(), ++i2s) {
    //
    aTreeFiller.Fill();
    //
    // 2.
    aItF1.Initialize(aLF1);
    for (j=1; aItF1.More(); aItF1.Next(), ++j) {
      Bnd_Box aBoxF1x;
      //
      const TopoDS_Face& aF1x=*((TopoDS_Face*)(&aItF1.Value()));
      //
      BRepBndLib::Add(aF1x, aBoxF1x);
      //
      aSelector.Clear();
      aSelector.SetBox(aBoxF1x);
      aNbSD=aBBTree.Select(aSelector);
      if (!aNbSD) {
        continue;
      }
      //
      const TColStd_ListOfInteger& aLI=aSelector.Indices();
      aItLI.Initialize(aLI);
      for (; aItLI.More(); aItLI.Next()) {
        i2s=aItLI.Value();
        const TopoDS_Face& aF2y=*((TopoDS_Face*)(&aMIS.Find(i2s)));
        //
        bIsSDF=NMTTools_Tools::AreFacesSameDomain(aF1x, aF2y, aCtx);
        if (bIsSDF) {
          if (aMFence.Contains(aF1x) || aMFence.Contains(aF2y)) {
            continue;
          }
          aMFence.Add(aF1x);
          aMFence.Add(aF2y);
          //
          NMTTools_CoupleOfShape aCS;
          //
          aCS.SetShape1(aF1x);
          aCS.SetShape2(aF2y);
          aLCS.Append(aCS);
          //
          if (bForward) {
            if (aF1x==aF1) {
              if (!mySplitFaces.HasImage(aF1)) {
                mySplitFaces.Bind(aF1, aF1);
              }
            }
            if (aF2y==aF2) {
              if (!mySplitFaces.HasImage(aF2)) {
                mySplitFaces.Bind(aF2, aF2);
              }
            }
          }
          else {
            if (aF1x==aF2) {
              if (!mySplitFaces.HasImage(aF2)) {
                mySplitFaces.Bind(aF2, aF2);
              }
            }
            if (aF2y==aF1) {
              if (!mySplitFaces.HasImage(aF1)) {
                mySplitFaces.Bind(aF1, aF1);
              }
            }
          }
          //
          break;
        }//if (bIsSDF) {
      }//for (; aItLI.More(); aItLI.Next()) {
    }//for (; aItF1.More(); aItF1.Next()) {
  }//for (i=1; i<=aNbFF; ++i)
  //-------------------------------------------------------------
  aNbC=aLCS.Extent();
  if (!aNbC) {
    return;
  }
  //
  // 2. Find Chains
  NMTTools_IndexedDataMapOfShapeIndexedMapOfShape aMC;
  //
  NMTTools_Tools::FindChains(aLCS, aMC);
  //
  Standard_Boolean bIsImage;
  Standard_Integer aIx, aIxMin, aNbMSDF, k, aNbMFj;
  TopoDS_Shape aFOld, aFSDmin;
  TopTools_IndexedMapOfShape aMFj;
  TopTools_DataMapOfShapeInteger aDMSI;
  //
  aItF1.Initialize(myShapes);
  for (j=1; aItF1.More(); aItF1.Next(), ++j) {
    const TopoDS_Shape& aSj=aItF1.Value();
    aMFj.Clear();
    TopExp::MapShapes(aSj, TopAbs_FACE, aMFj);
    aNbMFj=aMFj.Extent();
    for (k=1; k<=aNbMFj; ++k) {
      const TopoDS_Shape& aFk=aMFj(k);
      if (!aDMSI.IsBound(aFk)) {
	aDMSI.Bind(aFk, j);
      }
    }
  }
  //
  // 3. Fill the map of SDF mySameDomainFaces
  aNbC=aMC.Extent();
  for (i=1; i<=aNbC; ++i) {
   // const TopoDS_Shape& aF=aMC.FindKey(i);
    const TopTools_IndexedMapOfShape& aMSDF=aMC(i);
    //
    aNbMSDF=aMSDF.Extent();
    for (j=1; j<=aNbMSDF; ++j) {
      const TopoDS_Shape& aFSD=aMSDF(j);
      bIsImage=mySplitFaces.IsImage(aFSD);
      aFOld=aFSD;
      if (bIsImage) {
	aFOld=mySplitFaces.ImageFrom(aFSD);
      }
      //
      aIx=aDMSI.Find(aFOld);
      if (j==1) {
	aIxMin=aIx;
	aFSDmin=aFSD;
	continue;
      }
      else {
	if (aIx<aIxMin) {
	  aIxMin=aIx;
	  aFSDmin=aFSD;
	}
      }
    }
    //
    for (j=1; j<=aNbMSDF; ++j) {
      const TopoDS_Shape& aFSD=aMSDF(j);
      mySameDomainShapes.Add(aFSD, aFSDmin);
    }
  }
  //
}
//=======================================================================
//function : DetectVertices
//purpose  : 
//=======================================================================
void GEOMAlgo_GlueDetector::DetectVertices()
{
  Standard_Integer j, i, aNbV, aNbVSD;
  Standard_Real aTolV;
  gp_Pnt aPV;
  TColStd_ListIteratorOfListOfInteger aIt;
  TopoDS_Shape aVF;
  TopTools_IndexedMapOfShape aMV;
  TopTools_MapOfShape aMVProcessed;
  TopTools_ListIteratorOfListOfShape aItS;
  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItIm;
  TopTools_DataMapOfShapeListOfShape aMVV;
  GEOMAlgo_IndexedDataMapOfIntegerShape aMIS;
  NMTDS_IndexedDataMapOfShapeBndSphere aMSB;
  //
  NMTDS_BndSphereTreeSelector aSelector;
  NMTDS_BndSphereTree aBBTree;
  NCollection_UBTreeFiller <Standard_Integer, NMTDS_BndSphere> aTreeFiller(aBBTree);
  //
  myErrorStatus=0;
  //
  TopExp::MapShapes(myArgument, TopAbs_VERTEX, aMV);
  aNbV=aMV.Extent();
  if (!aNbV) {
    myErrorStatus=2; // no vertices in source shape
    return;
  }
  //
  for (i=1; i<=aNbV; ++i) {
    NMTDS_BndSphere aBox;
    //
    const TopoDS_Vertex& aV=*((TopoDS_Vertex*)&aMV(i));
    aPV=BRep_Tool::Pnt(aV);
    aTolV=BRep_Tool::Tolerance(aV);
    //
    aBox.SetGap(myTolerance);
    aBox.SetCenter(aPV);
    aBox.SetRadius(aTolV);
    //
    aTreeFiller.Add(i, aBox);
    //
    aMIS.Add(i, aV);
    aMSB.Add(aV, aBox); 
  }
  //
  aTreeFiller.Fill();
  //
  //---------------------------------------------------
  // Chains
  for (i=1; i<=aNbV; ++i) {
    const TopoDS_Shape& aV=aMV(i);
    //
    if (aMVProcessed.Contains(aV)) {
      continue;
    }
    //
    Standard_Integer aNbIP, aIP, aNbIP1, aIP1;
    TopTools_ListOfShape aLVSD;
    TColStd_MapOfInteger aMIP, aMIP1, aMIPC;
    TColStd_MapIteratorOfMapOfInteger aIt1;
    //
    aMIP.Add(i);
    while(1) {
      aNbIP=aMIP.Extent();
      aIt1.Initialize(aMIP);
      for(; aIt1.More(); aIt1.Next()) {
	aIP=aIt1.Key();
	if (aMIPC.Contains(aIP)) {
	  continue;
	}
	//
	const TopoDS_Shape& aVP=aMIS.FindFromKey(aIP);
	const NMTDS_BndSphere& aBoxVP=aMSB.FindFromKey(aVP);
	//
	aSelector.Clear();
	aSelector.SetBox(aBoxVP);
	//
	aNbVSD=aBBTree.Select(aSelector);
	if (!aNbVSD) {
	  continue;  // it shoild not be so [at least IP itself]    
	}
	//
	const TColStd_ListOfInteger& aLI=aSelector.Indices();
	aIt.Initialize(aLI);
	for (; aIt.More(); aIt.Next()) {
	  aIP1=aIt.Value();
	  if (aMIP.Contains(aIP1)) {
	    continue;
	  }
	  aMIP1.Add(aIP1);
	} //for (; aIt.More(); aIt.Next()) {
      }//for(; aIt1.More(); aIt1.Next()) {
      //
      aNbIP1=aMIP1.Extent();
      if (!aNbIP1) {
	break;
      }
      //
      aIt1.Initialize(aMIP);
      for(; aIt1.More(); aIt1.Next()) {
	aIP=aIt1.Key();
	aMIPC.Add(aIP);
      }
      //
      aMIP.Clear();
      aIt1.Initialize(aMIP1);
      for(; aIt1.More(); aIt1.Next()) {
	aIP=aIt1.Key();
	aMIP.Add(aIP);
      }
      aMIP1.Clear();
    }// while(1)
    //
    // Fill myImages
    aNbIP=aMIPC.Extent();
    //
    if (!aNbIP) {// no SD vertices is found
      aMVProcessed.Add(aV);
      continue;
    }
    //else { // SD vertices founded [ aMIPC ]
    aIt1.Initialize(aMIPC);
    for(j=0; aIt1.More(); aIt1.Next(), ++j) {
      aIP=aIt1.Key();
      const TopoDS_Shape& aVP=aMIS.FindFromKey(aIP);
      if (!j) {
	aVF=aVP;
      }
      aLVSD.Append(aVP);
      aMVProcessed.Add(aVP);
    }
    //}
    myImages.Bind(aVF, aLVSD);
  }// for (i=1; i<=aNbV; ++i) {
  //------------------------------
  // Origins
  aItIm.Initialize(myImages);
  for (; aItIm.More(); aItIm.Next()) {
    const TopoDS_Shape& aV=aItIm.Key();
    const TopTools_ListOfShape& aLVSD=aItIm.Value();
    aItS.Initialize(aLVSD);
    for (; aItS.More(); aItS.Next()) {
      const TopoDS_Shape& aVSD=aItS.Value();
      if (!myOrigins.IsBound(aVSD)) {
	myOrigins.Bind(aVSD, aV);
      }
    }
  }
}