0026937: Eliminate NO_CXX_EXCEPTION macro support
[occt.git] / src / RWStl / RWStl.cxx
CommitLineData
b311480e 1// Created on: 1994-10-13
2// Created by: Marc LEGAY
3// Copyright (c) 1994-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
42cf5bc1 17
18#include <BRepBuilderAPI_CellFilter.hxx>
19#include <BRepBuilderAPI_VertexInspector.hxx>
20#include <gp.hxx>
21#include <gp_Vec.hxx>
22#include <gp_XYZ.hxx>
a47d34ef 23#include <Message.hxx>
24#include <Message_Messenger.hxx>
42cf5bc1 25#include <Message_ProgressIndicator.hxx>
9c6afe19 26#include <Message_ProgressSentry.hxx>
7fd59977 27#include <OSD.hxx>
42cf5bc1 28#include <OSD_File.hxx>
7fd59977 29#include <OSD_Host.hxx>
94708556 30#include <OSD_OpenFile.hxx>
42cf5bc1 31#include <OSD_Path.hxx>
32#include <OSD_Protection.hxx>
33#include <Precision.hxx>
34#include <RWStl.hxx>
35#include <Standard_NoMoreObject.hxx>
36#include <Standard_TypeMismatch.hxx>
37#include <StlMesh_Mesh.hxx>
38#include <StlMesh_MeshExplorer.hxx>
39#include <TCollection_AsciiString.hxx>
7fd59977 40
42cf5bc1 41#include <stdio.h>
fcc61cc4 42// A static method adding nodes to a mesh and keeping coincident (sharing) nodes.
43static Standard_Integer AddVertex(Handle(StlMesh_Mesh)& mesh,
44 BRepBuilderAPI_CellFilter& filter,
45 BRepBuilderAPI_VertexInspector& inspector,
46 const gp_XYZ& p)
47{
48 Standard_Integer index;
49 inspector.SetCurrent(p);
50 gp_XYZ minp = inspector.Shift(p, -Precision::Confusion());
51 gp_XYZ maxp = inspector.Shift(p, +Precision::Confusion());
52 filter.Inspect(minp, maxp, inspector);
53 const TColStd_ListOfInteger& indices = inspector.ResInd();
54 if (indices.IsEmpty() == Standard_False)
55 {
56 index = indices.First(); // it should be only one
57 inspector.ClearResList();
58 }
59 else
60 {
61 index = mesh->AddVertex(p.X(), p.Y(), p.Z());
62 filter.Add(index, p);
63 inspector.Add(p);
64 }
65 return index;
66}
67
7fd59977 68// constants
8cb69787 69static const size_t HEADER_SIZE = 84;
70static const size_t SIZEOF_STL_FACET = 50;
8cb69787 71static const size_t ASCII_LINES_PER_FACET = 7;
72
73static const int IND_THRESHOLD = 1000; // increment the indicator every 1k triangles
7fd59977 74
ed482379 75//=======================================================================
7fd59977 76//function : WriteInteger
77//purpose : writing a Little Endian 32 bits integer
78//=======================================================================
79
80inline static void WriteInteger(OSD_File& ofile,const Standard_Integer value)
81{
82 union {
83 Standard_Integer i;// don't be afraid, this is just an unsigned int
84 char c[4];
85 } bidargum;
86
87 bidargum.i = value;
88
89 Standard_Integer entier;
ed482379 90
7fd59977 91 entier = bidargum.c[0] & 0xFF;
92 entier |= (bidargum.c[1] & 0xFF) << 0x08;
93 entier |= (bidargum.c[2] & 0xFF) << 0x10;
94 entier |= (bidargum.c[3] & 0xFF) << 0x18;
95
96 ofile.Write((char *)&entier,sizeof(bidargum.c));
97}
98
99//=======================================================================
100//function : WriteDouble2Float
101//purpose : writing a Little Endian 32 bits float
102//=======================================================================
103
104inline static void WriteDouble2Float(OSD_File& ofile,Standard_Real value)
105{
106 union {
107 Standard_ShortReal f;
108 char c[4];
109 } bidargum;
110
111 bidargum.f = (Standard_ShortReal)value;
112
113 Standard_Integer entier;
ed482379 114
7fd59977 115 entier = bidargum.c[0] & 0xFF;
116 entier |= (bidargum.c[1] & 0xFF) << 0x08;
117 entier |= (bidargum.c[2] & 0xFF) << 0x10;
118 entier |= (bidargum.c[3] & 0xFF) << 0x18;
119
120 ofile.Write((char *)&entier,sizeof(bidargum.c));
121}
122
123
124//=======================================================================
125//function : readFloat2Double
126//purpose : reading a Little Endian 32 bits float
127//=======================================================================
128
129inline static Standard_Real ReadFloat2Double(OSD_File &aFile)
130{
131 union {
dde68833 132 uint32_t i;
133 float f;
7fd59977 134 }bidargum;
135
136 char c[4];
137 Standard_Address adr;
138 adr = (Standard_Address)c;
139 Standard_Integer lread;
140 aFile.Read(adr,4,lread);
141 bidargum.i = c[0] & 0xFF;
142 bidargum.i |= (c[1] & 0xFF) << 0x08;
143 bidargum.i |= (c[2] & 0xFF) << 0x10;
144 bidargum.i |= (c[3] & 0xFF) << 0x18;
145
146 return (Standard_Real)(bidargum.f);
147}
148
149
150
151//=======================================================================
152//function : WriteBinary
153//purpose : write a binary STL file in Little Endian format
154//=======================================================================
155
9c6afe19
RK
156Standard_Boolean RWStl::WriteBinary (const Handle(StlMesh_Mesh)& theMesh,
157 const OSD_Path& thePath,
158 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 159{
9c6afe19
RK
160 OSD_File aFile (thePath);
161 aFile.Build (OSD_WriteOnly, OSD_Protection());
7fd59977 162
163 Standard_Real x1, y1, z1;
164 Standard_Real x2, y2, z2;
165 Standard_Real x3, y3, z3;
ed482379 166
9c6afe19 167 // writing 80 bytes of the trash?
7fd59977 168 char sval[80];
9c6afe19
RK
169 aFile.Write ((Standard_Address)sval,80);
170 WriteInteger (aFile, theMesh->NbTriangles());
171
7fd59977 172 int dum=0;
9c6afe19
RK
173 StlMesh_MeshExplorer aMexp (theMesh);
174
175 // create progress sentry for domains
176 Standard_Integer aNbDomains = theMesh->NbDomains();
177 Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
178 for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
179 {
180 // create progress sentry for triangles in domain
181 Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
182 theMesh->NbTriangles (nbd), IND_THRESHOLD);
183 Standard_Integer aTriangleInd = 0;
184 for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
185 {
186 aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
187 //pgo aMexp.TriangleOrientation (x,y,z);
188 gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
189 gp_XYZ Vect13 ((x3-x1), (y3-y1), (z3-z1));
190 gp_XYZ Vnorm = Vect12 ^ Vect13;
191 Standard_Real Vmodul = Vnorm.Modulus ();
192 if (Vmodul > gp::Resolution())
193 {
194 Vnorm.Divide(Vmodul);
195 }
196 else
197 {
198 // si Vnorm est quasi-nul, on le charge a 0 explicitement
199 Vnorm.SetCoord (0., 0., 0.);
200 }
201
202 WriteDouble2Float (aFile, Vnorm.X());
203 WriteDouble2Float (aFile, Vnorm.Y());
204 WriteDouble2Float (aFile, Vnorm.Z());
205
206 WriteDouble2Float (aFile, x1);
207 WriteDouble2Float (aFile, y1);
208 WriteDouble2Float (aFile, z1);
209
210 WriteDouble2Float (aFile, x2);
211 WriteDouble2Float (aFile, y2);
212 WriteDouble2Float (aFile, z2);
213
214 WriteDouble2Float (aFile, x3);
215 WriteDouble2Float (aFile, y3);
216 WriteDouble2Float (aFile, z3);
ed482379 217
9c6afe19
RK
218 aFile.Write (&dum, 2);
219
220 // update progress only per 1k triangles
221 if (++aTriangleInd % IND_THRESHOLD == 0)
222 {
223 if (!aTPS.More())
224 break;
225 aTPS.Next();
7fd59977 226 }
9c6afe19 227 }
7fd59977 228 }
9c6afe19
RK
229 aFile.Close();
230 Standard_Boolean isInterrupted = !aDPS.More();
231 return !isInterrupted;
7fd59977 232}
233//=======================================================================
234//function : WriteAscii
235//purpose : write an ASCII STL file
236//=======================================================================
237
9c6afe19
RK
238Standard_Boolean RWStl::WriteAscii (const Handle(StlMesh_Mesh)& theMesh,
239 const OSD_Path& thePath,
240 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 241{
9c6afe19 242 OSD_File theFile (thePath);
7fd59977 243 theFile.Build(OSD_WriteOnly,OSD_Protection());
9c6afe19 244 TCollection_AsciiString buf ("solid\n");
7fd59977 245 theFile.Write (buf,buf.Length());buf.Clear();
ed482379 246
7fd59977 247 Standard_Real x1, y1, z1;
248 Standard_Real x2, y2, z2;
249 Standard_Real x3, y3, z3;
9c6afe19
RK
250 char sval[512];
251
252 // create progress sentry for domains
253 Standard_Integer aNbDomains = theMesh->NbDomains();
254 Message_ProgressSentry aDPS (theProgInd, "Mesh domains", 0, aNbDomains, 1);
255 StlMesh_MeshExplorer aMexp (theMesh);
256 for (Standard_Integer nbd = 1; nbd <= aNbDomains && aDPS.More(); nbd++, aDPS.Next())
257 {
258 // create progress sentry for triangles in domain
259 Message_ProgressSentry aTPS (theProgInd, "Triangles", 0,
260 theMesh->NbTriangles (nbd), IND_THRESHOLD);
261 Standard_Integer aTriangleInd = 0;
262 for (aMexp.InitTriangle (nbd); aMexp.MoreTriangle(); aMexp.NextTriangle())
263 {
7fd59977 264 aMexp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3);
ed482379 265
7fd59977 266// Standard_Real x, y, z;
267// aMexp.TriangleOrientation (x,y,z);
ed482379 268
7fd59977 269 gp_XYZ Vect12 ((x2-x1), (y2-y1), (z2-z1));
270 gp_XYZ Vect23 ((x3-x2), (y3-y2), (z3-z2));
9c6afe19 271 gp_XYZ Vnorm = Vect12 ^ Vect23;
7fd59977 272 Standard_Real Vmodul = Vnorm.Modulus ();
9c6afe19
RK
273 if (Vmodul > gp::Resolution())
274 {
275 Vnorm.Divide (Vmodul);
276 }
277 else
278 {
279 // si Vnorm est quasi-nul, on le charge a 0 explicitement
280 Vnorm.SetCoord (0., 0., 0.);
7fd59977 281 }
91322f44 282 Sprintf (sval,
9c6afe19
RK
283 " facet normal % 12e % 12e % 12e\n"
284 " outer loop\n"
285 " vertex % 12e % 12e % 12e\n"
286 " vertex % 12e % 12e % 12e\n"
287 " vertex % 12e % 12e % 12e\n"
288 " endloop\n"
289 " endfacet\n",
290 Vnorm.X(), Vnorm.Y(), Vnorm.Z(),
291 x1, y1, z1,
292 x2, y2, z2,
293 x3, y3, z3);
68bc5ed7 294 buf += sval;
9c6afe19
RK
295 theFile.Write (buf, buf.Length()); buf.Clear();
296
297 // update progress only per 1k triangles
298 if (++aTriangleInd % IND_THRESHOLD == 0)
299 {
300 if (!aTPS.More())
301 break;
302 aTPS.Next();
7fd59977 303 }
7fd59977 304 }
305 }
ed482379 306
7fd59977 307 buf += "endsolid\n";
9c6afe19
RK
308 theFile.Write (buf, buf.Length()); buf.Clear();
309 theFile.Close();
310 Standard_Boolean isInterrupted = !aDPS.More();
311 return !isInterrupted;
7fd59977 312}
313//=======================================================================
314//function : ReadFile
ed482379
K
315//Design :
316//Warning :
7fd59977 317//=======================================================================
318
857ffd5e 319Handle(StlMesh_Mesh) RWStl::ReadFile (const OSD_Path& thePath,
9c6afe19 320 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 321{
9c6afe19 322 OSD_File file (thePath);
7fd59977 323 file.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
324 Standard_Boolean IsAscii;
325 unsigned char str[128];
326 Standard_Integer lread,i;
327 Standard_Address ach;
328 ach = (Standard_Address)str;
ed482379 329
7fd59977 330 // we skip the header which is in Ascii for both modes
331 file.Read(ach,HEADER_SIZE,lread);
332
333 // we read 128 characters to detect if we have a non-ascii char
334 file.Read(ach,sizeof(str),lread);
335
336 IsAscii = Standard_True;
337 for (i = 0; i< lread && IsAscii; ++i) {
338 if (str[i] > '~') {
339 IsAscii = Standard_False;
340 }
341 }
0797d9d3 342#ifdef OCCT_DEBUG
ed482379
K
343 cout << (IsAscii ? "ascii\n" : "binary\n");
344#endif
7fd59977 345 file.Close();
ed482379 346
9c6afe19
RK
347 return IsAscii ? RWStl::ReadAscii (thePath, theProgInd)
348 : RWStl::ReadBinary (thePath, theProgInd);
7fd59977 349}
350
351//=======================================================================
352//function : ReadBinary
ed482379
K
353//Design :
354//Warning :
7fd59977 355//=======================================================================
356
857ffd5e 357Handle(StlMesh_Mesh) RWStl::ReadBinary (const OSD_Path& thePath,
9c6afe19 358 const Handle(Message_ProgressIndicator)& /*theProgInd*/)
7fd59977 359{
7fd59977 360 Standard_Integer ifacet;
361 Standard_Real fx,fy,fz,fx1,fy1,fz1,fx2,fy2,fz2,fx3,fy3,fz3;
362 Standard_Integer i1,i2,i3,lread;
363 char buftest[5];
364 Standard_Address adr;
365 adr = (Standard_Address)buftest;
366
ed482379 367 // Open the file
9c6afe19 368 OSD_File theFile (thePath);
7fd59977 369 theFile.Open(OSD_ReadOnly,OSD_Protection(OSD_RWD,OSD_RWD,OSD_RWD,OSD_RWD));
370
371 // the size of the file (minus the header size)
372 // must be a multiple of SIZEOF_STL_FACET
373
374 // compute file size
6ff736d8 375 Standard_Size filesize = theFile.Size();
7fd59977 376
a47d34ef 377 // don't trust the number of triangles which is coded in the file sometimes it is wrong
378 Standard_Integer NBFACET = (Standard_Integer)((filesize - HEADER_SIZE) / SIZEOF_STL_FACET);
379 if (NBFACET < 1)
380 {
9775fa61 381 throw Standard_NoMoreObject("RWStl::ReadBinary (wrong file size)");
7fd59977 382 }
383
a47d34ef 384 theFile.Seek (80, OSD_FromBeginning);
385 theFile.Read (adr, 4, lread);
386 Standard_Integer aNbTrisInHeader = (((char* )buftest)[3] << 24) | (((Standard_Byte* )buftest)[2] << 16)
387 | (((Standard_Byte* )buftest)[1] << 8 ) | (((Standard_Byte* )buftest)[0] << 0 );
388 if (NBFACET < aNbTrisInHeader)
389 {
390 Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file defines more triangles (") + aNbTrisInHeader
391 + ") that can be read (" + NBFACET + ") - probably corrupted file",
392 Message_Warning);
393 }
394 else if (NBFACET > aNbTrisInHeader)
395 {
396 Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file defines less triangles (") + aNbTrisInHeader
397 + ") that can be read (" + NBFACET + ") - probably corrupted file",
398 Message_Warning);
399 }
400 else if ((filesize - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
401 {
402 Message::DefaultMessenger()->Send (TCollection_AsciiString ("RWStl - Binary STL file has unidentified tail"),
403 Message_Warning);
404 }
7fd59977 405
406 // skip the header
407 theFile.Seek(HEADER_SIZE,OSD_FromBeginning);
408
409 // create the StlMesh_Mesh object
410 Handle(StlMesh_Mesh) ReadMesh = new StlMesh_Mesh ();
411 ReadMesh->AddDomain ();
412
fcc61cc4 413 // Filter unique vertices to share the nodes of the mesh.
a7653f4f 414 BRepBuilderAPI_CellFilter uniqueVertices(Precision::Confusion());
fcc61cc4 415 BRepBuilderAPI_VertexInspector inspector(Precision::Confusion());
416
7fd59977 417 for (ifacet=1; ifacet<=NBFACET; ++ifacet) {
418 // read normal coordinates
419 fx = ReadFloat2Double(theFile);
420 fy = ReadFloat2Double(theFile);
421 fz = ReadFloat2Double(theFile);
422
423 // read vertex 1
424 fx1 = ReadFloat2Double(theFile);
425 fy1 = ReadFloat2Double(theFile);
426 fz1 = ReadFloat2Double(theFile);
427
428 // read vertex 2
429 fx2 = ReadFloat2Double(theFile);
430 fy2 = ReadFloat2Double(theFile);
431 fz2 = ReadFloat2Double(theFile);
432
433 // read vertex 3
434 fx3 = ReadFloat2Double(theFile);
435 fy3 = ReadFloat2Double(theFile);
436 fz3 = ReadFloat2Double(theFile);
437
fcc61cc4 438 // Add vertices.
439 i1 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx1, fy1, fz1));
440 i2 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx2, fy2, fz2));
441 i3 = AddVertex(ReadMesh, uniqueVertices, inspector, gp_XYZ(fx3, fy3, fz3));
442
443 // Add triangle.
7fd59977 444 ReadMesh->AddTriangle (i1,i2,i3,fx,fy,fz);
445
446 // skip extra bytes
447 theFile.Read(adr,2,lread);
448 }
449
450 theFile.Close ();
451 return ReadMesh;
7fd59977 452}
fcc61cc4 453
7fd59977 454//=======================================================================
455//function : ReadAscii
ed482379
K
456//Design :
457//Warning :
7fd59977 458//=======================================================================
459
857ffd5e 460Handle(StlMesh_Mesh) RWStl::ReadAscii (const OSD_Path& thePath,
9c6afe19 461 const Handle(Message_ProgressIndicator)& theProgInd)
7fd59977 462{
463 TCollection_AsciiString filename;
464 long ipos;
465 Standard_Integer nbLines = 0;
466 Standard_Integer nbTris = 0;
467 Standard_Integer iTri;
7fd59977 468 Standard_Integer i1,i2,i3;
469 Handle(StlMesh_Mesh) ReadMesh;
470
9c6afe19 471 thePath.SystemName (filename);
7fd59977 472
ed482379 473 // Open the file
94708556 474 FILE* file = OSD_OpenFile(filename.ToCString(),"r");
7fd59977 475
476 fseek(file,0L,SEEK_END);
477
478 long filesize = ftell(file);
479
94708556 480 rewind(file);
7fd59977 481
7fd59977 482 // count the number of lines
483 for (ipos = 0; ipos < filesize; ++ipos) {
484 if (getc(file) == '\n')
485 nbLines++;
486 }
487
488 // compute number of triangles
489 nbTris = (nbLines / ASCII_LINES_PER_FACET);
490
491 // go back to the beginning of the file
7fd59977 492 rewind(file);
493
494 // skip header
495 while (getc(file) != '\n');
0797d9d3 496#ifdef OCCT_DEBUG
ed482379
K
497 cout << "start mesh\n";
498#endif
499 ReadMesh = new StlMesh_Mesh();
7fd59977 500 ReadMesh->AddDomain();
501
fcc61cc4 502 // Filter unique vertices to share the nodes of the mesh.
a7653f4f 503 BRepBuilderAPI_CellFilter uniqueVertices(Precision::Confusion());
fcc61cc4 504 BRepBuilderAPI_VertexInspector inspector(Precision::Confusion());
505
7fd59977 506 // main reading
9c6afe19
RK
507 Message_ProgressSentry aPS (theProgInd, "Triangles", 0, (nbTris - 1) * 1.0 / IND_THRESHOLD, 1);
508 for (iTri = 0; iTri < nbTris && aPS.More();)
509 {
91322f44 510 char x[256]="", y[256]="", z[256]="";
511
7fd59977 512 // reading the facet normal
91322f44 513 if (3 != fscanf(file,"%*s %*s %80s %80s %80s\n", x, y, z))
514 break; // error should be properly reported
515 gp_XYZ aN (Atof(x), Atof(y), Atof(z));
7fd59977 516
517 // skip the keywords "outer loop"
98160038 518 if (fscanf(file,"%*s %*s") < 0)
519 break;
7fd59977 520
521 // reading vertex
91322f44 522 if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
523 break; // error should be properly reported
524 gp_XYZ aV1 (Atof(x), Atof(y), Atof(z));
525 if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
526 break; // error should be properly reported
527 gp_XYZ aV2 (Atof(x), Atof(y), Atof(z));
528 if (3 != fscanf(file,"%*s %80s %80s %80s\n", x, y, z))
529 break; // error should be properly reported
530 gp_XYZ aV3 (Atof(x), Atof(y), Atof(z));
7fd59977 531
ed482379 532 // here the facet must be built and put in the mesh datastructure
7fd59977 533
fcc61cc4 534 i1 = AddVertex(ReadMesh, uniqueVertices, inspector, aV1);
535 i2 = AddVertex(ReadMesh, uniqueVertices, inspector, aV2);
536 i3 = AddVertex(ReadMesh, uniqueVertices, inspector, aV3);
91322f44 537 ReadMesh->AddTriangle (i1, i2, i3, aN.X(), aN.Y(), aN.Z());
7fd59977 538
539 // skip the keywords "endloop"
98160038 540 if (fscanf(file,"%*s") < 0)
541 break;
7fd59977 542
543 // skip the keywords "endfacet"
98160038 544 if (fscanf(file,"%*s") < 0)
545 break;
7fd59977 546
9c6afe19
RK
547 // update progress only per 1k triangles
548 if (++iTri % IND_THRESHOLD == 0)
549 aPS.Next();
7fd59977 550 }
0797d9d3 551#ifdef OCCT_DEBUG
ed482379
K
552 cout << "end mesh\n";
553#endif
7fd59977 554 fclose(file);
555 return ReadMesh;
7fd59977 556}