Salome HOME
53045: MG-Tetra and MG-Tetra parallel failed on sub-shape #1
[plugins/ghs3dplugin.git] / src / GHS3DPlugin / GHS3DPlugin_GHS3D.cxx
1 // Copyright (C) 2004-2015  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 //=============================================================================
21 // File      : GHS3DPlugin_GHS3D.cxx
22 // Created   : 
23 // Author    : Edward AGAPOV, modified by Lioka RAZAFINDRAZAKA (CEA) 09/02/2007
24 // Project   : SALOME
25 //=============================================================================
26 //
27 #include "GHS3DPlugin_GHS3D.hxx"
28 #include "GHS3DPlugin_Hypothesis.hxx"
29
30 #include <SMDS_FaceOfNodes.hxx>
31 #include <SMDS_MeshElement.hxx>
32 #include <SMDS_MeshNode.hxx>
33 #include <SMDS_VolumeOfNodes.hxx>
34 #include <SMESHDS_Group.hxx>
35 #include <SMESH_Comment.hxx>
36 #include <SMESH_Group.hxx>
37 #include <SMESH_HypoFilter.hxx>
38 #include <SMESH_Mesh.hxx>
39 #include <SMESH_MeshAlgos.hxx>
40 #include <SMESH_MeshEditor.hxx>
41 #include <SMESH_MesherHelper.hxx>
42 #include <SMESH_OctreeNode.hxx>
43 #include <SMESH_subMeshEventListener.hxx>
44 #include <StdMeshers_QuadToTriaAdaptor.hxx>
45 #include <StdMeshers_ViscousLayers.hxx>
46
47 #include <BRepAdaptor_Surface.hxx>
48 #include <BRepBndLib.hxx>
49 #include <BRepBuilderAPI_MakeVertex.hxx>
50 #include <BRepClass3d.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRepExtrema_DistShapeShape.hxx>
53 #include <BRepGProp.hxx>
54 #include <BRepTools.hxx>
55 #include <BRep_Tool.hxx>
56 #include <Bnd_Box.hxx>
57 #include <GProp_GProps.hxx>
58 #include <GeomAPI_ProjectPointOnSurf.hxx>
59 #include <OSD_File.hxx>
60 #include <Precision.hxx>
61 #include <Standard_ErrorHandler.hxx>
62 #include <Standard_Failure.hxx>
63 #include <Standard_ProgramError.hxx>
64 #include <TopExp.hxx>
65 #include <TopExp_Explorer.hxx>
66 #include <TopTools_IndexedMapOfShape.hxx>
67 #include <TopTools_ListIteratorOfListOfShape.hxx>
68 #include <TopTools_MapOfShape.hxx>
69 #include <TopoDS.hxx>
70 #include <TopoDS_Shell.hxx>
71 #include <TopoDS_Solid.hxx>
72
73 #include <Basics_Utils.hxx>
74 #include <utilities.h>
75
76 #ifdef WIN32
77 #include <io.h>
78 #else
79 #include <sys/sysinfo.h>
80 #endif
81 #include <algorithm>
82 #include <errno.h>
83
84 #define castToNode(n) static_cast<const SMDS_MeshNode *>( n );
85
86 extern "C"
87 {
88 #ifndef WIN32
89 #include <unistd.h>
90 #include <sys/mman.h>
91 #endif
92 #include <sys/stat.h>
93 #include <fcntl.h>
94 }
95
96 #define HOLE_ID -1
97
98 // flags returning state of enforced entities, returned from writeGMFFile
99 enum InvalidEnforcedFlags { FLAG_BAD_ENF_VERT = 1,
100                             FLAG_BAD_ENF_NODE = 2,
101                             FLAG_BAD_ENF_EDGE = 4,
102                             FLAG_BAD_ENF_TRIA = 8
103 };
104 static std::string flagsToErrorStr( int anInvalidEnforcedFlags )
105 {
106   std::string str;
107   if ( anInvalidEnforcedFlags != 0 )
108   {
109     if ( anInvalidEnforcedFlags & FLAG_BAD_ENF_VERT )
110       str = "There are enforced vertices incorrectly defined.\n";
111     if ( anInvalidEnforcedFlags & FLAG_BAD_ENF_NODE )
112       str += "There are enforced nodes incorrectly defined.\n";
113     if ( anInvalidEnforcedFlags & FLAG_BAD_ENF_EDGE )
114       str += "There are enforced edge incorrectly defined.\n";
115     if ( anInvalidEnforcedFlags & FLAG_BAD_ENF_TRIA )
116       str += "There are enforced triangles incorrectly defined.\n";
117   }
118   return str;
119 }
120
121 typedef const list<const SMDS_MeshFace*> TTriaList;
122
123 static const char theDomainGroupNamePrefix[] = "Domain_";
124
125 static void removeFile( const TCollection_AsciiString& fileName )
126 {
127   try {
128     OSD_File( fileName ).Remove();
129   }
130   catch ( Standard_ProgramError ) {
131     MESSAGE("Can't remove file: " << fileName.ToCString() << " ; file does not exist or permission denied");
132   }
133 }
134
135 //=============================================================================
136 /*!
137  *  
138  */
139 //=============================================================================
140
141 GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
142   : SMESH_3D_Algo(hypId, studyId, gen)
143 {
144   MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
145   _name = Name();
146   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
147   _onlyUnaryInput = false; // Compute() will be called on a compound of solids
148   _iShape=0;
149   _nbShape=0;
150   _compatibleHypothesis.push_back( GHS3DPlugin_Hypothesis::GetHypType());
151   _compatibleHypothesis.push_back( StdMeshers_ViscousLayers::GetHypType() );
152   _requireShape = false; // can work without shape_studyId
153
154   smeshGen_i = SMESH_Gen_i::GetSMESHGen();
155   CORBA::Object_var anObject = smeshGen_i->GetNS()->Resolve("/myStudyManager");
156   SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject);
157
158   MESSAGE("studyid = " << _studyId);
159
160   myStudy = NULL;
161   myStudy = aStudyMgr->GetStudyByID(_studyId);
162   if (myStudy)
163     MESSAGE("myStudy->StudyId() = " << myStudy->StudyId());
164   
165   _compute_canceled = false;
166 }
167
168 //=============================================================================
169 /*!
170  *  
171  */
172 //=============================================================================
173
174 GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D()
175 {
176   MESSAGE("GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D");
177 }
178
179 //=============================================================================
180 /*!
181  *  
182  */
183 //=============================================================================
184
185 bool GHS3DPlugin_GHS3D::CheckHypothesis ( SMESH_Mesh&         aMesh,
186                                           const TopoDS_Shape& aShape,
187                                           Hypothesis_Status&  aStatus )
188 {
189   aStatus = SMESH_Hypothesis::HYP_OK;
190
191   _hyp = 0;
192   _viscousLayersHyp = 0;
193   _keepFiles = false;
194   _removeLogOnSuccess = true;
195   _logInStandardOutput = false;
196
197   const list <const SMESHDS_Hypothesis * >& hyps =
198     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false);
199   list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
200   for ( ; h != hyps.end(); ++h )
201   {
202     if ( !_hyp )
203       _hyp = dynamic_cast< const GHS3DPlugin_Hypothesis*> ( *h );
204     if ( !_viscousLayersHyp )
205       _viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h );
206   }
207   if ( _hyp )
208   {
209     _keepFiles = _hyp->GetKeepFiles();
210     _removeLogOnSuccess = _hyp->GetRemoveLogOnSuccess();
211     _logInStandardOutput = _hyp->GetStandardOutputLog();
212   }
213
214   if ( _viscousLayersHyp )
215     error( _viscousLayersHyp->CheckHypothesis( aMesh, aShape, aStatus ));
216
217   return aStatus == HYP_OK;
218 }
219
220
221 //=======================================================================
222 //function : entryToShape
223 //purpose  : 
224 //=======================================================================
225
226 TopoDS_Shape GHS3DPlugin_GHS3D::entryToShape(std::string entry)
227 {
228   MESSAGE("GHS3DPlugin_GHS3D::entryToShape "<<entry );
229   GEOM::GEOM_Object_var aGeomObj;
230   TopoDS_Shape S = TopoDS_Shape();
231   SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() );
232   if (!aSObj->_is_nil() ) {
233     CORBA::Object_var obj = aSObj->GetObject();
234     aGeomObj = GEOM::GEOM_Object::_narrow(obj);
235     aSObj->UnRegister();
236   }
237   if ( !aGeomObj->_is_nil() )
238     S = smeshGen_i->GeomObjectToShape( aGeomObj.in() );
239   return S;
240 }
241
242 //=======================================================================
243 //function : findShape
244 //purpose  : 
245 //=======================================================================
246
247 // static TopoDS_Shape findShape(const SMDS_MeshNode *aNode[],
248 //                               TopoDS_Shape        aShape,
249 //                               const TopoDS_Shape  shape[],
250 //                               double**            box,
251 //                               const int           nShape,
252 //                               TopAbs_State *      state = 0)
253 // {
254 //   gp_XYZ aPnt(0,0,0);
255 //   int j, iShape, nbNode = 4;
256
257 //   for ( j=0; j<nbNode; j++ ) {
258 //     gp_XYZ p ( aNode[j]->X(), aNode[j]->Y(), aNode[j]->Z() );
259 //     if ( aNode[j]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) {
260 //       aPnt = p;
261 //       break;
262 //     }
263 //     aPnt += p / nbNode;
264 //   }
265
266 //   BRepClass3d_SolidClassifier SC (aShape, aPnt, Precision::Confusion());
267 //   if (state) *state = SC.State();
268 //   if ( SC.State() != TopAbs_IN || aShape.IsNull() || aShape.ShapeType() != TopAbs_SOLID) {
269 //     for (iShape = 0; iShape < nShape; iShape++) {
270 //       aShape = shape[iShape];
271 //       if ( !( aPnt.X() < box[iShape][0] || box[iShape][1] < aPnt.X() ||
272 //               aPnt.Y() < box[iShape][2] || box[iShape][3] < aPnt.Y() ||
273 //               aPnt.Z() < box[iShape][4] || box[iShape][5] < aPnt.Z()) ) {
274 //         BRepClass3d_SolidClassifier SC (aShape, aPnt, Precision::Confusion());
275 //         if (state) *state = SC.State();
276 //         if (SC.State() == TopAbs_IN)
277 //           break;
278 //       }
279 //     }
280 //   }
281 //   return aShape;
282 // }
283
284 //================================================================================
285 /*!
286  * \brief returns id of a solid if a triangle defined by the nodes is a temporary face on a
287  * side facet of pyramid and defines sub-domian outside the pyramid; else returns HOLE_ID
288  */
289 //================================================================================
290
291 static int checkTmpFace(const SMDS_MeshNode* node1,
292                         const SMDS_MeshNode* node2,
293                         const SMDS_MeshNode* node3)
294 {
295   // find a pyramid sharing the 3 nodes
296   SMDS_ElemIteratorPtr vIt1 = node1->GetInverseElementIterator(SMDSAbs_Volume);
297   while ( vIt1->more() )
298   {
299     const SMDS_MeshElement* pyram = vIt1->next();
300     if ( pyram->NbCornerNodes() != 5 ) continue;
301     int i2, i3;
302     if ( (i2 = pyram->GetNodeIndex( node2 )) >= 0 &&
303          (i3 = pyram->GetNodeIndex( node3 )) >= 0 )
304     {
305       // Triangle defines sub-domian inside the pyramid if it's
306       // normal points out of the pyram
307
308       // make i2 and i3 hold indices of base nodes of the pyram while
309       // keeping the nodes order in the triangle
310       const int iApex = 4;
311       if ( i2 == iApex )
312         i2 = i3, i3 = pyram->GetNodeIndex( node1 );
313       else if ( i3 == iApex )
314         i3 = i2, i2 = pyram->GetNodeIndex( node1 );
315
316       int i3base = (i2+1) % 4; // next index after i2 within the pyramid base
317       bool isDomainInPyramid = ( i3base != i3 );
318       return isDomainInPyramid ? HOLE_ID : pyram->getshapeId();
319     }
320   }
321   return HOLE_ID;
322 }
323
324 //=======================================================================
325 //function : findShapeID
326 //purpose  : find the solid corresponding to MG-Tetra sub-domain following
327 //           the technique proposed in MG-Tetra manual (available within
328 //           MG-Tetra installation) in chapter "B.4 Subdomain (sub-region) assignment".
329 //           In brief: normal of the triangle defined by the given nodes
330 //           points out of the domain it is associated to
331 //=======================================================================
332
333 static int findShapeID(SMESH_Mesh&          mesh,
334                        const SMDS_MeshNode* node1,
335                        const SMDS_MeshNode* node2,
336                        const SMDS_MeshNode* node3,
337                        const bool           toMeshHoles)
338 {
339   const int invalidID = 0;
340   SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
341
342   // face the nodes belong to
343   vector<const SMDS_MeshNode *> nodes(3);
344   nodes[0] = node1;
345   nodes[1] = node2;
346   nodes[2] = node3;
347   const SMDS_MeshElement * face = meshDS->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/true);
348   if ( !face )
349     return checkTmpFace(node1, node2, node3);
350 #ifdef _DEBUG_
351   std::cout << "bnd face " << face->GetID() << " - ";
352 #endif
353   // geom face the face assigned to
354   SMESH_MeshEditor editor(&mesh);
355   int geomFaceID = editor.FindShape( face );
356   if ( !geomFaceID )
357     return checkTmpFace(node1, node2, node3);
358   TopoDS_Shape shape = meshDS->IndexToShape( geomFaceID );
359   if ( shape.IsNull() || shape.ShapeType() != TopAbs_FACE )
360     return invalidID;
361   TopoDS_Face geomFace = TopoDS::Face( shape );
362
363   // solids bounded by geom face
364   TopTools_IndexedMapOfShape solids, shells;
365   TopTools_ListIteratorOfListOfShape ansIt = mesh.GetAncestors(geomFace);
366   for ( ; ansIt.More(); ansIt.Next() ) {
367     switch ( ansIt.Value().ShapeType() ) {
368     case TopAbs_SOLID:
369       solids.Add( ansIt.Value() ); break;
370     case TopAbs_SHELL:
371       shells.Add( ansIt.Value() ); break;
372     default:;
373     }
374   }
375   // analyse found solids
376   if ( solids.Extent() == 0 || shells.Extent() == 0)
377     return invalidID;
378
379   const TopoDS_Solid& solid1 = TopoDS::Solid( solids(1) );
380   if ( solids.Extent() == 1 )
381   {
382     if ( toMeshHoles )
383       return meshDS->ShapeToIndex( solid1 );
384
385     // - Are we at a hole boundary face?
386     if ( shells(1).IsSame( BRepClass3d::OuterShell( solid1 )) )
387     { // - No, but maybe a hole is bound by two shapes? Does shells(1) touch another shell?
388       bool touch = false;
389       TopExp_Explorer eExp( shells(1), TopAbs_EDGE );
390       // check if any edge of shells(1) belongs to another shell
391       for ( ; eExp.More() && !touch; eExp.Next() ) {
392         ansIt = mesh.GetAncestors( eExp.Current() );
393         for ( ; ansIt.More() && !touch; ansIt.Next() ) {
394           if ( ansIt.Value().ShapeType() == TopAbs_SHELL )
395             touch = ( !ansIt.Value().IsSame( shells(1) ));
396         }
397       }
398       if (!touch)
399         return meshDS->ShapeToIndex( solid1 );
400     }
401   }
402   // find orientation of geom face within the first solid
403   TopExp_Explorer fExp( solid1, TopAbs_FACE );
404   for ( ; fExp.More(); fExp.Next() )
405     if ( geomFace.IsSame( fExp.Current() )) {
406       geomFace = TopoDS::Face( fExp.Current() );
407       break;
408     }
409   if ( !fExp.More() )
410     return invalidID; // face not found
411
412   // normale to triangle
413   gp_Pnt node1Pnt ( node1->X(), node1->Y(), node1->Z() );
414   gp_Pnt node2Pnt ( node2->X(), node2->Y(), node2->Z() );
415   gp_Pnt node3Pnt ( node3->X(), node3->Y(), node3->Z() );
416   gp_Vec vec12( node1Pnt, node2Pnt );
417   gp_Vec vec13( node1Pnt, node3Pnt );
418   gp_Vec meshNormal = vec12 ^ vec13;
419   if ( meshNormal.SquareMagnitude() < DBL_MIN )
420     return invalidID;
421
422   // get normale to geomFace at any node
423   bool geomNormalOK = false;
424   gp_Vec geomNormal;
425   SMESH_MesherHelper helper( mesh ); helper.SetSubShape( geomFace );
426   for ( int i = 0; !geomNormalOK && i < 3; ++i )
427   {
428     // find UV of i-th node on geomFace
429     const SMDS_MeshNode* nNotOnSeamEdge = 0;
430     if ( helper.IsSeamShape( nodes[i]->getshapeId() )) {
431       if ( helper.IsSeamShape( nodes[(i+1)%3]->getshapeId() ))
432         nNotOnSeamEdge = nodes[(i+2)%3];
433       else
434         nNotOnSeamEdge = nodes[(i+1)%3];
435     }
436     bool uvOK = true;
437     gp_XY uv = helper.GetNodeUV( geomFace, nodes[i], nNotOnSeamEdge, &uvOK );
438     // check that uv is correct
439     if (uvOK) {
440       double tol = 1e-6;
441       TopoDS_Shape nodeShape = helper.GetSubShapeByNode( nodes[i], meshDS );
442       if ( !nodeShape.IsNull() )
443         switch ( nodeShape.ShapeType() )
444         {
445         case TopAbs_FACE:   tol = BRep_Tool::Tolerance( TopoDS::Face( nodeShape )); break;
446         case TopAbs_EDGE:   tol = BRep_Tool::Tolerance( TopoDS::Edge( nodeShape )); break;
447         case TopAbs_VERTEX: tol = BRep_Tool::Tolerance( TopoDS::Vertex( nodeShape )); break;
448         default:;
449         }
450       gp_Pnt nodePnt ( nodes[i]->X(), nodes[i]->Y(), nodes[i]->Z() );
451       BRepAdaptor_Surface surface( geomFace );
452       uvOK = ( nodePnt.Distance( surface.Value( uv.X(), uv.Y() )) < 2 * tol );
453       if ( uvOK ) {
454         // normale to geomFace at UV
455         gp_Vec du, dv;
456         surface.D1( uv.X(), uv.Y(), nodePnt, du, dv );
457         geomNormal = du ^ dv;
458         if ( geomFace.Orientation() == TopAbs_REVERSED )
459           geomNormal.Reverse();
460         geomNormalOK = ( geomNormal.SquareMagnitude() > DBL_MIN * 1e3 );
461       }
462     }
463   }
464   if ( !geomNormalOK)
465     return invalidID;
466
467   // compare normals
468   bool isReverse = ( meshNormal * geomNormal ) < 0;
469   if ( !isReverse )
470     return meshDS->ShapeToIndex( solid1 );
471
472   if ( solids.Extent() == 1 )
473     return HOLE_ID; // we are inside a hole
474   else
475     return meshDS->ShapeToIndex( solids(2) );
476 }
477
478 //=======================================================================
479 //function : addElemInMeshGroup
480 //purpose  : Update or create groups in mesh
481 //=======================================================================
482
483 static void addElemInMeshGroup(SMESH_Mesh*             theMesh,
484                                const SMDS_MeshElement* anElem,
485                                std::string&            groupName,
486                                std::set<std::string>&  groupsToRemove)
487 {
488   if ( !anElem ) return; // issue 0021776
489
490   bool groupDone = false;
491   SMESH_Mesh::GroupIteratorPtr grIt = theMesh->GetGroups();
492   while (grIt->more()) {
493     SMESH_Group * group = grIt->next();
494     if ( !group ) continue;
495     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
496     if ( !groupDS ) continue;
497     if ( groupDS->GetType()==anElem->GetType() &&groupName.compare(group->GetName())==0) {
498       SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( groupDS );
499       aGroupDS->SMDSGroup().Add(anElem);
500       groupDone = true;
501 //       MESSAGE("Successfully added enforced element to existing group " << groupName);
502       break;
503     }
504   }
505   
506   if (!groupDone)
507   {
508     int groupId;
509     SMESH_Group* aGroup = theMesh->AddGroup(anElem->GetType(), groupName.c_str(), groupId);
510     aGroup->SetName( groupName.c_str() );
511     SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
512     aGroupDS->SMDSGroup().Add(anElem);
513 //     MESSAGE("Successfully created enforced vertex group " << groupName);
514     groupDone = true;
515   }
516   if (!groupDone)
517     throw SALOME_Exception(LOCALIZED("A given element was not added to a group"));
518 }
519
520
521 //=======================================================================
522 //function : updateMeshGroups
523 //purpose  : Update or create groups in mesh
524 //=======================================================================
525
526 static void updateMeshGroups(SMESH_Mesh* theMesh, std::set<std::string> groupsToRemove)
527 {
528   SMESH_Mesh::GroupIteratorPtr grIt = theMesh->GetGroups();
529   while (grIt->more()) {
530     SMESH_Group * group = grIt->next();
531     if ( !group ) continue;
532     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
533     if ( !groupDS ) continue;
534     std::string currentGroupName = (string)group->GetName();
535     if (groupDS->IsEmpty() && groupsToRemove.find(currentGroupName) != groupsToRemove.end()) {
536       // Previous group created by enforced elements
537       MESSAGE("Delete previous group created by removed enforced elements: " << group->GetName())
538       theMesh->RemoveGroup(groupDS->GetID());
539     }
540   }
541 }
542
543 //=======================================================================
544 //function : removeEmptyGroupsOfDomains
545 //purpose  : remove empty groups named "Domain_nb" created due to
546 //           "To make groups of domains" option.
547 //=======================================================================
548
549 static void removeEmptyGroupsOfDomains(SMESH_Mesh* mesh,
550                                        bool        notEmptyAsWell = false)
551 {
552   const char* refName = theDomainGroupNamePrefix;
553   const size_t refLen = strlen( theDomainGroupNamePrefix );
554
555   std::list<int> groupIDs = mesh->GetGroupIds();
556   std::list<int>::const_iterator id = groupIDs.begin();
557   for ( ; id != groupIDs.end(); ++id )
558   {
559     SMESH_Group* group = mesh->GetGroup( *id );
560     if ( !group || ( !group->GetGroupDS()->IsEmpty() && !notEmptyAsWell ))
561       continue;
562     const char* name = group->GetName();
563     char* end;
564     // check the name
565     if ( strncmp( name, refName, refLen ) == 0 && // starts from refName;
566          isdigit( *( name + refLen )) &&          // refName is followed by a digit;
567          strtol( name + refLen, &end, 10) >= 0 && // there are only digits ...
568          *end == '\0')                            // ... till a string end.
569     {
570       mesh->RemoveGroup( *id );
571     }
572   }
573 }
574
575 //================================================================================
576 /*!
577  * \brief Create the groups corresponding to domains
578  */
579 //================================================================================
580
581 static void makeDomainGroups( std::vector< std::vector< const SMDS_MeshElement* > >& elemsOfDomain,
582                               SMESH_MesherHelper*                                    theHelper)
583 {
584   // int nbDomains = 0;
585   // for ( size_t i = 0; i < elemsOfDomain.size(); ++i )
586   //   nbDomains += ( elemsOfDomain[i].size() > 0 );
587
588   // if ( nbDomains > 1 )
589   for ( size_t iDomain = 0; iDomain < elemsOfDomain.size(); ++iDomain )
590   {
591     std::vector< const SMDS_MeshElement* > & elems = elemsOfDomain[ iDomain ];
592     if ( elems.empty() ) continue;
593
594     // find existing groups
595     std::vector< SMESH_Group* > groupOfType( SMDSAbs_NbElementTypes, (SMESH_Group*)NULL );
596     const std::string domainName = ( SMESH_Comment( theDomainGroupNamePrefix ) << iDomain );
597     SMESH_Mesh::GroupIteratorPtr groupIt = theHelper->GetMesh()->GetGroups();
598     while ( groupIt->more() )
599     {
600       SMESH_Group* group = groupIt->next();
601       if ( domainName == group->GetName() &&
602            dynamic_cast< SMESHDS_Group* >( group->GetGroupDS()) )
603         groupOfType[ group->GetGroupDS()->GetType() ] = group;
604     }
605     // create and fill the groups
606     size_t iElem = 0;
607     int groupID;
608     do
609     {
610       SMESH_Group* group = groupOfType[ elems[ iElem ]->GetType() ];
611       if ( !group )
612         group = theHelper->GetMesh()->AddGroup( elems[ iElem ]->GetType(),
613                                                 domainName.c_str(), groupID );
614       SMDS_MeshGroup& groupDS =
615         static_cast< SMESHDS_Group* >( group->GetGroupDS() )->SMDSGroup();
616
617       while ( iElem < elems.size() && groupDS.Add( elems[iElem] ))
618         ++iElem;
619
620     } while ( iElem < elems.size() );
621   }
622 }
623
624 //=======================================================================
625 //function : readGMFFile
626 //purpose  : read GMF file w/o geometry associated to mesh
627 //=======================================================================
628
629 static bool readGMFFile(const char*                     theFile,
630                         GHS3DPlugin_GHS3D*              theAlgo,
631                         SMESH_MesherHelper*             theHelper,
632                         std::vector <const SMDS_MeshNode*> &    theNodeByGhs3dId,
633                         std::vector <const SMDS_MeshElement*> & theFaceByGhs3dId,
634                         map<const SMDS_MeshNode*,int> & theNodeToGhs3dIdMap,
635                         std::vector<std::string> &      aNodeGroupByGhs3dId,
636                         std::vector<std::string> &      anEdgeGroupByGhs3dId,
637                         std::vector<std::string> &      aFaceGroupByGhs3dId,
638                         std::set<std::string> &         groupsToRemove,
639                         bool                            toMakeGroupsOfDomains=false,
640                         bool                            toMeshHoles=true)
641 {
642   std::string tmpStr;
643   SMESHDS_Mesh* theMeshDS = theHelper->GetMeshDS();
644   const bool hasGeom = ( theHelper->GetMesh()->HasShapeToMesh() );
645
646   int nbInitialNodes = theNodeByGhs3dId.size();
647   int nbMeshNodes = theMeshDS->NbNodes();
648   
649   const bool isQuadMesh = 
650     theHelper->GetMesh()->NbEdges( ORDER_QUADRATIC ) ||
651     theHelper->GetMesh()->NbFaces( ORDER_QUADRATIC ) ||
652     theHelper->GetMesh()->NbVolumes( ORDER_QUADRATIC );
653     
654 #ifdef _DEBUG_
655   std::cout << "theNodeByGhs3dId.size(): " << nbInitialNodes << std::endl;
656   std::cout << "theHelper->GetMesh()->NbNodes(): " << nbMeshNodes << std::endl;
657   std::cout << "isQuadMesh: " << isQuadMesh << std::endl;
658 #endif
659   
660   // ---------------------------------
661   // Read generated elements and nodes
662   // ---------------------------------
663
664   int nbElem = 0, nbRef = 0;
665   int aGMFNodeID = 0;
666   const SMDS_MeshNode** GMFNode;
667 #ifdef _DEBUG_
668   std::map<int, std::set<int> > subdomainId2tetraId;
669 #endif
670   std::map <GmfKwdCod,int> tabRef;
671   const bool force3d = !hasGeom;
672   const int  noID    = 0;
673
674   tabRef[GmfVertices]       = 3; // for new nodes and enforced nodes
675   tabRef[GmfCorners]        = 1;
676   tabRef[GmfEdges]          = 2; // for enforced edges
677   tabRef[GmfRidges]         = 1;
678   tabRef[GmfTriangles]      = 3; // for enforced faces
679   tabRef[GmfQuadrilaterals] = 4;
680   tabRef[GmfTetrahedra]     = 4; // for new tetras
681   tabRef[GmfHexahedra]      = 8;
682
683   int ver, dim;
684   MESSAGE("Read " << theFile << " file");
685   int InpMsh = GmfOpenMesh(theFile, GmfRead, &ver, &dim);
686   if (!InpMsh)
687     return false;
688   MESSAGE("Done ");
689
690   // Read ids of domains
691   vector< int > solidIDByDomain;
692   if ( hasGeom )
693   {
694     int solid1; // id used in case of 1 domain or some reading failure
695     if ( theHelper->GetSubShape().ShapeType() == TopAbs_SOLID )
696       solid1 = theHelper->GetSubShapeID();
697     else
698       solid1 = theMeshDS->ShapeToIndex
699         ( TopExp_Explorer( theHelper->GetSubShape(), TopAbs_SOLID ).Current() );
700
701     int nbDomains = GmfStatKwd( InpMsh, GmfSubDomainFromGeom );
702     if ( nbDomains > 1 )
703     {
704       solidIDByDomain.resize( nbDomains+1, theHelper->GetSubShapeID() );
705       int faceNbNodes, faceIndex, orientation, domainNb;
706       GmfGotoKwd( InpMsh, GmfSubDomainFromGeom );
707       for ( int i = 0; i < nbDomains; ++i )
708       {
709         faceIndex = 0;
710         GmfGetLin( InpMsh, GmfSubDomainFromGeom,
711                    &faceNbNodes, &faceIndex, &orientation, &domainNb);
712         solidIDByDomain[ domainNb ] = 1;
713         if ( 0 < faceIndex && faceIndex-1 < (int)theFaceByGhs3dId.size() )
714         {
715           const SMDS_MeshElement* face = theFaceByGhs3dId[ faceIndex-1 ];
716           const SMDS_MeshNode* nn[3] = { face->GetNode(0),
717                                          face->GetNode(1),
718                                          face->GetNode(2) };
719           if ( orientation < 0 )
720             std::swap( nn[1], nn[2] );
721           solidIDByDomain[ domainNb ] =
722             findShapeID( *theHelper->GetMesh(), nn[0], nn[1], nn[2], toMeshHoles );
723           if ( solidIDByDomain[ domainNb ] > 0 )
724           {
725 #ifdef _DEBUG_
726             std::cout << "solid " << solidIDByDomain[ domainNb ] << std::endl;
727 #endif
728             const TopoDS_Shape& foundShape = theMeshDS->IndexToShape( solidIDByDomain[ domainNb ] );
729             if ( ! theHelper->IsSubShape( foundShape, theHelper->GetSubShape() ))
730               solidIDByDomain[ domainNb ] = HOLE_ID;
731           }
732         }
733       }
734     }
735     if ( solidIDByDomain.size() < 2 )
736       solidIDByDomain.resize( 2, solid1 );
737   }
738
739   // Issue 0020682. Avoid creating nodes and tetras at place where
740   // volumic elements already exist
741   SMESH_ElementSearcher* elemSearcher = 0;
742   std::vector< const SMDS_MeshElement* > foundVolumes;
743   if ( !hasGeom && theHelper->GetMesh()->NbVolumes() > 0 )
744     elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *theMeshDS );
745   auto_ptr< SMESH_ElementSearcher > elemSearcherDeleter( elemSearcher );
746
747   // IMP 0022172: [CEA 790] create the groups corresponding to domains
748   std::vector< std::vector< const SMDS_MeshElement* > > elemsOfDomain;
749
750   int nbVertices = GmfStatKwd(InpMsh, GmfVertices) - nbInitialNodes;
751   GMFNode = new const SMDS_MeshNode*[ nbVertices + 1 ];
752
753   std::map <GmfKwdCod,int>::const_iterator it = tabRef.begin();
754   for ( ; it != tabRef.end() ; ++it)
755   {
756     if(theAlgo->computeCanceled()) {
757       GmfCloseMesh(InpMsh);
758       delete [] GMFNode;
759       return false;
760     }
761     int dummy, solidID;
762     GmfKwdCod token = it->first;
763     nbRef           = it->second;
764
765     nbElem = GmfStatKwd(InpMsh, token);
766     if (nbElem > 0) {
767       GmfGotoKwd(InpMsh, token);
768       std::cout << "Read " << nbElem;
769     }
770     else
771       continue;
772
773     std::vector<int> id (nbElem*tabRef[token]); // node ids
774     std::vector<int> domainID( nbElem ); // domain
775
776     if (token == GmfVertices) {
777       (nbElem <= 1) ? tmpStr = " vertex" : tmpStr = " vertices";
778 //       std::cout << nbInitialNodes << " from input mesh " << std::endl;
779
780       // Remove orphan nodes from previous enforced mesh which was cleared
781 //       if ( nbElem < nbMeshNodes ) {
782 //         const SMDS_MeshNode* node;
783 //         SMDS_NodeIteratorPtr nodeIt = theMeshDS->nodesIterator();
784 //         while ( nodeIt->more() )
785 //         {
786 //           node = nodeIt->next();
787 //           if (theNodeToGhs3dIdMap.find(node) != theNodeToGhs3dIdMap.end())
788 //             theMeshDS->RemoveNode(node);
789 //         }
790 //       }
791
792       
793       int aGMFID;
794
795       float VerTab_f[3];
796       double x, y, z;
797       const SMDS_MeshNode * aGMFNode;
798
799       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
800         if(theAlgo->computeCanceled()) {
801           GmfCloseMesh(InpMsh);
802           delete [] GMFNode;
803           return false;
804         }
805         if (ver == GmfFloat) {
806           GmfGetLin(InpMsh, token, &VerTab_f[0], &VerTab_f[1], &VerTab_f[2], &dummy);
807           x = VerTab_f[0];
808           y = VerTab_f[1];
809           z = VerTab_f[2];
810         }
811         else {
812           GmfGetLin(InpMsh, token, &x, &y, &z, &dummy);
813         }
814         if (iElem >= nbInitialNodes) {
815           if ( elemSearcher &&
816                 elemSearcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_Volume, foundVolumes))
817             aGMFNode = 0;
818           else
819             aGMFNode = theHelper->AddNode(x, y, z);
820           
821           aGMFID = iElem -nbInitialNodes +1;
822           GMFNode[ aGMFID ] = aGMFNode;
823           if (aGMFID-1 < (int)aNodeGroupByGhs3dId.size() && !aNodeGroupByGhs3dId.at(aGMFID-1).empty())
824             addElemInMeshGroup(theHelper->GetMesh(), aGMFNode, aNodeGroupByGhs3dId.at(aGMFID-1), groupsToRemove);
825         }
826       }
827     }
828     else if (token == GmfCorners && nbElem > 0) {
829       (nbElem <= 1) ? tmpStr = " corner" : tmpStr = " corners";
830       for ( int iElem = 0; iElem < nbElem; iElem++ )
831         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]]);
832     }
833     else if (token == GmfRidges && nbElem > 0) {
834       (nbElem <= 1) ? tmpStr = " ridge" : tmpStr = " ridges";
835       for ( int iElem = 0; iElem < nbElem; iElem++ )
836         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]]);
837     }
838     else if (token == GmfEdges && nbElem > 0) {
839       (nbElem <= 1) ? tmpStr = " edge" : tmpStr = " edges";
840       for ( int iElem = 0; iElem < nbElem; iElem++ )
841         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &domainID[iElem]);
842     }
843     else if (token == GmfTriangles && nbElem > 0) {
844       (nbElem <= 1) ? tmpStr = " triangle" : tmpStr = " triangles";
845       for ( int iElem = 0; iElem < nbElem; iElem++ )
846         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &domainID[iElem]);
847     }
848     else if (token == GmfQuadrilaterals && nbElem > 0) {
849       (nbElem <= 1) ? tmpStr = " Quadrilateral" : tmpStr = " Quadrilaterals";
850       for ( int iElem = 0; iElem < nbElem; iElem++ )
851         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
852     }
853     else if (token == GmfTetrahedra && nbElem > 0) {
854       (nbElem <= 1) ? tmpStr = " Tetrahedron" : tmpStr = " Tetrahedra";
855       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
856         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
857 #ifdef _DEBUG_
858         subdomainId2tetraId[dummy].insert(iElem+1);
859 //         MESSAGE("subdomainId2tetraId["<<dummy<<"].insert("<<iElem+1<<")");
860 #endif
861       }
862     }
863     else if (token == GmfHexahedra && nbElem > 0) {
864       (nbElem <= 1) ? tmpStr = " Hexahedron" : tmpStr = " Hexahedra";
865       for ( int iElem = 0; iElem < nbElem; iElem++ )
866         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3],
867                   &id[iElem*tabRef[token]+4], &id[iElem*tabRef[token]+5], &id[iElem*tabRef[token]+6], &id[iElem*tabRef[token]+7], &domainID[iElem]);
868     }
869     std::cout << tmpStr << std::endl;
870     std::cout << std::endl;
871
872     switch (token) {
873     case GmfCorners:
874     case GmfRidges:
875     case GmfEdges:
876     case GmfTriangles:
877     case GmfQuadrilaterals:
878     case GmfTetrahedra:
879     case GmfHexahedra:
880     {
881       std::vector< const SMDS_MeshNode* > node( nbRef );
882       std::vector< int >          nodeID( nbRef );
883       std::vector< SMDS_MeshNode* > enfNode( nbRef );
884       const SMDS_MeshElement* aCreatedElem;
885
886       for ( int iElem = 0; iElem < nbElem; iElem++ )
887       {
888         if(theAlgo->computeCanceled()) {
889           GmfCloseMesh(InpMsh);
890           delete [] GMFNode;
891           return false;
892         }
893         // Check if elem is already in input mesh. If yes => skip
894         bool fullyCreatedElement = false; // if at least one of the nodes was created
895         for ( int iRef = 0; iRef < nbRef; iRef++ )
896         {
897           aGMFNodeID = id[iElem*tabRef[token]+iRef]; // read nbRef aGMFNodeID
898           if (aGMFNodeID <= nbInitialNodes) // input nodes
899           {
900             aGMFNodeID--;
901             node[ iRef ] = theNodeByGhs3dId[aGMFNodeID];
902           }
903           else
904           {
905             fullyCreatedElement = true;
906             aGMFNodeID -= nbInitialNodes;
907             nodeID[ iRef ] = aGMFNodeID ;
908             node  [ iRef ] = GMFNode[ aGMFNodeID ];
909           }
910         }
911         aCreatedElem = 0;
912         switch (token)
913         {
914         case GmfEdges:
915           if (fullyCreatedElement) {
916             aCreatedElem = theHelper->AddEdge( node[0], node[1], noID, force3d );
917             if (anEdgeGroupByGhs3dId.size() && !anEdgeGroupByGhs3dId[iElem].empty())
918               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, anEdgeGroupByGhs3dId[iElem], groupsToRemove);
919           }
920           break;
921         case GmfTriangles:
922           if (fullyCreatedElement) {
923             aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], noID, force3d );
924             if (aFaceGroupByGhs3dId.size() && !aFaceGroupByGhs3dId[iElem].empty())
925               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, aFaceGroupByGhs3dId[iElem], groupsToRemove);
926           }
927           break;
928         case GmfQuadrilaterals:
929           if (fullyCreatedElement) {
930             aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], node[3], noID, force3d );
931           }
932           break;
933         case GmfTetrahedra:
934           if ( hasGeom )
935           {
936             solidID = solidIDByDomain[ domainID[iElem]];
937             if ( solidID != HOLE_ID )
938             {
939               aCreatedElem = theHelper->AddVolume( node[1], node[0], node[2], node[3],
940                                                    noID, force3d );
941               theMeshDS->SetMeshElementOnShape( aCreatedElem, solidID );
942               for ( int iN = 0; iN < 4; ++iN )
943                 if ( node[iN]->getshapeId() < 1 )
944                   theMeshDS->SetNodeInVolume( node[iN], solidID );
945             }
946           }
947           else
948           {
949             if ( elemSearcher ) {
950               // Issue 0020682. Avoid creating nodes and tetras at place where
951               // volumic elements already exist
952               if ( !node[1] || !node[0] || !node[2] || !node[3] )
953                 continue;
954               if ( elemSearcher->FindElementsByPoint((SMESH_TNodeXYZ(node[0]) +
955                                                       SMESH_TNodeXYZ(node[1]) +
956                                                       SMESH_TNodeXYZ(node[2]) +
957                                                       SMESH_TNodeXYZ(node[3]) ) / 4.,
958                                                      SMDSAbs_Volume, foundVolumes ))
959                 break;
960             }
961             aCreatedElem = theHelper->AddVolume( node[1], node[0], node[2], node[3],
962                                                  noID, force3d );
963           }
964           break;
965         case GmfHexahedra:
966           if ( hasGeom )
967           {
968             solidID = solidIDByDomain[ domainID[iElem]];
969             if ( solidID != HOLE_ID )
970             {
971               aCreatedElem = theHelper->AddVolume( node[0], node[3], node[2], node[1],
972                                                    node[4], node[7], node[6], node[5],
973                                                    noID, force3d );
974               theMeshDS->SetMeshElementOnShape( aCreatedElem, solidID );
975               for ( int iN = 0; iN < 8; ++iN )
976                 if ( node[iN]->getshapeId() < 1 )
977                   theMeshDS->SetNodeInVolume( node[iN], solidID );
978             }
979           }
980           else
981           {
982             if ( elemSearcher ) {
983               // Issue 0020682. Avoid creating nodes and tetras at place where
984               // volumic elements already exist
985               if ( !node[1] || !node[0] || !node[2] || !node[3] || !node[4] || !node[5] || !node[6] || !node[7])
986                 continue;
987               if ( elemSearcher->FindElementsByPoint((SMESH_TNodeXYZ(node[0]) +
988                                                       SMESH_TNodeXYZ(node[1]) +
989                                                       SMESH_TNodeXYZ(node[2]) +
990                                                       SMESH_TNodeXYZ(node[3]) +
991                                                       SMESH_TNodeXYZ(node[4]) +
992                                                       SMESH_TNodeXYZ(node[5]) +
993                                                       SMESH_TNodeXYZ(node[6]) +
994                                                       SMESH_TNodeXYZ(node[7])) / 8.,
995                                                      SMDSAbs_Volume, foundVolumes ))
996                 break;
997             }
998             aCreatedElem = theHelper->AddVolume( node[0], node[3], node[2], node[1],
999                                                  node[4], node[7], node[6], node[5],
1000                                                  noID, force3d );
1001           }
1002           break;
1003         default: continue;
1004         } // switch (token)
1005
1006         if ( aCreatedElem && toMakeGroupsOfDomains )
1007         {
1008           if ( domainID[iElem] >= (int) elemsOfDomain.size() )
1009             elemsOfDomain.resize( domainID[iElem] + 1 );
1010           elemsOfDomain[ domainID[iElem] ].push_back( aCreatedElem );
1011         }
1012       } // loop on elements of one type
1013       break;
1014     } // case ...
1015     default:;
1016     } // switch (token)
1017   } // loop on tabRef
1018
1019   // remove nodes in holes
1020   if ( hasGeom )
1021   {
1022     for ( int i = 1; i <= nbVertices; ++i )
1023       if ( GMFNode[i]->NbInverseElements() == 0 )
1024         theMeshDS->RemoveFreeNode( GMFNode[i], /*sm=*/0, /*fromGroups=*/false );
1025   }
1026
1027   GmfCloseMesh(InpMsh);
1028   delete [] GMFNode;
1029
1030   // 0022172: [CEA 790] create the groups corresponding to domains
1031   if ( toMakeGroupsOfDomains )
1032     makeDomainGroups( elemsOfDomain, theHelper );
1033
1034 #ifdef _DEBUG_
1035   MESSAGE("Nb subdomains " << subdomainId2tetraId.size());
1036   std::map<int, std::set<int> >::const_iterator subdomainIt = subdomainId2tetraId.begin();
1037   TCollection_AsciiString aSubdomainFileName = theFile;
1038   aSubdomainFileName = aSubdomainFileName + ".subdomain";
1039   ofstream aSubdomainFile  ( aSubdomainFileName.ToCString()  , ios::out);
1040
1041   aSubdomainFile << "Nb subdomains " << subdomainId2tetraId.size() << std::endl;
1042   for(;subdomainIt != subdomainId2tetraId.end() ; ++subdomainIt) {
1043     int subdomainId = subdomainIt->first;
1044     std::set<int> tetraIds = subdomainIt->second;
1045     MESSAGE("Subdomain #"<<subdomainId<<": "<<tetraIds.size()<<" tetrahedrons");
1046     std::set<int>::const_iterator tetraIdsIt = tetraIds.begin();
1047     aSubdomainFile << subdomainId << std::endl;
1048     for(;tetraIdsIt != tetraIds.end() ; ++tetraIdsIt) {
1049       aSubdomainFile << (*tetraIdsIt) << " ";
1050     }
1051     aSubdomainFile << std::endl;
1052   }
1053   aSubdomainFile.close();
1054 #endif  
1055   
1056   return true;
1057 }
1058
1059
1060 static bool writeGMFFile(const char*                                     theMeshFileName,
1061                          const char*                                     theRequiredFileName,
1062                          const char*                                     theSolFileName,
1063                          const SMESH_ProxyMesh&                          theProxyMesh,
1064                          SMESH_MesherHelper&                             theHelper,
1065                          std::vector <const SMDS_MeshNode*> &            theNodeByGhs3dId,
1066                          std::vector <const SMDS_MeshElement*> &         theFaceByGhs3dId,
1067                          std::map<const SMDS_MeshNode*,int> &            aNodeToGhs3dIdMap,
1068                          std::vector<std::string> &                      aNodeGroupByGhs3dId,
1069                          std::vector<std::string> &                      anEdgeGroupByGhs3dId,
1070                          std::vector<std::string> &                      aFaceGroupByGhs3dId,
1071                          GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap & theEnforcedNodes,
1072                          GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedEdges,
1073                          GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedTriangles,
1074                          std::map<std::vector<double>, std::string> &    enfVerticesWithGroup,
1075                          GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues & theEnforcedVertices,
1076                          int &                                           theInvalidEnforcedFlags)
1077 {
1078   MESSAGE("writeGMFFile w/o geometry");
1079   std::string tmpStr;
1080   int idx, idxRequired = 0, idxSol = 0;
1081   const int dummyint = 0;
1082   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues::const_iterator vertexIt;
1083   std::vector<double> enfVertexSizes;
1084   const SMDS_MeshElement* elem;
1085   TIDSortedElemSet anElemSet, theKeptEnforcedEdges, theKeptEnforcedTriangles;
1086   SMDS_ElemIteratorPtr nodeIt;
1087   std::vector <const SMDS_MeshNode*> theEnforcedNodeByGhs3dId;
1088   map<const SMDS_MeshNode*,int> anEnforcedNodeToGhs3dIdMap, anExistingEnforcedNodeToGhs3dIdMap;
1089   std::vector< const SMDS_MeshElement* > foundElems;
1090   map<const SMDS_MeshNode*,TopAbs_State> aNodeToTopAbs_StateMap;
1091   int nbFoundElems;
1092   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap::iterator elemIt;
1093   TIDSortedElemSet::iterator elemSetIt;
1094   bool isOK;
1095   SMESH_Mesh* theMesh = theHelper.GetMesh();
1096   const bool hasGeom = theMesh->HasShapeToMesh();
1097   SMESHUtils::Deleter< SMESH_ElementSearcher > pntCls
1098     ( SMESH_MeshAlgos::GetElementSearcher(*theMesh->GetMeshDS()));
1099   
1100   int nbEnforcedVertices = theEnforcedVertices.size();
1101   theInvalidEnforcedFlags = 0;
1102
1103   // count faces
1104   int nbFaces = theProxyMesh.NbFaces();
1105   int nbNodes;
1106   theFaceByGhs3dId.reserve( nbFaces );
1107   
1108   // groups management
1109   int usedEnforcedNodes = 0;
1110   std::string gn = "";
1111
1112   if ( nbFaces == 0 )
1113     return false;
1114   
1115   idx = GmfOpenMesh(theMeshFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1116   if (!idx)
1117     return false;
1118   
1119   /* ========================== FACES ========================== */
1120   /* TRIANGLES ========================== */
1121   SMDS_ElemIteratorPtr eIt =
1122     hasGeom ? theProxyMesh.GetFaces( theHelper.GetSubShape()) : theProxyMesh.GetFaces();
1123   while ( eIt->more() )
1124   {
1125     elem = eIt->next();
1126     anElemSet.insert(elem);
1127     nodeIt = elem->nodesIterator();
1128     nbNodes = elem->NbCornerNodes();
1129     while ( nodeIt->more() && nbNodes--)
1130     {
1131       // find MG-Tetra ID
1132       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1133       int newId = aNodeToGhs3dIdMap.size() + 1; // MG-Tetra ids count from 1
1134       aNodeToGhs3dIdMap.insert( make_pair( node, newId ));
1135     }
1136   }
1137   
1138   /* EDGES ========================== */
1139   
1140   // Iterate over the enforced edges
1141   for(elemIt = theEnforcedEdges.begin() ; elemIt != theEnforcedEdges.end() ; ++elemIt) {
1142     elem = elemIt->first;
1143     isOK = true;
1144     nodeIt = elem->nodesIterator();
1145     nbNodes = 2;
1146     while ( nodeIt->more() && nbNodes-- ) {
1147       // find MG-Tetra ID
1148       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1149       // Test if point is inside shape to mesh
1150       gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1151       TopAbs_State result = pntCls->GetPointState( myPoint );
1152       if ( result == TopAbs_OUT ) {
1153         isOK = false;
1154         theInvalidEnforcedFlags |= FLAG_BAD_ENF_EDGE;
1155         break;
1156       }
1157       aNodeToTopAbs_StateMap.insert( make_pair( node, result ));
1158     }
1159     if (isOK) {
1160       nodeIt = elem->nodesIterator();
1161       nbNodes = 2;
1162       int newId = -1;
1163       while ( nodeIt->more() && nbNodes-- ) {
1164         // find MG-Tetra ID
1165         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1166         gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1167         nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1168 #ifdef _DEBUG_
1169         std::cout << "Node at "<<node->X()<<", "<<node->Y()<<", "<<node->Z()<<std::endl;
1170         std::cout << "Nb nodes found : "<<nbFoundElems<<std::endl;
1171 #endif
1172         if (nbFoundElems ==0) {
1173           if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1174             newId = aNodeToGhs3dIdMap.size() + anEnforcedNodeToGhs3dIdMap.size() + 1; // MG-Tetra ids count from 1
1175             anEnforcedNodeToGhs3dIdMap.insert( make_pair( node, newId ));
1176           }
1177         }
1178         else if (nbFoundElems ==1) {
1179           const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1180           newId = (*aNodeToGhs3dIdMap.find(existingNode)).second;
1181           anExistingEnforcedNodeToGhs3dIdMap.insert( make_pair( node, newId ));
1182         }
1183         else
1184           isOK = false;
1185 #ifdef _DEBUG_
1186         std::cout << "MG-Tetra node ID: "<<newId<<std::endl;
1187 #endif
1188       }
1189       if (isOK)
1190         theKeptEnforcedEdges.insert(elem);
1191       else
1192         theInvalidEnforcedFlags |= FLAG_BAD_ENF_EDGE;
1193     }
1194   }
1195   
1196   /* ENFORCED TRIANGLES ========================== */
1197   
1198   // Iterate over the enforced triangles
1199   for(elemIt = theEnforcedTriangles.begin() ; elemIt != theEnforcedTriangles.end() ; ++elemIt) {
1200     elem = elemIt->first;
1201     isOK = true;
1202     nodeIt = elem->nodesIterator();
1203     nbNodes = 3;
1204     while ( nodeIt->more() && nbNodes--) {
1205       // find MG-Tetra ID
1206       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1207       // Test if point is inside shape to mesh
1208       gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1209       TopAbs_State result = pntCls->GetPointState( myPoint );
1210       if ( result == TopAbs_OUT ) {
1211         isOK = false;
1212         theInvalidEnforcedFlags |= FLAG_BAD_ENF_TRIA;
1213         break;
1214       }
1215       aNodeToTopAbs_StateMap.insert( make_pair( node, result ));
1216     }
1217     if (isOK) {
1218       nodeIt = elem->nodesIterator();
1219       nbNodes = 3;
1220       int newId = -1;
1221       while ( nodeIt->more() && nbNodes--) {
1222         // find MG-Tetra ID
1223         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1224         gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1225         nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1226 #ifdef _DEBUG_
1227         std::cout << "Nb nodes found : "<<nbFoundElems<<std::endl;
1228 #endif
1229         if (nbFoundElems ==0) {
1230           if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1231             newId = aNodeToGhs3dIdMap.size() + anEnforcedNodeToGhs3dIdMap.size() + 1; // MG-Tetra ids count from 1
1232             anEnforcedNodeToGhs3dIdMap.insert( make_pair( node, newId ));
1233           }
1234         }
1235         else if (nbFoundElems ==1) {
1236           const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1237           newId = (*aNodeToGhs3dIdMap.find(existingNode)).second;
1238           anExistingEnforcedNodeToGhs3dIdMap.insert( make_pair( node, newId ));
1239         }
1240         else
1241           isOK = false;
1242 #ifdef _DEBUG_
1243         std::cout << "MG-Tetra node ID: "<<newId<<std::endl;
1244 #endif
1245       }
1246       if (isOK)
1247         theKeptEnforcedTriangles.insert(elem);
1248       else
1249         theInvalidEnforcedFlags |= FLAG_BAD_ENF_TRIA;
1250     }
1251   }
1252   
1253   // put nodes to theNodeByGhs3dId vector
1254 #ifdef _DEBUG_
1255   std::cout << "aNodeToGhs3dIdMap.size(): "<<aNodeToGhs3dIdMap.size()<<std::endl;
1256 #endif
1257   theNodeByGhs3dId.resize( aNodeToGhs3dIdMap.size() );
1258   map<const SMDS_MeshNode*,int>::const_iterator n2id = aNodeToGhs3dIdMap.begin();
1259   for ( ; n2id != aNodeToGhs3dIdMap.end(); ++ n2id)
1260   {
1261 //     std::cout << "n2id->first: "<<n2id->first<<std::endl;
1262     theNodeByGhs3dId[ n2id->second - 1 ] = n2id->first; // MG-Tetra ids count from 1
1263   }
1264
1265   // put nodes to anEnforcedNodeToGhs3dIdMap vector
1266 #ifdef _DEBUG_
1267   std::cout << "anEnforcedNodeToGhs3dIdMap.size(): "<<anEnforcedNodeToGhs3dIdMap.size()<<std::endl;
1268 #endif
1269   theEnforcedNodeByGhs3dId.resize( anEnforcedNodeToGhs3dIdMap.size());
1270   n2id = anEnforcedNodeToGhs3dIdMap.begin();
1271   for ( ; n2id != anEnforcedNodeToGhs3dIdMap.end(); ++ n2id)
1272   {
1273     if (n2id->second > (int)aNodeToGhs3dIdMap.size()) {
1274       theEnforcedNodeByGhs3dId[ n2id->second - aNodeToGhs3dIdMap.size() - 1 ] = n2id->first; // MG-Tetra ids count from 1
1275     }
1276   }
1277   
1278   
1279   /* ========================== NODES ========================== */
1280   vector<const SMDS_MeshNode*> theOrderedNodes, theRequiredNodes;
1281   std::set< std::vector<double> > nodesCoords;
1282   vector<const SMDS_MeshNode*>::const_iterator ghs3dNodeIt = theNodeByGhs3dId.begin();
1283   vector<const SMDS_MeshNode*>::const_iterator after  = theNodeByGhs3dId.end();
1284   
1285   (theNodeByGhs3dId.size() <= 1) ? tmpStr = " node" : " nodes";
1286   std::cout << theNodeByGhs3dId.size() << tmpStr << " from mesh ..." << std::endl;
1287   for ( ; ghs3dNodeIt != after; ++ghs3dNodeIt )
1288   {
1289     const SMDS_MeshNode* node = *ghs3dNodeIt;
1290     std::vector<double> coords;
1291     coords.push_back(node->X());
1292     coords.push_back(node->Y());
1293     coords.push_back(node->Z());
1294     nodesCoords.insert(coords);
1295     theOrderedNodes.push_back(node);
1296   }
1297   
1298   // Iterate over the enforced nodes given by enforced elements
1299   ghs3dNodeIt = theEnforcedNodeByGhs3dId.begin();
1300   after  = theEnforcedNodeByGhs3dId.end();
1301   (theEnforcedNodeByGhs3dId.size() <= 1) ? tmpStr = " node" : " nodes";
1302   std::cout << theEnforcedNodeByGhs3dId.size() << tmpStr << " from enforced elements ..." << std::endl;
1303   for ( ; ghs3dNodeIt != after; ++ghs3dNodeIt )
1304   {
1305     const SMDS_MeshNode* node = *ghs3dNodeIt;
1306     std::vector<double> coords;
1307     coords.push_back(node->X());
1308     coords.push_back(node->Y());
1309     coords.push_back(node->Z());
1310 #ifdef _DEBUG_
1311     std::cout << "Node at " << node->X()<<", " <<node->Y()<<", " <<node->Z();
1312 #endif
1313     
1314     if (nodesCoords.find(coords) != nodesCoords.end()) {
1315       // node already exists in original mesh
1316 #ifdef _DEBUG_
1317       std::cout << " found" << std::endl;
1318 #endif
1319       continue;
1320     }
1321     
1322     if (theEnforcedVertices.find(coords) != theEnforcedVertices.end()) {
1323       // node already exists in enforced vertices
1324 #ifdef _DEBUG_
1325       std::cout << " found" << std::endl;
1326 #endif
1327       continue;
1328     }
1329     
1330 //     gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1331 //     nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1332 //     if (nbFoundElems ==0) {
1333 //       std::cout << " not found" << std::endl;
1334 //       if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1335 //         nodesCoords.insert(coords);
1336 //         theOrderedNodes.push_back(node);
1337 //       }
1338 //     }
1339 //     else {
1340 //       std::cout << " found in initial mesh" << std::endl;
1341 //       const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1342 //       nodesCoords.insert(coords);
1343 //       theOrderedNodes.push_back(existingNode);
1344 //     }
1345     
1346 #ifdef _DEBUG_
1347     std::cout << " not found" << std::endl;
1348 #endif
1349     
1350     nodesCoords.insert(coords);
1351     theOrderedNodes.push_back(node);
1352 //     theRequiredNodes.push_back(node);
1353   }
1354   
1355   
1356   // Iterate over the enforced nodes
1357   GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap::const_iterator enfNodeIt;
1358   (theEnforcedNodes.size() <= 1) ? tmpStr = " node" : " nodes";
1359   std::cout << theEnforcedNodes.size() << tmpStr << " from enforced nodes ..." << std::endl;
1360   for(enfNodeIt = theEnforcedNodes.begin() ; enfNodeIt != theEnforcedNodes.end() ; ++enfNodeIt)
1361   {
1362     const SMDS_MeshNode* node = enfNodeIt->first;
1363     std::vector<double> coords;
1364     coords.push_back(node->X());
1365     coords.push_back(node->Y());
1366     coords.push_back(node->Z());
1367 #ifdef _DEBUG_
1368     std::cout << "Node at " << node->X()<<", " <<node->Y()<<", " <<node->Z();
1369 #endif
1370     
1371     // Test if point is inside shape to mesh
1372     gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1373     TopAbs_State result = pntCls->GetPointState( myPoint );
1374     if ( result == TopAbs_OUT ) {
1375 #ifdef _DEBUG_
1376       std::cout << " out of volume" << std::endl;
1377 #endif
1378       theInvalidEnforcedFlags |= FLAG_BAD_ENF_NODE;
1379       continue;
1380     }
1381     
1382     if (nodesCoords.find(coords) != nodesCoords.end()) {
1383 #ifdef _DEBUG_
1384       std::cout << " found in nodesCoords" << std::endl;
1385 #endif
1386 //       theRequiredNodes.push_back(node);
1387       continue;
1388     }
1389
1390     if (theEnforcedVertices.find(coords) != theEnforcedVertices.end()) {
1391 #ifdef _DEBUG_
1392       std::cout << " found in theEnforcedVertices" << std::endl;
1393 #endif
1394       continue;
1395     }
1396     
1397 //     nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1398 //     if (nbFoundElems ==0) {
1399 //       std::cout << " not found" << std::endl;
1400 //       if (result == TopAbs_IN) {
1401 //         nodesCoords.insert(coords);
1402 //         theRequiredNodes.push_back(node);
1403 //       }
1404 //     }
1405 //     else {
1406 //       std::cout << " found in initial mesh" << std::endl;
1407 //       const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1408 // //       nodesCoords.insert(coords);
1409 //       theRequiredNodes.push_back(existingNode);
1410 //     }
1411 //     
1412 //     
1413 //     
1414 //     if (pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems) == 0)
1415 //       continue;
1416
1417 //     if ( result != TopAbs_IN )
1418 //       continue;
1419     
1420 #ifdef _DEBUG_
1421     std::cout << " not found" << std::endl;
1422 #endif
1423     nodesCoords.insert(coords);
1424 //     theOrderedNodes.push_back(node);
1425     theRequiredNodes.push_back(node);
1426   }
1427   int requiredNodes = theRequiredNodes.size();
1428   
1429   int solSize = 0;
1430   std::vector<std::vector<double> > ReqVerTab;
1431   if (nbEnforcedVertices) {
1432 //    ReqVerTab.clear();
1433     (nbEnforcedVertices <= 1) ? tmpStr = " node" : " nodes";
1434     std::cout << nbEnforcedVertices << tmpStr << " from enforced vertices ..." << std::endl;
1435     // Iterate over the enforced vertices
1436     for(vertexIt = theEnforcedVertices.begin() ; vertexIt != theEnforcedVertices.end() ; ++vertexIt) {
1437       double x = vertexIt->first[0];
1438       double y = vertexIt->first[1];
1439       double z = vertexIt->first[2];
1440       // Test if point is inside shape to mesh
1441       gp_Pnt myPoint(x,y,z);
1442       TopAbs_State result = pntCls->GetPointState( myPoint );
1443       if ( result == TopAbs_OUT )
1444       {
1445         std::cout << "Warning: enforced vertex at ( " << x << "," << y << "," << z << " ) is out of the meshed domain!!!" << std::endl;
1446         theInvalidEnforcedFlags |= FLAG_BAD_ENF_VERT;
1447         //continue;
1448       }
1449       std::vector<double> coords;
1450       coords.push_back(x);
1451       coords.push_back(y);
1452       coords.push_back(z);
1453       ReqVerTab.push_back(coords);
1454       enfVertexSizes.push_back(vertexIt->second);
1455       solSize++;
1456     }
1457   }
1458   
1459   
1460   // GmfVertices
1461   std::cout << "Begin writting required nodes in GmfVertices" << std::endl;
1462   std::cout << "Nb vertices: " << theOrderedNodes.size() << std::endl;
1463   GmfSetKwd(idx, GmfVertices, theOrderedNodes.size()/*+solSize*/);
1464   for (ghs3dNodeIt = theOrderedNodes.begin();ghs3dNodeIt != theOrderedNodes.end();++ghs3dNodeIt) {
1465     GmfSetLin(idx, GmfVertices, (*ghs3dNodeIt)->X(), (*ghs3dNodeIt)->Y(), (*ghs3dNodeIt)->Z(), dummyint);
1466   }
1467
1468   std::cout << "End writting required nodes in GmfVertices" << std::endl;
1469
1470   if (requiredNodes + solSize) {
1471     std::cout << "Begin writting in req and sol file" << std::endl;
1472     aNodeGroupByGhs3dId.resize( requiredNodes + solSize );
1473     idxRequired = GmfOpenMesh(theRequiredFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1474     if (!idxRequired) {
1475       GmfCloseMesh(idx);
1476       return false;
1477     }
1478     idxSol = GmfOpenMesh(theSolFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1479     if (!idxSol) {
1480       GmfCloseMesh(idx);
1481       if (idxRequired)
1482         GmfCloseMesh(idxRequired);
1483       return false;
1484     }
1485     int TypTab[] = {GmfSca};
1486     double ValTab[] = {0.0};
1487     GmfSetKwd(idxRequired, GmfVertices, requiredNodes + solSize);
1488     GmfSetKwd(idxSol, GmfSolAtVertices, requiredNodes + solSize, 1, TypTab);
1489 //     int usedEnforcedNodes = 0;
1490 //     std::string gn = "";
1491     for (ghs3dNodeIt = theRequiredNodes.begin();ghs3dNodeIt != theRequiredNodes.end();++ghs3dNodeIt) {
1492       GmfSetLin(idxRequired, GmfVertices, (*ghs3dNodeIt)->X(), (*ghs3dNodeIt)->Y(), (*ghs3dNodeIt)->Z(), dummyint);
1493       GmfSetLin(idxSol, GmfSolAtVertices, ValTab);
1494       if (theEnforcedNodes.find((*ghs3dNodeIt)) != theEnforcedNodes.end())
1495         gn = theEnforcedNodes.find((*ghs3dNodeIt))->second;
1496       aNodeGroupByGhs3dId[usedEnforcedNodes] = gn;
1497       usedEnforcedNodes++;
1498     }
1499
1500     for (int i=0;i<solSize;i++) {
1501       std::cout << ReqVerTab[i][0] <<" "<< ReqVerTab[i][1] << " "<< ReqVerTab[i][2] << std::endl;
1502 #ifdef _DEBUG_
1503       std::cout << "enfVertexSizes.at("<<i<<"): " << enfVertexSizes.at(i) << std::endl;
1504 #endif
1505       double solTab[] = {enfVertexSizes.at(i)};
1506       GmfSetLin(idxRequired, GmfVertices, ReqVerTab[i][0], ReqVerTab[i][1], ReqVerTab[i][2], dummyint);
1507       GmfSetLin(idxSol, GmfSolAtVertices, solTab);
1508       aNodeGroupByGhs3dId[usedEnforcedNodes] = enfVerticesWithGroup.find(ReqVerTab[i])->second;
1509 #ifdef _DEBUG_
1510       std::cout << "aNodeGroupByGhs3dId["<<usedEnforcedNodes<<"] = \""<<aNodeGroupByGhs3dId[usedEnforcedNodes]<<"\""<<std::endl;
1511 #endif
1512       usedEnforcedNodes++;
1513     }
1514     std::cout << "End writting in req and sol file" << std::endl;
1515   }
1516
1517   int nedge[2], ntri[3];
1518     
1519   // GmfEdges
1520   int usedEnforcedEdges = 0;
1521   if (theKeptEnforcedEdges.size()) {
1522     anEdgeGroupByGhs3dId.resize( theKeptEnforcedEdges.size() );
1523 //    idxRequired = GmfOpenMesh(theRequiredFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1524 //    if (!idxRequired)
1525 //      return false;
1526     GmfSetKwd(idx, GmfEdges, theKeptEnforcedEdges.size());
1527 //    GmfSetKwd(idxRequired, GmfEdges, theKeptEnforcedEdges.size());
1528     for(elemSetIt = theKeptEnforcedEdges.begin() ; elemSetIt != theKeptEnforcedEdges.end() ; ++elemSetIt) {
1529       elem = (*elemSetIt);
1530       nodeIt = elem->nodesIterator();
1531       int index=0;
1532       while ( nodeIt->more() ) {
1533         // find MG-Tetra ID
1534         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1535         map< const SMDS_MeshNode*,int >::iterator it = anEnforcedNodeToGhs3dIdMap.find(node);
1536         if (it == anEnforcedNodeToGhs3dIdMap.end()) {
1537           it = anExistingEnforcedNodeToGhs3dIdMap.find(node);
1538           if (it == anEnforcedNodeToGhs3dIdMap.end())
1539             throw "Node not found";
1540         }
1541         nedge[index] = it->second;
1542         index++;
1543       }
1544       GmfSetLin(idx, GmfEdges, nedge[0], nedge[1], dummyint);
1545       anEdgeGroupByGhs3dId[usedEnforcedEdges] = theEnforcedEdges.find(elem)->second;
1546 //      GmfSetLin(idxRequired, GmfEdges, nedge[0], nedge[1], dummyint);
1547       usedEnforcedEdges++;
1548     }
1549 //    GmfCloseMesh(idxRequired);
1550   }
1551
1552
1553   if (usedEnforcedEdges) {
1554     GmfSetKwd(idx, GmfRequiredEdges, usedEnforcedEdges);
1555     for (int enfID=1;enfID<=usedEnforcedEdges;enfID++) {
1556       GmfSetLin(idx, GmfRequiredEdges, enfID);
1557     }
1558   }
1559
1560   // GmfTriangles
1561   int usedEnforcedTriangles = 0;
1562   if (anElemSet.size()+theKeptEnforcedTriangles.size()) {
1563     aFaceGroupByGhs3dId.resize( anElemSet.size()+theKeptEnforcedTriangles.size() );
1564     GmfSetKwd(idx, GmfTriangles, anElemSet.size()+theKeptEnforcedTriangles.size());
1565     int k=0;
1566     for(elemSetIt = anElemSet.begin() ; elemSetIt != anElemSet.end() ; ++elemSetIt,++k) {
1567       elem = (*elemSetIt);
1568       theFaceByGhs3dId.push_back( elem );
1569       nodeIt = elem->nodesIterator();
1570       int index=0;
1571       for ( int j = 0; j < 3; ++j ) {
1572         // find MG-Tetra ID
1573         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1574         map< const SMDS_MeshNode*,int >::iterator it = aNodeToGhs3dIdMap.find(node);
1575         if (it == aNodeToGhs3dIdMap.end())
1576           throw "Node not found";
1577         ntri[index] = it->second;
1578         index++;
1579       }
1580       GmfSetLin(idx, GmfTriangles, ntri[0], ntri[1], ntri[2], dummyint);
1581       aFaceGroupByGhs3dId[k] = "";
1582     }
1583     if ( !theHelper.GetMesh()->HasShapeToMesh() )
1584       SMESHUtils::FreeVector( theFaceByGhs3dId );
1585     if (theKeptEnforcedTriangles.size()) {
1586       for(elemSetIt = theKeptEnforcedTriangles.begin() ; elemSetIt != theKeptEnforcedTriangles.end() ; ++elemSetIt,++k) {
1587         elem = (*elemSetIt);
1588         nodeIt = elem->nodesIterator();
1589         int index=0;
1590         for ( int j = 0; j < 3; ++j ) {
1591           // find MG-Tetra ID
1592           const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1593           map< const SMDS_MeshNode*,int >::iterator it = anEnforcedNodeToGhs3dIdMap.find(node);
1594           if (it == anEnforcedNodeToGhs3dIdMap.end()) {
1595             it = anExistingEnforcedNodeToGhs3dIdMap.find(node);
1596             if (it == anEnforcedNodeToGhs3dIdMap.end())
1597               throw "Node not found";
1598           }
1599           ntri[index] = it->second;
1600           index++;
1601         }
1602         GmfSetLin(idx, GmfTriangles, ntri[0], ntri[1], ntri[2], dummyint);
1603         aFaceGroupByGhs3dId[k] = theEnforcedTriangles.find(elem)->second;
1604         usedEnforcedTriangles++;
1605       }
1606     }
1607   }
1608
1609   
1610   if (usedEnforcedTriangles) {
1611     GmfSetKwd(idx, GmfRequiredTriangles, usedEnforcedTriangles);
1612     for (int enfID=1;enfID<=usedEnforcedTriangles;enfID++)
1613       GmfSetLin(idx, GmfRequiredTriangles, anElemSet.size()+enfID);
1614   }
1615
1616   GmfCloseMesh(idx);
1617   if (idxRequired)
1618     GmfCloseMesh(idxRequired);
1619   if (idxSol)
1620     GmfCloseMesh(idxSol);
1621   
1622   return true;
1623   
1624 }
1625
1626 //=============================================================================
1627 /*!
1628  *Here we are going to use the MG-Tetra mesher with geometry
1629  */
1630 //=============================================================================
1631
1632 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
1633                                 const TopoDS_Shape& theShape)
1634 {
1635   bool Ok(false);
1636   //SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
1637
1638   // we count the number of shapes
1639   // _nbShape = countShape( meshDS, TopAbs_SOLID ); -- 0020330: Pb with MG-Tetra as a submesh
1640   // _nbShape = 0;
1641   TopExp_Explorer expBox ( theShape, TopAbs_SOLID );
1642   // for ( ; expBox.More(); expBox.Next() )
1643   //   _nbShape++;
1644
1645   // create bounding box for every shape inside the compound
1646
1647   // int iShape = 0;
1648   // TopoDS_Shape* tabShape;
1649   // double**      tabBox;
1650   // tabShape = new TopoDS_Shape[_nbShape];
1651   // tabBox   = new double*[_nbShape];
1652   // for (int i=0; i<_nbShape; i++)
1653   //   tabBox[i] = new double[6];
1654   // Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
1655
1656   // for (expBox.ReInit(); expBox.More(); expBox.Next()) {
1657   //   tabShape[iShape] = expBox.Current();
1658   //   Bnd_Box BoundingBox;
1659   //   BRepBndLib::Add(expBox.Current(), BoundingBox);
1660   //   BoundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
1661   //   tabBox[iShape][0] = Xmin; tabBox[iShape][1] = Xmax;
1662   //   tabBox[iShape][2] = Ymin; tabBox[iShape][3] = Ymax;
1663   //   tabBox[iShape][4] = Zmin; tabBox[iShape][5] = Zmax;
1664   //   iShape++;
1665   // }
1666
1667   // a unique working file name
1668   // to avoid access to the same files by eg different users
1669   _genericName = GHS3DPlugin_Hypothesis::GetFileName(_hyp);
1670   TCollection_AsciiString aGenericName((char*) _genericName.c_str() );
1671   TCollection_AsciiString aGenericNameRequired = aGenericName + "_required";
1672
1673   TCollection_AsciiString aLogFileName    = aGenericName + ".log";    // log
1674   TCollection_AsciiString aResultFileName;
1675
1676   TCollection_AsciiString aGMFFileName, aRequiredVerticesFileName, aSolFileName, aResSolFileName;
1677 //#ifdef _DEBUG_
1678   aGMFFileName              = aGenericName + ".mesh"; // GMF mesh file
1679   aResultFileName           = aGenericName + "Vol.mesh"; // GMF mesh file
1680   aResSolFileName           = aGenericName + "Vol.sol"; // GMF mesh file
1681   aRequiredVerticesFileName = aGenericNameRequired + ".mesh"; // GMF required vertices mesh file
1682   aSolFileName              = aGenericNameRequired + ".sol"; // GMF solution file
1683 //#else
1684 //  aGMFFileName    = aGenericName + ".meshb"; // GMF mesh file
1685 //  aResultFileName = aGenericName + "Vol.meshb"; // GMF mesh file
1686 //  aRequiredVerticesFileName    = aGenericNameRequired + ".meshb"; // GMF required vertices mesh file
1687 //  aSolFileName    = aGenericNameRequired + ".solb"; // GMF solution file
1688 //#endif
1689   
1690   std::map <int,int> aNodeId2NodeIndexMap, aSmdsToGhs3dIdMap, anEnforcedNodeIdToGhs3dIdMap;
1691   //std::map <int,const SMDS_MeshNode*> aGhs3dIdToNodeMap;
1692   std::map <int, int> nodeID2nodeIndexMap;
1693   std::map<std::vector<double>, std::string> enfVerticesWithGroup;
1694   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues coordsSizeMap = GHS3DPlugin_Hypothesis::GetEnforcedVerticesCoordsSize(_hyp);
1695   GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap enforcedNodes = GHS3DPlugin_Hypothesis::GetEnforcedNodes(_hyp);
1696   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap enforcedEdges = GHS3DPlugin_Hypothesis::GetEnforcedEdges(_hyp);
1697   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap enforcedTriangles = GHS3DPlugin_Hypothesis::GetEnforcedTriangles(_hyp);
1698 //   TIDSortedElemSet enforcedQuadrangles = GHS3DPlugin_Hypothesis::GetEnforcedQuadrangles(_hyp);
1699   GHS3DPlugin_Hypothesis::TID2SizeMap nodeIDToSizeMap = GHS3DPlugin_Hypothesis::GetNodeIDToSizeMap(_hyp);
1700
1701   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList enfVertices = GHS3DPlugin_Hypothesis::GetEnforcedVertices(_hyp);
1702   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList::const_iterator enfVerIt = enfVertices.begin();
1703   std::vector<double> coords;
1704
1705   for ( ; enfVerIt != enfVertices.end() ; ++enfVerIt)
1706   {
1707     GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* enfVertex = (*enfVerIt);
1708 //     if (enfVertex->geomEntry.empty() && enfVertex->coords.size()) {
1709     if (enfVertex->coords.size()) {
1710       coordsSizeMap.insert(make_pair(enfVertex->coords,enfVertex->size));
1711       enfVerticesWithGroup.insert(make_pair(enfVertex->coords,enfVertex->groupName));
1712 //       MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<enfVertex->coords[0]<<","<<enfVertex->coords[1]<<","<<enfVertex->coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
1713     }
1714     else {
1715 //     if (!enfVertex->geomEntry.empty()) {
1716       TopoDS_Shape GeomShape = entryToShape(enfVertex->geomEntry);
1717 //       GeomType = GeomShape.ShapeType();
1718
1719 //       if (!enfVertex->isCompound) {
1720 // //       if (GeomType == TopAbs_VERTEX) {
1721 //         coords.clear();
1722 //         aPnt = BRep_Tool::Pnt(TopoDS::Vertex(GeomShape));
1723 //         coords.push_back(aPnt.X());
1724 //         coords.push_back(aPnt.Y());
1725 //         coords.push_back(aPnt.Z());
1726 //         if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
1727 //           coordsSizeMap.insert(make_pair(coords,enfVertex->size));
1728 //           enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
1729 //         }
1730 //       }
1731 //
1732 //       // Group Management
1733 //       else {
1734 //       if (GeomType == TopAbs_COMPOUND){
1735         for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){
1736           coords.clear();
1737           if (it.Value().ShapeType() == TopAbs_VERTEX){
1738             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(it.Value()));
1739             coords.push_back(aPnt.X());
1740             coords.push_back(aPnt.Y());
1741             coords.push_back(aPnt.Z());
1742             if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
1743               coordsSizeMap.insert(make_pair(coords,enfVertex->size));
1744               enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
1745 //               MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<coords[0]<<","<<coords[1]<<","<<coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
1746             }
1747           }
1748         }
1749 //       }
1750     }
1751   }
1752   int nbEnforcedVertices = coordsSizeMap.size();
1753   int nbEnforcedNodes = enforcedNodes.size();
1754   
1755   std::string tmpStr;
1756   (nbEnforcedNodes <= 1) ? tmpStr = "node" : "nodes";
1757   std::cout << nbEnforcedNodes << " enforced " << tmpStr << " from hypo" << std::endl;
1758   (nbEnforcedVertices <= 1) ? tmpStr = "vertex" : "vertices";
1759   std::cout << nbEnforcedVertices << " enforced " << tmpStr << " from hypo" << std::endl;
1760   
1761   SMESH_MesherHelper helper( theMesh );
1762   helper.SetSubShape( theShape );
1763
1764   std::vector <const SMDS_MeshNode*> aNodeByGhs3dId, anEnforcedNodeByGhs3dId;
1765   std::vector <const SMDS_MeshElement*> aFaceByGhs3dId;
1766   std::map<const SMDS_MeshNode*,int> aNodeToGhs3dIdMap;
1767   std::vector<std::string> aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId;
1768
1769   // proxyMesh must live till readGMFFile() as a proxy face can be used by
1770   // MG-Tetra for domain indication
1771   //{
1772     SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( theMesh ));
1773
1774     // make prisms on quadrangles
1775     if ( theMesh.NbQuadrangles() > 0 )
1776     {
1777       vector<SMESH_ProxyMesh::Ptr> components;
1778       for (expBox.ReInit(); expBox.More(); expBox.Next())
1779       {
1780         if ( _viscousLayersHyp )
1781         {
1782           proxyMesh = _viscousLayersHyp->Compute( theMesh, expBox.Current() );
1783           if ( !proxyMesh )
1784             return false;
1785         }
1786         StdMeshers_QuadToTriaAdaptor* q2t = new StdMeshers_QuadToTriaAdaptor;
1787         q2t->Compute( theMesh, expBox.Current(), proxyMesh.get() );
1788         components.push_back( SMESH_ProxyMesh::Ptr( q2t ));
1789       }
1790       proxyMesh.reset( new SMESH_ProxyMesh( components ));
1791     }
1792     // build viscous layers
1793     else if ( _viscousLayersHyp )
1794     {
1795       proxyMesh = _viscousLayersHyp->Compute( theMesh, theShape );
1796       if ( !proxyMesh )
1797         return false;
1798     }
1799
1800     // Ok = (writePoints( aPointsFile, helper, 
1801     //                    aSmdsToGhs3dIdMap, anEnforcedNodeIdToGhs3dIdMap, aGhs3dIdToNodeMap, 
1802     //                    nodeIDToSizeMap,
1803     //                    coordsSizeMap, enforcedNodes, enforcedEdges, enforcedTriangles)
1804     //       &&
1805     //       writeFaces ( aFacesFile, *proxyMesh, theShape, 
1806     //                    aSmdsToGhs3dIdMap, anEnforcedNodeIdToGhs3dIdMap,
1807     //                    enforcedEdges, enforcedTriangles ));
1808     int anInvalidEnforcedFlags = 0;
1809     Ok = writeGMFFile(aGMFFileName.ToCString(), aRequiredVerticesFileName.ToCString(), aSolFileName.ToCString(),
1810                       *proxyMesh, helper,
1811                       aNodeByGhs3dId, aFaceByGhs3dId, aNodeToGhs3dIdMap,
1812                       aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId,
1813                       enforcedNodes, enforcedEdges, enforcedTriangles, /*enforcedQuadrangles,*/
1814                       enfVerticesWithGroup, coordsSizeMap, anInvalidEnforcedFlags);
1815     //}
1816
1817   // Write aSmdsToGhs3dIdMap to temp file
1818   TCollection_AsciiString aSmdsToGhs3dIdMapFileName;
1819   aSmdsToGhs3dIdMapFileName = aGenericName + ".ids";  // ids relation
1820   ofstream aIdsFile  ( aSmdsToGhs3dIdMapFileName.ToCString()  , ios::out);
1821   Ok = aIdsFile.rdbuf()->is_open();
1822   if (!Ok) {
1823     INFOS( "Can't write into " << aSmdsToGhs3dIdMapFileName);
1824     return error(SMESH_Comment("Can't write into ") << aSmdsToGhs3dIdMapFileName);
1825   }
1826   INFOS( "Writing ids relation into " << aSmdsToGhs3dIdMapFileName);
1827   aIdsFile << "Smds MG-Tetra" << std::endl;
1828   map <int,int>::const_iterator myit;
1829   for (myit=aSmdsToGhs3dIdMap.begin() ; myit != aSmdsToGhs3dIdMap.end() ; ++myit) {
1830     aIdsFile << myit->first << " " << myit->second << std::endl;
1831   }
1832
1833   aIdsFile.close();
1834   
1835   if ( ! Ok ) {
1836     if ( !_keepFiles ) {
1837       removeFile( aGMFFileName );
1838       removeFile( aRequiredVerticesFileName );
1839       removeFile( aSolFileName );
1840       removeFile( aSmdsToGhs3dIdMapFileName );
1841     }
1842     return error(COMPERR_BAD_INPUT_MESH);
1843   }
1844   removeFile( aResultFileName ); // needed for boundary recovery module usage
1845
1846   // -----------------
1847   // run MG-Tetra mesher
1848   // -----------------
1849
1850   TCollection_AsciiString cmd( (char*)GHS3DPlugin_Hypothesis::CommandToRun( _hyp ).c_str() );
1851   
1852   cmd += TCollection_AsciiString(" --in ") + aGMFFileName;
1853   if ( nbEnforcedVertices + nbEnforcedNodes)
1854     cmd += TCollection_AsciiString(" --required_vertices ") + aGenericNameRequired;
1855   cmd += TCollection_AsciiString(" --out ") + aResultFileName;
1856   if ( !_logInStandardOutput )
1857     cmd += TCollection_AsciiString(" 1>" ) + aLogFileName;  // dump into file
1858
1859   std::cout << std::endl;
1860   std::cout << "MG-Tetra execution..." << std::endl;
1861   std::cout << cmd << std::endl;
1862
1863   _compute_canceled = false;
1864
1865   int err = system( cmd.ToCString() ); // run
1866
1867   std::string errStr;
1868   if ( err )
1869     errStr = SMESH_Comment("system(mg-tetra.exe ...) command failed with error: ")
1870       << strerror( errno );
1871   else
1872     std::cout << std::endl << "End of MG-Tetra execution !" << std::endl;
1873
1874   // --------------
1875   // read a result
1876   // --------------
1877
1878   // Mapping the result file
1879
1880   // int fileOpen;
1881   // fileOpen = open( aResultFileName.ToCString(), O_RDONLY);
1882   // if ( fileOpen < 0 ) {
1883   //   std::cout << std::endl;
1884   //   std::cout << "Can't open the " << aResultFileName.ToCString() << " MG-Tetra output file" << std::endl;
1885   //   std::cout << "Log: " << aLogFileName << std::endl;
1886   //   Ok = false;
1887   // }
1888   // else {
1889     GHS3DPlugin_Hypothesis::TSetStrings groupsToRemove = GHS3DPlugin_Hypothesis::GetGroupsToRemove(_hyp);
1890     bool toMeshHoles =
1891       _hyp ? _hyp->GetToMeshHoles(true) : GHS3DPlugin_Hypothesis::DefaultMeshHoles();
1892     const bool toMakeGroupsOfDomains = GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains( _hyp );
1893
1894     helper.IsQuadraticSubMesh( theShape );
1895     helper.SetElementsOnShape( false );
1896
1897 //     Ok = readResultFile( fileOpen,
1898 // #ifdef WIN32
1899 //                          aResultFileName.ToCString(),
1900 // #endif
1901 //                          this,
1902 //                          /*theMesh, */helper, tabShape, tabBox, _nbShape, 
1903 //                          aGhs3dIdToNodeMap, aNodeId2NodeIndexMap,
1904 //                          toMeshHoles, 
1905 //                          nbEnforcedVertices, nbEnforcedNodes, 
1906 //                          enforcedEdges, enforcedTriangles,
1907 //                          toMakeGroupsOfDomains );
1908                          
1909     Ok = readGMFFile(aResultFileName.ToCString(),
1910                      this,
1911                      &helper, aNodeByGhs3dId, aFaceByGhs3dId, aNodeToGhs3dIdMap,
1912                      aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId,
1913                      groupsToRemove, toMakeGroupsOfDomains, toMeshHoles);
1914
1915     removeEmptyGroupsOfDomains( helper.GetMesh(), /*notEmptyAsWell =*/ !toMakeGroupsOfDomains );
1916     //}
1917
1918
1919
1920
1921   // ---------------------
1922   // remove working files
1923   // ---------------------
1924
1925   if ( Ok )
1926   {
1927     if ( anInvalidEnforcedFlags )
1928       error( COMPERR_WARNING, flagsToErrorStr( anInvalidEnforcedFlags ));
1929     if ( _removeLogOnSuccess )
1930       removeFile( aLogFileName );
1931     // if ( _hyp && _hyp->GetToMakeGroupsOfDomains() )
1932     //   error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since the mesh is on shape" );
1933   }
1934   else if ( OSD_File( aLogFileName ).Size() > 0 )
1935   {
1936     // get problem description from the log file
1937     _Ghs2smdsConvertor conv( aNodeByGhs3dId, proxyMesh );
1938     storeErrorDescription( aLogFileName, conv );
1939   }
1940   else
1941   {
1942     // the log file is empty
1943     removeFile( aLogFileName );
1944     INFOS( "MG-Tetra Error, " << errStr);
1945     error(COMPERR_ALGO_FAILED, errStr);
1946   }
1947
1948   if ( !_keepFiles ) {
1949     if (! Ok && _compute_canceled)
1950       removeFile( aLogFileName );
1951     removeFile( aGMFFileName );
1952     removeFile( aRequiredVerticesFileName );
1953     removeFile( aSolFileName );
1954     removeFile( aResSolFileName );
1955     removeFile( aResultFileName );
1956     removeFile( aSmdsToGhs3dIdMapFileName );
1957   }
1958   std::cout << "<" << aResultFileName.ToCString() << "> MG-Tetra output file ";
1959   if ( !Ok )
1960     std::cout << "not ";
1961   std::cout << "treated !" << std::endl;
1962   std::cout << std::endl;
1963
1964   // _nbShape = 0;    // re-initializing _nbShape for the next Compute() method call
1965   // delete [] tabShape;
1966   // delete [] tabBox;
1967
1968   return Ok;
1969 }
1970
1971 //=============================================================================
1972 /*!
1973  *Here we are going to use the MG-Tetra mesher w/o geometry
1974  */
1975 //=============================================================================
1976 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
1977                                 SMESH_MesherHelper* theHelper)
1978 {
1979   MESSAGE("GHS3DPlugin_GHS3D::Compute()");
1980
1981   theHelper->IsQuadraticSubMesh( theHelper->GetSubShape() );
1982
1983   // a unique working file name
1984   // to avoid access to the same files by eg different users
1985   _genericName = GHS3DPlugin_Hypothesis::GetFileName(_hyp);
1986   TCollection_AsciiString aGenericName((char*) _genericName.c_str() );
1987   TCollection_AsciiString aGenericNameRequired = aGenericName + "_required";
1988
1989   TCollection_AsciiString aLogFileName    = aGenericName + ".log";    // log
1990   TCollection_AsciiString aResultFileName;
1991   bool Ok;
1992
1993   TCollection_AsciiString aGMFFileName, aRequiredVerticesFileName, aSolFileName, aResSolFileName;
1994 //#ifdef _DEBUG_
1995   aGMFFileName              = aGenericName + ".mesh"; // GMF mesh file
1996   aResultFileName           = aGenericName + "Vol.mesh"; // GMF mesh file
1997   aResSolFileName           = aGenericName + "Vol.sol"; // GMF mesh file
1998   aRequiredVerticesFileName = aGenericNameRequired + ".mesh"; // GMF required vertices mesh file
1999   aSolFileName              = aGenericNameRequired + ".sol"; // GMF solution file
2000 //#else
2001 //  aGMFFileName    = aGenericName + ".meshb"; // GMF mesh file
2002 //  aResultFileName = aGenericName + "Vol.meshb"; // GMF mesh file
2003 //  aRequiredVerticesFileName    = aGenericNameRequired + ".meshb"; // GMF required vertices mesh file
2004 //  aSolFileName    = aGenericNameRequired + ".solb"; // GMF solution file
2005 //#endif
2006
2007   std::map <int, int> nodeID2nodeIndexMap;
2008   std::map<std::vector<double>, std::string> enfVerticesWithGroup;
2009   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues coordsSizeMap;
2010   TopoDS_Shape GeomShape;
2011 //   TopAbs_ShapeEnum GeomType;
2012   std::vector<double> coords;
2013   gp_Pnt aPnt;
2014   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* enfVertex;
2015
2016   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList enfVertices = GHS3DPlugin_Hypothesis::GetEnforcedVertices(_hyp);
2017   GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList::const_iterator enfVerIt = enfVertices.begin();
2018
2019   for ( ; enfVerIt != enfVertices.end() ; ++enfVerIt)
2020   {
2021     enfVertex = (*enfVerIt);
2022 //     if (enfVertex->geomEntry.empty() && enfVertex->coords.size()) {
2023     if (enfVertex->coords.size()) {
2024       coordsSizeMap.insert(make_pair(enfVertex->coords,enfVertex->size));
2025       enfVerticesWithGroup.insert(make_pair(enfVertex->coords,enfVertex->groupName));
2026 //       MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<enfVertex->coords[0]<<","<<enfVertex->coords[1]<<","<<enfVertex->coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
2027     }
2028     else {
2029 //     if (!enfVertex->geomEntry.empty()) {
2030       GeomShape = entryToShape(enfVertex->geomEntry);
2031 //       GeomType = GeomShape.ShapeType();
2032
2033 //       if (!enfVertex->isCompound) {
2034 // //       if (GeomType == TopAbs_VERTEX) {
2035 //         coords.clear();
2036 //         aPnt = BRep_Tool::Pnt(TopoDS::Vertex(GeomShape));
2037 //         coords.push_back(aPnt.X());
2038 //         coords.push_back(aPnt.Y());
2039 //         coords.push_back(aPnt.Z());
2040 //         if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
2041 //           coordsSizeMap.insert(make_pair(coords,enfVertex->size));
2042 //           enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
2043 //         }
2044 //       }
2045 //
2046 //       // Group Management
2047 //       else {
2048 //       if (GeomType == TopAbs_COMPOUND){
2049         for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){
2050           coords.clear();
2051           if (it.Value().ShapeType() == TopAbs_VERTEX){
2052             aPnt = BRep_Tool::Pnt(TopoDS::Vertex(it.Value()));
2053             coords.push_back(aPnt.X());
2054             coords.push_back(aPnt.Y());
2055             coords.push_back(aPnt.Z());
2056             if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
2057               coordsSizeMap.insert(make_pair(coords,enfVertex->size));
2058               enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
2059 //               MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<coords[0]<<","<<coords[1]<<","<<coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
2060             }
2061           }
2062         }
2063 //       }
2064     }
2065   }
2066
2067 //   const SMDS_MeshNode* enfNode;
2068   GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap enforcedNodes = GHS3DPlugin_Hypothesis::GetEnforcedNodes(_hyp);
2069 //   GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap::const_iterator enfNodeIt = enforcedNodes.begin();
2070 //   for ( ; enfNodeIt != enforcedNodes.end() ; ++enfNodeIt)
2071 //   {
2072 //     enfNode = enfNodeIt->first;
2073 //     coords.clear();
2074 //     coords.push_back(enfNode->X());
2075 //     coords.push_back(enfNode->Y());
2076 //     coords.push_back(enfNode->Z());
2077 //     if (enfVerticesWithGro
2078 //       enfVerticesWithGroup.insert(make_pair(coords,enfNodeIt->second));
2079 //   }
2080
2081
2082   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap enforcedEdges = GHS3DPlugin_Hypothesis::GetEnforcedEdges(_hyp);
2083   GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap enforcedTriangles = GHS3DPlugin_Hypothesis::GetEnforcedTriangles(_hyp);
2084 //   TIDSortedElemSet enforcedQuadrangles = GHS3DPlugin_Hypothesis::GetEnforcedQuadrangles(_hyp);
2085   GHS3DPlugin_Hypothesis::TID2SizeMap nodeIDToSizeMap = GHS3DPlugin_Hypothesis::GetNodeIDToSizeMap(_hyp);
2086
2087   std::string tmpStr;
2088
2089   int nbEnforcedVertices = coordsSizeMap.size();
2090   int nbEnforcedNodes = enforcedNodes.size();
2091   (nbEnforcedNodes <= 1) ? tmpStr = "node" : tmpStr = "nodes";
2092   std::cout << nbEnforcedNodes << " enforced " << tmpStr << " from hypo" << std::endl;
2093   (nbEnforcedVertices <= 1) ? tmpStr = "vertex" : tmpStr = "vertices";
2094   std::cout << nbEnforcedVertices << " enforced " << tmpStr << " from hypo" << std::endl;
2095
2096   std::vector <const SMDS_MeshNode*> aNodeByGhs3dId, anEnforcedNodeByGhs3dId;
2097   std::vector <const SMDS_MeshElement*> aFaceByGhs3dId;
2098   std::map<const SMDS_MeshNode*,int> aNodeToGhs3dIdMap;
2099   std::vector<std::string> aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId;
2100
2101   // proxyMesh must live till readGMFFile() as a proxy face can be used by
2102   // MG-Tetra for domain indication
2103   //{
2104     SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( theMesh ));
2105     if ( theMesh.NbQuadrangles() > 0 )
2106     {
2107       StdMeshers_QuadToTriaAdaptor* aQuad2Trias = new StdMeshers_QuadToTriaAdaptor;
2108       aQuad2Trias->Compute( theMesh );
2109       proxyMesh.reset( aQuad2Trias );
2110     }
2111
2112     int anInvalidEnforcedFlags = 0;
2113     Ok = writeGMFFile(aGMFFileName.ToCString(), aRequiredVerticesFileName.ToCString(), aSolFileName.ToCString(),
2114                       *proxyMesh, *theHelper,
2115                       aNodeByGhs3dId, aFaceByGhs3dId, aNodeToGhs3dIdMap,
2116                       aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId,
2117                       enforcedNodes, enforcedEdges, enforcedTriangles,
2118                       enfVerticesWithGroup, coordsSizeMap, anInvalidEnforcedFlags);
2119     //}
2120
2121   // -----------------
2122   // run MG-Tetra mesher
2123   // -----------------
2124
2125   TCollection_AsciiString cmd = TCollection_AsciiString((char*)GHS3DPlugin_Hypothesis::CommandToRun( _hyp, false ).c_str());
2126
2127   cmd += TCollection_AsciiString(" --in ") + aGMFFileName;
2128   if ( nbEnforcedVertices + nbEnforcedNodes)
2129     cmd += TCollection_AsciiString(" --required_vertices ") + aGenericNameRequired;
2130   cmd += TCollection_AsciiString(" --out ") + aResultFileName;
2131   if ( !_logInStandardOutput )
2132     cmd += TCollection_AsciiString(" 1>" ) + aLogFileName;  // dump into file
2133
2134   std::cout << std::endl;
2135   std::cout << "MG-Tetra execution..." << std::endl;
2136   std::cout << cmd << std::endl;
2137
2138   _compute_canceled = false;
2139
2140   int err = system( cmd.ToCString() ); // run
2141
2142   std::string errStr;
2143   if ( err )
2144     errStr = SMESH_Comment("system(mg-tetra.exe ...) command failed with error: ")
2145       << strerror( errno );
2146   else
2147     std::cout << std::endl << "End of MG-Tetra execution !" << std::endl;
2148
2149   // --------------
2150   // read a result
2151   // --------------
2152   GHS3DPlugin_Hypothesis::TSetStrings groupsToRemove = GHS3DPlugin_Hypothesis::GetGroupsToRemove(_hyp);
2153   const bool toMakeGroupsOfDomains = GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains( _hyp );
2154
2155   Ok = readGMFFile(aResultFileName.ToCString(),
2156                    this,
2157                    theHelper, aNodeByGhs3dId, aFaceByGhs3dId, aNodeToGhs3dIdMap,
2158                    aNodeGroupByGhs3dId, anEdgeGroupByGhs3dId, aFaceGroupByGhs3dId,
2159                    groupsToRemove, toMakeGroupsOfDomains);
2160
2161   updateMeshGroups(theHelper->GetMesh(), groupsToRemove);
2162   removeEmptyGroupsOfDomains( theHelper->GetMesh(), /*notEmptyAsWell =*/ !toMakeGroupsOfDomains );
2163
2164   if ( Ok ) {
2165     GHS3DPlugin_Hypothesis* that = (GHS3DPlugin_Hypothesis*)this->_hyp;
2166     if (that)
2167       that->ClearGroupsToRemove();
2168   }
2169   // ---------------------
2170   // remove working files
2171   // ---------------------
2172
2173   if ( Ok )
2174   {
2175     if ( anInvalidEnforcedFlags )
2176       error( COMPERR_WARNING, flagsToErrorStr( anInvalidEnforcedFlags ));
2177     if ( _removeLogOnSuccess )
2178       removeFile( aLogFileName );
2179
2180     //if ( !toMakeGroupsOfDomains && _hyp && _hyp->GetToMakeGroupsOfDomains() )
2181     //error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since 'toMeshHoles' is OFF." );
2182   }
2183   else if ( OSD_File( aLogFileName ).Size() > 0 )
2184   {
2185     // get problem description from the log file
2186     _Ghs2smdsConvertor conv( aNodeByGhs3dId, proxyMesh );
2187     storeErrorDescription( aLogFileName, conv );
2188   }
2189   else {
2190     // the log file is empty
2191     removeFile( aLogFileName );
2192     INFOS( "MG-Tetra Error, " << errStr);
2193     error(COMPERR_ALGO_FAILED, errStr);
2194   }
2195
2196   if ( !_keepFiles )
2197   {
2198     if (! Ok && _compute_canceled)
2199       removeFile( aLogFileName );
2200     removeFile( aGMFFileName );
2201     removeFile( aResultFileName );
2202     removeFile( aRequiredVerticesFileName );
2203     removeFile( aSolFileName );
2204     removeFile( aResSolFileName );
2205   }
2206   return Ok;
2207 }
2208
2209 void GHS3DPlugin_GHS3D::CancelCompute()
2210 {
2211   _compute_canceled = true;
2212 #ifdef WIN32
2213 #else
2214   std::string cmd = "ps xo pid,args | grep " + _genericName;
2215   //cmd += " | grep -e \"^ *[0-9]\\+ \\+" + GHS3DPlugin_Hypothesis::GetExeName() + "\"";
2216   cmd += " | awk '{print $1}' | xargs kill -9 > /dev/null 2>&1";
2217   system( cmd.c_str() );
2218 #endif
2219 }
2220
2221 //================================================================================
2222 /*!
2223  * \brief Provide human readable text by error code reported by MG-Tetra
2224  */
2225 //================================================================================
2226
2227 static const char* translateError(const int errNum)
2228 {
2229   switch ( errNum ) {
2230   case 0:
2231     return "The surface mesh includes a face of type other than edge, "
2232       "triangle or quadrilateral. This face type is not supported.";
2233   case 1:
2234     return "Not enough memory for the face table.";
2235   case 2:
2236     return "Not enough memory.";
2237   case 3:
2238     return "Not enough memory.";
2239   case 4:
2240     return "Face is ignored.";
2241   case 5:
2242     return "End of file. Some data are missing in the file.";
2243   case 6:
2244     return "Read error on the file. There are wrong data in the file.";
2245   case 7:
2246     return "the metric file is inadequate (dimension other than 3).";
2247   case 8:
2248     return "the metric file is inadequate (values not per vertices).";
2249   case 9:
2250     return "the metric file contains more than one field.";
2251   case 10:
2252     return "the number of values in the \".bb\" (metric file) is incompatible with the expected"
2253       "value of number of mesh vertices in the \".noboite\" file.";
2254   case 12:
2255     return "Too many sub-domains.";
2256   case 13:
2257     return "the number of vertices is negative or null.";
2258   case 14:
2259     return "the number of faces is negative or null.";
2260   case 15:
2261     return "A face has a null vertex.";
2262   case 22:
2263     return "incompatible data.";
2264   case 131:
2265     return "the number of vertices is negative or null.";
2266   case 132:
2267     return "the number of vertices is negative or null (in the \".mesh\" file).";
2268   case 133:
2269     return "the number of faces is negative or null.";
2270   case 1000:
2271     return "A face appears more than once in the input surface mesh.";
2272   case 1001:
2273     return "An edge appears more than once in the input surface mesh.";
2274   case 1002:
2275     return "A face has a vertex negative or null.";
2276   case 1003:
2277     return "NOT ENOUGH MEMORY.";
2278   case 2000:
2279     return "Not enough available memory.";
2280   case 2002:
2281     return "Some initial points cannot be inserted. The surface mesh is probably very bad "
2282       "in terms of quality or the input list of points is wrong.";
2283   case 2003:
2284     return "Some vertices are too close to one another or coincident.";
2285   case 2004:
2286     return "Some vertices are too close to one another or coincident.";
2287   case 2012:
2288     return "A vertex cannot be inserted.";
2289   case 2014:
2290     return "There are at least two points considered as coincident.";
2291   case 2103:
2292     return "Some vertices are too close to one another or coincident.";
2293   case 3000:
2294     return "The surface mesh regeneration step has failed.";
2295   case 3009:
2296     return "Constrained edge cannot be enforced.";
2297   case 3019:
2298     return "Constrained face cannot be enforced.";
2299   case 3029:
2300     return "Missing faces.";
2301   case 3100:
2302     return "No guess to start the definition of the connected component(s).";
2303   case 3101:
2304     return "The surface mesh includes at least one hole. The domain is not well defined.";
2305   case 3102:
2306     return "Impossible to define a component.";
2307   case 3103:
2308     return "The surface edge intersects another surface edge.";
2309   case 3104:
2310     return "The surface edge intersects the surface face.";
2311   case 3105:
2312     return "One boundary point lies within a surface face.";
2313   case 3106:
2314     return "One surface edge intersects a surface face.";
2315   case 3107:
2316     return "One boundary point lies within a surface edge.";
2317   case 3108:
2318     return "Insufficient memory ressources detected due to a bad quality surface mesh leading "
2319       "to too many swaps.";
2320   case 3109:
2321     return "Edge is unique (i.e., bounds a hole in the surface).";
2322   case 3122:
2323     return "Presumably, the surface mesh is not compatible with the domain being processed.";
2324   case 3123:
2325     return "Too many components, too many sub-domain.";
2326   case 3209:
2327     return "The surface mesh includes at least one hole. "
2328       "Therefore there is no domain properly defined.";
2329   case 3300:
2330     return "Statistics.";
2331   case 3400:
2332     return "Statistics.";
2333   case 3500:
2334     return "Warning, it is dramatically tedious to enforce the boundary items.";
2335   case 4000:
2336     return "Not enough memory at this time, nevertheless, the program continues. "
2337       "The expected mesh will be correct but not really as large as required.";
2338   case 4002:
2339     return "see above error code, resulting quality may be poor.";
2340   case 4003:
2341     return "Not enough memory at this time, nevertheless, the program continues (warning).";
2342   case 8000:
2343     return "Unknown face type.";
2344   case 8005:
2345   case 8006:
2346     return "End of file. Some data are missing in the file.";
2347   case 9000:
2348     return "A too small volume element is detected.";
2349   case 9001:
2350     return "There exists at least a null or negative volume element.";
2351   case 9002:
2352     return "There exist null or negative volume elements.";
2353   case 9003:
2354     return "A too small volume element is detected. A face is considered being degenerated.";
2355   case 9100:
2356     return "Some element is suspected to be very bad shaped or wrong.";
2357   case 9102:
2358     return "A too bad quality face is detected. This face is considered degenerated.";
2359   case 9112:
2360     return "A too bad quality face is detected. This face is degenerated.";
2361   case 9122:
2362     return "Presumably, the surface mesh is not compatible with the domain being processed.";
2363   case 9999:
2364     return "Abnormal error occured, contact hotline.";
2365   case 23600:
2366     return "Not enough memory for the face table.";
2367   case 23601:
2368     return "The algorithm cannot run further. "
2369       "The surface mesh is probably very bad in terms of quality.";
2370   case 23602:
2371     return "Bad vertex number.";
2372   case 1001200:
2373     return "Cannot close mesh file NomFil.";
2374   case 1002010:
2375     return "There are wrong data.";
2376   case 1002120:
2377     return "The number of faces is negative or null.";
2378   case 1002170:
2379     return "The number of vertices is negative or null in the '.sol' file.";
2380   case 1002190:
2381     return "The number of tetrahedra is negative or null.";
2382   case 1002210:
2383     return "The number of vertices is negative or null.";
2384   case 1002211:
2385     return "A face has a vertex negative or null.";
2386   case 1002270:
2387     return "The field is not a size in file NomFil.";
2388   case 1002280:
2389     return "A count is wrong in the enclosing box in the .boite.mesh input "
2390       "file (option '--read_boite').";
2391   case 1002290:
2392     return "A tetrahedron has a vertex with a negative number.";
2393   case 1002300:
2394     return "the 'MeshVersionFormatted' is not 1 or 2 in the '.mesh' file or the '.sol'.";
2395  case 1002370:
2396    return "The number of values in the '.sol' (metric file) is incompatible with "
2397      "the expected value of number of mesh vertices in the '.mesh' file.";
2398   case 1003000:
2399     return "Not enough memory.";
2400   case 1003020:
2401     return "Not enough memory for the face table.";
2402   case 1003050:
2403     return "Insufficient memory ressources detected due to a bad quality "
2404       "surface mesh leading to too many swaps.";
2405   case 1005010:
2406     return "The surface coordinates of a vertex are differing from the "
2407       "volume coordinates, probably due to a precision problem.";
2408   case 1005050:
2409     return "Invalid dimension. Dimension 3 expected.";
2410   case 1005100:
2411     return "A point has a tag 0. This point is probably outside the domain which has been meshed.";
2412   case 1005103:
2413     return "The vertices of an element are too close to one another or coincident.";
2414   case 1005104:
2415     return "There are at least two points whose distance is very small, and considered as coincident.";
2416   case 1005105:
2417     return "Two vertices are too close to one another or coincident.";
2418   case 1005106:
2419     return "A vertex cannot be inserted.";
2420   case 1005107:
2421     return "Two vertices are too close to one another or coincident. Note : When "
2422       "this error occurs during the overconstrained processing phase, this is only "
2423       "a warning which means that it is difficult to break some overconstrained facets.";
2424   case 1005110:
2425     return "Two surface edges are intersecting.";
2426   case 1005120:
2427     return "A surface edge intersects a surface face.";
2428   case 1005150:
2429     return "A boundary point lies within a surface face.";
2430   case 1005160:
2431     return "A boundary point lies within a surface edge.";
2432   case 1005200:
2433     return "A surface mesh appears more than once in the input surface mesh.";
2434   case 1005210:
2435     return "An edge appears more than once in the input surface mesh.";
2436   case 1005225:
2437     return "Surface with unvalid triangles.";
2438   case 1005270:
2439     return "The metric in the '.sol' file contains more than one field.";
2440   case 1005300:
2441     return "The surface mesh includes at least one hole. The domain is not well defined.";
2442   case 1005301:
2443     return "Presumably, the surface mesh is not compatible with the domain being processed (warning).";
2444   case 1005302:
2445     return "Probable faces overlapping somewher.";
2446   case 1005320:
2447     return "The quadratic version does not work with prescribed free edges.";
2448   case 1005321:
2449     return "The quadratic version does not work with a volume mesh.";
2450   case 1005370:
2451     return "The metric in the '.sol' file is inadequate (values not per vertices).";
2452   case 1005371:
2453     return "The number of vertices in the '.sol' is different from the one in the "
2454       "'.mesh' file for the required vertices (option '--required_vertices').";
2455   case 1005372:
2456     return "More than one type in file NomFil. The type must be equal to 1 in the '.sol'"
2457       "for the required vertices (option '--required_vertices').";
2458   case 1005515:
2459     return "Bad vertex number.";
2460   case 1005560:
2461     return "No guess to start the definition of the connected component(s).";
2462   case 1005602:
2463     return "Some initial points cannot be inserted.";
2464   case 1005620:
2465     return "A too bad quality face is detected. This face is considered degenerated.";
2466   case 1005621:
2467     return "A too bad quality face is detected. This face is degenerated.";
2468   case 1005622:
2469     return "The algorithm cannot run further.";
2470   case 1005690:
2471     return "A too small volume element is detected.";
2472   case 1005691:
2473     return "A tetrahedra is suspected to be very bad shaped or wrong.";
2474   case 1005692:
2475     return "There is at least a null or negative volume element. The resulting mesh"
2476       "may be inappropriate.";
2477   case 1005693:
2478     return "There are some null or negative volume element. The resulting mesh may"
2479       "be inappropriate.";
2480   case 1005820:
2481     return "An edge is unique (i.e., bounds a hole in the surface).";
2482   case 1007000:
2483     return "Abnormal or internal error.";
2484   case 1007010:
2485     return "Too many components with respect to too many sub-domain.";
2486   case 1007400:
2487     return "An internal error has been encountered or a signal has been received. "
2488       "Current mesh will not be saved.";
2489   case 1008491:
2490     return "Impossible to define a component.";
2491   case 1008410:
2492     return "There are some overconstrained edges.";
2493   case 1008420:
2494     return "There are some overconstrained facets.";
2495   case 1008422:
2496     return "Give the number of missing faces (information given when regeneration phase failed).";
2497   case 1008423:
2498     return "A constrained face cannot be enforced (information given when regeneration phase failed).";
2499   case 1008441:
2500     return "A constrained edge cannot be enforced.";
2501   case 1008460:
2502     return "It is dramatically tedious to enforce the boundary items.";
2503   case 1008480:
2504     return "The surface mesh regeneration step has failed. A .boite.mesh and .boite.map files are created.";
2505   case 1008490:
2506     return "Invalid resulting mesh.";
2507   case 1008495:
2508     return "P2 correction not successful.";
2509   case 1009000:
2510     return "Program has received an interruption or a termination signal sent by the "
2511       "user or the system administrator. Current mesh will not be saved.";
2512   }
2513   return "";
2514 }
2515
2516 //================================================================================
2517 /*!
2518  * \brief Retrieve from a string given number of integers
2519  */
2520 //================================================================================
2521
2522 static char* getIds( char* ptr, int nbIds, vector<int>& ids )
2523 {
2524   ids.clear();
2525   ids.reserve( nbIds );
2526   while ( nbIds )
2527   {
2528     while ( !isdigit( *ptr )) ++ptr;
2529     if ( ptr[-1] == '-' ) --ptr;
2530     ids.push_back( strtol( ptr, &ptr, 10 ));
2531     --nbIds;
2532   }
2533   return ptr;
2534 }
2535
2536 //================================================================================
2537 /*!
2538  * \brief Retrieve problem description form a log file
2539  *  \retval bool - always false
2540  */
2541 //================================================================================
2542
2543 bool GHS3DPlugin_GHS3D::storeErrorDescription(const TCollection_AsciiString& logFile,
2544                                               const _Ghs2smdsConvertor &     toSmdsConvertor )
2545 {
2546   if(_compute_canceled)
2547     return error(SMESH_Comment("interruption initiated by user"));
2548   // open file
2549 #ifdef WIN32
2550   int file = ::_open (logFile.ToCString(), _O_RDONLY|_O_BINARY);
2551 #else
2552   int file = ::open (logFile.ToCString(), O_RDONLY);
2553 #endif
2554   if ( file < 0 )
2555     return error( SMESH_Comment("See ") << logFile << " for problem description");
2556
2557   // get file size
2558   off_t length = lseek( file, 0, SEEK_END);
2559   lseek( file, 0, SEEK_SET);
2560
2561   // read file
2562   vector< char > buf( length );
2563   int nBytesRead = ::read (file, & buf[0], length);
2564   ::close (file);
2565   char* ptr = & buf[0];
2566   char* bufEnd = ptr + nBytesRead;
2567
2568   SMESH_Comment errDescription;
2569
2570   enum { NODE = 1, EDGE, TRIA, VOL, SKIP_ID = 1 };
2571
2572   // look for MeshGems version
2573   // Since "MG-TETRA -- MeshGems 1.1-3 (January, 2013)" error codes change.
2574   // To discriminate old codes from new ones we add 1000000 to the new codes.
2575   // This way value of the new codes is same as absolute value of codes printed
2576   // in the log after "MGMESSAGE" string.
2577   int versionAddition = 0;
2578   {
2579     char* verPtr = ptr;
2580     while ( ++verPtr < bufEnd )
2581     {
2582       if ( strncmp( verPtr, "MG-TETRA -- MeshGems ", 21 ) != 0 )
2583         continue;
2584       if ( strcmp( verPtr, "MG-TETRA -- MeshGems 1.1-3 " ) >= 0 )
2585         versionAddition = 1000000;
2586       ptr = verPtr;
2587       break;
2588     }
2589   }
2590
2591   // look for errors "ERR #"
2592
2593   set<string> foundErrorStr; // to avoid reporting same error several times
2594   set<int>    elemErrorNums; // not to report different types of errors with bad elements
2595   while ( ++ptr < bufEnd )
2596   {
2597     if ( strncmp( ptr, "ERR ", 4 ) != 0 )
2598       continue;
2599
2600     list<const SMDS_MeshElement*> badElems;
2601     vector<int> nodeIds;
2602
2603     ptr += 4;
2604     char* errBeg = ptr;
2605     int   errNum = strtol(ptr, &ptr, 10) + versionAddition;
2606     // we treat errors enumerated in [SALOME platform 0019316] issue
2607     // and all errors from a new (Release 1.1) MeshGems User Manual
2608     switch ( errNum ) {
2609     case 0015: // The face number (numfac) with vertices (f 1, f 2, f 3) has a null vertex.
2610     case 1005620 : // a too bad quality face is detected. This face is considered degenerated.
2611       ptr = getIds(ptr, SKIP_ID, nodeIds);
2612       ptr = getIds(ptr, TRIA, nodeIds);
2613       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2614       break;
2615     case 1005621 : // a too bad quality face is detected. This face is degenerated.
2616       // hence the is degenerated it is invisible, add its edges in addition
2617       ptr = getIds(ptr, SKIP_ID, nodeIds);
2618       ptr = getIds(ptr, TRIA, nodeIds);
2619       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2620       {
2621         vector<int> edgeNodes( nodeIds.begin(), --nodeIds.end() ); // 01
2622         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
2623         edgeNodes[1] = nodeIds[2]; // 02
2624         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
2625         edgeNodes[0] = nodeIds[1]; // 12
2626       }      
2627       break;
2628     case 1000: // Face (f 1, f 2, f 3) appears more than once in the input surface mesh.
2629       // ERR  1000 :  1 3 2
2630     case 1002: // Face (f 1, f 2, f 3) has a vertex negative or null
2631     case 3019: // Constrained face (f 1, f 2, f 3) cannot be enforced
2632     case 1002211: // a face has a vertex negative or null.
2633     case 1005200 : // a surface mesh appears more than once in the input surface mesh.
2634     case 1008423 : // a constrained face cannot be enforced (regeneration phase failed).
2635       ptr = getIds(ptr, TRIA, nodeIds);
2636       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2637       break;
2638     case 1001: // Edge (e1, e2) appears more than once in the input surface mesh
2639     case 3009: // Constrained edge (e1, e2) cannot be enforced (warning).
2640       // ERR  3109 :  EDGE  5 6 UNIQUE
2641     case 3109: // Edge (e1, e2) is unique (i.e., bounds a hole in the surface)
2642     case 1005210 : // an edge appears more than once in the input surface mesh.
2643     case 1005820 : // an edge is unique (i.e., bounds a hole in the surface).
2644     case 1008441 : // a constrained edge cannot be enforced.
2645       ptr = getIds(ptr, EDGE, nodeIds);
2646       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2647       break;
2648     case 2004: // Vertex v1 and vertex v2 are too close to one another or coincident (warning).
2649     case 2014: // at least two points whose distance is dist, i.e., considered as coincident
2650     case 2103: // Vertex v1 and vertex v2 are too close to one another or coincident (warning).
2651       // ERR  2103 :  16 WITH  3
2652     case 1005105 : // two vertices are too close to one another or coincident.
2653     case 1005107: // Two vertices are too close to one another or coincident.
2654       ptr = getIds(ptr, NODE, nodeIds);
2655       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2656       ptr = getIds(ptr, NODE, nodeIds);
2657       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2658       break;
2659     case 2012: // Vertex v1 cannot be inserted (warning).
2660     case 1005106 : // a vertex cannot be inserted.
2661       ptr = getIds(ptr, NODE, nodeIds);
2662       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2663       break;
2664     case 3103: // The surface edge (e1, e2) intersects another surface edge (e3, e4)
2665     case 1005110 : // two surface edges are intersecting.
2666       // ERR  3103 :  1 2 WITH  7 3
2667       ptr = getIds(ptr, EDGE, nodeIds);
2668       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2669       ptr = getIds(ptr, EDGE, nodeIds);
2670       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2671       break;
2672     case 3104: // The surface edge (e1, e2) intersects the surface face (f 1, f 2, f 3)
2673       // ERR  3104 :  9 10 WITH  1 2 3
2674     case 3106: // One surface edge (say e1, e2) intersects a surface face (f 1, f 2, f 3)
2675     case 1005120 : // a surface edge intersects a surface face.
2676       ptr = getIds(ptr, EDGE, nodeIds);
2677       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2678       ptr = getIds(ptr, TRIA, nodeIds);
2679       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2680       break;
2681     case 3105: // One boundary point (say p1) lies within a surface face (f 1, f 2, f 3)
2682       // ERR  3105 :  8 IN  2 3 5
2683     case 1005150 : // a boundary point lies within a surface face.
2684       ptr = getIds(ptr, NODE, nodeIds);
2685       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2686       ptr = getIds(ptr, TRIA, nodeIds);
2687       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2688       break;
2689     case 3107: // One boundary point (say p1) lies within a surface edge (e1, e2) (stop).
2690       // ERR  3107 :  2 IN  4 1
2691     case 1005160 : // a boundary point lies within a surface edge.
2692       ptr = getIds(ptr, NODE, nodeIds);
2693       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2694       ptr = getIds(ptr, EDGE, nodeIds);
2695       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2696       break;
2697     case 9000: // ERR  9000
2698       //  ELEMENT  261 WITH VERTICES :  7 396 -8 242
2699       //  VOLUME   : -1.11325045E+11 W.R.T. EPSILON   0.
2700       // A too small volume element is detected. Are reported the index of the element,
2701       // its four vertex indices, its volume and the tolerance threshold value
2702       ptr = getIds(ptr, SKIP_ID, nodeIds);
2703       ptr = getIds(ptr, VOL, nodeIds);
2704       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2705       // even if all nodes found, volume it most probably invisible,
2706       // add its faces to demonstrate it anyhow
2707       {
2708         vector<int> faceNodes( nodeIds.begin(), --nodeIds.end() ); // 012
2709         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
2710         faceNodes[2] = nodeIds[3]; // 013
2711         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
2712         faceNodes[1] = nodeIds[2]; // 023
2713         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
2714         faceNodes[0] = nodeIds[1]; // 123
2715         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
2716       }
2717       break;
2718     case 9001: // ERR  9001
2719       //  %% NUMBER OF NEGATIVE VOLUME TETS  :  1
2720       //  %% THE LARGEST NEGATIVE TET        :   1.75376581E+11
2721       //  %%  NUMBER OF NULL VOLUME TETS     :  0
2722       // There exists at least a null or negative volume element
2723       break;
2724     case 9002:
2725       // There exist n null or negative volume elements
2726       break;
2727     case 9003:
2728       // A too small volume element is detected
2729       break;
2730     case 9102:
2731       // A too bad quality face is detected. This face is considered degenerated,
2732       // its index, its three vertex indices together with its quality value are reported
2733       break; // same as next
2734     case 9112: // ERR  9112
2735       //  FACE   2 WITH VERTICES :  4 2 5
2736       //  SMALL INRADIUS :   0.
2737       // A too bad quality face is detected. This face is degenerated,
2738       // its index, its three vertex indices together with its inradius are reported
2739       ptr = getIds(ptr, SKIP_ID, nodeIds);
2740       ptr = getIds(ptr, TRIA, nodeIds);
2741       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2742       // add triangle edges as it most probably has zero area and hence invisible
2743       {
2744         vector<int> edgeNodes(2);
2745         edgeNodes[0] = nodeIds[0]; edgeNodes[1] = nodeIds[1]; // 0-1
2746         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
2747         edgeNodes[1] = nodeIds[2]; // 0-2
2748         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
2749         edgeNodes[0] = nodeIds[1]; // 1-2
2750         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
2751       }
2752       break;
2753     case 1005103 : // the vertices of an element are too close to one another or coincident.
2754       ptr = getIds(ptr, TRIA, nodeIds);
2755       if ( nodeIds.back() == 0 ) // index of the third vertex of the element (0 for an edge)
2756         nodeIds.resize( EDGE );
2757       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
2758       break;
2759     }
2760
2761     bool isNewError = foundErrorStr.insert( string( errBeg, ptr )).second;
2762     if ( !isNewError )
2763       continue; // not to report same error several times
2764
2765 //     const SMDS_MeshElement* nullElem = 0;
2766 //     bool allElemsOk = ( find( badElems.begin(), badElems.end(), nullElem) == badElems.end());
2767
2768 //     if ( allElemsOk && !badElems.empty() && !elemErrorNums.empty() ) {
2769 //       bool oneMoreErrorType = elemErrorNums.insert( errNum ).second;
2770 //       if ( oneMoreErrorType )
2771 //         continue; // not to report different types of errors with bad elements
2772 //     }
2773
2774     // store bad elements
2775     //if ( allElemsOk ) {
2776       list<const SMDS_MeshElement*>::iterator elem = badElems.begin();
2777       for ( ; elem != badElems.end(); ++elem )
2778         addBadInputElement( *elem );
2779       //}
2780
2781     // make error text
2782     string text = translateError( errNum );
2783     if ( errDescription.find( text ) == text.npos ) {
2784       if ( !errDescription.empty() )
2785         errDescription << "\n";
2786       errDescription << text;
2787     }
2788
2789   } // end while
2790
2791   if ( errDescription.empty() ) { // no errors found
2792     char msgLic1[] = "connection to server failed";
2793     char msgLic2[] = " Dlim ";
2794     if ( search( &buf[0], bufEnd, msgLic1, msgLic1 + strlen(msgLic1)) != bufEnd ||
2795          search( &buf[0], bufEnd, msgLic2, msgLic2 + strlen(msgLic2)) != bufEnd )
2796       errDescription << "Licence problems.";
2797     else
2798     {
2799       char msg2[] = "SEGMENTATION FAULT";
2800       if ( search( &buf[0], bufEnd, msg2, msg2 + strlen(msg2)) != bufEnd )
2801         errDescription << "MG-Tetra: SEGMENTATION FAULT. ";
2802     }
2803   }
2804
2805   if ( errDescription.empty() )
2806     errDescription << "See " << logFile << " for problem description";
2807   else
2808     errDescription << "\nSee " << logFile << " for more information";
2809
2810   return error( errDescription );
2811 }
2812
2813 //================================================================================
2814 /*!
2815  * \brief Creates _Ghs2smdsConvertor
2816  */
2817 //================================================================================
2818
2819 _Ghs2smdsConvertor::_Ghs2smdsConvertor( const map <int,const SMDS_MeshNode*> & ghs2NodeMap,
2820                                         SMESH_ProxyMesh::Ptr                   mesh)
2821   :_ghs2NodeMap( & ghs2NodeMap ), _nodeByGhsId( 0 ), _mesh( mesh )
2822 {
2823 }
2824
2825 //================================================================================
2826 /*!
2827  * \brief Creates _Ghs2smdsConvertor
2828  */
2829 //================================================================================
2830
2831 _Ghs2smdsConvertor::_Ghs2smdsConvertor( const vector <const SMDS_MeshNode*> &  nodeByGhsId,
2832                                         SMESH_ProxyMesh::Ptr                   mesh)
2833   : _ghs2NodeMap( 0 ), _nodeByGhsId( &nodeByGhsId ), _mesh( mesh )
2834 {
2835 }
2836
2837 //================================================================================
2838 /*!
2839  * \brief Return SMDS element by ids of MG-Tetra nodes
2840  */
2841 //================================================================================
2842
2843 const SMDS_MeshElement* _Ghs2smdsConvertor::getElement(const vector<int>& ghsNodes) const
2844 {
2845   size_t nbNodes = ghsNodes.size();
2846   vector<const SMDS_MeshNode*> nodes( nbNodes, 0 );
2847   for ( size_t i = 0; i < nbNodes; ++i ) {
2848     int ghsNode = ghsNodes[ i ];
2849     if ( _ghs2NodeMap ) {
2850       map <int,const SMDS_MeshNode*>::const_iterator in = _ghs2NodeMap->find( ghsNode);
2851       if ( in == _ghs2NodeMap->end() )
2852         return 0;
2853       nodes[ i ] = in->second;
2854     }
2855     else {
2856       if ( ghsNode < 1 || ghsNode > (int)_nodeByGhsId->size() )
2857         return 0;
2858       nodes[ i ] = (*_nodeByGhsId)[ ghsNode-1 ];
2859     }
2860   }
2861   if ( nbNodes == 1 )
2862     return nodes[0];
2863
2864   if ( nbNodes == 2 ) {
2865     const SMDS_MeshElement* edge= SMDS_Mesh::FindEdge( nodes[0], nodes[1] );
2866     if ( !edge || edge->GetID() < 1 || _mesh->IsTemporary( edge ))
2867       edge = new SMDS_LinearEdge( nodes[0], nodes[1] );
2868     return edge;
2869   }
2870   if ( nbNodes == 3 ) {
2871     const SMDS_MeshElement* face = SMDS_Mesh::FindFace( nodes );
2872     if ( !face || face->GetID() < 1 || _mesh->IsTemporary( face ))
2873       face = new SMDS_FaceOfNodes( nodes[0], nodes[1], nodes[2] );
2874     return face;
2875   }
2876   if ( nbNodes == 4 )
2877     return new SMDS_VolumeOfNodes( nodes[0], nodes[1], nodes[2], nodes[3] );
2878
2879   return 0;
2880 }
2881
2882
2883 //=============================================================================
2884 /*!
2885  *
2886  */
2887 //=============================================================================
2888 bool GHS3DPlugin_GHS3D::Evaluate(SMESH_Mesh& aMesh,
2889                                  const TopoDS_Shape& aShape,
2890                                  MapShapeNbElems& aResMap)
2891 {
2892   int nbtri = 0, nbqua = 0;
2893   double fullArea = 0.0;
2894   for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) {
2895     TopoDS_Face F = TopoDS::Face( exp.Current() );
2896     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
2897     MapShapeNbElemsItr anIt = aResMap.find(sm);
2898     if( anIt==aResMap.end() ) {
2899       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
2900       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
2901                                             "Submesh can not be evaluated",this));
2902       return false;
2903     }
2904     std::vector<int> aVec = (*anIt).second;
2905     nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
2906     nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
2907     GProp_GProps G;
2908     BRepGProp::SurfaceProperties(F,G);
2909     double anArea = G.Mass();
2910     fullArea += anArea;
2911   }
2912
2913   // collect info from edges
2914   int nb0d_e = 0, nb1d_e = 0;
2915   bool IsQuadratic = false;
2916   bool IsFirst = true;
2917   TopTools_MapOfShape tmpMap;
2918   for (TopExp_Explorer exp(aShape, TopAbs_EDGE); exp.More(); exp.Next()) {
2919     TopoDS_Edge E = TopoDS::Edge(exp.Current());
2920     if( tmpMap.Contains(E) )
2921       continue;
2922     tmpMap.Add(E);
2923     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
2924     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
2925     std::vector<int> aVec = (*anIt).second;
2926     nb0d_e += aVec[SMDSEntity_Node];
2927     nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
2928     if(IsFirst) {
2929       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
2930       IsFirst = false;
2931     }
2932   }
2933   tmpMap.Clear();
2934
2935   double ELen = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) );
2936
2937   GProp_GProps G;
2938   BRepGProp::VolumeProperties(aShape,G);
2939   double aVolume = G.Mass();
2940   double tetrVol = 0.1179*ELen*ELen*ELen;
2941   double CoeffQuality = 0.9;
2942   int nbVols = int(aVolume/tetrVol/CoeffQuality);
2943   int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
2944   int nb1d_in = (int) ( nbVols*6 - nb1d_e - nb1d_f ) / 5;
2945   std::vector<int> aVec(SMDSEntity_Last);
2946   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
2947   if( IsQuadratic ) {
2948     aVec[SMDSEntity_Node] = nb1d_in/6 + 1 + nb1d_in;
2949     aVec[SMDSEntity_Quad_Tetra] = nbVols - nbqua*2;
2950     aVec[SMDSEntity_Quad_Pyramid] = nbqua;
2951   }
2952   else {
2953     aVec[SMDSEntity_Node] = nb1d_in/6 + 1;
2954     aVec[SMDSEntity_Tetra] = nbVols - nbqua*2;
2955     aVec[SMDSEntity_Pyramid] = nbqua;
2956   }
2957   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
2958   aResMap.insert(std::make_pair(sm,aVec));
2959
2960   return true;
2961 }
2962
2963 bool GHS3DPlugin_GHS3D::importGMFMesh(const char* theGMFFileName, SMESH_Mesh& theMesh)
2964 {
2965   SMESH_MesherHelper* helper  = new SMESH_MesherHelper(theMesh );
2966   std::vector <const SMDS_MeshNode*> dummyNodeVector;
2967   std::vector <const SMDS_MeshElement*> aFaceByGhs3dId;
2968   std::map<const SMDS_MeshNode*,int> dummyNodeMap;
2969   std::map<std::vector<double>, std::string> dummyEnfVertGroup;
2970   std::vector<std::string> dummyElemGroup;
2971   std::set<std::string> dummyGroupsToRemove;
2972
2973   bool ok = readGMFFile(theGMFFileName,
2974                         this,
2975                         helper, dummyNodeVector, aFaceByGhs3dId, dummyNodeMap, dummyElemGroup, dummyElemGroup, dummyElemGroup, dummyGroupsToRemove);
2976   theMesh.GetMeshDS()->Modified();
2977   return ok;
2978 }
2979
2980 namespace
2981 {
2982   //================================================================================
2983   /*!
2984    * \brief Sub-mesh event listener setting enforced elements as soon as an enforced
2985    *        mesh is loaded
2986    */
2987   struct _EnforcedMeshRestorer : public SMESH_subMeshEventListener
2988   {
2989     _EnforcedMeshRestorer():
2990       SMESH_subMeshEventListener( /*isDeletable = */true, Name() )
2991     {}
2992
2993     //================================================================================
2994     /*!
2995      * \brief Returns an ID of listener
2996      */
2997     static const char* Name() { return "GHS3DPlugin_GHS3D::_EnforcedMeshRestorer"; }
2998
2999     //================================================================================
3000     /*!
3001      * \brief Treat events of the subMesh
3002      */
3003     void ProcessEvent(const int                       event,
3004                       const int                       eventType,
3005                       SMESH_subMesh*                  subMesh,
3006                       SMESH_subMeshEventListenerData* data,
3007                       const SMESH_Hypothesis*         hyp)
3008     {
3009       if ( SMESH_subMesh::SUBMESH_LOADED == event &&
3010            SMESH_subMesh::COMPUTE_EVENT  == eventType &&
3011            data &&
3012            !data->mySubMeshes.empty() )
3013       {
3014         // An enforced mesh (subMesh->_father) has been loaded from hdf file
3015         if ( GHS3DPlugin_Hypothesis* hyp = GetGHSHypothesis( data->mySubMeshes.front() ))
3016           hyp->RestoreEnfElemsByMeshes();
3017       }
3018     }
3019     //================================================================================
3020     /*!
3021      * \brief Returns GHS3DPlugin_Hypothesis used to compute a subMesh
3022      */
3023     static GHS3DPlugin_Hypothesis* GetGHSHypothesis( SMESH_subMesh* subMesh )
3024     {
3025       SMESH_HypoFilter ghsHypFilter
3026         ( SMESH_HypoFilter::HasName( GHS3DPlugin_Hypothesis::GetHypType() ));
3027       return (GHS3DPlugin_Hypothesis* )
3028         subMesh->GetFather()->GetHypothesis( subMesh->GetSubShape(),
3029                                              ghsHypFilter,
3030                                              /*visitAncestors=*/true);
3031     }
3032   };
3033
3034   //================================================================================
3035   /*!
3036    * \brief Sub-mesh event listener removing empty groups created due to "To make
3037    *        groups of domains".
3038    */
3039   struct _GroupsOfDomainsRemover : public SMESH_subMeshEventListener
3040   {
3041     _GroupsOfDomainsRemover():
3042       SMESH_subMeshEventListener( /*isDeletable = */true,
3043                                   "GHS3DPlugin_GHS3D::_GroupsOfDomainsRemover" ) {}
3044     /*!
3045      * \brief Treat events of the subMesh
3046      */
3047     void ProcessEvent(const int                       event,
3048                       const int                       eventType,
3049                       SMESH_subMesh*                  subMesh,
3050                       SMESH_subMeshEventListenerData* data,
3051                       const SMESH_Hypothesis*         hyp)
3052     {
3053       if (SMESH_subMesh::ALGO_EVENT == eventType &&
3054           !subMesh->GetAlgo() )
3055       {
3056         removeEmptyGroupsOfDomains( subMesh->GetFather(), /*notEmptyAsWell=*/true );
3057       }
3058     }
3059   };
3060 }
3061
3062 //================================================================================
3063 /*!
3064  * \brief Set an event listener to set enforced elements as soon as an enforced
3065  *        mesh is loaded
3066  */
3067 //================================================================================
3068
3069 void GHS3DPlugin_GHS3D::SubmeshRestored(SMESH_subMesh* subMesh)
3070 {
3071   if ( GHS3DPlugin_Hypothesis* hyp = _EnforcedMeshRestorer::GetGHSHypothesis( subMesh ))
3072   {
3073     GHS3DPlugin_Hypothesis::TGHS3DEnforcedMeshList enfMeshes = hyp->_GetEnforcedMeshes();
3074     GHS3DPlugin_Hypothesis::TGHS3DEnforcedMeshList::iterator it = enfMeshes.begin();
3075     for(;it != enfMeshes.end();++it) {
3076       GHS3DPlugin_Hypothesis::TGHS3DEnforcedMesh* enfMesh = *it;
3077       if ( SMESH_Mesh* mesh = GetMeshByPersistentID( enfMesh->persistID ))
3078       {
3079         SMESH_subMesh* smToListen = mesh->GetSubMesh( mesh->GetShapeToMesh() );
3080         // a listener set to smToListen will care of hypothesis stored in SMESH_EventListenerData
3081         subMesh->SetEventListener( new _EnforcedMeshRestorer(),
3082                                    SMESH_subMeshEventListenerData::MakeData( subMesh ),
3083                                    smToListen);
3084       }
3085     }
3086   }
3087 }
3088
3089 //================================================================================
3090 /*!
3091  * \brief Sets an event listener removing empty groups created due to "To make
3092  *        groups of domains".
3093  * \param subMesh - submesh where algo is set
3094  *
3095  * This method is called when a submesh gets HYP_OK algo_state.
3096  * After being set, event listener is notified on each event of a submesh.
3097  */
3098 //================================================================================
3099
3100 void GHS3DPlugin_GHS3D::SetEventListener(SMESH_subMesh* subMesh)
3101 {
3102   subMesh->SetEventListener( new _GroupsOfDomainsRemover(), 0, subMesh );
3103 }