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