//=============================================================================
bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap)
{
#ifdef WNT
  netgen::MeshingParameters& mparams = netgen::GlobalMeshingParameters();
#else
  netgen::MeshingParameters& mparams = netgen::mparam;
#endif  


  // -------------------------
  // Prepare OCC geometry
  // -------------------------
  netgen::OCCGeometry occgeo;
  list< SMESH_subMesh* > meshedSM;
  PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM );

  bool tooManyElems = false;
  const int hugeNb = std::numeric_limits<int>::max() / 100;

  // ----------------
  // evaluate 1D 
  // ----------------
  // pass 1D simple parameters to NETGEN
  int nbs = 0;
  if ( _simpleHyp ) {
    if ( int nbSeg = _simpleHyp->GetNumberOfSegments() ) {
      nbs = nbSeg;
      // nb of segments
      mparams.segmentsperedge = nbSeg + 0.1;
      mparams.maxh = occgeo.boundingbox.Diam();
      mparams.grading = 0.01;
    }
    else {
      // segment length
      mparams.segmentsperedge = 1;
      mparams.maxh = _simpleHyp->GetLocalLength();
    }
  }
  TopTools_DataMapOfShapeInteger EdgesMap;
  double fullLen = 0.0;
  double fullNbSeg = 0;
  for (TopExp_Explorer exp(_shape, TopAbs_EDGE); exp.More(); exp.Next()) {
    TopoDS_Edge E = TopoDS::Edge( exp.Current() );
    if( EdgesMap.IsBound(E) )
      continue;
    SMESH_subMesh *sm = _mesh->GetSubMesh(E);
    std::vector<int> aVec(SMDSEntity_Last, 0);
    double aLen = SMESH_Algo::EdgeLength(E);
    fullLen += aLen;
    int nb1d = nbs;
    tooManyElems = ( aLen/hugeNb > mparams.maxh );
    if(nb1d==0 && !tooManyElems) {
      nb1d = (int)( aLen/mparams.maxh + 1 );
    }
    if ( tooManyElems ) // avoid FPE
    {
      aVec[SMDSEntity_Node] = hugeNb;
      aVec[ mparams.secondorder > 0 ? SMDSEntity_Quad_Edge : SMDSEntity_Edge] = hugeNb;
    }
    else
    {
      fullNbSeg += nb1d;
      if( mparams.secondorder > 0 ) {
        aVec[SMDSEntity_Node] = 2*nb1d - 1;
        aVec[SMDSEntity_Quad_Edge] = nb1d;
      }
      else {
        aVec[SMDSEntity_Node] = nb1d - 1;
        aVec[SMDSEntity_Edge] = nb1d;
      }
    }
    aResMap.insert(std::make_pair(sm,aVec));
    EdgesMap.Bind(E,nb1d);
  }

  // ----------------
  // evaluate 2D 
  // ----------------
  if ( _simpleHyp ) {
    if ( double area = _simpleHyp->GetMaxElementArea() ) {
      // face area
      mparams.maxh = sqrt(2. * area/sqrt(3.0));
      mparams.grading = 0.4; // moderate size growth
    }
    else {
      // length from edges
      mparams.maxh = fullLen/fullNbSeg;
      mparams.grading = 0.2; // slow size growth
    }
    mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
  }

  for (TopExp_Explorer exp(_shape, TopAbs_FACE); exp.More(); exp.Next())
  {
    TopoDS_Face F = TopoDS::Face( exp.Current() );
    SMESH_subMesh *sm = _mesh->GetSubMesh(F);
    GProp_GProps G;
    BRepGProp::SurfaceProperties(F,G);
    double anArea = G.Mass();
    tooManyElems = tooManyElems || ( anArea/hugeNb > mparams.maxh*mparams.maxh );
    int nb1d = 0;
    if ( !tooManyElems )
      for (TopExp_Explorer exp1(F,TopAbs_EDGE); exp1.More(); exp1.Next())
        nb1d += EdgesMap.Find(exp1.Current());

    int nbFaces = tooManyElems ? hugeNb : int( 4*anArea / mparams.maxh*mparams.maxh*sqrt(3.));
    int nbNodes = tooManyElems ? hugeNb : (( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );

    std::vector<int> aVec(SMDSEntity_Last, 0);
    if( mparams.secondorder > 0 ) {
      int nb1d_in = (nbFaces*3 - nb1d) / 2;
      aVec[SMDSEntity_Node] = nbNodes + nb1d_in;
      aVec[SMDSEntity_Quad_Triangle] = nbFaces;
    }
    else {
      aVec[SMDSEntity_Node] = nbNodes;
      aVec[SMDSEntity_Triangle] = nbFaces;
    }
    aResMap.insert(std::make_pair(sm,aVec));
  }

  // ----------------
  // evaluate 3D
  // ----------------
  if(_isVolume) {
    // pass 3D simple parameters to NETGEN
    const NETGENPlugin_SimpleHypothesis_3D* simple3d =
      dynamic_cast< const NETGENPlugin_SimpleHypothesis_3D* > ( _simpleHyp );
    if ( simple3d ) {
      if ( double vol = simple3d->GetMaxElementVolume() ) {
        // max volume
        mparams.maxh = pow( 72, 1/6. ) * pow( vol, 1/3. );
        mparams.maxh = min( mparams.maxh, occgeo.boundingbox.Diam()/2 );
      }
      else {
        // using previous length from faces
      }
      mparams.grading = 0.4;
    }
    GProp_GProps G;
    BRepGProp::VolumeProperties(_shape,G);
    double aVolume = G.Mass();
    double tetrVol = 0.1179*mparams.maxh*mparams.maxh*mparams.maxh;
    tooManyElems = tooManyElems || ( aVolume/hugeNb > tetrVol );
    int nbVols = tooManyElems ? hugeNb : int(aVolume/tetrVol);
    int nb1d_in = int(( nbVols*6 - fullNbSeg ) / 6 );
    std::vector<int> aVec(SMDSEntity_Last, 0 );
    if ( tooManyElems ) // avoid FPE
    {
      aVec[SMDSEntity_Node] = hugeNb;
      aVec[ mparams.secondorder > 0 ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra] = hugeNb;
    }
    else
    {
      if( mparams.secondorder > 0 ) {
        aVec[SMDSEntity_Node] = nb1d_in/3 + 1 + nb1d_in;
        aVec[SMDSEntity_Quad_Tetra] = nbVols;
      }
      else {
        aVec[SMDSEntity_Node] = nb1d_in/3 + 1;
        aVec[SMDSEntity_Tetra] = nbVols;
      }
    }
    SMESH_subMesh *sm = _mesh->GetSubMesh(_shape);
    aResMap.insert(std::make_pair(sm,aVec));
  }

  return true;
}
//=======================================================================
// 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);
    }
  }
  //
}