Loading...
Searching...
No Matches
STLCore.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 | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2016-2024 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "STLCore.H"
30#include "OSspecific.H"
31#include "IFstream.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35// The number of bytes in the STL binary header
36static constexpr const unsigned STLHeaderSize = 80;
38
39// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
40
41// Check if "SOLID" or "solid" appears as the first non-space content.
42// Assume that any leading space is less than 75 chars or so, otherwise
43// it is really bad input.
44static bool startsWithSolid(const char header[STLHeaderSize])
45{
46 unsigned pos = 0;
47 while (std::isspace(header[pos]) && pos < STLHeaderSize)
48 {
49 ++pos;
50 }
51
52 return
53 (
54 pos < (STLHeaderSize-5) // At least 5 chars remaining
55 && std::toupper(header[pos+0]) == 'S'
56 && std::toupper(header[pos+1]) == 'O'
57 && std::toupper(header[pos+2]) == 'L'
58 && std::toupper(header[pos+3]) == 'I'
59 && std::toupper(header[pos+4]) == 'D'
60 );
61}
62
64// Check if file size appears to be reasonable for an STL binary file.
65// Compare file size with that expected from number of tris
66// If this is not sensible, it may be an ASCII file
67//
68// sizeof(STLtriangle) = 50 bytes [int16 + 4 * (3 float)]
69
70inline static bool checkBinaryFileSize
71(
72 const int64_t nTris,
73 const Foam::fileName& file
74)
75{
76 // When checking the content size, account for the header size (80),
77 // but ignore the nTris information (int32_t) to give some rounding
78
79 const int64_t contentSize =
80 (
81 int64_t(Foam::fileSize(file))
82 - int64_t(STLHeaderSize)
83 );
84
85 return
86 (
87 (contentSize >= 0)
88 && (nTris >= contentSize/50)
89 && (nTris <= contentSize/25)
90 );
91}
92
93
94// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
95
97(
98 const fileName& filename,
99 const STLFormat format
100)
101{
102 return
103 (
105 ? filename.has_ext("stlb")
107 );
108}
109
111// Check binary by getting the header and number of facets
112// this seems to work better than the old token-based method
113// - using wordToken can cause an abort if non-word (binary) content
114// is detected ... this is not exactly what we want.
115// - some programs (eg, PROSTAR) have 'solid' as the first word in
116// the binary header. This is just wrong and not our fault.
118(
119 const fileName& filename
120)
121{
122 // Handle compressed (.gz) or uncompressed input files
123
124 ifstreamPointer isPtr(filename);
125 const bool unCompressed =
127
128 auto& is = *isPtr;
129
130 if (!is.good())
131 {
133 << "Cannot read file " << filename
134 << " or file " << filename + ".gz"
135 << exit(FatalError);
136 }
137
138 // Read the STL header
139 char header[STLHeaderSize];
140 is.read(header, STLHeaderSize);
141
142 // If the stream is bad, it can't be a binary STL
143 if (!is.good() || startsWithSolid(header))
144 {
145 return 0;
146 }
147
148
149 // Read the number of triangles in the STL file
150 // (note: read as signed int so we can check whether >2^31).
151 //
152 // With nTris == 2^31, file size is 107.37 GB !
153 //
154 // However, the limit is more likely caused by the number of points
155 // that can be stored (label-size=32) when flattened for merging.
156 // So more like 715.8M triangles (~35.8 GB)
157
158 int32_t nTris;
159 is.read(reinterpret_cast<char*>(&nTris), sizeof(int32_t));
160
161 bool ok = (is && nTris >= 0);
162
163 if (ok && unCompressed)
164 {
165 ok = checkBinaryFileSize(nTris, filename);
166 }
167
168 //if (ok)
169 //{
170 // InfoErr<< "stlb : " << nTris << " triangles" << nl;
171 //}
173 // Return number of triangles if it appears to be BINARY and good.
174 return (ok ? nTris : 0);
175}
176
177
178std::unique_ptr<std::istream>
180(
181 const fileName& filename,
182 label& nTrisEstimated
183)
184{
185 nTrisEstimated = 0;
186
187 std::unique_ptr<std::istream> streamPtr;
188 bool unCompressed(true);
189
190 // Handle compressed (.gz) or uncompressed input files
191 {
192 ifstreamPointer isPtr(filename);
193 unCompressed =
195
196 // Take ownership
197 streamPtr.reset(isPtr.release());
198 }
199 auto& is = *streamPtr;
200
201 if (!is.good())
202 {
204 << "Cannot read file " << filename
205 << " or file " << filename + ".gz"
206 << exit(FatalError);
207 }
208
209
210 // Read the STL header
211 char header[STLHeaderSize];
212 is.read(header, STLHeaderSize);
213
214 // Check that stream is OK, if not this may be an ASCII file
215 if (!is.good()) // could check again: startsWithSolid(header)
216 {
218 << "problem reading header, perhaps file is not binary "
219 << exit(FatalError);
220 }
221
222
223 // Read the number of triangles in the STL file
224 // (note: read as signed int so we can check whether >2^31).
225 //
226 // With nTris == 2^31, file size is 107.37 GB !
227 //
228 // However, the limit is more likely caused by the number of points
229 // that can be stored (label-size=32) when flattened for merging.
230 // So more like 715.8M triangles (~35.8 GB)
231
232 int32_t nTris;
233 is.read(reinterpret_cast<char*>(&nTris), sizeof(int32_t));
234
235 bool ok = (is && nTris >= 0);
236
237 if (ok && unCompressed)
238 {
239 ok = checkBinaryFileSize(nTris, filename);
240 }
241
242 if (!ok)
243 {
245 << "problem reading number of triangles, perhaps file is not binary"
246 << exit(FatalError);
247 }
249 nTrisEstimated = nTris;
250
251 return streamPtr;
252}
253
254
256(
257 ostream& os,
258 uint32_t nTris
259)
260{
261 // STL header with extra information about nTris
262 char header[STLHeaderSize];
263 ::snprintf(header, STLHeaderSize, "STL binary file %u facets", nTris);
264
265 // Fill trailing with zeroes (to avoid writing junk)
266 for (size_t i = strlen(header); i < STLHeaderSize; ++i)
267 {
268 header[i] = 0;
269 }
270
271 os.write(header, STLHeaderSize);
272 os.write(reinterpret_cast<char*>(&nTris), sizeof(uint32_t));
273}
274
275
276// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static bool startsWithSolid(const char header[STLHeaderSize])
Definition STLCore.C:37
static constexpr const unsigned STLHeaderSize
Definition STLCore.C:29
static bool checkBinaryFileSize(const int64_t nTris, const Foam::fileName &file)
Definition STLCore.C:64
@ UNCOMPRESSED
compression = false
static bool isBinaryName(const fileName &filename, const STLFormat format)
Detect 'stlb' extension as binary when format = UNKNOWN.
Definition STLCore.C:90
static int detectBinaryHeader(const fileName &filename)
Check contents to detect if the file is a binary STL.
Definition STLCore.C:111
static void writeBinaryHeader(ostream &os, uint32_t nTris)
Write STL binary file and number of triangles to stream.
Definition STLCore.C:249
static std::unique_ptr< std::istream > readBinaryHeader(const fileName &filename, label &nTrisEstimated)
Read STL binary file header.
Definition STLCore.C:173
STLFormat
Enumeration for the format of data in the stream.
Definition STLCore.H:60
@ UNKNOWN
Detect based on (input) content or (output) extension.
Definition STLCore.H:63
A class for handling file names.
Definition fileName.H:75
bool has_ext() const
Various checks for extensions.
Definition stringI.H:43
A wrapped std::ifstream with possible compression handling (igzstream) that behaves much like a std::...
IOstreamOption::compressionType whichCompression() const
Which compression type?
std::istream * release() noexcept
Return managed pointer and release ownership.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
off_t fileSize(const fileName &name, const bool followLink=true)
Return size of file or -1 on failure (normally follows symbolic links).
Definition POSIX.C:907
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
word format(conversionProperties.get< word >("format"))