]> SALOME platform Git repositories - plugins/ghs3dplugin.git/blob - src/GHS3DPlugin_GHS3D.cxx
Salome HOME
Restore code lost in revision 1.9.6.5
[plugins/ghs3dplugin.git] / src / GHS3DPlugin_GHS3D.cxx
1 // Copyright (C) 2005  CEA/DEN, EDF R&D, OPEN CASCADE, PRINCIPIA 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 // File      : GHS3DPlugin_GHS3D.cxx
21 // Created   : 
22 // Author    : Edward AGAPOV, modified by Lioka RAZAFINDRAZAKA (CEA) 09/02/2007
23 // Project   : SALOME
24 // Copyright : CEA 2003
25 // $Header$
26 //=============================================================================
27 using namespace std;
28
29 #include "GHS3DPlugin_GHS3D.hxx"
30 #include "SMESH_Gen.hxx"
31 #include "SMESH_Mesh.hxx"
32 #include "SMESH_Comment.hxx"
33
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36
37 #include <TopExp_Explorer.hxx>
38 #include <OSD_File.hxx>
39
40 #include "utilities.h"
41
42 #ifndef WIN32
43 #include <sys/sysinfo.h>
44 #endif
45
46 //#include <Standard_Stream.hxx>
47
48 #include <BRepGProp.hxx>
49 #include <BRepBndLib.hxx>
50 #include <BRepClass_FaceClassifier.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <TopAbs.hxx>
53 #include <Bnd_Box.hxx>
54 #include <GProp_GProps.hxx>
55 #include <Precision.hxx>
56
57 #define castToNode(n) static_cast<const SMDS_MeshNode *>( n );
58
59 #ifdef _DEBUG_
60 #define DUMP(txt) \
61 //  cout << txt
62 #else
63 #define DUMP(txt)
64 #endif
65
66 extern "C"
67 {
68 #ifndef WNT
69 #include <unistd.h>
70 #include <sys/mman.h>
71 #endif
72 #include <sys/stat.h>
73 #include <fcntl.h>
74 }
75
76 //=============================================================================
77 /*!
78  *  
79  */
80 //=============================================================================
81
82 GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
83   : SMESH_3D_Algo(hypId, studyId, gen)
84 {
85   MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
86   _name = "GHS3D_3D";
87   _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
88   _onlyUnaryInput = false; // Compute() will be called on a compound of solids
89 //   _iShape=0;
90 //   _nbShape=0;
91 }
92
93 //=============================================================================
94 /*!
95  *  
96  */
97 //=============================================================================
98
99 GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D()
100 {
101   MESSAGE("GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D");
102 }
103
104 //=============================================================================
105 /*!
106  *  
107  */
108 //=============================================================================
109
110 bool GHS3DPlugin_GHS3D::CheckHypothesis ( SMESH_Mesh&                          aMesh,
111                                           const TopoDS_Shape&                  aShape,
112                                           SMESH_Hypothesis::Hypothesis_Status& aStatus )
113 {
114 //  MESSAGE("GHS3DPlugin_GHS3D::CheckHypothesis");
115   aStatus = SMESH_Hypothesis::HYP_OK;
116   return true;
117 }
118
119 //================================================================================
120 /*!
121  * \brief Write faces bounding theShape to file
122  */
123 //================================================================================
124
125 static bool writeFaces (ofstream &                      theFile,
126                         SMESHDS_Mesh *                  theMesh,
127                         const TopoDS_Shape&             theShape,
128                         vector <const SMDS_MeshNode*> & theNodeByGhs3dId)
129 {
130   // record structure:
131   //
132   // NB_ELEMS DUMMY_INT
133   // Loop from 1 to NB_ELEMS
134   // NB_NODES NODE_NB_1 NODE_NB_2 ... (NB_NODES + 1) times: DUMMY_INT
135
136   // get all faces bound to theShape
137
138   // Solids in the ShapeToMesh() can be meshed by different meshers,
139   // so we take faces only from the given shape
140   //TopoDS_Shape theShape = theMesh->ShapeToMesh();
141   int nbFaces = 0;
142   list< const SMDS_MeshElement* > faces;
143   // Use TopTools_IndexedMapOfShape in order not to take twice mesh faces from
144   // a geom face shared by two solids
145   TopTools_IndexedMapOfShape faceMap;
146   TopExp::MapShapes( theShape, TopAbs_FACE, faceMap );
147   SMESHDS_SubMesh* sm;
148   SMDS_ElemIteratorPtr eIt;
149
150   const char* space    = "  ";
151   const int   dummyint = 0;
152
153   list< const SMDS_MeshElement* >::iterator f;
154   map< const SMDS_MeshNode*,int >::iterator it;
155   SMDS_ElemIteratorPtr nodeIt;
156   const SMDS_MeshElement* elem;
157   int nbNodes;
158   //int aSmdsID;
159
160   for ( int i = 0; i < faceMap.Extent(); ++i ) {
161     sm = theMesh->MeshElements( faceMap( i+1 ) );
162     if ( sm ) {
163       eIt = sm->GetElements();
164       while ( eIt->more() ) {
165         faces.push_back( eIt->next() );
166         nbFaces++;
167       }
168     }
169   }
170
171   if ( nbFaces == 0 )
172     return false;
173
174   cout << "The initial 2D mesh contains " << nbFaces << " faces and ";
175
176   // NB_ELEMS DUMMY_INT
177   theFile << space << nbFaces << space << dummyint << endl;
178
179   // Loop from 1 to NB_ELEMS
180
181   map<const SMDS_MeshNode*,int> aNodeToGhs3dIdMap;
182   f = faces.begin();
183   for ( ; f != faces.end(); ++f )
184   {
185     // NB_NODES PER FACE
186     elem = *f;
187     nbNodes = elem->NbNodes();
188     theFile << space << nbNodes;
189
190     // NODE_NB_1 NODE_NB_2 ...
191     nodeIt = elem->nodesIterator();
192     while ( nodeIt->more() )
193     {
194       // find GHS3D ID
195       const SMDS_MeshNode* node = castToNode( nodeIt->next() );
196       int newId = aNodeToGhs3dIdMap.size() + 1; // ghs3d ids count from 1
197       it = aNodeToGhs3dIdMap.insert( make_pair( node, newId )).first;
198       theFile << space << it->second;
199     }
200
201     // (NB_NODES + 1) times: DUMMY_INT
202     for ( int i=0; i<=nbNodes; i++)
203       theFile << space << dummyint;
204
205     theFile << endl;
206   }
207
208   // put nodes to theNodeByGhs3dId vector
209   theNodeByGhs3dId.resize( aNodeToGhs3dIdMap.size() );
210   map<const SMDS_MeshNode*,int>::const_iterator n2id = aNodeToGhs3dIdMap.begin();
211   for ( ; n2id != aNodeToGhs3dIdMap.end(); ++ n2id)
212   {
213     theNodeByGhs3dId[ n2id->second - 1 ] = n2id->first; // ghs3d ids count from 1
214   }
215
216   return true;
217 }
218
219 //=======================================================================
220 //function : writePoints
221 //purpose  : 
222 //=======================================================================
223
224 static bool writePoints (ofstream &                            theFile,
225                          SMESHDS_Mesh *                        theMesh,
226                          const vector <const SMDS_MeshNode*> & theNodeByGhs3dId)
227 {
228   // record structure:
229   //
230   // NB_NODES
231   // Loop from 1 to NB_NODES
232   //   X Y Z DUMMY_INT
233
234   //int nbNodes = theMesh->NbNodes();
235   int nbNodes = theNodeByGhs3dId.size();
236   if ( nbNodes == 0 )
237     return false;
238
239   const char* space    = "  ";
240   const int   dummyint = 0;
241
242   const SMDS_MeshNode* node;
243
244   // NB_NODES
245   theFile << space << nbNodes << endl;
246   cout << nbNodes << " nodes" << endl;
247
248   // Loop from 1 to NB_NODES
249
250   vector<const SMDS_MeshNode*>::const_iterator nodeIt = theNodeByGhs3dId.begin();
251   vector<const SMDS_MeshNode*>::const_iterator after  = theNodeByGhs3dId.end();
252   for ( ; nodeIt != after; ++nodeIt )
253   {
254     node = *nodeIt;
255
256     // X Y Z DUMMY_INT
257     theFile
258       << space << node->X()
259       << space << node->Y()
260       << space << node->Z()
261       << space << dummyint;
262
263     theFile << endl;
264   }
265
266   return true;
267 }
268
269 //=======================================================================
270 //function : findSolid
271 //purpose  : 
272 //=======================================================================
273
274 static TopoDS_Shape findSolid(const SMDS_MeshNode *aNode[],
275                               TopoDS_Shape        aSolid,
276                               const TopoDS_Shape  shape[],
277                               const double        box[][6],
278                               const int           nShape) {
279
280   Standard_Real PX, PY, PZ;
281   int iShape;
282
283   PX = ( aNode[0]->X() + aNode[1]->X() + aNode[2]->X() + aNode[3]->X() ) / 4.0;
284   PY = ( aNode[0]->Y() + aNode[1]->Y() + aNode[2]->Y() + aNode[3]->Y() ) / 4.0;
285   PZ = ( aNode[0]->Z() + aNode[1]->Z() + aNode[2]->Z() + aNode[3]->Z() ) / 4.0;
286   gp_Pnt aPnt(PX, PY, PZ);
287
288   BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
289   if ( not(SC.State() == TopAbs_IN) ) {
290     for (iShape = 0; iShape < nShape; iShape++) {
291       aSolid = shape[iShape];
292       if ( not( PX < box[iShape][0] || box[iShape][1] < PX ||
293                 PY < box[iShape][2] || box[iShape][3] < PY ||
294                 PZ < box[iShape][4] || box[iShape][5] < PZ) ) {
295         BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
296         if (SC.State() == TopAbs_IN)
297           break;
298       }
299     }
300   }
301   return aSolid;
302 }
303
304 //=======================================================================
305 //function : readMapIntLine
306 //purpose  : 
307 //=======================================================================
308
309 static char* readMapIntLine(char* ptr, int tab[]) {
310   long int intVal;
311   cout << endl;
312
313   for ( int i=0; i<17; i++ ) {
314     intVal = strtol(ptr, &ptr, 10);
315     if ( i < 3 )
316       tab[i] = intVal;
317   }
318   return ptr;
319 }
320
321 //=======================================================================
322 //function : readLine
323 //purpose  : 
324 //=======================================================================
325
326 #define GHS3DPlugin_BUFLENGTH 256
327 #define GHS3DPlugin_ReadLine(aPtr,aBuf,aFile,aLineNb) \
328 {  aPtr = fgets( aBuf, GHS3DPlugin_BUFLENGTH - 2, aFile ); aLineNb++; DUMP(endl); }
329
330 #include <list>
331 //=======================================================================
332 //function : readResultFile
333 //purpose  : 
334 //=======================================================================
335
336 static bool readResultFile(const int                      fileOpen,
337                            SMESHDS_Mesh*                  theMeshDS,
338                            TopoDS_Shape                   tabShape[],
339                            double                         tabBox[][6],
340                            const int                      nShape,
341                            vector <const SMDS_MeshNode*>& theNodeByGhs3dId) {
342
343   struct stat  status;
344   size_t       length;
345
346   char *ptr, *mapPtr;
347   char *tetraPtr;
348   char *shapePtr;
349
350   int fileStat;
351   int nbElems, nbNodes, nbInputNodes;
352   int nodeId, triangleId;
353   int tab[3]/*, tabID[nShape]*/;
354   int nbTriangle;
355   int ID, shapeID, ghs3dShapeID;
356
357   double coord [3];
358   vector< int > tabID (nShape, 0);
359
360   TopoDS_Shape aSolid;
361   SMDS_MeshNode * aNewNode;
362   const SMDS_MeshNode * node[4];
363   map <int,const SMDS_MeshNode*>::iterator IdNode;
364   SMDS_MeshElement* aTet;
365
366 //   for (int i=0; i<nShape; i++)
367 //     tabID[i] = 0;
368
369   // Read the file state
370   fileStat = fstat(fileOpen, &status);
371   length   = status.st_size;
372
373   // Mapping the result file into memory
374   ptr = (char *) mmap(0,length,PROT_READ,MAP_PRIVATE,fileOpen,0);
375   mapPtr = ptr;
376
377   ptr      = readMapIntLine(ptr, tab);
378   tetraPtr = ptr;
379
380   nbElems      = tab[0];
381   nbNodes      = tab[1];
382   nbInputNodes = tab[2];
383
384   theNodeByGhs3dId.resize( nbNodes );
385
386   // Reading the nodeId
387   for (int i=0; i < 4*nbElems; i++)
388     nodeId = strtol(ptr, &ptr, 10);
389
390   // Reading the nodeCoor and update the nodeMap
391   for (int iNode=0; iNode < nbNodes; iNode++) {
392     for (int iCoor=0; iCoor < 3; iCoor++)
393       coord[ iCoor ] = strtod(ptr, &ptr);
394     if ((iNode+1) > nbInputNodes) {
395       aNewNode = theMeshDS->AddNode( coord[0],coord[1],coord[2] );
396       theNodeByGhs3dId[ iNode ] = aNewNode;
397     }
398   }
399
400   // Reading the triangles
401   nbTriangle = strtol(ptr, &ptr, 10);
402
403   for (int i=0; i < 3*nbTriangle; i++)
404     triangleId = strtol(ptr, &ptr, 10);
405
406   shapePtr = ptr;
407
408   // Associating the tetrahedrons to the shapes
409   for (int iElem = 0; iElem < nbElems; iElem++) {
410     for (int iNode = 0; iNode < 4; iNode++) {
411       ID = strtol(tetraPtr, &tetraPtr, 10);
412       node[ iNode ] = theNodeByGhs3dId[ ID-1 ];
413     }
414     aTet = theMeshDS->AddVolume( node[1], node[0], node[2], node[3] );
415     ghs3dShapeID = strtol(shapePtr, &shapePtr, 10);
416     if ( tabID[ ghs3dShapeID - 1 ] == 0 ) {
417       if (iElem == 0)
418         aSolid = tabShape[0];
419       aSolid = findSolid(node, aSolid, tabShape, tabBox, nShape /*nbTriangle*/);
420       shapeID = theMeshDS->ShapeToIndex( aSolid );
421       tabID[ ghs3dShapeID - 1] = shapeID;
422     }
423     else {
424       shapeID = tabID[ ghs3dShapeID - 1];
425     }
426     theMeshDS->SetMeshElementOnShape( aTet, shapeID );
427     // set new nodes on to the shape
428     SMDS_ElemIteratorPtr nodeIt = aTet->nodesIterator();
429     while ( nodeIt->more() ) {
430       const SMDS_MeshNode * n = castToNode( nodeIt->next() );
431       if ( !n->GetPosition()->GetShapeId() )
432         theMeshDS->SetNodeInVolume( n, shapeID );
433     }
434   }
435   if ( nbElems )
436     cout << nbElems << " tetrahedrons have been associated to " << nbTriangle << " shapes" << endl;
437   munmap(mapPtr, length);
438   close(fileOpen);
439   return true;
440 }
441
442 //=======================================================================
443 //function : getTmpDir
444 //purpose  : 
445 //=======================================================================
446
447 static TCollection_AsciiString getTmpDir()
448 {
449   TCollection_AsciiString aTmpDir;
450
451   char *Tmp_dir = getenv("SALOME_TMP_DIR");
452   if(Tmp_dir != NULL) {
453     aTmpDir = Tmp_dir;
454 #ifdef WIN32
455     if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
456 #else
457     if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
458 #endif      
459   }
460   else {
461 #ifdef WIN32
462     aTmpDir = TCollection_AsciiString("C:\\");
463 #else
464     aTmpDir = TCollection_AsciiString("/tmp/");
465 #endif
466   }
467   return aTmpDir;
468 }
469
470 //================================================================================
471 /*!
472  * \brief Look for a line containing a text in a file
473   * \retval bool - true if the line is found
474  */
475 //================================================================================
476
477 static bool findLineContaing(const TCollection_AsciiString& theText,
478                              const TCollection_AsciiString& theFile,
479                              TCollection_AsciiString &      theFoundLine)
480 {
481   bool found = false;
482   if ( FILE * aFile = fopen( theFile.ToCString(), "r" ))
483   {
484     char * aPtr;
485     char aBuffer[ GHS3DPlugin_BUFLENGTH ];
486     int aLineNb = 0;
487     do {
488       GHS3DPlugin_ReadLine( aPtr, aBuffer, aFile, aLineNb );
489       if ( aPtr ) {
490         theFoundLine = aPtr;
491         found = theFoundLine.Search( theText ) >= 0;
492       }
493     } while ( aPtr && !found );
494
495     fclose( aFile );
496   }
497   return found;
498 }
499
500 //=============================================================================
501 /*!
502  *Here we are going to use the GHS3D mesher
503  */
504 //=============================================================================
505
506 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh&         theMesh,
507                                 const TopoDS_Shape& theShape)
508 {
509   // theShape is a compound of solids as _onlyUnaryInput = false
510   bool Ok(false);
511   SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
512
513   int _nbShape = 0;
514   /*if (_iShape == 0 && _nbShape == 0)*/ {
515     cout << endl;
516     cout << "Ghs3d execution..." << endl;
517     cout << endl;
518     
519     //TopExp_Explorer exp (meshDS->ShapeToMesh(), TopAbs_SOLID);
520     TopExp_Explorer exp (theShape, TopAbs_SOLID);
521     for (; exp.More(); exp.Next())
522       _nbShape++;
523   }
524   
525   //_iShape++;
526
527   /*if ( _iShape == _nbShape )*/ {
528
529     // create bounding box for every shape
530
531     int iShape = 0;
532     TopoDS_Shape tabShape[_nbShape];
533     double tabBox[_nbShape][6];
534     Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
535
536     TopExp_Explorer expBox (theShape, TopAbs_SOLID);
537     for (; expBox.More(); expBox.Next()) {
538       tabShape[iShape] = expBox.Current();
539       Bnd_Box BoundingBox;
540       BRepBndLib::Add(expBox.Current(), BoundingBox);
541       BoundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
542       tabBox[iShape][0] = Xmin; tabBox[iShape][1] = Xmax;
543       tabBox[iShape][2] = Ymin; tabBox[iShape][3] = Ymax;
544       tabBox[iShape][4] = Zmin; tabBox[iShape][5] = Zmax;
545       iShape++;
546     }
547
548     // make a unique working file name
549     // to avoid access to the same files by eg different users
550   
551     TCollection_AsciiString aGenericName, aTmpDir = getTmpDir();
552     aGenericName = aTmpDir + "GHS3D_";
553 #ifdef WIN32
554     aGenericName += GetCurrentProcessId();
555 #else
556     aGenericName += getpid();
557 #endif
558     aGenericName += "_";
559     aGenericName += meshDS->ShapeToIndex( theShape );
560
561     TCollection_AsciiString aFacesFileName, aPointsFileName, aResultFileName;
562     TCollection_AsciiString aBadResFileName, aBbResFileName, aLogFileName;
563     aFacesFileName  = aGenericName + ".faces";  // in faces
564     aPointsFileName = aGenericName + ".points"; // in points
565     aResultFileName = aGenericName + ".noboite";// out points and volumes
566     aBadResFileName = aGenericName + ".boite";  // out bad result
567     aBbResFileName  = aGenericName + ".bb";     // out vertex stepsize
568     aLogFileName    = aGenericName + ".log";    // log
569
570     // -----------------
571     // make input files
572     // -----------------
573
574     ofstream aFacesFile  ( aFacesFileName.ToCString()  , ios::out);
575     ofstream aPointsFile ( aPointsFileName.ToCString() , ios::out);
576     // bool Ok =
577     Ok =
578 #ifdef WIN32
579       aFacesFile->is_open() && aPointsFile->is_open();
580 #else
581       aFacesFile.rdbuf()->is_open() && aPointsFile.rdbuf()->is_open();
582 #endif
583     if (!Ok)
584         return error(dfltErr(), SMESH_Comment("Can't write into ") << aTmpDir);
585
586     vector <const SMDS_MeshNode*> aNodeByGhs3dId;
587
588     Ok = ( writeFaces ( aFacesFile,  meshDS, theShape, aNodeByGhs3dId ) &&
589            writePoints( aPointsFile, meshDS, aNodeByGhs3dId ));
590
591     aFacesFile.close();
592     aPointsFile.close();
593
594     if ( ! Ok ) {
595       if ( !getenv("GHS3D_KEEP_FILES") ) {
596         OSD_File( aFacesFileName ).Remove();
597         OSD_File( aPointsFileName ).Remove();
598       }
599       return error(COMPERR_BAD_INPUT_MESH);
600     }
601
602     // -----------------
603     // run ghs3d mesher              WIN32???
604     // -----------------
605
606     // ghs3d need to know amount of memory it may use (MB).
607     // Default memory is defined at ghs3d installation but it may be not enough,
608     // so allow to use about all available memory
609
610     TCollection_AsciiString memory;
611 #ifdef WIN32
612     // ????
613 #else
614     struct sysinfo si;
615     int err = sysinfo( &si );
616     if ( !err ) {
617       int freeMem = si.totalram * si.mem_unit / 1024 / 1024;
618       memory = "-m ";
619       memory += int( 0.7 * freeMem );
620     }
621 #endif
622
623     OSD_File( aResultFileName ).Remove(); // old file prevents writing a new one
624
625     TCollection_AsciiString cmd( "ghs3d " ); // command to run
626     cmd +=
627       memory +                // memory
628       " -c 0"                 // 0 - mesh all components, 1 - keep only the main component
629       " -f " + aGenericName + // file to read
630       " 1>" + aLogFileName;   // dump into file
631
632     MESSAGE("GHS3DPlugin_GHS3D::Compute() " << cmd );
633     system( cmd.ToCString() ); // run
634
635     cout << endl;
636     cout << "End of Ghs3d execution !" << endl;
637
638     // --------------
639     // read a result
640     // --------------
641
642     // Mapping the result file
643
644     int fileOpen;
645     fileOpen = open( aResultFileName.ToCString(), O_RDONLY);
646     if ( fileOpen < 0 ) {
647       cout << endl;
648       cout << "Error when opening the " << aResultFileName.ToCString() << " file" << endl;
649       cout << endl;
650       Ok = false;
651     }
652     else {
653       Ok = readResultFile( fileOpen, meshDS, tabShape, tabBox, _nbShape, aNodeByGhs3dId );
654     }
655
656   // ---------------------
657   // remove working files
658   // ---------------------
659
660     if ( Ok )
661     {
662       OSD_File( aLogFileName ).Remove();
663     }
664     else if ( OSD_File( aLogFileName ).Size() > 0 )
665     {
666       // get problem description from the log file
667       SMESH_Comment comment;
668       TCollection_AsciiString foundLine;
669       if ( findLineContaing( "has expired",aLogFileName,foundLine) &&
670            foundLine.Search("Licence") >= 0)
671       {
672         foundLine.LeftAdjust();
673         comment << foundLine;
674       }
675       if ( findLineContaing( "%% ERROR",aLogFileName,foundLine))
676       {
677         foundLine.LeftAdjust();
678         comment << foundLine;
679       }
680       if ( findLineContaing( "%% NO SAVING OPERATION",aLogFileName,foundLine))
681       {
682         comment << "Too many elements generated for a trial version.\n";
683       }
684       if ( comment.empty() )
685         comment << "See " << aLogFileName << " for problem description";
686       else
687         comment << "See " << aLogFileName << " for more information";
688       error(COMPERR_ALGO_FAILED, comment);
689     }
690     else
691     {
692       // the log file is empty
693       OSD_File( aLogFileName ).Remove();
694       error(COMPERR_ALGO_FAILED, "ghs3d: command not found" );
695     }
696
697     if ( !getenv("GHS3D_KEEP_FILES") )
698     {
699       OSD_File( aFacesFileName ).Remove();
700       OSD_File( aPointsFileName ).Remove();
701       OSD_File( aResultFileName ).Remove();
702       OSD_File( aBadResFileName ).Remove();
703       OSD_File( aBbResFileName ).Remove();
704     }
705     /*if ( _iShape == _nbShape )*/ {
706       cout << aResultFileName.ToCString() << " Output file ";
707       if ( !Ok )
708         cout << "not ";
709       cout << "treated !" << endl;
710       cout << endl;
711     }
712   }
713
714   return Ok;
715 }