Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
STLReader.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 <map>
55 
56 #include <float.h>
57 #include <fstream>
58 
59 // OpenMesh
60 #include <OpenMesh/Core/IO/BinaryHelper.hh>
61 #include <OpenMesh/Core/IO/reader/STLReader.hh>
62 #include <OpenMesh/Core/IO/IOManager.hh>
63 
64 
65 //=== NAMESPACES ==============================================================
66 
67 
68 namespace OpenMesh {
69 namespace IO {
70 
71 
72 //=== INSTANCIATE =============================================================
73 
74 
75 // register the STLReader singleton with MeshReader
77 _STLReader_& STLReader() { return __STLReaderInstance; }
78 
79 
80 //=== IMPLEMENTATION ==========================================================
81 
82 
83 _STLReader_::
84 _STLReader_()
85  : eps_(FLT_MIN)
86 {
87  IOManager().register_module(this);
88 }
89 
90 
91 //-----------------------------------------------------------------------------
92 
93 
94 bool
95 _STLReader_::
96 read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
97 {
98  bool result = false;
99 
100  STL_Type file_type = NONE;
101 
102  if ( check_extension( _filename, "stla" ) )
103  {
104  file_type = STLA;
105  }
106 
107  else if ( check_extension( _filename, "stlb" ) )
108  {
109  file_type = STLB;
110  }
111 
112  else if ( check_extension( _filename, "stl" ) )
113  {
114  file_type = check_stl_type(_filename);
115  }
116 
117 
118  switch (file_type)
119  {
120  case STLA:
121  {
122  result = read_stla(_filename, _bi, _opt);
123  _opt -= Options::Binary;
124  break;
125  }
126 
127  case STLB:
128  {
129  result = read_stlb(_filename, _bi, _opt);
130  _opt += Options::Binary;
131  break;
132  }
133 
134  default:
135  {
136  result = false;
137  break;
138  }
139  }
140 
141 
142  return result;
143 }
144 
145 bool
146 _STLReader_::read(std::istream& _is,
147  BaseImporter& _bi,
148  Options& _opt)
149 {
150 
151  bool result = false;
152 
153  if (_opt & Options::Binary)
154  result = read_stlb(_is, _bi, _opt);
155  else
156  result = read_stla(_is, _bi, _opt);
157 
158  return result;
159 }
160 
161 
162 //-----------------------------------------------------------------------------
163 
164 
165 #ifndef DOXY_IGNORE_THIS
166 
167 class CmpVec
168 {
169 public:
170 
171  CmpVec(float _eps=FLT_MIN) : eps_(_eps) {}
172 
173  bool operator()( const Vec3f& _v0, const Vec3f& _v1 ) const
174  {
175  if (fabs(_v0[0] - _v1[0]) <= eps_)
176  {
177  if (fabs(_v0[1] - _v1[1]) <= eps_)
178  {
179  return (_v0[2] < _v1[2] - eps_);
180  }
181  else return (_v0[1] < _v1[1] - eps_);
182  }
183  else return (_v0[0] < _v1[0] - eps_);
184  }
185 
186 private:
187  float eps_;
188 };
189 
190 #endif
191 
192 
193 //-----------------------------------------------------------------------------
194 
195 void trimStdString( std::string& _string) {
196  // Trim Both leading and trailing spaces
197 
198  size_t start = _string.find_first_not_of(" \t\r\n");
199  size_t end = _string.find_last_not_of(" \t\r\n");
200 
201  if(( std::string::npos == start ) || ( std::string::npos == end))
202  _string = "";
203  else
204  _string = _string.substr( start, end-start+1 );
205 }
206 
207 //-----------------------------------------------------------------------------
208 
209 bool
210 _STLReader_::
211 read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const
212 {
213  std::fstream in( _filename.c_str(), std::ios_base::in );
214 
215  if (!in)
216  {
217  omerr() << "[STLReader] : cannot not open file "
218  << _filename
219  << std::endl;
220  return false;
221  }
222 
223  bool res = read_stla(in, _bi, _opt);
224 
225  if (in)
226  in.close();
227 
228  return res;
229 }
230 
231 //-----------------------------------------------------------------------------
232 
233 bool
234 _STLReader_::
235 read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const
236 {
237 
238  unsigned int i;
239  OpenMesh::Vec3f v;
240  OpenMesh::Vec3f n;
241  BaseImporter::VHandles vhandles;
242 
243  CmpVec comp(eps_);
244  std::map<Vec3f, VertexHandle, CmpVec> vMap(comp);
245  std::map<Vec3f, VertexHandle, CmpVec>::iterator vMapIt;
246 
247  std::string line;
248 
249  std::string garbage;
250  std::stringstream strstream;
251 
252  bool facet_normal(false);
253 
254  while( _in && !_in.eof() ) {
255 
256  // Get one line
257  std::getline(_in, line);
258  if ( _in.bad() ){
259  omerr() << " Warning! Could not read stream properly!\n";
260  return false;
261  }
262 
263  // Trim Both leading and trailing spaces
264  trimStdString(line);
265 
266  // Normal found?
267  if (line.find("facet normal") != std::string::npos) {
268  strstream.str(line);
269  strstream.clear();
270 
271  // facet
272  strstream >> garbage;
273 
274  // normal
275  strstream >> garbage;
276 
277  strstream >> n[0];
278  strstream >> n[1];
279  strstream >> n[2];
280 
281  facet_normal = true;
282  }
283 
284  // Detected a triangle
285  if ( (line.find("outer") != std::string::npos) || (line.find("OUTER") != std::string::npos ) ) {
286 
287  vhandles.clear();
288 
289  for (i=0; i<3; ++i) {
290  // Get one vertex
291  std::getline(_in, line);
292  trimStdString(line);
293 
294  strstream.str(line);
295  strstream.clear();
296 
297  strstream >> garbage;
298 
299  strstream >> v[0];
300  strstream >> v[1];
301  strstream >> v[2];
302 
303  // has vector been referenced before?
304  if ((vMapIt=vMap.find(v)) == vMap.end())
305  {
306  // No : add vertex and remember idx/vector mapping
307  VertexHandle handle = _bi.add_vertex(v);
308  vhandles.push_back(handle);
309  vMap[v] = handle;
310  }
311  else
312  // Yes : get index from map
313  vhandles.push_back(vMapIt->second);
314 
315  }
316 
317  // Add face only if it is not degenerated
318  if ((vhandles[0] != vhandles[1]) &&
319  (vhandles[0] != vhandles[2]) &&
320  (vhandles[1] != vhandles[2])) {
321 
322 
323  FaceHandle fh = _bi.add_face(vhandles);
324 
325  // set the normal if requested
326  // if a normal was requested but could not be found we unset the option
327  if (facet_normal) {
328  if (fh.is_valid() && _opt.face_has_normal())
329  _bi.set_normal(fh, n);
330  } else
331  _opt -= Options::FaceNormal;
332  }
333 
334  facet_normal = false;
335  }
336  }
337 
338  return true;
339 }
340 
341 //-----------------------------------------------------------------------------
342 
343 bool
344 _STLReader_::
345 read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const
346 {
347  std::fstream in( _filename.c_str(), std::ios_base::in | std::ios_base::binary);
348 
349  if (!in)
350  {
351  omerr() << "[STLReader] : cannot not open file "
352  << _filename
353  << std::endl;
354  return false;
355  }
356 
357  bool res = read_stlb(in, _bi, _opt);
358 
359  if (in)
360  in.close();
361 
362  return res;
363 }
364 
365 //-----------------------------------------------------------------------------
366 
367 bool
368 _STLReader_::
369 read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const
370 {
371  char dummy[100];
372  bool swapFlag;
373  unsigned int i, nT;
374  OpenMesh::Vec3f v, n;
375  BaseImporter::VHandles vhandles;
376 
377  std::map<Vec3f, VertexHandle, CmpVec> vMap;
378  std::map<Vec3f, VertexHandle, CmpVec>::iterator vMapIt;
379 
380 
381  // check size of types
382  if ((sizeof(float) != 4) || (sizeof(int) != 4)) {
383  omerr() << "[STLReader] : wrong type size\n";
384  return false;
385  }
386 
387  // determine endian mode
388  union { unsigned int i; unsigned char c[4]; } endian_test;
389  endian_test.i = 1;
390  swapFlag = (endian_test.c[3] == 1);
391 
392  // read number of triangles
393  _in.read(dummy, 80);
394  nT = read_int(_in, swapFlag);
395 
396  // read triangles
397  while (nT)
398  {
399  vhandles.clear();
400 
401  // read triangle normal
402  n[0] = read_float(_in, swapFlag);
403  n[1] = read_float(_in, swapFlag);
404  n[2] = read_float(_in, swapFlag);
405 
406  // triangle's vertices
407  for (i=0; i<3; ++i)
408  {
409  v[0] = read_float(_in, swapFlag);
410  v[1] = read_float(_in, swapFlag);
411  v[2] = read_float(_in, swapFlag);
412 
413  // has vector been referenced before?
414  if ((vMapIt=vMap.find(v)) == vMap.end())
415  {
416  // No : add vertex and remember idx/vector mapping
417  VertexHandle handle = _bi.add_vertex(v);
418  vhandles.push_back(handle);
419  vMap[v] = handle;
420  }
421  else
422  // Yes : get index from map
423  vhandles.push_back(vMapIt->second);
424  }
425 
426 
427  // Add face only if it is not degenerated
428  if ((vhandles[0] != vhandles[1]) &&
429  (vhandles[0] != vhandles[2]) &&
430  (vhandles[1] != vhandles[2])) {
431  FaceHandle fh = _bi.add_face(vhandles);
432 
433  if (fh.is_valid() && _opt.face_has_normal())
434  _bi.set_normal(fh, n);
435  }
436 
437  _in.read(dummy, 2);
438  --nT;
439  }
440 
441  return true;
442 }
443 
444 //-----------------------------------------------------------------------------
445 
446 _STLReader_::STL_Type
447 _STLReader_::
448 check_stl_type(const std::string& _filename) const
449 {
450  // assume it's binary stl, then file size is known from #triangles
451  // if size matches, it's really binary
452 
453 
454  // open file
455  FILE* in = fopen(_filename.c_str(), "rb");
456  if (!in) return NONE;
457 
458 
459  // determine endian mode
460  union { unsigned int i; unsigned char c[4]; } endian_test;
461  endian_test.i = 1;
462  bool swapFlag = (endian_test.c[3] == 1);
463 
464 
465  // read number of triangles
466  char dummy[100];
467  fread(dummy, 1, 80, in);
468  size_t nT = read_int(in, swapFlag);
469 
470 
471  // compute file size from nT
472  size_t binary_size = 84 + nT*50;
473 
474 
475  // get actual file size
476  size_t file_size(0);
477  rewind(in);
478  while (!feof(in))
479  file_size += fread(dummy, 1, 100, in);
480  fclose(in);
481 
482 
483  // if sizes match -> it's STLB
484  return (binary_size == file_size ? STLB : STLA);
485 }
486 
487 
488 //=============================================================================
489 } // namespace IO
490 } // namespace OpenMesh
491 //=============================================================================
float read_float(FILE *_in, bool _swap=false)
int read_int(FILE *_in, bool _swap=false)
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Set options for reader/writer modules.
Definition: Options.hh:95
_STLReader_ __STLReaderInstance
Declare the single entity of the STL reader.
Definition: STLReader.cc:76
_IOManager_ & IOManager()
Definition: IOManager.cc:77
DrawMode NONE
not a valid draw mode
Definition: DrawModes.cc:77