Salome HOME
0021130: EDF 1746 SMESH: Issue with export in STL format
[modules/smesh.git] / src / DriverSTL / DriverSTL_W_SMDS_Mesh.cxx
1 //  Copyright (C) 2007-2010  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
25 #include "DriverSTL_W_SMDS_Mesh.h"
26
27 #include "SMDS_FaceOfNodes.hxx"
28 #include "SMDS_IteratorOnIterators.hxx"
29 #include "SMDS_Mesh.hxx"
30 #include "SMDS_MeshElement.hxx"
31 #include "SMDS_MeshNode.hxx"
32 #include "SMDS_SetIterator.hxx"
33 #include "SMDS_VolumeTool.hxx"
34 #include "SMESH_TypeDefs.hxx"
35
36 #include <OSD_File.hxx>
37 //#include <OSD_FromWhere.hxx>
38 #include <OSD_Path.hxx>
39 #include <OSD_Protection.hxx>
40 //#include <OSD_SingleProtection.hxx>
41 #include <TCollection_AsciiString.hxx>
42 #include <gp_XYZ.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   Status aResult = DRS_OK;
62
63   if ( !myMesh ) {
64     fprintf(stderr, ">> ERROR : Mesh is null \n");
65     return DRS_FAIL;
66   }
67   findVolumeTriangles();
68   if ( myIsAscii )
69     aResult = writeAscii();
70   else
71     aResult = writeBinary();
72
73   return aResult;
74 }
75 //================================================================================
76 /*!
77  * \brief Destructor deletes temporary faces
78  */
79 //================================================================================
80
81 DriverSTL_W_SMDS_Mesh::~DriverSTL_W_SMDS_Mesh()
82 {
83   for ( unsigned i = 0; i < myVolumeTrias.size(); ++i )
84     delete myVolumeTrias[i];
85 }
86
87 //================================================================================
88 /*!
89  * \brief Finds free facets of volumes for which faces are missing in the mesh
90  */
91 //================================================================================
92
93 void DriverSTL_W_SMDS_Mesh::findVolumeTriangles()
94 {
95   SMDS_VolumeTool myTool;
96   SMDS_VolumeIteratorPtr vIt = myMesh->volumesIterator();
97   while ( vIt->more() )
98   {
99     myTool.Set( vIt->next() );
100     for ( int iF = 0; iF < myTool.NbFaces(); ++iF )
101       if ( myTool.IsFreeFace( iF ))
102       {
103         const SMDS_MeshNode** n = myTool.GetFaceNodes(iF);
104         int                 nbN = myTool.NbFaceNodes(iF);
105         std::vector< const SMDS_MeshNode*> nodes( n, n+nbN );
106         if ( !myMesh->FindElement( nodes, SMDSAbs_Face, /*Nomedium=*/false))
107         {
108           int nbTria = nbN - 2;
109           for ( int iT = 0; iT < nbTria; ++iT )
110           {
111             myVolumeTrias.push_back( new SMDS_FaceOfNodes( n[0], n[1+iT], n[2+iT] ));
112           }
113         }
114       }
115   }
116 }
117
118 //================================================================================
119 /*!
120  * \brief Return iterator on both faces in the mesh and on temporary faces
121  */
122 //================================================================================
123
124 SMDS_ElemIteratorPtr DriverSTL_W_SMDS_Mesh::getFaces() const
125 {
126   SMDS_ElemIteratorPtr facesIter = myMesh->elementsIterator(SMDSAbs_Face);
127   SMDS_ElemIteratorPtr tmpTriaIter( new SMDS_ElementVectorIterator( myVolumeTrias.begin(),
128                                                                     myVolumeTrias.end()));
129   typedef std::vector< SMDS_ElemIteratorPtr > TElemIterVector;
130   TElemIterVector iters(2);
131   iters[0] = facesIter;
132   iters[1] = tmpTriaIter;
133   
134   typedef SMDS_IteratorOnIterators<const SMDS_MeshElement *, TElemIterVector> TItersIter;
135   return SMDS_ElemIteratorPtr( new TItersIter( iters ));
136 }
137
138 // static methods
139
140 static void writeInteger( const Standard_Integer& theVal,
141                          OSD_File& ofile )
142 {
143   union {
144     Standard_Integer i;
145     char c[4];
146   }u;
147
148   u.i = theVal;
149
150   Standard_Integer entier;
151   entier  =  u.c[0] & 0xFF;
152   entier |= (u.c[1] & 0xFF) << 0x08;
153   entier |= (u.c[2] & 0xFF) << 0x10;
154   entier |= (u.c[3] & 0xFF) << 0x18;
155
156   ofile.Write((char *)&entier,sizeof(u.c));
157 }
158
159 static void writeFloat  ( const Standard_ShortReal& theVal,
160                          OSD_File& ofile)
161 {
162   union {
163     Standard_ShortReal f;
164     char c[4]; 
165   }u;
166
167   u.f = theVal;
168
169   Standard_Integer entier;
170
171   entier  =  u.c[0] & 0xFF;
172   entier |= (u.c[1] & 0xFF) << 0x08;
173   entier |= (u.c[2] & 0xFF) << 0x10;
174   entier |= (u.c[3] & 0xFF) << 0x18;
175
176   ofile.Write((char *)&entier,sizeof(u.c));
177 }
178
179 static gp_XYZ getNormale( const SMDS_MeshNode* n1,
180                           const SMDS_MeshNode* n2,
181                           const SMDS_MeshNode* n3)
182 {
183   SMESH_TNodeXYZ xyz1( n1 );
184   SMESH_TNodeXYZ xyz2( n2 );
185   SMESH_TNodeXYZ xyz3( n3 );
186   gp_XYZ q1 = xyz2 - xyz1;
187   gp_XYZ q2 = xyz3 - xyz1;
188   gp_XYZ n  = q1 ^ q2;
189   double len = n.Modulus();
190   if ( len > std::numeric_limits<double>::min() )
191     n /= len;
192
193   return n;
194 }
195
196 //================================================================================
197 /*!
198  * \brief Decompose a mesh face into triangles
199  *  \retval int - number of triangles
200  */
201 //================================================================================
202
203 static int getTriangles( const SMDS_MeshElement* face,
204                          const SMDS_MeshNode**   nodes)
205 {
206   // WARNING: implementation must be coherent with counting triangles in writeBinary()
207   int nbN = face->NbCornerNodes();
208   const int nbTria = nbN-2;
209   for ( int i = 0; nbN > 1; --nbN )
210   {
211     nodes[ i++ ] = face->GetNode( 0 );
212     nodes[ i++ ] = face->GetNode( nbN-2 );
213     nodes[ i++ ] = face->GetNode( nbN-1 );
214   }
215   return nbTria;
216 }
217
218 // private methods
219
220 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeAscii() const
221 {
222   Status aResult = DRS_OK;
223   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
224   if ( aFileName.IsEmpty() ) {
225     fprintf(stderr, ">> ERREOR : invalid file name \n");
226     return DRS_FAIL;
227   }
228
229   OSD_File aFile = OSD_File(OSD_Path(aFileName));
230   aFile.Build(OSD_WriteOnly,OSD_Protection());
231
232   char sval[16];
233   TCollection_AsciiString buf = TCollection_AsciiString ("solid\n");
234   aFile.Write (buf,buf.Length());buf.Clear();
235
236   const SMDS_MeshNode* triaNodes[2048];
237
238   SMDS_ElemIteratorPtr itFaces = getFaces();
239   while ( itFaces->more() )
240   {
241     const SMDS_MeshElement* aFace = itFaces->next();
242     int nbTria = getTriangles( aFace, triaNodes );
243     
244     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
245     {
246       gp_XYZ normale = getNormale( triaNodes[iN],
247                                    triaNodes[iN+1],
248                                    triaNodes[iN+2] );
249
250       buf += " facet normal "; 
251       sprintf (sval,"% 12e",normale.X());
252       buf += sval;
253       buf += " "; 
254       sprintf (sval,"% 12e",normale.Y());
255       buf += sval;
256       buf += " "; 
257       sprintf (sval,"% 12e",normale.Z());
258       buf += sval;
259       buf += '\n';
260       aFile.Write (buf,buf.Length());buf.Clear();
261       buf += "   outer loop\n"; 
262       aFile.Write (buf,buf.Length());buf.Clear();
263       
264       for ( int jN = 0; jN < 3; ++jN, ++iN ) {
265         const SMDS_MeshNode* node = triaNodes[iN];
266         buf += "     vertex "; 
267         sprintf (sval,"% 12e",node->X());
268         buf += sval;
269         buf += " "; 
270         sprintf (sval,"% 12e",node->Y());
271         buf += sval;
272         buf += " "; 
273         sprintf (sval,"% 12e",node->Z());
274         buf += sval;
275         buf += '\n';
276         aFile.Write (buf,buf.Length());buf.Clear();
277       }
278       buf += "   endloop\n"; 
279       aFile.Write (buf,buf.Length());buf.Clear();
280       buf += " endfacet\n"; 
281       aFile.Write (buf,buf.Length());buf.Clear();
282     } 
283   }
284   buf += "endsolid\n";
285   aFile.Write (buf,buf.Length());buf.Clear();
286   
287   aFile.Close ();
288
289   return aResult;
290 }
291
292 Driver_Mesh::Status DriverSTL_W_SMDS_Mesh::writeBinary() const
293 {
294   Status aResult = DRS_OK;
295   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
296   if ( aFileName.IsEmpty() ) {
297     fprintf(stderr, ">> ERREOR : invalid filename \n");
298     return DRS_FAIL;
299   }
300
301   OSD_File aFile = OSD_File(OSD_Path(aFileName));
302   aFile.Build(OSD_WriteOnly,OSD_Protection());
303
304   // we first count the number of triangles
305   // WARNING: counting triangles must be coherent with getTriangles()
306   int nbTri = 0;
307   const SMDS_MeshInfo& info = myMesh->GetMeshInfo();
308   nbTri += info.NbTriangles();
309   nbTri += info.NbQuadrangles() * 2;
310   nbTri += myVolumeTrias.size();
311   if ( info.NbPolygons() > 0 )
312   {
313     SMDS_FaceIteratorPtr itFaces = myMesh->facesIterator();
314     while ( itFaces->more() )
315     {
316       const SMDS_MeshElement* aFace = itFaces->next();
317       if ( aFace->IsPoly() )
318         nbTri += aFace->NbNodes() - 2;
319     }
320   }
321
322   // char sval[80]; -- avoid writing not initialized memory
323   TCollection_AsciiString sval(LABEL_SIZE-1,' ');
324   aFile.Write((Standard_Address)sval.ToCString(),LABEL_SIZE);
325
326   // write number of triangles
327   writeInteger(nbTri,aFile);  
328
329   // Loop writing nodes
330
331   int dum=0;
332
333   const SMDS_MeshNode* triaNodes[2048];
334
335   SMDS_ElemIteratorPtr itFaces = getFaces();
336   while ( itFaces->more() )
337   {
338     const SMDS_MeshElement* aFace = itFaces->next();
339     int nbTria = getTriangles( aFace, triaNodes );
340     
341     for ( int iT = 0, iN = 0; iT < nbTria; ++iT )
342     {
343       gp_XYZ normale = getNormale( triaNodes[iN],
344                                    triaNodes[iN+1],
345                                    triaNodes[iN+2] );
346       writeFloat(normale.X(),aFile);
347       writeFloat(normale.Y(),aFile);
348       writeFloat(normale.Z(),aFile);
349
350       for ( int jN = 0; jN < 3; ++jN, ++iN )
351       {
352         const SMDS_MeshNode* node = triaNodes[iN];
353         writeFloat(node->X(),aFile);
354         writeFloat(node->Y(),aFile);
355         writeFloat(node->Z(),aFile);
356       }
357       aFile.Write (&dum,2);
358     } 
359   }
360   aFile.Close ();
361
362   return aResult;
363 }