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