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