Salome HOME
Fix PAL8529: get faces from the shape being meshed only.
[plugins/ghs3dplugin.git] / src / GHS3DPlugin_GHS3D.cxx
1 //=============================================================================
2 // File      : GHS3DPlugin_GHS3D.cxx
3 // Created   : 
4 // Author    : Edward AGAPOV
5 // Project   : SALOME
6 // Copyright : CEA 2003
7 // $Header$
8 //=============================================================================
9 using namespace std;
10
11 #include "GHS3DPlugin_GHS3D.hxx"
12 #include "SMESH_Gen.hxx"
13 #include "SMESH_Mesh.hxx"
14
15 #include "SMDS_MeshElement.hxx"
16 #include "SMDS_MeshNode.hxx"
17
18 #include <TopExp_Explorer.hxx>
19 #include <OSD_File.hxx>
20
21 #include "utilities.h"
22
23 #ifndef WIN32
24 #include <sys/sysinfo.h>
25 #endif
26
27
28 #ifdef _DEBUG_
29 #define DUMP(txt) \
30 //  cout << txt
31 #else
32 #define DUMP(txt)
33 #endif
34
35 //=============================================================================
36 /*!
37  *  
38  */
39 //=============================================================================
40
41 GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
42   : SMESH_3D_Algo(hypId, studyId, gen)
43 {
44   MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
45   _name = "GHS3D_3D";
46   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
47 }
48
49 //=============================================================================
50 /*!
51  *  
52  */
53 //=============================================================================
54
55 GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D()
56 {
57   MESSAGE("GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D");
58 }
59
60 //=============================================================================
61 /*!
62  *  
63  */
64 //=============================================================================
65
66 bool GHS3DPlugin_GHS3D::CheckHypothesis
67                          (SMESH_Mesh& aMesh,
68                           const TopoDS_Shape& aShape,
69                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
70 {
71 //  MESSAGE("GHS3DPlugin_GHS3D::CheckHypothesis");
72   aStatus = SMESH_Hypothesis::HYP_OK;
73   return true;
74 }
75
76 //=======================================================================
77 //function : writeFaces
78 //purpose  : 
79 //=======================================================================
80
81 static bool writeFaces (ofstream &            theFile,
82                         SMESHDS_Mesh *        theMesh,
83                         const TopoDS_Shape&   theShape,
84                         const map <int,int> & theSmdsToGhs3dIdMap)
85 {
86   // record structure:
87   //
88   // NB_ELEMS DUMMY_INT
89   // Loop from 1 to NB_ELEMS
90   //   NB_NODES NODE_NB_1 NODE_NB_2 ... (NB_NODES + 1) times: DUMMY_INT
91
92   // get all faces bound to theShape
93   int nbFaces = 0;
94   list< const SMDS_MeshElement* > faces;
95   TopExp_Explorer fExp( theShape, TopAbs_FACE );
96   for ( ; fExp.More(); fExp.Next() ) {
97     SMESHDS_SubMesh* sm = theMesh->MeshElements( fExp.Current() );
98     if ( sm ) {
99       SMDS_ElemIteratorPtr eIt = sm->GetElements();
100       while ( eIt->more() ) {
101         faces.push_back( eIt->next() );
102         nbFaces++;
103       }
104     }
105   }
106
107   if ( nbFaces == 0 )
108     return false;
109
110   const char* space    = "  ";
111   const int   dummyint = 0;
112
113   // NB_ELEMS DUMMY_INT
114   theFile << space << nbFaces << space << dummyint << endl;
115
116   // Loop from 1 to NB_ELEMS
117   list< const SMDS_MeshElement* >::iterator f = faces.begin();
118   for ( ; f != faces.end(); ++f )
119   {
120     // NB_NODES
121     const SMDS_MeshElement* elem = *f;
122     const int nbNodes = elem->NbNodes();
123     theFile << space << nbNodes;
124
125     // NODE_NB_1 NODE_NB_2 ...
126     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
127     while ( nodeIt->more() )
128     {
129       // find GHS3D ID
130       int aSmdsID = nodeIt->next()->GetID();
131       map<int,int>::const_iterator it = theSmdsToGhs3dIdMap.find( aSmdsID );
132       ASSERT( it != theSmdsToGhs3dIdMap.end() );
133       theFile << space << (*it).second;
134     }
135
136     // (NB_NODES + 1) times: DUMMY_INT
137     for ( int i=0; i<=nbNodes; i++)
138       theFile << space << dummyint;
139
140     theFile << endl;
141   }
142
143   return true;
144 }
145
146 //=======================================================================
147 //function : writePoints
148 //purpose  : 
149 //=======================================================================
150
151 static bool writePoints (ofstream &                       theFile,
152                          SMESHDS_Mesh *                   theMesh,
153                          map <int,int> &                  theSmdsToGhs3dIdMap,
154                          map <int,const SMDS_MeshNode*> & theGhs3dIdToNodeMap)
155 {
156   // record structure:
157   //
158   // NB_NODES
159   // Loop from 1 to NB_NODES
160   //   X Y Z DUMMY_INT
161
162   int nbNodes = theMesh->NbNodes();
163   if ( nbNodes == 0 )
164     return false;
165
166   const char* space    = "  ";
167   const int   dummyint = 0;
168
169   // NB_NODES
170   theFile << space << nbNodes << endl;
171
172   // Loop from 1 to NB_NODES
173   int aGhs3dID = 1;
174   SMDS_NodeIteratorPtr it = theMesh->nodesIterator();
175   while ( it->more() )
176   {
177     const SMDS_MeshNode* node = it->next();
178     theSmdsToGhs3dIdMap.insert( map <int,int>::value_type( node->GetID(), aGhs3dID ));
179     theGhs3dIdToNodeMap.insert (map <int,const SMDS_MeshNode*>::value_type( aGhs3dID, node ));
180     aGhs3dID++;
181
182     // X Y Z DUMMY_INT
183     theFile
184       << space << node->X()
185       << space << node->Y()
186       << space << node->Z()
187       << space << dummyint;
188
189     theFile << endl;
190   }
191
192   return true;
193 }
194
195 //=======================================================================
196 //function : getInt
197 //purpose  : 
198 //=======================================================================
199
200 static bool getInt( int & theValue, char * & theLine )
201 {
202   char *ptr;
203   theValue = strtol( theLine, &ptr, 10 );
204   if ( ptr == theLine ||
205       // there must not be neither '.' nor ',' nor 'E' ...
206       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
207     return false;
208
209   DUMP( "  " << theValue );
210   theLine = ptr;
211   return true;
212 }
213
214 //=======================================================================
215 //function : getDouble
216 //purpose  : 
217 //=======================================================================
218
219 static bool getDouble( double & theValue, char * & theLine )
220 {
221   char *ptr;
222   theValue = strtod( theLine, &ptr );
223   if ( ptr == theLine )
224     return false;
225
226   DUMP( "   " << theValue );
227   theLine = ptr;
228   return true;
229 }
230   
231 //=======================================================================
232 //function : readLine
233 //purpose  : 
234 //=======================================================================
235
236 #define GHS3DPlugin_BUFLENGTH 256
237 #define GHS3DPlugin_ReadLine(aPtr,aBuf,aFile,aLineNb) \
238 {  aPtr = fgets( aBuf, GHS3DPlugin_BUFLENGTH - 2, aFile ); aLineNb++; DUMP(endl); }
239
240 //=======================================================================
241 //function : readResult
242 //purpose  : 
243 //=======================================================================
244
245 static bool readResult(FILE *                          theFile,
246                        SMESHDS_Mesh *                  theMesh,
247                        const TopoDS_Shape&             theShape,
248                        map <int,const SMDS_MeshNode*>& theGhs3dIdToNodeMap)
249 {
250   // structure:
251
252   // record 1:
253   //  NB_ELEMENTS NB_NODES NB_INPUT_NODES (14 DUMMY_INT)
254   // record 2:
255   //  (NB_ELEMENTS * 4) node nbs
256   // record 3:
257   //  (NB_NODES) node XYZ
258
259   char aBuffer[ GHS3DPlugin_BUFLENGTH ];
260   char * aPtr;
261   int aLineNb = 0;
262
263   // get shell to set nodes in
264   TopExp_Explorer exp( theShape, TopAbs_SHELL );
265   TopoDS_Shell aShell = TopoDS::Shell( exp.Current() );
266   if ( aShell.IsNull() )
267     return false;
268
269   // ----------------------------------------
270   // record 1:
271   // read nb of generated elements and nodes
272   // ----------------------------------------
273   int nbElems = 0 , nbNodes = 0, nbInputNodes = 0;
274   GHS3DPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
275   if (!aPtr ||
276       !getInt( nbElems, aPtr ) ||
277       !getInt( nbNodes, aPtr ) ||
278       !getInt( nbInputNodes, aPtr))
279     return false;
280
281   // -------------------------------------------
282   // record 2:
283   // read element nodes and create tetrahedrons
284   // -------------------------------------------
285   GHS3DPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
286   for (int iElem = 0; iElem < nbElems; iElem++)
287   {
288     // read 4 nodes
289     const SMDS_MeshNode * node[4];
290     for (int iNode = 0; iNode < 4; iNode++)
291     {
292       // read Ghs3d node ID
293       int ID = 0;
294       if (!aPtr || ! getInt ( ID, aPtr ))
295       {
296         GHS3DPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
297         if (!aPtr || ! getInt ( ID, aPtr ))
298         {
299           MESSAGE( "Cant read " << (iNode+1) << "-th node on line " << aLineNb );
300           return false;
301         }
302       }
303       // find/create a node with ID
304       map <int,const SMDS_MeshNode*>::iterator IdNode = theGhs3dIdToNodeMap.find( ID );
305       if ( IdNode == theGhs3dIdToNodeMap.end())
306       {
307         // ID is not yet in theGhs3dIdToNodeMap
308         ASSERT ( ID > nbInputNodes ); // it should be a new one
309         SMDS_MeshNode * aNewNode = theMesh->AddNode( 0.,0.,0. ); // read XYZ later
310         theMesh->SetNodeInVolume( aNewNode, aShell );
311         theGhs3dIdToNodeMap.insert
312           ( map <int,const SMDS_MeshNode*>::value_type( ID, aNewNode ));
313         node[ iNode ] = aNewNode;
314       }
315       else
316       {
317         node[ iNode ] = (*IdNode).second;
318       }
319     }
320     // create a tetrahedron with orientation as for MED
321     SMDS_MeshElement* aTet = theMesh->AddVolume( node[1], node[0], node[2], node[3] );
322     theMesh->SetMeshElementOnShape( aTet, theShape );
323   }
324
325   // ------------------------
326   // record 3:
327   // read and set nodes' XYZ
328   // ------------------------
329   GHS3DPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
330   for (int iNode = 0; iNode < nbNodes; iNode++)
331   {
332     // read 3 coordinates
333     double coord [3];
334     for (int iCoord = 0; iCoord < 3; iCoord++)
335     {
336       if (!aPtr || ! getDouble ( coord[ iCoord ], aPtr ))
337       {
338         GHS3DPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
339         if (!aPtr || ! getDouble ( coord[ iCoord ], aPtr ))
340         {
341           MESSAGE( "Cant read " << (iCoord+1) << "-th node coord on line " << aLineNb );
342           return false;
343         }
344       }
345     }
346     // do not move old nodes
347     int ID = iNode + 1;
348     if (ID <= nbInputNodes)
349       continue;
350     // find a node
351     map <int,const SMDS_MeshNode*>::iterator IdNode = theGhs3dIdToNodeMap.find( ID );
352     ASSERT ( IdNode != theGhs3dIdToNodeMap.end());
353     SMDS_MeshNode* node = const_cast<SMDS_MeshNode*> ( (*IdNode).second );
354
355     // set XYZ
356     theMesh->MoveNode( node, coord[0], coord[1], coord[2] );
357   }
358
359   return nbElems;
360 }
361
362 //=======================================================================
363 //function : getTmpDir
364 //purpose  : 
365 //=======================================================================
366
367 static TCollection_AsciiString getTmpDir()
368 {
369   TCollection_AsciiString aTmpDir;
370
371   char *Tmp_dir = getenv("SALOME_TMP_DIR");
372   if(Tmp_dir != NULL) {
373     aTmpDir = Tmp_dir;
374 #ifdef WIN32
375     if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
376 #else
377     if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
378 #endif      
379   }
380   else {
381 #ifdef WIN32
382     aTmpDir = TCollection_AsciiString("C:\\");
383 #else
384     aTmpDir = TCollection_AsciiString("/tmp/");
385 #endif
386   }
387   return aTmpDir;
388 }
389
390 //=============================================================================
391 /*!
392  *Here we are going to use the GHS3D mesher
393  */
394 //=============================================================================
395
396 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
397                                 const TopoDS_Shape& theShape)
398 {
399   MESSAGE("GHS3DPlugin_GHS3D::Compute");
400
401   SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
402
403   // make a unique working file name
404   // to avoid access to the same files by eg different users
405   
406   TCollection_AsciiString aGenericName, aTmpDir = getTmpDir();
407   aGenericName = aTmpDir + "GHS3D_";
408 #ifdef WIN32
409   aGenericName += GetCurrentProcessId();
410 #else
411   aGenericName += getpid();
412 #endif
413   aGenericName += "_";
414   aGenericName += meshDS->ShapeToIndex( theShape );
415
416   TCollection_AsciiString aFacesFileName, aPointsFileName, aResultFileName;
417   TCollection_AsciiString aBadResFileName, aBbResFileName, aLogFileName;
418   aFacesFileName  = aGenericName + ".faces";  // in faces
419   aPointsFileName = aGenericName + ".points"; // in points
420   aResultFileName = aGenericName + ".noboite";// out points and volumes
421   aBadResFileName = aGenericName + ".boite";  // out bad result
422   aBbResFileName  = aGenericName + ".bb";     // out vertex stepsize
423   aLogFileName    = aGenericName + ".log";    // log
424
425   // -----------------
426   // make input files
427   // -----------------
428
429   ofstream aFacesFile  ( aFacesFileName.ToCString()  , ios::out);
430   ofstream aPointsFile ( aPointsFileName.ToCString() , ios::out);
431   bool Ok =
432 #ifdef WIN32
433     aFacesFile->is_open() && aPointsFile->is_open();
434 #else
435     aFacesFile.rdbuf()->is_open() && aPointsFile.rdbuf()->is_open();
436 #endif
437   if (!Ok)
438   {
439     INFOS( "Can't write into " << aTmpDir.ToCString());
440     return false;
441   }
442   map <int,int> aSmdsToGhs3dIdMap;
443   map <int,const SMDS_MeshNode*> aGhs3dIdToNodeMap;
444
445   Ok =
446     (writePoints( aPointsFile, meshDS, aSmdsToGhs3dIdMap, aGhs3dIdToNodeMap ) &&
447      writeFaces ( aFacesFile, meshDS, theShape, aSmdsToGhs3dIdMap ));
448
449   aFacesFile.close();
450   aPointsFile.close();
451
452   if ( ! Ok ) {
453     if ( !getenv("GHS3D_KEEP_FILES") ) {
454       OSD_File( aFacesFileName ).Remove();
455       OSD_File( aPointsFileName ).Remove();
456     }
457     return false;
458   }
459
460   // -----------------
461   // run ghs3d mesher              WIN32???
462   // -----------------
463
464   // ghs3d need to know amount of memory it may use (MB).
465   // Default memory is defined at ghs3d installation but it may be not enough,
466   // so allow to use about all available memory
467   TCollection_AsciiString memory;
468 #ifndef WIN32
469   struct sysinfo si;
470   int err = sysinfo( &si );
471   if ( err == 0 ) {
472     memory = "-m ";
473     memory += int ( 0.8 * ( si.freeram + si.freeswap ) * si.mem_unit / 1024 / 1024 );
474   }
475 #endif
476
477   TCollection_AsciiString cmd( "ghs3d " ); // command to run
478   cmd +=
479     memory +                   // memory
480       " -f " + aGenericName +  // file to read
481         " 1>" + aLogFileName;  // dump into file
482
483   system( cmd.ToCString() ); // run
484
485   // --------------
486   // read a result
487   // --------------
488
489   FILE * aResultFile = fopen( aResultFileName.ToCString(), "r" );
490   if (aResultFile)
491   {
492     Ok = readResult( aResultFile, meshDS, theShape, aGhs3dIdToNodeMap );
493     fclose(aResultFile);
494   }
495   else
496     Ok = false;
497
498   // ---------------------
499   // remove working files
500   // ---------------------
501
502   if ( Ok ) {
503     OSD_File( aLogFileName ).Remove();
504   }
505   else if ( OSD_File( aLogFileName ).Size() > 0 ) {
506     INFOS( "GHS3D Error: see " << aLogFileName.ToCString() );
507   }
508   else {
509     OSD_File( aLogFileName ).Remove();
510     INFOS( "GHS3D Error: command '" << cmd.ToCString() << "' failed" );
511   }
512
513   if ( !getenv("GHS3D_KEEP_FILES") )
514   {
515     OSD_File( aFacesFileName ).Remove();
516     OSD_File( aPointsFileName ).Remove();
517     OSD_File( aResultFileName ).Remove();
518     OSD_File( aBadResFileName ).Remove();
519     OSD_File( aBbResFileName ).Remove();
520   }
521   
522   return Ok;
523 }
524
525
526 //=============================================================================
527 /*!
528  *  
529  */
530 //=============================================================================
531
532 ostream & GHS3DPlugin_GHS3D::SaveTo(ostream & save)
533 {
534   return save;
535 }
536
537 //=============================================================================
538 /*!
539  *  
540  */
541 //=============================================================================
542
543 istream & GHS3DPlugin_GHS3D::LoadFrom(istream & load)
544 {
545   return load;
546 }
547
548 //=============================================================================
549 /*!
550  *  
551  */
552 //=============================================================================
553
554 ostream & operator << (ostream & save, GHS3DPlugin_GHS3D & hyp)
555 {
556   return hyp.SaveTo( save );
557 }
558
559 //=============================================================================
560 /*!
561  *  
562  */
563 //=============================================================================
564
565 istream & operator >> (istream & load, GHS3DPlugin_GHS3D & hyp)
566 {
567   return hyp.LoadFrom( load );
568 }