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 // ************************************************************************* //
STLsurfaceFormatCore(const fileName &)
Read from file, filling in the information.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
A class for handling file names.
Definition: fileName.H:79
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
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.
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
stressControl lookup("compactNormalStress") >> compactNormalStress
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
static const char nl
Definition: Ostream.H:260
Input from file stream.
Definition: IFstream.H:81
void setSize(const label)
Reset size of List.
Definition: List.C:281
messageStream Info
off_t fileSize(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return size of file.
Definition: POSIX.C:576
static const unsigned int headerSize
The number of bytes in the STL binary header.
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342