Salome HOME
Merge branch 'V8_2_BR' into pre/V8_2_BR
[modules/smesh.git] / src / DriverGMF / DriverGMF_Write.cxx
1 // Copyright (C) 2007-2016  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   int totalNbElems  = myMesh->GetMeshInfo().NbElements( SMDSGeom );     \
61   int 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   const int dim = 3, version = sizeof(double) < 8 ? 1 : 2;
104
105   int meshID = GmfOpenMesh( myFile.c_str(), GmfWrite, version, dim );
106   if ( !meshID )
107   {
108     if ( DriverGMF::isExtensionCorrect( myFile ))
109       return addMessage( SMESH_Comment("Can't open for writing ") << myFile, /*fatal=*/true );
110     else
111       return addMessage( SMESH_Comment("Not '.mesh' or '.meshb' extension of file ") << myFile, /*fatal=*/true );
112   }
113
114   DriverGMF::MeshCloser aMeshCloser( meshID ); // An object closing GMF mesh at destruction
115
116   // nodes
117   std::map< const SMDS_MeshNode* , int > node2IdMap;
118   int iN = 0, nbNodes = myMesh->NbNodes();
119   GmfSetKwd( meshID, GmfVertices, nbNodes );
120   double xyz[3];
121   SMDS_NodeIteratorPtr nodeIt = myMesh->nodesIterator();
122   while ( nodeIt->more() )
123   {
124     const SMDS_MeshNode* n = nodeIt->next();
125     n->GetXYZ( xyz );
126     GmfSetLin( meshID, GmfVertices, xyz[0], xyz[1], xyz[2], n->getshapeId() );
127     node2IdMap.insert( node2IdMap.end(), std::make_pair( n, ++iN ));
128   }
129   if ( iN != nbNodes )
130     return addMessage("Wrong nb of nodes returned by nodesIterator", /*fatal=*/true);
131
132
133   SMDS_ElemIteratorPtr elemIt;
134   typedef std::map< const SMDS_MeshElement*, size_t, TIDCompare > TElem2IDMap;
135
136   // edges
137   TElem2IDMap edge2IDMap;
138   BEGIN_ELEM_WRITE( SMDSGeom_EDGE, GmfEdges, edge )
139     node2IdMap[ edge->GetNode( 0 )],
140     node2IdMap[ edge->GetNode( 1 )],
141     END_ELEM_WRITE_ADD_TO_MAP( edge, edge2IDMap );
142
143   // nodes of quadratic edges
144   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_EDGE, SMDSEntity_Edge,
145                               GmfExtraVerticesAtEdges, edge )
146     node2IdMap[ edge->GetNode( 2 )]
147     END_EXTRA_VERTICES_WRITE();
148
149   // triangles
150   TElem2IDMap tria2IDMap;
151   BEGIN_ELEM_WRITE( SMDSGeom_TRIANGLE, GmfTriangles, tria )
152     node2IdMap[ tria->GetNode( 0 )],
153     node2IdMap[ tria->GetNode( 1 )],
154     node2IdMap[ tria->GetNode( 2 )],
155     END_ELEM_WRITE_ADD_TO_MAP( tria, tria2IDMap );
156
157   // nodes of quadratic triangles
158   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TRIANGLE, SMDSEntity_Triangle,
159                               GmfExtraVerticesAtTriangles, tria )
160     node2IdMap[ tria->GetNode( 3 )],
161     node2IdMap[ tria->GetNode( 4 )],
162     node2IdMap[ tria->GetNode( 5 )],
163     node2IdMap[ tria->GetNodeWrap( 6 )] // for TRIA7
164     END_EXTRA_VERTICES_WRITE();
165
166   // quadrangles
167   TElem2IDMap quad2IDMap;
168   BEGIN_ELEM_WRITE( SMDSGeom_QUADRANGLE, GmfQuadrilaterals, quad )
169     node2IdMap[ quad->GetNode( 0 )],
170     node2IdMap[ quad->GetNode( 1 )],
171     node2IdMap[ quad->GetNode( 2 )],
172     node2IdMap[ quad->GetNode( 3 )],
173     END_ELEM_WRITE_ADD_TO_MAP( quad, quad2IDMap );
174
175   // nodes of quadratic quadrangles
176   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_QUADRANGLE, SMDSEntity_Quadrangle,
177                               GmfExtraVerticesAtQuadrilaterals, quad )
178     node2IdMap[ quad->GetNode( 4 )],
179     node2IdMap[ quad->GetNode( 5 )],
180     node2IdMap[ quad->GetNode( 6 )],
181     node2IdMap[ quad->GetNode( 7 )],
182     node2IdMap[ quad->GetNodeWrap( 8 )] // for QUAD9
183     END_EXTRA_VERTICES_WRITE();
184
185   // terahedra
186   BEGIN_ELEM_WRITE( SMDSGeom_TETRA, GmfTetrahedra, tetra )
187     node2IdMap[ tetra->GetNode( 0 )],
188     node2IdMap[ tetra->GetNode( 2 )],
189     node2IdMap[ tetra->GetNode( 1 )],
190     node2IdMap[ tetra->GetNode( 3 )],
191     END_ELEM_WRITE( tetra );
192
193   // nodes of quadratic terahedra
194   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_TETRA, SMDSEntity_Tetra,
195                               GmfExtraVerticesAtTetrahedra, tetra )
196     node2IdMap[ tetra->GetNode( 6 )],
197     node2IdMap[ tetra->GetNode( 5 )],
198     node2IdMap[ tetra->GetNode( 4 )],
199     node2IdMap[ tetra->GetNode( 7 )],
200     node2IdMap[ tetra->GetNode( 9 )],
201     node2IdMap[ tetra->GetNode( 8 )]
202     //node2IdMap[ tetra->GetNodeWrap( 10 )], // for TETRA11
203     END_EXTRA_VERTICES_WRITE();
204
205   // pyramids
206   BEGIN_ELEM_WRITE( SMDSEntity_Pyramid, GmfPyramids, pyra )
207     node2IdMap[ pyra->GetNode( 3 )],
208     node2IdMap[ pyra->GetNode( 2 )],
209     node2IdMap[ pyra->GetNode( 1 )],
210     node2IdMap[ pyra->GetNode( 0 )],
211     node2IdMap[ pyra->GetNode( 4 )],
212     END_ELEM_WRITE( pyra );
213
214   // hexahedra
215   BEGIN_ELEM_WRITE( SMDSGeom_HEXA, GmfHexahedra, hexa )
216     node2IdMap[ hexa->GetNode( 0 )],
217     node2IdMap[ hexa->GetNode( 3 )],
218     node2IdMap[ hexa->GetNode( 2 )],
219     node2IdMap[ hexa->GetNode( 1 )],
220     node2IdMap[ hexa->GetNode( 4 )],
221     node2IdMap[ hexa->GetNode( 7 )],
222     node2IdMap[ hexa->GetNode( 6 )],
223     node2IdMap[ hexa->GetNode( 5 )],
224     END_ELEM_WRITE( hexa );
225
226   // nodes of quadratic hexahedra
227   BEGIN_EXTRA_VERTICES_WRITE( SMDSGeom_HEXA, SMDSEntity_Hexa,
228                               GmfExtraVerticesAtHexahedra, hexa )
229     node2IdMap[ hexa->GetNode( 11 )], // HEXA20
230     node2IdMap[ hexa->GetNode( 10 )],
231     node2IdMap[ hexa->GetNode(  9 )],
232     node2IdMap[ hexa->GetNode(  8 )],
233     node2IdMap[ hexa->GetNode( 15 )],
234     node2IdMap[ hexa->GetNode( 14 )],
235     node2IdMap[ hexa->GetNode( 13 )],
236     node2IdMap[ hexa->GetNode( 12 )],
237     node2IdMap[ hexa->GetNode( 16 )],
238     node2IdMap[ hexa->GetNode( 19 )],
239     node2IdMap[ hexa->GetNodeWrap( 18 )], // + HEXA27
240     node2IdMap[ hexa->GetNodeWrap( 17 )],
241     node2IdMap[ hexa->GetNodeWrap( 20 )],
242     node2IdMap[ hexa->GetNodeWrap( 24 )],
243     node2IdMap[ hexa->GetNodeWrap( 23 )],
244     node2IdMap[ hexa->GetNodeWrap( 22 )],
245     node2IdMap[ hexa->GetNodeWrap( 21 )],
246     node2IdMap[ hexa->GetNodeWrap( 25 )],
247     node2IdMap[ hexa->GetNodeWrap( 26 )]
248     END_EXTRA_VERTICES_WRITE();
249
250   // prism
251   BEGIN_ELEM_WRITE( SMDSEntity_Penta, GmfPrisms, prism )
252     node2IdMap[ prism->GetNode( 0 )],
253     node2IdMap[ prism->GetNode( 2 )],
254     node2IdMap[ prism->GetNode( 1 )],
255     node2IdMap[ prism->GetNode( 3 )],
256     node2IdMap[ prism->GetNode( 5 )],
257     node2IdMap[ prism->GetNode( 4 )],
258     END_ELEM_WRITE( prism );
259
260
261   if ( _exportRequiredGroups )
262   {
263     // required entities
264     SMESH_Comment badGroups;
265     const std::set<SMESHDS_GroupBase*>&      groupSet = myMesh->GetGroups();
266     std::set<SMESHDS_GroupBase*>::const_iterator grIt = groupSet.begin();
267     for ( ; grIt != groupSet.end(); ++grIt )
268     {
269       const SMESHDS_GroupBase* group = *grIt;
270       std::string          groupName = group->GetStoreName();
271       std::string::size_type     pos = groupName.find( "_required_" );
272       if ( pos == std::string::npos ) continue;
273
274       int                    gmfKwd;
275       SMDSAbs_EntityType smdsEntity;
276       std::string entity = groupName.substr( pos + strlen("_required_"));
277       if      ( entity == "Vertices" ) {
278         gmfKwd     = GmfRequiredVertices;
279         smdsEntity = SMDSEntity_Node;
280       }
281       else if ( entity == "Edges" ) {
282         gmfKwd     = GmfRequiredEdges;
283         smdsEntity = SMDSEntity_Edge;
284       }
285       else if ( entity == "Triangles" ) {
286         gmfKwd     = GmfRequiredTriangles;
287         smdsEntity = SMDSEntity_Triangle;
288       }
289       else if ( entity == "Quadrilaterals" ) {
290         gmfKwd     = GmfRequiredQuadrilaterals;
291         smdsEntity = SMDSEntity_Quadrangle;
292       }
293       else {
294         addMessage( SMESH_Comment("Invalig gmf entity name: ") << entity, /*fatal=*/false );
295         continue;
296       }
297
298       // check elem type in the group
299       int nbOkElems = 0;
300       SMDS_ElemIteratorPtr elemIt = group->GetElements();
301       while ( elemIt->more() )
302         nbOkElems += ( elemIt->next()->GetEntityType() == smdsEntity );
303
304       if ( nbOkElems != group->Extent() && nbOkElems == 0 )
305       {
306         badGroups << " " << groupName;
307         continue;
308       }
309
310       // choose a TElem2IDMap
311       TElem2IDMap* elem2IDMap = 0;
312       if ( smdsEntity == SMDSEntity_Quadrangle    && nbOkElems != myMesh->NbFaces() )
313         elem2IDMap = & quad2IDMap;
314       else if ( smdsEntity == SMDSEntity_Triangle && nbOkElems != myMesh->NbFaces() )
315         elem2IDMap = & tria2IDMap;
316       else if ( smdsEntity == SMDSEntity_Edge     && nbOkElems != myMesh->NbEdges() )
317         elem2IDMap = & edge2IDMap;
318
319       // write the group
320       GmfSetKwd( meshID, gmfKwd, nbOkElems );
321       elemIt = group->GetElements();
322       if ( elem2IDMap )
323         for ( ; elemIt->more(); )
324         {
325           const SMDS_MeshElement* elem = elemIt->next();
326           if ( elem->GetEntityType() == smdsEntity )
327             GmfSetLin( meshID, gmfKwd, (*elem2IDMap)[ elem ] );
328         }
329       else
330         for ( int gmfID = 1; elemIt->more(); ++gmfID)
331         {
332           const SMDS_MeshElement* elem = elemIt->next();
333           if ( elem->GetEntityType() == smdsEntity )
334             GmfSetLin( meshID, gmfKwd, gmfID );
335         }
336
337     } // loop on groups
338
339     if ( !badGroups.empty() )
340       addMessage( SMESH_Comment("Groups of elements of inappropriate geometry:")
341                   << badGroups, /*fatal=*/false );
342   }
343
344   return DRS_OK;
345 }
346
347 Driver_Mesh::Status DriverGMF_Write::PerformSizeMap( const std::vector<ControlPnt>& points )
348 {
349 //   const int dim = 3, version = sizeof(long) == 4 ? 2 : 3;
350   const int dim = 3, version = 2; // Version 3 not supported by mg-hexa
351   
352   // Open files
353   int verticesFileID = GmfOpenMesh( myVerticesFile.c_str(), GmfWrite, version, dim );  
354   int solFileID = GmfOpenMesh( mySolFile.c_str(), GmfWrite, version, dim );
355   
356   int pointsNumber = points.size();
357   
358   // Vertices Keyword
359   GmfSetKwd( verticesFileID, GmfVertices, pointsNumber );
360   // SolAtVertices Keyword
361   int TypTab[] = {GmfSca};
362   GmfSetKwd(solFileID, GmfSolAtVertices, pointsNumber, 1, TypTab);
363   
364   // Read the control points information from the vector and write it into the files
365   std::vector<ControlPnt>::const_iterator points_it;
366   for (points_it = points.begin(); points_it != points.end(); points_it++ )
367   {
368     GmfSetLin( verticesFileID, GmfVertices, points_it->X(), points_it->Y(), points_it->Z(), 0 );
369     double ValTab[] = {points_it->Size()};
370     GmfSetLin( solFileID, GmfSolAtVertices, ValTab);
371   } 
372   
373   // Close Files
374   GmfCloseMesh( verticesFileID );
375   GmfCloseMesh( solFileID );
376
377   return DRS_OK;
378 }
379
380 std::vector<std::string> DriverGMF_Write::GetSizeMapFiles()
381 {
382   std::vector<std::string> files;
383   files.push_back(myVerticesFile);
384   files.push_back(mySolFile);
385   return files;
386 }
387
388 //================================================================================
389 /*!
390  * \brief Returns an iterator on elements of a certain type
391  */
392 //================================================================================
393
394 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_ElementType type)
395 {
396   return myMesh->elementsIterator(type);
397 }
398 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_EntityType type) 
399 {
400   return myMesh->elementEntityIterator(type);
401 }
402 SMDS_ElemIteratorPtr DriverGMF_Write::elementIterator(SMDSAbs_GeometryType type)
403 {
404   return myMesh->elementGeomIterator(type);
405 }