FreeFOAM The Cross-Platform CFD Toolkit
STLsurfaceFormatCore.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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 <OpenFOAM/gzstream.h>
28 #include <OpenFOAM/OSspecific.H>
29 #include <OpenFOAM/Map.H>
30 #include <OpenFOAM/IFstream.H>
31 #include <OpenFOAM/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  (
106  "fileFormats::STLsurfaceFormatCore::readBINARY(IFstream&)"
107  )
108  << "problem reading header, perhaps file is not binary "
109  << exit(FatalError);
110  }
111 
112  // Read the number of triangles in the STl file
113  // (note: read as int so we can check whether >2^31)
114  int nTris;
115  is.read(reinterpret_cast<char*>(&nTris), sizeof(unsigned int));
116 
117  // Check that stream is OK and number of triangles is positive,
118  // if not this maybe an ASCII file
119  //
120  // Also compare the file size with that expected from the number of tris
121  // If the comparison is not sensible then it may be an ASCII file
122  if
123  (
124  !is
125  || nTris < 0
126  || nTris < int(dataFileSize - headerSize)/50
127  || nTris > int(dataFileSize - headerSize)/25
128  )
129  {
131  (
132  "fileFormats::STLsurfaceFormatCore::readBINARY(istream&)"
133  )
134  << "problem reading number of triangles, perhaps file is not binary"
135  << exit(FatalError);
136  }
137 
138 #ifdef DEBUG_STLBINARY
139  Info<< "# " << nTris << " facets" << endl;
140  label prevZone = -1;
141 #endif
142 
143  points_.setSize(3*nTris);
144  zoneIds_.setSize(nTris);
145 
146  Map<label> lookup;
147  DynamicList<label> dynSizes;
148 
149  label ptI = 0;
150  label zoneI = -1;
151  forAll(zoneIds_, faceI)
152  {
153  // Read an STL triangle
154  STLtriangle stlTri(is);
155 
156  // transcribe the vertices of the STL triangle -> points
157  points_[ptI++] = stlTri.a();
158  points_[ptI++] = stlTri.b();
159  points_[ptI++] = stlTri.c();
160 
161  // interprete stl attribute as a zone
162  const label origId = stlTri.attrib();
163 
164  Map<label>::const_iterator fnd = lookup.find(origId);
165  if (fnd != lookup.end())
166  {
167  if (zoneI != fnd())
168  {
169  // group appeared out of order
170  sorted_ = false;
171  }
172  zoneI = fnd();
173  }
174  else
175  {
176  zoneI = dynSizes.size();
177  lookup.insert(origId, zoneI);
178  dynSizes.append(0);
179  }
180 
181  zoneIds_[faceI] = zoneI;
182  dynSizes[zoneI]++;
183 
184 #ifdef DEBUG_STLBINARY
185  if (prevZone != zoneI)
186  {
187  if (prevZone != -1)
188  {
189  Info<< "endsolid zone" << prevZone << nl;
190  }
191  prevZone = zoneI;
192 
193  Info<< "solid zone" << prevZone << nl;
194  }
195 
196  Info<< " facet normal " << stlTri.normal() << nl
197  << " outer loop" << nl
198  << " vertex " << stlTri.a() << nl
199  << " vertex " << stlTri.b() << nl
200  << " vertex " << stlTri.c() << nl
201  << " outer loop" << nl
202  << " endfacet" << endl;
203 #endif
204  }
205 
206  names_.clear();
207  sizes_.transfer(dynSizes);
208 
209  return true;
210 }
211 
212 
213 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
214 
215 Foam::fileFormats::STLsurfaceFormatCore::STLsurfaceFormatCore
216 (
217  const fileName& filename
218 )
219 :
220  sorted_(true),
221  points_(0),
222  zoneIds_(0),
223  names_(0),
224  sizes_(0)
225 {
226  off_t dataFileSize = Foam::fileSize(filename);
227 
228  // auto-detect ascii/binary
229  if (detectBINARY(filename))
230  {
231  readBINARY
232  (
233  IFstream(filename, IOstream::BINARY)().stdStream(),
234  dataFileSize
235  );
236  }
237  else
238  {
239  readASCII
240  (
241  IFstream(filename)().stdStream(),
242  dataFileSize
243  );
244  }
245 }
246 
247 
248 // * * * * * * * * * * * * * * * * Destructors * * * * * * * * * * * * * * * //
249 
251 {}
252 
253 
254 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
255 
257 (
258  ostream& os,
259  unsigned int nTris
260 )
261 {
262  // STL header with extra information about nTris
263  char header[headerSize];
264  sprintf(header, "STL binary file %u facets", nTris);
265 
266  // avoid trailing junk
267  for (size_t i = strlen(header); i < headerSize; ++i)
268  {
269  header[i] = 0;
270  }
271 
272  os.write(header, headerSize);
273  os.write(reinterpret_cast<char*>(&nTris), sizeof(unsigned int));
274 
275 }
276 
277 
278 // ************************ vim: set sw=4 sts=4 et: ************************ //