]> SALOME platform Git repositories - plugins/netgenplugin.git/blob - src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx
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 //=============================================================================
72 /*!
73  *  
74  */
75 //=============================================================================
76
77 NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, int studyId,
78                                                          SMESH_Gen* gen)
79   : SMESH_2D_Algo(hypId, studyId, gen)
80 {
81   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY");
82   _name = "NETGEN_2D_ONLY";
83   
84   _shapeType = (1 << TopAbs_FACE);// 1 bit /shape type
85
86   _compatibleHypothesis.push_back("MaxElementArea");
87   _compatibleHypothesis.push_back("LengthFromEdges");
88   _compatibleHypothesis.push_back("QuadranglePreference");
89
90   _hypMaxElementArea = 0;
91   _hypLengthFromEdges = 0;
92   _hypQuadranglePreference = 0;
93 }
94
95 //=============================================================================
96 /*!
97  *  
98  */
99 //=============================================================================
100
101 NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY()
102 {
103   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY");
104 }
105
106 //=============================================================================
107 /*!
108  *  
109  */
110 //=============================================================================
111
112 bool NETGENPlugin_NETGEN_2D_ONLY::CheckHypothesis (SMESH_Mesh&         aMesh,
113                                                    const TopoDS_Shape& aShape,
114                                                    Hypothesis_Status&  aStatus)
115 {
116   _hypMaxElementArea = 0;
117   _hypLengthFromEdges = 0;
118   _hypQuadranglePreference = 0;
119
120   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape, false);
121
122   if (hyps.empty())
123   {
124     aStatus = HYP_OK; //SMESH_Hypothesis::HYP_MISSING;
125     return true;  // (PAL13464) can work with no hypothesis, LengthFromEdges is default one
126   }
127
128   aStatus = HYP_MISSING;
129
130   list<const SMESHDS_Hypothesis*>::const_iterator ith;
131   for (ith = hyps.begin(); ith != hyps.end(); ++ith )
132   {
133     const SMESHDS_Hypothesis* hyp = (*ith);
134
135     string hypName = hyp->GetName();
136
137     if      ( hypName == "MaxElementArea")
138       _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea*> (hyp);
139     else if ( hypName == "LengthFromEdges" )
140       _hypLengthFromEdges = static_cast<const StdMeshers_LengthFromEdges*> (hyp);
141     else if ( hypName == "QuadranglePreference" )
142       _hypQuadranglePreference = static_cast<const StdMeshers_QuadranglePreference*>(hyp);
143     else {
144       aStatus = HYP_INCOMPATIBLE;
145       return false;
146     }
147   }
148
149   if ( _hypMaxElementArea && _hypLengthFromEdges ) {
150     aStatus = HYP_CONCURENT;
151     return false;
152   }
153
154   if ( _hypMaxElementArea || _hypLengthFromEdges || _hypQuadranglePreference)
155     aStatus = HYP_OK;
156
157   return aStatus == HYP_OK;
158 }
159
160 //================================================================================
161 /*!
162  * \brief Fill netgen mesh with segments
163   * \retval SMESH_ComputeErrorPtr - error description
164  */
165 //================================================================================
166
167 static TError AddSegmentsToMesh(netgen::Mesh&                    ngMesh,
168                                 OCCGeometry&                     geom,
169                                 const TSideVector&               wires,
170                                 SMESH_MesherHelper&              helper,
171                                 vector< const SMDS_MeshNode* > & nodeVec)
172 {
173   // ----------------------------
174   // Check wires and count nodes
175   // ----------------------------
176   int nbNodes = 0;
177   double totalLength = 0;
178   for ( int iW = 0; iW < wires.size(); ++iW )
179   {
180     StdMeshers_FaceSidePtr wire = wires[ iW ];
181     if ( wire->MissVertexNode() )
182       return TError
183         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH, "Missing nodes on vertices"));
184       
185     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
186     if ( uvPtVec.size() != wire->NbPoints() )
187       return TError
188         (new SMESH_ComputeError(COMPERR_BAD_INPUT_MESH,
189                                 SMESH_Comment("Unexpected nb of points on wire ") << iW
190                                 << ": " << uvPtVec.size()<<" != "<<wire->NbPoints()));
191     nbNodes += wire->NbPoints();
192     totalLength += wire->Length();
193   }
194   nodeVec.reserve( nbNodes );
195
196   // -----------------
197   // Fill netgen mesh
198   // -----------------
199
200 //   netgen::Box<3> bb = geom.GetBoundingBox();
201 //   bb.Increase (bb.Diam()/10);
202 //   ngMesh.SetLocalH (bb.PMin(), bb.PMax(), 0.5); // set grading
203
204   const int faceID = 1, solidID = 0;
205   if ( ngMesh.GetNFD() < 1 )
206     ngMesh.AddFaceDescriptor (FaceDescriptor(faceID, solidID, solidID, 0));
207
208   for ( int iW = 0; iW < wires.size(); ++iW )
209   {
210     StdMeshers_FaceSidePtr wire = wires[ iW ];
211     const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct();
212     const int nbSegments = wire->NbPoints() - 1;
213
214     int firstPointID = ngMesh.GetNP() + 1;
215     int edgeID = 1, posID = -2;
216     bool isInternalEdge = false;
217     for ( int i = 0; i < nbSegments; ++i ) // loop on segments
218     {
219       // Add the first point of a segment
220       const SMDS_MeshNode * n = uvPtVec[ i ].node;
221       const int posShapeID = n->GetPosition()->GetShapeId();
222
223       // skip nodes on degenerated edges
224       if ( helper.IsDegenShape( posShapeID ) &&
225            helper.IsDegenShape( uvPtVec[ i+1 ].node->GetPosition()->GetShapeId() ))
226         continue;
227
228       nodeVec.push_back( n );
229
230       MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) );
231       ngMesh.AddPoint ( mp, 1, EDGEPOINT );
232
233       // Add the segment
234       Segment seg;
235
236 #ifdef NETGEN_NEW
237       seg.pnums[0] = ngMesh.GetNP();    // ng node id
238       seg.pnums[1] = seg.pnums[0] + 1;  // ng node id
239 #else
240       seg.p1 = ngMesh.GetNP();          // ng node id
241       seg.p2 = seg.p1 + 1;              // ng node id
242 #endif
243       seg.edgenr = ngMesh.GetNSeg() + 1;// segment id
244       seg.si = faceID;                  // = geom.fmap.FindIndex (face);
245
246       for ( int iEnd = 0; iEnd < 2; ++iEnd)
247       {
248         const UVPtStruct& pnt = uvPtVec[ i + iEnd ];
249
250         seg.epgeominfo[ iEnd ].dist = pnt.param; // param on curve
251         seg.epgeominfo[ iEnd ].u    = pnt.u;
252         seg.epgeominfo[ iEnd ].v    = pnt.v;
253
254         // find out edge id and node parameter on edge
255         bool onVertex = ( pnt.node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX );
256         if ( onVertex || posShapeID != posID )
257         {
258           // get edge id
259           double normParam = pnt.normParam;
260           if ( onVertex )
261             normParam = 0.5 * ( uvPtVec[ i ].normParam + uvPtVec[ i+1 ].normParam );
262           const TopoDS_Edge& edge = wire->Edge( wire->EdgeIndex( normParam ));
263           edgeID = geom.emap.FindIndex( edge );
264           posID  = posShapeID;
265           isInternalEdge = ( edge.Orientation() == TopAbs_INTERNAL );
266           if ( onVertex ) // param on curve is different on each of two edges
267             seg.epgeominfo[ iEnd ].dist = helper.GetNodeU( edge, pnt.node );
268         }
269         seg.epgeominfo[ iEnd ].edgenr = edgeID; //  = geom.emap.FindIndex(edge);
270       }
271
272       ngMesh.AddSegment (seg);
273
274 //       cout << "Segment: " << seg.edgenr << endl
275 //            << "\tp1: " << seg.p1 << endl
276 //            << "\tp2: " << seg.p2 << endl
277 //            << "\tp0 param: " << seg.epgeominfo[ 0 ].dist << endl
278 //            << "\tp0 uv: " << seg.epgeominfo[ 0 ].u <<", "<< seg.epgeominfo[ 0 ].v << endl
279 //            << "\tp0 edge: " << seg.epgeominfo[ 0 ].edgenr << endl
280 //            << "\tp1 param: " << seg.epgeominfo[ 1 ].dist << endl
281 //            << "\tp1 uv: " << seg.epgeominfo[ 1 ].u <<", "<< seg.epgeominfo[ 1 ].v << endl
282 //            << "\tp1 edge: " << seg.epgeominfo[ 1 ].edgenr << endl;
283
284       if ( isInternalEdge )
285       {
286 #ifdef NETGEN_NEW
287         swap (seg.pnums[0], seg.pnums[1]);
288 #else
289         swap (seg.p1, seg.p2);
290 #endif
291         swap( seg.epgeominfo[0], seg.epgeominfo[1] );
292         seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
293         ngMesh.AddSegment (seg);
294       }
295     } // loop on segments on a wire
296
297     // close chain of segments
298     bool isClosedWire = ( wire->FirstVertex().IsSame( wire->LastVertex() ));
299     if ( isClosedWire )
300     {
301       Segment& seg = ngMesh.LineSegment( ngMesh.GetNSeg() );
302 #ifdef NETGEN_NEW
303       seg.pnums[1] = firstPointID;
304 #else
305       seg.p2 = firstPointID;
306 #endif
307     }
308     else // INTERNAL wire (Issue 0020676)
309     {
310       const SMDS_MeshNode * n = uvPtVec.back().node;
311       nodeVec.push_back( n );
312
313       MeshPoint mp( Point<3> (n->X(), n->Y(), n->Z()) );
314       ngMesh.AddPoint ( mp, 1, EDGEPOINT );
315     }
316
317   } // loop on wires of a face
318
319   // add a segment instead of internal vertex
320   // const TopoDS_Face& face = TopoDS::Face( helper.GetSubShape() );
321 //   for ( TopoDS_Iterator sh (face); sh.More(); sh.Next())
322 //   {
323 //     if ( sh.Value().ShapeType() != TopAbs_VERTEX ) continue;
324
325 //     const TopoDS_Vertex V = TopoDS::Vertex( sh.Value() );
326 //     SMESH_subMesh* sm = helper.GetMesh()->GetSubMesh( V );
327 //     sm->ComputeStateEngine( SMESH_subMesh::COMPUTE );
328 //     const SMDS_MeshNode * nV = SMESH_Algo::VertexNode( V, helper.GetMeshDS() );
329 //     if ( !nV ) continue;
330 //     double segLen = totalLength / ngMesh.GetNSeg() / 2;
331 //     bool uvOK = false;
332 //     gp_XY uvV = helper.GetNodeUV( face, nV, 0, &uvOK );
333 //     if ( !uvOK ) helper.CheckNodeUV( face, nV, uvV, BRep_Tool::Tolerance( V ),/*force=*/true);
334 //     gp_XY uvP( uvV.X() + segLen, uvV.Y() );
335 //     TopLoc_Location loc;
336 //     Handle(Geom_Surface) surf = BRep_Tool::Surface(face,loc);
337 //     gp_Pnt P = surf->Value( uvP.X(), uvP.Y() ).Transformed( loc );
338
339 //     MeshPoint mpV( Point<3> (nV->X(), nV->Y(), nV->Z()) );
340 //     MeshPoint mpP( Point<3> (P.X(), P.Y(), P.Z()));
341
342 //     ngMesh.AddPoint ( mpV, 1, EDGEPOINT );
343 //     ngMesh.AddPoint ( mpP, 1, EDGEPOINT );
344
345 //     nodeVec.push_back( nV );
346
347 //     // Add the segment
348 //     Segment seg;
349
350 // #ifdef NETGEN_NEW
351 //     seg.pnums[0] = ngMesh.GetNP()-1;  // ng node id
352 //     seg.pnums[1] = ngMesh.GetNP();  // ng node id
353 // #else
354 //     seg.p1 = ngMesh.GetNP()-1;  // ng node id
355 //     seg.p2 = ngMesh.GetNP(); // ng node id
356 // #endif
357 //     seg.edgenr = ngMesh.GetNSeg() + 1;// segment id
358 //     seg.si = faceID;                  // = geom.fmap.FindIndex (face);
359
360 //     seg.epgeominfo[ 0 ].dist = 0; // param on curve
361 //     seg.epgeominfo[ 0 ].u    = uvV.X();
362 //     seg.epgeominfo[ 0 ].v    = uvV.Y();
363 //     seg.epgeominfo[ 1 ].dist = segLen; // param on curve
364 //     seg.epgeominfo[ 1 ].u    = uvP.X();
365 //     seg.epgeominfo[ 1 ].v    = uvP.Y();
366
367 //     seg.epgeominfo[ 0 ].edgenr = 10; //  = geom.emap.FindIndex(edge);
368 //     seg.epgeominfo[ 1 ].edgenr = 10; //  = geom.emap.FindIndex(edge);
369
370 //     ngMesh.AddSegment (seg);
371
372 //     // add reverse segment
373 // #ifdef NETGEN_NEW
374 //     swap (seg.pnums[0], seg.pnums[1]);
375 // #else
376 //     swap (seg.p1, seg.p2);
377 // #endif
378 //     swap( seg.epgeominfo[0], seg.epgeominfo[1] );
379 //     seg.edgenr = ngMesh.GetNSeg() + 1; // segment id
380 //     ngMesh.AddSegment (seg);
381 //   }
382
383   ngMesh.CalcSurfacesOfNode();
384
385   return TError();
386 }
387
388 //=============================================================================
389 /*!
390  *Here we are going to use the NETGEN mesher
391  */
392 //=============================================================================
393
394 bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh&         aMesh,
395                                           const TopoDS_Shape& aShape)
396 {
397   MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()");
398
399   SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
400   int faceID = meshDS->ShapeToIndex( aShape );
401
402   SMESH_MesherHelper helper(aMesh);
403   _quadraticMesh = helper.IsQuadraticSubMesh(aShape);
404   helper.SetElementsOnShape( true );
405   const bool ignoreMediumNodes = _quadraticMesh;
406   
407   // ------------------------
408   // get all edges of a face
409   // ------------------------
410   const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD ));
411   TError problem;
412   TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem );
413   if ( problem && !problem->IsOK() )
414     return error( problem );
415   int nbWires = wires.size();
416   if ( nbWires == 0 )
417     return error( "Problem in StdMeshers_FaceSide::GetFaceWires()");
418   if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments
419     return error(COMPERR_BAD_INPUT_MESH,
420                  SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments());
421
422   // -------------------------
423   // Make input netgen mesh
424   // -------------------------
425
426   NETGENPlugin_NetgenLibWrapper ngLib;
427   netgen::Mesh * ngMesh = (netgen::Mesh*) ngLib._ngMesh;
428
429   netgen::OCCGeometry occgeo;
430   NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh );
431   occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978)
432   occgeo.fmap.Add( F );
433
434   vector< const SMDS_MeshNode* > nodeVec;
435   problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec );
436   if ( problem && !problem->IsOK() )
437     return error( problem );
438
439   // --------------------
440   // compute edge length
441   // --------------------
442
443   double edgeLength = 0;
444   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea)
445   {
446     int nbSegments = 0;
447     for ( int iW = 0; iW < nbWires; ++iW )
448     {
449       edgeLength += wires[ iW ]->Length();
450       nbSegments += wires[ iW ]->NbSegments();
451     }
452     if ( nbSegments )
453       edgeLength /= nbSegments;
454   }
455   if ( _hypMaxElementArea )
456   {
457     double maxArea = _hypMaxElementArea->GetMaxArea();
458     edgeLength = sqrt(2. * maxArea/sqrt(3.0));
459   }
460   if ( edgeLength < DBL_MIN )
461     edgeLength = occgeo.GetBoundingBox().Diam();
462
463   //cout << " edgeLength = " << edgeLength << endl;
464
465   netgen::mparam.maxh = edgeLength;
466   netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0;
467   //ngMesh->SetGlobalH ( edgeLength );
468
469   // -------------------------
470   // Generate surface mesh
471   // -------------------------
472
473   char *optstr = 0;
474   int startWith = MESHCONST_MESHSURFACE;
475   int endWith   = MESHCONST_OPTSURFACE;
476   int err = 1;
477
478   try {
479 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
480     OCC_CATCH_SIGNALS;
481 #endif
482     err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr);
483   }
484   catch (Standard_Failure& ex) {
485     string comment = ex.DynamicType()->Name();
486     if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) {
487       comment += ": ";
488       comment += ex.GetMessageString();
489     }
490     error(COMPERR_OCC_EXCEPTION, comment);
491   }
492   catch (NgException exc) {
493     error( SMESH_Comment("NgException: ") << exc.What() );
494   }
495   catch (...) {
496     error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()");
497   }
498
499   // ----------------------------------------------------
500   // Fill the SMESHDS with the generated nodes and faces
501   // ----------------------------------------------------
502
503   int nbNodes = ngMesh->GetNP();
504   int nbFaces = ngMesh->GetNSE();
505
506   int nbInputNodes = nodeVec.size();
507   nodeVec.resize( nbNodes, 0 );
508
509   // add nodes
510   for ( int i = nbInputNodes + 1; i <= nbNodes; ++i )
511   {
512     const MeshPoint& ngPoint = ngMesh->Point(i);
513 #ifdef NETGEN_NEW
514     SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2));
515 #else
516     SMDS_MeshNode * node = meshDS->AddNode(ngPoint.X(), ngPoint.Y(), ngPoint.Z());
517 #endif
518     nodeVec[ i-1 ] = node;
519   }
520
521   // create faces
522   bool reverse = ( aShape.Orientation() == TopAbs_REVERSED );
523   for ( int i = 1; i <= nbFaces ; ++i )
524   {
525     const Element2d& elem = ngMesh->SurfaceElement(i);
526     vector<const SMDS_MeshNode*> nodes( elem.GetNP() );
527     for (int j=1; j <= elem.GetNP(); ++j)
528     {
529       int pind = elem.PNum(j);
530       const SMDS_MeshNode* node = nodeVec.at(pind-1);
531       if ( reverse )
532         nodes[ nodes.size()-j ] = node;
533       else
534         nodes[ j-1 ] = node;
535       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE )
536       {
537         const PointGeomInfo& pgi = elem.GeomInfoPi(j);
538         meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v);
539       }
540     }
541     SMDS_MeshFace* face = 0;
542     if ( elem.GetType() == TRIG )
543       face = helper.AddFace(nodes[0],nodes[1],nodes[2]);
544     else
545       face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]);
546   }
547
548   return !err;
549 }
550
551
552 //=============================================================================
553 /*!
554  *
555  */
556 //=============================================================================
557
558 bool NETGENPlugin_NETGEN_2D_ONLY::Evaluate(SMESH_Mesh& aMesh,
559                                            const TopoDS_Shape& aShape,
560                                            MapShapeNbElems& aResMap)
561 {
562   TopoDS_Face F = TopoDS::Face(aShape);
563   if(F.IsNull())
564     return false;
565
566   // collect info from edges
567   int nb0d = 0, nb1d = 0;
568   bool IsQuadratic = false;
569   bool IsFirst = true;
570   double fullLen = 0.0;
571   TopTools_MapOfShape tmpMap;
572   for (TopExp_Explorer exp(F, TopAbs_EDGE); exp.More(); exp.Next()) {
573     TopoDS_Edge E = TopoDS::Edge(exp.Current());
574     if( tmpMap.Contains(E) )
575       continue;
576     tmpMap.Add(E);
577     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
578     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
579     if( anIt==aResMap.end() ) {
580       SMESH_subMesh *sm = aMesh.GetSubMesh(F);
581       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
582       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
583       return false;
584     }
585     std::vector<int> aVec = (*anIt).second;
586     nb0d += aVec[SMDSEntity_Node];
587     nb1d += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
588     double aLen = SMESH_Algo::EdgeLength(E);
589     fullLen += aLen;
590     if(IsFirst) {
591       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
592       IsFirst = false;
593     }
594   }
595   tmpMap.Clear();
596
597   // compute edge length
598   double ELen = 0;
599   if (_hypLengthFromEdges || !_hypLengthFromEdges && !_hypMaxElementArea) {
600     if ( nb1d > 0 )
601       ELen = fullLen / nb1d;
602   }
603   if ( _hypMaxElementArea ) {
604     double maxArea = _hypMaxElementArea->GetMaxArea();
605     ELen = sqrt(2. * maxArea/sqrt(3.0));
606   }
607   GProp_GProps G;
608   BRepGProp::SurfaceProperties(F,G);
609   double anArea = G.Mass();
610
611   const int hugeNb = numeric_limits<int>::max()/10;
612   if ( anArea / hugeNb > ELen*ELen )
613   {
614     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
615     SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
616     smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated.\nToo small element length",this));
617     return false;
618   }
619   int nbFaces = (int) ( anArea / ( ELen*ELen*sqrt(3.) / 4 ) );
620   int nbNodes = (int) ( ( nbFaces*3 - (nb1d-1)*2 ) / 6 + 1 );
621   std::vector<int> aVec(SMDSEntity_Last);
622   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
623   if( IsQuadratic ) {
624     aVec[SMDSEntity_Node] = nbNodes;
625     aVec[SMDSEntity_Quad_Triangle] = nbFaces;
626   }
627   else {
628     aVec[SMDSEntity_Node] = nbNodes;
629     aVec[SMDSEntity_Triangle] = nbFaces;
630   }
631   SMESH_subMesh *sm = aMesh.GetSubMesh(F);
632   aResMap.insert(std::make_pair(sm,aVec));
633
634   return true;
635 }