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
133
134
135//-----------------------------------------------------------------------------
136
137
138bool
139_STLWriter_::
140write_stla(const std::string& _filename, const BaseExporter& _be, Options /* _opt */) const
141{
142 omlog() << "[STLWriter] : write ascii file\n";
143
144
145 // open file
146 FILE* out = fopen(_filename.c_str(), "w");
147 if (!out)
148 {
149 omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
150 return false;
151 }
152
153
154
155
156 int i, nF(int(_be.n_faces()));
157 Vec3f a, b, c, n;
158 std::vector<VertexHandle> vhandles;
159 FaceHandle fh;
160
161
162 // header
163 fprintf(out, "solid \n");
164
165
166 // write face set
167 for (i=0; i<nF; ++i)
168 {
169 fh = FaceHandle(i);
170 const int nV = _be.get_vhandles(fh, vhandles);
171
172 if (nV == 3)
173 {
174 a = _be.point(vhandles[0]);
175 b = _be.point(vhandles[1]);
176 c = _be.point(vhandles[2]);
177 n = (_be.has_face_normals() ?
178 _be.normal(fh) :
179 ((c-b) % (a-b)).normalize());
180
181 fprintf(out, "facet normal %f %f %f\nouter loop\n", n[0], n[1], n[2]);
182 fprintf(out, "vertex %.10f %.10f %.10f\n", a[0], a[1], a[2]);
183 fprintf(out, "vertex %.10f %.10f %.10f\n", b[0], b[1], b[2]);
184 fprintf(out, "vertex %.10f %.10f %.10f", c[0], c[1], c[2]);
185 }
186 else
187 omerr() << "[STLWriter] : Warning non-triangle data!\n";
188
189 fprintf(out, "\nendloop\nendfacet\n");
190 }
191
192 fprintf(out, "endsolid\n");
193
194 fclose(out);
195
196 return true;
197}
198
199
200//-----------------------------------------------------------------------------
201
202
203bool
204_STLWriter_::
205write_stla(std::ostream& _out, const BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
206{
207 omlog() << "[STLWriter] : write ascii file\n";
208
209 int i, nF(int(_be.n_faces()));
210 Vec3f a, b, c, n;
211 std::vector<VertexHandle> vhandles;
212 FaceHandle fh;
213 _out.precision(_precision);
214
215
216 // header
217 _out << "solid \n";
218
219
220 // write face set
221 for (i=0; i<nF; ++i)
222 {
223 fh = FaceHandle(i);
224 const int nV = _be.get_vhandles(fh, vhandles);
225
226 if (nV == 3)
227 {
228 a = _be.point(vhandles[0]);
229 b = _be.point(vhandles[1]);
230 c = _be.point(vhandles[2]);
231 n = (_be.has_face_normals() ?
232 _be.normal(fh) :
233 ((c-b) % (a-b)).normalize());
234
235 _out << "facet normal " << n[0] << " " << n[1] << " " << n[2] << "\nouter loop\n";
236 _out.precision(10);
237 _out << "vertex " << a[0] << " " << a[1] << " " << a[2] << "\n";
238 _out << "vertex " << b[0] << " " << b[1] << " " << b[2] << "\n";
239 _out << "vertex " << c[0] << " " << c[1] << " " << c[2] << "\n";
240 } else {
241 omerr() << "[STLWriter] : Warning non-triangle data!\n";
242 }
243
244 _out << "\nendloop\nendfacet\n";
245 }
246
247 _out << "endsolid\n";
248
249 return true;
250}
251
252//-----------------------------------------------------------------------------
253
254
255bool
256_STLWriter_::
257write_stlb(const std::string& _filename, const BaseExporter& _be, Options /* _opt */) const
258{
259 omlog() << "[STLWriter] : write binary file\n";
260
261
262 // open file
263 FILE* out = fopen(_filename.c_str(), "wb");
264 if (!out)
265 {
266 omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
267 return false;
268 }
269
270
271 int i, nF(int(_be.n_faces()));
272 Vec3f a, b, c, n;
273 std::vector<VertexHandle> vhandles;
274 FaceHandle fh;
275
276
277 // write header
278 const char header[80] =
279 "binary stl file"
280 " ";
281 fwrite(header, 1, 80, out);
282
283
284 // number of faces
285 write_int( int(_be.n_faces()), out);
286
287
288 // write face set
289 for (i=0; i<nF; ++i)
290 {
291 fh = FaceHandle(i);
292 const int nV = _be.get_vhandles(fh, vhandles);
293
294 if (nV == 3)
295 {
296 a = _be.point(vhandles[0]);
297 b = _be.point(vhandles[1]);
298 c = _be.point(vhandles[2]);
299 n = (_be.has_face_normals() ?
300 _be.normal(fh) :
301 ((c-b) % (a-b)).normalize());
302
303 // face normal
304 write_float(n[0], out);
305 write_float(n[1], out);
306 write_float(n[2], out);
307
308 // face vertices
309 write_float(a[0], out);
310 write_float(a[1], out);
311 write_float(a[2], out);
312
313 write_float(b[0], out);
314 write_float(b[1], out);
315 write_float(b[2], out);
316
317 write_float(c[0], out);
318 write_float(c[1], out);
319 write_float(c[2], out);
320
321 // space filler
322 write_short(0, out);
323 }
324 else
325 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
326 }
327
328
329 fclose(out);
330 return true;
331}
332
333//-----------------------------------------------------------------------------
334
335bool
336_STLWriter_::
337write_stlb(std::ostream& _out, const BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
338{
339 omlog() << "[STLWriter] : write binary file\n";
340
341
342 int i, nF(int(_be.n_faces()));
343 Vec3f a, b, c, n;
344 std::vector<VertexHandle> vhandles;
345 FaceHandle fh;
346 _out.precision(_precision);
347
348
349 // write header
350 const char header[80] =
351 "binary stl file"
352 " ";
353 _out.write(header, 80);
354
355
356 // number of faces
357 write_int(int(_be.n_faces()), _out);
358
359
360 // write face set
361 for (i=0; i<nF; ++i)
362 {
363 fh = FaceHandle(i);
364 const int nV = _be.get_vhandles(fh, vhandles);
365
366 if (nV == 3)
367 {
368 a = _be.point(vhandles[0]);
369 b = _be.point(vhandles[1]);
370 c = _be.point(vhandles[2]);
371 n = (_be.has_face_normals() ?
372 _be.normal(fh) :
373 ((c-b) % (a-b)).normalize());
374
375 // face normal
376 write_float(n[0], _out);
377 write_float(n[1], _out);
378 write_float(n[2], _out);
379
380 // face vertices
381 write_float(a[0], _out);
382 write_float(a[1], _out);
383 write_float(a[2], _out);
384
385 write_float(b[0], _out);
386 write_float(b[1], _out);
387 write_float(b[2], _out);
388
389 write_float(c[0], _out);
390 write_float(c[1], _out);
391 write_float(c[2], _out);
392
393 // space filler
394 write_short(0, _out);
395 }
396 else
397 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
398 }
399
400
401 return true;
402}
403
404
405//-----------------------------------------------------------------------------
406
407
408size_t
410binary_size(BaseExporter& _be, const Options& /* _opt */) const
411{
412 size_t bytes(0);
413 size_t _12floats(12*sizeof(float));
414
415 bytes += 80; // header
416 bytes += 4; // #faces
417
418
419 int i, nF(int(_be.n_faces()));
420 std::vector<VertexHandle> vhandles;
421
422 for (i=0; i<nF; ++i)
423 if (_be.get_vhandles(FaceHandle(i), vhandles) == 3)
424 bytes += _12floats + sizeof(short);
425 else
426 omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
427
428 return bytes;
429}
430
431
432//=============================================================================
433} // namespace IO
434} // namespace OpenMesh
435//=============================================================================
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:410
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