Salome HOME
bos #20256: [CEA 18523] Porting SMESH to int 64 bits
[modules/smesh.git] / src / DriverGMF / DriverGMF_Write.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : DriverGMF_Write.cxx
23 // Created   : Mon Sep 17 17:03:02 2012
24 // Author    : Edward AGAPOV (eap)
25
26 #include "DriverGMF_Write.hxx"
27 #include "DriverGMF.hxx"
28
29 #include "SMESHDS_GroupBase.hxx"
30 #include "SMESHDS_Mesh.hxx"
31 #include "SMESH_Comment.hxx"
32
33 #include <Basics_Utils.hxx>
34
35 #include "utilities.h"
36
37 using SMESHUtils::ControlPnt;
38
39 extern "C"
40 {
41 #include "libmesh5.h"
42 }
43
44 #include <vector>
45
46 #define BEGIN_ELEM_WRITE( SMDSEntity, GmfKwd, elem )                    \
47   elemIt = elementIterator( SMDSEntity );                               \
48   if ( elemIt->more() )                                                 \
49   {                                                                     \
50   GmfSetKwd(meshID, GmfKwd, myMesh->GetMeshInfo().NbElements( SMDSEntity )); \
51   for ( int gmfID = 1; elemIt->more(); ++gmfID )                        \
52   {                                                                     \
53   const SMDS_MeshElement* elem = elemIt->next();                        \
54   GmfSetLin(meshID, GmfKwd,
55
56 #define BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom, LinType, GmfKwd, elem )   \
57   elemIt = elementIterator( SMDSGeom );                                 \
58   if ( elemIt->more() )                                                 \
59   {                                                                     \
60   smIdType totalNbElems  = myMesh->GetMeshInfo().NbElements( SMDSGeom );\
61   smIdType nbLinearElems = myMesh->GetMeshInfo().NbElements( LinType ); \
62   if ( totalNbElems - nbLinearElems > 0 )                               \
63   {                                                                     \
64   GmfSetKwd(meshID, GmfKwd, totalNbElems - nbLinearElems);              \
65   for ( int gmfID = 1; elemIt->more(); ++gmfID )                        \
66   {                                                                     \
67   const SMDS_MeshElement* elem = elemIt->next();                        \
68   if ( elem->IsQuadratic() ) {                                          \
69   GmfSetLin(meshID, GmfKwd, gmfID, elem->NbNodes() - elem->NbCornerNodes(),
70
71 #define END_ELEM_WRITE( elem )                  \
72   elem->getshapeId() );                         \
73   }}
74
75 #define END_ELEM_WRITE_ADD_TO_MAP( elem, e2id )            \
76   elem->getshapeId() );                                    \
77   e2id.insert( e2id.end(), std::make_pair( elem, gmfID )); \
78   }}
79
80 #define END_EXTRA_VERTICES_WRITE()           \
81   );                                         \
82   }}}}
83   
84
85 DriverGMF_Write::DriverGMF_Write():
86   Driver_SMESHDS_Mesh(), _exportRequiredGroups( true )
87 {
88 }
89 DriverGMF_Write::~DriverGMF_Write()
90 {
91 }
92
93 //================================================================================
94 /*!
95  * \brief Reads a GMF file
96  */
97 //================================================================================
98
99 Driver_Mesh::Status DriverGMF_Write::Perform()
100 {
101   Kernel_Utils::Localizer loc;
102
103   if ( Driver_Mesh::IsMeshTooLarge< int >( myMesh, /*checkIDs =*/ false))
104     return DRS_TOO_LARGE_MESH;
105
106   const int dim = 3, version = sizeof(double) < 8 ? 1 : 2;
107
108   int meshID = GmfOpenMesh( myFile.c_str(), GmfWrite, version, dim );
109   if ( !meshID )
110   {
111     if ( DriverGMF::isExtensionCorrect( myFile ))
112       return addMessage( SMESH_Comment("Can't open for writing ") << myFile, /*fatal=*/true );
113     else
114       return addMessage( SMESH_Comment("Not '.mesh' or '.meshb' extension of file ") << myFile, /*fatal=*/true );
115   }
116
117   DriverGMF::MeshCloser aMeshCloser( meshID ); // An object closing GMF mesh at destruction
118
119   // nodes
120   std::map< const SMDS_MeshNode* , int > node2IdMap;
121   smIdType iN = 0, nbNodes = myMesh->NbNodes();
122   GmfSetKwd( meshID, GmfVertices, nbNodes );
123   double xyz[3];
124   SMDS_NodeIteratorPtr nodeIt = myMesh->nodesIterator();
125   while ( nodeIt->more() )
126   {
127     const SMDS_MeshNode* n = nodeIt->next();
128     n->GetXYZ( xyz );
129     GmfSetLin( meshID, GmfVertices, xyz[0], xyz[1], xyz[2], n->getshapeId() );
130     node2IdMap.insert( node2IdMap.end(), std::make_pair( n, ++iN ));
131   }
132   if ( iN != nbNodes )
133     return addMessage("Wrong nb of nodes returned by nodesIterator", /*fatal=*/true);
134
135
136   SMDS_ElemIteratorPtr elemIt;
137   typedef std::map< const SMDS_MeshElement*, size_t, TIDCompare > TElem2IDMap;
138
139   // edges
140   TElem2IDMap edge2IDMap;
141   BEGIN_ELEM_WRITE( SMDSGeom_EDGE, GmfEdges, edge )
142     node2IdMap[ edge->GetNode( 0 )],
143     node2IdMap[ edge->GetNode( 1 )],
144     END_ELEM_WRITE_ADD_TO_MAP( edge, edge2IDMap );
145
146   // nodes of quadratic edges
147   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_EDGE, SMDSEntity_Edge,
148                               GmfExtraVerticesAtEdges, edge )
149     node2IdMap[ edge->GetNode( 2 )]
150     END_EXTRA_VERTICES_WRITE();
151
152   // triangles
153   TElem2IDMap tria2IDMap;
154   BEGIN_ELEM_WRITE( SMDSGeom_TRIANGLE, GmfTriangles, tria )
155     node2IdMap[ tria->GetNode( 0 )],
156     node2IdMap[ tria->GetNode( 1 )],
157     node2IdMap[ tria->GetNode( 2 )],
158     END_ELEM_WRITE_ADD_TO_MAP( tria, tria2IDMap );
159
160   // nodes of quadratic triangles
161   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TRIANGLE, SMDSEntity_Triangle,
162                               GmfExtraVerticesAtTriangles, tria )
163     node2IdMap[ tria->GetNode( 3 )],
164     node2IdMap[ tria->GetNode( 4 )],
165     node2IdMap[ tria->GetNode( 5 )],
166     node2IdMap[ tria->GetNodeWrap( 6 )] // for TRIA7
167     END_EXTRA_VERTICES_WRITE();
168
169   // quadrangles
170   TElem2IDMap quad2IDMap;
171   BEGIN_ELEM_WRITE( SMDSGeom_QUADRANGLE, GmfQuadrilaterals, quad )
172     node2IdMap[ quad->GetNode( 0 )],
173     node2IdMap[ quad->GetNode( 1 )],
174     node2IdMap[ quad->GetNode( 2 )],
175     node2IdMap[ quad->GetNode( 3 )],
176     END_ELEM_WRITE_ADD_TO_MAP( quad, quad2IDMap );
177
178   // nodes of quadratic quadrangles
179   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_QUADRANGLE, SMDSEntity_Quadrangle,
180                               GmfExtraVerticesAtQuadrilaterals, quad )
181     node2IdMap[ quad->GetNode( 4 )],
182     node2IdMap[ quad->GetNode( 5 )],
183     node2IdMap[ quad->GetNode( 6 )],
184     node2IdMap[ quad->GetNode( 7 )],
185     node2IdMap[ quad->GetNodeWrap( 8 )] // for QUAD9
186     END_EXTRA_VERTICES_WRITE();
187
188   // terahedra
189   BEGIN_ELEM_WRITE( SMDSGeom_TETRA, GmfTetrahedra, tetra )
190     node2IdMap[ tetra->GetNode( 0 )],
191     node2IdMap[ tetra->GetNode( 2 )],
192     node2IdMap[ tetra->GetNode( 1 )],
193     node2IdMap[ tetra->GetNode( 3 )],
194     END_ELEM_WRITE( tetra );
195
196   // nodes of quadratic terahedra
197   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TETRA, SMDSEntity_Tetra,
198                               GmfExtraVerticesAtTetrahedra, tetra )
199     node2IdMap[ tetra->GetNode( 6 )],
200     node2IdMap[ tetra->GetNode( 5 )],
201     node2IdMap[ tetra->GetNode( 4 )],
202     node2IdMap[ tetra->GetNode( 7 )],
203     node2IdMap[ tetra->GetNode( 9 )],
204     node2IdMap[ tetra->GetNode( 8 )]
205     //node2IdMap[ tetra->GetNodeWrap( 10 )], // for TETRA11
206     END_EXTRA_VERTICES_WRITE();
207
208   // pyramids
209   BEGIN_ELEM_WRITE( SMDSEntity_Pyramid, GmfPyramids, pyra )
210     node2IdMap[ pyra->GetNode( 3 )],
211     node2IdMap[ pyra->GetNode( 2 )],
212     node2IdMap[ pyra->GetNode( 1 )],
213     node2IdMap[ pyra->GetNode( 0 )],
214     node2IdMap[ pyra->GetNode( 4 )],
215     END_ELEM_WRITE( pyra );
216
217   // hexahedra
218   BEGIN_ELEM_WRITE( SMDSGeom_HEXA, GmfHexahedra, hexa )
219     node2IdMap[ hexa->GetNode( 0 )],
220     node2IdMap[ hexa->GetNode( 3 )],
221     node2IdMap[ hexa->GetNode( 2 )],
222     node2IdMap[ hexa->GetNode( 1 )],
223     node2IdMap[ hexa->GetNode( 4 )],
224     node2IdMap[ hexa->GetNode( 7 )],
225     node2IdMap[ hexa->GetNode( 6 )],
226     node2IdMap[ hexa->GetNode( 5 )],
227     END_ELEM_WRITE( hexa );
228
229   // nodes of quadratic hexahedra
230   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_HEXA, SMDSEntity_Hexa,
231                               GmfExtraVerticesAtHexahedra, hexa )
232     node2IdMap[ hexa->GetNode( 11 )], // HEXA20
233     node2IdMap[ hexa->GetNode( 10 )],
234     node2IdMap[ hexa->GetNode(  9 )],
235     node2IdMap[ hexa->GetNode(  8 )],
236     node2IdMap[ hexa->GetNode( 15 )],
237     node2IdMap[ hexa->GetNode( 14 )],
238     node2IdMap[ hexa->GetNode( 13 )],
239     node2IdMap[ hexa->GetNode( 12 )],
240     node2IdMap[ hexa->GetNode( 16 )],
241     node2IdMap[ hexa->GetNode( 19 )],
242     node2IdMap[ hexa->GetNodeWrap( 18 )], // + HEXA27
243     node2IdMap[ hexa->GetNodeWrap( 17 )],
244     node2IdMap[ hexa->GetNodeWrap( 20 )],
245     node2IdMap[ hexa->GetNodeWrap( 24 )],
246     node2IdMap[ hexa->GetNodeWrap( 23 )],
247     node2IdMap[ hexa->GetNodeWrap( 22 )],
248     node2IdMap[ hexa->GetNodeWrap( 21 )],
249     node2IdMap[ hexa->GetNodeWrap( 25 )],
250     node2IdMap[ hexa->GetNodeWrap( 26 )]
251     END_EXTRA_VERTICES_WRITE();
252
253   // prism
254   BEGIN_ELEM_WRITE( SMDSEntity_Penta, GmfPrisms, prism )
255     node2IdMap[ prism->GetNode( 0 )],
256     node2IdMap[ prism->GetNode( 2 )],
257     node2IdMap[ prism->GetNode( 1 )],
258     node2IdMap[ prism->GetNode( 3 )],
259     node2IdMap[ prism->GetNode( 5 )],
260     node2IdMap[ prism->GetNode( 4 )],
261     END_ELEM_WRITE( prism );
262
263
264   if ( _exportRequiredGroups )
265   {
266     // required entities
267     SMESH_Comment badGroups;
268     const std::set<SMESHDS_GroupBase*>&      groupSet = myMesh->GetGroups();
269     std::set<SMESHDS_GroupBase*>::const_iterator grIt = groupSet.begin();
270     for ( ; grIt != groupSet.end(); ++grIt )
271     {
272       const SMESHDS_GroupBase* group = *grIt;
273       std::string          groupName = group->GetStoreName();
274       std::string::size_type     pos = groupName.find( "_required_" );
275       if ( pos == std::string::npos ) continue;
276
277       int                    gmfKwd;
278       SMDSAbs_EntityType smdsEntity;
279       std::string entity = groupName.substr( pos + strlen("_required_"));
280       if      ( entity == "Vertices" ) {
281         gmfKwd     = GmfRequiredVertices;
282         smdsEntity = SMDSEntity_Node;
283       }
284       else if ( entity == "Edges" ) {
285         gmfKwd     = GmfRequiredEdges;
286         smdsEntity = SMDSEntity_Edge;
287       }
288       else if ( entity == "Triangles" ) {
289         gmfKwd     = GmfRequiredTriangles;
290         smdsEntity = SMDSEntity_Triangle;
291       }
292       else if ( entity == "Quadrilaterals" ) {
293         gmfKwd     = GmfRequiredQuadrilaterals;
294         smdsEntity = SMDSEntity_Quadrangle;
295       }
296       else {
297         addMessage( SMESH_Comment("Invalig gmf entity name: ") << entity, /*fatal=*/false );
298         continue;
299       }
300
301       // check elem type in the group
302       int nbOkElems = 0;
303       SMDS_ElemIteratorPtr elemIt = group->GetElements();
304       while ( elemIt->more() )
305         nbOkElems += ( elemIt->next()->GetEntityType() == smdsEntity );
306
307       if ( nbOkElems != group->Extent() && nbOkElems == 0 )
308       {
309         badGroups << " " << groupName;
310         continue;
311       }
312
313       // choose a TElem2IDMap
314       TElem2IDMap* elem2IDMap = 0;
315       if ( smdsEntity == SMDSEntity_Quadrangle    && nbOkElems != myMesh->NbFaces() )
316         elem2IDMap = & quad2IDMap;
317       else if ( smdsEntity == SMDSEntity_Triangle && nbOkElems != myMesh->NbFaces() )
318         elem2IDMap = & tria2IDMap;
319       else if ( smdsEntity == SMDSEntity_Edge     && nbOkElems != myMesh->NbEdges() )
320         elem2IDMap = & edge2IDMap;
321
322       // write the group
323       GmfSetKwd( meshID, gmfKwd, nbOkElems );
324       elemIt = group->GetElements();
325       if ( elem2IDMap )
326         for ( ; elemIt->more(); )
327         {
328           const SMDS_MeshElement* elem = elemIt->next();
329           if ( elem->GetEntityType() == smdsEntity )
330             GmfSetLin( meshID, gmfKwd, (*elem2IDMap)[ elem ] );
331         }
332       else
333         for ( int gmfID = 1; elemIt->more(); ++gmfID)
334         {
335           const SMDS_MeshElement* elem = elemIt->next();
336           if ( elem->GetEntityType() == smdsEntity )
337             GmfSetLin( meshID, gmfKwd, gmfID );
338         }
339
340     } // loop on groups
341
342     if ( !badGroups.empty() )
343       addMessage( SMESH_Comment("Groups of elements of inappropriate geometry:")
344                   << badGroups, /*fatal=*/false );
345   }
346
347   return DRS_OK;
348 }
349
350 Driver_Mesh::Status DriverGMF_Write::PerformSizeMap( const std::vector<ControlPnt>& points )
351 {
352 //   const int dim = 3, version = sizeof(long) == 4 ? 2 : 3;
353   const int dim = 3, version = 2; // Version 3 not supported by mg-hexa
354   
355   // Open files
356   int verticesFileID = GmfOpenMesh( myVerticesFile.c_str(), GmfWrite, version, dim );  
357   int solFileID = GmfOpenMesh( mySolFile.c_str(), GmfWrite, version, dim );
358   
359   int pointsNumber = points.size();
360   
361   // Vertices Keyword
362   GmfSetKwd( verticesFileID, GmfVertices, pointsNumber );
363   // SolAtVertices Keyword
364   int TypTab[] = {GmfSca};
365   GmfSetKwd(solFileID, GmfSolAtVertices, pointsNumber, 1, TypTab);
366   
367   // Read the control points information from the vector and write it into the files
368   std::vector<ControlPnt>::const_iterator points_it;
369   for (points_it = points.begin(); points_it != points.end(); points_it++ )
370   {
371     GmfSetLin( verticesFileID, GmfVertices, points_it->X(), points_it->Y(), points_it->Z(), 0 );
372     double ValTab[] = {points_it->Size()};
373     GmfSetLin( solFileID, GmfSolAtVertices, ValTab);
374   } 
375   
376   // Close Files
377   GmfCloseMesh( verticesFileID );
378   GmfCloseMesh( solFileID );
379
380   return DRS_OK;
381 }
382
383 std::vector<std::string> DriverGMF_Write::GetSizeMapFiles()
384 {
385   std::vector<std::string> files;
386   files.push_back(myVerticesFile);
387   files.push_back(mySolFile);
388   return files;
389 }
390
391 //================================================================================
392 /*!
393  * \brief Returns an iterator on elements of a certain type
394  */
395 //================================================================================
396
397 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_ElementType type)
398 {
399   return myMesh->elementsIterator(type);
400 }
401 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_EntityType type) 
402 {
403   return myMesh->elementEntityIterator(type);
404 }
405 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_GeometryType type)
406 {
407   return myMesh->elementGeomIterator(type);
408 }