0022627: Change OCCT memory management defaults
[occt.git] / src / RWStl / RWStl.cxx
CommitLineData
7fd59977 1// File: RWStl.cxx
2// Created: Thu Oct 13 13:41:29 1994
3// Author: Marc LEGAY
4// <mle@bourdon>
5
ed482379 6// Copyright: Matra Datavision
7fd59977 7
ed482379 8#include <RWStl.ixx>
7fd59977 9#include <OSD_Protection.hxx>
10#include <OSD_File.hxx>
9c6afe19 11#include <Message_ProgressSentry.hxx>
7fd59977 12#include <TCollection_AsciiString.hxx>
13#include <Standard_NoMoreObject.hxx>
14#include <Standard_TypeMismatch.hxx>
15#include <Precision.hxx>
16#include <StlMesh_MeshExplorer.hxx>
17#include <OSD.hxx>
18#include <OSD_Host.hxx>
19#include <gp_XYZ.hxx>
20#include <gp.hxx>
21#include <stdio.h>
22#include <gp_Vec.hxx>
23
24
25// constants
ed482379
K
26static const int HEADER_SIZE = 84;
27static const int SIZEOF_STL_FACET = 50;
28static const int STL_MIN_FILE_SIZE = 284;
29static const int ASCII_LINES_PER_FACET = 7;
9c6afe19 30static const int IND_THRESHOLD = 1000; // increment the indicator every 1k triangles
7fd59977 31
ed482379 32//=======================================================================
7fd59977 33//function : WriteInteger
34//purpose : writing a Little Endian 32 bits integer
35//=======================================================================
36
37inline static void WriteInteger(OSD_File& ofile,const Standard_Integer value)
38{
39 union {
40 Standard_Integer i;// don't be afraid, this is just an unsigned int
41 char c[4];
42 } bidargum;
43
44 bidargum.i = value;
45
46 Standard_Integer entier;
ed482379 47
7fd59977 48 entier = bidargum.c[0] & 0xFF;
49 entier |= (bidargum.c[1] & 0xFF) << 0x08;
50 entier |= (bidargum.c[2] & 0xFF) << 0x10;
51 entier |= (bidargum.c[3] & 0xFF) << 0x18;
52
53 ofile.Write((char *)&entier,sizeof(bidargum.c));
54}
55
56//=======================================================================
57//function : WriteDouble2Float
58//purpose : writing a Little Endian 32 bits float
59//=======================================================================
60
61inline static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
62{
63 union {
64 Standard_ShortReal f;
65 char c[4];
66 } bidargum;
67
68 bidargum.f = (Standard_ShortReal)value;
69
70 Standard_Integer entier;
ed482379 71
7fd59977 72 entier = bidargum.c[0] & 0xFF;
73 entier |= (bidargum.c[1] & 0xFF) << 0x08;
74 entier |= (bidargum.c[2] & 0xFF) << 0x10;
75 entier |= (bidargum.c[3] & 0xFF) << 0x18;
76
77 ofile.Write((char *)&entier,sizeof(bidargum.c));
78}
79
80
81//=======================================================================
82//function : readFloat2Double
83//purpose : reading a Little Endian 32 bits float
84//=======================================================================
85
86inline static Standard_Real ReadFloat2Double(OSD_File &aFile)
87{
88 union {
89 Standard_Boolean i; // don't be afraid, this is just an unsigned int
90 Standard_ShortReal f;
91 }bidargum;
92
93 char c[4];
94 Standard_Address adr;
95 adr = (Standard_Address)c;
96 Standard_Integer lread;
97 aFile.Read(adr,4,lread);
98 bidargum.i = c[0] & 0xFF;
99 bidargum.i |= (c[1] & 0xFF) << 0x08;
100 bidargum.i |= (c[2] & 0xFF) << 0x10;
101 bidargum.i |= (c[3] & 0xFF) << 0x18;
102
103 return (Standard_Real)(bidargum.f);
104}
105
106
107
108//=======================================================================
109//function : WriteBinary
110//purpose : write a binary STL file in Little Endian format
111//=======================================================================
112
9c6afe19
RK
113Standard_Boolean RWStl::WriteBinary (const Handle(StlMesh_Mesh)& theMesh,
114 const OSD_Path& thePath,
115 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 116{
9c6afe19
RK
117 OSD_File aFile (thePath);
118 aFile.Build (OSD_WriteOnly, OSD_Protection());
7fd59977 119
120 Standard_Real x1, y1, z1;
121 Standard_Real x2, y2, z2;
122 Standard_Real x3, y3, z3;
ed482379 123
9c6afe19 124 // writing 80 bytes of the trash?
7fd59977 125 char sval[80];
9c6afe19
RK
126 aFile.Write ((Standard_Address)sval,80);
127 WriteInteger (aFile, theMesh->NbTriangles());
128
7fd59977 129 int dum=0;
9c6afe19
RK
130 StlMesh_MeshExplorer aMexp (theMesh);
131
132 // create progress sentry for domains
133 Standard_Integer aNbDomains = theMesh->NbDomains();
134 Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
135 for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
136 {
137 // create progress sentry for triangles in domain
138 Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
139 theMesh->NbTriangles (nbd), IND_THRESHOLD);
140 Standard_Integer aTriangleInd = 0;
141 for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
142 {
143 aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
144 //pgo aMexp.TriangleOrientation (x,y,z);
145 gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
146 gp_XYZ Vect13 ((x3-x1), (y3-y1), (z3-z1));
147 gp_XYZ Vnorm = Vect12 ^ Vect13;
148 Standard_Real Vmodul = Vnorm.Modulus ();
149 if (Vmodul > gp::Resolution())
150 {
151 Vnorm.Divide(Vmodul);
152 }
153 else
154 {
155 // si Vnorm est quasi-nul, on le charge a 0 explicitement
156 Vnorm.SetCoord (0., 0., 0.);
157 }
158
159 WriteDouble2Float (aFile, Vnorm.X());
160 WriteDouble2Float (aFile, Vnorm.Y());
161 WriteDouble2Float (aFile, Vnorm.Z());
162
163 WriteDouble2Float (aFile, x1);
164 WriteDouble2Float (aFile, y1);
165 WriteDouble2Float (aFile, z1);
166
167 WriteDouble2Float (aFile, x2);
168 WriteDouble2Float (aFile, y2);
169 WriteDouble2Float (aFile, z2);
170
171 WriteDouble2Float (aFile, x3);
172 WriteDouble2Float (aFile, y3);
173 WriteDouble2Float (aFile, z3);
ed482379 174
9c6afe19
RK
175 aFile.Write (&dum, 2);
176
177 // update progress only per 1k triangles
178 if (++aTriangleInd % IND_THRESHOLD == 0)
179 {
180 if (!aTPS.More())
181 break;
182 aTPS.Next();
7fd59977 183 }
9c6afe19 184 }
7fd59977 185 }
9c6afe19
RK
186 aFile.Close();
187 Standard_Boolean isInterrupted = !aDPS.More();
188 return !isInterrupted;
7fd59977 189}
190//=======================================================================
191//function : WriteAscii
192//purpose : write an ASCII STL file
193//=======================================================================
194
9c6afe19
RK
195Standard_Boolean RWStl::WriteAscii (const Handle(StlMesh_Mesh)& theMesh,
196 const OSD_Path& thePath,
197 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 198{
9c6afe19 199 OSD_File theFile (thePath);
7fd59977 200 theFile.Build(OSD_WriteOnly,OSD_Protection());
9c6afe19 201 TCollection_AsciiString buf ("solid\n");
7fd59977 202 theFile.Write (buf,buf.Length());buf.Clear();
ed482379 203
7fd59977 204 Standard_Real x1, y1, z1;
205 Standard_Real x2, y2, z2;
206 Standard_Real x3, y3, z3;
9c6afe19
RK
207 char sval[512];
208
209 // create progress sentry for domains
210 Standard_Integer aNbDomains = theMesh->NbDomains();
211 Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
212 StlMesh_MeshExplorer aMexp (theMesh);
213 for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
214 {
215 // create progress sentry for triangles in domain
216 Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
217 theMesh->NbTriangles (nbd), IND_THRESHOLD);
218 Standard_Integer aTriangleInd = 0;
219 for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
220 {
7fd59977 221 aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
ed482379 222
7fd59977 223// Standard_Real x, y, z;
224// aMexp.TriangleOrientation (x,y,z);
ed482379 225
7fd59977 226 gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
227 gp_XYZ Vect23 ((x3-x2), (y3-y2), (z3-z2));
9c6afe19 228 gp_XYZ Vnorm = Vect12 ^ Vect23;
7fd59977 229 Standard_Real Vmodul = Vnorm.Modulus ();
9c6afe19
RK
230 if (Vmodul > gp::Resolution())
231 {
232 Vnorm.Divide (Vmodul);
233 }
234 else
235 {
236 // si Vnorm est quasi-nul, on le charge a 0 explicitement
237 Vnorm.SetCoord (0., 0., 0.);
7fd59977 238 }
9c6afe19
RK
239 sprintf (sval,
240 " facet normal % 12e % 12e % 12e\n"
241 " outer loop\n"
242 " vertex % 12e % 12e % 12e\n"
243 " vertex % 12e % 12e % 12e\n"
244 " vertex % 12e % 12e % 12e\n"
245 " endloop\n"
246 " endfacet\n",
247 Vnorm.X(), Vnorm.Y(), Vnorm.Z(),
248 x1, y1, z1,
249 x2, y2, z2,
250 x3, y3, z3);
68bc5ed7 251 buf += sval;
9c6afe19
RK
252 theFile.Write (buf, buf.Length()); buf.Clear();
253
254 // update progress only per 1k triangles
255 if (++aTriangleInd % IND_THRESHOLD == 0)
256 {
257 if (!aTPS.More())
258 break;
259 aTPS.Next();
7fd59977 260 }
7fd59977 261 }
262 }
ed482379 263
7fd59977 264 buf += "endsolid\n";
9c6afe19
RK
265 theFile.Write (buf, buf.Length()); buf.Clear();
266 theFile.Close();
267 Standard_Boolean isInterrupted = !aDPS.More();
268 return !isInterrupted;
7fd59977 269}
270//=======================================================================
271//function : ReadFile
ed482379
K
272//Design :
273//Warning :
7fd59977 274//=======================================================================
275
9c6afe19
RK
276Handle_StlMesh_Mesh RWStl::ReadFile (const OSD_Path& thePath,
277 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 278{
9c6afe19 279 OSD_File file (thePath);
7fd59977 280 file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
281 Standard_Boolean IsAscii;
282 unsigned char str[128];
283 Standard_Integer lread,i;
284 Standard_Address ach;
285 ach = (Standard_Address)str;
ed482379 286
7fd59977 287 // we skip the header which is in Ascii for both modes
288 file.Read(ach,HEADER_SIZE,lread);
289
290 // we read 128 characters to detect if we have a non-ascii char
291 file.Read(ach,sizeof(str),lread);
292
293 IsAscii = Standard_True;
294 for (i = 0; i< lread && IsAscii; ++i) {
295 if (str[i] > '~') {
296 IsAscii = Standard_False;
297 }
298 }
ed482379
K
299#ifdef DEB
300 cout << (IsAscii ? "ascii\n" : "binary\n");
301#endif
7fd59977 302 file.Close();
ed482379 303
9c6afe19
RK
304 return IsAscii ? RWStl::ReadAscii (thePath, theProgInd)
305 : RWStl::ReadBinary (thePath, theProgInd);
7fd59977 306}
307
308//=======================================================================
309//function : ReadBinary
ed482379
K
310//Design :
311//Warning :
7fd59977 312//=======================================================================
313
9c6afe19
RK
314Handle_StlMesh_Mesh RWStl::ReadBinary (const OSD_Path& thePath,
315 const Handle(Message_ProgressIndicator)& /*theProgInd*/)
7fd59977 316{
317 Standard_Integer NBFACET;
318 Standard_Integer ifacet;
319 Standard_Real fx,fy,fz,fx1,fy1,fz1,fx2,fy2,fz2,fx3,fy3,fz3;
320 Standard_Integer i1,i2,i3,lread;
321 char buftest[5];
322 Standard_Address adr;
323 adr = (Standard_Address)buftest;
324
ed482379 325 // Open the file
9c6afe19 326 OSD_File theFile (thePath);
7fd59977 327 theFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
328
329 // the size of the file (minus the header size)
330 // must be a multiple of SIZEOF_STL_FACET
331
332 // compute file size
333 Standard_Integer filesize = theFile.Size();
334
ed482379 335 if ( (filesize - HEADER_SIZE) % SIZEOF_STL_FACET !=0
7fd59977 336 || (filesize < STL_MIN_FILE_SIZE)) {
337 Standard_NoMoreObject::Raise("RWStl::ReadBinary (wrong file size)");
338 }
339
340 // don't trust the number of triangles which is coded in the file
341 // sometimes it is wrong, and with this technique we don't need to swap endians for integer
342 NBFACET = ((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
343
344 // skip the header
345 theFile.Seek(HEADER_SIZE,OSD_FromBeginning);
346
347 // create the StlMesh_Mesh object
348 Handle(StlMesh_Mesh) ReadMesh = new StlMesh_Mesh ();
349 ReadMesh->AddDomain ();
350
351 for (ifacet=1; ifacet<=NBFACET; ++ifacet) {
352 // read normal coordinates
353 fx = ReadFloat2Double(theFile);
354 fy = ReadFloat2Double(theFile);
355 fz = ReadFloat2Double(theFile);
356
357 // read vertex 1
358 fx1 = ReadFloat2Double(theFile);
359 fy1 = ReadFloat2Double(theFile);
360 fz1 = ReadFloat2Double(theFile);
361
362 // read vertex 2
363 fx2 = ReadFloat2Double(theFile);
364 fy2 = ReadFloat2Double(theFile);
365 fz2 = ReadFloat2Double(theFile);
366
367 // read vertex 3
368 fx3 = ReadFloat2Double(theFile);
369 fy3 = ReadFloat2Double(theFile);
370 fz3 = ReadFloat2Double(theFile);
371
372 i1 = ReadMesh->AddOnlyNewVertex (fx1,fy1,fz1);
373 i2 = ReadMesh->AddOnlyNewVertex (fx2,fy2,fz2);
374 i3 = ReadMesh->AddOnlyNewVertex (fx3,fy3,fz3);
375 ReadMesh->AddTriangle (i1,i2,i3,fx,fy,fz);
376
377 // skip extra bytes
378 theFile.Read(adr,2,lread);
379 }
380
381 theFile.Close ();
382 return ReadMesh;
ed482379 383
7fd59977 384}
385//=======================================================================
386//function : ReadAscii
ed482379
K
387//Design :
388//Warning :
7fd59977 389//=======================================================================
390
9c6afe19
RK
391Handle_StlMesh_Mesh RWStl::ReadAscii (const OSD_Path& thePath,
392 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 393{
394 TCollection_AsciiString filename;
395 long ipos;
396 Standard_Integer nbLines = 0;
397 Standard_Integer nbTris = 0;
398 Standard_Integer iTri;
399 Standard_ShortReal x[4],y[4],z[4];
400 Standard_Integer i1,i2,i3;
401 Handle(StlMesh_Mesh) ReadMesh;
402
9c6afe19 403 thePath.SystemName (filename);
7fd59977 404
ed482379 405 // Open the file
7fd59977 406 FILE* file = fopen(filename.ToCString(),"r");
407
408 fseek(file,0L,SEEK_END);
409
410 long filesize = ftell(file);
411
412 fclose(file);
413 file = fopen(filename.ToCString(),"r");
414
415
416
417 // count the number of lines
418 for (ipos = 0; ipos < filesize; ++ipos) {
419 if (getc(file) == '\n')
420 nbLines++;
421 }
422
423 // compute number of triangles
424 nbTris = (nbLines / ASCII_LINES_PER_FACET);
425
426 // go back to the beginning of the file
427// fclose(file);
428// file = fopen(filename.ToCString(),"r");
429 rewind(file);
430
431 // skip header
432 while (getc(file) != '\n');
ed482379
K
433#ifdef DEB
434 cout << "start mesh\n";
435#endif
436 ReadMesh = new StlMesh_Mesh();
7fd59977 437 ReadMesh->AddDomain();
438
439 // main reading
9c6afe19
RK
440 Message_ProgressSentry aPS (theProgInd, "Triangles", 0, (nbTris - 1) * 1.0 / IND_THRESHOLD, 1);
441 for (iTri = 0; iTri < nbTris && aPS.More();)
442 {
7fd59977 443 // reading the facet normal
444 fscanf(file,"%*s %*s %f %f %f\n",&x[0],&y[0],&z[0]);
445
446 // skip the keywords "outer loop"
447 fscanf(file,"%*s %*s");
448
449 // reading vertex
450 fscanf(file,"%*s %f %f %f\n",&x[1],&y[1],&z[1]);
451 fscanf(file,"%*s %f %f %f\n",&x[2],&y[2],&z[2]);
452 fscanf(file,"%*s %f %f %f\n",&x[3],&y[3],&z[3]);
453
ed482379 454 // here the facet must be built and put in the mesh datastructure
7fd59977 455
456 i1 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[1],(Standard_Real)y[1],(Standard_Real)z[1]);
457 i2 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[2],(Standard_Real)y[2],(Standard_Real)z[2]);
458 i3 = ReadMesh->AddOnlyNewVertex ((Standard_Real)x[3],(Standard_Real)y[3],(Standard_Real)z[3]);
459 ReadMesh->AddTriangle (i1,i2,i3,(Standard_Real)x[0],(Standard_Real)y[0],(Standard_Real)z[0]);
460
461 // skip the keywords "endloop"
462 fscanf(file,"%*s");
463
464 // skip the keywords "endfacet"
465 fscanf(file,"%*s");
466
9c6afe19
RK
467 // update progress only per 1k triangles
468 if (++iTri % IND_THRESHOLD == 0)
469 aPS.Next();
7fd59977 470 }
ed482379
K
471#ifdef DEB
472 cout << "end mesh\n";
473#endif
7fd59977 474 fclose(file);
475 return ReadMesh;
ed482379 476
7fd59977 477}