1 // Copyright (C) 2005 CEA/DEN, EDF R&D, OPEN CASCADE, PRINCIPIA R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //=============================================================================
20 // File : GHS3DPlugin_GHS3D.cxx
22 // Author : Edward AGAPOV, modified by Lioka RAZAFINDRAZAKA (CEA) 09/02/2007
24 // Copyright : CEA 2003
26 //=============================================================================
29 #include "GHS3DPlugin_GHS3D.hxx"
30 #include "SMESH_Gen.hxx"
31 #include "SMESH_Mesh.hxx"
32 #include "SMESH_Comment.hxx"
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
37 #include <TopExp_Explorer.hxx>
38 #include <OSD_File.hxx>
40 #include "utilities.h"
43 #include <sys/sysinfo.h>
46 //#include <Standard_Stream.hxx>
48 #include <BRepGProp.hxx>
49 #include <BRepBndLib.hxx>
50 #include <BRepClass_FaceClassifier.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <Bnd_Box.hxx>
54 #include <GProp_GProps.hxx>
55 #include <Precision.hxx>
74 //=============================================================================
78 //=============================================================================
80 GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D(int hypId, int studyId, SMESH_Gen* gen)
81 : SMESH_3D_Algo(hypId, studyId, gen)
83 MESSAGE("GHS3DPlugin_GHS3D::GHS3DPlugin_GHS3D");
85 _shapeType = (1 << TopAbs_SHELL) | (1 << TopAbs_SOLID);// 1 bit /shape type
90 //=============================================================================
94 //=============================================================================
96 GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D()
98 MESSAGE("GHS3DPlugin_GHS3D::~GHS3DPlugin_GHS3D");
101 //=============================================================================
105 //=============================================================================
107 bool GHS3DPlugin_GHS3D::CheckHypothesis ( SMESH_Mesh& aMesh,
108 const TopoDS_Shape& aShape,
109 SMESH_Hypothesis::Hypothesis_Status& aStatus )
111 // MESSAGE("GHS3DPlugin_GHS3D::CheckHypothesis");
112 aStatus = SMESH_Hypothesis::HYP_OK;
116 //=======================================================================
117 //function : writeFaces
119 //=======================================================================
121 static bool writeFaces (ofstream & theFile,
122 SMESHDS_Mesh * theMesh,
123 const map <int,int> & theSmdsToGhs3dIdMap)
127 // NB_ELEMS DUMMY_INT
128 // Loop from 1 to NB_ELEMS
129 // NB_NODES NODE_NB_1 NODE_NB_2 ... (NB_NODES + 1) times: DUMMY_INT
131 // get all faces bound to theShape
134 TopoDS_Shape theShape = theMesh->ShapeToMesh();
135 list< const SMDS_MeshElement* > faces;
136 TopExp_Explorer fExp( theShape, TopAbs_FACE );
138 SMDS_ElemIteratorPtr eIt;
140 const char* space = " ";
141 const int dummyint = 0;
143 list< const SMDS_MeshElement* >::iterator f;
144 map<int,int>::const_iterator it;
145 SMDS_ElemIteratorPtr nodeIt;
146 const SMDS_MeshElement* elem;
150 for ( ; fExp.More(); fExp.Next() ) {
151 sm = theMesh->MeshElements( fExp.Current() );
153 eIt = sm->GetElements();
154 while ( eIt->more() ) {
155 faces.push_back( eIt->next() );
164 cout << nbFaces << " triangles" << endl;
166 // NB_ELEMS DUMMY_INT
167 theFile << space << nbFaces << space << dummyint << endl;
169 // Loop from 1 to NB_ELEMS
172 for ( ; f != faces.end(); ++f )
176 nbNodes = elem->NbNodes();
177 theFile << space << nbNodes;
179 // NODE_NB_1 NODE_NB_2 ...
180 nodeIt = elem->nodesIterator();
181 while ( nodeIt->more() )
184 aSmdsID = nodeIt->next()->GetID();
185 it = theSmdsToGhs3dIdMap.find( aSmdsID );
186 ASSERT( it != theSmdsToGhs3dIdMap.end() );
187 theFile << space << (*it).second;
190 // (NB_NODES + 1) times: DUMMY_INT
191 for ( int i=0; i<=nbNodes; i++)
192 theFile << space << dummyint;
200 //=======================================================================
201 //function : writePoints
203 //=======================================================================
205 static bool writePoints (ofstream & theFile,
206 SMESHDS_Mesh * theMesh,
207 map <int,int> & theSmdsToGhs3dIdMap,
208 map <int,const SMDS_MeshNode*> & theGhs3dIdToNodeMap)
213 // Loop from 1 to NB_NODES
216 int nbNodes = theMesh->NbNodes();
220 const char* space = " ";
221 const int dummyint = 0;
224 SMDS_NodeIteratorPtr it = theMesh->nodesIterator();
225 const SMDS_MeshNode* node;
228 theFile << space << nbNodes << endl;
229 cout << "The initial 2D mesh contains " << nbNodes << " nodes and ";
231 // Loop from 1 to NB_NODES
236 theSmdsToGhs3dIdMap.insert( map <int,int>::value_type( node->GetID(), aGhs3dID ));
237 theGhs3dIdToNodeMap.insert (map <int,const SMDS_MeshNode*>::value_type( aGhs3dID, node ));
242 << space << node->X()
243 << space << node->Y()
244 << space << node->Z()
245 << space << dummyint;
253 //=======================================================================
254 //function : findSolid
256 //=======================================================================
258 static TopoDS_Shape findSolid(const SMDS_MeshNode *aNode[],
260 const TopoDS_Shape shape[],
261 const double box[][6],
264 Standard_Real PX, PY, PZ;
267 PX = ( aNode[0]->X() + aNode[1]->X() + aNode[2]->X() + aNode[3]->X() ) / 4.0;
268 PY = ( aNode[0]->Y() + aNode[1]->Y() + aNode[2]->Y() + aNode[3]->Y() ) / 4.0;
269 PZ = ( aNode[0]->Z() + aNode[1]->Z() + aNode[2]->Z() + aNode[3]->Z() ) / 4.0;
270 gp_Pnt aPnt(PX, PY, PZ);
272 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
273 if ( not(SC.State() == TopAbs_IN) ) {
274 for (iShape = 0; iShape < nShape; iShape++) {
275 aSolid = shape[iShape];
276 if ( not( PX < box[iShape][0] || box[iShape][1] < PX ||
277 PY < box[iShape][2] || box[iShape][3] < PY ||
278 PZ < box[iShape][4] || box[iShape][5] < PZ) ) {
279 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
280 if (SC.State() == TopAbs_IN)
288 //=======================================================================
289 //function : readMapIntLine
291 //=======================================================================
293 static char* readMapIntLine(char* ptr, int tab[]) {
297 for ( int i=0; i<17; i++ ) {
298 intVal = strtol(ptr, &ptr, 10);
305 //=======================================================================
306 //function : readLine
308 //=======================================================================
310 #define GHS3DPlugin_BUFLENGTH 256
311 #define GHS3DPlugin_ReadLine(aPtr,aBuf,aFile,aLineNb) \
312 { aPtr = fgets( aBuf, GHS3DPlugin_BUFLENGTH - 2, aFile ); aLineNb++; DUMP(endl); }
315 //=======================================================================
316 //function : readResultFile
318 //=======================================================================
320 static bool readResultFile(const int fileOpen,
321 SMESHDS_Mesh* theMeshDS,
322 TopoDS_Shape tabShape[],
325 map <int,const SMDS_MeshNode*>& theGhs3dIdToNodeMap) {
335 int nbElems, nbNodes, nbInputNodes;
336 int nodeId, triangleId;
337 int tab[3], tabID[nShape];
339 int ID, shapeID, ghs3dShapeID;
344 SMDS_MeshNode * aNewNode;
345 const SMDS_MeshNode * node[4];
346 map <int,const SMDS_MeshNode*>::iterator IdNode;
347 SMDS_MeshElement* aTet;
349 for (int i=0; i<nShape; i++)
352 // Read the file state
353 fileStat = fstat(fileOpen, &status);
354 length = status.st_size;
356 // Mapping the result file into memory
357 ptr = (char *) mmap(0,length,PROT_READ,MAP_PRIVATE,fileOpen,0);
360 ptr = readMapIntLine(ptr, tab);
365 nbInputNodes = tab[2];
367 // Reading the nodeId
368 for (int i=0; i < 4*nbElems; i++)
369 nodeId = strtol(ptr, &ptr, 10);
371 // Reading the nodeCoor and update the nodeMap
372 for (int iNode=0; iNode < nbNodes; iNode++) {
373 for (int iCoor=0; iCoor < 3; iCoor++)
374 coord[ iCoor ] = strtod(ptr, &ptr);
375 if ((iNode+1) > nbInputNodes) {
376 aNewNode = theMeshDS->AddNode( coord[0],coord[1],coord[2] );
377 theGhs3dIdToNodeMap.insert(make_pair( (iNode+1), aNewNode ));
381 // Reading the triangles
382 nbTriangle = strtol(ptr, &ptr, 10);
384 for (int i=0; i < 3*nbTriangle; i++)
385 triangleId = strtol(ptr, &ptr, 10);
389 // Associating the tetrahedrons to the shapes
390 for (int iElem = 0; iElem < nbElems; iElem++) {
391 for (int iNode = 0; iNode < 4; iNode++) {
392 ID = strtol(tetraPtr, &tetraPtr, 10);
393 IdNode = theGhs3dIdToNodeMap.find(ID);
394 node[ iNode ] = IdNode->second;
396 aTet = theMeshDS->AddVolume( node[1], node[0], node[2], node[3] );
397 ghs3dShapeID = strtol(shapePtr, &shapePtr, 10);
398 if ( tabID[ ghs3dShapeID - 1 ] == 0 ) {
400 aSolid = tabShape[0];
401 aSolid = findSolid(node, aSolid, tabShape, tabBox, nbTriangle);
402 shapeID = theMeshDS->ShapeToIndex( aSolid );
403 tabID[ ghs3dShapeID - 1] = shapeID;
406 shapeID = tabID[ ghs3dShapeID - 1];
407 theMeshDS->SetMeshElementOnShape( aTet, shapeID );
408 if ( (iElem + 1) == nbElems )
409 cout << nbElems << " tetrahedrons have been associated to " << nbTriangle << " shapes" << endl;
411 munmap(mapPtr, length);
416 //=======================================================================
417 //function : getTmpDir
419 //=======================================================================
421 static TCollection_AsciiString getTmpDir()
423 TCollection_AsciiString aTmpDir;
425 char *Tmp_dir = getenv("SALOME_TMP_DIR");
426 if(Tmp_dir != NULL) {
429 if(aTmpDir.Value(aTmpDir.Length()) != '\\') aTmpDir+='\\';
431 if(aTmpDir.Value(aTmpDir.Length()) != '/') aTmpDir+='/';
436 aTmpDir = TCollection_AsciiString("C:\\");
438 aTmpDir = TCollection_AsciiString("/tmp/");
444 //================================================================================
446 * \brief Decrease amount of memory GHS3D may use until it can allocate it
447 * \param nbMB - memory size to adjust
448 * \param aLogFileName - file for GHS3D output
449 * \retval bool - false if GHS3D can not run for any reason
451 //================================================================================
453 static bool adjustMemory(int & nbMB, const TCollection_AsciiString & aLogFileName)
455 TCollection_AsciiString cmd( "ghs3d -m " );
460 system( cmd.ToCString() ); // run
464 FILE * aLogFile = fopen( aLogFileName.ToCString(), "r" );
467 bool memoryOK = true;
469 char aBuffer[ GHS3DPlugin_BUFLENGTH ];
472 GHS3DPlugin_ReadLine( aPtr, aBuffer, aLogFile, aLineNb );
474 TCollection_AsciiString line( aPtr );
475 if ( line.Search( "UNABLE TO ALLOCATE MEMORY" ) > 0 )
478 } while ( aPtr && memoryOK );
484 return adjustMemory( nbMB, aLogFileName );
491 //=============================================================================
493 *Here we are going to use the GHS3D mesher
495 //=============================================================================
497 bool GHS3DPlugin_GHS3D::Compute(SMESH_Mesh& theMesh,
498 const TopoDS_Shape& theShape)
501 SMESHDS_Mesh* meshDS = theMesh.GetMeshDS();
503 if (_iShape == 0 && _nbShape == 0) {
505 cout << "Ghs3d execution..." << endl;
508 TopExp_Explorer exp (meshDS->ShapeToMesh(), TopAbs_SOLID);
509 for (; exp.More(); exp.Next())
515 if ( _iShape == _nbShape ) {
517 // create bounding box for every shape
520 TopoDS_Shape tabShape[_nbShape];
521 double tabBox[_nbShape][6];
522 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
524 TopExp_Explorer expBox (meshDS->ShapeToMesh(), TopAbs_SOLID);
525 for (; expBox.More(); expBox.Next()) {
526 tabShape[iShape] = expBox.Current();
528 BRepBndLib::Add(expBox.Current(), BoundingBox);
529 BoundingBox.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
530 tabBox[iShape][0] = Xmin; tabBox[iShape][1] = Xmax;
531 tabBox[iShape][2] = Ymin; tabBox[iShape][3] = Ymax;
532 tabBox[iShape][4] = Zmin; tabBox[iShape][5] = Zmax;
536 // make a unique working file name
537 // to avoid access to the same files by eg different users
539 TCollection_AsciiString aGenericName, aTmpDir = getTmpDir();
540 aGenericName = aTmpDir + "GHS3D_";
542 aGenericName += GetCurrentProcessId();
544 aGenericName += getpid();
547 aGenericName += meshDS->ShapeToIndex( theShape );
549 TCollection_AsciiString aFacesFileName, aPointsFileName, aResultFileName;
550 TCollection_AsciiString aBadResFileName, aBbResFileName, aLogFileName;
551 aFacesFileName = aGenericName + ".faces"; // in faces
552 aPointsFileName = aGenericName + ".points"; // in points
553 aResultFileName = aGenericName + ".noboite";// out points and volumes
554 aBadResFileName = aGenericName + ".boite"; // out bad result
555 aBbResFileName = aGenericName + ".bb"; // out vertex stepsize
556 aLogFileName = aGenericName + ".log"; // log
562 ofstream aFacesFile ( aFacesFileName.ToCString() , ios::out);
563 ofstream aPointsFile ( aPointsFileName.ToCString() , ios::out);
567 aFacesFile->is_open() && aPointsFile->is_open();
569 aFacesFile.rdbuf()->is_open() && aPointsFile.rdbuf()->is_open();
572 return error(dfltErr(), SMESH_Comment("Can't write into ") << aTmpDir.ToCString());
574 map <int,int> aSmdsToGhs3dIdMap;
575 map <int,const SMDS_MeshNode*> aGhs3dIdToNodeMap;
577 Ok = writePoints( aPointsFile, meshDS, aSmdsToGhs3dIdMap, aGhs3dIdToNodeMap ) &&
578 writeFaces ( aFacesFile, meshDS, aSmdsToGhs3dIdMap );
584 if ( !getenv("GHS3D_KEEP_FILES") ) {
585 OSD_File( aFacesFileName ).Remove();
586 OSD_File( aPointsFileName ).Remove();
588 return error(COMPERR_BAD_INPUT_MESH);
592 // run ghs3d mesher WIN32???
595 // ghs3d need to know amount of memory it may use (MB).
596 // Default memory is defined at ghs3d installation but it may be not enough,
597 // so allow to use about all available memory
599 TCollection_AsciiString memory;
602 int err = sysinfo( &si );
604 int MB = 0.9 * ( si.freeram + si.freeswap ) * si.mem_unit / 1024 / 1024;
605 adjustMemory( MB, aLogFileName );
611 MESSAGE("GHS3DPlugin_GHS3D::Compute");
612 TCollection_AsciiString cmd( "ghs3d " ); // command to run
615 " -c0 -f " + aGenericName + // file to read
616 " 1>" + aLogFileName; // dump into file
618 system( cmd.ToCString() ); // run
621 cout << "End of Ghs3d execution !" << endl;
627 // Mapping the result file
630 fileOpen = open( aResultFileName.ToCString(), O_RDONLY);
631 if ( fileOpen < 0 ) {
633 cout << "Error when opening the " << aResultFileName.ToCString() << " file" << endl;
638 Ok = readResultFile( fileOpen, meshDS, tabShape, tabBox, _nbShape, aGhs3dIdToNodeMap );
640 // ---------------------
641 // remove working files
642 // ---------------------
645 OSD_File( aLogFileName ).Remove();
647 else if ( OSD_File( aLogFileName ).Size() > 0 ) {
648 Ok = error(dfltErr(), SMESH_Comment("See ")<< aLogFileName.ToCString() );
651 OSD_File( aLogFileName ).Remove();