Salome HOME
Merge from V6_main 01/04/2013
[modules/smesh.git] / src / DriverSTL / DriverSTL_R_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 <gp_Pnt.hxx>
25 #include <Basics_Utils.hxx>
26
27 //=======================================================================
28 //function : HashCode
29 //purpose  : 
30 //=======================================================================
31 inline Standard_Integer HashCode
32   (const gp_Pnt& point,  Standard_Integer Upper)
33 {
34   union 
35     {
36     Standard_Real R[3];
37     Standard_Integer I[6];
38     } U;
39
40   point.Coord(U.R[0],U.R[1],U.R[2]);  
41
42   return ::HashCode(U.I[0]/23+U.I[1]/19+U.I[2]/17+U.I[3]/13+U.I[4]/11+U.I[5]/7,Upper);
43 }
44 static Standard_Real tab1[3];
45 static Standard_Real tab2[3];
46 //=======================================================================
47 //function : IsEqual
48 //purpose  : 
49 //=======================================================================
50 inline Standard_Boolean IsEqual
51   (const gp_Pnt& point1, const gp_Pnt& point2)
52 {
53   point1.Coord(tab1[0],tab1[1],tab1[2]);  
54   point2.Coord(tab2[0],tab2[1],tab2[2]);  
55   return (memcmp(tab1,tab2,sizeof(tab1)) == 0);
56 }
57 #include "DriverSTL_R_SMDS_Mesh.h"
58
59 #include "SMDS_Mesh.hxx"
60 #include "SMDS_MeshElement.hxx"
61 #include "SMDS_MeshNode.hxx"
62
63 #include <OSD_Path.hxx>
64 #include <OSD_File.hxx>
65 #include <OSD_FromWhere.hxx>
66 #include <OSD_Protection.hxx>
67 #include <OSD_SingleProtection.hxx>
68 #include <Standard_NoMoreObject.hxx>
69
70 #include "utilities.h"
71
72 static const int HEADER_SIZE           =  84;
73 static const int SIZEOF_STL_FACET      =  50;
74 //static const int STL_MIN_FILE_SIZE     = 284;
75 static const int ASCII_LINES_PER_FACET =   7;
76
77
78 //typedef NCollection_BaseCollection<SMDS_MeshNodePtr> DriverSTL_ColOfNodePtr;
79
80
81 #include <NCollection_DataMap.hxx>
82 typedef NCollection_DataMap<gp_Pnt,SMDS_MeshNode*> DriverSTL_DataMapOfPntNodePtr;
83 //=======================================================================
84 //function : DriverSTL_R_SMDS_Mesh
85 //purpose  : 
86 //=======================================================================
87
88 DriverSTL_R_SMDS_Mesh::DriverSTL_R_SMDS_Mesh()
89 {
90   myIsCreateFaces = true;
91   myIsAscii = Standard_True;
92 }
93
94 //=======================================================================
95 //function : SetIsCreateFaces
96 //purpose  : 
97 //=======================================================================
98
99 void DriverSTL_R_SMDS_Mesh::SetIsCreateFaces( const bool theIsCreate )
100 { myIsCreateFaces = theIsCreate; }
101
102 //=======================================================================
103 //function : Perform
104 //purpose  : 
105 //=======================================================================
106
107 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::Perform()
108 {
109   Kernel_Utils::Localizer loc;
110
111   Status aResult = DRS_OK;
112
113   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
114   if ( aFileName.IsEmpty() ) {
115     fprintf(stderr, ">> ERREOR : invalid file name \n");
116     return DRS_FAIL;
117   }
118
119   filebuf fic;
120   Standard_IStream is(&fic);
121   if (!fic.open(aFileName.ToCString(),ios::in)) {
122     fprintf(stderr, ">> ERROR : cannot open file %s \n", aFileName.ToCString());
123     return DRS_FAIL;
124   }
125
126
127   OSD_Path aPath( aFileName );
128   OSD_File file = OSD_File( aPath );
129   file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
130   unsigned char str[128];
131   Standard_Integer lread,i;
132   Standard_Address ach;
133   ach = (Standard_Address)str;
134   // we skip the header which is in Ascii for both modes
135   file.Read(ach,HEADER_SIZE,lread);
136
137   // we read 128 characters to detect if we have a non-ascii char
138   file.Read(ach,sizeof(str),lread);
139   
140   myIsAscii = Standard_True;
141   for (i = 0; i < lread; ++i) {
142     if (str[i] > '~') {
143       myIsAscii = Standard_False;
144       break;
145     }
146   }
147       
148   file.Close();
149
150   if ( !myMesh ) {
151     fprintf(stderr, ">> ERREOR : cannot create mesh \n");
152     return DRS_FAIL;
153   }
154
155   if ( myIsAscii )
156     aResult = readAscii();
157   else
158     aResult = readBinary();
159
160   return aResult;
161 }
162
163 // static methods
164
165 static Standard_Real readFloat(OSD_File& theFile)
166 {
167   union {
168     Standard_Boolean i; 
169     Standard_ShortReal f;
170   }u;
171
172   char c[4];
173   Standard_Address adr;
174   adr = (Standard_Address)c;
175   Standard_Integer lread;
176   theFile.Read(adr,4,lread);
177   u.i  =  c[0] & 0xFF;
178   u.i |= (c[1] & 0xFF) << 0x08;
179   u.i |= (c[2] & 0xFF) << 0x10;
180   u.i |= (c[3] & 0xFF) << 0x18;
181
182   return u.f;
183 }
184
185 static SMDS_MeshNode* addNode(const gp_Pnt& P,
186                               DriverSTL_DataMapOfPntNodePtr& uniqnodes,
187                               SMDS_Mesh* theMesh)
188 {
189   SMDS_MeshNode* node = 0;
190   if ( uniqnodes.IsBound(P) ) {
191     node = uniqnodes.Find(P);
192   } else {
193     node = theMesh->AddNode(P.X(), P.Y(), P.Z() );
194     uniqnodes.Bind(P,node);
195   }
196   
197   return node;
198 }                                
199
200 static SMDS_MeshNode* readNode(FILE* file,
201                                DriverSTL_DataMapOfPntNodePtr& uniqnodes,
202                                SMDS_Mesh* theMesh)
203 {
204   Standard_ShortReal coord[3];
205   // reading vertex
206   fscanf(file,"%*s %f %f %f\n",&coord[0],&coord[1],&coord[2]);
207
208   gp_Pnt P(coord[0],coord[1],coord[2]);
209   return addNode( P, uniqnodes, theMesh );
210 }
211
212 static SMDS_MeshNode* readNode(OSD_File& theFile,
213                                DriverSTL_DataMapOfPntNodePtr& uniqnodes,
214                                SMDS_Mesh* theMesh)
215 {
216   Standard_ShortReal coord[3];
217   coord[0] = readFloat(theFile);
218   coord[1] = readFloat(theFile);
219   coord[2] = readFloat(theFile);
220
221   gp_Pnt P(coord[0],coord[1],coord[2]);
222   return addNode( P, uniqnodes, theMesh );
223 }
224
225 //=======================================================================
226 //function : readAscii
227 //purpose  : 
228 //=======================================================================
229
230 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readAscii() const
231 {
232   Status aResult = DRS_OK;
233   long ipos;
234   Standard_Integer nbLines = 0;
235
236   // Open the file 
237   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
238   FILE* file = fopen(aFileName.ToCString(),"r");
239   fseek(file,0L,SEEK_END);
240   // get the file size
241   long filesize = ftell(file);
242   fclose(file);
243   file = fopen(aFileName.ToCString(),"r");
244   
245   // count the number of lines
246   for (ipos = 0; ipos < filesize; ++ipos) {
247     if (getc(file) == '\n')
248       nbLines++;
249   }
250
251   // go back to the beginning of the file
252 //  fclose(file);
253 //  file = fopen(aFileName.ToCString(),"r");
254   rewind(file);
255   
256   Standard_Integer nbTri = (nbLines / ASCII_LINES_PER_FACET);
257
258   DriverSTL_DataMapOfPntNodePtr uniqnodes;
259   // skip header
260   while (getc(file) != '\n');
261
262   // main reading
263   for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
264
265     // skipping the facet normal
266     Standard_ShortReal normal[3];
267     fscanf(file,"%*s %*s %f %f %f\n",&normal[0],&normal[1],&normal[2]);
268
269     // skip the keywords "outer loop"
270     fscanf(file,"%*s %*s");
271
272     // reading nodes
273     SMDS_MeshNode* node1 = readNode( file, uniqnodes, myMesh );
274     SMDS_MeshNode* node2 = readNode( file, uniqnodes, myMesh );
275     SMDS_MeshNode* node3 = readNode( file, uniqnodes, myMesh );
276
277     if (myIsCreateFaces)
278       myMesh->AddFace(node1,node2,node3);
279
280     // skip the keywords "endloop"
281     fscanf(file,"%*s");
282
283     // skip the keywords "endfacet"
284     fscanf(file,"%*s");
285   }
286
287   fclose(file);
288   return aResult;
289 }
290
291 //=======================================================================
292 //function : readBinary
293 //purpose  : 
294 //=======================================================================
295
296 Driver_Mesh::Status DriverSTL_R_SMDS_Mesh::readBinary() const
297 {
298   Status aResult = DRS_OK;
299
300   char buftest[5];
301   Standard_Address adr;
302   adr = (Standard_Address)buftest;
303
304   TCollection_AsciiString aFileName( (char *)myFile.c_str() );
305   OSD_File aFile = OSD_File(OSD_Path( aFileName ));
306   aFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
307
308   // the size of the file (minus the header size)
309   // must be a multiple of SIZEOF_STL_FACET
310
311   // compute file size
312   Standard_Integer filesize = aFile.Size();
313
314   if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0 
315       // Commented to allow reading small files (ex: 1 face)
316       /*|| (filesize < STL_MIN_FILE_SIZE)*/) {
317     Standard_NoMoreObject::Raise("DriverSTL_R_SMDS_MESH::readBinary (wrong file size)");
318   }
319
320   // don't trust the number of triangles which is coded in the file
321   // sometimes it is wrong, and with this technique we don't need to swap endians for integer
322   Standard_Integer nbTri = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
323
324   // skip the header
325   aFile.Seek(HEADER_SIZE,OSD_FromBeginning);
326
327   DriverSTL_DataMapOfPntNodePtr uniqnodes;
328   Standard_Integer lread;
329   
330   for (Standard_Integer iTri = 0; iTri < nbTri; ++iTri) {
331
332     // ignore normals
333     readFloat(aFile);
334     readFloat(aFile);
335     readFloat(aFile);
336
337     // read vertices
338     SMDS_MeshNode* node1 = readNode( aFile, uniqnodes, myMesh );
339     SMDS_MeshNode* node2 = readNode( aFile, uniqnodes, myMesh );
340     SMDS_MeshNode* node3 = readNode( aFile, uniqnodes, myMesh );
341
342     if (myIsCreateFaces)
343       myMesh->AddFace(node1,node2,node3);
344
345     // skip extra bytes
346     aFile.Read(adr,2,lread);
347   }
348   aFile.Close();
349   return aResult;
350 }