Salome HOME
Merge remote branch 'origin/gdd/translations'
[modules/smesh.git] / src / DriverGMF / DriverGMF_Read.cxx
1 // Copyright (C) 2007-2015  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_Read.cxx
23 // Created   : Mon Sep 17 17:03:02 2012
24 // Author    : Edward AGAPOV (eap)
25
26 #include "DriverGMF_Read.hxx"
27 #include "DriverGMF.hxx"
28
29 #include "SMESHDS_Group.hxx"
30 #include "SMESHDS_Mesh.hxx"
31 #include "SMESH_Comment.hxx"
32 #include "SMESH_TypeDefs.hxx"
33
34 #include <Basics_Utils.hxx>
35
36 extern "C"
37 {
38 #include "libmesh5.h"
39 }
40
41 #include <stdarg.h>
42
43 // --------------------------------------------------------------------------------
44 DriverGMF_Read::DriverGMF_Read():
45   Driver_SMESHDS_Mesh(),
46   _makeRequiredGroups( true )
47 {
48 }
49 // --------------------------------------------------------------------------------
50 DriverGMF_Read::~DriverGMF_Read()
51 {
52 }
53
54 //================================================================================
55 /*!
56  * \brief Read a GMF file
57  */
58 //================================================================================
59
60 Driver_Mesh::Status DriverGMF_Read::Perform()
61 {
62   Kernel_Utils::Localizer loc;
63
64   Status status = DRS_OK;
65
66   int dim, version;
67
68   // open the file
69   int meshID = GmfOpenMesh( myFile.c_str(), GmfRead, &version, &dim );
70   if ( !meshID )
71   {
72     if ( DriverGMF::isExtensionCorrect( myFile ))
73       return addMessage( SMESH_Comment("Can't open for reading ") << myFile,
74                          /*fatal=*/true );
75     else
76       return addMessage( SMESH_Comment("Not '.mesh' or '.meshb' extension of file ") << myFile,
77                          /*fatal=*/true );
78   }
79   DriverGMF::MeshCloser aMeshCloser( meshID ); // An object closing GMF mesh at destruction
80
81   // Read nodes
82
83   int nbNodes = GmfStatKwd(meshID, GmfVertices);
84   if ( nbNodes < 1 )
85     return addMessage( "No nodes in the mesh", /*fatal=*/true );
86
87   GmfGotoKwd(meshID, GmfVertices);
88
89   int ref;
90
91   const int nodeIDShift = myMesh->GetMeshInfo().NbNodes();
92   if ( version != GmfFloat )
93   {
94     double x, y, z;
95     for ( int i = 1; i <= nbNodes; ++i )
96     {
97       GmfGetLin(meshID, GmfVertices, &x, &y, &z, &ref);
98       myMesh->AddNodeWithID( x,y,z, nodeIDShift + i);
99     }
100   }
101   else
102   {
103     float x, y, z;
104     for ( int i = 1; i <= nbNodes; ++i )
105     {
106       GmfGetLin(meshID, GmfVertices, &x, &y, &z, &ref);
107       myMesh->AddNodeWithID( x,y,z, nodeIDShift + i);
108     }
109   }
110
111   // Read elements
112
113   int iN[28]; // 28 - nb nodes in HEX27 (+ 1 for safety :)
114
115   /* Read edges */
116   const int edgeIDShift = myMesh->GetMeshInfo().NbElements();
117   if ( int nbEdges = GmfStatKwd(meshID, GmfEdges))
118   {
119     // read extra vertices for quadratic edges
120     std::vector<int> quadNodesAtEdges( nbEdges + 1, -1 );
121     if ( int nbQuadEdges = GmfStatKwd(meshID, GmfExtraVerticesAtEdges))
122     {
123       GmfGotoKwd(meshID, GmfExtraVerticesAtEdges);
124       for ( int i = 1; i <= nbQuadEdges; ++i )
125       {
126         GmfGetLin(meshID, GmfExtraVerticesAtEdges, &iN[0], &iN[1], &iN[2]);
127         if ( iN[1] >= 1 )
128           quadNodesAtEdges[ iN[0] ] = iN[2];
129       }
130     }
131     // create edges
132     GmfGotoKwd(meshID, GmfEdges);
133     for ( int i = 1; i <= nbEdges; ++i )
134     {
135       GmfGetLin(meshID, GmfEdges, &iN[0], &iN[1], &ref);
136       const int midN = quadNodesAtEdges[ i ];
137       if ( midN > 0 )
138       {
139         if ( !myMesh->AddEdgeWithID( iN[0], iN[1], midN, edgeIDShift + i ))
140           status = storeBadNodeIds( "GmfEdges + GmfExtraVerticesAtEdges",i,
141                                     3, iN[0], iN[1], midN);
142       }
143       else
144       {
145         if ( !myMesh->AddEdgeWithID( iN[0], iN[1], edgeIDShift + i ))
146           status = storeBadNodeIds( "GmfEdges",i, 2, iN[0], iN[1] );
147       }
148     }
149   }
150
151   /* Read triangles */
152   const int triaIDShift = myMesh->GetMeshInfo().NbElements();
153   if ( int nbTria = GmfStatKwd(meshID, GmfTriangles))
154   {
155     // read extra vertices for quadratic triangles
156     std::vector< std::vector<int> > quadNodesAtTriangles( nbTria + 1 );
157     if ( int nbQuadTria = GmfStatKwd(meshID, GmfExtraVerticesAtTriangles ))
158     {
159       GmfGotoKwd( meshID, GmfExtraVerticesAtTriangles );
160       for ( int i = 1; i <= nbQuadTria; ++i )
161       {
162         GmfGetLin(meshID, GmfExtraVerticesAtTriangles,
163                   &iN[0], &iN[1], &iN[2], &iN[3], &iN[4],
164                   &iN[5]); // iN[5] - preview TRIA7
165         if ( iN[0] <= nbTria )
166         {
167           std::vector<int>& nodes = quadNodesAtTriangles[ iN[0] ];
168           nodes.insert( nodes.end(), & iN[2], & iN[5+1] );
169           nodes.resize( iN[1] );
170         }
171       }
172     }
173     // create triangles
174     GmfGotoKwd(meshID, GmfTriangles);
175     for ( int i = 1; i <= nbTria; ++i )
176     {
177       GmfGetLin(meshID, GmfTriangles, &iN[0], &iN[1], &iN[2], &ref);
178       std::vector<int>& midN = quadNodesAtTriangles[ i ];
179       if ( midN.size() >= 3 )
180       {
181         if ( !myMesh->AddFaceWithID( iN[0],iN[1],iN[2], midN[0],midN[1],midN[2],
182                                      triaIDShift + i ))
183           status = storeBadNodeIds( "GmfTriangles + GmfExtraVerticesAtTriangles",i, 6,
184                                     iN[0],iN[1],iN[2], midN[0],midN[1],midN[2] );
185       }
186       else
187       {
188         if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], triaIDShift + i ))
189           status = storeBadNodeIds( "GmfTriangles",i, 3, iN[0], iN[1], iN[2] );
190       }
191       if ( !midN.empty() ) SMESHUtils::FreeVector( midN );
192     }
193   }
194
195   /* Read quadrangles */
196   const int quadIDShift = myMesh->GetMeshInfo().NbElements();
197   if ( int nbQuad = GmfStatKwd(meshID, GmfQuadrilaterals))
198   {
199     // read extra vertices for quadratic quadrangles
200     std::vector< std::vector<int> > quadNodesAtQuadrilaterals( nbQuad + 1 );
201     if ( int nbQuadQuad = GmfStatKwd( meshID, GmfExtraVerticesAtQuadrilaterals ))
202     {
203       GmfGotoKwd(meshID, GmfExtraVerticesAtQuadrilaterals);
204       for ( int i = 1; i <= nbQuadQuad; ++i )
205       {
206         GmfGetLin(meshID, GmfExtraVerticesAtQuadrilaterals,
207                   &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &iN[6]);
208         if ( iN[0] <= nbQuad )
209         {
210           std::vector<int>& nodes = quadNodesAtQuadrilaterals[ iN[0] ];
211           nodes.insert( nodes.end(), & iN[2], & iN[6+1] );
212           nodes.resize( iN[1] );
213         }
214       }
215     }
216     // create quadrangles
217     GmfGotoKwd(meshID, GmfQuadrilaterals);
218     for ( int i = 1; i <= nbQuad; ++i )
219     {
220       GmfGetLin(meshID, GmfQuadrilaterals, &iN[0], &iN[1], &iN[2], &iN[3], &ref);
221       std::vector<int>& midN = quadNodesAtQuadrilaterals[ i ];
222       if ( midN.size() == 8-4 ) // QUAD8
223       {
224         if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3],
225                                      midN[0], midN[1], midN[2], midN[3],
226                                      quadIDShift + i ))
227           status = storeBadNodeIds( "GmfQuadrilaterals + GmfExtraVerticesAtQuadrilaterals",i, 8,
228                                     iN[0], iN[1],iN[2], iN[3],
229                                     midN[0], midN[1], midN[2], midN[3]);
230       }
231       else if ( midN.size() > 8-4 ) // QUAD9
232       {
233         if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3],
234                                      midN[0], midN[1], midN[2], midN[3], midN[4],
235                                      quadIDShift + i ))
236           status = storeBadNodeIds( "GmfQuadrilaterals + GmfExtraVerticesAtQuadrilaterals",i, 9,
237                                     iN[0], iN[1],iN[2], iN[3],
238                                     midN[0], midN[1], midN[2], midN[3], midN[4]);
239       }
240       else // QUAD4
241       {
242         if ( !myMesh->AddFaceWithID( iN[0], iN[1], iN[2], iN[3], quadIDShift + i ))
243           status = storeBadNodeIds( "GmfQuadrilaterals",i, 4, iN[0], iN[1],iN[2], iN[3] );
244       }
245       if ( !midN.empty() ) SMESHUtils::FreeVector( midN );
246     }
247   }
248
249   /* Read terahedra */
250   const int tetIDShift = myMesh->GetMeshInfo().NbElements();
251   if ( int nbTet = GmfStatKwd( meshID, GmfTetrahedra ))
252   {
253     // read extra vertices for quadratic tetrahedra
254     std::vector< std::vector<int> > quadNodesAtTetrahedra( nbTet + 1 );
255     if ( int nbQuadTetra = GmfStatKwd( meshID, GmfExtraVerticesAtTetrahedra ))
256     {
257       GmfGotoKwd(meshID, GmfExtraVerticesAtTetrahedra);
258       for ( int i = 1; i <= nbQuadTetra; ++i )
259       {
260         GmfGetLin(meshID, GmfExtraVerticesAtTetrahedra,
261                   &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &iN[6], &iN[7]);
262         if ( iN[0] <= nbTet )
263         {
264           std::vector<int>& nodes = quadNodesAtTetrahedra[ iN[0] ];
265           nodes.insert( nodes.end(), & iN[2], & iN[7+1] );
266           nodes.resize( iN[1] );
267         }
268       }
269     }
270     // create tetrahedra
271     GmfGotoKwd(meshID, GmfTetrahedra);
272     for ( int i = 1; i <= nbTet; ++i )
273     {
274       GmfGetLin(meshID, GmfTetrahedra, &iN[0], &iN[1], &iN[2], &iN[3], &ref);
275       std::vector<int>& midN = quadNodesAtTetrahedra[ i ];  
276       if ( midN.size() >= 10-4 ) // TETRA10
277       {
278         if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], 
279                                        midN[2], midN[1], midN[0], midN[3], midN[5], midN[4],
280                                        tetIDShift + i ))
281           status = storeBadNodeIds( "GmfTetrahedra + GmfExtraVerticesAtTetrahedra",i, 10,
282                                     iN[0], iN[2], iN[1], iN[3], 
283                                     midN[2], midN[1], midN[0], midN[3], midN[5], midN[4] );
284       }
285       else // TETRA4
286       {
287         if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], tetIDShift + i ))
288           status = storeBadNodeIds( "GmfTetrahedra" ,i, 4, iN[0], iN[2], iN[1], iN[3] );
289       }
290       if ( !midN.empty() ) SMESHUtils::FreeVector( midN );
291     }
292   }
293
294   /* Read pyramids */
295   const int pyrIDShift = myMesh->GetMeshInfo().NbElements();
296   if ( int nbPyr = GmfStatKwd(meshID, GmfPyramids))
297   {
298     GmfGotoKwd(meshID, GmfPyramids);
299     for ( int i = 1; i <= nbPyr; ++i )
300     {
301       GmfGetLin(meshID, GmfPyramids, &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &ref);
302       if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], iN[4], pyrIDShift + i ))
303         status = storeBadNodeIds( "GmfPyramids",i, 5, iN[0], iN[1],iN[2], iN[3], iN[4] );
304     }
305   }
306
307   /* Read hexahedra */
308   const int hexIDShift = myMesh->GetMeshInfo().NbElements();
309   if ( int nbHex = GmfStatKwd(meshID, GmfHexahedra))
310   {
311     // read extra vertices for quadratic hexahedra
312     std::vector< std::vector<int> > quadNodesAtHexahedra( nbHex + 1 );
313     if ( int nbQuadHexa = GmfStatKwd( meshID, GmfExtraVerticesAtHexahedra ))
314     {
315       GmfGotoKwd(meshID, GmfExtraVerticesAtHexahedra);
316       for ( int i = 1; i <= nbQuadHexa; ++i )
317       {
318         GmfGetLin(meshID, GmfExtraVerticesAtHexahedra, &iN[0], &iN[1], // Hexa Id, Nb extra vertices
319                   &iN[2], &iN[3], &iN[4], &iN[5],
320                   &iN[6], &iN[7], &iN[8], &iN[9],
321                   &iN[10], &iN[11], &iN[12], &iN[13], // HEXA20
322                   &iN[14],
323                   &iN[15], &iN[16], &iN[17], &iN[18], 
324                   &iN[19],
325                   &iN[20]);                          // HEXA27
326         if ( iN[0] <= nbHex )
327         {
328           std::vector<int>& nodes = quadNodesAtHexahedra[ iN[0] ];
329           nodes.insert( nodes.end(), & iN[2], & iN[20+1] );
330           nodes.resize( iN[1] );
331         }
332       }
333     }
334     // create hexhedra
335     GmfGotoKwd(meshID, GmfHexahedra);
336     for ( int i = 1; i <= nbHex; ++i )
337     {
338       GmfGetLin(meshID, GmfHexahedra, &iN[0], &iN[1], &iN[2], &iN[3],
339                 &iN[4], &iN[5], &iN[6], &iN[7], &ref);
340       std::vector<int>& midN = quadNodesAtHexahedra[ i ];
341       if ( midN.size() == 20-8 ) // HEXA20
342       {
343         if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1],
344                                        iN[4], iN[7], iN[6], iN[5],
345                                        midN[3], midN[2], midN[1], midN[0],
346                                        midN[7], midN[6], midN[5], midN[4],
347                                        midN[8], midN[11], midN[10], midN[9],
348                                        hexIDShift + i ))
349           status = storeBadNodeIds( "GmfHexahedra + GmfExtraVerticesAtHexahedra",i, 20, 
350                                     iN[0], iN[3], iN[2], iN[1],
351                                     iN[4], iN[7], iN[6], iN[5],
352                                     midN[3], midN[2], midN[1], midN[0],
353                                     midN[7], midN[6], midN[5], midN[4],
354                                     midN[8], midN[11], midN[10], midN[9]);
355       }
356       else if ( midN.size() >= 27-8 ) // HEXA27
357       {
358         if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1],
359                                        iN[4], iN[7], iN[6], iN[5],
360                                        midN[3], midN[2], midN[1], midN[0],
361                                        midN[7], midN[6], midN[5], midN[4],
362                                        midN[8], midN[11], midN[10], midN[9],
363                                        midN[12],
364                                        midN[16], midN[15], midN[14], midN[13],
365                                        midN[17],
366                                        midN[18],
367                                        hexIDShift + i ))
368           status = storeBadNodeIds( "GmfHexahedra + GmfExtraVerticesAtHexahedra",i, 27, 
369                                     iN[0], iN[3], iN[2], iN[1],
370                                     iN[4], iN[7], iN[6], iN[5],
371                                     midN[3], midN[2], midN[1], midN[0],
372                                     midN[7], midN[6], midN[5], midN[4],
373                                     midN[8], midN[11], midN[10], midN[9],
374                                     midN[12],
375                                     midN[16], midN[15], midN[14], midN[13],
376                                     midN[17],
377                                     midN[18]);
378       }
379       else // HEXA8
380       {
381         if ( !myMesh->AddVolumeWithID( iN[0], iN[3], iN[2], iN[1],
382                                        iN[4], iN[7], iN[6], iN[5], hexIDShift + i ) )
383           status = storeBadNodeIds( "GmfHexahedra" ,i, 8, iN[0], iN[3], iN[2], iN[1],
384                                     iN[4], iN[7], iN[6], iN[5] );
385       }
386       if ( !midN.empty() ) SMESHUtils::FreeVector( midN );
387     }
388   }
389
390   /* Read prism */
391   const int prismIDShift = myMesh->GetMeshInfo().NbElements();
392   if ( int nbPrism = GmfStatKwd(meshID, GmfPrisms))
393   {
394     GmfGotoKwd(meshID, GmfPrisms);
395     for ( int i = 1; i <= nbPrism; ++i )
396     {
397       GmfGetLin(meshID, GmfPrisms, &iN[0], &iN[1], &iN[2], &iN[3], &iN[4], &iN[5], &ref);
398       if ( !myMesh->AddVolumeWithID( iN[0], iN[2], iN[1], iN[3], iN[5], iN[4], prismIDShift + i))
399         status = storeBadNodeIds( "GmfPrisms",i,
400                                   6, iN[0], iN[1],iN[2], iN[3], iN[4], iN[5] );
401     }
402   }
403
404   // Read required entities into groups
405
406   if ( _makeRequiredGroups )
407   {
408     // get ids of existing groups
409     std::set< int > groupIDs;
410     const std::set<SMESHDS_GroupBase*>& groups = myMesh->GetGroups();
411     std::set<SMESHDS_GroupBase*>::const_iterator grIter = groups.begin();
412     for ( ; grIter != groups.end(); ++grIter )
413       groupIDs.insert( (*grIter)->GetID() );
414     if ( groupIDs.empty() ) groupIDs.insert( 0 );
415
416     const int kes[4][3] = { { GmfRequiredVertices,      SMDSAbs_Node, nodeIDShift },
417                             { GmfRequiredEdges,         SMDSAbs_Edge, edgeIDShift },
418                             { GmfRequiredTriangles,     SMDSAbs_Face, triaIDShift },
419                             { GmfRequiredQuadrilaterals,SMDSAbs_Face, quadIDShift }};
420     const char* names[4] = { "_required_Vertices"      ,
421                              "_required_Edges"         ,
422                              "_required_Triangles"     ,
423                              "_required_Quadrilaterals" };
424     for ( int i = 0; i < 4; ++i )
425     {
426       int                 gmfKwd = kes[i][0];
427       SMDSAbs_ElementType entity = (SMDSAbs_ElementType) kes[i][1];
428       int                 shift  = kes[i][2];
429       if ( int nb = GmfStatKwd(meshID, gmfKwd))
430       {
431         const int newID = *groupIDs.rbegin() + 1;
432         groupIDs.insert( newID );
433         SMESHDS_Group* group = new SMESHDS_Group( newID, myMesh, entity );
434         group->SetStoreName( names[i] );
435         myMesh->AddGroup( group );
436
437         GmfGotoKwd(meshID, gmfKwd);
438         for ( int i = 0; i < nb; ++i )
439         {
440           GmfGetLin(meshID, gmfKwd, &iN[0] );
441           group->Add( shift + iN[0] );
442         }
443       }
444     }
445   }
446
447   return status;
448 }
449
450 //================================================================================
451 /*!
452  * \brief Store a message about invalid IDs of nodes
453  */
454 //================================================================================
455
456 Driver_Mesh::Status DriverGMF_Read::storeBadNodeIds(const char* gmfKwd, int elemNb, int nb, ...)
457 {
458   if ( myStatus != DRS_OK )
459     return myStatus;
460
461   SMESH_Comment msg;
462
463   va_list VarArg;
464   va_start(VarArg, nb);
465
466   for ( int i = 0; i < nb; ++i )
467   {
468     int id = va_arg(VarArg, int );
469     if ( !myMesh->FindNode( id ))
470       msg << " " << id;
471   }
472   va_end(VarArg);
473
474   if ( !msg.empty() )
475   {
476     std::string nbStr;
477     const char* nbNames[] = { "1-st ", "2-nd ", "3-d " };
478     if ( elemNb < 3 ) nbStr = nbNames[ elemNb-1 ];
479     else              nbStr = SMESH_Comment(elemNb) << "-th ";
480
481     return addMessage
482       ( SMESH_Comment("Wrong node IDs of ")<< nbStr << gmfKwd << ":" << msg,
483         /*fatal=*/false );
484   }
485   return DRS_OK;
486 }