From 1e6aa0f11a737a2d9a314ee005993e03f42fbf16 Mon Sep 17 00:00:00 2001 From: Julius Nehring-Wirxel <julius.nehring-wirxel@rwth-aachen.de> Date: Mon, 25 Jan 2021 20:27:49 +0100 Subject: [PATCH] Fix several bugs with the STL reader On windows ifstreams handle data differently depending if the file was opened in binary mode or not. This messed with the parsing for some files. Fixed reading a binary file into any other scalar type other than float. Binary STL always contain 32 bit floats, but the parser depended on ScalarT for how much data should be read, which can lead to false results if e.g. a double position type is given. --- src/polymesh/formats/stl.cc | 40 +++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/polymesh/formats/stl.cc b/src/polymesh/formats/stl.cc index 1d2cf6f..1f384c1 100644 --- a/src/polymesh/formats/stl.cc +++ b/src/polymesh/formats/stl.cc @@ -70,7 +70,17 @@ bool read_stl(const std::string& filename, Mesh& mesh, vertex_attribute<std::arr if (!file.good()) return false; - return read_stl(file, mesh, position, normals); + if (is_ascii_stl(file)) + { + return read_stl_ascii(file, mesh, position, normals); + } + else + { + // Windows interprets binary files differently from ascii which messes with the parsing. + // Therefore we create a new stream in binary mode. + file = std::ifstream(filename, std::ios::binary); + return read_stl_binary(file, mesh, position, normals); + } } template <class ScalarT> @@ -99,9 +109,10 @@ bool read_stl_binary(std::istream& input, Mesh& mesh, vertex_attribute<std::arra // } uint32_t n_triangles; - input.read((char*)&n_triangles, sizeof(n_triangles)); + input.read(reinterpret_cast<char*>(&n_triangles), sizeof(n_triangles)); - size_t fs_expect = 80 + sizeof(n_triangles) + n_triangles * (sizeof(std::array<ScalarT, 3>) * 4 + sizeof(uint16_t)); + // note: binary stl always stores 32bit floats + size_t fs_expect = 80 + sizeof(n_triangles) + n_triangles * (sizeof(std::array<float, 3>) * 4 + sizeof(uint16_t)); if (fs_expect != fs_real) { std::cerr << "Expected file size mismatch: " << fs_expect << " vs " << fs_real << " bytes (file corrupt or wrong format?)" << std::endl; @@ -125,12 +136,25 @@ bool read_stl_binary(std::istream& input, Mesh& mesh, vertex_attribute<std::arra auto v2 = mesh.vertices().add(); auto f = mesh.faces().add(v0, v1, v2); - input.read((char*)&f[normals], sizeof(std::array<ScalarT, 3>)); - input.read((char*)&position[v0], sizeof(std::array<ScalarT, 3>)); - input.read((char*)&position[v1], sizeof(std::array<ScalarT, 3>)); - input.read((char*)&position[v2], sizeof(std::array<ScalarT, 3>)); + std::array<float, 3> n; + input.read(reinterpret_cast<char*>(&n), sizeof(n)); + + if (normals) + f[normals] = {n[0], n[1], n[2]}; + + std::array<float, 3> p0; + std::array<float, 3> p1; + std::array<float, 3> p2; + input.read(reinterpret_cast<char*>(&p0), sizeof(p0)); + input.read(reinterpret_cast<char*>(&p1), sizeof(p1)); + input.read(reinterpret_cast<char*>(&p2), sizeof(p2)); + // convert float to ScalarT + position[v0] = {ScalarT(p0[0]), ScalarT(p0[1]), ScalarT(p0[2])}; + position[v1] = {ScalarT(p1[0]), ScalarT(p1[1]), ScalarT(p1[2])}; + position[v2] = {ScalarT(p2[0]), ScalarT(p2[1]), ScalarT(p2[2])}; + uint16_t attr_cnt; - input.read((char*)&attr_cnt, sizeof(attr_cnt)); + input.read(reinterpret_cast<char*>(&attr_cnt), sizeof(attr_cnt)); } return true; -- GitLab