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