Salome HOME
Import a new plugin, sent by Stephane LIAUZU
[plugins/hexoticplugin.git] / src / HexoticPlugin / HexoticPlugin_Hexotic.cxx
1 //  HexoticPlugin : C++ implementation
2 //
3 //  Copyright (C) 2006  OPEN CASCADE, CEA/DEN, EDF R&D
4 // 
5 //  This library is free software; you can redistribute it and/or 
6 //  modify it under the terms of the GNU Lesser General Public 
7 //  License as published by the Free Software Foundation; either 
8 //  version 2.1 of the License. 
9 // 
10 //  This library is distributed in the hope that it will be useful, 
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
13 //  Lesser General Public License for more details. 
14 // 
15 //  You should have received a copy of the GNU Lesser General Public 
16 //  License along with this library; if not, write to the Free Software 
17 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
18 // 
19 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
20 //
21 //
22 // File    : HexoticPlugin_Hexotic.cxx
23 // Author  : Lioka RAZAFINDRAZAKA (CEA)
24 // Date    : 2006/06/30
25 // Project : SALOME
26 //=============================================================================
27 using namespace std;
28
29 #include "HexoticPlugin_Hexotic.hxx"
30 #include "HexoticPlugin_Hypothesis.hxx"
31 // #include "HexoticPlugin_Mesher.hxx"
32
33 #include "SMDS_MeshElement.hxx"
34 #include "SMDS_MeshNode.hxx"
35
36 #include <TopExp_Explorer.hxx>
37 #include <OSD_File.hxx>
38
39 #include "utilities.h"
40
41 #ifndef WIN32
42 #include <sys/sysinfo.h>
43 #endif
44
45 #ifdef _DEBUG_
46 #define DUMP(txt) \
47 //  cout << txt
48 #else
49 #define DUMP(txt)
50 #endif
51
52 #include <SMESH_Gen.hxx>
53 #include <SMESHDS_Mesh.hxx>
54 #include <SMESH_ControlsDef.hxx>
55
56 #include <list>
57
58 //=============================================================================
59 /*!
60  *  
61  */
62 //=============================================================================
63
64 HexoticPlugin_Hexotic::HexoticPlugin_Hexotic(int hypId, int studyId, SMESH_Gen* gen)
65   : SMESH_3D_Algo(hypId, studyId, gen)
66 {
67   MESSAGE("HexoticPlugin_Hexotic::HexoticPlugin_Hexotic");
68   _name = "Hexotic_3D";
69   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
70   _iShape=0;
71   _nbShape=0;
72   _nodeRefNumber=0;
73   _compatibleHypothesis.push_back("Hexotic_Parameters");
74 }
75
76 //=============================================================================
77 /*!
78  *  
79  */
80 //=============================================================================
81
82 HexoticPlugin_Hexotic::~HexoticPlugin_Hexotic()
83 {
84   MESSAGE("HexoticPlugin_Hexotic::~HexoticPlugin_Hexotic");
85 }
86
87 //=============================================================================
88 /*!
89  *  
90  */
91 //=============================================================================
92
93 bool HexoticPlugin_Hexotic::CheckHypothesis( SMESH_Mesh&                          aMesh,
94                                              const TopoDS_Shape&                  aShape,
95                                              SMESH_Hypothesis::Hypothesis_Status& aStatus )
96 {
97   // MESSAGE("HexoticPlugin_Hexotic::CheckHypothesis");
98
99   _hypothesis = NULL;
100
101   list<const SMESHDS_Hypothesis*>::const_iterator itl;
102   const SMESHDS_Hypothesis* theHyp;
103
104   const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
105   int nbHyp = hyps.size();
106   if (!nbHyp)
107   {
108     aStatus = SMESH_Hypothesis::HYP_OK;
109     return true;  // can work with no hypothesis
110   }
111
112   itl = hyps.begin();
113   theHyp = (*itl); // use only the first hypothesis
114
115   string hypName = theHyp->GetName();
116   if (hypName == "Hexotic_Parameters")
117   {
118     _hypothesis = static_cast<const HexoticPlugin_Hypothesis*> (theHyp);
119     ASSERT(_hypothesis);
120     aStatus = SMESH_Hypothesis::HYP_OK;
121   }
122   else
123     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
124
125   return aStatus == SMESH_Hypothesis::HYP_OK;
126 }
127
128 //=======================================================================
129 //function : countFaces
130 //purpose  : 
131 //=======================================================================
132
133 static int countFaces( SMESHDS_Mesh*                    the2DMesh,
134                        list< const SMDS_MeshElement* >& theListOfFaces,
135                        bool                             externalFaces )
136 {
137   int nbFaces = 0;
138   TopExp_Explorer fExp( (the2DMesh->ShapeToMesh()), TopAbs_FACE );
139   SMESHDS_SubMesh* the2DSubMesh;
140   SMDS_ElemIteratorPtr itOnSmdsElement;
141
142   if ( externalFaces )
143     nbFaces = the2DMesh->NbFaces();
144   else {
145     for ( ; fExp.More(); fExp.Next() ) {
146       the2DSubMesh = the2DMesh->MeshElements( fExp.Current() );
147       if ( the2DSubMesh ) {
148         itOnSmdsElement = the2DSubMesh->GetElements();
149         while ( itOnSmdsElement->more() ) {
150           theListOfFaces.push_back( itOnSmdsElement->next() );
151           nbFaces++;
152         }
153       }
154     }
155   }
156   return nbFaces;
157 }
158
159 //=======================================================================
160 //function : writeHexoticFile
161 //purpose  : 
162 //=======================================================================
163
164 static bool writeHexoticFile (ofstream &                      theFile,
165                              SMESHDS_Mesh *                   theMesh,
166                              map <int,int> &                  theSmdsToHexoticIdMap,
167                              map <int,const SMDS_MeshNode*> & theHexoticIdToNodeMap,
168                              const TCollection_AsciiString &  Hexotic_In) {
169   cout << endl;
170   cout << "Creating Hexotic processed mesh file : " << Hexotic_In << endl;
171
172   bool onlyExternalFaces = true;
173   int nbVertices         = 0;
174   int nbTriangles        = 0;
175   const char* space      = "  ";
176   const int   dummyint   = 0;
177
178   int aSmdsNodeID = 1;
179   const SMDS_MeshNode* aNode;
180   SMDS_NodeIteratorPtr itOnNode;
181
182   list< const SMDS_MeshElement* > faces;
183   list< const SMDS_MeshElement* >::iterator itListFace;
184   const SMDS_MeshElement* aFace;
185   map<int,int>::const_iterator itOnSmdsNode;
186   SMDS_ElemIteratorPtr itOnSmdsElement;
187   SMDS_ElemIteratorPtr itOnFaceNode;
188   SMDS_FaceIteratorPtr itOnSmdsFace;
189
190 // Writing SMESH points into Hexotic File
191
192   nbVertices = theMesh->NbNodes();
193
194   theFile << "MeshVersionFormatted 1" << endl;
195   theFile << endl;
196   theFile << "Dimension" << endl;
197   theFile << 3 << endl;
198   theFile << "# Set of mesh vertices" << endl;
199   theFile << "Vertices" << endl;
200   theFile << nbVertices << endl;
201
202   itOnNode = theMesh->nodesIterator();
203   while ( itOnNode->more() ) {
204       aNode = itOnNode->next();
205       theSmdsToHexoticIdMap.insert( map <int,int>::value_type( aNode->GetID(), aSmdsNodeID ));
206       theHexoticIdToNodeMap.insert (map <int,const SMDS_MeshNode*>::value_type( aSmdsNodeID, aNode ));
207       aSmdsNodeID++;
208       theFile << aNode->X() << space << aNode->Y() << space << aNode->Z() << space << dummyint << endl;
209       }
210
211 // Writing SMESH faces into Hexotic File
212
213   nbTriangles = countFaces(theMesh, faces, onlyExternalFaces);
214
215   theFile << endl;
216   theFile << "# Set of mesh triangles (v1,v2,v3,tag)" << endl;
217   theFile << "Triangles" << endl;
218   theFile << nbTriangles << endl;
219
220   if ( onlyExternalFaces ) {
221     itOnSmdsFace = theMesh->facesIterator();
222     while ( itOnSmdsFace->more() ) {
223       aFace = itOnSmdsFace->next();
224       itOnFaceNode = aFace->nodesIterator();
225       while ( itOnFaceNode->more() ) {
226         aSmdsNodeID = itOnFaceNode->next()->GetID();
227         itOnSmdsNode = theSmdsToHexoticIdMap.find( aSmdsNodeID );
228         ASSERT( itOnSmdsNode != theSmdsToHexoticIdMap.end() );
229         theFile << (*itOnSmdsNode).second << space;
230       }
231       theFile << dummyint << endl;
232     }
233   }
234   else {
235     itListFace = faces.begin();
236     for ( ; itListFace != faces.end(); ++itListFace ) {
237       aFace = *itListFace;
238       itOnFaceNode = aFace->nodesIterator();
239       while ( itOnFaceNode->more() ) {
240         aSmdsNodeID = itOnFaceNode->next()->GetID();
241         itOnSmdsNode = theSmdsToHexoticIdMap.find( aSmdsNodeID );
242         ASSERT( itOnSmdsNode != theSmdsToHexoticIdMap.end() );
243         theFile << (*itOnSmdsNode).second << space;
244       }
245       theFile << dummyint << endl;
246     }
247   }
248
249   theFile << endl;
250   theFile << "End" << endl;
251
252   cout << "Processed mesh file created, it contains :" << endl;
253   cout << "    " << nbVertices  << " vertices"  << endl;
254   cout << "    " << nbTriangles << " triangles" << endl;
255   cout << endl;
256
257   return true;
258 }
259
260 //=======================================================================
261 //function : getInt
262 //purpose  : 
263 //=======================================================================
264
265 static bool getInt( int & theValue, char * & theLine )
266 {
267   char *ptr;
268   theValue = strtol( theLine, &ptr, 10 );
269   if ( ptr == theLine ||
270       // there must not be neither '.' nor ',' nor 'E' ...
271       (*ptr != ' ' && *ptr != '\n' && *ptr != '\0'))
272     return false;
273
274   DUMP( "  " << theValue );
275   theLine = ptr;
276   return true;
277 }
278
279 //=======================================================================
280 //function : getDouble
281 //purpose  : 
282 //=======================================================================
283
284 static bool getDouble( double & theValue, char * & theLine )
285 {
286   char *ptr;
287   theValue = strtod( theLine, &ptr );
288   if ( ptr == theLine )
289     return false;
290
291   DUMP( "   " << theValue );
292   theLine = ptr;
293   return true;
294 }
295   
296 //=======================================================================
297 //function : readLine
298 //purpose  : 
299 //=======================================================================
300
301 #define HexoticPlugin_BUFLENGTH 256
302 #define HexoticPlugin_ReadLine(aPtr,aBuf,aFile,aLineNb) \
303 {  aPtr = fgets( aBuf, HexoticPlugin_BUFLENGTH - 2, aFile ); aLineNb++; DUMP(endl); }
304
305 //=======================================================================
306 //function : readResult
307 //purpose  : 
308 //=======================================================================
309
310 static bool readResult(FILE *                           theFile,
311                        SMESHDS_Mesh *                   theMesh,
312                        const TopoDS_Shape &             theShape,
313                        map <int,const SMDS_MeshNode*> & theHexoticIdToNodeMap,
314                        const TCollection_AsciiString &  Hexotic_Out,
315                        int &                            nodeRefNumber)
316 {
317   // ---------------------------------
318   // Read generated elements and nodes
319   // ---------------------------------
320
321   cout << "Reading Hexotic output file : " << Hexotic_Out << endl;
322   cout << endl;
323
324   char aBuffer[ HexoticPlugin_BUFLENGTH ];
325   char * aPtr;
326   int aLineNb = 0;
327   int shapeID = theMesh->ShapeToIndex( theShape );
328
329   int line = 1, EndOfFile = 0, nbElem = 0, nField = 10, nbRef = 0, aHexoticNodeID = 0;
330   char * theField;
331
332   char * tabField [nField];
333   int    tabRef [nField];
334
335   tabField[0] = "MeshVersionFormatted";    tabRef[0] = 0;
336   tabField[1] = "Dimension";               tabRef[1] = 0;
337   tabField[2] = "Vertices";                tabRef[2] = 3;
338   tabField[3] = "Edges";                   tabRef[3] = 2;
339   tabField[4] = "Triangles";               tabRef[4] = 3;
340   tabField[5] = "Quadrilaterals";          tabRef[5] = 4;
341   tabField[6] = "Hexahedra";               tabRef[6] = 8;
342   tabField[7] = "Corners";                 tabRef[7] = 1;
343   tabField[8] = "Ridges";                  tabRef[0] = 1;
344   tabField[9] = "End";                     tabRef[0] = 0;
345
346   nodeRefNumber += theMesh->NbNodes();
347
348   SMDS_NodeIteratorPtr itOnHexoticInputNode = theMesh->nodesIterator();
349   while ( itOnHexoticInputNode->more() )
350     theMesh->RemoveNode( itOnHexoticInputNode->next() );
351
352   while ( EndOfFile == 0  ) {
353     HexoticPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
354     for ( int iField = 0; iField < nField; iField++ ) {
355       stringstream theMessage;
356       theField = tabField[iField];
357       if ( strncmp(aPtr, theField, strlen(theField)) == 0 ) {
358         if ( strcmp(theField, "End") == 0 ) {
359           EndOfFile = 1;
360           theMessage << "End of Hexotic output file has been reached";
361         }
362         else {
363           HexoticPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );
364           line++;
365           getInt( nbElem, aPtr );
366
367           if ( strcmp(theField, "MeshVersionFormatted") == 0 )
368             theMessage << "Hexotic mesh descriptor : " << theField << " " << nbElem;
369           else if ( strcmp(theField, "Dimension") == 0 )
370             theMessage << "Hexotic mesh of " << nbElem << "D dimension";
371           else if ( strcmp(theField, "Vertices")       == 0 ||
372                     strcmp(theField, "Edges")          == 0 ||
373                     strcmp(theField, "Quadrilaterals") == 0 ||
374                     strcmp(theField, "Hexahedra")      == 0 ) {
375             nbRef = tabRef[iField];
376             HexoticPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );           // read blank line
377
378             if ( strcmp(theField, "Vertices") == 0 ) {
379               int aHexoticID;
380               double coord[nbRef];
381               SMDS_MeshNode * aHexoticNode;
382
383               for ( int iElem = 0; iElem < nbElem; iElem++ ) {
384                 aHexoticID = iElem + 1 + nodeRefNumber;
385                 HexoticPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );   // read file lines
386                 for ( int iCoord = 0; iCoord < 3; iCoord++ )
387                   getDouble ( coord[ iCoord ], aPtr );
388                 aHexoticNode = theMesh->AddNode(coord[0], coord[1], coord[2]);
389                 theMesh->SetNodeInVolume( aHexoticNode, shapeID );
390                 theHexoticIdToNodeMap[ aHexoticID ] = aHexoticNode;
391               }
392             }
393             else {
394               const SMDS_MeshNode * node[nbRef];
395               SMDS_MeshElement* aHexoticElement;
396               map <int,const SMDS_MeshNode*>::iterator itOnHexoticNode;
397
398               for ( int iElem = 0; iElem < nbElem; iElem++ ) {
399                 HexoticPlugin_ReadLine( aPtr, aBuffer, theFile, aLineNb );   // read file lines
400                 for ( int iRef = 0; iRef < nbRef; iRef++ ) {
401                   getInt ( aHexoticNodeID, aPtr );                         // read nbRef aHexoticNodeID
402                   aHexoticNodeID += nodeRefNumber;
403                   itOnHexoticNode = theHexoticIdToNodeMap.find( aHexoticNodeID );
404                   node[ iRef ] = itOnHexoticNode->second;
405                 }
406
407                 if ( strcmp(theField, "Edges") == 0 )                        // create an element
408                   aHexoticElement = theMesh->AddEdge( node[0], node[1] );
409                 else if ( strcmp(theField, "Quadrilaterals") == 0 )
410                   aHexoticElement = theMesh->AddFace( node[0], node[1], node[2], node[3] );
411                 else if ( strcmp(theField, "Hexahedra") == 0 )
412                   aHexoticElement = theMesh->AddVolume( node[0], node[1], node[2], node[3], node[4], node[5], node[6], node[7] );
413
414                 theMesh->SetMeshElementOnShape( aHexoticElement, shapeID );
415               }
416             }
417             theMessage << nbElem << " " << theField << " created";
418           }
419         }
420         if ( theMessage.str().size() != 0 ) {
421           cout << theMessage.str() << endl;
422           break;
423         }
424       }
425     }
426   }
427   cout << endl;
428   return true;
429 }
430
431 //=============================================================================
432 /*!
433  * Pass parameters to Hexotic
434  */
435 //=============================================================================
436
437 void HexoticPlugin_Hexotic::SetParameters(const HexoticPlugin_Hypothesis* hyp) {
438   if (hyp) {
439     MESSAGE("HexoticPlugin_Hexotic::SetParameters");
440     _hexesMinLevel = hyp->GetHexesMinLevel();
441     _hexesMaxLevel = hyp->GetHexesMaxLevel();
442     _hexoticQuadrangles = hyp->GetHexoticQuadrangles();
443   }
444 }
445
446 //=======================================================================
447 //function : getTmpDir
448 //purpose  : 
449 //=======================================================================
450
451 static TCollection_AsciiString getTmpDir()
452 {
453   TCollection_AsciiString aTmpDir;
454
455   char *Tmp_dir = getenv("SALOME_TMP_DIR");
456   if(Tmp_dir != NULL) {
457     aTmpDir = Tmp_dir;
458     #ifdef WIN32
459       if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
460     #else
461       if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
462     #endif      
463   }
464   else {
465     #ifdef WIN32
466       aTmpDir = TCollection_AsciiString("C:\\");
467     #else
468       aTmpDir = TCollection_AsciiString("/tmp/");
469     #endif
470   }
471   return aTmpDir;
472 }
473
474 //=============================================================================
475 /*!
476  * Here we are going to use the Hexotic mesher
477  */
478 //=============================================================================
479
480 bool HexoticPlugin_Hexotic::Compute(SMESH_Mesh&          theMesh,
481                                      const TopoDS_Shape& theShape)
482 {
483   bool Ok;
484   SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
485
486   if (_iShape == 0 && _nbShape == 0) {
487     cout << endl;
488     cout << "Hexotic execution..." << endl;
489     cout << endl;
490
491     TopExp_Explorer expf(meshDS->ShapeToMesh(), TopAbs_SOLID);
492     for ( ; expf.More(); expf.Next() )
493         _nbShape++;
494   }
495
496   _iShape++;
497
498   if (_iShape == _nbShape ) {
499     SetParameters(_hypothesis);
500
501     cout << endl;
502     cout << _name << " parameters :" << endl;
503     cout << "    " << _name << " Segments Min Level = " << _hexesMinLevel << endl;
504     cout << "    " << _name << " Segments Max Level = " << _hexesMaxLevel << endl;
505     cout << "    " << "Salome Quadrangles : " << (_hexoticQuadrangles ? "yes":"no") << endl;
506
507     TCollection_AsciiString aTmpDir = getTmpDir();
508     TCollection_AsciiString Hexotic_In, Hexotic_Out;
509     TCollection_AsciiString run_Hexotic( "hexotic" );
510
511     TCollection_AsciiString minl = " -minl ", maxl = " -maxl ";
512     TCollection_AsciiString in   = " -in ",   out  = " -out ";
513
514     TCollection_AsciiString minLevel, maxLevel;
515     minLevel = _hexesMinLevel;
516     maxLevel = _hexesMaxLevel;
517
518     map <int,int> aSmdsToHexoticIdMap;
519     map <int,const SMDS_MeshNode*> aHexoticIdToNodeMap;
520
521     Hexotic_In  = aTmpDir + "Hexotic_In.mesh";
522     Hexotic_Out = aTmpDir + "Hexotic_Out.mesh";
523     run_Hexotic += minl + minLevel + maxl + maxLevel + in + Hexotic_In + out + Hexotic_Out;
524
525     // cout << "Hexotic command : " << run_Hexotic << endl;
526
527     OSD_File( Hexotic_In  ).Remove();
528     OSD_File( Hexotic_Out ).Remove();
529
530     ofstream HexoticFile (Hexotic_In.ToCString() , ios::out);
531
532     Ok = ( writeHexoticFile(HexoticFile, meshDS, aSmdsToHexoticIdMap, aHexoticIdToNodeMap, Hexotic_In) );
533     HexoticFile.close();
534
535     MESSAGE("HexoticPlugin_Hexotic::Compute");
536
537     system( run_Hexotic.ToCString() );
538
539     // --------------
540     // read a result
541     // --------------
542
543     FILE * aResultFile = fopen( Hexotic_Out.ToCString(), "r" );
544     if (aResultFile) {
545       Ok = readResult( aResultFile, meshDS, theShape, aHexoticIdToNodeMap, Hexotic_Out, _nodeRefNumber );
546       fclose(aResultFile);
547       cout << "Hexotic output file read !" << endl;
548       cout << endl;
549     }
550     else
551       Ok = false;
552     _iShape=0;
553   }
554   return Ok;
555 }
556
557 //=============================================================================
558 /*!
559  *  
560  */
561 //=============================================================================
562
563 ostream & HexoticPlugin_Hexotic::SaveTo(ostream & save)
564 {
565   return save;
566 }
567
568 //=============================================================================
569 /*!
570  *  
571  */
572 //=============================================================================
573
574 istream & HexoticPlugin_Hexotic::LoadFrom(istream & load)
575 {
576   return load;
577 }
578
579 //=============================================================================
580 /*!
581  *  
582  */
583 //=============================================================================
584
585 ostream & operator << (ostream & save, HexoticPlugin_Hexotic & hyp)
586 {
587   return hyp.SaveTo( save );
588 }
589
590 //=============================================================================
591 /*!
592  *  
593  */
594 //=============================================================================
595
596 istream & operator >> (istream & load, HexoticPlugin_Hexotic & hyp)
597 {
598   return hyp.LoadFrom( load );
599 }