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