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