Salome HOME
new combo for element generation etc...
[plugins/hybridplugin.git] / src / HYBRIDPlugin / HYBRIDPlugin_HYBRID.cxx
1 // Copyright (C) 2004-2013  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.
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      : HYBRIDPlugin_HYBRID.cxx
22 // Created   : 
23 // Author    : Edward AGAPOV, modified by Lioka RAZAFINDRAZAKA (CEA) 09/02/2007
24 // Project   : SALOME
25 //=============================================================================
26 //
27 #include "HYBRIDPlugin_HYBRID.hxx"
28 #include "HYBRIDPlugin_Hypothesis.hxx"
29
30 #include <SMDS_FaceOfNodes.hxx>
31 #include <SMDS_MeshElement.hxx>
32 #include <SMDS_MeshNode.hxx>
33 #include <SMDS_VolumeOfNodes.hxx>
34 #include <SMESHDS_Group.hxx>
35 #include <SMESH_Comment.hxx>
36 #include <SMESH_Group.hxx>
37 #include <SMESH_HypoFilter.hxx>
38 #include <SMESH_Mesh.hxx>
39 #include <SMESH_MeshAlgos.hxx>
40 #include <SMESH_MeshEditor.hxx>
41 #include <SMESH_MesherHelper.hxx>
42 #include <SMESH_OctreeNode.hxx>
43 #include <SMESH_subMeshEventListener.hxx>
44 #include <StdMeshers_QuadToTriaAdaptor.hxx>
45 #include <StdMeshers_ViscousLayers.hxx>
46
47 #include <BRepAdaptor_Surface.hxx>
48 #include <BRepBndLib.hxx>
49 #include <BRepBuilderAPI_MakeVertex.hxx>
50 #include <BRepClass3d.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRepExtrema_DistShapeShape.hxx>
53 #include <BRepGProp.hxx>
54 #include <BRepTools.hxx>
55 #include <BRep_Tool.hxx>
56 #include <Bnd_Box.hxx>
57 #include <GProp_GProps.hxx>
58 #include <GeomAPI_ProjectPointOnSurf.hxx>
59 #include <OSD_File.hxx>
60 #include <Precision.hxx>
61 #include <Standard_ErrorHandler.hxx>
62 #include <Standard_Failure.hxx>
63 #include <Standard_ProgramError.hxx>
64 #include <TopExp.hxx>
65 #include <TopExp_Explorer.hxx>
66 #include <TopTools_IndexedMapOfShape.hxx>
67 #include <TopTools_ListIteratorOfListOfShape.hxx>
68 #include <TopTools_MapOfShape.hxx>
69 #include <TopoDS.hxx>
70 #include <TopoDS_Shell.hxx>
71 #include <TopoDS_Solid.hxx>
72
73 #include <Basics_Utils.hxx>
74 #include <utilities.h>
75
76 #ifdef WIN32
77 #include <io.h>
78 #else
79 #include <sys/sysinfo.h>
80 #endif
81 #include <algorithm>
82
83 #define castToNode(n) static_cast<const SMDS_MeshNode *>( n );
84
85 extern "C"
86 {
87 #ifndef WIN32
88 #include <unistd.h>
89 #include <sys/mman.h>
90 #endif
91 #include <sys/stat.h>
92 #include <fcntl.h>
93 }
94
95 #define HOLE_ID -1
96
97 typedef const list<const SMDS_MeshFace*> TTriaList;
98
99 static const char theDomainGroupNamePrefix[] = "Domain_";
100
101 static void removeFile( const TCollection_AsciiString& fileName )
102 {
103   try {
104     OSD_File( fileName ).Remove();
105   }
106   catch ( Standard_ProgramError ) {
107     MESSAGE("Can't remove file: " << fileName.ToCString() << " ; file does not exist or permission denied");
108   }
109 }
110
111 //=============================================================================
112 /*!
113  *  
114  */
115 //=============================================================================
116
117 HYBRIDPlugin_HYBRID::HYBRIDPlugin_HYBRID(int hypId, int studyId, SMESH_Gen* gen)
118   : SMESH_3D_Algo(hypId, studyId, gen)
119 {
120   MESSAGE("HYBRIDPlugin_HYBRID::HYBRIDPlugin_HYBRID");
121   _name = Name();
122   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
123   _onlyUnaryInput = false; // Compute() will be called on a compound of solids
124   _iShape=0;
125   _nbShape=0;
126   _compatibleHypothesis.push_back( HYBRIDPlugin_Hypothesis::GetHypType());
127   _compatibleHypothesis.push_back( StdMeshers_ViscousLayers::GetHypType() );
128   _requireShape = false; // can work without shape_studyId
129
130   smeshGen_i = SMESH_Gen_i::GetSMESHGen();
131   CORBA::Object_var anObject = smeshGen_i->GetNS()->Resolve("/myStudyManager");
132   SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject);
133
134   MESSAGE("studyid = " << _studyId);
135
136   myStudy = NULL;
137   myStudy = aStudyMgr->GetStudyByID(_studyId);
138   if (myStudy)
139     MESSAGE("myStudy->StudyId() = " << myStudy->StudyId());
140   
141   _compute_canceled = false;
142 }
143
144 //=============================================================================
145 /*!
146  *  
147  */
148 //=============================================================================
149
150 HYBRIDPlugin_HYBRID::~HYBRIDPlugin_HYBRID()
151 {
152   MESSAGE("HYBRIDPlugin_HYBRID::~HYBRIDPlugin_HYBRID");
153 }
154
155 //=============================================================================
156 /*!
157  *  
158  */
159 //=============================================================================
160
161 bool HYBRIDPlugin_HYBRID::CheckHypothesis ( SMESH_Mesh&         aMesh,
162                                           const TopoDS_Shape& aShape,
163                                           Hypothesis_Status&  aStatus )
164 {
165   aStatus = SMESH_Hypothesis::HYP_OK;
166
167   _hyp = 0;
168   _viscousLayersHyp = 0;
169   _keepFiles = false;
170   _removeLogOnSuccess = true;
171   _logInStandardOutput = false;
172
173   const list <const SMESHDS_Hypothesis * >& hyps =
174     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliary=*/false);
175   list <const SMESHDS_Hypothesis* >::const_iterator h = hyps.begin();
176   for ( ; h != hyps.end(); ++h )
177   {
178     if ( !_hyp )
179       _hyp = dynamic_cast< const HYBRIDPlugin_Hypothesis*> ( *h );
180     if ( !_viscousLayersHyp )
181       _viscousLayersHyp = dynamic_cast< const StdMeshers_ViscousLayers*> ( *h );
182   }
183   if ( _hyp )
184   {
185     _keepFiles = _hyp->GetKeepFiles();
186     _removeLogOnSuccess = _hyp->GetRemoveLogOnSuccess();
187     _logInStandardOutput = _hyp->GetStandardOutputLog();
188   }
189
190   return true;
191 }
192
193
194 //=======================================================================
195 //function : entryToShape
196 //purpose  : 
197 //=======================================================================
198
199 TopoDS_Shape HYBRIDPlugin_HYBRID::entryToShape(std::string entry)
200 {
201   MESSAGE("HYBRIDPlugin_HYBRID::entryToShape "<<entry );
202   GEOM::GEOM_Object_var aGeomObj;
203   TopoDS_Shape S = TopoDS_Shape();
204   SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() );
205   if (!aSObj->_is_nil() ) {
206     CORBA::Object_var obj = aSObj->GetObject();
207     aGeomObj = GEOM::GEOM_Object::_narrow(obj);
208     aSObj->UnRegister();
209   }
210   if ( !aGeomObj->_is_nil() )
211     S = smeshGen_i->GeomObjectToShape( aGeomObj.in() );
212   return S;
213 }
214
215 //=======================================================================
216 //function : findShape
217 //purpose  : 
218 //=======================================================================
219
220 static TopoDS_Shape findShape(const SMDS_MeshNode *aNode[],
221                               TopoDS_Shape        aShape,
222                               const TopoDS_Shape  shape[],
223                               double**            box,
224                               const int           nShape,
225                               TopAbs_State *      state = 0)
226 {
227   gp_XYZ aPnt(0,0,0);
228   int j, iShape, nbNode = 4;
229
230   for ( j=0; j<nbNode; j++ ) {
231     gp_XYZ p ( aNode[j]->X(), aNode[j]->Y(), aNode[j]->Z() );
232     if ( aNode[j]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) {
233       aPnt = p;
234       break;
235     }
236     aPnt += p / nbNode;
237   }
238
239   BRepClass3d_SolidClassifier SC (aShape, aPnt, Precision::Confusion());
240   if (state) *state = SC.State();
241   if ( SC.State() != TopAbs_IN || aShape.IsNull() || aShape.ShapeType() != TopAbs_SOLID) {
242     for (iShape = 0; iShape < nShape; iShape++) {
243       aShape = shape[iShape];
244       if ( !( aPnt.X() < box[iShape][0] || box[iShape][1] < aPnt.X() ||
245               aPnt.Y() < box[iShape][2] || box[iShape][3] < aPnt.Y() ||
246               aPnt.Z() < box[iShape][4] || box[iShape][5] < aPnt.Z()) ) {
247         BRepClass3d_SolidClassifier SC (aShape, aPnt, Precision::Confusion());
248         if (state) *state = SC.State();
249         if (SC.State() == TopAbs_IN)
250           break;
251       }
252     }
253   }
254   return aShape;
255 }
256
257 //=======================================================================
258 //function : readMapIntLine
259 //purpose  : 
260 //=======================================================================
261
262 static char* readMapIntLine(char* ptr, int tab[]) {
263   long int intVal;
264   std::cout << std::endl;
265
266   for ( int i=0; i<17; i++ ) {
267     intVal = strtol(ptr, &ptr, 10);
268     if ( i < 3 )
269       tab[i] = intVal;
270   }
271   return ptr;
272 }
273
274 //================================================================================
275 /*!
276  * \brief returns true if a triangle defined by the nodes is a temporary face on a
277  * side facet of pyramid and defines sub-domain inside the pyramid
278  */
279 //================================================================================
280
281 static bool isTmpFace(const SMDS_MeshNode* node1,
282                       const SMDS_MeshNode* node2,
283                       const SMDS_MeshNode* node3)
284 {
285   // find a pyramid sharing the 3 nodes
286   //const SMDS_MeshElement* pyram = 0;
287   SMDS_ElemIteratorPtr vIt1 = node1->GetInverseElementIterator(SMDSAbs_Volume);
288   while ( vIt1->more() )
289   {
290     const SMDS_MeshElement* pyram = vIt1->next();
291     if ( pyram->NbCornerNodes() != 5 ) continue;
292     int i2, i3;
293     if ( (i2 = pyram->GetNodeIndex( node2 )) >= 0 &&
294          (i3 = pyram->GetNodeIndex( node3 )) >= 0 )
295     {
296       // Triangle defines sub-domian inside the pyramid if it's
297       // normal points out of the pyram
298
299       // make i2 and i3 hold indices of base nodes of the pyram while
300       // keeping the nodes order in the triangle
301       const int iApex = 4;
302       if ( i2 == iApex )
303         i2 = i3, i3 = pyram->GetNodeIndex( node1 );
304       else if ( i3 == iApex )
305         i3 = i2, i2 = pyram->GetNodeIndex( node1 );
306
307       int i3base = (i2+1) % 4; // next index after i2 within the pyramid base
308       return ( i3base != i3 );
309     }
310   }
311   return false;
312 }
313
314 //=======================================================================
315 //function : findShapeID
316 //purpose  : find the solid corresponding to HYBRID sub-domain following
317 //           the technique proposed in GHS3D manual (available within
318 //           ghs3d installation) in chapter "B.4 Subdomain (sub-region) assignment".
319 //           In brief: normal of the triangle defined by the given nodes
320 //           points out of the domain it is associated to
321 //=======================================================================
322
323 static int findShapeID(SMESH_Mesh&          mesh,
324                        const SMDS_MeshNode* node1,
325                        const SMDS_MeshNode* node2,
326                        const SMDS_MeshNode* node3,
327                        const bool           toMeshHoles)
328 {
329   const int invalidID = 0;
330   SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
331
332   // face the nodes belong to
333   vector<const SMDS_MeshNode *> nodes(3);
334   nodes[0] = node1;
335   nodes[1] = node2;
336   nodes[2] = node3;
337   const SMDS_MeshElement * face = meshDS->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/true);
338   if ( !face )
339     return isTmpFace(node1, node2, node3) ? HOLE_ID : invalidID;
340 #ifdef _DEBUG_
341   std::cout << "bnd face " << face->GetID() << " - ";
342 #endif
343   // geom face the face assigned to
344   SMESH_MeshEditor editor(&mesh);
345   int geomFaceID = editor.FindShape( face );
346   if ( !geomFaceID )
347     return isTmpFace(node1, node2, node3) ? HOLE_ID : invalidID;
348   TopoDS_Shape shape = meshDS->IndexToShape( geomFaceID );
349   if ( shape.IsNull() || shape.ShapeType() != TopAbs_FACE )
350     return invalidID;
351   TopoDS_Face geomFace = TopoDS::Face( shape );
352
353   // solids bounded by geom face
354   TopTools_IndexedMapOfShape solids, shells;
355   TopTools_ListIteratorOfListOfShape ansIt = mesh.GetAncestors(geomFace);
356   for ( ; ansIt.More(); ansIt.Next() ) {
357     switch ( ansIt.Value().ShapeType() ) {
358     case TopAbs_SOLID:
359       solids.Add( ansIt.Value() ); break;
360     case TopAbs_SHELL:
361       shells.Add( ansIt.Value() ); break;
362     default:;
363     }
364   }
365   // analyse found solids
366   if ( solids.Extent() == 0 || shells.Extent() == 0)
367     return invalidID;
368
369   const TopoDS_Solid& solid1 = TopoDS::Solid( solids(1) );
370   if ( solids.Extent() == 1 )
371   {
372     if ( toMeshHoles )
373       return meshDS->ShapeToIndex( solid1 );
374
375     // - Are we at a hole boundary face?
376     if ( shells(1).IsSame( BRepClass3d::OuterShell( solid1 )) )
377     { // - No, but maybe a hole is bound by two shapes? Does shells(1) touches another shell?
378       bool touch = false;
379       TopExp_Explorer eExp( shells(1), TopAbs_EDGE );
380       // check if any edge of shells(1) belongs to another shell
381       for ( ; eExp.More() && !touch; eExp.Next() ) {
382         ansIt = mesh.GetAncestors( eExp.Current() );
383         for ( ; ansIt.More() && !touch; ansIt.Next() ) {
384           if ( ansIt.Value().ShapeType() == TopAbs_SHELL )
385             touch = ( !ansIt.Value().IsSame( shells(1) ));
386         }
387       }
388       if (!touch)
389         return meshDS->ShapeToIndex( solid1 );
390     }
391   }
392   // find orientation of geom face within the first solid
393   TopExp_Explorer fExp( solid1, TopAbs_FACE );
394   for ( ; fExp.More(); fExp.Next() )
395     if ( geomFace.IsSame( fExp.Current() )) {
396       geomFace = TopoDS::Face( fExp.Current() );
397       break;
398     }
399   if ( !fExp.More() )
400     return invalidID; // face not found
401
402   // normale to triangle
403   gp_Pnt node1Pnt ( node1->X(), node1->Y(), node1->Z() );
404   gp_Pnt node2Pnt ( node2->X(), node2->Y(), node2->Z() );
405   gp_Pnt node3Pnt ( node3->X(), node3->Y(), node3->Z() );
406   gp_Vec vec12( node1Pnt, node2Pnt );
407   gp_Vec vec13( node1Pnt, node3Pnt );
408   gp_Vec meshNormal = vec12 ^ vec13;
409   if ( meshNormal.SquareMagnitude() < DBL_MIN )
410     return invalidID;
411
412   // get normale to geomFace at any node
413   bool geomNormalOK = false;
414   gp_Vec geomNormal;
415   SMESH_MesherHelper helper( mesh ); helper.SetSubShape( geomFace );
416   for ( int i = 0; !geomNormalOK && i < 3; ++i )
417   {
418     // find UV of i-th node on geomFace
419     const SMDS_MeshNode* nNotOnSeamEdge = 0;
420     if ( helper.IsSeamShape( nodes[i]->getshapeId() )) {
421       if ( helper.IsSeamShape( nodes[(i+1)%3]->getshapeId() ))
422         nNotOnSeamEdge = nodes[(i+2)%3];
423       else
424         nNotOnSeamEdge = nodes[(i+1)%3];
425     }
426     bool uvOK;
427     gp_XY uv = helper.GetNodeUV( geomFace, nodes[i], nNotOnSeamEdge, &uvOK );
428     // check that uv is correct
429     if (uvOK) {
430       double tol = 1e-6;
431       TopoDS_Shape nodeShape = helper.GetSubShapeByNode( nodes[i], meshDS );
432       if ( !nodeShape.IsNull() )
433         switch ( nodeShape.ShapeType() )
434         {
435         case TopAbs_FACE:   tol = BRep_Tool::Tolerance( TopoDS::Face( nodeShape )); break;
436         case TopAbs_EDGE:   tol = BRep_Tool::Tolerance( TopoDS::Edge( nodeShape )); break;
437         case TopAbs_VERTEX: tol = BRep_Tool::Tolerance( TopoDS::Vertex( nodeShape )); break;
438         default:;
439         }
440       gp_Pnt nodePnt ( nodes[i]->X(), nodes[i]->Y(), nodes[i]->Z() );
441       BRepAdaptor_Surface surface( geomFace );
442       uvOK = ( nodePnt.Distance( surface.Value( uv.X(), uv.Y() )) < 2 * tol );
443       if ( uvOK ) {
444         // normale to geomFace at UV
445         gp_Vec du, dv;
446         surface.D1( uv.X(), uv.Y(), nodePnt, du, dv );
447         geomNormal = du ^ dv;
448         if ( geomFace.Orientation() == TopAbs_REVERSED )
449           geomNormal.Reverse();
450         geomNormalOK = ( geomNormal.SquareMagnitude() > DBL_MIN * 1e3 );
451       }
452     }
453   }
454   if ( !geomNormalOK)
455     return invalidID;
456
457   // compare normals
458   bool isReverse = ( meshNormal * geomNormal ) < 0;
459   if ( !isReverse )
460     return meshDS->ShapeToIndex( solid1 );
461
462   if ( solids.Extent() == 1 )
463     return HOLE_ID; // we are inside a hole
464   else
465     return meshDS->ShapeToIndex( solids(2) );
466 }
467
468
469 //=======================================================================
470 //function : addElemInMeshGroup
471 //purpose  : Update or create groups in mesh
472 //=======================================================================
473
474 static void addElemInMeshGroup(SMESH_Mesh*             theMesh,
475                                const SMDS_MeshElement* anElem,
476                                std::string&            groupName,
477                                std::set<std::string>&  groupsToRemove)
478 {
479   if ( !anElem ) return; // issue 0021776
480
481   bool groupDone = false;
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     if ( groupDS->GetType()==anElem->GetType() &&groupName.compare(group->GetName())==0) {
489       SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( groupDS );
490       aGroupDS->SMDSGroup().Add(anElem);
491       groupDone = true;
492 //       MESSAGE("Successfully added enforced element to existing group " << groupName);
493       break;
494     }
495   }
496   
497   if (!groupDone)
498   {
499     int groupId;
500     SMESH_Group* aGroup = theMesh->AddGroup(anElem->GetType(), groupName.c_str(), groupId);
501     aGroup->SetName( groupName.c_str() );
502     SMESHDS_Group* aGroupDS = static_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
503     aGroupDS->SMDSGroup().Add(anElem);
504 //     MESSAGE("Successfully created enforced vertex group " << groupName);
505     groupDone = true;
506   }
507   if (!groupDone)
508     throw SALOME_Exception(LOCALIZED("A given element was not added to a group"));
509 }
510
511
512 //=======================================================================
513 //function : updateMeshGroups
514 //purpose  : Update or create groups in mesh
515 //=======================================================================
516
517 static void updateMeshGroups(SMESH_Mesh* theMesh, std::set<std::string> groupsToRemove)
518 {
519   SMESH_Mesh::GroupIteratorPtr grIt = theMesh->GetGroups();
520   while (grIt->more()) {
521     SMESH_Group * group = grIt->next();
522     if ( !group ) continue;
523     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
524     if ( !groupDS ) continue;
525     std::string currentGroupName = (string)group->GetName();
526     if (groupDS->IsEmpty() && groupsToRemove.find(currentGroupName) != groupsToRemove.end()) {
527       // Previous group created by enforced elements
528       MESSAGE("Delete previous group created by removed enforced elements: " << group->GetName())
529       theMesh->RemoveGroup(groupDS->GetID());
530     }
531   }
532 }
533
534 //=======================================================================
535 //function : removeEmptyGroupsOfDomains
536 //purpose  : remove empty groups named "Domain_nb" created due to
537 //           "To make groups of domains" option.
538 //=======================================================================
539
540 static void removeEmptyGroupsOfDomains(SMESH_Mesh* mesh,
541                                        bool        notEmptyAsWell = false)
542 {
543   const char* refName = theDomainGroupNamePrefix;
544   const size_t refLen = strlen( theDomainGroupNamePrefix );
545
546   std::list<int> groupIDs = mesh->GetGroupIds();
547   std::list<int>::const_iterator id = groupIDs.begin();
548   for ( ; id != groupIDs.end(); ++id )
549   {
550     SMESH_Group* group = mesh->GetGroup( *id );
551     if ( !group || ( !group->GetGroupDS()->IsEmpty() && !notEmptyAsWell ))
552       continue;
553     const char* name = group->GetName();
554     char* end;
555     // check the name
556     if ( strncmp( name, refName, refLen ) == 0 && // starts from refName;
557          isdigit( *( name + refLen )) &&          // refName is followed by a digit;
558          strtol( name + refLen, &end, 10) >= 0 && // there are only digits ...
559          *end == '\0')                            // ... till a string end.
560     {
561       mesh->RemoveGroup( *id );
562     }
563   }
564 }
565
566 //================================================================================
567 /*!
568  * \brief Create the groups corresponding to domains
569  */
570 //================================================================================
571
572 static void makeDomainGroups( std::vector< std::vector< const SMDS_MeshElement* > >& elemsOfDomain,
573                               SMESH_MesherHelper*                                    theHelper)
574 {
575   // int nbDomains = 0;
576   // for ( size_t i = 0; i < elemsOfDomain.size(); ++i )
577   //   nbDomains += ( elemsOfDomain[i].size() > 0 );
578
579   // if ( nbDomains > 1 )
580   for ( size_t iDomain = 0; iDomain < elemsOfDomain.size(); ++iDomain )
581   {
582     std::vector< const SMDS_MeshElement* > & elems = elemsOfDomain[ iDomain ];
583     if ( elems.empty() ) continue;
584
585     // find existing groups
586     std::vector< SMESH_Group* > groupOfType( SMDSAbs_NbElementTypes, (SMESH_Group*)NULL );
587     const std::string domainName = ( SMESH_Comment( theDomainGroupNamePrefix ) << iDomain );
588     SMESH_Mesh::GroupIteratorPtr groupIt = theHelper->GetMesh()->GetGroups();
589     while ( groupIt->more() )
590     {
591       SMESH_Group* group = groupIt->next();
592       if ( domainName == group->GetName() &&
593            dynamic_cast< SMESHDS_Group* >( group->GetGroupDS()) )
594         groupOfType[ group->GetGroupDS()->GetType() ] = group;
595     }
596     // create and fill the groups
597     size_t iElem = 0;
598     int groupID;
599     do
600     {
601       SMESH_Group* group = groupOfType[ elems[ iElem ]->GetType() ];
602       if ( !group )
603         group = theHelper->GetMesh()->AddGroup( elems[ iElem ]->GetType(),
604                                                 domainName.c_str(), groupID );
605       SMDS_MeshGroup& groupDS =
606         static_cast< SMESHDS_Group* >( group->GetGroupDS() )->SMDSGroup();
607
608       while ( iElem < elems.size() && groupDS.Add( elems[iElem] ))
609         ++iElem;
610
611     } while ( iElem < elems.size() );
612   }
613 }
614
615 //=======================================================================
616 //function : readGMFFile
617 //purpose  : read GMF file w/o geometry associated to mesh
618 //=======================================================================
619
620 static bool readGMFFile(const char*                     theFile,
621                         HYBRIDPlugin_HYBRID*              theAlgo,
622                         SMESH_MesherHelper*             theHelper,
623                         std::vector <const SMDS_MeshNode*> &    theNodeByHybridId,
624                         std::vector <const SMDS_MeshElement*> & theFaceByHybridId,
625                         map<const SMDS_MeshNode*,int> & theNodeToHybridIdMap,
626                         std::vector<std::string> &      aNodeGroupByHybridId,
627                         std::vector<std::string> &      anEdgeGroupByHybridId,
628                         std::vector<std::string> &      aFaceGroupByHybridId,
629                         std::set<std::string> &         groupsToRemove,
630                         bool                            toMakeGroupsOfDomains=false,
631                         bool                            toMeshHoles=true)
632 {
633   std::string tmpStr;
634   SMESHDS_Mesh* theMeshDS = theHelper->GetMeshDS();
635   const bool hasGeom = ( theHelper->GetMesh()->HasShapeToMesh() );
636
637   int nbInitialNodes = theNodeByHybridId.size();
638   int nbMeshNodes = theMeshDS->NbNodes();
639   
640   const bool isQuadMesh = 
641     theHelper->GetMesh()->NbEdges( ORDER_QUADRATIC ) ||
642     theHelper->GetMesh()->NbFaces( ORDER_QUADRATIC ) ||
643     theHelper->GetMesh()->NbVolumes( ORDER_QUADRATIC );
644     
645 #ifdef _DEBUG_
646   std::cout << "theNodeByHybridId.size(): " << nbInitialNodes << std::endl;
647   std::cout << "theHelper->GetMesh()->NbNodes(): " << nbMeshNodes << std::endl;
648   std::cout << "isQuadMesh: " << isQuadMesh << std::endl;
649 #endif
650   
651   // ---------------------------------
652   // Read generated elements and nodes
653   // ---------------------------------
654
655   int nbElem = 0, nbRef = 0;
656   int aGMFNodeID = 0;
657   const SMDS_MeshNode** GMFNode;
658 #ifdef _DEBUG_
659   std::map<int, std::set<int> > subdomainId2tetraId;
660 #endif
661   std::map <GmfKwdCod,int> tabRef;
662   const bool force3d = !hasGeom;
663   const int  noID    = 0;
664
665   tabRef[GmfVertices]       = 3; // for new nodes and enforced nodes
666   tabRef[GmfCorners]        = 1;
667   tabRef[GmfEdges]          = 2; // for enforced edges
668   tabRef[GmfRidges]         = 1;
669   tabRef[GmfTriangles]      = 3; // for enforced faces
670   tabRef[GmfQuadrilaterals] = 4;
671   tabRef[GmfTetrahedra]     = 4; // for new tetras
672   tabRef[GmfHexahedra]      = 8;
673
674   int ver, dim;
675   MESSAGE("Read " << theFile << " file");
676   int InpMsh = GmfOpenMesh(theFile, GmfRead, &ver, &dim);
677   if (!InpMsh)
678     return false;
679   MESSAGE("Done ");
680
681   // Read ids of domains
682   vector< int > solidIDByDomain;
683   if ( hasGeom )
684   {
685     int solid1; // id used in case of 1 domain or some reading failure
686     if ( theHelper->GetSubShape().ShapeType() == TopAbs_SOLID )
687       solid1 = theHelper->GetSubShapeID();
688     else
689       solid1 = theMeshDS->ShapeToIndex
690         ( TopExp_Explorer( theHelper->GetSubShape(), TopAbs_SOLID ).Current() );
691
692     int nbDomains = GmfStatKwd( InpMsh, GmfSubDomainFromGeom );
693     if ( nbDomains > 1 )
694     {
695       solidIDByDomain.resize( nbDomains+1, theHelper->GetSubShapeID() );
696       int faceNbNodes, faceIndex, orientation, domainNb;
697       GmfGotoKwd( InpMsh, GmfSubDomainFromGeom );
698       for ( int i = 0; i < nbDomains; ++i )
699       {
700         faceIndex = 0;
701         GmfGetLin( InpMsh, GmfSubDomainFromGeom,
702                    &faceNbNodes, &faceIndex, &orientation, &domainNb);
703         solidIDByDomain[ domainNb ] = 1;
704         if ( 0 < faceIndex && faceIndex-1 < theFaceByHybridId.size() )
705         {
706           const SMDS_MeshElement* face = theFaceByHybridId[ faceIndex-1 ];
707           const SMDS_MeshNode* nn[3] = { face->GetNode(0),
708                                          face->GetNode(1),
709                                          face->GetNode(2) };
710           if ( orientation < 0 )
711             std::swap( nn[1], nn[2] );
712           solidIDByDomain[ domainNb ] =
713             findShapeID( *theHelper->GetMesh(), nn[0], nn[1], nn[2], toMeshHoles );
714           if ( solidIDByDomain[ domainNb ] > 0 )
715           {
716             const TopoDS_Shape& foundShape = theMeshDS->IndexToShape( solidIDByDomain[ domainNb ] );
717             if ( ! theHelper->IsSubShape( foundShape, theHelper->GetSubShape() ))
718               solidIDByDomain[ domainNb ] = HOLE_ID;
719           }
720         }
721       }
722     }
723     if ( solidIDByDomain.size() < 2 )
724       solidIDByDomain.resize( 2, solid1 );
725   }
726
727   // Issue 0020682. Avoid creating nodes and tetras at place where
728   // volumic elements already exist
729   SMESH_ElementSearcher* elemSearcher = 0;
730   std::vector< const SMDS_MeshElement* > foundVolumes;
731   if ( !hasGeom && theHelper->GetMesh()->NbVolumes() > 0 )
732     elemSearcher = SMESH_MeshAlgos::GetElementSearcher( *theMeshDS );
733   auto_ptr< SMESH_ElementSearcher > elemSearcherDeleter( elemSearcher );
734
735   // IMP 0022172: [CEA 790] create the groups corresponding to domains
736   std::vector< std::vector< const SMDS_MeshElement* > > elemsOfDomain;
737
738   int nbVertices = GmfStatKwd(InpMsh, GmfVertices) - nbInitialNodes;
739   GMFNode = new const SMDS_MeshNode*[ nbVertices + 1 ];
740
741   std::map <GmfKwdCod,int>::const_iterator it = tabRef.begin();
742   for ( ; it != tabRef.end() ; ++it)
743   {
744     if(theAlgo->computeCanceled()) {
745       GmfCloseMesh(InpMsh);
746       delete [] GMFNode;
747       return false;
748     }
749     int dummy, solidID;
750     GmfKwdCod token = it->first;
751     nbRef           = it->second;
752
753     nbElem = GmfStatKwd(InpMsh, token);
754     if (nbElem > 0) {
755       GmfGotoKwd(InpMsh, token);
756       std::cout << "Read " << nbElem;
757     }
758     else
759       continue;
760
761     std::vector<int> id (nbElem*tabRef[token]); // node ids
762     std::vector<int> domainID( nbElem ); // domain
763
764     if (token == GmfVertices) {
765       (nbElem <= 1) ? tmpStr = " vertex" : tmpStr = " vertices";
766 //       std::cout << nbInitialNodes << " from input mesh " << std::endl;
767
768       // Remove orphan nodes from previous enforced mesh which was cleared
769 //       if ( nbElem < nbMeshNodes ) {
770 //         const SMDS_MeshNode* node;
771 //         SMDS_NodeIteratorPtr nodeIt = theMeshDS->nodesIterator();
772 //         while ( nodeIt->more() )
773 //         {
774 //           node = nodeIt->next();
775 //           if (theNodeToHybridIdMap.find(node) != theNodeToHybridIdMap.end())
776 //             theMeshDS->RemoveNode(node);
777 //         }
778 //       }
779
780       
781       int aGMFID;
782
783       float VerTab_f[3];
784       double x, y, z;
785       const SMDS_MeshNode * aGMFNode;
786
787       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
788         if(theAlgo->computeCanceled()) {
789           GmfCloseMesh(InpMsh);
790           delete [] GMFNode;
791           return false;
792         }
793         if (ver == GmfFloat) {
794           GmfGetLin(InpMsh, token, &VerTab_f[0], &VerTab_f[1], &VerTab_f[2], &dummy);
795           x = VerTab_f[0];
796           y = VerTab_f[1];
797           z = VerTab_f[2];
798         }
799         else {
800           GmfGetLin(InpMsh, token, &x, &y, &z, &dummy);
801         }
802         if (iElem >= nbInitialNodes) {
803           if ( elemSearcher &&
804                 elemSearcher->FindElementsByPoint( gp_Pnt(x,y,z), SMDSAbs_Volume, foundVolumes))
805             aGMFNode = 0;
806           else
807             aGMFNode = theHelper->AddNode(x, y, z);
808           
809           aGMFID = iElem -nbInitialNodes +1;
810           GMFNode[ aGMFID ] = aGMFNode;
811           if (aGMFID-1 < aNodeGroupByHybridId.size() && !aNodeGroupByHybridId.at(aGMFID-1).empty())
812             addElemInMeshGroup(theHelper->GetMesh(), aGMFNode, aNodeGroupByHybridId.at(aGMFID-1), groupsToRemove);
813         }
814       }
815     }
816     else if (token == GmfCorners && nbElem > 0) {
817       (nbElem <= 1) ? tmpStr = " corner" : tmpStr = " corners";
818       for ( int iElem = 0; iElem < nbElem; iElem++ )
819         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]]);
820     }
821     else if (token == GmfRidges && nbElem > 0) {
822       (nbElem <= 1) ? tmpStr = " ridge" : tmpStr = " ridges";
823       for ( int iElem = 0; iElem < nbElem; iElem++ )
824         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]]);
825     }
826     else if (token == GmfEdges && nbElem > 0) {
827       (nbElem <= 1) ? tmpStr = " edge" : tmpStr = " edges";
828       for ( int iElem = 0; iElem < nbElem; iElem++ )
829         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &domainID[iElem]);
830     }
831     else if (token == GmfTriangles && nbElem > 0) {
832       (nbElem <= 1) ? tmpStr = " triangle" : tmpStr = " triangles";
833       for ( int iElem = 0; iElem < nbElem; iElem++ )
834         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &domainID[iElem]);
835     }
836     else if (token == GmfQuadrilaterals && nbElem > 0) {
837       (nbElem <= 1) ? tmpStr = " Quadrilateral" : tmpStr = " Quadrilaterals";
838       for ( int iElem = 0; iElem < nbElem; iElem++ )
839         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
840     }
841     else if (token == GmfTetrahedra && nbElem > 0) {
842       (nbElem <= 1) ? tmpStr = " Tetrahedron" : tmpStr = " Tetrahedra";
843       for ( int iElem = 0; iElem < nbElem; iElem++ ) {
844         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3], &domainID[iElem]);
845 #ifdef _DEBUG_
846         subdomainId2tetraId[dummy].insert(iElem+1);
847 //         MESSAGE("subdomainId2tetraId["<<dummy<<"].insert("<<iElem+1<<")");
848 #endif
849       }
850     }
851     else if (token == GmfHexahedra && nbElem > 0) {
852       (nbElem <= 1) ? tmpStr = " Hexahedron" : tmpStr = " Hexahedra";
853       for ( int iElem = 0; iElem < nbElem; iElem++ )
854         GmfGetLin(InpMsh, token, &id[iElem*tabRef[token]], &id[iElem*tabRef[token]+1], &id[iElem*tabRef[token]+2], &id[iElem*tabRef[token]+3],
855                   &id[iElem*tabRef[token]+4], &id[iElem*tabRef[token]+5], &id[iElem*tabRef[token]+6], &id[iElem*tabRef[token]+7], &domainID[iElem]);
856     }
857     std::cout << tmpStr << std::endl;
858     std::cout << std::endl;
859
860     switch (token) {
861     case GmfCorners:
862     case GmfRidges:
863     case GmfEdges:
864     case GmfTriangles:
865     case GmfQuadrilaterals:
866     case GmfTetrahedra:
867     case GmfHexahedra:
868     {
869       std::vector< const SMDS_MeshNode* > node( nbRef );
870       std::vector< int >          nodeID( nbRef );
871       std::vector< SMDS_MeshNode* > enfNode( nbRef );
872       const SMDS_MeshElement* aCreatedElem;
873
874       for ( int iElem = 0; iElem < nbElem; iElem++ )
875       {
876         if(theAlgo->computeCanceled()) {
877           GmfCloseMesh(InpMsh);
878           delete [] GMFNode;
879           return false;
880         }
881         // Check if elem is already in input mesh. If yes => skip
882         bool fullyCreatedElement = false; // if at least one of the nodes was created
883         for ( int iRef = 0; iRef < nbRef; iRef++ )
884         {
885           aGMFNodeID = id[iElem*tabRef[token]+iRef]; // read nbRef aGMFNodeID
886           if (aGMFNodeID <= nbInitialNodes) // input nodes
887           {
888             aGMFNodeID--;
889             node[ iRef ] = theNodeByHybridId[aGMFNodeID];
890           }
891           else
892           {
893             fullyCreatedElement = true;
894             aGMFNodeID -= nbInitialNodes;
895             nodeID[ iRef ] = aGMFNodeID ;
896             node  [ iRef ] = GMFNode[ aGMFNodeID ];
897           }
898         }
899         aCreatedElem = 0;
900         switch (token)
901         {
902         case GmfEdges:
903           if (fullyCreatedElement) {
904             aCreatedElem = theHelper->AddEdge( node[0], node[1], noID, force3d );
905             if (anEdgeGroupByHybridId.size() && !anEdgeGroupByHybridId[iElem].empty())
906               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, anEdgeGroupByHybridId[iElem], groupsToRemove);
907           }
908           break;
909         case GmfTriangles:
910           if (fullyCreatedElement) {
911             aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], noID, force3d );
912             if (aFaceGroupByHybridId.size() && !aFaceGroupByHybridId[iElem].empty())
913               addElemInMeshGroup(theHelper->GetMesh(), aCreatedElem, aFaceGroupByHybridId[iElem], groupsToRemove);
914           }
915           break;
916         case GmfQuadrilaterals:
917           if (fullyCreatedElement) {
918             aCreatedElem = theHelper->AddFace( node[0], node[1], node[2], node[3], noID, force3d );
919           }
920           break;
921         case GmfTetrahedra:
922           if ( hasGeom )
923           {
924             solidID = solidIDByDomain[ domainID[iElem]];
925             if ( solidID != HOLE_ID )
926             {
927               aCreatedElem = theHelper->AddVolume( node[1], node[0], node[2], node[3],
928                                                    noID, force3d );
929               theMeshDS->SetMeshElementOnShape( aCreatedElem, solidID );
930               for ( int iN = 0; iN < 4; ++iN )
931                 if ( node[iN]->getshapeId() < 1 )
932                   theMeshDS->SetNodeInVolume( node[iN], solidID );
933             }
934           }
935           else
936           {
937             if ( elemSearcher ) {
938               // Issue 0020682. Avoid creating nodes and tetras at place where
939               // volumic elements already exist
940               if ( !node[1] || !node[0] || !node[2] || !node[3] )
941                 continue;
942               if ( elemSearcher->FindElementsByPoint((SMESH_TNodeXYZ(node[0]) +
943                                                       SMESH_TNodeXYZ(node[1]) +
944                                                       SMESH_TNodeXYZ(node[2]) +
945                                                       SMESH_TNodeXYZ(node[3]) ) / 4.,
946                                                      SMDSAbs_Volume, foundVolumes ))
947                 break;
948             }
949             aCreatedElem = theHelper->AddVolume( node[1], node[0], node[2], node[3],
950                                                  noID, force3d );
951           }
952           break;
953         case GmfHexahedra:
954           if ( hasGeom )
955           {
956             solidID = solidIDByDomain[ domainID[iElem]];
957             if ( solidID != HOLE_ID )
958             {
959               aCreatedElem = theHelper->AddVolume( node[0], node[3], node[2], node[1],
960                                                    node[4], node[7], node[6], node[5],
961                                                    noID, force3d );
962               theMeshDS->SetMeshElementOnShape( aCreatedElem, solidID );
963               for ( int iN = 0; iN < 8; ++iN )
964                 if ( node[iN]->getshapeId() < 1 )
965                   theMeshDS->SetNodeInVolume( node[iN], solidID );
966             }
967           }
968           else
969           {
970             if ( elemSearcher ) {
971               // Issue 0020682. Avoid creating nodes and tetras at place where
972               // volumic elements already exist
973               if ( !node[1] || !node[0] || !node[2] || !node[3] || !node[4] || !node[5] || !node[6] || !node[7])
974                 continue;
975               if ( elemSearcher->FindElementsByPoint((SMESH_TNodeXYZ(node[0]) +
976                                                       SMESH_TNodeXYZ(node[1]) +
977                                                       SMESH_TNodeXYZ(node[2]) +
978                                                       SMESH_TNodeXYZ(node[3]) +
979                                                       SMESH_TNodeXYZ(node[4]) +
980                                                       SMESH_TNodeXYZ(node[5]) +
981                                                       SMESH_TNodeXYZ(node[6]) +
982                                                       SMESH_TNodeXYZ(node[7])) / 8.,
983                                                      SMDSAbs_Volume, foundVolumes ))
984                 break;
985             }
986             aCreatedElem = theHelper->AddVolume( node[0], node[3], node[2], node[1],
987                                                  node[4], node[7], node[6], node[5],
988                                                  noID, force3d );
989           }
990           break;
991         default: continue;
992         } // switch (token)
993
994         if ( aCreatedElem && toMakeGroupsOfDomains )
995         {
996           if ( domainID[iElem] >= (int) elemsOfDomain.size() )
997             elemsOfDomain.resize( domainID[iElem] + 1 );
998           elemsOfDomain[ domainID[iElem] ].push_back( aCreatedElem );
999         }
1000       } // loop on elements of one type
1001       break;
1002     } // case ...
1003     } // switch (token)
1004   } // loop on tabRef
1005
1006   // remove nodes in holes
1007   if ( hasGeom )
1008   {
1009     for ( int i = 1; i <= nbVertices; ++i )
1010       if ( GMFNode[i]->NbInverseElements() == 0 )
1011         theMeshDS->RemoveFreeNode( GMFNode[i], /*sm=*/0, /*fromGroups=*/false );
1012   }
1013
1014   GmfCloseMesh(InpMsh);
1015   delete [] GMFNode;
1016
1017   // 0022172: [CEA 790] create the groups corresponding to domains
1018   if ( toMakeGroupsOfDomains )
1019     makeDomainGroups( elemsOfDomain, theHelper );
1020
1021 #ifdef _DEBUG_
1022   MESSAGE("Nb subdomains " << subdomainId2tetraId.size());
1023   std::map<int, std::set<int> >::const_iterator subdomainIt = subdomainId2tetraId.begin();
1024   TCollection_AsciiString aSubdomainFileName = theFile;
1025   aSubdomainFileName = aSubdomainFileName + ".subdomain";
1026   ofstream aSubdomainFile  ( aSubdomainFileName.ToCString()  , ios::out);
1027
1028   aSubdomainFile << "Nb subdomains " << subdomainId2tetraId.size() << std::endl;
1029   for(;subdomainIt != subdomainId2tetraId.end() ; ++subdomainIt) {
1030     int subdomainId = subdomainIt->first;
1031     std::set<int> tetraIds = subdomainIt->second;
1032     MESSAGE("Subdomain #"<<subdomainId<<": "<<tetraIds.size()<<" tetrahedrons");
1033     std::set<int>::const_iterator tetraIdsIt = tetraIds.begin();
1034     aSubdomainFile << subdomainId << std::endl;
1035     for(;tetraIdsIt != tetraIds.end() ; ++tetraIdsIt) {
1036       aSubdomainFile << (*tetraIdsIt) << " ";
1037     }
1038     aSubdomainFile << std::endl;
1039   }
1040   aSubdomainFile.close();
1041 #endif  
1042   
1043   return true;
1044 }
1045
1046
1047 static bool writeGMFFile(const char*                                     theMeshFileName,
1048                          const char*                                     theRequiredFileName,
1049                          const char*                                     theSolFileName,
1050                          const SMESH_ProxyMesh&                          theProxyMesh,
1051                          SMESH_MesherHelper&                             theHelper,
1052                          std::vector <const SMDS_MeshNode*> &            theNodeByHybridId,
1053                          std::vector <const SMDS_MeshElement*> &         theFaceByHybridId,
1054                          std::map<const SMDS_MeshNode*,int> &            aNodeToHybridIdMap,
1055                          std::vector<std::string> &                      aNodeGroupByHybridId,
1056                          std::vector<std::string> &                      anEdgeGroupByHybridId,
1057                          std::vector<std::string> &                      aFaceGroupByHybridId,
1058                          HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap & theEnforcedNodes,
1059                          HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedEdges,
1060                          HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedTriangles,
1061                          std::map<std::vector<double>, std::string> &    enfVerticesWithGroup,
1062                          HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues & theEnforcedVertices)
1063 {
1064   MESSAGE("writeGMFFile w/o geometry");
1065   std::string tmpStr;
1066   int idx, idxRequired = 0, idxSol = 0;
1067   const int dummyint = 0;
1068   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues::const_iterator vertexIt;
1069   std::vector<double> enfVertexSizes;
1070   const SMDS_MeshElement* elem;
1071   TIDSortedElemSet anElemSet, theKeptEnforcedEdges, theKeptEnforcedTriangles;
1072   SMDS_ElemIteratorPtr nodeIt;
1073   std::vector <const SMDS_MeshNode*> theEnforcedNodeByHybridId;
1074   map<const SMDS_MeshNode*,int> anEnforcedNodeToHybridIdMap, anExistingEnforcedNodeToHybridIdMap;
1075   std::vector< const SMDS_MeshElement* > foundElems;
1076   map<const SMDS_MeshNode*,TopAbs_State> aNodeToTopAbs_StateMap;
1077   int nbFoundElems;
1078   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap::iterator elemIt;
1079   TIDSortedElemSet::iterator elemSetIt;
1080   bool isOK;
1081   SMESH_Mesh* theMesh = theHelper.GetMesh();
1082   const bool hasGeom = theMesh->HasShapeToMesh();
1083   auto_ptr< SMESH_ElementSearcher > pntCls
1084     ( SMESH_MeshAlgos::GetElementSearcher(*theMesh->GetMeshDS()));
1085   
1086   int nbEnforcedVertices = theEnforcedVertices.size();
1087   
1088   // count faces
1089   int nbFaces = theProxyMesh.NbFaces();
1090   int nbNodes;
1091   theFaceByHybridId.reserve( nbFaces );
1092   
1093   // groups management
1094   int usedEnforcedNodes = 0;
1095   std::string gn = "";
1096
1097   if ( nbFaces == 0 )
1098     return false;
1099   
1100   idx = GmfOpenMesh(theMeshFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1101   if (!idx)
1102     return false;
1103   
1104   // ========================== FACES ==========================
1105   // TRIANGLES ==========================
1106   SMDS_ElemIteratorPtr eIt =
1107     hasGeom ? theProxyMesh.GetFaces( theHelper.GetSubShape()) : theProxyMesh.GetFaces();
1108   while ( eIt->more() )
1109   {
1110     elem = eIt->next();
1111     anElemSet.insert(elem);
1112     nodeIt = elem->nodesIterator();
1113     nbNodes = elem->NbCornerNodes();
1114     while ( nodeIt->more() && nbNodes--)
1115     {
1116       // find HYBRID ID
1117       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1118       int newId = aNodeToHybridIdMap.size() + 1; // hybrid ids count from 1
1119       aNodeToHybridIdMap.insert( make_pair( node, newId ));
1120     }
1121   }
1122   
1123   //EDGES ==========================
1124   
1125   // Iterate over the enforced edges
1126   for(elemIt = theEnforcedEdges.begin() ; elemIt != theEnforcedEdges.end() ; ++elemIt) {
1127     elem = elemIt->first;
1128     isOK = true;
1129     nodeIt = elem->nodesIterator();
1130     nbNodes = 2;
1131     while ( nodeIt->more() && nbNodes-- ) {
1132       // find HYBRID ID
1133       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1134       // Test if point is inside shape to mesh
1135       gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1136       TopAbs_State result = pntCls->GetPointState( myPoint );
1137       if ( result == TopAbs_OUT ) {
1138         isOK = false;
1139         break;
1140       }
1141       aNodeToTopAbs_StateMap.insert( make_pair( node, result ));
1142     }
1143     if (isOK) {
1144       nodeIt = elem->nodesIterator();
1145       nbNodes = 2;
1146       int newId = -1;
1147       while ( nodeIt->more() && nbNodes-- ) {
1148         // find HYBRID ID
1149         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1150         gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1151         nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1152 #ifdef _DEBUG_
1153         std::cout << "Node at "<<node->X()<<", "<<node->Y()<<", "<<node->Z()<<std::endl;
1154         std::cout << "Nb nodes found : "<<nbFoundElems<<std::endl;
1155 #endif
1156         if (nbFoundElems ==0) {
1157           if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1158             newId = aNodeToHybridIdMap.size() + anEnforcedNodeToHybridIdMap.size() + 1; // hybrid ids count from 1
1159             anEnforcedNodeToHybridIdMap.insert( make_pair( node, newId ));
1160           }
1161         }
1162         else if (nbFoundElems ==1) {
1163           const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1164           newId = (*aNodeToHybridIdMap.find(existingNode)).second;
1165           anExistingEnforcedNodeToHybridIdMap.insert( make_pair( node, newId ));
1166         }
1167         else
1168           isOK = false;
1169 #ifdef _DEBUG_
1170         std::cout << "HYBRID node ID: "<<newId<<std::endl;
1171 #endif
1172       }
1173       if (isOK)
1174         theKeptEnforcedEdges.insert(elem);
1175     }
1176   }
1177   
1178   //ENFORCED TRIANGLES ==========================
1179   
1180   // Iterate over the enforced triangles
1181   for(elemIt = theEnforcedTriangles.begin() ; elemIt != theEnforcedTriangles.end() ; ++elemIt) {
1182     elem = elemIt->first;
1183     isOK = true;
1184     nodeIt = elem->nodesIterator();
1185     nbNodes = 3;
1186     while ( nodeIt->more() && nbNodes--) {
1187       // find HYBRID ID
1188       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1189       // Test if point is inside shape to mesh
1190       gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1191       TopAbs_State result = pntCls->GetPointState( myPoint );
1192       if ( result == TopAbs_OUT ) {
1193         isOK = false;
1194         break;
1195       }
1196       aNodeToTopAbs_StateMap.insert( make_pair( node, result ));
1197     }
1198     if (isOK) {
1199       nodeIt = elem->nodesIterator();
1200       nbNodes = 3;
1201       int newId = -1;
1202       while ( nodeIt->more() && nbNodes--) {
1203         // find HYBRID ID
1204         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1205         gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1206         nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1207 #ifdef _DEBUG_
1208         std::cout << "Nb nodes found : "<<nbFoundElems<<std::endl;
1209 #endif
1210         if (nbFoundElems ==0) {
1211           if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1212             newId = aNodeToHybridIdMap.size() + anEnforcedNodeToHybridIdMap.size() + 1; // hybrid ids count from 1
1213             anEnforcedNodeToHybridIdMap.insert( make_pair( node, newId ));
1214           }
1215         }
1216         else if (nbFoundElems ==1) {
1217           const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1218           newId = (*aNodeToHybridIdMap.find(existingNode)).second;
1219           anExistingEnforcedNodeToHybridIdMap.insert( make_pair( node, newId ));
1220         }
1221         else
1222           isOK = false;
1223 #ifdef _DEBUG_
1224         std::cout << "HYBRID node ID: "<<newId<<std::endl;
1225 #endif
1226       }
1227       if (isOK)
1228         theKeptEnforcedTriangles.insert(elem);
1229     }
1230   }
1231   
1232   // put nodes to theNodeByHybridId vector
1233 #ifdef _DEBUG_
1234   std::cout << "aNodeToHybridIdMap.size(): "<<aNodeToHybridIdMap.size()<<std::endl;
1235 #endif
1236   theNodeByHybridId.resize( aNodeToHybridIdMap.size() );
1237   map<const SMDS_MeshNode*,int>::const_iterator n2id = aNodeToHybridIdMap.begin();
1238   for ( ; n2id != aNodeToHybridIdMap.end(); ++ n2id)
1239   {
1240 //     std::cout << "n2id->first: "<<n2id->first<<std::endl;
1241     theNodeByHybridId[ n2id->second - 1 ] = n2id->first; // hybrid ids count from 1
1242   }
1243
1244   // put nodes to anEnforcedNodeToHybridIdMap vector
1245 #ifdef _DEBUG_
1246   std::cout << "anEnforcedNodeToHybridIdMap.size(): "<<anEnforcedNodeToHybridIdMap.size()<<std::endl;
1247 #endif
1248   theEnforcedNodeByHybridId.resize( anEnforcedNodeToHybridIdMap.size());
1249   n2id = anEnforcedNodeToHybridIdMap.begin();
1250   for ( ; n2id != anEnforcedNodeToHybridIdMap.end(); ++ n2id)
1251   {
1252     if (n2id->second > aNodeToHybridIdMap.size()) {
1253       theEnforcedNodeByHybridId[ n2id->second - aNodeToHybridIdMap.size() - 1 ] = n2id->first; // hybrid ids count from 1
1254     }
1255   }
1256   
1257   
1258   //========================== NODES ==========================
1259   vector<const SMDS_MeshNode*> theOrderedNodes, theRequiredNodes;
1260   std::set< std::vector<double> > nodesCoords;
1261   vector<const SMDS_MeshNode*>::const_iterator hybridNodeIt = theNodeByHybridId.begin();
1262   vector<const SMDS_MeshNode*>::const_iterator after  = theNodeByHybridId.end();
1263   
1264   (theNodeByHybridId.size() <= 1) ? tmpStr = " node" : " nodes";
1265   std::cout << theNodeByHybridId.size() << tmpStr << " from mesh ..." << std::endl;
1266   for ( ; hybridNodeIt != after; ++hybridNodeIt )
1267   {
1268     const SMDS_MeshNode* node = *hybridNodeIt;
1269     std::vector<double> coords;
1270     coords.push_back(node->X());
1271     coords.push_back(node->Y());
1272     coords.push_back(node->Z());
1273     nodesCoords.insert(coords);
1274     theOrderedNodes.push_back(node);
1275   }
1276   
1277   // Iterate over the enforced nodes given by enforced elements
1278   hybridNodeIt = theEnforcedNodeByHybridId.begin();
1279   after  = theEnforcedNodeByHybridId.end();
1280   (theEnforcedNodeByHybridId.size() <= 1) ? tmpStr = " node" : " nodes";
1281   std::cout << theEnforcedNodeByHybridId.size() << tmpStr << " from enforced elements ..." << std::endl;
1282   for ( ; hybridNodeIt != after; ++hybridNodeIt )
1283   {
1284     const SMDS_MeshNode* node = *hybridNodeIt;
1285     std::vector<double> coords;
1286     coords.push_back(node->X());
1287     coords.push_back(node->Y());
1288     coords.push_back(node->Z());
1289 #ifdef _DEBUG_
1290     std::cout << "Node at " << node->X()<<", " <<node->Y()<<", " <<node->Z();
1291 #endif
1292     
1293     if (nodesCoords.find(coords) != nodesCoords.end()) {
1294       // node already exists in original mesh
1295 #ifdef _DEBUG_
1296       std::cout << " found" << std::endl;
1297 #endif
1298       continue;
1299     }
1300     
1301     if (theEnforcedVertices.find(coords) != theEnforcedVertices.end()) {
1302       // node already exists in enforced vertices
1303 #ifdef _DEBUG_
1304       std::cout << " found" << std::endl;
1305 #endif
1306       continue;
1307     }
1308     
1309 //     gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1310 //     nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1311 //     if (nbFoundElems ==0) {
1312 //       std::cout << " not found" << std::endl;
1313 //       if ((*aNodeToTopAbs_StateMap.find(node)).second == TopAbs_IN) {
1314 //         nodesCoords.insert(coords);
1315 //         theOrderedNodes.push_back(node);
1316 //       }
1317 //     }
1318 //     else {
1319 //       std::cout << " found in initial mesh" << std::endl;
1320 //       const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1321 //       nodesCoords.insert(coords);
1322 //       theOrderedNodes.push_back(existingNode);
1323 //     }
1324     
1325 #ifdef _DEBUG_
1326     std::cout << " not found" << std::endl;
1327 #endif
1328     
1329     nodesCoords.insert(coords);
1330     theOrderedNodes.push_back(node);
1331 //     theRequiredNodes.push_back(node);
1332   }
1333   
1334   
1335   // Iterate over the enforced nodes
1336   HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap::const_iterator enfNodeIt;
1337   (theEnforcedNodes.size() <= 1) ? tmpStr = " node" : " nodes";
1338   std::cout << theEnforcedNodes.size() << tmpStr << " from enforced nodes ..." << std::endl;
1339   for(enfNodeIt = theEnforcedNodes.begin() ; enfNodeIt != theEnforcedNodes.end() ; ++enfNodeIt)
1340   {
1341     const SMDS_MeshNode* node = enfNodeIt->first;
1342     std::vector<double> coords;
1343     coords.push_back(node->X());
1344     coords.push_back(node->Y());
1345     coords.push_back(node->Z());
1346 #ifdef _DEBUG_
1347     std::cout << "Node at " << node->X()<<", " <<node->Y()<<", " <<node->Z();
1348 #endif
1349     
1350     // Test if point is inside shape to mesh
1351     gp_Pnt myPoint(node->X(),node->Y(),node->Z());
1352     TopAbs_State result = pntCls->GetPointState( myPoint );
1353     if ( result == TopAbs_OUT ) {
1354 #ifdef _DEBUG_
1355       std::cout << " out of volume" << std::endl;
1356 #endif
1357       continue;
1358     }
1359     
1360     if (nodesCoords.find(coords) != nodesCoords.end()) {
1361 #ifdef _DEBUG_
1362       std::cout << " found in nodesCoords" << std::endl;
1363 #endif
1364 //       theRequiredNodes.push_back(node);
1365       continue;
1366     }
1367
1368     if (theEnforcedVertices.find(coords) != theEnforcedVertices.end()) {
1369 #ifdef _DEBUG_
1370       std::cout << " found in theEnforcedVertices" << std::endl;
1371 #endif
1372       continue;
1373     }
1374     
1375 //     nbFoundElems = pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems);
1376 //     if (nbFoundElems ==0) {
1377 //       std::cout << " not found" << std::endl;
1378 //       if (result == TopAbs_IN) {
1379 //         nodesCoords.insert(coords);
1380 //         theRequiredNodes.push_back(node);
1381 //       }
1382 //     }
1383 //     else {
1384 //       std::cout << " found in initial mesh" << std::endl;
1385 //       const SMDS_MeshNode* existingNode = (SMDS_MeshNode*) foundElems.at(0);
1386 // //       nodesCoords.insert(coords);
1387 //       theRequiredNodes.push_back(existingNode);
1388 //     }
1389 //     
1390 //     
1391 //     
1392 //     if (pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems) == 0)
1393 //       continue;
1394
1395 //     if ( result != TopAbs_IN )
1396 //       continue;
1397     
1398 #ifdef _DEBUG_
1399     std::cout << " not found" << std::endl;
1400 #endif
1401     nodesCoords.insert(coords);
1402 //     theOrderedNodes.push_back(node);
1403     theRequiredNodes.push_back(node);
1404   }
1405   int requiredNodes = theRequiredNodes.size();
1406   
1407   int solSize = 0;
1408   std::vector<std::vector<double> > ReqVerTab;
1409   if (nbEnforcedVertices) {
1410 //    ReqVerTab.clear();
1411     (nbEnforcedVertices <= 1) ? tmpStr = " node" : " nodes";
1412     std::cout << nbEnforcedVertices << tmpStr << " from enforced vertices ..." << std::endl;
1413     // Iterate over the enforced vertices
1414     for(vertexIt = theEnforcedVertices.begin() ; vertexIt != theEnforcedVertices.end() ; ++vertexIt) {
1415       double x = vertexIt->first[0];
1416       double y = vertexIt->first[1];
1417       double z = vertexIt->first[2];
1418       // Test if point is inside shape to mesh
1419       gp_Pnt myPoint(x,y,z);
1420       TopAbs_State result = pntCls->GetPointState( myPoint );
1421       if ( result == TopAbs_OUT )
1422         continue;
1423       //if (pntCls->FindElementsByPoint(myPoint, SMDSAbs_Node, foundElems) == 0)
1424       //continue;
1425
1426 //       if ( result != TopAbs_IN )
1427 //         continue;
1428       std::vector<double> coords;
1429       coords.push_back(x);
1430       coords.push_back(y);
1431       coords.push_back(z);
1432       ReqVerTab.push_back(coords);
1433       enfVertexSizes.push_back(vertexIt->second);
1434       solSize++;
1435     }
1436   }
1437   
1438   
1439   // GmfVertices
1440   std::cout << "Begin writting required nodes in GmfVertices" << std::endl;
1441   std::cout << "Nb vertices: " << theOrderedNodes.size() << std::endl;
1442   GmfSetKwd(idx, GmfVertices, theOrderedNodes.size()); //theOrderedNodes.size()+solSize)
1443   for (hybridNodeIt = theOrderedNodes.begin();hybridNodeIt != theOrderedNodes.end();++hybridNodeIt) {
1444     GmfSetLin(idx, GmfVertices, (*hybridNodeIt)->X(), (*hybridNodeIt)->Y(), (*hybridNodeIt)->Z(), dummyint);
1445   }
1446
1447   std::cout << "End writting required nodes in GmfVertices" << std::endl;
1448
1449   if (requiredNodes + solSize) {
1450     std::cout << "Begin writting in req and sol file" << std::endl;
1451     aNodeGroupByHybridId.resize( requiredNodes + solSize );
1452     idxRequired = GmfOpenMesh(theRequiredFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1453     if (!idxRequired) {
1454       GmfCloseMesh(idx);
1455       return false;
1456     }
1457     idxSol = GmfOpenMesh(theSolFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1458     if (!idxSol) {
1459       GmfCloseMesh(idx);
1460       if (idxRequired)
1461         GmfCloseMesh(idxRequired);
1462       return false;
1463     }
1464     int TypTab[] = {GmfSca};
1465     double ValTab[] = {0.0};
1466     GmfSetKwd(idxRequired, GmfVertices, requiredNodes + solSize);
1467     GmfSetKwd(idxSol, GmfSolAtVertices, requiredNodes + solSize, 1, TypTab);
1468 //     int usedEnforcedNodes = 0;
1469 //     std::string gn = "";
1470     for (hybridNodeIt = theRequiredNodes.begin();hybridNodeIt != theRequiredNodes.end();++hybridNodeIt) {
1471       GmfSetLin(idxRequired, GmfVertices, (*hybridNodeIt)->X(), (*hybridNodeIt)->Y(), (*hybridNodeIt)->Z(), dummyint);
1472       GmfSetLin(idxSol, GmfSolAtVertices, ValTab);
1473       if (theEnforcedNodes.find((*hybridNodeIt)) != theEnforcedNodes.end())
1474         gn = theEnforcedNodes.find((*hybridNodeIt))->second;
1475       aNodeGroupByHybridId[usedEnforcedNodes] = gn;
1476       usedEnforcedNodes++;
1477     }
1478
1479     for (int i=0;i<solSize;i++) {
1480       std::cout << ReqVerTab[i][0] <<" "<< ReqVerTab[i][1] << " "<< ReqVerTab[i][2] << std::endl;
1481 #ifdef _DEBUG_
1482       std::cout << "enfVertexSizes.at("<<i<<"): " << enfVertexSizes.at(i) << std::endl;
1483 #endif
1484       double solTab[] = {enfVertexSizes.at(i)};
1485       GmfSetLin(idxRequired, GmfVertices, ReqVerTab[i][0], ReqVerTab[i][1], ReqVerTab[i][2], dummyint);
1486       GmfSetLin(idxSol, GmfSolAtVertices, solTab);
1487       aNodeGroupByHybridId[usedEnforcedNodes] = enfVerticesWithGroup.find(ReqVerTab[i])->second;
1488 #ifdef _DEBUG_
1489       std::cout << "aNodeGroupByHybridId["<<usedEnforcedNodes<<"] = \""<<aNodeGroupByHybridId[usedEnforcedNodes]<<"\""<<std::endl;
1490 #endif
1491       usedEnforcedNodes++;
1492     }
1493     std::cout << "End writting in req and sol file" << std::endl;
1494   }
1495
1496   int nedge[2], ntri[3];
1497     
1498   // GmfEdges
1499   int usedEnforcedEdges = 0;
1500   if (theKeptEnforcedEdges.size()) {
1501     anEdgeGroupByHybridId.resize( theKeptEnforcedEdges.size() );
1502 //    idxRequired = GmfOpenMesh(theRequiredFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1503 //    if (!idxRequired)
1504 //      return false;
1505     GmfSetKwd(idx, GmfEdges, theKeptEnforcedEdges.size());
1506 //    GmfSetKwd(idxRequired, GmfEdges, theKeptEnforcedEdges.size());
1507     for(elemSetIt = theKeptEnforcedEdges.begin() ; elemSetIt != theKeptEnforcedEdges.end() ; ++elemSetIt) {
1508       elem = (*elemSetIt);
1509       nodeIt = elem->nodesIterator();
1510       int index=0;
1511       while ( nodeIt->more() ) {
1512         // find HYBRID ID
1513         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1514         map< const SMDS_MeshNode*,int >::iterator it = anEnforcedNodeToHybridIdMap.find(node);
1515         if (it == anEnforcedNodeToHybridIdMap.end()) {
1516           it = anExistingEnforcedNodeToHybridIdMap.find(node);
1517           if (it == anEnforcedNodeToHybridIdMap.end())
1518             throw "Node not found";
1519         }
1520         nedge[index] = it->second;
1521         index++;
1522       }
1523       GmfSetLin(idx, GmfEdges, nedge[0], nedge[1], dummyint);
1524       anEdgeGroupByHybridId[usedEnforcedEdges] = theEnforcedEdges.find(elem)->second;
1525 //      GmfSetLin(idxRequired, GmfEdges, nedge[0], nedge[1], dummyint);
1526       usedEnforcedEdges++;
1527     }
1528 //    GmfCloseMesh(idxRequired);
1529   }
1530
1531
1532   if (usedEnforcedEdges) {
1533     GmfSetKwd(idx, GmfRequiredEdges, usedEnforcedEdges);
1534     for (int enfID=1;enfID<=usedEnforcedEdges;enfID++) {
1535       GmfSetLin(idx, GmfRequiredEdges, enfID);
1536     }
1537   }
1538
1539   // GmfTriangles
1540   int usedEnforcedTriangles = 0;
1541   if (anElemSet.size()+theKeptEnforcedTriangles.size()) {
1542     aFaceGroupByHybridId.resize( anElemSet.size()+theKeptEnforcedTriangles.size() );
1543     GmfSetKwd(idx, GmfTriangles, anElemSet.size()+theKeptEnforcedTriangles.size());
1544     int k=0;
1545     for(elemSetIt = anElemSet.begin() ; elemSetIt != anElemSet.end() ; ++elemSetIt,++k) {
1546       elem = (*elemSetIt);
1547       theFaceByHybridId.push_back( elem );
1548       nodeIt = elem->nodesIterator();
1549       int index=0;
1550       for ( int j = 0; j < 3; ++j ) {
1551         // find HYBRID ID
1552         const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1553         map< const SMDS_MeshNode*,int >::iterator it = aNodeToHybridIdMap.find(node);
1554         if (it == aNodeToHybridIdMap.end())
1555           throw "Node not found";
1556         ntri[index] = it->second;
1557         index++;
1558       }
1559       GmfSetLin(idx, GmfTriangles, ntri[0], ntri[1], ntri[2], dummyint);
1560       aFaceGroupByHybridId[k] = "";
1561     }
1562     if ( !theHelper.GetMesh()->HasShapeToMesh() )
1563       SMESHUtils::FreeVector( theFaceByHybridId );
1564     if (theKeptEnforcedTriangles.size()) {
1565       for(elemSetIt = theKeptEnforcedTriangles.begin() ; elemSetIt != theKeptEnforcedTriangles.end() ; ++elemSetIt,++k) {
1566         elem = (*elemSetIt);
1567         nodeIt = elem->nodesIterator();
1568         int index=0;
1569         for ( int j = 0; j < 3; ++j ) {
1570           // find HYBRID ID
1571           const SMDS_MeshNode* node = castToNode( nodeIt->next() );
1572           map< const SMDS_MeshNode*,int >::iterator it = anEnforcedNodeToHybridIdMap.find(node);
1573           if (it == anEnforcedNodeToHybridIdMap.end()) {
1574             it = anExistingEnforcedNodeToHybridIdMap.find(node);
1575             if (it == anEnforcedNodeToHybridIdMap.end())
1576               throw "Node not found";
1577           }
1578           ntri[index] = it->second;
1579           index++;
1580         }
1581         GmfSetLin(idx, GmfTriangles, ntri[0], ntri[1], ntri[2], dummyint);
1582         aFaceGroupByHybridId[k] = theEnforcedTriangles.find(elem)->second;
1583         usedEnforcedTriangles++;
1584       }
1585     }
1586   }
1587
1588   
1589   if (usedEnforcedTriangles) {
1590     GmfSetKwd(idx, GmfRequiredTriangles, usedEnforcedTriangles);
1591     for (int enfID=1;enfID<=usedEnforcedTriangles;enfID++)
1592       GmfSetLin(idx, GmfRequiredTriangles, anElemSet.size()+enfID);
1593   }
1594
1595   GmfCloseMesh(idx);
1596   if (idxRequired)
1597     GmfCloseMesh(idxRequired);
1598   if (idxSol)
1599     GmfCloseMesh(idxSol);
1600   
1601   return true;
1602   
1603 }
1604
1605 // static bool writeGMFFile(const char*                                    theMeshFileName,
1606 //                         const char*                                     theRequiredFileName,
1607 //                         const char*                                     theSolFileName,
1608 //                         SMESH_MesherHelper&                             theHelper,
1609 //                         const SMESH_ProxyMesh&                          theProxyMesh,
1610 //                         std::map <int,int> &                            theNodeId2NodeIndexMap,
1611 //                         std::map <int,int> &                            theSmdsToHybridIdMap,
1612 //                         std::map <int,const SMDS_MeshNode*> &           theHybridIdToNodeMap,
1613 //                         TIDSortedNodeSet &                              theEnforcedNodes,
1614 //                         TIDSortedElemSet &                              theEnforcedEdges,
1615 //                         TIDSortedElemSet &                              theEnforcedTriangles,
1616 // //                         TIDSortedElemSet &                              theEnforcedQuadrangles,
1617 //                         HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues & theEnforcedVertices)
1618 // {
1619 //   MESSAGE("writeGMFFile with geometry");
1620 //   int idx, idxRequired, idxSol;
1621 //   int nbv, nbev, nben, aHybridID = 0;
1622 //   const int dummyint = 0;
1623 //   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues::const_iterator vertexIt;
1624 //   std::vector<double> enfVertexSizes;
1625 //   TIDSortedNodeSet::const_iterator enfNodeIt;
1626 //   const SMDS_MeshNode* node;
1627 //   SMDS_NodeIteratorPtr nodeIt;
1628 // 
1629 //   idx = GmfOpenMesh(theMeshFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1630 //   if (!idx)
1631 //     return false;
1632 //   
1633 //   SMESHDS_Mesh * theMeshDS = theHelper.GetMeshDS();
1634 //   
1635 //   /* ========================== NODES ========================== */
1636 //   // NB_NODES
1637 //   nbv = theMeshDS->NbNodes();
1638 //   if ( nbv == 0 )
1639 //     return false;
1640 //   nbev = theEnforcedVertices.size();
1641 //   nben = theEnforcedNodes.size();
1642 //   
1643 //   // Issue 020674: EDF 870 SMESH: Mesh generated by Netgen not usable by HYBRID
1644 //   // The problem is in nodes on degenerated edges, we need to skip nodes which are free
1645 //   // and replace not-free nodes on edges by the node on vertex
1646 //   TNodeNodeMap n2nDegen; // map a node on degenerated edge to a node on vertex
1647 //   TNodeNodeMap::iterator n2nDegenIt;
1648 //   if ( theHelper.HasDegeneratedEdges() )
1649 //   {
1650 //     set<int> checkedSM;
1651 //     for (TopExp_Explorer e(theMeshDS->ShapeToMesh(), TopAbs_EDGE ); e.More(); e.Next())
1652 //     {
1653 //       SMESH_subMesh* sm = theHelper.GetMesh()->GetSubMesh( e.Current() );
1654 //       if ( checkedSM.insert( sm->GetId() ).second && theHelper.IsDegenShape(sm->GetId() ))
1655 //       {
1656 //         if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() )
1657 //         {
1658 //           TopoDS_Shape vertex = TopoDS_Iterator( e.Current() ).Value();
1659 //           const SMDS_MeshNode* vNode = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), theMeshDS);
1660 //           {
1661 //             SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
1662 //             while ( nIt->more() )
1663 //               n2nDegen.insert( make_pair( nIt->next(), vNode ));
1664 //           }
1665 //         }
1666 //       }
1667 //     }
1668 //   }
1669 //   
1670 //   const bool isQuadMesh = 
1671 //     theHelper.GetMesh()->NbEdges( ORDER_QUADRATIC ) ||
1672 //     theHelper.GetMesh()->NbFaces( ORDER_QUADRATIC ) ||
1673 //     theHelper.GetMesh()->NbVolumes( ORDER_QUADRATIC );
1674 // 
1675 //   std::vector<std::vector<double> > VerTab;
1676 //   std::set<std::vector<double> > VerMap;
1677 //   VerTab.clear();
1678 //   std::vector<double> aVerTab;
1679 //   // Loop from 1 to NB_NODES
1680 // 
1681 //   nodeIt = theMeshDS->nodesIterator();
1682 //   
1683 //   while ( nodeIt->more() )
1684 //   {
1685 //     node = nodeIt->next();
1686 //     if ( isQuadMesh && theHelper.IsMedium( node )) // Issue 0021238
1687 //       continue;
1688 //     if ( n2nDegen.count( node ) ) // Issue 0020674
1689 //       continue;
1690 // 
1691 //     std::vector<double> coords;
1692 //     coords.push_back(node->X());
1693 //     coords.push_back(node->Y());
1694 //     coords.push_back(node->Z());
1695 //     if (VerMap.find(coords) != VerMap.end()) {
1696 //       aHybridID = theSmdsToHybridIdMap[node->GetID()];
1697 //       theHybridIdToNodeMap[theSmdsToHybridIdMap[node->GetID()]] = node;
1698 //       continue;
1699 //     }
1700 //     VerTab.push_back(coords);
1701 //     VerMap.insert(coords);
1702 //     aHybridID++;
1703 //     theSmdsToHybridIdMap.insert( make_pair( node->GetID(), aHybridID ));
1704 //     theHybridIdToNodeMap.insert( make_pair( aHybridID, node ));
1705 //   }
1706 //   
1707 //   
1708 //   /* ENFORCED NODES ========================== */
1709 //   if (nben) {
1710 //     std::cout << "Add " << nben << " enforced nodes to input .mesh file" << std::endl;
1711 //     for(enfNodeIt = theEnforcedNodes.begin() ; enfNodeIt != theEnforcedNodes.end() ; ++enfNodeIt) {
1712 //       double x = (*enfNodeIt)->X();
1713 //       double y = (*enfNodeIt)->Y();
1714 //       double z = (*enfNodeIt)->Z();
1715 //       // Test if point is inside shape to mesh
1716 //       gp_Pnt myPoint(x,y,z);
1717 //       BRepClass3d_SolidClassifier scl(theMeshDS->ShapeToMesh());
1718 //       scl.Perform(myPoint, 1e-7);
1719 //       TopAbs_State result = scl.State();
1720 //       if ( result != TopAbs_IN )
1721 //         continue;
1722 //       std::vector<double> coords;
1723 //       coords.push_back(x);
1724 //       coords.push_back(y);
1725 //       coords.push_back(z);
1726 //       if (theEnforcedVertices.find(coords) != theEnforcedVertices.end())
1727 //         continue;
1728 //       if (VerMap.find(coords) != VerMap.end())
1729 //         continue;
1730 //       VerTab.push_back(coords);
1731 //       VerMap.insert(coords);
1732 //       aHybridID++;
1733 //       theNodeId2NodeIndexMap.insert( make_pair( (*enfNodeIt)->GetID(), aHybridID ));
1734 //     }
1735 //   }
1736 //     
1737 //   
1738 //   /* ENFORCED VERTICES ========================== */
1739 //   int solSize = 0;
1740 //   std::vector<std::vector<double> > ReqVerTab;
1741 //   ReqVerTab.clear();
1742 //   if (nbev) {
1743 //     std::cout << "Add " << nbev << " enforced vertices to input .mesh file" << std::endl;
1744 //     for(vertexIt = theEnforcedVertices.begin() ; vertexIt != theEnforcedVertices.end() ; ++vertexIt) {
1745 //       double x = vertexIt->first[0];
1746 //       double y = vertexIt->first[1];
1747 //       double z = vertexIt->first[2];
1748 //       // Test if point is inside shape to mesh
1749 //       gp_Pnt myPoint(x,y,z);
1750 //       BRepClass3d_SolidClassifier scl(theMeshDS->ShapeToMesh());
1751 //       scl.Perform(myPoint, 1e-7);
1752 //       TopAbs_State result = scl.State();
1753 //       if ( result != TopAbs_IN )
1754 //         continue;
1755 //       enfVertexSizes.push_back(vertexIt->second);
1756 //       std::vector<double> coords;
1757 //       coords.push_back(x);
1758 //       coords.push_back(y);
1759 //       coords.push_back(z);
1760 //       if (VerMap.find(coords) != VerMap.end())
1761 //         continue;
1762 //       ReqVerTab.push_back(coords);
1763 //       VerMap.insert(coords);
1764 //       solSize++;
1765 //     }
1766 //   }
1767 // 
1768 //   
1769 //   /* ========================== FACES ========================== */
1770 //   
1771 //   int nbTriangles = 0/*, nbQuadrangles = 0*/, aSmdsID;
1772 //   TopTools_IndexedMapOfShape facesMap, trianglesMap/*, quadranglesMap*/;
1773 //   TIDSortedElemSet::const_iterator elemIt;
1774 //   const SMESHDS_SubMesh* theSubMesh;
1775 //   TopoDS_Shape aShape;
1776 //   SMDS_ElemIteratorPtr itOnSubMesh, itOnSubFace;
1777 //   const SMDS_MeshElement* aFace;
1778 //   map<int,int>::const_iterator itOnMap;
1779 //   std::vector<std::vector<int> > tt, qt,et;
1780 //   tt.clear();
1781 //   qt.clear();
1782 //   et.clear();
1783 //   std::vector<int> att, aqt, aet;
1784 //   
1785 //   TopExp::MapShapes( theMeshDS->ShapeToMesh(), TopAbs_FACE, facesMap );
1786 // 
1787 //   for ( int i = 1; i <= facesMap.Extent(); ++i )
1788 //     if (( theSubMesh  = theProxyMesh.GetSubMesh( facesMap(i))))
1789 //     {
1790 //       SMDS_ElemIteratorPtr it = theSubMesh->GetElements();
1791 //       while (it->more())
1792 //       {
1793 //         const SMDS_MeshElement *elem = it->next();
1794 //         int nbCornerNodes = elem->NbCornerNodes();
1795 //         if (nbCornerNodes == 3)
1796 //         {
1797 //           trianglesMap.Add(facesMap(i));
1798 //           nbTriangles ++;
1799 //         }
1800 // //         else if (nbCornerNodes == 4)
1801 // //         {
1802 // //           quadranglesMap.Add(facesMap(i));
1803 // //           nbQuadrangles ++;
1804 // //         }
1805 //       }
1806 //     }
1807 //     
1808 //   /* TRIANGLES ========================== */
1809 //   if (nbTriangles) {
1810 //     for ( int i = 1; i <= trianglesMap.Extent(); i++ )
1811 //     {
1812 //       aShape = trianglesMap(i);
1813 //       theSubMesh = theProxyMesh.GetSubMesh(aShape);
1814 //       if ( !theSubMesh ) continue;
1815 //       itOnSubMesh = theSubMesh->GetElements();
1816 //       while ( itOnSubMesh->more() )
1817 //       {
1818 //         aFace = itOnSubMesh->next();
1819 //         itOnSubFace = aFace->nodesIterator();
1820 //         att.clear();
1821 //         for ( int j = 0; j < 3; ++j ) {
1822 //           // find HYBRID ID
1823 //           node = castToNode( itOnSubFace->next() );
1824 //           if (( n2nDegenIt = n2nDegen.find( node )) != n2nDegen.end() )
1825 //             node = n2nDegenIt->second;
1826 //           aSmdsID = node->GetID();
1827 //           itOnMap = theSmdsToHybridIdMap.find( aSmdsID );
1828 //           ASSERT( itOnMap != theSmdsToHybridIdMap.end() );
1829 //           att.push_back((*itOnMap).second);
1830 //         }
1831 //         tt.push_back(att);
1832 //       }
1833 //     }
1834 //   }
1835 // 
1836 //   if (theEnforcedTriangles.size()) {
1837 //     std::cout << "Add " << theEnforcedTriangles.size() << " enforced triangles to input .mesh file" << std::endl;
1838 //     // Iterate over the enforced triangles
1839 //     for(elemIt = theEnforcedTriangles.begin() ; elemIt != theEnforcedTriangles.end() ; ++elemIt) {
1840 //       aFace = (*elemIt);
1841 //       itOnSubFace = aFace->nodesIterator();
1842 //       bool isOK = true;
1843 //       att.clear();
1844 //       
1845 //       for ( int j = 0; j < 3; ++j ) {
1846 //         node = castToNode( itOnSubFace->next() );
1847 //         if (( n2nDegenIt = n2nDegen.find( node )) != n2nDegen.end() )
1848 //           node = n2nDegenIt->second;
1849 // //         std::cout << node;
1850 //         double x = node->X();
1851 //         double y = node->Y();
1852 //         double z = node->Z();
1853 //         // Test if point is inside shape to mesh
1854 //         gp_Pnt myPoint(x,y,z);
1855 //         BRepClass3d_SolidClassifier scl(theMeshDS->ShapeToMesh());
1856 //         scl.Perform(myPoint, 1e-7);
1857 //         TopAbs_State result = scl.State();
1858 //         if ( result != TopAbs_IN ) {
1859 //           isOK = false;
1860 //           theEnforcedTriangles.erase(elemIt);
1861 //           continue;
1862 //         }
1863 //         std::vector<double> coords;
1864 //         coords.push_back(x);
1865 //         coords.push_back(y);
1866 //         coords.push_back(z);
1867 //         if (VerMap.find(coords) != VerMap.end()) {
1868 //           att.push_back(theNodeId2NodeIndexMap[node->GetID()]);
1869 //           continue;
1870 //         }
1871 //         VerTab.push_back(coords);
1872 //         VerMap.insert(coords);
1873 //         aHybridID++;
1874 //         theNodeId2NodeIndexMap.insert( make_pair( node->GetID(), aHybridID ));
1875 //         att.push_back(aHybridID);
1876 //       }
1877 //       if (isOK)
1878 //         tt.push_back(att);
1879 //     }
1880 //   }
1881 // 
1882 // 
1883 //   /* ========================== EDGES ========================== */
1884 // 
1885 //   if (theEnforcedEdges.size()) {
1886 //     // Iterate over the enforced edges
1887 //     std::cout << "Add " << theEnforcedEdges.size() << " enforced edges to input .mesh file" << std::endl;
1888 //     for(elemIt = theEnforcedEdges.begin() ; elemIt != theEnforcedEdges.end() ; ++elemIt) {
1889 //       aFace = (*elemIt);
1890 //       bool isOK = true;
1891 //       itOnSubFace = aFace->nodesIterator();
1892 //       aet.clear();
1893 //       for ( int j = 0; j < 2; ++j ) {
1894 //         node = castToNode( itOnSubFace->next() );
1895 //         if (( n2nDegenIt = n2nDegen.find( node )) != n2nDegen.end() )
1896 //           node = n2nDegenIt->second;
1897 //         double x = node->X();
1898 //         double y = node->Y();
1899 //         double z = node->Z();
1900 //         // Test if point is inside shape to mesh
1901 //         gp_Pnt myPoint(x,y,z);
1902 //         BRepClass3d_SolidClassifier scl(theMeshDS->ShapeToMesh());
1903 //         scl.Perform(myPoint, 1e-7);
1904 //         TopAbs_State result = scl.State();
1905 //         if ( result != TopAbs_IN ) {
1906 //           isOK = false;
1907 //           theEnforcedEdges.erase(elemIt);
1908 //           continue;
1909 //         }
1910 //         std::vector<double> coords;
1911 //         coords.push_back(x);
1912 //         coords.push_back(y);
1913 //         coords.push_back(z);
1914 //         if (VerMap.find(coords) != VerMap.end()) {
1915 //           aet.push_back(theNodeId2NodeIndexMap[node->GetID()]);
1916 //           continue;
1917 //         }
1918 //         VerTab.push_back(coords);
1919 //         VerMap.insert(coords);
1920 //         
1921 //         aHybridID++;
1922 //         theNodeId2NodeIndexMap.insert( make_pair( node->GetID(), aHybridID ));
1923 //         aet.push_back(aHybridID);
1924 //       }
1925 //       if (isOK)
1926 //         et.push_back(aet);
1927 //     }
1928 //   }
1929 // 
1930 // 
1931 //   /* Write vertices number */
1932 //   MESSAGE("Number of vertices: "<<aHybridID);
1933 //   MESSAGE("Size of vector: "<<VerTab.size());
1934 //   GmfSetKwd(idx, GmfVertices, aHybridID/*+solSize*/);
1935 //   for (int i=0;i<aHybridID;i++)
1936 //     GmfSetLin(idx, GmfVertices, VerTab[i][0], VerTab[i][1], VerTab[i][2], dummyint);
1937 // //   for (int i=0;i<solSize;i++) {
1938 // //     std::cout << ReqVerTab[i][0] <<" "<< ReqVerTab[i][1] << " "<< ReqVerTab[i][2] << std::endl;
1939 // //     GmfSetLin(idx, GmfVertices, ReqVerTab[i][0], ReqVerTab[i][1], ReqVerTab[i][2], dummyint);
1940 // //   }
1941 // 
1942 //   if (solSize) {
1943 //     idxRequired = GmfOpenMesh(theRequiredFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1944 //     if (!idxRequired) {
1945 //       GmfCloseMesh(idx);
1946 //       return false;
1947 //     }
1948 //     idxSol = GmfOpenMesh(theSolFileName, GmfWrite, GMFVERSION, GMFDIMENSION);
1949 //     if (!idxSol){
1950 //       GmfCloseMesh(idx);
1951 //       if (idxRequired)
1952 //         GmfCloseMesh(idxRequired);
1953 //       return false;
1954 //     }
1955 //     
1956 //     int TypTab[] = {GmfSca};
1957 //     GmfSetKwd(idxRequired, GmfVertices, solSize);
1958 //     GmfSetKwd(idxSol, GmfSolAtVertices, solSize, 1, TypTab);
1959 //     
1960 //     for (int i=0;i<solSize;i++) {
1961 //       double solTab[] = {enfVertexSizes.at(i)};
1962 //       GmfSetLin(idxRequired, GmfVertices, ReqVerTab[i][0], ReqVerTab[i][1], ReqVerTab[i][2], dummyint);
1963 //       GmfSetLin(idxSol, GmfSolAtVertices, solTab);
1964 //     }
1965 //     GmfCloseMesh(idxRequired);
1966 //     GmfCloseMesh(idxSol);
1967 //   }
1968 //   
1969 //   /* Write triangles number */
1970 //   if (tt.size()) {
1971 //     GmfSetKwd(idx, GmfTriangles, tt.size());
1972 //     for (int i=0;i<tt.size();i++)
1973 //       GmfSetLin(idx, GmfTriangles, tt[i][0], tt[i][1], tt[i][2], dummyint);
1974 //   }  
1975 //   
1976 //   /* Write edges number */
1977 //   if (et.size()) {
1978 //     GmfSetKwd(idx, GmfEdges, et.size());
1979 //     for (int i=0;i<et.size();i++)
1980 //       GmfSetLin(idx, GmfEdges, et[i][0], et[i][1], dummyint);
1981 //   }
1982 // 
1983 //   /* QUADRANGLES ========================== */
1984 //   // TODO: add pyramids ?
1985 // //   if (nbQuadrangles) {
1986 // //     for ( int i = 1; i <= quadranglesMap.Extent(); i++ )
1987 // //     {
1988 // //       aShape = quadranglesMap(i);
1989 // //       theSubMesh = theProxyMesh.GetSubMesh(aShape);
1990 // //       if ( !theSubMesh ) continue;
1991 // //       itOnSubMesh = theSubMesh->GetElements();
1992 // //       for ( int j = 0; j < 4; ++j )
1993 // //       {
1994 // //         aFace = itOnSubMesh->next();
1995 // //         itOnSubFace = aFace->nodesIterator();
1996 // //         aqt.clear();
1997 // //         while ( itOnSubFace->more() ) {
1998 // //           // find HYBRID ID
1999 // //           aSmdsID = itOnSubFace->next()->GetID();
2000 // //           itOnMap = theSmdsToHybridIdMap.find( aSmdsID );
2001 // //           ASSERT( itOnMap != theSmdsToHybridIdMap.end() );
2002 // //           aqt.push_back((*itOnMap).second);
2003 // //         }
2004 // //         qt.push_back(aqt);
2005 // //       }
2006 // //     }
2007 // //   }
2008 // // 
2009 // //   if (theEnforcedQuadrangles.size()) {
2010 // //     // Iterate over the enforced triangles
2011 // //     for(elemIt = theEnforcedQuadrangles.begin() ; elemIt != theEnforcedQuadrangles.end() ; ++elemIt) {
2012 // //       aFace = (*elemIt);
2013 // //       bool isOK = true;
2014 // //       itOnSubFace = aFace->nodesIterator();
2015 // //       aqt.clear();
2016 // //       for ( int j = 0; j < 4; ++j ) {
2017 // //         int aNodeID = itOnSubFace->next()->GetID();
2018 // //         itOnMap = theNodeId2NodeIndexMap.find(aNodeID);
2019 // //         if (itOnMap != theNodeId2NodeIndexMap.end())
2020 // //           aqt.push_back((*itOnMap).second);
2021 // //         else {
2022 // //           isOK = false;
2023 // //           theEnforcedQuadrangles.erase(elemIt);
2024 // //           break;
2025 // //         }
2026 // //       }
2027 // //       if (isOK)
2028 // //         qt.push_back(aqt);
2029 // //     }
2030 // //   }
2031 // //  
2032 //   
2033 // //   /* Write quadrilaterals number */
2034 // //   if (qt.size()) {
2035 // //     GmfSetKwd(idx, GmfQuadrilaterals, qt.size());
2036 // //     for (int i=0;i<qt.size();i++)
2037 // //       GmfSetLin(idx, GmfQuadrilaterals, qt[i][0], qt[i][1], qt[i][2], qt[i][3], dummyint);
2038 // //   }
2039 // 
2040 //   GmfCloseMesh(idx);
2041 //   return true;
2042 // }
2043
2044
2045 //=======================================================================
2046 //function : writeFaces
2047 //purpose  : 
2048 //=======================================================================
2049
2050 static bool writeFaces (ofstream &              theFile,
2051                         const SMESH_ProxyMesh&  theMesh,
2052                         const TopoDS_Shape&     theShape,
2053                         const map <int,int> &   theSmdsToHybridIdMap,
2054                         const map <int,int> &   theEnforcedNodeIdToHybridIdMap,
2055                         HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedEdges,
2056                         HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedTriangles)
2057 {
2058   // record structure:
2059   //
2060   // NB_ELEMS DUMMY_INT
2061   // Loop from 1 to NB_ELEMS
2062   // NB_NODES NODE_NB_1 NODE_NB_2 ... (NB_NODES + 1) times: DUMMY_INT
2063
2064   TopoDS_Shape aShape;
2065   const SMESHDS_SubMesh* theSubMesh;
2066   const SMDS_MeshElement* aFace;
2067   const char* space    = "  ";
2068   const int   dummyint = 0;
2069   map<int,int>::const_iterator itOnMap;
2070   SMDS_ElemIteratorPtr itOnSubMesh, itOnSubFace;
2071   int nbNodes, aSmdsID;
2072
2073   TIDSortedElemSet::const_iterator elemIt;
2074   int nbEnforcedEdges       = theEnforcedEdges.size();
2075   int nbEnforcedTriangles   = theEnforcedTriangles.size();
2076
2077   // count triangles bound to geometry
2078   int nbTriangles = 0;
2079
2080   TopTools_IndexedMapOfShape facesMap, trianglesMap;
2081   TopExp::MapShapes( theShape, TopAbs_FACE, facesMap );
2082   
2083   int nbFaces = facesMap.Extent();
2084
2085   for ( int i = 1; i <= nbFaces; ++i )
2086     if (( theSubMesh  = theMesh.GetSubMesh( facesMap(i))))
2087       nbTriangles += theSubMesh->NbElements();
2088   std::string tmpStr;
2089   (nbFaces == 0 || nbFaces == 1) ? tmpStr = " shape " : tmpStr = " shapes " ;
2090   std::cout << "    " << nbFaces << tmpStr << "of 2D dimension";
2091   int nbEnforcedElements = nbEnforcedEdges+nbEnforcedTriangles;
2092   if (nbEnforcedElements > 0) {
2093     (nbEnforcedElements == 1) ? tmpStr = "shape:" : tmpStr = "shapes:";
2094     std::cout << " and" << std::endl;
2095     std::cout << "    " << nbEnforcedElements 
2096                         << " enforced " << tmpStr << std::endl;
2097   }
2098   else
2099     std::cout << std::endl;
2100   if (nbEnforcedEdges) {
2101     (nbEnforcedEdges == 1) ? tmpStr = "edge" : tmpStr = "edges";
2102     std::cout << "      " << nbEnforcedEdges << " enforced " << tmpStr << std::endl;
2103   }
2104   if (nbEnforcedTriangles) {
2105     (nbEnforcedTriangles == 1) ? tmpStr = "triangle" : tmpStr = "triangles";
2106     std::cout << "      " << nbEnforcedTriangles << " enforced " << tmpStr << std::endl;
2107   }
2108   std::cout << std::endl;
2109
2110 //   theFile << space << nbTriangles << space << dummyint << std::endl;
2111   std::ostringstream globalStream, localStream, aStream;
2112
2113   for ( int i = 1; i <= facesMap.Extent(); i++ )
2114   {
2115     aShape = facesMap(i);
2116     theSubMesh = theMesh.GetSubMesh(aShape);
2117     if ( !theSubMesh ) continue;
2118     itOnSubMesh = theSubMesh->GetElements();
2119     while ( itOnSubMesh->more() )
2120     {
2121       aFace = itOnSubMesh->next();
2122       nbNodes = aFace->NbCornerNodes();
2123
2124       localStream << nbNodes << space;
2125
2126       itOnSubFace = aFace->nodesIterator();
2127       for ( int j = 0; j < 3; ++j ) {
2128         // find HYBRID ID
2129         aSmdsID = itOnSubFace->next()->GetID();
2130         itOnMap = theSmdsToHybridIdMap.find( aSmdsID );
2131         // if ( itOnMap == theSmdsToHybridIdMap.end() ) {
2132         //   cout << "not found node: " << aSmdsID << endl;
2133         //   return false;
2134         // }
2135         ASSERT( itOnMap != theSmdsToHybridIdMap.end() );
2136
2137         localStream << (*itOnMap).second << space ;
2138       }
2139
2140       // (NB_NODES + 1) times: DUMMY_INT
2141       for ( int j=0; j<=nbNodes; j++)
2142         localStream << dummyint << space ;
2143
2144       localStream << std::endl;
2145     }
2146   }
2147   
2148   globalStream << localStream.str();
2149   localStream.str("");
2150
2151   //
2152   //        FACES : END
2153   //
2154
2155 //   //
2156 //   //        ENFORCED EDGES : BEGIN
2157 //   //
2158 //   
2159 //   // Iterate over the enforced edges
2160 //   int usedEnforcedEdges = 0;
2161 //   bool isOK;
2162 //   for(elemIt = theEnforcedEdges.begin() ; elemIt != theEnforcedEdges.end() ; ++elemIt) {
2163 //     aFace = (*elemIt);
2164 //     isOK = true;
2165 //     itOnSubFace = aFace->nodesIterator();
2166 //     aStream.str("");
2167 //     aStream << "2" << space ;
2168 //     for ( int j = 0; j < 2; ++j ) {
2169 //       aSmdsID = itOnSubFace->next()->GetID();
2170 //       itOnMap = theEnforcedNodeIdToHybridIdMap.find(aSmdsID);
2171 //       if (itOnMap != theEnforcedNodeIdToHybridIdMap.end())
2172 //         aStream << (*itOnMap).second << space;
2173 //       else {
2174 //         isOK = false;
2175 //         break;
2176 //       }
2177 //     }
2178 //     if (isOK) {
2179 //       for ( int j=0; j<=2; j++)
2180 //         aStream << dummyint << space ;
2181 // //       aStream << dummyint << space << dummyint;
2182 //       localStream << aStream.str() << std::endl;
2183 //       usedEnforcedEdges++;
2184 //     }
2185 //   }
2186 //   
2187 //   if (usedEnforcedEdges) {
2188 //     globalStream << localStream.str();
2189 //     localStream.str("");
2190 //   }
2191 // 
2192 //   //
2193 //   //        ENFORCED EDGES : END
2194 //   //
2195 //   //
2196 // 
2197 //   //
2198 //   //        ENFORCED TRIANGLES : BEGIN
2199 //   //
2200 //     // Iterate over the enforced triangles
2201 //   int usedEnforcedTriangles = 0;
2202 //   for(elemIt = theEnforcedTriangles.begin() ; elemIt != theEnforcedTriangles.end() ; ++elemIt) {
2203 //     aFace = (*elemIt);
2204 //     nbNodes = aFace->NbCornerNodes();
2205 //     isOK = true;
2206 //     itOnSubFace = aFace->nodesIterator();
2207 //     aStream.str("");
2208 //     aStream << nbNodes << space ;
2209 //     for ( int j = 0; j < 3; ++j ) {
2210 //       aSmdsID = itOnSubFace->next()->GetID();
2211 //       itOnMap = theEnforcedNodeIdToHybridIdMap.find(aSmdsID);
2212 //       if (itOnMap != theEnforcedNodeIdToHybridIdMap.end())
2213 //         aStream << (*itOnMap).second << space;
2214 //       else {
2215 //         isOK = false;
2216 //         break;
2217 //       }
2218 //     }
2219 //     if (isOK) {
2220 //       for ( int j=0; j<=3; j++)
2221 //         aStream << dummyint << space ;
2222 //       localStream << aStream.str() << std::endl;
2223 //       usedEnforcedTriangles++;
2224 //     }
2225 //   }
2226 //   
2227 //   if (usedEnforcedTriangles) {
2228 //     globalStream << localStream.str();
2229 //     localStream.str("");
2230 //   }
2231 // 
2232 //   //
2233 //   //        ENFORCED TRIANGLES : END
2234 //   //
2235   
2236   theFile
2237   << nbTriangles/*+usedEnforcedTriangles+usedEnforcedEdges*/
2238   << " 0" << std::endl
2239   << globalStream.str();
2240
2241   return true;
2242 }
2243
2244 //=======================================================================
2245 //function : writePoints
2246 //purpose  : 
2247 //=======================================================================
2248
2249 static bool writePoints (ofstream &                       theFile,
2250                          SMESH_MesherHelper&              theHelper,
2251                          map <int,int> &                  theSmdsToHybridIdMap,
2252                          map <int,int> &                  theEnforcedNodeIdToHybridIdMap,
2253                          map <int,const SMDS_MeshNode*> & theHybridIdToNodeMap,
2254                          HYBRIDPlugin_Hypothesis::TID2SizeMap & theNodeIDToSizeMap,
2255                          HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues & theEnforcedVertices,
2256                          HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap & theEnforcedNodes,
2257                          HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedEdges,
2258                          HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedTriangles)
2259 {
2260   // record structure:
2261   //
2262   // NB_NODES
2263   // Loop from 1 to NB_NODES
2264   //   X Y Z DUMMY_INT
2265
2266   SMESHDS_Mesh * theMeshDS = theHelper.GetMeshDS();
2267   int nbNodes = theMeshDS->NbNodes();
2268   if ( nbNodes == 0 )
2269     return false;
2270   
2271   int nbEnforcedVertices = theEnforcedVertices.size();
2272   int nbEnforcedNodes    = theEnforcedNodes.size();
2273   
2274   const TopoDS_Shape shapeToMesh = theMeshDS->ShapeToMesh();
2275   
2276   int aHybridID = 1;
2277   SMDS_NodeIteratorPtr nodeIt = theMeshDS->nodesIterator();
2278   const SMDS_MeshNode* node;
2279
2280   // Issue 020674: EDF 870 SMESH: Mesh generated by Netgen not usable by HYBRID
2281   // The problem is in nodes on degenerated edges, we need to skip nodes which are free
2282   // and replace not-free nodes on degenerated edges by the node on vertex
2283   TNodeNodeMap n2nDegen; // map a node on degenerated edge to a node on vertex
2284   TNodeNodeMap::iterator n2nDegenIt;
2285   if ( theHelper.HasDegeneratedEdges() )
2286   {
2287     set<int> checkedSM;
2288     for (TopExp_Explorer e(theMeshDS->ShapeToMesh(), TopAbs_EDGE ); e.More(); e.Next())
2289     {
2290       SMESH_subMesh* sm = theHelper.GetMesh()->GetSubMesh( e.Current() );
2291       if ( checkedSM.insert( sm->GetId() ).second && theHelper.IsDegenShape(sm->GetId() ))
2292       {
2293         if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() )
2294         {
2295           TopoDS_Shape vertex = TopoDS_Iterator( e.Current() ).Value();
2296           const SMDS_MeshNode* vNode = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), theMeshDS);
2297           {
2298             SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
2299             while ( nIt->more() )
2300               n2nDegen.insert( make_pair( nIt->next(), vNode ));
2301           }
2302         }
2303       }
2304     }
2305     nbNodes -= n2nDegen.size();
2306   }
2307
2308   const bool isQuadMesh = 
2309     theHelper.GetMesh()->NbEdges( ORDER_QUADRATIC ) ||
2310     theHelper.GetMesh()->NbFaces( ORDER_QUADRATIC ) ||
2311     theHelper.GetMesh()->NbVolumes( ORDER_QUADRATIC );
2312   if ( isQuadMesh )
2313   {
2314     // descrease nbNodes by nb of medium nodes
2315     while ( nodeIt->more() )
2316     {
2317       node = nodeIt->next();
2318       if ( !theHelper.IsDegenShape( node->getshapeId() ))
2319         nbNodes -= int( theHelper.IsMedium( node ));
2320     }
2321     nodeIt = theMeshDS->nodesIterator();
2322   }
2323
2324   const char* space    = "  ";
2325   const int   dummyint = 0;
2326
2327   std::string tmpStr;
2328   (nbNodes == 0 || nbNodes == 1) ? tmpStr = " node" : tmpStr = " nodes";
2329   // NB_NODES
2330   std::cout << std::endl;
2331   std::cout << "The initial 2D mesh contains :" << std::endl;
2332   std::cout << "    " << nbNodes << tmpStr << std::endl;
2333   if (nbEnforcedVertices > 0) {
2334     (nbEnforcedVertices == 1) ? tmpStr = "vertex" : tmpStr = "vertices";
2335     std::cout << "    " << nbEnforcedVertices << " enforced " << tmpStr << std::endl;
2336   }
2337   if (nbEnforcedNodes > 0) {
2338     (nbEnforcedNodes == 1) ? tmpStr = "node" : tmpStr = "nodes";
2339     std::cout << "    " << nbEnforcedNodes << " enforced " << tmpStr << std::endl;
2340   }
2341   std::cout << std::endl;
2342   std::cout << "Start writing in 'points' file ..." << std::endl;
2343
2344   theFile << nbNodes << std::endl;
2345
2346   // Loop from 1 to NB_NODES
2347
2348   while ( nodeIt->more() )
2349   {
2350     node = nodeIt->next();
2351     if ( isQuadMesh && theHelper.IsMedium( node )) // Issue 0021238
2352       continue;
2353     if ( n2nDegen.count( node ) ) // Issue 0020674
2354       continue;
2355
2356     theSmdsToHybridIdMap.insert( make_pair( node->GetID(), aHybridID ));
2357     theHybridIdToNodeMap.insert( make_pair( aHybridID, node ));
2358     aHybridID++;
2359
2360     // X Y Z DUMMY_INT
2361     theFile
2362     << node->X() << space 
2363     << node->Y() << space 
2364     << node->Z() << space 
2365     << dummyint;
2366
2367     theFile << std::endl;
2368
2369   }
2370   
2371   // Iterate over the enforced nodes
2372   std::map<int,double> enfVertexIndexSizeMap;
2373   if (nbEnforcedNodes) {
2374     HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap::const_iterator nodeIt = theEnforcedNodes.begin();
2375     for( ; nodeIt != theEnforcedNodes.end() ; ++nodeIt) {
2376       double x = nodeIt->first->X();
2377       double y = nodeIt->first->Y();
2378       double z = nodeIt->first->Z();
2379       // Test if point is inside shape to mesh
2380       gp_Pnt myPoint(x,y,z);
2381       BRepClass3d_SolidClassifier scl(shapeToMesh);
2382       scl.Perform(myPoint, 1e-7);
2383       TopAbs_State result = scl.State();
2384       if ( result != TopAbs_IN )
2385         continue;
2386       std::vector<double> coords;
2387       coords.push_back(x);
2388       coords.push_back(y);
2389       coords.push_back(z);
2390       if (theEnforcedVertices.find(coords) != theEnforcedVertices.end())
2391         continue;
2392         
2393 //      double size = theNodeIDToSizeMap.find(nodeIt->first->GetID())->second;
2394   //       theHybridIdToNodeMap.insert( make_pair( nbNodes + i, (*nodeIt) ));
2395   //       MESSAGE("Adding enforced node (" << x << "," << y <<"," << z << ")");
2396       // X Y Z PHY_SIZE DUMMY_INT
2397       theFile
2398       << x << space 
2399       << y << space 
2400       << z << space
2401       << -1 << space
2402       << dummyint << space;
2403       theFile << std::endl;
2404       theEnforcedNodeIdToHybridIdMap.insert( make_pair( nodeIt->first->GetID(), aHybridID ));
2405       enfVertexIndexSizeMap[aHybridID] = -1;
2406       aHybridID++;
2407   //     else
2408   //         MESSAGE("Enforced vertex (" << x << "," << y <<"," << z << ") is not inside the geometry: it was not added ");
2409     }
2410   }
2411   
2412   if (nbEnforcedVertices) {
2413     // Iterate over the enforced vertices
2414     HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues::const_iterator vertexIt = theEnforcedVertices.begin();
2415     for( ; vertexIt != theEnforcedVertices.end() ; ++vertexIt) {
2416       double x = vertexIt->first[0];
2417       double y = vertexIt->first[1];
2418       double z = vertexIt->first[2];
2419       // Test if point is inside shape to mesh
2420       gp_Pnt myPoint(x,y,z);
2421       BRepClass3d_SolidClassifier scl(shapeToMesh);
2422       scl.Perform(myPoint, 1e-7);
2423       TopAbs_State result = scl.State();
2424       if ( result != TopAbs_IN )
2425         continue;
2426       MESSAGE("Adding enforced vertex (" << x << "," << y <<"," << z << ") = " << vertexIt->second);
2427       // X Y Z PHY_SIZE DUMMY_INT
2428       theFile
2429       << x << space 
2430       << y << space 
2431       << z << space
2432       << vertexIt->second << space 
2433       << dummyint << space;
2434       theFile << std::endl;
2435       enfVertexIndexSizeMap[aHybridID] = vertexIt->second;
2436       aHybridID++;
2437     }
2438   }
2439   
2440   
2441   std::cout << std::endl;
2442   std::cout << "End writing in 'points' file." << std::endl;
2443
2444   return true;
2445 }
2446
2447 //=======================================================================
2448 //function : readResultFile
2449 //purpose  : readResultFile with geometry
2450 //=======================================================================
2451
2452 static bool readResultFile(const int                       fileOpen,
2453 #ifdef WIN32
2454                            const char*                     fileName,
2455 #endif
2456                            HYBRIDPlugin_HYBRID*            theAlgo,
2457                            SMESH_MesherHelper&             theHelper,
2458                            TopoDS_Shape                    tabShape[],
2459                            double**                        tabBox,
2460                            const int                       nbShape,
2461                            map <int,const SMDS_MeshNode*>& theHybridIdToNodeMap,
2462                            std::map <int,int> &            theNodeId2NodeIndexMap,
2463                            bool                            toMeshHoles,
2464                            int                             nbEnforcedVertices,
2465                            int                             nbEnforcedNodes,
2466                            HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedEdges,
2467                            HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap & theEnforcedTriangles,
2468                            bool                            toMakeGroupsOfDomains)
2469 {
2470   MESSAGE("HYBRIDPlugin_HYBRID::readResultFile()");
2471   Kernel_Utils::Localizer loc;
2472   struct stat status;
2473   size_t      length;
2474   
2475   std::string tmpStr;
2476
2477   char *ptr, *mapPtr;
2478   char *tetraPtr;
2479   char *shapePtr;
2480
2481   SMESHDS_Mesh* theMeshDS = theHelper.GetMeshDS();
2482
2483   int nbElems, nbNodes, nbInputNodes;
2484   int nbTriangle;
2485   int ID, shapeID, hybridShapeID;
2486   int IdShapeRef = 1;
2487   int compoundID =
2488     nbShape ? theMeshDS->ShapeToIndex( tabShape[0] ) : theMeshDS->ShapeToIndex( theMeshDS->ShapeToMesh() );
2489
2490   int *tab, *tabID, *nodeID, *nodeAssigne;
2491   double *coord;
2492   const SMDS_MeshNode **node;
2493
2494   tab    = new int[3];
2495   nodeID = new int[4];
2496   coord  = new double[3];
2497   node   = new const SMDS_MeshNode*[4];
2498
2499   TopoDS_Shape aSolid;
2500   SMDS_MeshNode * aNewNode;
2501   map <int,const SMDS_MeshNode*>::iterator itOnNode;
2502   SMDS_MeshElement* aTet;
2503 #ifdef _DEBUG_
2504   set<int> shapeIDs;
2505 #endif
2506
2507   // Read the file state
2508   fstat(fileOpen, &status);
2509   length   = status.st_size;
2510
2511   // Mapping the result file into memory
2512 #ifdef WIN32
2513   HANDLE fd = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ,
2514                          NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
2515   HANDLE hMapObject = CreateFileMapping(fd, NULL, PAGE_READONLY,
2516                                         0, (DWORD)length, NULL);
2517   ptr = ( char* ) MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0 );
2518 #else
2519   ptr = (char *) mmap(0,length,PROT_READ,MAP_PRIVATE,fileOpen,0);
2520 #endif
2521   mapPtr = ptr;
2522
2523   ptr      = readMapIntLine(ptr, tab);
2524   tetraPtr = ptr;
2525
2526   nbElems      = tab[0];
2527   nbNodes      = tab[1];
2528   nbInputNodes = tab[2];
2529
2530   nodeAssigne = new int[ nbNodes+1 ];
2531
2532   if (nbShape > 0)
2533     aSolid = tabShape[0];
2534
2535   // Reading the nodeId
2536   for (int i=0; i < 4*nbElems; i++)
2537     strtol(ptr, &ptr, 10);
2538
2539   MESSAGE("nbInputNodes: "<<nbInputNodes);
2540   MESSAGE("nbEnforcedVertices: "<<nbEnforcedVertices);
2541   MESSAGE("nbEnforcedNodes: "<<nbEnforcedNodes);
2542   // Reading the nodeCoor and update the nodeMap
2543   for (int iNode=1; iNode <= nbNodes; iNode++) {
2544     if(theAlgo->computeCanceled())
2545       return false;
2546     for (int iCoor=0; iCoor < 3; iCoor++)
2547       coord[ iCoor ] = strtod(ptr, &ptr);
2548     nodeAssigne[ iNode ] = 1;
2549     if ( iNode > (nbInputNodes-(nbEnforcedVertices+nbEnforcedNodes)) ) {
2550       // Creating SMESH nodes
2551       // - for enforced vertices
2552       // - for vertices of forced edges
2553       // - for hybrid nodes
2554       nodeAssigne[ iNode ] = 0;
2555       aNewNode = theMeshDS->AddNode( coord[0],coord[1],coord[2] );
2556       theHybridIdToNodeMap.insert(theHybridIdToNodeMap.end(), make_pair( iNode, aNewNode ));
2557     }
2558   }
2559
2560   // Reading the number of triangles which corresponds to the number of sub-domains
2561   nbTriangle = strtol(ptr, &ptr, 10);
2562
2563   tabID = new int[nbTriangle];
2564   for (int i=0; i < nbTriangle; i++) {
2565     if(theAlgo->computeCanceled())
2566       return false;
2567     tabID[i] = 0;
2568     // find the solid corresponding to HYBRID sub-domain following
2569     // the technique proposed in HYBRID manual in chapter
2570     // "B.4 Subdomain (sub-region) assignment"
2571     int nodeId1 = strtol(ptr, &ptr, 10);
2572     int nodeId2 = strtol(ptr, &ptr, 10);
2573     int nodeId3 = strtol(ptr, &ptr, 10);
2574     if ( nbTriangle > 1 ) {
2575       const SMDS_MeshNode* n1 = theHybridIdToNodeMap[ nodeId1 ];
2576       const SMDS_MeshNode* n2 = theHybridIdToNodeMap[ nodeId2 ];
2577       const SMDS_MeshNode* n3 = theHybridIdToNodeMap[ nodeId3 ];
2578       if (!n1 || !n2 || !n3) {
2579         tabID[i] = HOLE_ID;
2580         continue;
2581       }
2582       try {
2583         OCC_CATCH_SIGNALS;
2584 //         tabID[i] = findShapeID( theHelper, n1, n2, n3, toMeshHoles );
2585         tabID[i] = findShapeID( *theHelper.GetMesh(), n1, n2, n3, toMeshHoles );
2586         // -- 0020330: Pb with hybrid as a submesh
2587         // check that found shape is to be meshed
2588         if ( tabID[i] > 0 ) {
2589           const TopoDS_Shape& foundShape = theMeshDS->IndexToShape( tabID[i] );
2590           bool isToBeMeshed = false;
2591           for ( int iS = 0; !isToBeMeshed && iS < nbShape; ++iS )
2592             isToBeMeshed = foundShape.IsSame( tabShape[ iS ]);
2593           if ( !isToBeMeshed )
2594             tabID[i] = HOLE_ID;
2595         }
2596         // END -- 0020330: Pb with hybrid as a submesh
2597 #ifdef _DEBUG_
2598         std::cout << i+1 << " subdomain: findShapeID() returns " << tabID[i] << std::endl;
2599 #endif
2600       }
2601       catch ( Standard_Failure & ex)
2602       {
2603 #ifdef _DEBUG_
2604         std::cout << i+1 << " subdomain: Exception caugt: " << ex.GetMessageString() << std::endl;
2605 #endif
2606       }
2607       catch (...) {
2608 #ifdef _DEBUG_
2609         std::cout << i+1 << " subdomain: unknown exception caught " << std::endl;
2610 #endif
2611       }
2612     }
2613   }
2614
2615   shapePtr = ptr;
2616
2617   if ( nbTriangle <= nbShape ) // no holes
2618     toMeshHoles = true; // not avoid creating tetras in holes
2619
2620   // IMP 0022172: [CEA 790] create the groups corresponding to domains
2621   std::vector< std::vector< const SMDS_MeshElement* > > elemsOfDomain( Max( nbTriangle, nbShape ));
2622
2623   // Associating the tetrahedrons to the shapes
2624   shapeID = compoundID;
2625   for (int iElem = 0; iElem < nbElems; iElem++) {
2626     if(theAlgo->computeCanceled())
2627       return false;
2628     for (int iNode = 0; iNode < 4; iNode++) {
2629       ID = strtol(tetraPtr, &tetraPtr, 10);
2630       itOnNode = theHybridIdToNodeMap.find(ID);
2631       node[ iNode ] = itOnNode->second;
2632       nodeID[ iNode ] = ID;
2633     }
2634     // We always run HYBRID with "to mesh holes"==TRUE but we must not create
2635     // tetras within holes depending on hypo option,
2636     // so we first check if aTet is inside a hole and then create it 
2637     //aTet = theMeshDS->AddVolume( node[1], node[0], node[2], node[3] );
2638     hybridShapeID = 0; // domain ID
2639     if ( nbTriangle > 1 ) {
2640       shapeID = HOLE_ID; // negative shapeID means not to create tetras if !toMeshHoles
2641       hybridShapeID = strtol(shapePtr, &shapePtr, 10) - IdShapeRef;
2642       if ( tabID[ hybridShapeID ] == 0 ) {
2643         TopAbs_State state;
2644         aSolid = findShape(node, aSolid, tabShape, tabBox, nbShape, &state);
2645         if ( toMeshHoles || state == TopAbs_IN )
2646           shapeID = theMeshDS->ShapeToIndex( aSolid );
2647         tabID[ hybridShapeID ] = shapeID;
2648       }
2649       else
2650         shapeID = tabID[ hybridShapeID ];
2651     }
2652     else if ( nbShape > 1 ) {
2653       // Case where nbTriangle == 1 while nbShape == 2 encountered
2654       // with compound of 2 boxes and "To mesh holes"==False,
2655       // so there are no subdomains specified for each tetrahedron.
2656       // Try to guess a solid by a node already bound to shape
2657       shapeID = 0;
2658       for ( int i=0; i<4 && shapeID==0; i++ ) {
2659         if ( nodeAssigne[ nodeID[i] ] == 1 &&
2660              node[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE &&
2661              node[i]->getshapeId() > 1 )
2662         {
2663           shapeID = node[i]->getshapeId();
2664         }
2665       }
2666       if ( shapeID==0 ) {
2667         aSolid = findShape(node, aSolid, tabShape, tabBox, nbShape);
2668         shapeID = theMeshDS->ShapeToIndex( aSolid );
2669       }
2670     }
2671     // set new nodes and tetrahedron onto the shape
2672     for ( int i=0; i<4; i++ ) {
2673       if ( nodeAssigne[ nodeID[i] ] == 0 ) {
2674         if ( shapeID != HOLE_ID )
2675           theMeshDS->SetNodeInVolume( node[i], shapeID );
2676         nodeAssigne[ nodeID[i] ] = shapeID;
2677       }
2678     }
2679     if ( toMeshHoles || shapeID != HOLE_ID ) {
2680       aTet = theHelper.AddVolume( node[1], node[0], node[2], node[3],
2681                                   /*id=*/0, /*force3d=*/false);
2682       theMeshDS->SetMeshElementOnShape( aTet, shapeID );
2683       if ( toMakeGroupsOfDomains )
2684       {
2685         if ( int( elemsOfDomain.size() ) < hybridShapeID+1 )
2686           elemsOfDomain.resize( hybridShapeID+1 );
2687         elemsOfDomain[ hybridShapeID ].push_back( aTet );
2688       }
2689     }
2690 #ifdef _DEBUG_
2691     shapeIDs.insert( shapeID );
2692 #endif
2693   }
2694   if ( toMakeGroupsOfDomains )
2695     makeDomainGroups( elemsOfDomain, &theHelper );
2696   
2697   // Add enforced elements
2698   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap::const_iterator elemIt;
2699   const SMDS_MeshElement* anElem;
2700   SMDS_ElemIteratorPtr itOnEnfElem;
2701   map<int,int>::const_iterator itOnMap;
2702   shapeID = compoundID;
2703   // Enforced edges
2704   if (theEnforcedEdges.size()) {
2705     (theEnforcedEdges.size() <= 1) ? tmpStr = " enforced edge" : " enforced edges";
2706     std::cout << "Add " << theEnforcedEdges.size() << tmpStr << std::endl;
2707     std::vector< const SMDS_MeshNode* > node( 2 );
2708     // Iterate over the enforced edges
2709     for(elemIt = theEnforcedEdges.begin() ; elemIt != theEnforcedEdges.end() ; ++elemIt) {
2710       anElem = elemIt->first;
2711       bool addElem = true;
2712       itOnEnfElem = anElem->nodesIterator();
2713       for ( int j = 0; j < 2; ++j ) {
2714         int aNodeID = itOnEnfElem->next()->GetID();
2715         itOnMap = theNodeId2NodeIndexMap.find(aNodeID);
2716         if (itOnMap != theNodeId2NodeIndexMap.end()) {
2717           itOnNode = theHybridIdToNodeMap.find((*itOnMap).second);
2718           if (itOnNode != theHybridIdToNodeMap.end()) {
2719             node.push_back((*itOnNode).second);
2720 //             shapeID =(*itOnNode).second->getshapeId();
2721           }
2722           else
2723             addElem = false;
2724         }
2725         else
2726           addElem = false;
2727       }
2728       if (addElem) {
2729         aTet = theHelper.AddEdge( node[0], node[1], 0,  false);
2730         theMeshDS->SetMeshElementOnShape( aTet, shapeID );
2731       }
2732     }
2733   }
2734   // Enforced faces
2735   if (theEnforcedTriangles.size()) {
2736     (theEnforcedTriangles.size() <= 1) ? tmpStr = " enforced triangle" : " enforced triangles";
2737     std::cout << "Add " << theEnforcedTriangles.size() << " enforced triangles" << std::endl;
2738     std::vector< const SMDS_MeshNode* > node( 3 );
2739     // Iterate over the enforced triangles
2740     for(elemIt = theEnforcedTriangles.begin() ; elemIt != theEnforcedTriangles.end() ; ++elemIt) {
2741       anElem = elemIt->first;
2742       bool addElem = true;
2743       itOnEnfElem = anElem->nodesIterator();
2744       for ( int j = 0; j < 3; ++j ) {
2745         int aNodeID = itOnEnfElem->next()->GetID();
2746         itOnMap = theNodeId2NodeIndexMap.find(aNodeID);
2747         if (itOnMap != theNodeId2NodeIndexMap.end()) {
2748           itOnNode = theHybridIdToNodeMap.find((*itOnMap).second);
2749           if (itOnNode != theHybridIdToNodeMap.end()) {
2750             node.push_back((*itOnNode).second);
2751 //             shapeID =(*itOnNode).second->getshapeId();
2752           }
2753           else
2754             addElem = false;
2755         }
2756         else
2757           addElem = false;
2758       }
2759       if (addElem) {
2760         aTet = theHelper.AddFace( node[0], node[1], node[2], 0,  false);
2761         theMeshDS->SetMeshElementOnShape( aTet, shapeID );
2762       }
2763     }
2764   }
2765
2766   // Remove nodes of tetras inside holes if !toMeshHoles
2767   if ( !toMeshHoles ) {
2768     itOnNode = theHybridIdToNodeMap.find( nbInputNodes );
2769     for ( ; itOnNode != theHybridIdToNodeMap.end(); ++itOnNode) {
2770       ID = itOnNode->first;
2771       if ( nodeAssigne[ ID ] == HOLE_ID )
2772         theMeshDS->RemoveFreeNode( itOnNode->second, 0 );
2773     }
2774   }
2775
2776   
2777   if ( nbElems ) {
2778     (nbElems <= 1) ? tmpStr = " tetrahedra" : " tetrahedrons";
2779     cout << nbElems << tmpStr << " have been associated to " << nbShape;
2780     (nbShape <= 1) ? tmpStr = " shape" : " shapes";
2781     cout << tmpStr << endl;
2782   }
2783 #ifdef WIN32
2784   UnmapViewOfFile(mapPtr);
2785   CloseHandle(hMapObject);
2786   CloseHandle(fd);
2787 #else
2788   munmap(mapPtr, length);
2789 #endif
2790   close(fileOpen);
2791
2792   delete [] tab;
2793   delete [] tabID;
2794   delete [] nodeID;
2795   delete [] coord;
2796   delete [] node;
2797   delete [] nodeAssigne;
2798
2799 #ifdef _DEBUG_
2800   shapeIDs.erase(-1);
2801   if ( shapeIDs.size() != nbShape ) {
2802     (shapeIDs.size() <= 1) ? tmpStr = " solid" : " solids";
2803     std::cout << "Only " << shapeIDs.size() << tmpStr << " of " << nbShape << " found" << std::endl;
2804     for (int i=0; i<nbShape; i++) {
2805       shapeID = theMeshDS->ShapeToIndex( tabShape[i] );
2806       if ( shapeIDs.find( shapeID ) == shapeIDs.end() )
2807         std::cout << "  Solid #" << shapeID << " not found" << std::endl;
2808     }
2809   }
2810 #endif
2811
2812   return true;
2813 }
2814
2815
2816 //=============================================================================
2817 /*!
2818  *Here we are going to use the HYBRID mesher with geometry
2819  */
2820 //=============================================================================
2821
2822 bool HYBRIDPlugin_HYBRID::Compute(SMESH_Mesh&         theMesh,
2823                                   const TopoDS_Shape& theShape)
2824 {
2825   bool Ok(false);
2826   //SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
2827
2828   // we count the number of shapes
2829   // _nbShape = countShape( meshDS, TopAbs_SOLID ); -- 0020330: Pb with hybrid as a submesh
2830   // _nbShape = 0;
2831   TopExp_Explorer expBox ( theShape, TopAbs_SOLID );
2832   // for ( ; expBox.More(); expBox.Next() )
2833   //   _nbShape++;
2834
2835   // create bounding box for every shape inside the compound
2836
2837   // int iShape = 0;
2838   // TopoDS_Shape* tabShape;
2839   // double**      tabBox;
2840   // tabShape = new TopoDS_Shape[_nbShape];
2841   // tabBox   = new double*[_nbShape];
2842   // for (int i=0; i<_nbShape; i++)
2843   //   tabBox[i] = new double[6];
2844   // Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2845
2846   // for (expBox.ReInit(); expBox.More(); expBox.Next()) {
2847   //   tabShape[iShape] = expBox.Current();
2848   //   Bnd_Box BoundingBox;
2849   //   BRepBndLib::Add(expBox.Current(), BoundingBox);
2850   //   BoundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2851   //   tabBox[iShape][0] = Xmin; tabBox[iShape][1] = Xmax;
2852   //   tabBox[iShape][2] = Ymin; tabBox[iShape][3] = Ymax;
2853   //   tabBox[iShape][4] = Zmin; tabBox[iShape][5] = Zmax;
2854   //   iShape++;
2855   // }
2856
2857   // a unique working file name
2858   // to avoid access to the same files by eg different users
2859   _genericName = HYBRIDPlugin_Hypothesis::GetFileName(_hyp);
2860   TCollection_AsciiString aGenericName((char*) _genericName.c_str() );
2861   TCollection_AsciiString aGenericNameRequired = aGenericName + "_required";
2862
2863   TCollection_AsciiString aLogFileName    = aGenericName + ".log";    // log
2864   TCollection_AsciiString aResultFileName;
2865
2866   TCollection_AsciiString aGMFFileName, aRequiredVerticesFileName, aSolFileName, aResSolFileName;
2867 //#ifdef _DEBUG_
2868   aGMFFileName              = aGenericName + ".mesh"; // GMF mesh file
2869   aResultFileName           = aGenericName + "Vol.mesh"; // GMF mesh file
2870   aResSolFileName           = aGenericName + "Vol.sol"; // GMF mesh file
2871   aRequiredVerticesFileName = aGenericNameRequired + ".mesh"; // GMF required vertices mesh file
2872   aSolFileName              = aGenericNameRequired + ".sol"; // GMF solution file
2873 //#else
2874 //  aGMFFileName    = aGenericName + ".meshb"; // GMF mesh file
2875 //  aResultFileName = aGenericName + "Vol.meshb"; // GMF mesh file
2876 //  aRequiredVerticesFileName    = aGenericNameRequired + ".meshb"; // GMF required vertices mesh file
2877 //  aSolFileName    = aGenericNameRequired + ".solb"; // GMF solution file
2878 //#endif
2879   
2880   std::map <int,int> aNodeId2NodeIndexMap, aSmdsToHybridIdMap, anEnforcedNodeIdToHybridIdMap;
2881   //std::map <int,const SMDS_MeshNode*> aHybridIdToNodeMap;
2882   std::map <int, int> nodeID2nodeIndexMap;
2883   std::map<std::vector<double>, std::string> enfVerticesWithGroup;
2884   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues coordsSizeMap = HYBRIDPlugin_Hypothesis::GetEnforcedVerticesCoordsSize(_hyp);
2885   HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap enforcedNodes = HYBRIDPlugin_Hypothesis::GetEnforcedNodes(_hyp);
2886   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap enforcedEdges = HYBRIDPlugin_Hypothesis::GetEnforcedEdges(_hyp);
2887   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap enforcedTriangles = HYBRIDPlugin_Hypothesis::GetEnforcedTriangles(_hyp);
2888 //   TIDSortedElemSet enforcedQuadrangles = HYBRIDPlugin_Hypothesis::GetEnforcedQuadrangles(_hyp);
2889   HYBRIDPlugin_Hypothesis::TID2SizeMap nodeIDToSizeMap = HYBRIDPlugin_Hypothesis::GetNodeIDToSizeMap(_hyp);
2890
2891   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexList enfVertices = HYBRIDPlugin_Hypothesis::GetEnforcedVertices(_hyp);
2892   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexList::const_iterator enfVerIt = enfVertices.begin();
2893   std::vector<double> coords;
2894
2895   for ( ; enfVerIt != enfVertices.end() ; ++enfVerIt)
2896   {
2897     HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertex* enfVertex = (*enfVerIt);
2898 //     if (enfVertex->geomEntry.empty() && enfVertex->coords.size()) {
2899     if (enfVertex->coords.size()) {
2900       coordsSizeMap.insert(make_pair(enfVertex->coords,enfVertex->size));
2901       enfVerticesWithGroup.insert(make_pair(enfVertex->coords,enfVertex->groupName));
2902 //       MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<enfVertex->coords[0]<<","<<enfVertex->coords[1]<<","<<enfVertex->coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
2903     }
2904     else {
2905 //     if (!enfVertex->geomEntry.empty()) {
2906       TopoDS_Shape GeomShape = entryToShape(enfVertex->geomEntry);
2907 //       GeomType = GeomShape.ShapeType();
2908
2909 //       if (!enfVertex->isCompound) {
2910 // //       if (GeomType == TopAbs_VERTEX) {
2911 //         coords.clear();
2912 //         aPnt = BRep_Tool::Pnt(TopoDS::Vertex(GeomShape));
2913 //         coords.push_back(aPnt.X());
2914 //         coords.push_back(aPnt.Y());
2915 //         coords.push_back(aPnt.Z());
2916 //         if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
2917 //           coordsSizeMap.insert(make_pair(coords,enfVertex->size));
2918 //           enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
2919 //         }
2920 //       }
2921 //
2922 //       // Group Management
2923 //       else {
2924 //       if (GeomType == TopAbs_COMPOUND){
2925         for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){
2926           coords.clear();
2927           if (it.Value().ShapeType() == TopAbs_VERTEX){
2928             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(it.Value()));
2929             coords.push_back(aPnt.X());
2930             coords.push_back(aPnt.Y());
2931             coords.push_back(aPnt.Z());
2932             if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
2933               coordsSizeMap.insert(make_pair(coords,enfVertex->size));
2934               enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
2935 //               MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<coords[0]<<","<<coords[1]<<","<<coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
2936             }
2937           }
2938         }
2939 //       }
2940     }
2941   }
2942   int nbEnforcedVertices = coordsSizeMap.size();
2943   int nbEnforcedNodes = enforcedNodes.size();
2944   
2945   std::string tmpStr;
2946   (nbEnforcedNodes <= 1) ? tmpStr = "node" : "nodes";
2947   std::cout << nbEnforcedNodes << " enforced " << tmpStr << " from hypo" << std::endl;
2948   (nbEnforcedVertices <= 1) ? tmpStr = "vertex" : "vertices";
2949   std::cout << nbEnforcedVertices << " enforced " << tmpStr << " from hypo" << std::endl;
2950   
2951   SMESH_MesherHelper helper( theMesh );
2952   helper.SetSubShape( theShape );
2953
2954   std::vector <const SMDS_MeshNode*> aNodeByHybridId, anEnforcedNodeByHybridId;
2955   std::vector <const SMDS_MeshElement*> aFaceByHybridId;
2956   std::map<const SMDS_MeshNode*,int> aNodeToHybridIdMap;
2957   std::vector<std::string> aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId;
2958   {
2959     SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( theMesh ));
2960
2961     // make prisms on quadrangles
2962     if ( theMesh.NbQuadrangles() > 0 )
2963     {
2964       vector<SMESH_ProxyMesh::Ptr> components;
2965       for (expBox.ReInit(); expBox.More(); expBox.Next())
2966       {
2967         if ( _viscousLayersHyp )
2968         {
2969           proxyMesh = _viscousLayersHyp->Compute( theMesh, expBox.Current() );
2970           if ( !proxyMesh )
2971             return false;
2972         }
2973         StdMeshers_QuadToTriaAdaptor* q2t = new StdMeshers_QuadToTriaAdaptor;
2974         q2t->Compute( theMesh, expBox.Current(), proxyMesh.get() );
2975         components.push_back( SMESH_ProxyMesh::Ptr( q2t ));
2976       }
2977       proxyMesh.reset( new SMESH_ProxyMesh( components ));
2978     }
2979     // build viscous layers
2980     else if ( _viscousLayersHyp )
2981     {
2982       proxyMesh = _viscousLayersHyp->Compute( theMesh, theShape );
2983       if ( !proxyMesh )
2984         return false;
2985     }
2986
2987     // Ok = (writePoints( aPointsFile, helper, 
2988     //                    aSmdsToHybridIdMap, anEnforcedNodeIdToHybridIdMap, aHybridIdToNodeMap, 
2989     //                    nodeIDToSizeMap,
2990     //                    coordsSizeMap, enforcedNodes, enforcedEdges, enforcedTriangles)
2991     //       &&
2992     //       writeFaces ( aFacesFile, *proxyMesh, theShape, 
2993     //                    aSmdsToHybridIdMap, anEnforcedNodeIdToHybridIdMap,
2994     //                    enforcedEdges, enforcedTriangles ));
2995     Ok = writeGMFFile(aGMFFileName.ToCString(), aRequiredVerticesFileName.ToCString(), aSolFileName.ToCString(),
2996                       *proxyMesh, helper,
2997                       aNodeByHybridId, aFaceByHybridId, aNodeToHybridIdMap,
2998                       aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId,
2999                       enforcedNodes, enforcedEdges, enforcedTriangles, /*enforcedQuadrangles,*/
3000                       enfVerticesWithGroup, coordsSizeMap);
3001   }
3002
3003   // Write aSmdsToHybridIdMap to temp file
3004   TCollection_AsciiString aSmdsToHybridIdMapFileName;
3005   aSmdsToHybridIdMapFileName = aGenericName + ".ids";  // ids relation
3006   ofstream aIdsFile  ( aSmdsToHybridIdMapFileName.ToCString()  , ios::out);
3007   Ok = aIdsFile.rdbuf()->is_open();
3008   if (!Ok) {
3009     INFOS( "Can't write into " << aSmdsToHybridIdMapFileName);
3010     return error(SMESH_Comment("Can't write into ") << aSmdsToHybridIdMapFileName);
3011   }
3012   INFOS( "Writing ids relation into " << aSmdsToHybridIdMapFileName);
3013   aIdsFile << "Smds Hybrid" << std::endl;
3014   map <int,int>::const_iterator myit;
3015   for (myit=aSmdsToHybridIdMap.begin() ; myit != aSmdsToHybridIdMap.end() ; ++myit) {
3016     aIdsFile << myit->first << " " << myit->second << std::endl;
3017   }
3018
3019   aIdsFile.close();
3020   
3021   if ( ! Ok ) {
3022     if ( !_keepFiles ) {
3023       removeFile( aGMFFileName );
3024       removeFile( aRequiredVerticesFileName );
3025       removeFile( aSolFileName );
3026       removeFile( aSmdsToHybridIdMapFileName );
3027     }
3028     return error(COMPERR_BAD_INPUT_MESH);
3029   }
3030   removeFile( aResultFileName ); // needed for boundary recovery module usage
3031
3032   // -----------------
3033   // run hybrid mesher
3034   // -----------------
3035
3036   TCollection_AsciiString cmd( (char*)HYBRIDPlugin_Hypothesis::CommandToRun( _hyp ).c_str() );
3037   
3038   cmd += TCollection_AsciiString(" --in ") + aGMFFileName;
3039   if ( nbEnforcedVertices + nbEnforcedNodes)
3040     cmd += TCollection_AsciiString(" --required_vertices ") + aGenericNameRequired;
3041   cmd += TCollection_AsciiString(" --out ") + aResultFileName;
3042   if ( !_logInStandardOutput )
3043     cmd += TCollection_AsciiString(" 1>" ) + aLogFileName;  // dump into file
3044
3045   std::cout << std::endl;
3046   std::cout << "Hybrid execution..." << std::endl;
3047   std::cout << cmd << std::endl;
3048
3049   _compute_canceled = false;
3050
3051   system( cmd.ToCString() ); // run
3052
3053   std::cout << std::endl;
3054   std::cout << "End of Hybrid execution !" << std::endl;
3055
3056   // --------------
3057   // read a result
3058   // --------------
3059
3060   // Mapping the result file
3061
3062   // int fileOpen;
3063   // fileOpen = open( aResultFileName.ToCString(), O_RDONLY);
3064   // if ( fileOpen < 0 ) {
3065   //   std::cout << std::endl;
3066   //   std::cout << "Can't open the " << aResultFileName.ToCString() << " HYBRID output file" << std::endl;
3067   //   std::cout << "Log: " << aLogFileName << std::endl;
3068   //   Ok = false;
3069   // }
3070   // else {
3071     HYBRIDPlugin_Hypothesis::TSetStrings groupsToRemove = HYBRIDPlugin_Hypothesis::GetGroupsToRemove(_hyp);
3072     bool toMeshHoles =
3073       _hyp ? _hyp->GetToMeshHoles(true) : HYBRIDPlugin_Hypothesis::DefaultMeshHoles();
3074     const bool toMakeGroupsOfDomains = HYBRIDPlugin_Hypothesis::GetToMakeGroupsOfDomains( _hyp );
3075
3076     helper.IsQuadraticSubMesh( theShape );
3077     helper.SetElementsOnShape( false );
3078
3079 //     Ok = readResultFile( fileOpen,
3080 // #ifdef WIN32
3081 //                          aResultFileName.ToCString(),
3082 // #endif
3083 //                          this, //theMesh,
3084 //                          helper, tabShape, tabBox, _nbShape, 
3085 //                          aHybridIdToNodeMap, aNodeId2NodeIndexMap,
3086 //                          toMeshHoles, 
3087 //                          nbEnforcedVertices, nbEnforcedNodes, 
3088 //                          enforcedEdges, enforcedTriangles,
3089 //                          toMakeGroupsOfDomains );
3090                          
3091     Ok = readGMFFile(aResultFileName.ToCString(),
3092                      this,
3093                      &helper, aNodeByHybridId, aFaceByHybridId, aNodeToHybridIdMap,
3094                      aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId,
3095                      groupsToRemove, toMakeGroupsOfDomains, toMeshHoles);
3096
3097     //removeEmptyGroupsOfDomains( helper.GetMesh(), notEmptyAsWell );
3098     removeEmptyGroupsOfDomains( helper.GetMesh(), !toMakeGroupsOfDomains );
3099     //}
3100
3101
3102
3103
3104   // ---------------------
3105   // remove working files
3106   // ---------------------
3107
3108   if ( Ok )
3109   {
3110     if ( _removeLogOnSuccess )
3111       removeFile( aLogFileName );
3112
3113     // if ( _hyp && _hyp->GetToMakeGroupsOfDomains() )
3114     //   error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since the mesh is on shape" );
3115   }
3116   else if ( OSD_File( aLogFileName ).Size() > 0 )
3117   {
3118     // get problem description from the log file
3119     _Ghs2smdsConvertor conv( aNodeByHybridId );
3120     storeErrorDescription( aLogFileName, conv );
3121   }
3122   else
3123   {
3124     // the log file is empty
3125     removeFile( aLogFileName );
3126     INFOS( "HYBRID Error, command '" << cmd.ToCString() << "' failed" );
3127     error(COMPERR_ALGO_FAILED, "hybrid: command not found" );
3128   }
3129
3130   if ( !_keepFiles ) {
3131     if (! Ok && _compute_canceled)
3132       removeFile( aLogFileName );
3133     removeFile( aGMFFileName );
3134     removeFile( aRequiredVerticesFileName );
3135     removeFile( aSolFileName );
3136     removeFile( aResSolFileName );
3137     removeFile( aResultFileName );
3138     removeFile( aSmdsToHybridIdMapFileName );
3139   }
3140   std::cout << "<" << aResultFileName.ToCString() << "> HYBRID output file ";
3141   if ( !Ok )
3142     std::cout << "not ";
3143   std::cout << "treated !" << std::endl;
3144   std::cout << std::endl;
3145
3146   // _nbShape = 0;    // re-initializing _nbShape for the next Compute() method call
3147   // delete [] tabShape;
3148   // delete [] tabBox;
3149
3150   return Ok;
3151 }
3152
3153 //=============================================================================
3154 /*!
3155  *Here we are going to use the HYBRID mesher w/o geometry
3156  */
3157 //=============================================================================
3158 bool HYBRIDPlugin_HYBRID::Compute(SMESH_Mesh&         theMesh,
3159                                   SMESH_MesherHelper* theHelper)
3160 {
3161   MESSAGE("HYBRIDPlugin_HYBRID::Compute()");
3162
3163   theHelper->IsQuadraticSubMesh( theHelper->GetSubShape() );
3164
3165   // a unique working file name
3166   // to avoid access to the same files by eg different users
3167   _genericName = HYBRIDPlugin_Hypothesis::GetFileName(_hyp);
3168   TCollection_AsciiString aGenericName((char*) _genericName.c_str() );
3169   TCollection_AsciiString aGenericNameRequired = aGenericName + "_required";
3170
3171   TCollection_AsciiString aLogFileName    = aGenericName + ".log";    // log
3172   TCollection_AsciiString aResultFileName;
3173   bool Ok;
3174
3175   TCollection_AsciiString aGMFFileName, aRequiredVerticesFileName, aSolFileName, aResSolFileName;
3176 //#ifdef _DEBUG_
3177   aGMFFileName              = aGenericName + ".mesh"; // GMF mesh file
3178   aResultFileName           = aGenericName + "Vol.mesh"; // GMF mesh file
3179   aResSolFileName           = aGenericName + "Vol.sol"; // GMF mesh file
3180   aRequiredVerticesFileName = aGenericNameRequired + ".mesh"; // GMF required vertices mesh file
3181   aSolFileName              = aGenericNameRequired + ".sol"; // GMF solution file
3182 //#else
3183 //  aGMFFileName    = aGenericName + ".meshb"; // GMF mesh file
3184 //  aResultFileName = aGenericName + "Vol.meshb"; // GMF mesh file
3185 //  aRequiredVerticesFileName    = aGenericNameRequired + ".meshb"; // GMF required vertices mesh file
3186 //  aSolFileName    = aGenericNameRequired + ".solb"; // GMF solution file
3187 //#endif
3188
3189   std::map <int, int> nodeID2nodeIndexMap;
3190   std::map<std::vector<double>, std::string> enfVerticesWithGroup;
3191   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexCoordsValues coordsSizeMap;
3192   TopoDS_Shape GeomShape;
3193 //   TopAbs_ShapeEnum GeomType;
3194   std::vector<double> coords;
3195   gp_Pnt aPnt;
3196   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertex* enfVertex;
3197
3198   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexList enfVertices = HYBRIDPlugin_Hypothesis::GetEnforcedVertices(_hyp);
3199   HYBRIDPlugin_Hypothesis::THYBRIDEnforcedVertexList::const_iterator enfVerIt = enfVertices.begin();
3200
3201   for ( ; enfVerIt != enfVertices.end() ; ++enfVerIt)
3202   {
3203     enfVertex = (*enfVerIt);
3204 //     if (enfVertex->geomEntry.empty() && enfVertex->coords.size()) {
3205     if (enfVertex->coords.size()) {
3206       coordsSizeMap.insert(make_pair(enfVertex->coords,enfVertex->size));
3207       enfVerticesWithGroup.insert(make_pair(enfVertex->coords,enfVertex->groupName));
3208 //       MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<enfVertex->coords[0]<<","<<enfVertex->coords[1]<<","<<enfVertex->coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
3209     }
3210     else {
3211 //     if (!enfVertex->geomEntry.empty()) {
3212       GeomShape = entryToShape(enfVertex->geomEntry);
3213 //       GeomType = GeomShape.ShapeType();
3214
3215 //       if (!enfVertex->isCompound) {
3216 // //       if (GeomType == TopAbs_VERTEX) {
3217 //         coords.clear();
3218 //         aPnt = BRep_Tool::Pnt(TopoDS::Vertex(GeomShape));
3219 //         coords.push_back(aPnt.X());
3220 //         coords.push_back(aPnt.Y());
3221 //         coords.push_back(aPnt.Z());
3222 //         if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
3223 //           coordsSizeMap.insert(make_pair(coords,enfVertex->size));
3224 //           enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
3225 //         }
3226 //       }
3227 //
3228 //       // Group Management
3229 //       else {
3230 //       if (GeomType == TopAbs_COMPOUND){
3231         for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()){
3232           coords.clear();
3233           if (it.Value().ShapeType() == TopAbs_VERTEX){
3234             aPnt = BRep_Tool::Pnt(TopoDS::Vertex(it.Value()));
3235             coords.push_back(aPnt.X());
3236             coords.push_back(aPnt.Y());
3237             coords.push_back(aPnt.Z());
3238             if (coordsSizeMap.find(coords) == coordsSizeMap.end()) {
3239               coordsSizeMap.insert(make_pair(coords,enfVertex->size));
3240               enfVerticesWithGroup.insert(make_pair(coords,enfVertex->groupName));
3241 //               MESSAGE("enfVerticesWithGroup.insert(make_pair(("<<coords[0]<<","<<coords[1]<<","<<coords[2]<<"),\""<<enfVertex->groupName<<"\"))");
3242             }
3243           }
3244         }
3245 //       }
3246     }
3247   }
3248
3249 //   const SMDS_MeshNode* enfNode;
3250   HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap enforcedNodes = HYBRIDPlugin_Hypothesis::GetEnforcedNodes(_hyp);
3251 //   HYBRIDPlugin_Hypothesis::TIDSortedNodeGroupMap::const_iterator enfNodeIt = enforcedNodes.begin();
3252 //   for ( ; enfNodeIt != enforcedNodes.end() ; ++enfNodeIt)
3253 //   {
3254 //     enfNode = enfNodeIt->first;
3255 //     coords.clear();
3256 //     coords.push_back(enfNode->X());
3257 //     coords.push_back(enfNode->Y());
3258 //     coords.push_back(enfNode->Z());
3259 //     if (enfVerticesWithGro
3260 //       enfVerticesWithGroup.insert(make_pair(coords,enfNodeIt->second));
3261 //   }
3262
3263
3264   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap enforcedEdges = HYBRIDPlugin_Hypothesis::GetEnforcedEdges(_hyp);
3265   HYBRIDPlugin_Hypothesis::TIDSortedElemGroupMap enforcedTriangles = HYBRIDPlugin_Hypothesis::GetEnforcedTriangles(_hyp);
3266 //   TIDSortedElemSet enforcedQuadrangles = HYBRIDPlugin_Hypothesis::GetEnforcedQuadrangles(_hyp);
3267   HYBRIDPlugin_Hypothesis::TID2SizeMap nodeIDToSizeMap = HYBRIDPlugin_Hypothesis::GetNodeIDToSizeMap(_hyp);
3268
3269   std::string tmpStr;
3270
3271   int nbEnforcedVertices = coordsSizeMap.size();
3272   int nbEnforcedNodes = enforcedNodes.size();
3273   (nbEnforcedNodes <= 1) ? tmpStr = "node" : tmpStr = "nodes";
3274   std::cout << nbEnforcedNodes << " enforced " << tmpStr << " from hypo" << std::endl;
3275   (nbEnforcedVertices <= 1) ? tmpStr = "vertex" : tmpStr = "vertices";
3276   std::cout << nbEnforcedVertices << " enforced " << tmpStr << " from hypo" << std::endl;
3277
3278   std::vector <const SMDS_MeshNode*> aNodeByHybridId, anEnforcedNodeByHybridId;
3279   std::vector <const SMDS_MeshElement*> aFaceByHybridId;
3280   std::map<const SMDS_MeshNode*,int> aNodeToHybridIdMap;
3281   std::vector<std::string> aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId;
3282   {
3283     SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( theMesh ));
3284     if ( theMesh.NbQuadrangles() > 0 )
3285     {
3286       StdMeshers_QuadToTriaAdaptor* aQuad2Trias = new StdMeshers_QuadToTriaAdaptor;
3287       aQuad2Trias->Compute( theMesh );
3288       proxyMesh.reset( aQuad2Trias );
3289     }
3290
3291     Ok = writeGMFFile(aGMFFileName.ToCString(), aRequiredVerticesFileName.ToCString(), aSolFileName.ToCString(),
3292                       *proxyMesh, *theHelper,
3293                       aNodeByHybridId, aFaceByHybridId, aNodeToHybridIdMap,
3294                       aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId,
3295                       enforcedNodes, enforcedEdges, enforcedTriangles,
3296                       enfVerticesWithGroup, coordsSizeMap);
3297   }
3298
3299   // -----------------
3300   // run hybrid mesher
3301   // -----------------
3302
3303   TCollection_AsciiString cmd = TCollection_AsciiString((char*)HYBRIDPlugin_Hypothesis::CommandToRun( _hyp, false ).c_str());
3304
3305   cmd += TCollection_AsciiString(" --in ") + aGMFFileName;
3306   //if ( nbEnforcedVertices + nbEnforcedNodes)
3307   //  cmd += TCollection_AsciiString(" --required_vertices ") + aGenericNameRequired;
3308   cmd += TCollection_AsciiString(" --out ") + aResultFileName;
3309   if ( !_logInStandardOutput )
3310     cmd += TCollection_AsciiString(" 1>" ) + aLogFileName;  // dump into file
3311
3312   std::cout << std::endl;
3313   std::cout << "Hybrid execution..." << std::endl;
3314   std::cout << cmd << std::endl;
3315
3316   _compute_canceled = false;
3317
3318   system( cmd.ToCString() ); // run
3319
3320   std::cout << std::endl;
3321   std::cout << "End of Hybrid execution !" << std::endl;
3322
3323   // --------------
3324   // read a result
3325   // --------------
3326   HYBRIDPlugin_Hypothesis::TSetStrings groupsToRemove = HYBRIDPlugin_Hypothesis::GetGroupsToRemove(_hyp);
3327   const bool toMakeGroupsOfDomains = HYBRIDPlugin_Hypothesis::GetToMakeGroupsOfDomains( _hyp );
3328
3329   Ok = readGMFFile(aResultFileName.ToCString(),
3330                    this,
3331                    theHelper, aNodeByHybridId, aFaceByHybridId, aNodeToHybridIdMap,
3332                    aNodeGroupByHybridId, anEdgeGroupByHybridId, aFaceGroupByHybridId,
3333                    groupsToRemove, toMakeGroupsOfDomains);
3334
3335   updateMeshGroups(theHelper->GetMesh(), groupsToRemove);
3336   //removeEmptyGroupsOfDomains( theHelper->GetMesh(), notEmptyAsWell );
3337   removeEmptyGroupsOfDomains( theHelper->GetMesh(), !toMakeGroupsOfDomains );
3338
3339   if ( Ok ) {
3340     HYBRIDPlugin_Hypothesis* that = (HYBRIDPlugin_Hypothesis*)this->_hyp;
3341     if (that)
3342       that->ClearGroupsToRemove();
3343   }
3344   // ---------------------
3345   // remove working files
3346   // ---------------------
3347
3348   if ( Ok )
3349   {
3350     if ( _removeLogOnSuccess )
3351       removeFile( aLogFileName );
3352
3353     //if ( !toMakeGroupsOfDomains && _hyp && _hyp->GetToMakeGroupsOfDomains() )
3354     //error( COMPERR_WARNING, "'toMakeGroupsOfDomains' is ignored since 'toMeshHoles' is OFF." );
3355   }
3356   else if ( OSD_File( aLogFileName ).Size() > 0 )
3357   {
3358     // get problem description from the log file
3359     _Ghs2smdsConvertor conv( aNodeByHybridId );
3360     storeErrorDescription( aLogFileName, conv );
3361   }
3362   else {
3363     // the log file is empty
3364     removeFile( aLogFileName );
3365     INFOS( "HYBRID Error, command '" << cmd.ToCString() << "' failed" );
3366     error(COMPERR_ALGO_FAILED, "hybrid: command not found" );
3367   }
3368
3369   if ( !_keepFiles )
3370   {
3371     if (! Ok && _compute_canceled)
3372       removeFile( aLogFileName );
3373     removeFile( aGMFFileName );
3374     removeFile( aResultFileName );
3375     removeFile( aRequiredVerticesFileName );
3376     removeFile( aSolFileName );
3377     removeFile( aResSolFileName );
3378   }
3379   return Ok;
3380 }
3381
3382 void HYBRIDPlugin_HYBRID::CancelCompute()
3383 {
3384   _compute_canceled = true;
3385 #ifdef WIN32
3386 #else
3387   std::string cmd = "ps xo pid,args | grep " + _genericName;
3388   //cmd += " | grep -e \"^ *[0-9]\\+ \\+" + HYBRIDPlugin_Hypothesis::GetExeName() + "\"";
3389   cmd += " | awk '{print $1}' | xargs kill -9 > /dev/null 2>&1";
3390   system( cmd.c_str() );
3391 #endif
3392 }
3393
3394 //================================================================================
3395 /*!
3396  * \brief Provide human readable text by error code reported by hybrid
3397  */
3398 //================================================================================
3399
3400 static const char* translateError(const int errNum)
3401 {
3402   switch ( errNum ) {
3403   case 0:
3404     return "error distene 0";
3405   case 1:
3406     return "error distene 1";
3407   }
3408   return "unknown distene error";
3409 }
3410
3411 //================================================================================
3412 /*!
3413  * \brief Retrieve from a string given number of integers
3414  */
3415 //================================================================================
3416
3417 static char* getIds( char* ptr, int nbIds, vector<int>& ids )
3418 {
3419   ids.clear();
3420   ids.reserve( nbIds );
3421   while ( nbIds )
3422   {
3423     while ( !isdigit( *ptr )) ++ptr;
3424     if ( ptr[-1] == '-' ) --ptr;
3425     ids.push_back( strtol( ptr, &ptr, 10 ));
3426     --nbIds;
3427   }
3428   return ptr;
3429 }
3430
3431 //================================================================================
3432 /*!
3433  * \brief Retrieve problem description form a log file
3434  *  \retval bool - always false
3435  */
3436 //================================================================================
3437
3438 bool HYBRIDPlugin_HYBRID::storeErrorDescription(const TCollection_AsciiString& logFile,
3439                                                 const _Ghs2smdsConvertor &     toSmdsConvertor )
3440 {
3441   if(_compute_canceled)
3442     return error(SMESH_Comment("interruption initiated by user"));
3443   // open file
3444 #ifdef WIN32
3445   int file = ::_open (logFile.ToCString(), _O_RDONLY|_O_BINARY);
3446 #else
3447   int file = ::open (logFile.ToCString(), O_RDONLY);
3448 #endif
3449   if ( file < 0 )
3450     return error( SMESH_Comment("See ") << logFile << " for problem description");
3451
3452   // get file size
3453   off_t length = lseek( file, 0, SEEK_END);
3454   lseek( file, 0, SEEK_SET);
3455
3456   // read file
3457   vector< char > buf( length );
3458   int nBytesRead = ::read (file, & buf[0], length);
3459   ::close (file);
3460   char* ptr = & buf[0];
3461   char* bufEnd = ptr + nBytesRead;
3462
3463   SMESH_Comment errDescription;
3464
3465   enum { NODE = 1, EDGE, TRIA, VOL, SKIP_ID = 1 };
3466
3467   // look for MeshGems version
3468   // Since "MG-TETRA -- MeshGems 1.1-3 (January, 2013)" error codes change.
3469   // To discriminate old codes from new ones we add 1000000 to the new codes.
3470   // This way value of the new codes is same as absolute value of codes printed
3471   // in the log after "MGMESSAGE" string.
3472   int versionAddition = 0;
3473   {
3474     char* verPtr = ptr;
3475     while ( ++verPtr < bufEnd )
3476     {
3477       if ( strncmp( verPtr, "MG-TETRA -- MeshGems ", 21 ) != 0 )
3478         continue;
3479       if ( strcmp( verPtr, "MG-TETRA -- MeshGems 1.1-3 " ) >= 0 )
3480         versionAddition = 1000000;
3481       ptr = verPtr;
3482       break;
3483     }
3484   }
3485
3486   // look for errors "ERR #"
3487
3488   set<string> foundErrorStr; // to avoid reporting same error several times
3489   set<int>    elemErrorNums; // not to report different types of errors with bad elements
3490   while ( ++ptr < bufEnd )
3491   {
3492     if ( strncmp( ptr, "ERR ", 4 ) != 0 )
3493       continue;
3494
3495     list<const SMDS_MeshElement*> badElems;
3496     vector<int> nodeIds;
3497
3498     ptr += 4;
3499     char* errBeg = ptr;
3500     int   errNum = strtol(ptr, &ptr, 10) + versionAddition;
3501     // we treat errors enumerated in [SALOME platform 0019316] issue
3502     // and all errors from a new (Release 1.1) MeshGems User Manual
3503     switch ( errNum ) {
3504     case 0015: // The face number (numfac) with vertices (f 1, f 2, f 3) has a null vertex.
3505     case 1005620 : // a too bad quality face is detected. This face is considered degenerated.
3506       ptr = getIds(ptr, SKIP_ID, nodeIds);
3507       ptr = getIds(ptr, TRIA, nodeIds);
3508       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3509       break;
3510     case 1005621 : // a too bad quality face is detected. This face is degenerated.
3511       // hence the is degenerated it is invisible, add its edges in addition
3512       ptr = getIds(ptr, SKIP_ID, nodeIds);
3513       ptr = getIds(ptr, TRIA, nodeIds);
3514       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3515       {
3516         vector<int> edgeNodes( nodeIds.begin(), --nodeIds.end() ); // 01
3517         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
3518         edgeNodes[1] = nodeIds[2]; // 02
3519         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
3520         edgeNodes[0] = nodeIds[1]; // 12
3521       }      
3522       break;
3523     case 1000: // Face (f 1, f 2, f 3) appears more than once in the input surface mesh.
3524       // ERR  1000 :  1 3 2
3525     case 1002: // Face (f 1, f 2, f 3) has a vertex negative or null
3526     case 3019: // Constrained face (f 1, f 2, f 3) cannot be enforced
3527     case 1002211: // a face has a vertex negative or null.
3528     case 1005200 : // a surface mesh appears more than once in the input surface mesh.
3529     case 1008423 : // a constrained face cannot be enforced (regeneration phase failed).
3530       ptr = getIds(ptr, TRIA, nodeIds);
3531       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3532       break;
3533     case 1001: // Edge (e1, e2) appears more than once in the input surface mesh
3534     case 3009: // Constrained edge (e1, e2) cannot be enforced (warning).
3535       // ERR  3109 :  EDGE  5 6 UNIQUE
3536     case 3109: // Edge (e1, e2) is unique (i.e., bounds a hole in the surface)
3537     case 1005210 : // an edge appears more than once in the input surface mesh.
3538     case 1005820 : // an edge is unique (i.e., bounds a hole in the surface).
3539     case 1008441 : // a constrained edge cannot be enforced.
3540       ptr = getIds(ptr, EDGE, nodeIds);
3541       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3542       break;
3543     case 2004: // Vertex v1 and vertex v2 are too close to one another or coincident (warning).
3544     case 2014: // at least two points whose distance is dist, i.e., considered as coincident
3545     case 2103: // Vertex v1 and vertex v2 are too close to one another or coincident (warning).
3546       // ERR  2103 :  16 WITH  3
3547     case 1005105 : // two vertices are too close to one another or coincident.
3548     case 1005107: // Two vertices are too close to one another or coincident.
3549       ptr = getIds(ptr, NODE, nodeIds);
3550       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3551       ptr = getIds(ptr, NODE, nodeIds);
3552       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3553       break;
3554     case 2012: // Vertex v1 cannot be inserted (warning).
3555     case 1005106 : // a vertex cannot be inserted.
3556       ptr = getIds(ptr, NODE, nodeIds);
3557       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3558       break;
3559     case 3103: // The surface edge (e1, e2) intersects another surface edge (e3, e4)
3560     case 1005110 : // two surface edges are intersecting.
3561       // ERR  3103 :  1 2 WITH  7 3
3562       ptr = getIds(ptr, EDGE, nodeIds);
3563       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3564       ptr = getIds(ptr, EDGE, nodeIds);
3565       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3566       break;
3567     case 3104: // The surface edge (e1, e2) intersects the surface face (f 1, f 2, f 3)
3568       // ERR  3104 :  9 10 WITH  1 2 3
3569     case 3106: // One surface edge (say e1, e2) intersects a surface face (f 1, f 2, f 3)
3570     case 1005120 : // a surface edge intersects a surface face.
3571       ptr = getIds(ptr, EDGE, nodeIds);
3572       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3573       ptr = getIds(ptr, TRIA, nodeIds);
3574       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3575       break;
3576     case 3105: // One boundary point (say p1) lies within a surface face (f 1, f 2, f 3)
3577       // ERR  3105 :  8 IN  2 3 5
3578     case 1005150 : // a boundary point lies within a surface face.
3579       ptr = getIds(ptr, NODE, nodeIds);
3580       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3581       ptr = getIds(ptr, TRIA, nodeIds);
3582       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3583       break;
3584     case 3107: // One boundary point (say p1) lies within a surface edge (e1, e2) (stop).
3585       // ERR  3107 :  2 IN  4 1
3586     case 1005160 : // a boundary point lies within a surface edge.
3587       ptr = getIds(ptr, NODE, nodeIds);
3588       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3589       ptr = getIds(ptr, EDGE, nodeIds);
3590       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3591       break;
3592     case 9000: // ERR  9000
3593       //  ELEMENT  261 WITH VERTICES :  7 396 -8 242
3594       //  VOLUME   : -1.11325045E+11 W.R.T. EPSILON   0.
3595       // A too small volume element is detected. Are reported the index of the element,
3596       // its four vertex indices, its volume and the tolerance threshold value
3597       ptr = getIds(ptr, SKIP_ID, nodeIds);
3598       ptr = getIds(ptr, VOL, nodeIds);
3599       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3600       // even if all nodes found, volume it most probably invisible,
3601       // add its faces to demonstrate it anyhow
3602       {
3603         vector<int> faceNodes( nodeIds.begin(), --nodeIds.end() ); // 012
3604         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
3605         faceNodes[2] = nodeIds[3]; // 013
3606         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
3607         faceNodes[1] = nodeIds[2]; // 023
3608         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
3609         faceNodes[0] = nodeIds[1]; // 123
3610         badElems.push_back( toSmdsConvertor.getElement(faceNodes));
3611       }
3612       break;
3613     case 9001: // ERR  9001
3614       //  %% NUMBER OF NEGATIVE VOLUME TETS  :  1
3615       //  %% THE LARGEST NEGATIVE TET        :   1.75376581E+11
3616       //  %%  NUMBER OF NULL VOLUME TETS     :  0
3617       // There exists at least a null or negative volume element
3618       break;
3619     case 9002:
3620       // There exist n null or negative volume elements
3621       break;
3622     case 9003:
3623       // A too small volume element is detected
3624       break;
3625     case 9102:
3626       // A too bad quality face is detected. This face is considered degenerated,
3627       // its index, its three vertex indices together with its quality value are reported
3628       break; // same as next
3629     case 9112: // ERR  9112
3630       //  FACE   2 WITH VERTICES :  4 2 5
3631       //  SMALL INRADIUS :   0.
3632       // A too bad quality face is detected. This face is degenerated,
3633       // its index, its three vertex indices together with its inradius are reported
3634       ptr = getIds(ptr, SKIP_ID, nodeIds);
3635       ptr = getIds(ptr, TRIA, nodeIds);
3636       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3637       // add triangle edges as it most probably has zero area and hence invisible
3638       {
3639         vector<int> edgeNodes(2);
3640         edgeNodes[0] = nodeIds[0]; edgeNodes[1] = nodeIds[1]; // 0-1
3641         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
3642         edgeNodes[1] = nodeIds[2]; // 0-2
3643         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
3644         edgeNodes[0] = nodeIds[1]; // 1-2
3645         badElems.push_back( toSmdsConvertor.getElement(edgeNodes));
3646       }
3647       break;
3648     case 1005103 : // the vertices of an element are too close to one another or coincident.
3649       ptr = getIds(ptr, TRIA, nodeIds);
3650       if ( nodeIds.back() == 0 ) // index of the third vertex of the element (0 for an edge)
3651         nodeIds.resize( EDGE );
3652       badElems.push_back( toSmdsConvertor.getElement(nodeIds));
3653       break;
3654     }
3655
3656     bool isNewError = foundErrorStr.insert( string( errBeg, ptr )).second;
3657     if ( !isNewError )
3658       continue; // not to report same error several times
3659
3660 //     const SMDS_MeshElement* nullElem = 0;
3661 //     bool allElemsOk = ( find( badElems.begin(), badElems.end(), nullElem) == badElems.end());
3662
3663 //     if ( allElemsOk && !badElems.empty() && !elemErrorNums.empty() ) {
3664 //       bool oneMoreErrorType = elemErrorNums.insert( errNum ).second;
3665 //       if ( oneMoreErrorType )
3666 //         continue; // not to report different types of errors with bad elements
3667 //     }
3668
3669     // store bad elements
3670     //if ( allElemsOk ) {
3671       list<const SMDS_MeshElement*>::iterator elem = badElems.begin();
3672       for ( ; elem != badElems.end(); ++elem )
3673         addBadInputElement( *elem );
3674       //}
3675
3676     // make error text
3677     string text = translateError( errNum );
3678     if ( errDescription.find( text ) == text.npos ) {
3679       if ( !errDescription.empty() )
3680         errDescription << "\n";
3681       errDescription << text;
3682     }
3683
3684   } // end while
3685
3686   if ( errDescription.empty() ) { // no errors found
3687     char msgLic1[] = "connection to server failed";
3688     char msgLic2[] = " Dlim ";
3689     if ( search( &buf[0], bufEnd, msgLic1, msgLic1 + strlen(msgLic1)) != bufEnd ||
3690          search( &buf[0], bufEnd, msgLic2, msgLic2 + strlen(msgLic2)) != bufEnd )
3691       errDescription << "Licence problems.";
3692     else
3693     {
3694       char msg2[] = "SEGMENTATION FAULT";
3695       if ( search( &buf[0], bufEnd, msg2, msg2 + strlen(msg2)) != bufEnd )
3696         errDescription << "hybrid: SEGMENTATION FAULT. ";
3697     }
3698   }
3699
3700   if ( errDescription.empty() )
3701     errDescription << "See " << logFile << " for problem description";
3702   else
3703     errDescription << "\nSee " << logFile << " for more information";
3704
3705   return error( errDescription );
3706 }
3707
3708 //================================================================================
3709 /*!
3710  * \brief Creates _Ghs2smdsConvertor
3711  */
3712 //================================================================================
3713
3714 _Ghs2smdsConvertor::_Ghs2smdsConvertor( const map <int,const SMDS_MeshNode*> & ghs2NodeMap)
3715   :_ghs2NodeMap( & ghs2NodeMap ), _nodeByGhsId( 0 )
3716 {
3717 }
3718
3719 //================================================================================
3720 /*!
3721  * \brief Creates _Ghs2smdsConvertor
3722  */
3723 //================================================================================
3724
3725 _Ghs2smdsConvertor::_Ghs2smdsConvertor( const vector <const SMDS_MeshNode*> &  nodeByGhsId)
3726   : _ghs2NodeMap( 0 ), _nodeByGhsId( &nodeByGhsId )
3727 {
3728 }
3729
3730 //================================================================================
3731 /*!
3732  * \brief Return SMDS element by ids of HYBRID nodes
3733  */
3734 //================================================================================
3735
3736 const SMDS_MeshElement* _Ghs2smdsConvertor::getElement(const vector<int>& ghsNodes) const
3737 {
3738   size_t nbNodes = ghsNodes.size();
3739   vector<const SMDS_MeshNode*> nodes( nbNodes, 0 );
3740   for ( size_t i = 0; i < nbNodes; ++i ) {
3741     int ghsNode = ghsNodes[ i ];
3742     if ( _ghs2NodeMap ) {
3743       map <int,const SMDS_MeshNode*>::const_iterator in = _ghs2NodeMap->find( ghsNode);
3744       if ( in == _ghs2NodeMap->end() )
3745         return 0;
3746       nodes[ i ] = in->second;
3747     }
3748     else {
3749       if ( ghsNode < 1 || ghsNode > _nodeByGhsId->size() )
3750         return 0;
3751       nodes[ i ] = (*_nodeByGhsId)[ ghsNode-1 ];
3752     }
3753   }
3754   if ( nbNodes == 1 )
3755     return nodes[0];
3756
3757   if ( nbNodes == 2 ) {
3758     const SMDS_MeshElement* edge= SMDS_Mesh::FindEdge( nodes[0], nodes[1] );
3759     if ( !edge )
3760       edge = new SMDS_LinearEdge( nodes[0], nodes[1] );
3761     return edge;
3762   }
3763   if ( nbNodes == 3 ) {
3764     const SMDS_MeshElement* face = SMDS_Mesh::FindFace( nodes );
3765     if ( !face )
3766       face = new SMDS_FaceOfNodes( nodes[0], nodes[1], nodes[2] );
3767     return face;
3768   }
3769   if ( nbNodes == 4 )
3770     return new SMDS_VolumeOfNodes( nodes[0], nodes[1], nodes[2], nodes[3] );
3771
3772   return 0;
3773 }
3774
3775
3776 //=============================================================================
3777 /*!
3778  *
3779  */
3780 //=============================================================================
3781 bool HYBRIDPlugin_HYBRID::Evaluate(SMESH_Mesh& aMesh,
3782                                  const TopoDS_Shape& aShape,
3783                                  MapShapeNbElems& aResMap)
3784 {
3785   int nbtri = 0, nbqua = 0;
3786   double fullArea = 0.0;
3787   for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) {
3788     TopoDS_Face F = TopoDS::Face( exp.Current() );
3789     SMESH_subMesh *sm = aMesh.GetSubMesh(F);
3790     MapShapeNbElemsItr anIt = aResMap.find(sm);
3791     if( anIt==aResMap.end() ) {
3792       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
3793       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,
3794                                             "Submesh can not be evaluated",this));
3795       return false;
3796     }
3797     std::vector<int> aVec = (*anIt).second;
3798     nbtri += Max(aVec[SMDSEntity_Triangle],aVec[SMDSEntity_Quad_Triangle]);
3799     nbqua += Max(aVec[SMDSEntity_Quadrangle],aVec[SMDSEntity_Quad_Quadrangle]);
3800     GProp_GProps G;
3801     BRepGProp::SurfaceProperties(F,G);
3802     double anArea = G.Mass();
3803     fullArea += anArea;
3804   }
3805
3806   // collect info from edges
3807   int nb0d_e = 0, nb1d_e = 0;
3808   bool IsQuadratic = false;
3809   bool IsFirst = true;
3810   TopTools_MapOfShape tmpMap;
3811   for (TopExp_Explorer exp(aShape, TopAbs_EDGE); exp.More(); exp.Next()) {
3812     TopoDS_Edge E = TopoDS::Edge(exp.Current());
3813     if( tmpMap.Contains(E) )
3814       continue;
3815     tmpMap.Add(E);
3816     SMESH_subMesh *aSubMesh = aMesh.GetSubMesh(exp.Current());
3817     MapShapeNbElemsItr anIt = aResMap.find(aSubMesh);
3818     std::vector<int> aVec = (*anIt).second;
3819     nb0d_e += aVec[SMDSEntity_Node];
3820     nb1d_e += Max(aVec[SMDSEntity_Edge],aVec[SMDSEntity_Quad_Edge]);
3821     if(IsFirst) {
3822       IsQuadratic = (aVec[SMDSEntity_Quad_Edge] > aVec[SMDSEntity_Edge]);
3823       IsFirst = false;
3824     }
3825   }
3826   tmpMap.Clear();
3827
3828   double ELen = sqrt(2.* ( fullArea/(nbtri+nbqua*2) ) / sqrt(3.0) );
3829
3830   GProp_GProps G;
3831   BRepGProp::VolumeProperties(aShape,G);
3832   double aVolume = G.Mass();
3833   double tetrVol = 0.1179*ELen*ELen*ELen;
3834   double CoeffQuality = 0.9;
3835   int nbVols = int(aVolume/tetrVol/CoeffQuality);
3836   int nb1d_f = (nbtri*3 + nbqua*4 - nb1d_e) / 2;
3837   int nb1d_in = (int) ( nbVols*6 - nb1d_e - nb1d_f ) / 5;
3838   std::vector<int> aVec(SMDSEntity_Last);
3839   for(int i=SMDSEntity_Node; i<SMDSEntity_Last; i++) aVec[i]=0;
3840   if( IsQuadratic ) {
3841     aVec[SMDSEntity_Node] = nb1d_in/6 + 1 + nb1d_in;
3842     aVec[SMDSEntity_Quad_Tetra] = nbVols - nbqua*2;
3843     aVec[SMDSEntity_Quad_Pyramid] = nbqua;
3844   }
3845   else {
3846     aVec[SMDSEntity_Node] = nb1d_in/6 + 1;
3847     aVec[SMDSEntity_Tetra] = nbVols - nbqua*2;
3848     aVec[SMDSEntity_Pyramid] = nbqua;
3849   }
3850   SMESH_subMesh *sm = aMesh.GetSubMesh(aShape);
3851   aResMap.insert(std::make_pair(sm,aVec));
3852
3853   return true;
3854 }
3855
3856 bool HYBRIDPlugin_HYBRID::importGMFMesh(const char* theGMFFileName, SMESH_Mesh& theMesh)
3857 {
3858   SMESH_MesherHelper* helper  = new SMESH_MesherHelper(theMesh );
3859   std::vector <const SMDS_MeshNode*> dummyNodeVector;
3860   std::vector <const SMDS_MeshElement*> aFaceByHybridId;
3861   std::map<const SMDS_MeshNode*,int> dummyNodeMap;
3862   std::map<std::vector<double>, std::string> dummyEnfVertGroup;
3863   std::vector<std::string> dummyElemGroup;
3864   std::set<std::string> dummyGroupsToRemove;
3865
3866   bool ok = readGMFFile(theGMFFileName,
3867                         this,
3868                         helper, dummyNodeVector, aFaceByHybridId, dummyNodeMap, dummyElemGroup, dummyElemGroup, dummyElemGroup, dummyGroupsToRemove);
3869   theMesh.GetMeshDS()->Modified();
3870   return ok;
3871 }
3872
3873 namespace
3874 {
3875   //================================================================================
3876   /*!
3877    * \brief Sub-mesh event listener setting enforced elements as soon as an enforced
3878    *        mesh is loaded
3879    */
3880   struct _EnforcedMeshRestorer : public SMESH_subMeshEventListener
3881   {
3882     _EnforcedMeshRestorer():
3883       SMESH_subMeshEventListener( /*isDeletable = */true, Name() )
3884     {}
3885
3886     //================================================================================
3887     /*!
3888      * \brief Returns an ID of listener
3889      */
3890     static const char* Name() { return "HYBRIDPlugin_HYBRID::_EnforcedMeshRestorer"; }
3891
3892     //================================================================================
3893     /*!
3894      * \brief Treat events of the subMesh
3895      */
3896     void ProcessEvent(const int                       event,
3897                       const int                       eventType,
3898                       SMESH_subMesh*                  subMesh,
3899                       SMESH_subMeshEventListenerData* data,
3900                       const SMESH_Hypothesis*         hyp)
3901     {
3902       if ( SMESH_subMesh::SUBMESH_LOADED == event &&
3903            SMESH_subMesh::COMPUTE_EVENT  == eventType &&
3904            data &&
3905            !data->mySubMeshes.empty() )
3906       {
3907         // An enforced mesh (subMesh->_father) has been loaded from hdf file
3908         if ( HYBRIDPlugin_Hypothesis* hyp = GetGHSHypothesis( data->mySubMeshes.front() ))
3909           hyp->RestoreEnfElemsByMeshes();
3910       }
3911     }
3912     //================================================================================
3913     /*!
3914      * \brief Returns HYBRIDPlugin_Hypothesis used to compute a subMesh
3915      */
3916     static HYBRIDPlugin_Hypothesis* GetGHSHypothesis( SMESH_subMesh* subMesh )
3917     {
3918       SMESH_HypoFilter ghsHypFilter( SMESH_HypoFilter::HasName( "HYBRID_Parameters" ));
3919       return (HYBRIDPlugin_Hypothesis* )
3920         subMesh->GetFather()->GetHypothesis( subMesh->GetSubShape(),
3921                                              ghsHypFilter,
3922                                              /*visitAncestors=*/true);
3923     }
3924   };
3925
3926   //================================================================================
3927   /*!
3928    * \brief Sub-mesh event listener removing empty groups created due to "To make
3929    *        groups of domains".
3930    */
3931   struct _GroupsOfDomainsRemover : public SMESH_subMeshEventListener
3932   {
3933     _GroupsOfDomainsRemover():
3934       SMESH_subMeshEventListener( /*isDeletable = */true,
3935                                   "HYBRIDPlugin_HYBRID::_GroupsOfDomainsRemover" ) {}
3936     /*!
3937      * \brief Treat events of the subMesh
3938      */
3939     void ProcessEvent(const int                       event,
3940                       const int                       eventType,
3941                       SMESH_subMesh*                  subMesh,
3942                       SMESH_subMeshEventListenerData* data,
3943                       const SMESH_Hypothesis*         hyp)
3944     {
3945       if (SMESH_subMesh::ALGO_EVENT == eventType &&
3946           !subMesh->GetAlgo() )
3947       {
3948         removeEmptyGroupsOfDomains( subMesh->GetFather(), /*notEmptyAsWell=*/true );
3949       }
3950     }
3951   };
3952 }
3953
3954 //================================================================================
3955 /*!
3956  * \brief Set an event listener to set enforced elements as soon as an enforced
3957  *        mesh is loaded
3958  */
3959 //================================================================================
3960
3961 void HYBRIDPlugin_HYBRID::SubmeshRestored(SMESH_subMesh* subMesh)
3962 {
3963   if ( HYBRIDPlugin_Hypothesis* hyp = _EnforcedMeshRestorer::GetGHSHypothesis( subMesh ))
3964   {
3965     HYBRIDPlugin_Hypothesis::THYBRIDEnforcedMeshList enfMeshes = hyp->_GetEnforcedMeshes();
3966     HYBRIDPlugin_Hypothesis::THYBRIDEnforcedMeshList::iterator it = enfMeshes.begin();
3967     for(;it != enfMeshes.end();++it) {
3968       HYBRIDPlugin_Hypothesis::THYBRIDEnforcedMesh* enfMesh = *it;
3969       if ( SMESH_Mesh* mesh = GetMeshByPersistentID( enfMesh->persistID ))
3970       {
3971         SMESH_subMesh* smToListen = mesh->GetSubMesh( mesh->GetShapeToMesh() );
3972         // a listener set to smToListen will care of hypothesis stored in SMESH_EventListenerData
3973         subMesh->SetEventListener( new _EnforcedMeshRestorer(),
3974                                    SMESH_subMeshEventListenerData::MakeData( subMesh ),
3975                                    smToListen);
3976       }
3977     }
3978   }
3979 }
3980
3981 //================================================================================
3982 /*!
3983  * \brief Sets an event listener removing empty groups created due to "To make
3984  *        groups of domains".
3985  * \param subMesh - submesh where algo is set
3986  *
3987  * This method is called when a submesh gets HYP_OK algo_state.
3988  * After being set, event listener is notified on each event of a submesh.
3989  */
3990 //================================================================================
3991
3992 void HYBRIDPlugin_HYBRID::SetEventListener(SMESH_subMesh* subMesh)
3993 {
3994   subMesh->SetEventListener( new _GroupsOfDomainsRemover(), 0, subMesh );
3995 }