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  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 
50 //== INCLUDES =================================================================
51 
52 
53 //STL
54 #include <fstream>
55 
56 // OpenMesh
58 #include <OpenMesh/Core/Geometry/VectorT.hh>
59 #include <OpenMesh/Core/IO/BinaryHelper.hh>
60 #include <OpenMesh/Core/IO/IOManager.hh>
61 #include <OpenMesh/Core/IO/writer/STLWriter.hh>
62 
63 //=== NAMESPACES ==============================================================
64 
65 
66 namespace OpenMesh {
67 namespace IO {
68 
69 
70 //=== INSTANCIATE =============================================================
71 
72 
73 _STLWriter_ __STLWriterInstance;
74 _STLWriter_& STLWriter() { return __STLWriterInstance; }
75 
76 
77 //=== IMPLEMENTATION ==========================================================
78 
79 
80 _STLWriter_::_STLWriter_() { IOManager().register_module(this); }
81 
82 
83 //-----------------------------------------------------------------------------
84 
85 
86 bool
88 write(const std::string& _filename, BaseExporter& _be, Options _opt, std::streamsize _precision) const
89 {
90  // binary or ascii ?
91  if (_filename.rfind(".stla") != std::string::npos)
92  {
93  _opt -= Options::Binary;
94  }
95  else if (_filename.rfind(".stlb") != std::string::npos)
96  {
97  _opt += Options::Binary;
98  }
99 
100  // open file
101  std::fstream out(_filename.c_str(), (_opt.check(Options::Binary) ? std::ios_base::binary | std::ios_base::out
102  : std::ios_base::out) );
103 
104  bool result = write(out, _be, _opt, _precision);
105 
106  out.close();
107 
108  return result;
109 }
110 
111 //-----------------------------------------------------------------------------
112 
113 
114 bool
116 write(std::ostream& _os, BaseExporter& _be, Options _opt, std::streamsize _precision) const
117 {
118  // check exporter features
119  if (!check(_be, _opt)) return false;
120 
121  // check writer features
122  if (_opt.check(Options::VertexNormal) ||
123  _opt.check(Options::VertexTexCoord) ||
124  _opt.check(Options::FaceColor))
125  return false;
126 
127  if (!_opt.check(Options::Binary))
128  _os.precision(_precision);
129 
130  if (_opt & Options::Binary)
131  return write_stlb(_os, _be, _opt);
132  else
133  return write_stla(_os, _be, _opt);
134 
135  return false;
136 }
137 
138 
139 
140 //-----------------------------------------------------------------------------
141 
142 
143 bool
144 _STLWriter_::
145 write_stla(const std::string& _filename, BaseExporter& _be, Options /* _opt */) const
146 {
147  omlog() << "[STLWriter] : write ascii file\n";
148 
149 
150  // open file
151  FILE* out = fopen(_filename.c_str(), "w");
152  if (!out)
153  {
154  omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
155  return false;
156  }
157 
158 
159 
160 
161  int i, nF(int(_be.n_faces())), nV;
162  Vec3f a, b, c, n;
163  std::vector<VertexHandle> vhandles;
164  FaceHandle fh;
165 
166 
167  // header
168  fprintf(out, "solid \n");
169 
170 
171  // write face set
172  for (i=0; i<nF; ++i)
173  {
174  fh = FaceHandle(i);
175  nV = _be.get_vhandles(fh, vhandles);
176 
177  if (nV == 3)
178  {
179  a = _be.point(vhandles[0]);
180  b = _be.point(vhandles[1]);
181  c = _be.point(vhandles[2]);
182  n = (_be.has_face_normals() ?
183  _be.normal(fh) :
184  ((c-b) % (a-b)).normalize());
185 
186  fprintf(out, "facet normal %f %f %f\nouter loop\n", n[0], n[1], n[2]);
187  fprintf(out, "vertex %.10f %.10f %.10f\n", a[0], a[1], a[2]);
188  fprintf(out, "vertex %.10f %.10f %.10f\n", b[0], b[1], b[2]);
189  fprintf(out, "vertex %.10f %.10f %.10f", c[0], c[1], c[2]);
190  }
191  else
192  omerr() << "[STLWriter] : Warning non-triangle data!\n";
193 
194  fprintf(out, "\nendloop\nendfacet\n");
195  }
196 
197  fprintf(out, "endsolid\n");
198 
199  fclose(out);
200 
201  return true;
202 }
203 
204 
205 //-----------------------------------------------------------------------------
206 
207 
208 bool
209 _STLWriter_::
210 write_stla(std::ostream& _out, BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
211 {
212  omlog() << "[STLWriter] : write ascii file\n";
213 
214  int i, nF(int(_be.n_faces())), nV;
215  Vec3f a, b, c, n;
216  std::vector<VertexHandle> vhandles;
217  FaceHandle fh;
218  _out.precision(_precision);
219 
220 
221  // header
222  _out << "solid \n";
223 
224 
225  // write face set
226  for (i=0; i<nF; ++i)
227  {
228  fh = FaceHandle(i);
229  nV = _be.get_vhandles(fh, vhandles);
230 
231  if (nV == 3)
232  {
233  a = _be.point(vhandles[0]);
234  b = _be.point(vhandles[1]);
235  c = _be.point(vhandles[2]);
236  n = (_be.has_face_normals() ?
237  _be.normal(fh) :
238  ((c-b) % (a-b)).normalize());
239 
240  _out << "facet normal " << n[0] << " " << n[1] << " " << n[2] << "\nouter loop\n";
241  _out.precision(10);
242  _out << "vertex " << a[0] << " " << a[1] << " " << a[2] << "\n";
243  _out << "vertex " << b[0] << " " << b[1] << " " << b[2] << "\n";
244  _out << "vertex " << c[0] << " " << c[1] << " " << c[2] << "\n";
245  } else {
246  omerr() << "[STLWriter] : Warning non-triangle data!\n";
247  }
248 
249  _out << "\nendloop\nendfacet\n";
250  }
251 
252  _out << "endsolid\n";
253 
254  return true;
255 }
256 
257 //-----------------------------------------------------------------------------
258 
259 
260 bool
261 _STLWriter_::
262 write_stlb(const std::string& _filename, BaseExporter& _be, Options /* _opt */) const
263 {
264  omlog() << "[STLWriter] : write binary file\n";
265 
266 
267  // open file
268  FILE* out = fopen(_filename.c_str(), "wb");
269  if (!out)
270  {
271  omerr() << "[STLWriter] : cannot open file " << _filename << std::endl;
272  return false;
273  }
274 
275 
276  int i, nF(int(_be.n_faces())), nV;
277  Vec3f a, b, c, n;
278  std::vector<VertexHandle> vhandles;
279  FaceHandle fh;
280 
281 
282  // write header
283  const char header[80] =
284  "binary stl file"
285  " ";
286  fwrite(header, 1, 80, out);
287 
288 
289  // number of faces
290  write_int( int(_be.n_faces()), out);
291 
292 
293  // write face set
294  for (i=0; i<nF; ++i)
295  {
296  fh = FaceHandle(i);
297  nV = _be.get_vhandles(fh, vhandles);
298 
299  if (nV == 3)
300  {
301  a = _be.point(vhandles[0]);
302  b = _be.point(vhandles[1]);
303  c = _be.point(vhandles[2]);
304  n = (_be.has_face_normals() ?
305  _be.normal(fh) :
306  ((c-b) % (a-b)).normalize());
307 
308  // face normal
309  write_float(n[0], out);
310  write_float(n[1], out);
311  write_float(n[2], out);
312 
313  // face vertices
314  write_float(a[0], out);
315  write_float(a[1], out);
316  write_float(a[2], out);
317 
318  write_float(b[0], out);
319  write_float(b[1], out);
320  write_float(b[2], out);
321 
322  write_float(c[0], out);
323  write_float(c[1], out);
324  write_float(c[2], out);
325 
326  // space filler
327  write_short(0, out);
328  }
329  else
330  omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
331  }
332 
333 
334  fclose(out);
335  return true;
336 }
337 
338 //-----------------------------------------------------------------------------
339 
340 bool
341 _STLWriter_::
342 write_stlb(std::ostream& _out, BaseExporter& _be, Options /* _opt */, std::streamsize _precision) const
343 {
344  omlog() << "[STLWriter] : write binary file\n";
345 
346 
347  int i, nF(int(_be.n_faces())), nV;
348  Vec3f a, b, c, n;
349  std::vector<VertexHandle> vhandles;
350  FaceHandle fh;
351  _out.precision(_precision);
352 
353 
354  // write header
355  const char header[80] =
356  "binary stl file"
357  " ";
358  _out.write(header, 80);
359 
360 
361  // number of faces
362  write_int(int(_be.n_faces()), _out);
363 
364 
365  // write face set
366  for (i=0; i<nF; ++i)
367  {
368  fh = FaceHandle(i);
369  nV = _be.get_vhandles(fh, vhandles);
370 
371  if (nV == 3)
372  {
373  a = _be.point(vhandles[0]);
374  b = _be.point(vhandles[1]);
375  c = _be.point(vhandles[2]);
376  n = (_be.has_face_normals() ?
377  _be.normal(fh) :
378  ((c-b) % (a-b)).normalize());
379 
380  // face normal
381  write_float(n[0], _out);
382  write_float(n[1], _out);
383  write_float(n[2], _out);
384 
385  // face vertices
386  write_float(a[0], _out);
387  write_float(a[1], _out);
388  write_float(a[2], _out);
389 
390  write_float(b[0], _out);
391  write_float(b[1], _out);
392  write_float(b[2], _out);
393 
394  write_float(c[0], _out);
395  write_float(c[1], _out);
396  write_float(c[2], _out);
397 
398  // space filler
399  write_short(0, _out);
400  }
401  else
402  omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
403  }
404 
405 
406  return true;
407 }
408 
409 
410 //-----------------------------------------------------------------------------
411 
412 
413 size_t
415 binary_size(BaseExporter& _be, Options /* _opt */) const
416 {
417  size_t bytes(0);
418  size_t _12floats(12*sizeof(float));
419 
420  bytes += 80; // header
421  bytes += 4; // #faces
422 
423 
424  int i, nF(int(_be.n_faces()));
425  std::vector<VertexHandle> vhandles;
426 
427  for (i=0; i<nF; ++i)
428  if (_be.get_vhandles(FaceHandle(i), vhandles) == 3)
429  bytes += _12floats + sizeof(short);
430  else
431  omerr() << "[STLWriter] : Warning: Skipped non-triangle data!\n";
432 
433  return bytes;
434 }
435 
436 
437 //=============================================================================
438 } // namespace IO
439 } // namespace OpenMesh
440 //=============================================================================
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
void write_int(int _i, FILE *_out, bool _swap=false)
void write_float(float _f, FILE *_out, bool _swap=false)
Set binary mode for r/w.
Definition: Options.hh:105
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
bool write(const std::string &, BaseExporter &, Options, std::streamsize _precision=6) const
Definition: STLWriter.cc:88
Set options for reader/writer modules.
Definition: Options.hh:95
size_t binary_size(BaseExporter &, Options) const
Returns expected size of file if binary format is supported else 0.
Definition: STLWriter.cc:415
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Handle for a face entity.
Definition: Handles.hh:146
void write_short(short int _i, FILE *_out, bool _swap=false)
Has (r) / store (w) face colors.
Definition: Options.hh:114
_IOManager_ & IOManager()
Definition: IOManager.cc:77