Developer Documentation
Loading...
Searching...
No Matches
STLWriter.cc
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openmesh.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenMesh. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 * ========================================================================= */
41
42
43
44
45//== INCLUDES =================================================================
46
47
48//STL
49#include <fstream>
50
51// OpenMesh
53#include <OpenMesh/Core/Geometry/VectorT.hh>
54#include <OpenMesh/Core/IO/BinaryHelper.hh>
55#include <OpenMesh/Core/IO/IOManager.hh>
56#include <OpenMesh/Core/IO/writer/STLWriter.hh>
57
58//=== NAMESPACES ==============================================================
59
60
61namespace OpenMesh {
62namespace IO {
63
64
65//=== INSTANCIATE =============================================================
66
67
68_STLWriter_ __STLWriterInstance;
69_STLWriter_& STLWriter() { return __STLWriterInstance; }
70
71
72//=== IMPLEMENTATION ==========================================================
73
74
75_STLWriter_::_STLWriter_() { IOManager().register_module(this); }
76
77
78//-----------------------------------------------------------------------------
79
80
81bool
83write(const std::string& _filename, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const
84{
85 Options tmpOptions = _writeOptions;
86
87 // binary or ascii ?
88 if (_filename.rfind(".stla") != std::string::npos)
89 {
90 tmpOptions -= Options::Binary;
91 }
92 else if (_filename.rfind(".stlb") != std::string::npos)
93 {
94 tmpOptions += Options::Binary;
95 }
96
97 // open file
98 std::fstream out(_filename.c_str(), (tmpOptions.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out
99 : std::ios_base::out) );
100
101 bool result = write(out, _be, tmpOptions, _precision);
102
103 out.close();
104
105 return result;
106}
107
108//-----------------------------------------------------------------------------
109
110
111bool
113write(std::ostream& _os, BaseExporter& _be, const Options& _writeOptions, std::streamsize _precision) const
114{
115 // check exporter features
116 if (!check(_be, _writeOptions)) return false;
117
118 // check writer features
119 if (_writeOptions.check(Options::VertexNormal) ||
120 _writeOptions.check(Options::VertexTexCoord) ||
121 _writeOptions.check(Options::FaceColor))
122 return false;
123
124 if (!_writeOptions.check(Options::Binary))
125 _os.precision(_precision);
126
127 if (_writeOptions & Options::Binary)
128 return write_stlb(_os, _be, _writeOptions);
129 else
130 return write_stla(_os, _be, _writeOptions);
131
132 return false;
133}
134
135
136
137//-----------------------------------------------------------------------------
138
139
140bool
141_STLWriter_::
142write_stla(const std::string& _filename, const BaseExporter& _be, Options /* _opt */) const
143{
144 omlog() << "[STLWriter] : write ascii file\n";
145
146
147 // open file
148 FILE* out = fopen(_filename.c_str(), "w");
149 if (!out)
150 {
151 omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
152 return false;
153 }
154
155
156
157
158 int i, nF(int(_be.n_faces()));
159 Vec3f a, b, c, n;
160 std::vector<VertexHandle> vhandles;
161 FaceHandle fh;
162
163
164 // header
165 fprintf(out, "solid \n");
166
167
168 // write face set
169 for (i=0; i<nF; ++i)
170 {
171 fh = FaceHandle(i);
172 const int nV = _be.get_vhandles(fh, vhandles);
173
174 if (nV == 3)
175 {
176 a = _be.point(vhandles[0]);
177 b = _be.point(vhandles[1]);
178 c = _be.point(vhandles[2]);
179 n = (_be.has_face_normals() ?
180 _be.normal(fh) :
181 ((c-b) % (a-b)).normalize());
182
183 fprintf(out, "facet normal %f %f %f\nouter loop\n", n[0], n[1], n[2]);
184 fprintf(out, "vertex %.10f %.10f %.10f\n", a[0], a[1], a[2]);
185 fprintf(out, "vertex %.10f %.10f %.10f\n", b[0], b[1], b[2]);
186 fprintf(out, "vertex %.10f %.10f %.10f", c[0], c[1], c[2]);
187 }
188 else
189 omerr() << "[STLWriter] : Warning non-triangle data!\n";
190
191 fprintf(out, "\nendloop\nendfacet\n");
192 }
193
194 fprintf(out, "endsolid\n");
195
196 fclose(out);
197
198 return true;
199}
200
201
202//-----------------------------------------------------------------------------
203
204
205bool
206_STLWriter_::
207write_stla(std::ostream& _out, const BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
208{
209 omlog() << "[STLWriter] : write ascii file\n";
210
211 int i, nF(int(_be.n_faces()));
212 Vec3f a, b, c, n;
213 std::vector<VertexHandle> vhandles;
214 FaceHandle fh;
215 _out.precision(_precision);
216
217
218 // header
219 _out << "solid \n";
220
221
222 // write face set
223 for (i=0; i<nF; ++i)
224 {
225 fh = FaceHandle(i);
226 const int nV = _be.get_vhandles(fh, vhandles);
227
228 if (nV == 3)
229 {
230 a = _be.point(vhandles[0]);
231 b = _be.point(vhandles[1]);
232 c = _be.point(vhandles[2]);
233 n = (_be.has_face_normals() ?
234 _be.normal(fh) :
235 ((c-b) % (a-b)).normalize());
236
237 _out << "facet normal " << n[0] << " " << n[1] << " " << n[2] << "\nouter loop\n";
238 _out.precision(10);
239 _out << "vertex " << a[0] << " " << a[1] << " " << a[2] << "\n";
240 _out << "vertex " << b[0] << " " << b[1] << " " << b[2] << "\n";
241 _out << "vertex " << c[0] << " " << c[1] << " " << c[2] << "\n";
242 } else {
243 omerr() << "[STLWriter] : Warning non-triangle data!\n";
244 }
245
246 _out << "\nendloop\nendfacet\n";
247 }
248
249 _out << "endsolid\n";
250
251 return true;
252}
253
254//-----------------------------------------------------------------------------
255
256
257bool
258_STLWriter_::
259write_stlb(const std::string& _filename, const BaseExporter& _be, Options /* _opt */) const
260{
261 omlog() << "[STLWriter] : write binary file\n";
262
263
264 // open file
265 FILE* out = fopen(_filename.c_str(), "wb");
266 if (!out)
267 {
268 omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
269 return false;
270 }
271
272
273 int i, nF(int(_be.n_faces()));
274 Vec3f a, b, c, n;
275 std::vector<VertexHandle> vhandles;
276 FaceHandle fh;
277
278
279 // write header
280 const char header[80] =
281 "binary stl file"
282 " ";
283 fwrite(header, 1, 80, out);
284
285
286 // number of faces
287 write_int( int(_be.n_faces()), out);
288
289
290 // write face set
291 for (i=0; i<nF; ++i)
292 {
293 fh = FaceHandle(i);
294 const int nV = _be.get_vhandles(fh, vhandles);
295
296 if (nV == 3)
297 {
298 a = _be.point(vhandles[0]);
299 b = _be.point(vhandles[1]);
300 c = _be.point(vhandles[2]);
301 n = (_be.has_face_normals() ?
302 _be.normal(fh) :
303 ((c-b) % (a-b)).normalize());
304
305 // face normal
306 write_float(n[0], out);
307 write_float(n[1], out);
308 write_float(n[2], out);
309
310 // face vertices
311 write_float(a[0], out);
312 write_float(a[1], out);
313 write_float(a[2], out);
314
315 write_float(b[0], out);
316 write_float(b[1], out);
317 write_float(b[2], out);
318
319 write_float(c[0], out);
320 write_float(c[1], out);
321 write_float(c[2], out);
322
323 // space filler
324 write_short(0, out);
325 }
326 else
327 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
328 }
329
330
331 fclose(out);
332 return true;
333}
334
335//-----------------------------------------------------------------------------
336
337bool
338_STLWriter_::
339write_stlb(std::ostream& _out, const BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
340{
341 omlog() << "[STLWriter] : write binary file\n";
342
343
344 int i, nF(int(_be.n_faces()));
345 Vec3f a, b, c, n;
346 std::vector<VertexHandle> vhandles;
347 FaceHandle fh;
348 _out.precision(_precision);
349
350
351 // write header
352 const char header[80] =
353 "binary stl file"
354 " ";
355 _out.write(header, 80);
356
357
358 // number of faces
359 write_int(int(_be.n_faces()), _out);
360
361
362 // write face set
363 for (i=0; i<nF; ++i)
364 {
365 fh = FaceHandle(i);
366 const int nV = _be.get_vhandles(fh, vhandles);
367
368 if (nV == 3)
369 {
370 a = _be.point(vhandles[0]);
371 b = _be.point(vhandles[1]);
372 c = _be.point(vhandles[2]);
373 n = (_be.has_face_normals() ?
374 _be.normal(fh) :
375 ((c-b) % (a-b)).normalize());
376
377 // face normal
378 write_float(n[0], _out);
379 write_float(n[1], _out);
380 write_float(n[2], _out);
381
382 // face vertices
383 write_float(a[0], _out);
384 write_float(a[1], _out);
385 write_float(a[2], _out);
386
387 write_float(b[0], _out);
388 write_float(b[1], _out);
389 write_float(b[2], _out);
390
391 write_float(c[0], _out);
392 write_float(c[1], _out);
393 write_float(c[2], _out);
394
395 // space filler
396 write_short(0, _out);
397 }
398 else
399 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
400 }
401
402
403 return true;
404}
405
406
407//-----------------------------------------------------------------------------
408
409
410size_t
412binary_size(BaseExporter& _be, const Options& /* _opt */) const
413{
414 size_t bytes(0);
415 size_t _12floats(12*sizeof(float));
416
417 bytes += 80; // header
418 bytes += 4; // #faces
419
420
421 int i, nF(int(_be.n_faces()));
422 std::vector<VertexHandle> vhandles;
423
424 for (i=0; i<nF; ++i)
425 if (_be.get_vhandles(FaceHandle(i), vhandles) == 3)
426 bytes += _12floats + sizeof(short);
427 else
428 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
429
430 return bytes;
431}
432
433
434//=============================================================================
435} // namespace IO
436} // namespace OpenMesh
437//=============================================================================
Set options for reader/writer modules.
Definition Options.hh:92
@ FaceColor
Has (r) / store (w) face colors.
Definition Options.hh:110
@ Binary
Set binary mode for r/w.
Definition Options.hh:101
@ VertexNormal
Has (r) / store (w) vertex normals.
Definition Options.hh:105
@ VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition Options.hh:107
bool register_module(BaseReader *_bl)
Definition IOManager.hh:217
size_t binary_size(BaseExporter &, const Options &) const override
Returns expected size of file if binary format is supported else 0.
Definition STLWriter.cc:412
bool write(const std::string &, BaseExporter &, const Options &_writeOptions, std::streamsize _precision=6) const override
Definition STLWriter.cc:83
void write_int(int _i, FILE *_out, bool _swap=false)
void write_short(short int _i, FILE *_out, bool _swap=false)
_IOManager_ & IOManager()
Definition IOManager.cc:72
void write_float(float _f, FILE *_out, bool _swap=false)
Handle for a face entity.
Definition Handles.hh:142