Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
76 _STLReader_ __STLReaderInstance;
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 //=============================================================================
OpenMesh::IO::read_float
float read_float(FILE *_in, bool _swap=false)
OpenMesh
Definition: MeshItems.hh:64
OpenMesh::IO::read_int
int read_int(FILE *_in, bool _swap=false)
OpenMesh::IO::_IOManager_::register_module
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
BaseImporter
Definition: BaseImporter.hh:1
OpenMesh::IO::Options
Set options for reader/writer modules.
Definition: Options.hh:95
OpenMesh::IO::__STLReaderInstance
_STLReader_ __STLReaderInstance
Declare the single entity of the STL reader.
Definition: STLReader.cc:76
OpenMesh::VectorT< float, 3 >
OpenMesh::IO::_STLReader_
Definition: STLReader.hh:89
OpenMesh::IO::IOManager
_IOManager_ & IOManager()
Definition: IOManager.cc:77
ACG::SceneGraph::DrawModes::NONE
DrawMode NONE
not a valid draw mode
Definition: DrawModes.cc:77
OpenMesh::IO::BaseImporter
Definition: BaseImporter.hh:88