Salome HOME
8ddbfd0dd8463135b2516611a7f0952ec1590b07
[modules/smesh.git] / src / DriverSTL / DriverSTL_W_SMDS_Mesh.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
23 #include "DriverSTL_W_SMDS_Mesh.h"
24
25 #ifdef WIN32
26 #define NOMINMAX
27 #endif
28
29 #include <Basics_Utils.hxx>
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_IteratorOnIterators.hxx"
33 #include "SMDS_Mesh.hxx"
34 #include "SMDS_MeshElement.hxx"
35 #include "SMDS_MeshNode.hxx"
36 #include "SMDS_SetIterator.hxx"
37 #include "SMDS_VolumeTool.hxx"
38 #include "SMESH_File.hxx"
39 #include "SMESH_TypeDefs.hxx"
40
41 //#include "utilities.h"
42
43 #include <limits>
44
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, SMESH_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( entier );
166 }
167
168 static void writeFloat( const Standard_ShortReal& theVal, SMESH_File& ofile)
169 {
170   union {
171     Standard_ShortReal f;
172     char c[4]; 
173   } u;
174
175   u.f = theVal;
176
177   Standard_Integer entier;
178
179   entier  =  u.c[0] & 0xFF;
180   entier |= (u.c[1] & 0xFF) << 0x08;
181   entier |= (u.c[2] & 0xFF) << 0x10;
182   entier |= (u.c[3] & 0xFF) << 0x18;
183
184   ofile.write( entier );
185 }
186
187 static gp_XYZ getNormale( const SMDS_MeshNode* n1,
188                           const SMDS_MeshNode* n2,
189                           const SMDS_MeshNode* n3)
190 {
191   SMESH_TNodeXYZ xyz1( n1 );
192   SMESH_TNodeXYZ xyz2( n2 );
193   SMESH_TNodeXYZ xyz3( n3 );
194   gp_XYZ q1 = xyz2 - xyz1;
195   gp_XYZ q2 = xyz3 - xyz1;
196   gp_XYZ n  = q1 ^ q2;
197   double len = n.Modulus();
198   if ( len > std::numeric_limits<double>::min() )
199     n /= len;
200
201   return n;
202 }
203
204 //================================================================================
205 /*!
206  * \brief Return nb triangles in a decomposed mesh face
207  *  \retval int - number of triangles
208  */
209 //================================================================================
210
211 static int getNbTriangles( const SMDS_MeshElement* face)
212 {
213   // WARNING: counting triangles must be coherent with getTriangles()
214   switch ( face->GetEntityType() )
215   {
216   case SMDSEntity_BiQuad_Triangle:
217   case SMDSEntity_BiQuad_Quadrangle:
218     return face->NbNodes() - 1;
219   // case SMDSEntity_Triangle:
220   // case SMDSEntity_Quad_Triangle:
221   // case SMDSEntity_Quadrangle:
222   // case SMDSEntity_Quad_Quadrangle:
223   // case SMDSEntity_Polygon:
224   // case SMDSEntity_Quad_Polygon:
225   default:
226     return face->NbNodes() - 2;
227   }
228   return 0;
229 }
230
231 //================================================================================
232 /*!
233  * \brief Decompose a mesh face into triangles
234  *  \retval int - number of triangles
235  */
236 //================================================================================
237
238 static int getTriangles( const SMDS_MeshElement* face,
239                          const SMDS_MeshNode**   nodes)
240 {
241   // WARNING: decomposing into triangles must be coherent with getNbTriangles()
242   int nbTria, i = 0;
243   SMDS_NodeIteratorPtr nIt = face->interlacedNodesIterator();
244   nodes[ i++ ] = nIt->next();
245   nodes[ i++ ] = nIt->next();
246
247   const SMDSAbs_EntityType type = face->GetEntityType();
248   switch ( type )
249   {
250   case SMDSEntity_BiQuad_Triangle:
251   case SMDSEntity_BiQuad_Quadrangle:
252     nbTria = ( type == SMDSEntity_BiQuad_Triangle ) ? 6 : 8;
253     nodes[ i++ ] = face->GetNode( nbTria );
254     while ( i < 3*(nbTria-1) )
255     {
256       nodes[ i++ ] = nodes[ i-2 ];
257       nodes[ i++ ] = nIt->next();
258       nodes[ i++ ] = nodes[ 2 ];
259     }
260     nodes[ i++ ] = nodes[ i-2 ];
261     nodes[ i++ ] = nodes[ 0 ];
262     nodes[ i++ ] = nodes[ 2 ];
263     break;
264   default:
265     // case SMDSEntity_Triangle:
266     // case SMDSEntity_Quad_Triangle:
267     // case SMDSEntity_Quadrangle:
268     // case SMDSEntity_Quad_Quadrangle:
269     // case SMDSEntity_Polygon:
270     // case SMDSEntity_Quad_Polygon:
271     nbTria = face->NbNodes() - 2;
272     nodes[ i++ ] = nIt->next();
273     while ( i < 3*nbTria )
274     {
275       nodes[ i++ ] = nodes[ 0 ];
276       nodes[ i++ ] = nodes[ i-2 ];
277       nodes[ i++ ] = nIt->next();
278     }
279     break;
280   }
281   return nbTria;
282 }
283
284 // private methods
285
286 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
287 {
288   Status aResult = DRS_OK;
289   if ( myFile.empty() ) {
290     fprintf(stderr, ">> ERREOR : invalid file name \n");
291     return DRS_FAIL;
292   }
293
294   SMESH_File aFile( myFile, /*openForReading=*/false );
295   aFile.openForWriting();
296
297   std::string buf("solid\n");
298   aFile.writeRaw( buf.c_str(), buf.size() );
299
300   char sval[128];
301   const SMDS_MeshNode* triaNodes[2048];
302
303   SMDS_ElemIteratorPtr itFaces = getFaces();
304   while ( itFaces->more() )
305   {
306     const SMDS_MeshElement* aFace = itFaces->next();
307     int nbTria = getTriangles( aFace, triaNodes );
308     
309     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
310     {
311       gp_XYZ normale = getNormale( triaNodes[iN],
312                                    triaNodes[iN+1],
313                                    triaNodes[iN+2] );
314       sprintf (sval,
315                " facet normal % 12e % 12e % 12e\n"
316                "   outer loop\n" ,
317                normale.X(), normale.Y(), normale.Z());
318       aFile.writeRaw ( sval, 70 );
319
320       for ( int jN = 0; jN < 3; ++jN, ++iN )
321       {
322         SMESH_TNodeXYZ node = triaNodes[iN];
323         sprintf (sval,
324                  "     vertex % 12e % 12e % 12e\n",
325                  node.X(), node.Y(), node.Z() );
326         aFile.writeRaw ( sval, 54 );
327       }
328       aFile.writeRaw ("   endloop\n"
329                       " endfacet\n", 21 );
330     } 
331   }
332   aFile.writeRaw ("endsolid\n" , 9 );
333
334   return aResult;
335 }
336
337 //================================================================================
338 /*!
339  * \brief Writes all triangles in binary format
340  *  \return Driver_Mesh::Status - DRS_FAIL if no file name is provided
341  */
342 //================================================================================
343
344 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
345 {
346   Status aResult = DRS_OK;
347
348   if ( myFile.empty() ) {
349     fprintf(stderr, ">> ERREOR : invalid filename \n");
350     return DRS_FAIL;
351   }
352
353   SMESH_File aFile( myFile );
354   aFile.openForWriting();
355
356   // we first count the number of triangles
357   int nbTri = myVolumeTrias.size();
358   {
359     SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator();
360     while ( itFaces->more() ) {
361       const SMDS_MeshElement* aFace = itFaces->next();
362       nbTri += getNbTriangles( aFace );
363     }
364   }
365   std::string sval( LABEL_SIZE, ' ' );
366   aFile.write( sval.c_str(), LABEL_SIZE );
367
368   // write number of triangles
369   writeInteger( nbTri, aFile );  
370
371   // Loop writing nodes
372
373   int dum=0;
374
375   const SMDS_MeshNode* triaNodes[2048];
376
377   SMDS_ElemIteratorPtr itFaces = getFaces();
378   while ( itFaces->more() )
379   {
380     const SMDS_MeshElement* aFace = itFaces->next();
381     int nbTria = getTriangles( aFace, triaNodes );
382     
383     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
384     {
385       gp_XYZ normale = getNormale( triaNodes[iN],
386                                    triaNodes[iN+1],
387                                    triaNodes[iN+2] );
388       writeFloat(normale.X(),aFile);
389       writeFloat(normale.Y(),aFile);
390       writeFloat(normale.Z(),aFile);
391
392       for ( int jN = 0; jN < 3; ++jN, ++iN )
393       {
394         const SMDS_MeshNode* node = triaNodes[iN];
395         writeFloat(node->X(),aFile);
396         writeFloat(node->Y(),aFile);
397         writeFloat(node->Z(),aFile);
398       }
399       aFile.writeRaw ( &dum, 2 );
400     }
401   }
402
403   return aResult;
404 }