Salome HOME
0020676: EDF 1212 GEOM: Partition operation creates vertices which causes mesh comput...
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_NETGEN_2D_ONLY.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : NETGENPlugin_NETGEN_2D_ONLY.cxx
23 // Author    : Edward AGAPOV (OCC)
24 // Project   : SALOME
25 //
26 #include "NETGENPlugin_NETGEN_2D_ONLY.hxx"
27
28 #include "NETGENPlugin_Mesher.hxx"
29
30 #include "SMDS_MeshElement.hxx"
31 #include "SMDS_MeshNode.hxx"
32 #include "SMESHDS_Mesh.hxx"
33 #include "SMESH_Comment.hxx"
34 #include "SMESH_Gen.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_MesherHelper.hxx"
37 #include "StdMeshers_FaceSide.hxx"
38 #include "StdMeshers_MaxElementArea.hxx"
39 #include "StdMeshers_LengthFromEdges.hxx"
40 #include "StdMeshers_QuadranglePreference.hxx"
41
42 #include <Precision.hxx>
43 #include <Standard_ErrorHandler.hxx>
44 #include <Standard_Failure.hxx>
45
46 #include "utilities.h"
47
48 #include <list>
49 #include <vector>
50 #include <limits>
51
52 /*
53   Netgen include files
54 */
55 namespace nglib {
56 #include <nglib.h>
57 }
58 #define OCCGEOMETRY
59 #include <occgeom.hpp>
60 #include <meshing.hpp>
61 //#include <meshtype.hpp>
62 namespace netgen {
63   extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
64   /*extern*/ MeshingParameters mparam;
65 }
66
67 using namespace std;
68 using namespace netgen;
69 using namespace nglib;
70
71 //#define DUMP_SEGMENTS
72
73 //=============================================================================
74 /*!
75  *  
76  */
77 //=============================================================================
78
79 NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, int studyId,
80                                                          SMESH_Gen* gen)
81   : SMESH_2D_Algo(hypId, studyId, gen)
82 {
83   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY");
84   _name = "NETGEN_2D_ONLY";
85   
86   _shapeType = (1 << TopAbs_FACE);// 1 bit /shape type
87
88   _compatibleHypothesis.push_back("MaxElementArea");
89   _compatibleHypothesis.push_back("LengthFromEdges");
90   _compatibleHypothesis.push_back("QuadranglePreference");
91
92   _hypMaxElementArea = 0;
93   _hypLengthFromEdges = 0;
94   _hypQuadranglePreference = 0;
95 }
96
97 //=============================================================================
98 /*!
99  *  
100  */
101 //=============================================================================
102
103 NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY()
104 {
105   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY");
106 }
107
108 //=============================================================================
109 /*!
110  *  
111  */
112 //=============================================================================
113
114 bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh&         aMesh,
115                                                    const TopoDS_Shape& aShape,
116                                                    Hypothesis_Status&  aStatus)
117 {
118   _hypMaxElementArea = 0;
119   _hypLengthFromEdges = 0;
120   _hypQuadranglePreference = 0;
121
122   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape, false);
123
124   if (hyps.empty())
125   {
126     aStatus = HYP_OK; //SMESH_Hypothesis::HYP_MISSING;
127     return true;  // (PAL13464) can work with no hypothesis, LengthFromEdges is default one
128   }
129
130   aStatus = HYP_MISSING;
131
132   list<const SMESHDS_Hypothesis*>::const_iterator ith;
133   for (ith = hyps.begin(); ith != hyps.end(); ++ith )
134   {
135     const SMESHDS_Hypothesis* hyp = (*ith);
136
137     string hypName = hyp->GetName();
138
139     if      ( hypName == "MaxElementArea")
140       _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea*> (hyp);
141     else if ( hypName == "LengthFromEdges" )
142       _hypLengthFromEdges = static_cast<const StdMeshers_LengthFromEdges*> (hyp);
143     else if ( hypName == "QuadranglePreference" )
144       _hypQuadranglePreference = static_cast<const StdMeshers_QuadranglePreference*>(hyp);
145     else {
146       aStatus = HYP_INCOMPATIBLE;
147       return false;
148     }
149   }
150
151   if ( _hypMaxElementArea && _hypLengthFromEdges ) {
152     aStatus = HYP_CONCURENT;
153     return false;
154   }
155
156   if ( _hypMaxElementArea || _hypLengthFromEdges || _hypQuadranglePreference)
157     aStatus = HYP_OK;
158
159   return aStatus == HYP_OK;
160 }
161
162 //================================================================================
163 /*!
164  * \brief Fill netgen mesh with segments
165   * \retval SMESH_ComputeErrorPtr - error description
166  */
167 //================================================================================
168
169 static TError AddSegmentsToMesh(netgen::Mesh&                    ngMesh,
170                                 OCCGeometry&                     geom,
171                                 const TSideVector&               wires,
172                                 SMESH_MesherHelper&              helper,
173                                 vector< const SMDS_MeshNode* > & nodeVec)
174 {
175   // ----------------------------
176   // Check wires and count nodes
177   // ----------------------------
178   int nbNodes = 0;
179   double totalLength = 0;
180   for ( int iW = 0; iW < wires.size(); ++iW )
181   {
182     StdMeshers_FaceSidePtr wire = wires[ iW ];
183     if ( wire->MissVertexNode() )
184       return TError
185         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, "Missing nodes on vertices"));
186       
187     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
188     if ( uvPtVec.size() != wire->NbPoints() )
189       return TError
190         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,
191                                 SMESH_Comment("Unexpected nb of points on wire ") << iW
192                                 << ": " << uvPtVec.size()<<" != "<<wire->NbPoints()));
193     nbNodes += wire->NbPoints();
194     totalLength += wire->Length();
195   }
196   nodeVec.reserve( nbNodes );
197
198   // -----------------
199   // Fill netgen mesh
200   // -----------------
201
202 //   netgen::Box<3> bb = geom.GetBoundingBox();
203 //   bb.Increase (bb.Diam()/10);
204 //   ngMesh.SetLocalH (bb.PMin(), bb.PMax(), 0.5); // set grading
205
206   // map for nodes on vertices since they can be shared between wires
207   // ( issue 0020676, face_int_box.brep)
208   map<const SMDS_MeshNode*, int > node2ngID;
209
210   const int faceID = 1, solidID = 0;
211   if ( ngMesh.GetNFD() < 1 )
212     ngMesh.AddFaceDescriptor (FaceDescriptor(faceID, solidID, solidID, 0));
213
214   for ( int iW = 0; iW < wires.size(); ++iW )
215   {
216     StdMeshers_FaceSidePtr wire = wires[ iW ];
217     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
218     const int nbSegments = wire->NbPoints() - 1;
219
220     int edgeID = 1, posID = -2;
221     bool isInternalWire = false;
222     for ( int i = 0; i < nbSegments; ++i ) // loop on segments
223     {
224       // Add the first point of a segment
225       const SMDS_MeshNode * n = uvPtVec[ i ].node;
226       const int posShapeID = n->GetPosition()->GetShapeId();
227       bool onVertex = ( n->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
228
229       // skip nodes on degenerated edges
230       if ( helper.IsDegenShape( posShapeID ) &&
231            helper.IsDegenShape( uvPtVec[ i+1 ].node->GetPosition()->GetShapeId() ))
232         continue;
233
234       int ngID1 = ngMesh.GetNP() + 1, ngID2 = ngID1+1;
235       if ( onVertex )
236         ngID1 = node2ngID.insert( make_pair( n, ngID1 )).first->second;
237       if ( ngID1 > ngMesh.GetNP() )
238       {
239         MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) );
240         ngMesh.AddPoint ( mp, 1, EDGEPOINT );
241         nodeVec.push_back( n );
242       }
243       else
244       {
245         ngID2 = ngMesh.GetNP() + 1;
246         if ( i > 0 ) // prev segment belongs to same wire
247         {
248           Segment& prevSeg = ngMesh.LineSegment( ngMesh.GetNSeg() );
249           prevSeg[1] = ngID1;
250         }
251       }
252
253       // Add the segment
254       Segment seg;
255
256       seg[0] = ngID1;  // ng node id
257       seg[1] = ngID2;  // ng node id
258
259       seg.edgenr = ngMesh.GetNSeg() + 1;// segment id
260       seg.si = faceID;                  // = geom.fmap.FindIndex (face);
261
262       for ( int iEnd = 0; iEnd < 2; ++iEnd)
263       {
264         const UVPtStruct& pnt = uvPtVec[ i + iEnd ];
265
266         seg.epgeominfo[ iEnd ].dist = pnt.param; // param on curve
267         seg.epgeominfo[ iEnd ].u    = pnt.u;
268         seg.epgeominfo[ iEnd ].v    = pnt.v;
269
270         // find out edge id and node parameter on edge
271         onVertex = ( pnt.node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
272         if ( onVertex || posShapeID != posID )
273         {
274           // get edge id
275           double normParam = pnt.normParam;
276           if ( onVertex )
277             normParam = 0.5 * ( uvPtVec[ i ].normParam + uvPtVec[ i+1 ].normParam );
278           const TopoDS_Edge& edge = wire->Edge( wire->EdgeIndex( normParam ));
279           edgeID = geom.emap.FindIndex( edge );
280           posID  = posShapeID;
281           isInternalWire = ( edge.Orientation() == TopAbs_INTERNAL );
282           if ( onVertex ) // param on curve is different on each of two edges
283             seg.epgeominfo[ iEnd ].dist = helper.GetNodeU( edge, pnt.node );
284         }
285         seg.epgeominfo[ iEnd ].edgenr = edgeID; //  = geom.emap.FindIndex(edge);
286       }
287
288       ngMesh.AddSegment (seg);
289
290 #ifdef DUMP_SEGMENTS
291         cout << "Segment: " << seg.edgenr << endl
292            << "\tp1: " << seg[0] << endl
293            << "\tp2: " << seg[1] << endl
294            << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl
295            << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl
296            << "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl
297            << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl
298            << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl
299            << "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl;
300 #endif
301       if ( isInternalWire )
302       {
303         swap (seg[0], seg[1]);
304         swap( seg.epgeominfo[0], seg.epgeominfo[1] );
305         seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
306         ngMesh.AddSegment (seg);
307 #ifdef DUMP_SEGMENTS
308         cout << "Segment: " << seg.edgenr << endl << "\tis REVRESE of the previous one" << endl;
309 #endif
310       }
311     } // loop on segments on a wire
312
313     // close chain of segments
314     if ( nbSegments > 0 )
315     {
316       Segment& lastSeg = ngMesh.LineSegment( ngMesh.GetNSeg() - int( isInternalWire));
317       const SMDS_MeshNode * lastNode = uvPtVec.back().node;
318       lastSeg[1] = node2ngID.insert( make_pair( lastNode, lastSeg[1] )).first->second;
319       if ( lastSeg[1] > ngMesh.GetNP() )
320       {
321         MeshPoint mp( Point<3> (lastNode->X(), lastNode->Y(), lastNode->Z()) );
322         ngMesh.AddPoint ( mp, 1, EDGEPOINT );
323         nodeVec.push_back( lastNode );
324       }
325       if ( isInternalWire )
326       {
327         Segment& realLastSeg = ngMesh.LineSegment( ngMesh.GetNSeg() );
328         realLastSeg[0] = lastSeg[1];
329       }
330     }
331
332   } // loop on wires of a face
333
334   // add a segment instead of internal vertex
335   NETGENPlugin_Internals intShapes( *helper.GetMesh(), helper.GetSubShape(), /*is3D=*/false );
336   NETGENPlugin_Mesher::addIntVerticesInFaces( geom, ngMesh, nodeVec, intShapes );
337
338   ngMesh.CalcSurfacesOfNode();
339
340   return TError();
341 }
342
343 //=============================================================================
344 /*!
345  *Here we are going to use the NETGEN mesher
346  */
347 //=============================================================================
348
349 bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh&         aMesh,
350                                           const TopoDS_Shape& aShape)
351 {
352   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()");
353
354   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
355   int faceID = meshDS->ShapeToIndex( aShape );
356
357   SMESH_MesherHelper helper(aMesh);
358   _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
359   helper.SetElementsOnShape( true );
360   const bool ignoreMediumNodes = _quadraticMesh;
361   
362   // ------------------------
363   // get all edges of a face
364   // ------------------------
365   const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD ));
366   TError problem;
367   TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem );
368   if ( problem && !problem->IsOK() )
369     return error( problem );
370   int nbWires = wires.size();
371   if ( nbWires == 0 )
372     return error( "Problem in StdMeshers_FaceSide::GetFaceWires()");
373   if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments
374     return error(COMPERR_BAD_INPUT_MESH,
375                  SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments());
376
377   // -------------------------
378   // Make input netgen mesh
379   // -------------------------
380
381   NETGENPlugin_NetgenLibWrapper ngLib;
382   netgen::Mesh * ngMesh = (netgen::Mesh*) ngLib._ngMesh;
383
384   netgen::OCCGeometry occgeo;
385   NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh );
386   occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978)
387   occgeo.fmap.Add( F );
388
389   vector< const SMDS_MeshNode* > nodeVec;
390   problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec );
391   if ( problem && !problem->IsOK() )
392     return error( problem );
393
394   // --------------------
395   // compute edge length
396   // --------------------
397
398   double edgeLength = 0;
399   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea)
400   {
401     int nbSegments = 0;
402     for ( int iW = 0; iW < nbWires; ++iW )
403     {
404       edgeLength += wires[ iW ]->Length();
405       nbSegments += wires[ iW ]->NbSegments();
406     }
407     if ( nbSegments )
408       edgeLength /= nbSegments;
409   }
410   if ( _hypMaxElementArea )
411   {
412     double maxArea = _hypMaxElementArea->GetMaxArea();
413     edgeLength = sqrt(2. * maxArea/sqrt(3.0));
414   }
415   if ( edgeLength < DBL_MIN )
416     edgeLength = occgeo.GetBoundingBox().Diam();
417
418   //cout << " edgeLength = " << edgeLength << endl;
419
420   netgen::mparam.maxh = edgeLength;
421   netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0;
422   //ngMesh->SetGlobalH ( edgeLength );
423
424   // -------------------------
425   // Generate surface mesh
426   // -------------------------
427
428   char *optstr = 0;
429   int startWith = MESHCONST_MESHSURFACE;
430   int endWith   = MESHCONST_OPTSURFACE;
431   int err = 1;
432
433   try {
434 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
435     OCC_CATCH_SIGNALS;
436 #endif
437     err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
438   }
439   catch (Standard_Failure& ex) {
440     string comment = ex.DynamicType()->Name();
441     if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
442       comment += ": ";
443       comment += ex.GetMessageString();
444     }
445     error(COMPERR_OCC_EXCEPTION, comment);
446   }
447   catch (NgException exc) {
448     error( SMESH_Comment("NgException: ") << exc.What() );
449   }
450   catch (...) {
451     error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()");
452   }
453
454   // ----------------------------------------------------
455   // Fill the SMESHDS with the generated nodes and faces
456   // ----------------------------------------------------
457
458   int nbNodes = ngMesh->GetNP();
459   int nbFaces = ngMesh->GetNSE();
460
461   int nbInputNodes = nodeVec.size();
462   nodeVec.resize( nbNodes, 0 );
463
464   // add nodes
465   for ( int i = nbInputNodes + 1; i <= nbNodes; ++i )
466   {
467     const MeshPoint& ngPoint = ngMesh->Point(i);
468 #ifdef NETGEN_NEW
469     SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2));
470 #else
471     SMDS_MeshNode * node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z());
472 #endif
473     nodeVec[ i-1 ] = node;
474   }
475
476   // create faces
477   bool reverse = ( aShape.Orientation() == TopAbs_REVERSED );
478   for ( int i = 1; i <= nbFaces ; ++i )
479   {
480     const Element2d& elem = ngMesh->SurfaceElement(i);
481     vector<const SMDS_MeshNode*> nodes( elem.GetNP() );
482     for (int j=1; j <= elem.GetNP(); ++j)
483     {
484       int pind = elem.PNum(j);
485       const SMDS_MeshNode* node = nodeVec.at(pind-1);
486       if ( reverse )
487         nodes[ nodes.size()-j ] = node;
488       else
489         nodes[ j-1 ] = node;
490       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE )
491       {
492         const PointGeomInfo& pgi = elem.GeomInfoPi(j);
493         meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v);
494       }
495     }
496     SMDS_MeshFace* face = 0;
497     if ( elem.GetType() == TRIG )
498       face = helper.AddFace(nodes[0],nodes[1],nodes[2]);
499     else
500       face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
501   }
502
503   return !err;
504 }
505
506
507 //=============================================================================
508 /*!
509  *
510  */
511 //=============================================================================
512
513 bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh,
514                                            const TopoDS_Shape& aShape,
515                                            MapShapeNbElems& aResMap)
516 {
517   TopoDS_Face F = TopoDS::Face(aShape);
518   if(F.IsNull())
519     return false;
520
521   // collect info from edges
522   int nb0d = 0, nb1d = 0;
523   bool IsQuadratic = false;
524   bool IsFirst = true;
525   double fullLen = 0.0;
526   TopTools_MapOfShape tmpMap;
527   for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) {
528     TopoDS_Edge E = TopoDS::Edge(exp.Current());
529     if( tmpMap.Contains(E) )
530       continue;
531     tmpMap.Add(E);
532     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
533     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
534     if( anIt==aResMap.end() ) {
535       SMESH_subMesh *sm = aMesh.GetSubMesh(F);
536       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
537       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
538       return false;
539     }
540     std::vector<int> aVec = (*anIt).second;
541     nb0d += aVec[SMDSEntity_Node];
542     nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
543     double aLen = SMESH_Algo::EdgeLength(E);
544     fullLen += aLen;
545     if(IsFirst) {
546       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
547       IsFirst = false;
548     }
549   }
550   tmpMap.Clear();
551
552   // compute edge length
553   double ELen = 0;
554   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea) {
555     if ( nb1d > 0 )
556       ELen = fullLen / nb1d;
557   }
558   if ( _hypMaxElementArea ) {
559     double maxArea = _hypMaxElementArea->GetMaxArea();
560     ELen = sqrt(2. * maxArea/sqrt(3.0));
561   }
562   GProp_GProps G;
563   BRepGProp::SurfaceProperties(F,G);
564   double anArea = G.Mass();
565
566   const int hugeNb = numeric_limits<int>::max()/10;
567   if ( anArea / hugeNb > ELen*ELen )
568   {
569     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
570     SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
571     smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this));
572     return false;
573   }
574   int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) );
575   int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
576   std::vector<int> aVec(SMDSEntity_Last);
577   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
578   if( IsQuadratic ) {
579     aVec[SMDSEntity_Node] = nbNodes;
580     aVec[SMDSEntity_Quad_Triangle] = nbFaces;
581   }
582   else {
583     aVec[SMDSEntity_Node] = nbNodes;
584     aVec[SMDSEntity_Triangle] = nbFaces;
585   }
586   SMESH_subMesh *sm = aMesh.GetSubMesh(F);
587   aResMap.insert(std::make_pair(sm,aVec));
588
589   return true;
590 }