diff --git a/src/OpenMesh/Core/IO/reader/STLReader.cc b/src/OpenMesh/Core/IO/reader/STLReader.cc index 56e43e3a..e8751dd9 100644 --- a/src/OpenMesh/Core/IO/reader/STLReader.cc +++ b/src/OpenMesh/Core/IO/reader/STLReader.cc @@ -115,14 +115,14 @@ read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { case STLA: { - result = read_stla(_filename, _bi); + result = read_stla(_filename, _bi, _opt); _opt -= Options::Binary; break; } case STLB: { - result = read_stlb(_filename, _bi); + result = read_stlb(_filename, _bi, _opt); _opt += Options::Binary; break; } @@ -147,9 +147,9 @@ _STLReader_::read(std::istream& _is, bool result = false; if (_opt & Options::Binary) - result = read_stlb(_is, _bi); + result = read_stlb(_is, _bi, _opt); else - result = read_stla(_is, _bi); + result = read_stla(_is, _bi, _opt); return result; } @@ -204,7 +204,7 @@ void trimStdString( std::string& _string) { bool _STLReader_:: -read_stla(const std::string& _filename, BaseImporter& _bi) const +read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const { omlog() << "[STLReader] : read ascii file\n"; @@ -218,110 +218,19 @@ read_stla(const std::string& _filename, BaseImporter& _bi) const return false; } - - unsigned int i; - OpenMesh::Vec3f v; - OpenMesh::Vec3f n; - BaseImporter::VHandles vhandles; - - CmpVec comp(eps_); - std::map vMap(comp); - std::map::iterator vMapIt; - - std::string line; - - //bool normal = false; - - while( in && !in.eof() ) { - - // Get one line - std::getline(in,line); - if ( in.bad() ){ - omerr() << " Warning! Could not read file properly!\n"; - in.close(); - return false; - } - - // Trim Both leading and trailing spaces - trimStdString(line); - - // Normal found? - if (line.find("facet normal") != std::string::npos) { - std::stringstream strstream(line); - - std::string garbage; - - // facet - strstream >> garbage; - - // normal - strstream >> garbage; - - strstream >> n[0]; - strstream >> n[1]; - strstream >> n[2]; - - //normal = true; - } - - // Detected a triangle - if ( (line.find("outer") != std::string::npos) || (line.find("OUTER") != std::string::npos ) ) { - - vhandles.clear(); - - for (i=0; i<3; ++i) { - // Get one vertex - std::getline(in,line); - trimStdString(line); - - std::stringstream strstream(line); - - std::string garbage; - strstream >> garbage; - - strstream >> v[0]; - strstream >> v[1]; - strstream >> v[2]; - - // has vector been referenced before? - if ((vMapIt=vMap.find(v)) == vMap.end()) - { - // No : add vertex and remember idx/vector mapping - VertexHandle handle = _bi.add_vertex(v); - vhandles.push_back(handle); - vMap[v] = handle; - } - else - // Yes : get index from map - vhandles.push_back(vMapIt->second); - - } - - // Add face only if it is not degenerated - if ((vhandles[0] != vhandles[1]) && - (vhandles[0] != vhandles[2]) && - (vhandles[1] != vhandles[2])) { - - - FaceHandle fh = _bi.add_face(vhandles); - - } - - //normal = false; - } - } + bool res = read_stla(in, _bi, _opt); if (in) in.close(); - return true; + return res; } //----------------------------------------------------------------------------- bool _STLReader_:: -read_stla(std::istream& _in, BaseImporter& _bi) const +read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const { omlog() << "[STLReader] : read ascii stream\n"; @@ -337,7 +246,7 @@ read_stla(std::istream& _in, BaseImporter& _bi) const std::string line; - //bool normal = false; + bool facet_normal(false); while( _in && !_in.eof() ) { @@ -367,7 +276,7 @@ read_stla(std::istream& _in, BaseImporter& _bi) const strstream >> n[1]; strstream >> n[2]; - //normal = true; + facet_normal = true; } // Detected a triangle @@ -411,9 +320,16 @@ read_stla(std::istream& _in, BaseImporter& _bi) const FaceHandle fh = _bi.add_face(vhandles); + // set the normal if requested + // if a normal was requested but could not be found we unset the option + if (facet_normal) { + if (_opt.face_has_normal()) + _bi.set_normal(fh, n); + } else + _opt -= Options::FaceNormal; } - //normal = false; + facet_normal = false; } } @@ -424,11 +340,12 @@ read_stla(std::istream& _in, BaseImporter& _bi) const bool _STLReader_:: -read_stlb(const std::string& _filename, BaseImporter& _bi) const +read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const { omlog() << "[STLReader] : read binary file\n"; - FILE* in = fopen(_filename.c_str(), "rb"); + std::fstream in( _filename.c_str(), std::ios_base::in | std::ios_base::binary); + if (!in) { omerr() << "[STLReader] : cannot not open file " @@ -437,88 +354,26 @@ read_stlb(const std::string& _filename, BaseImporter& _bi) const return false; } + bool res = read_stlb(in, _bi, _opt); - char dummy[100]; - bool swapFlag; - unsigned int i, nT; - OpenMesh::Vec3f v; - BaseImporter::VHandles vhandles; + if (in) + in.close(); - std::map vMap; - std::map::iterator vMapIt; - - - // check size of types - if ((sizeof(float) != 4) || (sizeof(int) != 4)) { - omerr() << "[STLReader] : wrong type size\n"; - return false; - } - - // determine endian mode - union { unsigned int i; unsigned char c[4]; } endian_test; - endian_test.i = 1; - swapFlag = (endian_test.c[3] == 1); - - // read number of triangles - fread(dummy, 1, 80, in); - nT = read_int(in, swapFlag); - - // read triangles - while (nT) - { - vhandles.clear(); - - // skip triangle normal - fread(dummy, 1, 12, in); - - // triangle's vertices - for (i=0; i<3; ++i) - { - v[0] = read_float(in, swapFlag); - v[1] = read_float(in, swapFlag); - v[2] = read_float(in, swapFlag); - - // has vector been referenced before? - if ((vMapIt=vMap.find(v)) == vMap.end()) - { - // No : add vertex and remember idx/vector mapping - VertexHandle handle = _bi.add_vertex(v); - vhandles.push_back(handle); - vMap[v] = handle; - } - else - // Yes : get index from map - vhandles.push_back(vMapIt->second); - } - - - // Add face only if it is not degenerated - if ((vhandles[0] != vhandles[1]) && - (vhandles[0] != vhandles[2]) && - (vhandles[1] != vhandles[2])) - _bi.add_face(vhandles); - - fread(dummy, 1, 2, in); - --nT; - } - - fclose(in); - - return true; + return res; } //----------------------------------------------------------------------------- bool _STLReader_:: -read_stlb(std::istream& _in, BaseImporter& _bi) const +read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const { omlog() << "[STLReader] : read binary stream\n"; char dummy[100]; bool swapFlag; unsigned int i, nT; - OpenMesh::Vec3f v; + OpenMesh::Vec3f v, n; BaseImporter::VHandles vhandles; std::map vMap; @@ -537,7 +392,6 @@ read_stlb(std::istream& _in, BaseImporter& _bi) const swapFlag = (endian_test.c[3] == 1); // read number of triangles - //fread(dummy, 1, 80, in); _in.read(dummy, 80); nT = read_int(_in, swapFlag); @@ -546,8 +400,10 @@ read_stlb(std::istream& _in, BaseImporter& _bi) const { vhandles.clear(); - // skip triangle normal - _in.read(dummy, 12); + // read triangle normal + n[0] = read_float(_in, swapFlag); + n[1] = read_float(_in, swapFlag); + n[2] = read_float(_in, swapFlag); // triangle's vertices for (i=0; i<3; ++i) @@ -573,8 +429,12 @@ read_stlb(std::istream& _in, BaseImporter& _bi) const // Add face only if it is not degenerated if ((vhandles[0] != vhandles[1]) && (vhandles[0] != vhandles[2]) && - (vhandles[1] != vhandles[2])) - _bi.add_face(vhandles); + (vhandles[1] != vhandles[2])) { + FaceHandle fh = _bi.add_face(vhandles); + + if (_opt.face_has_normal()) + _bi.set_normal(fh, n); + } _in.read(dummy, 2); --nT; diff --git a/src/OpenMesh/Core/IO/reader/STLReader.hh b/src/OpenMesh/Core/IO/reader/STLReader.hh index e932011f..578c6181 100644 --- a/src/OpenMesh/Core/IO/reader/STLReader.hh +++ b/src/OpenMesh/Core/IO/reader/STLReader.hh @@ -120,10 +120,10 @@ private: enum STL_Type { STLA, STLB, NONE }; STL_Type check_stl_type(const std::string& _filename) const; - bool read_stla(const std::string& _filename, BaseImporter& _bi) const; - bool read_stla(std::istream& _in, BaseImporter& _bi) const; - bool read_stlb(const std::string& _filename, BaseImporter& _bi) const; - bool read_stlb(std::istream& _in, BaseImporter& _bi) const; + bool read_stla(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stla(std::istream& _in, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(const std::string& _filename, BaseImporter& _bi, Options& _opt) const; + bool read_stlb(std::istream& _in, BaseImporter& _bi, Options& _opt) const; private: diff --git a/src/Unittests/unittests_read_write_STL.cc b/src/Unittests/unittests_read_write_STL.cc index c1e5b493..c61146b6 100644 --- a/src/Unittests/unittests_read_write_STL.cc +++ b/src/Unittests/unittests_read_write_STL.cc @@ -49,6 +49,36 @@ TEST_F(OpenMeshReadWriteSTL, LoadSimpleSTLFile) { } +/* + * Just load a simple mesh file in stla format and count whether + * the right number of entities has been loaded. Also check facet normals. + */ +TEST_F(OpenMeshReadWriteSTL, LoadSimpleSTLFileWithNormals) { + + mesh_.clear(); + mesh_.request_face_normals(); + + OpenMesh::IO::Options opt; + opt += OpenMesh::IO::Options::FaceNormal; + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.stl", opt); + + EXPECT_TRUE(ok); + + EXPECT_TRUE(opt.face_has_normal()); + EXPECT_FALSE(opt.vertex_has_normal()); + + EXPECT_NEAR(-0.038545f, mesh_.normal(mesh_.face_handle(0))[0], 0.0001 ) << "Wrong face normal at face 0 component 0"; + EXPECT_NEAR(-0.004330f, mesh_.normal(mesh_.face_handle(0))[1], 0.0001 ) << "Wrong face normal at face 0 component 1"; + EXPECT_NEAR(0.999247f, mesh_.normal(mesh_.face_handle(0))[2], 0.0001 ) << "Wrong face normal at face 0 component 2"; + + EXPECT_EQ(7526u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!"; + EXPECT_EQ(22572u , mesh_.n_edges()) << "The number of loaded edges is not correct!"; + EXPECT_EQ(15048u , mesh_.n_faces()) << "The number of loaded faces is not correct!"; + + mesh_.release_face_normals(); +} + /* * Just load a simple mesh file in stlb format and count whether @@ -67,4 +97,37 @@ TEST_F(OpenMeshReadWriteSTL, LoadSimpleSTLBinaryFile) { EXPECT_EQ(15048u , mesh_.n_faces()) << "The number of loaded faces is not correct!"; } + +/* + * Just load a simple mesh file in stlb format and count whether + * the right number of entities has been loaded. Also check facet normals. + */ +TEST_F(OpenMeshReadWriteSTL, LoadSimpleSTLBinaryFileWithNormals) { + + mesh_.clear(); + mesh_.request_face_normals(); + + OpenMesh::IO::Options opt; + opt += OpenMesh::IO::Options::FaceNormal; + opt += OpenMesh::IO::Options::Binary; + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1Binary.stl", opt); + + EXPECT_TRUE(ok); + + EXPECT_TRUE(opt.is_binary()); + EXPECT_TRUE(opt.face_has_normal()); + EXPECT_FALSE(opt.vertex_has_normal()); + + EXPECT_NEAR(-0.038545f, mesh_.normal(mesh_.face_handle(0))[0], 0.0001 ) << "Wrong face normal at face 0 component 0"; + EXPECT_NEAR(-0.004330f, mesh_.normal(mesh_.face_handle(0))[1], 0.0001 ) << "Wrong face normal at face 0 component 1"; + EXPECT_NEAR(0.999247f, mesh_.normal(mesh_.face_handle(0))[2], 0.0001 ) << "Wrong face normal at face 0 component 2"; + + EXPECT_EQ(7526u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!"; + EXPECT_EQ(22572u , mesh_.n_edges()) << "The number of loaded edges is not correct!"; + EXPECT_EQ(15048u , mesh_.n_faces()) << "The number of loaded faces is not correct!"; + + mesh_.release_face_normals(); +} + }