bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh,
                                      const TopoDS_Shape& aShape,
                                      MapShapeNbElems& aResMap)
{
    int nbtri = 0, nbqua = 0;
    double fullArea = 0.0;
    for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) {
        TopoDS_Face F = TopoDS::Face( exp.Current() );
        SMESH_subMesh *sm = aMesh.GetSubMesh(F);
        MapShapeNbElemsItr anIt = aResMap.find(sm);
        if( anIt==aResMap.end() ) {
            SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
            smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
            return false;
        }
        std::vector<int> aVec = (*anIt).second;
        nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
        nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
        GProp_GProps G;
        BRepGProp::SurfaceProperties(F,G);
        double anArea = G.Mass();
        fullArea += anArea;
    }

    // collect info from edges
    int nb0d_e = 0, nb1d_e = 0;
    bool IsQuadratic = false;
    bool IsFirst = true;
    TopTools_MapOfShape tmpMap;
    for (TopExp_Explorer exp(aShape, TopAbs_EDGE); exp.More(); exp.Next()) {
        TopoDS_Edge E = TopoDS::Edge(exp.Current());
        if( tmpMap.Contains(E) )
            continue;
        tmpMap.Add(E);
        SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
        MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
        if( anIt==aResMap.end() ) {
            SMESH_ComputeErrorPtr& smError = aSubMesh->GetComputeError();
            smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
                                                  "Submesh can not be evaluated",this));
            return false;
        }
        std::vector<int> aVec = (*anIt).second;
        nb0d_e += aVec[SMDSEntity_Node];
        nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
        if(IsFirst) {
            IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
            IsFirst = false;
        }
    }
    tmpMap.Clear();

    double ELen_face = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) );
    double ELen_vol = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. );
    double ELen = Min(ELen_vol,ELen_face*2);

    GProp_GProps G;
    BRepGProp::VolumeProperties(aShape,G);
    double aVolume = G.Mass();
    double tetrVol = 0.1179*ELen*ELen*ELen;
    double CoeffQuality = 0.9;
    int nbVols = (int)aVolume/tetrVol/CoeffQuality;
    int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
    int nb1d_in = (int) ( nbVols*6 - nb1d_e - nb1d_f ) / 5;
    std::vector<int> aVec(SMDSEntity_Last);
    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
    if( IsQuadratic ) {
        aVec[SMDSEntity_Node] = nb1d_in/6 + 1 + nb1d_in;
        aVec[SMDSEntity_Quad_Tetra] = nbVols - nbqua*2;
        aVec[SMDSEntity_Quad_Pyramid] = nbqua;
    }
    else {
        aVec[SMDSEntity_Node] = nb1d_in/6 + 1;
        aVec[SMDSEntity_Tetra] = nbVols - nbqua*2;
        aVec[SMDSEntity_Pyramid] = nbqua;
    }
    SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
    aResMap.insert(std::make_pair(sm,aVec));

    return true;
}
//=============================================================================
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;
}
bool StdMeshers_RadialPrism_3D::Evaluate(SMESH_Mesh& aMesh,
                                         const TopoDS_Shape& aShape,
                                         MapShapeNbElems& aResMap)
{
  // get 2 shells
  TopoDS_Solid solid = TopoDS::Solid( aShape );
  TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid );
  TopoDS_Shape innerShell;
  int nbShells = 0;
  for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells )
    if ( !outerShell.IsSame( It.Value() ))
      innerShell = It.Value();
  if ( nbShells != 2 ) {
    std::vector<int> aResVec(SMDSEntity_Last);
    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
    SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
    aResMap.insert(std::make_pair(sm,aResVec));
    SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
    smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
    return false;
  }

  // Associate sub-shapes of the shells
  ProjectionUtils::TShapeShapeMap shape2ShapeMap;
  if ( !ProjectionUtils::FindSubShapeAssociation( outerShell, &aMesh,
                                                  innerShell, &aMesh,
                                                  shape2ShapeMap) ) {
    std::vector<int> aResVec(SMDSEntity_Last);
    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
    SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
    aResMap.insert(std::make_pair(sm,aResVec));
    SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
    smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
    return false;
  }

  // get info for outer shell
  int nb0d_Out=0, nb2d_3_Out=0, nb2d_4_Out=0;
  //TopTools_SequenceOfShape FacesOut;
  for (TopExp_Explorer exp(outerShell, TopAbs_FACE); exp.More(); exp.Next()) {
    //FacesOut.Append(exp.Current());
    SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
    MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
    std::vector<int> aVec = (*anIt).second;
    nb0d_Out += aVec[SMDSEntity_Node];
    nb2d_3_Out += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
    nb2d_4_Out += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
  }
  int nb1d_Out = 0;
  TopTools_MapOfShape tmpMap;
  for (TopExp_Explorer exp(outerShell, TopAbs_EDGE); exp.More(); exp.Next()) {
    if( tmpMap.Contains( exp.Current() ) )
      continue;
    tmpMap.Add( exp.Current() );
    SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
    MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
    std::vector<int> aVec = (*anIt).second;
    nb0d_Out += aVec[SMDSEntity_Node];
    nb1d_Out += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
  }
  tmpMap.Clear();
  for (TopExp_Explorer exp(outerShell, TopAbs_VERTEX); exp.More(); exp.Next()) {
    if( tmpMap.Contains( exp.Current() ) )
      continue;
    tmpMap.Add( exp.Current() );
    nb0d_Out++;
  }

  // get info for inner shell
  int nb0d_In=0, nb2d_3_In=0, nb2d_4_In=0;
  //TopTools_SequenceOfShape FacesIn;
  for (TopExp_Explorer exp(innerShell, TopAbs_FACE); exp.More(); exp.Next()) {
    //FacesIn.Append(exp.Current());
    SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
    MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
    std::vector<int> aVec = (*anIt).second;
    nb0d_In += aVec[SMDSEntity_Node];
    nb2d_3_In += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
    nb2d_4_In += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
  }
  int nb1d_In = 0;
  tmpMap.Clear();
  bool IsQuadratic = false;
  bool IsFirst = true;
  for (TopExp_Explorer exp(innerShell, TopAbs_EDGE); exp.More(); exp.Next()) {
    if( tmpMap.Contains( exp.Current() ) )
      continue;
    tmpMap.Add( exp.Current() );
    SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
    MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
    std::vector<int> aVec = (*anIt).second;
    nb0d_In += aVec[SMDSEntity_Node];
    nb1d_In += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
    if(IsFirst) {
      IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
      IsFirst = false;
    }
  }
  tmpMap.Clear();
  for (TopExp_Explorer exp(innerShell, TopAbs_VERTEX); exp.More(); exp.Next()) {
    if( tmpMap.Contains( exp.Current() ) )
      continue;
    tmpMap.Add( exp.Current() );
    nb0d_In++;
  }

  bool IsOK = (nb0d_Out==nb0d_In) && (nb1d_Out==nb1d_In) && 
              (nb2d_3_Out==nb2d_3_In) && (nb2d_4_Out==nb2d_4_In);
  if(!IsOK) {
    std::vector<int> aResVec(SMDSEntity_Last);
    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
    SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
    aResMap.insert(std::make_pair(sm,aResVec));
    SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
    smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
    return false;
  }

  int nbLayers = 0;
  if( myNbLayerHypo ) {
    nbLayers = myNbLayerHypo->GetNumberOfLayers();
  }
  if ( myDistributionHypo ) {
    if ( !myDistributionHypo->GetLayerDistribution() ) {
      std::vector<int> aResVec(SMDSEntity_Last);
      for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
      SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
      aResMap.insert(std::make_pair(sm,aResVec));
      SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
      smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
      return false;
    }
    TopExp_Explorer exp(outerShell, TopAbs_VERTEX);
    TopoDS_Vertex Vout = TopoDS::Vertex(exp.Current());
    TopoDS_Vertex Vin = TopoDS::Vertex( shape2ShapeMap(Vout) );
    if ( myLayerPositions.empty() ) {
      gp_Pnt pIn = BRep_Tool::Pnt(Vin);
      gp_Pnt pOut = BRep_Tool::Pnt(Vout);
      computeLayerPositions( pIn, pOut );
    }
    nbLayers = myLayerPositions.size() + 1;
  }

  std::vector<int> aResVec(SMDSEntity_Last);
  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
  if(IsQuadratic) {
    aResVec[SMDSEntity_Quad_Penta] = nb2d_3_Out * nbLayers;
    aResVec[SMDSEntity_Quad_Hexa] = nb2d_4_Out * nbLayers;
    int nb1d = ( nb2d_3_Out*3 + nb2d_4_Out*4 ) / 2;
    aResVec[SMDSEntity_Node] = nb0d_Out * ( 2*nbLayers - 1 ) - nb1d * nbLayers;
  }
  else {
    aResVec[SMDSEntity_Node] = nb0d_Out * ( nbLayers - 1 );
    aResVec[SMDSEntity_Penta] = nb2d_3_Out * nbLayers;
    aResVec[SMDSEntity_Hexa] = nb2d_4_Out * nbLayers;
  }
  SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
  aResMap.insert(std::make_pair(sm,aResVec));

  return true;
}
bool StdMeshers_RadialQuadrangle_1D2D::Evaluate(SMESH_Mesh& aMesh,
                                                const TopoDS_Shape& aShape,
                                                MapShapeNbElems& aResMap)
{
  if( aShape.ShapeType() != TopAbs_FACE ) {
    return false;
  }
  SMESH_subMesh * smf = aMesh.GetSubMesh(aShape);
  MapShapeNbElemsItr anIt = aResMap.find(smf);
  if( anIt != aResMap.end() ) {
    return false;
  }

  myLayerPositions.clear();
  gp_Pnt P0(0,0,0);
  gp_Pnt P1(100,0,0);
  computeLayerPositions(P0,P1);

  TopoDS_Edge E1,E2,E3;
  Handle(Geom_Curve) C1,C2,C3;
  double f1,l1,f2,l2,f3,l3;
  int nbe = 0;
  TopExp_Explorer exp;
  for ( exp.Init( aShape, TopAbs_EDGE ); exp.More(); exp.Next() ) {
    nbe++;
    TopoDS_Edge E = TopoDS::Edge( exp.Current() );
    if(nbe==1) {
      E1 = E;
      C1 = BRep_Tool::Curve(E,f1,l1);
    }
    else if(nbe==2) {
      E2 = E;
      C2 = BRep_Tool::Curve(E,f2,l2);
    }
    else if(nbe==3) {
      E3 = E;
      C3 = BRep_Tool::Curve(E,f3,l3);
    }
  }

  TopoDS_Edge CircEdge, LinEdge1, LinEdge2;
  int nb0d=0, nb2d_tria=0, nb2d_quad=0;
  bool isQuadratic = false;
  if(nbe==1) {
    // C1 must be a circle
    Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(C1);
    if( !aCirc.IsNull() ) {
      bool ok = _gen->Evaluate( aMesh, CircEdge, aResMap );
      if(ok) {
        SMESH_subMesh * sm = aMesh.GetSubMesh(CircEdge);
        MapShapeNbElemsItr anIt = aResMap.find(sm);
        vector<int> aVec = (*anIt).second;
        isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge];
        if(isQuadratic) {
          // main nodes
          nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
          // radial medium nodes
          nb0d += (aVec[SMDSEntity_Node]+1) * (myLayerPositions.size()+1);
          // other medium nodes
          nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
        }
        else {
          nb0d = (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
        }
        nb2d_tria = aVec[SMDSEntity_Node] + 1;
        nb2d_quad = nb0d;
      }
    }
  }
  else if(nbe==2) {
    // one curve must be a half of circle and other curve must be
    // a segment of line
    Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(C1);
    while( !tc.IsNull() ) {
      C1 = tc->BasisCurve();
      tc = Handle(Geom_TrimmedCurve)::DownCast(C1);
    }
    tc = Handle(Geom_TrimmedCurve)::DownCast(C2);
    while( !tc.IsNull() ) {
      C2 = tc->BasisCurve();
      tc = Handle(Geom_TrimmedCurve)::DownCast(C2);
    }
    Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(C1);
    Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast(C2);
    CircEdge = E1;
    LinEdge1 = E2;
    double fp = f1;
    double lp = l1;
    if( aCirc.IsNull() ) {
      aCirc = Handle(Geom_Circle)::DownCast(C2);
      CircEdge = E2;
      LinEdge1 = E1;
      fp = f2;
      lp = l2;
      aLine = Handle(Geom_Line)::DownCast(C3);
    }
    bool ok = !aCirc.IsNull() && !aLine.IsNull();
    if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) {
      // not half of circle
      ok = false;
    }
    SMESH_subMesh* sm1 = aMesh.GetSubMesh(LinEdge1);
    MapShapeNbElemsItr anIt = aResMap.find(sm1);
    if( anIt!=aResMap.end() ) {
      ok = false;
    }
    if(ok) {
      ok = _gen->Evaluate( aMesh, CircEdge, aResMap );
    }
    if(ok) {
      SMESH_subMesh * sm = aMesh.GetSubMesh(CircEdge);
      MapShapeNbElemsItr anIt = aResMap.find(sm);
      vector<int> aVec = (*anIt).second;
      isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge];
      if(isQuadratic) {
        // main nodes
        nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
        // radial medium nodes
        nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1);
        // other medium nodes
        nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
      }
      else {
        nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
      }
      nb2d_tria = aVec[SMDSEntity_Node] + 1;
      nb2d_quad = nb2d_tria * myLayerPositions.size();
      // add evaluation for edges
      vector<int> aResVec(SMDSEntity_Last);
      for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
      if(isQuadratic) {
        aResVec[SMDSEntity_Node] = 4*myLayerPositions.size() + 3;
        aResVec[SMDSEntity_Quad_Edge] = 2*myLayerPositions.size() + 2;
      }
      else {
        aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1;
        aResVec[SMDSEntity_Edge] = 2*myLayerPositions.size() + 2;
      }
      sm = aMesh.GetSubMesh(LinEdge1);
      aResMap.insert(make_pair(sm,aResVec));
    }
  }
  else { // nbe==3
    // one curve must be a part of circle and other curves must be
    // segments of line
    Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(C1);
    while( !tc.IsNull() ) {
      C1 = tc->BasisCurve();
      tc = Handle(Geom_TrimmedCurve)::DownCast(C1);
    }
    tc = Handle(Geom_TrimmedCurve)::DownCast(C2);
    while( !tc.IsNull() ) {
      C2 = tc->BasisCurve();
      tc = Handle(Geom_TrimmedCurve)::DownCast(C2);
    }
    tc = Handle(Geom_TrimmedCurve)::DownCast(C3);
    while( !tc.IsNull() ) {
      C3 = tc->BasisCurve();
      tc = Handle(Geom_TrimmedCurve)::DownCast(C3);
    }
    Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(C1);
    Handle(Geom_Line) aLine1 = Handle(Geom_Line)::DownCast(C2);
    Handle(Geom_Line) aLine2 = Handle(Geom_Line)::DownCast(C3);
    CircEdge = E1;
    LinEdge1 = E2;
    LinEdge2 = E3;
    double fp = f1;
    double lp = l1;
    if( aCirc.IsNull() ) {
      aCirc = Handle(Geom_Circle)::DownCast(C2);
      CircEdge = E2;
      LinEdge1 = E3;
      LinEdge2 = E1;
      fp = f2;
      lp = l2;
      aLine1 = Handle(Geom_Line)::DownCast(C3);
      aLine2 = Handle(Geom_Line)::DownCast(C1);
      if( aCirc.IsNull() ) {
        aCirc = Handle(Geom_Circle)::DownCast(C3);
        CircEdge = E3;
        LinEdge1 = E1;
        LinEdge2 = E2;
        fp = f3;
        lp = l3;
        aLine1 = Handle(Geom_Line)::DownCast(C1);
        aLine2 = Handle(Geom_Line)::DownCast(C2);
      }
    }
    bool ok = !aCirc.IsNull() && !aLine1.IsNull() && !aLine1.IsNull();
    SMESH_subMesh* sm = aMesh.GetSubMesh(LinEdge1);
    MapShapeNbElemsItr anIt = aResMap.find(sm);
    if( anIt!=aResMap.end() ) {
      ok = false;
    }
    sm = aMesh.GetSubMesh(LinEdge2);
    anIt = aResMap.find(sm);
    if( anIt!=aResMap.end() ) {
      ok = false;
    }
    if(ok) {
      ok = _gen->Evaluate( aMesh, CircEdge, aResMap );
    }
    if(ok) {
      SMESH_subMesh * sm = aMesh.GetSubMesh(CircEdge);
      MapShapeNbElemsItr anIt = aResMap.find(sm);
      vector<int> aVec = (*anIt).second;
      isQuadratic = aVec[SMDSEntity_Quad_Edge]>aVec[SMDSEntity_Edge];
      if(isQuadratic) {
        // main nodes
        nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
        // radial medium nodes
        nb0d += aVec[SMDSEntity_Node] * (myLayerPositions.size()+1);
        // other medium nodes
        nb0d += (aVec[SMDSEntity_Node]+1) * myLayerPositions.size();
      }
      else {
        nb0d = aVec[SMDSEntity_Node] * myLayerPositions.size();
      }
      nb2d_tria = aVec[SMDSEntity_Node] + 1;
      nb2d_quad = nb2d_tria * myLayerPositions.size();
      // add evaluation for edges
      vector<int> aResVec(SMDSEntity_Last);
      for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
      if(isQuadratic) {
        aResVec[SMDSEntity_Node] = 2*myLayerPositions.size() + 1;
        aResVec[SMDSEntity_Quad_Edge] = myLayerPositions.size() + 1;
      }
      else {
        aResVec[SMDSEntity_Node] = myLayerPositions.size();
        aResVec[SMDSEntity_Edge] = myLayerPositions.size() + 1;
      }
      sm = aMesh.GetSubMesh(LinEdge1);
      aResMap.insert(make_pair(sm,aResVec));
      sm = aMesh.GetSubMesh(LinEdge2);
      aResMap.insert(make_pair(sm,aResVec));
    }
  }

  vector<int> aResVec(SMDSEntity_Last);
  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
  SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);

  //cout<<"nb0d = "<<nb0d<<"   nb2d_tria = "<<nb2d_tria<<"   nb2d_quad = "<<nb2d_quad<<endl;
  if(nb0d>0) {
    aResVec[0] = nb0d;
    if(isQuadratic) {
      aResVec[SMDSEntity_Quad_Triangle] = nb2d_tria;
      aResVec[SMDSEntity_Quad_Quadrangle] = nb2d_quad;
    }
    else {
      aResVec[SMDSEntity_Triangle] = nb2d_tria;
      aResVec[SMDSEntity_Quadrangle] = nb2d_quad;
    }
    aResMap.insert(make_pair(sm,aResVec));
    return true;
  }

  // invalid case
  aResMap.insert(make_pair(sm,aResVec));
  SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
  smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
                                        "Submesh can not be evaluated",this));
  return false;

}
bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh,
        const TopoDS_Shape& aShape,
        MapShapeNbElems& aResMap)
{
    TopoDS_Face F = TopoDS::Face(aShape);
    if(F.IsNull())
        return false;

    // collect info from edges
    int nb0d = 0, nb1d = 0;
    bool IsQuadratic = false;
    bool IsFirst = true;
    double fullLen = 0.0;
    TopTools_MapOfShape tmpMap;
    for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) {
        TopoDS_Edge E = TopoDS::Edge(exp.Current());
        if( tmpMap.Contains(E) )
            continue;
        tmpMap.Add(E);
        SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
        MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
        if( anIt==aResMap.end() ) {
            SMESH_subMesh *sm = aMesh.GetSubMesh(F);
            SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
            smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
            return false;
        }
        std::vector<int> aVec = (*anIt).second;
        nb0d += aVec[SMDSEntity_Node];
        nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
        double aLen = SMESH_Algo::EdgeLength(E);
        fullLen += aLen;
        if(IsFirst) {
            IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
            IsFirst = false;
        }
    }
    tmpMap.Clear();

    // compute edge length
    double ELen = 0;
    if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) {
        if ( nb1d > 0 )
            ELen = fullLen / nb1d;
    }
    if ( _hypMaxElementArea ) {
        double maxArea = _hypMaxElementArea->GetMaxArea();
        ELen = sqrt(2. * maxArea/sqrt(3.0));
    }
    GProp_GProps G;
    BRepGProp::SurfaceProperties(F,G);
    double anArea = G.Mass();

    const int hugeNb = numeric_limits<int>::max()/10;
    if ( anArea / hugeNb > ELen*ELen )
    {
        SMESH_subMesh *sm = aMesh.GetSubMesh(F);
        SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
        smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this));
        return false;
    }
    int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) );
    int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
    std::vector<int> aVec(SMDSEntity_Last);
    for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
    if( IsQuadratic ) {
        aVec[SMDSEntity_Node] = nbNodes;
        aVec[SMDSEntity_Quad_Triangle] = nbFaces;
    }
    else {
        aVec[SMDSEntity_Node] = nbNodes;
        aVec[SMDSEntity_Triangle] = nbFaces;
    }
    SMESH_subMesh *sm = aMesh.GetSubMesh(F);
    aResMap.insert(std::make_pair(sm,aVec));

    return true;
}
bool StdMeshers_Projection_3D::Evaluate(SMESH_Mesh& aMesh,
                                        const TopoDS_Shape& aShape,
                                        MapShapeNbElems& aResMap)
{
  if ( !_sourceHypo )
    return false;

  SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh();
  SMESH_Mesh * tgtMesh = & aMesh;
  if ( !srcMesh )
    srcMesh = tgtMesh;

  // get shell from shape3D
  TopoDS_Shell srcShell, tgtShell;
  TopExp_Explorer exp( _sourceHypo->GetSource3DShape(), TopAbs_SHELL );
  int nbShell;
  for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell )
    srcShell = TopoDS::Shell( exp.Current() );
  if ( nbShell != 1 )
    return error(COMPERR_BAD_SHAPE,
                 SMESH_Comment("Source shape must have 1 shell but not ") << nbShell);

  exp.Init( aShape, TopAbs_SHELL );
  for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell )
    tgtShell = TopoDS::Shell( exp.Current() );
  if ( nbShell != 1 )
    return error(COMPERR_BAD_SHAPE,
                 SMESH_Comment("Target shape must have 1 shell but not ") << nbShell);

  // Check that shapes are blocks
  if ( SMESH_MesherHelper::Count( tgtShell, TopAbs_FACE , 1 ) != 6 ||
       SMESH_MesherHelper::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 ||
       SMESH_MesherHelper::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 )
    return error(COMPERR_BAD_SHAPE, "Target shape is not a block");
  if ( SMESH_MesherHelper::Count( srcShell, TopAbs_FACE , 1 ) != 6 ||
       SMESH_MesherHelper::Count( srcShell, TopAbs_EDGE , 1 ) != 12 ||
       SMESH_MesherHelper::Count( srcShell, TopAbs_WIRE , 1 ) != 6 )
    return error(COMPERR_BAD_SHAPE, "Source shape is not a block");

  // Assure that mesh on a source shape is computed

  SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() );

  if ( !srcSubMesh->IsMeshComputed() )
    return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed");


  std::vector<int> aVec(SMDSEntity_Last);
  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i] = 0;

  aVec[SMDSEntity_Node] = srcSubMesh->GetSubMeshDS()->NbNodes();

  //bool quadratic = false;
  SMDS_ElemIteratorPtr elemIt = srcSubMesh->GetSubMeshDS()->GetElements();
  while ( elemIt->more() ) {
    const SMDS_MeshElement* E  = elemIt->next();
    if( E->NbNodes()==4 ) {
      aVec[SMDSEntity_Tetra]++;
    }
    else if( E->NbNodes()==5 ) {
      aVec[SMDSEntity_Pyramid]++;
    }
    else if( E->NbNodes()==6 ) {
      aVec[SMDSEntity_Penta]++;
    }
    else if( E->NbNodes()==8 ) {
      aVec[SMDSEntity_Hexa]++;
    }
    else if( E->NbNodes()==10 && E->IsQuadratic() ) {
      aVec[SMDSEntity_Quad_Tetra]++;
    }
    else if( E->NbNodes()==13 && E->IsQuadratic() ) {
      aVec[SMDSEntity_Quad_Pyramid]++;
    }
    else if( E->NbNodes()==15 && E->IsQuadratic() ) {
      aVec[SMDSEntity_Quad_Penta]++;
    }
    else if( E->NbNodes()==20 && E->IsQuadratic() ) {
      aVec[SMDSEntity_Quad_Hexa]++;
    }
    else {
      aVec[SMDSEntity_Polyhedra]++;
    }
  }

  SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
  aResMap.insert(std::make_pair(sm,aVec));

  return true;
}
bool StdMeshers_Hexa_3D::Evaluate(SMESH_Mesh & aMesh,
                                  const TopoDS_Shape & aShape,
                                  MapShapeNbElems& aResMap)
{
  vector < SMESH_subMesh * >meshFaces;
  TopTools_SequenceOfShape aFaces;
  for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) {
    aFaces.Append(exp.Current());
    SMESH_subMesh *aSubMesh = aMesh.GetSubMeshContaining(exp.Current());
    ASSERT(aSubMesh);
    meshFaces.push_back(aSubMesh);
  }
  if (meshFaces.size() != 6) {
    //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block");
    static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen());
    return compositeHexa.Evaluate(aMesh, aShape, aResMap);
  }
  
  int i = 0;
  for(; i<6; i++) {
    //TopoDS_Shape aFace = meshFaces[i]->GetSubShape();
    TopoDS_Shape aFace = aFaces.Value(i+1);
    SMESH_Algo *algo = _gen->GetAlgo(aMesh, aFace);
    if( !algo ) {
      std::vector<int> aResVec(SMDSEntity_Last);
      for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
      SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
      aResMap.insert(std::make_pair(sm,aResVec));
      SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
      smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
      return false;
    }
    string algoName = algo->GetName();
    bool isAllQuad = false;
    if (algoName == "Quadrangle_2D") {
      MapShapeNbElemsItr anIt = aResMap.find(meshFaces[i]);
      if( anIt == aResMap.end() ) continue;
      std::vector<int> aVec = (*anIt).second;
      int nbtri = Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
      if( nbtri == 0 )
        isAllQuad = true;
    }
    if ( ! isAllQuad ) {
      return EvaluatePentahedralMesh(aMesh, aShape, aResMap);
    }
  }
  
  // find number of 1d elems for 1 face
  int nb1d = 0;
  TopTools_MapOfShape Edges1;
  bool IsQuadratic = false;
  bool IsFirst = true;
  for (TopExp_Explorer exp(aFaces.Value(1), TopAbs_EDGE); exp.More(); exp.Next()) {
    Edges1.Add(exp.Current());
    SMESH_subMesh *sm = aMesh.GetSubMesh(exp.Current());
    if( sm ) {
      MapShapeNbElemsItr anIt = aResMap.find(sm);
      if( anIt == aResMap.end() ) continue;
      std::vector<int> aVec = (*anIt).second;
      nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
      if(IsFirst) {
        IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
        IsFirst = false;
      }
    }
  }
  // find face opposite to 1 face
  int OppNum = 0;
  for(i=2; i<=6; i++) {
    bool IsOpposite = true;
    for(TopExp_Explorer exp(aFaces.Value(i), TopAbs_EDGE); exp.More(); exp.Next()) {
      if( Edges1.Contains(exp.Current()) ) {
        IsOpposite = false;
        break;
      }
    }
    if(IsOpposite) {
      OppNum = i;
      break;
    }
  }
  // find number of 2d elems on side faces
  int nb2d = 0;
  for(i=2; i<=6; i++) {
    if( i == OppNum ) continue;
    MapShapeNbElemsItr anIt = aResMap.find( meshFaces[i-1] );
    if( anIt == aResMap.end() ) continue;
    std::vector<int> aVec = (*anIt).second;
    nb2d += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
  }
  
  MapShapeNbElemsItr anIt = aResMap.find( meshFaces[0] );
  std::vector<int> aVec = (*anIt).second;
  int nb2d_face0 = Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
  int nb0d_face0 = aVec[SMDSEntity_Node];

  std::vector<int> aResVec(SMDSEntity_Last);
  for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aResVec[i] = 0;
  if(IsQuadratic) {
    aResVec[SMDSEntity_Quad_Hexa] = nb2d_face0 * ( nb2d/nb1d );
    int nb1d_face0_int = ( nb2d_face0*4 - nb1d ) / 2;
    aResVec[SMDSEntity_Node] = nb0d_face0 * ( 2*nb2d/nb1d - 1 ) - nb1d_face0_int * nb2d/nb1d;
  }
  else {
    aResVec[SMDSEntity_Node] = nb0d_face0 * ( nb2d/nb1d - 1 );
    aResVec[SMDSEntity_Hexa] = nb2d_face0 * ( nb2d/nb1d );
  }
  SMESH_subMesh * sm = aMesh.GetSubMesh(aShape);
  aResMap.insert(std::make_pair(sm,aResVec));

  return true;
}