Developer Documentation

STLWriter.cc
1 /* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2015, 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
52 #include <OpenMesh/Core/System/omstream.hh>
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
61 namespace OpenMesh {
62 namespace 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
81 bool
82 _STLWriter_::
83 write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const
84 {
85 // binary or ascii ?
86 if (_filename.rfind(".stla") != std::string::npos)
87 {
88 _opt -= Options::Binary;
89 }
90 else if (_filename.rfind(".stlb") != std::string::npos)
91 {
92 _opt += Options::Binary;
93 }
94
95 // open file
96 std::fstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out
97 : std::ios_base::out) );
98
99 bool result = write(out, _be, _opt, _precision);
100
101 out.close();
102
103 return result;
104 }
105
106 //-----------------------------------------------------------------------------
107
108
109 bool
110 _STLWriter_::
111 write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const
112 {
113 // check exporter features
114 if (!check(_be, _opt)) return false;
115
116 // check writer features
117 if (_opt.check(Options::VertexNormal) ||
118 _opt.check(Options::VertexTexCoord) ||
119 _opt.check(Options::FaceColor))
120 return false;
121
122 if (!_opt.check(Options::Binary))
123 _os.precision(_precision);
124
125 if (_opt & Options::Binary)
126 return write_stlb(_os, _be, _opt);
127 else
128 return write_stla(_os, _be, _opt);
129
130 return false;
131 }
132
133
134
135 //-----------------------------------------------------------------------------
136
137
138 bool
139 _STLWriter_::
140 write_stla(const std::string& _filename, 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
203 bool
204 _STLWriter_::
205 write_stla(std::ostream& _out, 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
255 bool
256 _STLWriter_::
257 write_stlb(const std::string& _filename, 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
335 bool
336 _STLWriter_::
337 write_stlb(std::ostream& _out, 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
408 size_t
409 _STLWriter_::
410 binary_size(BaseExporter& _be, 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 //=============================================================================
OpenMesh::FaceHandle
Handle for a face entity.
Definition: Handles.hh:141
omstream.hh
OpenMesh::IO::_STLWriter_::write
bool write(const std::string &, BaseExporter &, Options, std::streamsize _precision=6) const override
Definition: STLWriter.cc:83
OpenMesh::IO::Options::FaceColor
Has (r) / store (w) face colors.
Definition: Options.hh:109
OpenMesh::VectorT< float, 3 >
OpenMesh::IO::write_int
void write_int(int _i, FILE *_out, bool _swap=false)
OpenMesh::IO::_IOManager_::register_module
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:217
OpenMesh
Definition: MeshItems.hh:59
OpenMesh::IO::BaseExporter
Definition: BaseExporter.hh:84
OpenMesh::IO::Options
Set options for reader/writer modules.
Definition: Options.hh:90
OpenMesh::IO::Options::VertexNormal
Has (r) / store (w) vertex normals.
Definition: Options.hh:104
OpenMesh::IO::IOManager
_IOManager_ & IOManager()
Definition: IOManager.cc:72
OpenMesh::IO::write_short
void write_short(short int _i, FILE *_out, bool _swap=false)
OpenMesh::IO::Options::Binary
Set binary mode for r/w.
Definition: Options.hh:100
OpenMesh::IO::write_float
void write_float(float _f, FILE *_out, bool _swap=false)
OpenMesh::IO::Options::VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition: Options.hh:106
OpenMesh::IO::_STLWriter_::binary_size
size_t binary_size(BaseExporter &, Options) const override
Returns expected size of file if binary format is supported else 0.
Definition: STLWriter.cc:410