Salome HOME
0022107: EDF 2502 SMESH: Publish the result of show bad mesh in a group
[modules/smesh.git] / src / DriverSTL / DriverSTL_W_SMDS_Mesh.cxx
1 // Copyright (C) 2007-2013  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.
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
23 #include <stdio.h>
24 #include <limits>
25
26 #include "DriverSTL_W_SMDS_Mesh.h"
27
28 #include "SMDS_FaceOfNodes.hxx"
29 #include "SMDS_IteratorOnIterators.hxx"
30 #include "SMDS_Mesh.hxx"
31 #include "SMDS_MeshElement.hxx"
32 #include "SMDS_MeshNode.hxx"
33 #include "SMDS_SetIterator.hxx"
34 #include "SMDS_VolumeTool.hxx"
35 #include "SMESH_TypeDefs.hxx"
36
37 #include <OSD_File.hxx>
38 #include <OSD_Path.hxx>
39 #include <OSD_Protection.hxx>
40 #include <TCollection_AsciiString.hxx>
41 #include <gp_XYZ.hxx>
42 #include <Basics_Utils.hxx>
43
44 #include "utilities.h"
45
46 // definition des constantes 
47 static const int LABEL_SIZE = 80;
48
49 DriverSTL_W_SMDS_Mesh::DriverSTL_W_SMDS_Mesh()
50 {
51   myIsAscii = false;
52 }
53
54 void DriverSTL_W_SMDS_Mesh::SetIsAscii( const bool theIsAscii )
55 {
56   myIsAscii = theIsAscii;
57 }
58
59 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::Perform()
60 {
61   Kernel_Utils::Localizer loc;
62
63   Status aResult = DRS_OK;
64
65   if ( !myMesh ) {
66     fprintf(stderr, ">> ERROR : Mesh is null \n");
67     return DRS_FAIL;
68   }
69   findVolumeTriangles();
70   if ( myIsAscii )
71     aResult = writeAscii();
72   else
73     aResult = writeBinary();
74
75   return aResult;
76 }
77 //================================================================================
78 /*!
79  * \brief Destructor deletes temporary faces
80  */
81 //================================================================================
82
83 DriverSTL_W_SMDS_Mesh::~DriverSTL_W_SMDS_Mesh()
84 {
85   for ( unsigned i = 0; i < myVolumeTrias.size(); ++i )
86     delete myVolumeTrias[i];
87 }
88
89 //================================================================================
90 /*!
91  * \brief Finds free facets of volumes for which faces are missing in the mesh
92  */
93 //================================================================================
94
95 void DriverSTL_W_SMDS_Mesh::findVolumeTriangles()
96 {
97   SMDS_VolumeTool theVolume;
98   SMDS_VolumeIteratorPtr vIt = myMesh->volumesIterator();
99   std::vector< const SMDS_MeshNode*> nodes;
100   while ( vIt->more() )
101   {
102     theVolume.Set( vIt->next(), /*ignoreCentralNodes=*/false );
103     for ( int iF = 0; iF < theVolume.NbFaces(); ++iF )
104       if ( theVolume.IsFreeFace( iF ))
105       {
106         const SMDS_MeshNode** n = theVolume.GetFaceNodes(iF);
107         int                 nbN = theVolume.NbFaceNodes(iF);
108         nodes.assign( n, n+nbN );
109         if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
110         {
111           if ( nbN == 9 && !theVolume.IsPoly() ) // facet is SMDSEntity_BiQuad_Quadrangle
112           {
113             int nbTria = nbN - 1;
114             for ( int iT = 0; iT < nbTria; ++iT )
115               myVolumeTrias.push_back( new SMDS_FaceOfNodes( n[8], n[0+iT], n[1+iT] ));
116           }
117           else
118           {
119             int nbTria = nbN - 2;
120             for ( int iT = 0; iT < nbTria; ++iT )
121               myVolumeTrias.push_back( new SMDS_FaceOfNodes( n[0], n[1+iT], n[2+iT] ));
122           }
123         }
124       }
125   }
126 }
127
128 //================================================================================
129 /*!
130  * \brief Return iterator on both faces in the mesh and on temporary faces
131  */
132 //================================================================================
133
134 SMDS_ElemIteratorPtr DriverSTL_W_SMDS_Mesh::getFaces() const
135 {
136   SMDS_ElemIteratorPtr facesIter = myMesh->elementsIterator(SMDSAbs_Face);
137   SMDS_ElemIteratorPtr tmpTriaIter( new SMDS_ElementVectorIterator( myVolumeTrias.begin(),
138                                                                     myVolumeTrias.end()));
139   typedef std::vector< SMDS_ElemIteratorPtr > TElemIterVector;
140   TElemIterVector iters(2);
141   iters[0] = facesIter;
142   iters[1] = tmpTriaIter;
143   
144   typedef SMDS_IteratorOnIterators<const SMDS_MeshElement *, TElemIterVector> TItersIter;
145   return SMDS_ElemIteratorPtr( new TItersIter( iters ));
146 }
147
148 // static methods
149
150 static void writeInteger( const Standard_Integer& theVal, OSD_File& ofile )
151 {
152   union {
153     Standard_Integer i;
154     char c[4];
155   } u;
156
157   u.i = theVal;
158
159   Standard_Integer entier;
160   entier  =  u.c[0] & 0xFF;
161   entier |= (u.c[1] & 0xFF) << 0x08;
162   entier |= (u.c[2] & 0xFF) << 0x10;
163   entier |= (u.c[3] & 0xFF) << 0x18;
164
165   ofile.Write((char *)&entier,sizeof(u.c));
166 }
167
168 static void writeFloat  ( const Standard_ShortReal& theVal,
169                          OSD_File& ofile)
170 {
171   union {
172     Standard_ShortReal f;
173     char c[4]; 
174   }u;
175
176   u.f = theVal;
177
178   Standard_Integer entier;
179
180   entier  =  u.c[0] & 0xFF;
181   entier |= (u.c[1] & 0xFF) << 0x08;
182   entier |= (u.c[2] & 0xFF) << 0x10;
183   entier |= (u.c[3] & 0xFF) << 0x18;
184
185   ofile.Write((char *)&entier,sizeof(u.c));
186 }
187
188 static gp_XYZ getNormale( const SMDS_MeshNode* n1,
189                           const SMDS_MeshNode* n2,
190                           const SMDS_MeshNode* n3)
191 {
192   SMESH_TNodeXYZ xyz1( n1 );
193   SMESH_TNodeXYZ xyz2( n2 );
194   SMESH_TNodeXYZ xyz3( n3 );
195   gp_XYZ q1 = xyz2 - xyz1;
196   gp_XYZ q2 = xyz3 - xyz1;
197   gp_XYZ n  = q1 ^ q2;
198   double len = n.Modulus();
199   if ( len > std::numeric_limits<double>::min() )
200     n /= len;
201
202   return n;
203 }
204
205 //================================================================================
206 /*!
207  * \brief Return nb triangles in a decomposed mesh face
208  *  \retval int - number of triangles
209  */
210 //================================================================================
211
212 static int getNbTriangles( const SMDS_MeshElement* face)
213 {
214   // WARNING: counting triangles must be coherent with getTriangles()
215   switch ( face->GetEntityType() )
216   {
217   case SMDSEntity_BiQuad_Triangle:
218   case SMDSEntity_BiQuad_Quadrangle:
219     return face->NbNodes() - 1;
220   // case SMDSEntity_Triangle:
221   // case SMDSEntity_Quad_Triangle:
222   // case SMDSEntity_Quadrangle:
223   // case SMDSEntity_Quad_Quadrangle:
224   // case SMDSEntity_Polygon:
225   // case SMDSEntity_Quad_Polygon:
226   default:
227     return face->NbNodes() - 2;
228   }
229   return 0;
230 }
231
232 //================================================================================
233 /*!
234  * \brief Decompose a mesh face into triangles
235  *  \retval int - number of triangles
236  */
237 //================================================================================
238
239 static int getTriangles( const SMDS_MeshElement* face,
240                          const SMDS_MeshNode**   nodes)
241 {
242   // WARNING: decomposing into triangles must be coherent with getNbTriangles()
243   int nbTria, i = 0;
244   SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator();
245   nodes[ i++ ] = nIt->next();
246   nodes[ i++ ] = nIt->next();
247
248   const SMDSAbs_EntityType type = face->GetEntityType();
249   switch ( type )
250   {
251   case SMDSEntity_BiQuad_Triangle:
252   case SMDSEntity_BiQuad_Quadrangle:
253     nbTria = ( type == SMDSEntity_BiQuad_Triangle ) ? 6 : 8;
254     nodes[ i++ ] = face->GetNode( nbTria );
255     while ( i < 3*(nbTria-1) )
256     {
257       nodes[ i++ ] = nodes[ i-2 ];
258       nodes[ i++ ] = nIt->next();
259       nodes[ i++ ] = nodes[ 2 ];
260     }
261     nodes[ i++ ] = nodes[ i-2 ];
262     nodes[ i++ ] = nodes[ 0 ];
263     nodes[ i++ ] = nodes[ 2 ];
264     break;
265   default:
266     // case SMDSEntity_Triangle:
267     // case SMDSEntity_Quad_Triangle:
268     // case SMDSEntity_Quadrangle:
269     // case SMDSEntity_Quad_Quadrangle:
270     // case SMDSEntity_Polygon:
271     // case SMDSEntity_Quad_Polygon:
272     nbTria = face->NbNodes() - 2;
273     nodes[ i++ ] = nIt->next();
274     while ( i < 3*nbTria )
275     {
276       nodes[ i++ ] = nodes[ 0 ];
277       nodes[ i++ ] = nodes[ i-2 ];
278       nodes[ i++ ] = nIt->next();
279     }
280     break;
281   }
282   return nbTria;
283 }
284
285 // private methods
286
287 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
288 {
289   Status aResult = DRS_OK;
290   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
291   if ( aFileName.IsEmpty() ) {
292     fprintf(stderr, ">> ERREOR : invalid file name \n");
293     return DRS_FAIL;
294   }
295
296   OSD_File aFile = OSD_File(OSD_Path(aFileName));
297   aFile.Build(OSD_WriteOnly,OSD_Protection());
298
299   char sval[16];
300   TCollection_AsciiString buf = TCollection_AsciiString ("solid\n");
301   aFile.Write (buf,buf.Length());buf.Clear();
302
303   const SMDS_MeshNode* triaNodes[2048];
304
305   SMDS_ElemIteratorPtr itFaces = getFaces();
306   while ( itFaces->more() )
307   {
308     const SMDS_MeshElement* aFace = itFaces->next();
309     int nbTria = getTriangles( aFace, triaNodes );
310     
311     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
312     {
313       gp_XYZ normale = getNormale( triaNodes[iN],
314                                    triaNodes[iN+1],
315                                    triaNodes[iN+2] );
316
317       buf += " facet normal "; 
318       sprintf (sval,"% 12e",normale.X());
319       buf += sval;
320       buf += " "; 
321       sprintf (sval,"% 12e",normale.Y());
322       buf += sval;
323       buf += " "; 
324       sprintf (sval,"% 12e",normale.Z());
325       buf += sval;
326       buf += '\n';
327       aFile.Write (buf,buf.Length());buf.Clear();
328       buf += "   outer loop\n"; 
329       aFile.Write (buf,buf.Length());buf.Clear();
330       
331       for ( int jN = 0; jN < 3; ++jN, ++iN ) {
332         const SMDS_MeshNode* node = triaNodes[iN];
333         buf += "     vertex "; 
334         sprintf (sval,"% 12e",node->X());
335         buf += sval;
336         buf += " "; 
337         sprintf (sval,"% 12e",node->Y());
338         buf += sval;
339         buf += " "; 
340         sprintf (sval,"% 12e",node->Z());
341         buf += sval;
342         buf += '\n';
343         aFile.Write (buf,buf.Length());buf.Clear();
344       }
345       buf += "   endloop\n"; 
346       aFile.Write (buf,buf.Length());buf.Clear();
347       buf += " endfacet\n"; 
348       aFile.Write (buf,buf.Length());buf.Clear();
349     } 
350   }
351   buf += "endsolid\n";
352   aFile.Write (buf,buf.Length());buf.Clear();
353   
354   aFile.Close ();
355
356   return aResult;
357 }
358
359 //================================================================================
360 /*!
361  * \brief Writes all triangles in binary format
362  *  \return Driver_Mesh::Status - DRS_FAIL if no file name is provided
363  */
364 //================================================================================
365
366 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
367 {
368   Status aResult = DRS_OK;
369   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
370   if ( aFileName.IsEmpty() ) {
371     fprintf(stderr, ">> ERREOR : invalid filename \n");
372     return DRS_FAIL;
373   }
374
375   OSD_File aFile = OSD_File(OSD_Path(aFileName));
376   aFile.Build(OSD_WriteOnly,OSD_Protection());
377
378   // we first count the number of triangles
379   int nbTri = myVolumeTrias.size();
380   {
381     SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator();
382     while ( itFaces->more() ) {
383       const SMDS_MeshElement* aFace = itFaces->next();
384       nbTri += getNbTriangles( aFace );
385     }
386   }
387   // char sval[80]; -- avoid writing not initialized memory
388   TCollection_AsciiString sval(LABEL_SIZE-1,' ');
389   aFile.Write((Standard_Address)sval.ToCString(),LABEL_SIZE);
390
391   // write number of triangles
392   writeInteger(nbTri,aFile);  
393
394   // Loop writing nodes
395
396   int dum=0;
397
398   const SMDS_MeshNode* triaNodes[2048];
399
400   SMDS_ElemIteratorPtr itFaces = getFaces();
401   while ( itFaces->more() )
402   {
403     const SMDS_MeshElement* aFace = itFaces->next();
404     int nbTria = getTriangles( aFace, triaNodes );
405     
406     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
407     {
408       gp_XYZ normale = getNormale( triaNodes[iN],
409                                    triaNodes[iN+1],
410                                    triaNodes[iN+2] );
411       writeFloat(normale.X(),aFile);
412       writeFloat(normale.Y(),aFile);
413       writeFloat(normale.Z(),aFile);
414
415       for ( int jN = 0; jN < 3; ++jN, ++iN )
416       {
417         const SMDS_MeshNode* node = triaNodes[iN];
418         writeFloat(node->X(),aFile);
419         writeFloat(node->Y(),aFile);
420         writeFloat(node->Z(),aFile);
421       }
422       aFile.Write (&dum,2);
423     } 
424   }
425   aFile.Close ();
426
427   return aResult;
428 }