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
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
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
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
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 //=============================================================================
Handle for a face entity.
Definition: Handles.hh:141
bool write(const std::string &, BaseExporter &, Options, std::streamsize _precision=6) const override
Definition: STLWriter.cc:83
Has (r) / store (w) face colors.
Definition: Options.hh:109
void write_int(int _i, FILE *_out, bool _swap=false)
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:217
Set options for reader/writer modules.
Definition: Options.hh:90
Has (r) / store (w) vertex normals.
Definition: Options.hh:104
_IOManager_ & IOManager()
Definition: IOManager.cc:72
void write_short(short int _i, FILE *_out, bool _swap=false)
Set binary mode for r/w.
Definition: Options.hh:100
void write_float(float _f, FILE *_out, bool _swap=false)
Has (r) / store (w) texture coordinates.
Definition: Options.hh:106
size_t binary_size(BaseExporter &, Options) const override
Returns expected size of file if binary format is supported else 0.
Definition: STLWriter.cc:410