STLsurfaceFormatCore.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "STLsurfaceFormatCore.H"
27 #include "gzstream.h"
28 #include "OSspecific.H"
29 #include "Map.H"
30 #include "IFstream.H"
31 #include "Ostream.H"
32 
33 #undef DEBUG_STLBINARY
34 
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 
37 // check binary by getting the header and number of facets
38 // this seems to work better than the old token-based method
39 // - some programs (eg, pro-STAR) have 'solid' as the first word in
40 // the binary header.
41 // - using wordToken can cause an abort if non-word (binary) content
42 // is detected ... this is not exactly what we want.
43 int Foam::fileFormats::STLsurfaceFormatCore::detectBINARY
44 (
45  const fileName& filename
46 )
47 {
48  off_t dataFileSize = Foam::fileSize(filename);
49 
50  IFstream str(filename, IOstream::BINARY);
51  istream& is = str().stdStream();
52 
53  // Read the STL header
54  char header[headerSize];
55  is.read(header, headerSize);
56 
57  // Check that stream is OK, if not this may be an ASCII file
58  if (!is.good())
59  {
60  return 0;
61  }
62 
63  // Read the number of triangles in the STl file
64  // (note: read as int so we can check whether >2^31)
65  int nTris;
66  is.read(reinterpret_cast<char*>(&nTris), sizeof(unsigned int));
67 
68  // Check that stream is OK and number of triangles is positive,
69  // if not this may be an ASCII file
70  //
71  // Also compare the file size with that expected from the number of tris
72  // If the comparison is not sensible then it may be an ASCII file
73  if
74  (
75  !is
76  || nTris < 0
77  || nTris < (dataFileSize - headerSize)/50
78  || nTris > (dataFileSize - headerSize)/25
79  )
80  {
81  return 0;
82  }
83 
84  // looks like it might be BINARY, return number of triangles
85  return nTris;
86 }
87 
88 
89 bool Foam::fileFormats::STLsurfaceFormatCore::readBINARY
90 (
91  istream& is,
92  const off_t dataFileSize
93 )
94 {
95  sorted_ = true;
96 
97  // Read the STL header
98  char header[headerSize];
99  is.read(header, headerSize);
100 
101  // Check that stream is OK, if not this may be an ASCII file
102  if (!is.good())
103  {
105  << "problem reading header, perhaps file is not binary "
106  << exit(FatalError);
107  }
108 
109  // Read the number of triangles in the STl file
110  // (note: read as int so we can check whether >2^31)
111  int nTris;
112  is.read(reinterpret_cast<char*>(&nTris), sizeof(unsigned int));
113 
114  // Check that stream is OK and number of triangles is positive,
115  // if not this maybe an ASCII file
116  //
117  // Also compare the file size with that expected from the number of tris
118  // If the comparison is not sensible then it may be an ASCII file
119  if
120  (
121  !is
122  || nTris < 0
123  || nTris < int(dataFileSize - headerSize)/50
124  || nTris > int(dataFileSize - headerSize)/25
125  )
126  {
128  << "problem reading number of triangles, perhaps file is not binary"
129  << exit(FatalError);
130  }
131 
132 #ifdef DEBUG_STLBINARY
133  Info<< "# " << nTris << " facets" << endl;
134  label prevZone = -1;
135 #endif
136 
137  points_.setSize(3*nTris);
138  zoneIds_.setSize(nTris);
139 
140  Map<label> lookup;
141  DynamicList<label> dynSizes;
142 
143  label ptI = 0;
144  label zoneI = -1;
145  forAll(zoneIds_, facei)
146  {
147  // Read an STL triangle
148  STLtriangle stlTri(is);
149 
150  // transcribe the vertices of the STL triangle -> points
151  points_[ptI++] = stlTri.a();
152  points_[ptI++] = stlTri.b();
153  points_[ptI++] = stlTri.c();
154 
155  // interpret stl attribute as a zone
156  const label origId = stlTri.attrib();
157 
158  Map<label>::const_iterator fnd = lookup.find(origId);
159  if (fnd != lookup.end())
160  {
161  if (zoneI != fnd())
162  {
163  // group appeared out of order
164  sorted_ = false;
165  }
166  zoneI = fnd();
167  }
168  else
169  {
170  zoneI = dynSizes.size();
171  lookup.insert(origId, zoneI);
172  dynSizes.append(0);
173  }
174 
175  zoneIds_[facei] = zoneI;
176  dynSizes[zoneI]++;
177 
178 #ifdef DEBUG_STLBINARY
179  if (prevZone != zoneI)
180  {
181  if (prevZone != -1)
182  {
183  Info<< "endsolid zone" << prevZone << nl;
184  }
185  prevZone = zoneI;
186 
187  Info<< "solid zone" << prevZone << nl;
188  }
189 
190  Info<< " facet normal " << stlTri.normal() << nl
191  << " outer loop" << nl
192  << " vertex " << stlTri.a() << nl
193  << " vertex " << stlTri.b() << nl
194  << " vertex " << stlTri.c() << nl
195  << " outer loop" << nl
196  << " endfacet" << endl;
197 #endif
198  }
199 
200  names_.clear();
201  sizes_.transfer(dynSizes);
202 
203  return true;
204 }
205 
206 
207 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
208 
210 (
211  const fileName& filename
212 )
213 :
214  sorted_(true),
215  points_(0),
216  zoneIds_(0),
217  names_(0),
218  sizes_(0)
219 {
220  off_t dataFileSize = Foam::fileSize(filename);
221 
222  // auto-detect ascii/binary
223  if (detectBINARY(filename))
224  {
225  readBINARY
226  (
227  IFstream(filename, IOstream::BINARY)().stdStream(),
228  dataFileSize
229  );
230  }
231  else
232  {
233  readASCII
234  (
235  IFstream(filename)().stdStream(),
236  dataFileSize
237  );
238  }
239 }
240 
241 
242 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
243 
245 {}
246 
247 
248 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
249 
251 (
252  ostream& os,
253  unsigned int nTris
254 )
255 {
256  // STL header with extra information about nTris
257  char header[headerSize];
258  sprintf(header, "STL binary file %u facets", nTris);
259 
260  // avoid trailing junk
261  for (size_t i = strlen(header); i < headerSize; ++i)
262  {
263  header[i] = 0;
264  }
265 
266  os.write(header, headerSize);
267  os.write(reinterpret_cast<char*>(&nTris), sizeof(unsigned int));
268 
269 }
270 
271 
272 // ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Input from file stream.
Definition: IFstream.H:85
HashTable< label, label, Hash< label > >::const_iterator const_iterator
Definition: Map.H:59
static void writeHeaderBINARY(ostream &, unsigned int)
Write "STL binary file" and number of triangles to stream.
static const unsigned int headerSize
The number of bytes in the STL binary header.
STLsurfaceFormatCore(const fileName &)
Read from file, filling in the information.
A class for handling file names.
Definition: fileName.H:82
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
off_t fileSize(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return size of file.
Definition: POSIX.C:576
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
messageStream Info
error FatalError
static const char nl
Definition: Ostream.H:260