From 04ac24f41c1828e720e5f5356e08e317427ae351 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 29 Nov 2024 15:04:35 +0100 Subject: [PATCH 1/5] Mesh: move PLY reader to own class --- src/Mod/Mesh/App/CMakeLists.txt | 2 + src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp | 560 +++++++++++++++++++++++++ src/Mod/Mesh/App/Core/IO/ReaderPLY.h | 60 +++ src/Mod/Mesh/App/Core/MeshIO.cpp | 514 +---------------------- 4 files changed, 625 insertions(+), 511 deletions(-) create mode 100644 src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp create mode 100644 src/Mod/Mesh/App/Core/IO/ReaderPLY.h diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt index 6a6ea57ae0..fe1e7a35fc 100644 --- a/src/Mod/Mesh/App/CMakeLists.txt +++ b/src/Mod/Mesh/App/CMakeLists.txt @@ -102,6 +102,8 @@ SET(Core_SRCS Core/IO/Reader3MF.h Core/IO/ReaderOBJ.cpp Core/IO/ReaderOBJ.h + Core/IO/ReaderPLY.cpp + Core/IO/ReaderPLY.h Core/IO/Writer3MF.cpp Core/IO/Writer3MF.h Core/IO/WriterInventor.cpp diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp new file mode 100644 index 0000000000..cc8884a6f3 --- /dev/null +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2024 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#endif + +#include "Core/MeshIO.h" +#include "Core/MeshKernel.h" +#include +#include + +#include "ReaderPLY.h" + + +using namespace MeshCore; + +namespace MeshCore::Ply +{ + +enum Number +{ + int8, + uint8, + int16, + uint16, + int32, + uint32, + float32, + float64 +}; + +struct Property +{ + using first_argument_type = std::pair; + using second_argument_type = std::string; + using result_type = bool; + + bool operator()(const std::pair& x, const std::string& y) const + { + return x.first == y; + } +}; + +} // namespace MeshCore::Ply + +using namespace MeshCore::Ply; + +ReaderPLY::ReaderPLY(MeshKernel& kernel, Material* material) + : _kernel(kernel) + , _material(material) +{} + +bool ReaderPLY::Load(std::istream& input) +{ + // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ + std::size_t v_count = 0, f_count = 0; + MeshPointArray meshPoints; + MeshFacetArray meshFacets; + + enum + { + unknown, + ascii, + binary_little_endian, + binary_big_endian + } format = unknown; + + if (!input || input.bad()) { + return false; + } + + std::streambuf* buf = input.rdbuf(); + if (!buf) { + return false; + } + + // read in the first three characters + char ply[3]; + input.read(ply, 3); + input.ignore(1); + if (!input) { + return false; + } + if ((ply[0] != 'p') || (ply[1] != 'l') || (ply[2] != 'y')) { + return false; // wrong header + } + + std::vector> vertex_props; + std::vector face_props; + std::string line, element; + + MeshIO::Binding rgb_value = MeshIO::OVERALL; + while (std::getline(input, line)) { + std::istringstream str(line); + str.unsetf(std::ios_base::skipws); + str >> std::ws; + if (str.eof()) { + continue; // empty line + } + std::string kw; + str >> kw; + if (kw == "format") { + std::string format_string, version; + char space_format_string {}, space_format_version {}; + str >> space_format_string >> std::ws >> format_string >> space_format_version + >> std::ws >> version; + if (/*!str || !str.eof() ||*/ + !std::isspace(space_format_string) || !std::isspace(space_format_version)) { + return false; + } + if (format_string == "ascii") { + format = ascii; + } + else if (format_string == "binary_big_endian") { + format = binary_big_endian; + } + else if (format_string == "binary_little_endian") { + format = binary_little_endian; + } + else { + // wrong format version + return false; + } + if (version != "1.0") { + // wrong version + return false; + } + } + else if (kw == "element") { + std::string name; + std::size_t count {}; + char space_element_name {}, space_name_count {}; + str >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count; + if (/*!str || !str.eof() ||*/ + !std::isspace(space_element_name) || !std::isspace(space_name_count)) { + return false; + } + if (name == "vertex") { + element = name; + v_count = count; + meshPoints.reserve(count); + } + else if (name == "face") { + element = name; + f_count = count; + meshFacets.reserve(count); + } + else { + element.clear(); + } + } + else if (kw == "property") { + std::string type, name; + char space {}; + if (element == "vertex") { + str >> space >> std::ws >> type >> space >> std::ws >> name >> std::ws; + + Ply::Number number {}; + if (type == "char" || type == "int8") { + number = int8; + } + else if (type == "uchar" || type == "uint8") { + number = uint8; + } + else if (type == "short" || type == "int16") { + number = int16; + } + else if (type == "ushort" || type == "uint16") { + number = uint16; + } + else if (type == "int" || type == "int32") { + number = int32; + } + else if (type == "uint" || type == "uint32") { + number = uint32; + } + else if (type == "float" || type == "float32") { + number = float32; + } + else if (type == "double" || type == "float64") { + number = float64; + } + else { + // no valid number type + return false; + } + + // store the property name and type + vertex_props.emplace_back(name, number); + } + else if (element == "face") { + std::string list, uchr; + str >> space >> std::ws >> list >> std::ws; + if (list == "list") { + str >> uchr >> std::ws >> type >> std::ws >> name >> std::ws; + } + else { + // not a 'list' + type = list; + str >> name; + } + if (name != "vertex_indices" && name != "vertex_index") { + Number number {}; + if (type == "char" || type == "int8") { + number = int8; + } + else if (type == "uchar" || type == "uint8") { + number = uint8; + } + else if (type == "short" || type == "int16") { + number = int16; + } + else if (type == "ushort" || type == "uint16") { + number = uint16; + } + else if (type == "int" || type == "int32") { + number = int32; + } + else if (type == "uint" || type == "uint32") { + number = uint32; + } + else if (type == "float" || type == "float32") { + number = float32; + } + else if (type == "double" || type == "float64") { + number = float64; + } + else { + // no valid number type + return false; + } + + // store the property name and type + face_props.push_back(number); + } + } + } + else if (kw == "end_header") { + break; // end of the header, now read the data + } + } + + // check if valid 3d points + Property property; + std::size_t num_x = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "x"); + }); + if (num_x != 1) { + return false; + } + + std::size_t num_y = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "y"); + }); + if (num_y != 1) { + return false; + } + + std::size_t num_z = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "z"); + }); + if (num_z != 1) { + return false; + } + + for (auto& it : vertex_props) { + if (it.first == "diffuse_red") { + it.first = "red"; + } + else if (it.first == "diffuse_green") { + it.first = "green"; + } + else if (it.first == "diffuse_blue") { + it.first = "blue"; + } + } + + // check if valid colors are set + std::size_t num_r = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "red"); + }); + std::size_t num_g = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "green"); + }); + std::size_t num_b = std::count_if(vertex_props.begin(), + vertex_props.end(), + [&property](const std::pair& p) { + return property(p, "blue"); + }); + std::size_t rgb_colors = num_r + num_g + num_b; + if (rgb_colors != 0 && rgb_colors != 3) { + return false; + } + + // only if set per vertex + if (rgb_colors == 3) { + rgb_value = MeshIO::PER_VERTEX; + if (_material) { + _material->binding = MeshIO::PER_VERTEX; + _material->diffuseColor.reserve(v_count); + } + } + + if (format == ascii) { + boost::regex rx_d("(([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?))\\s*"); + boost::regex rx_s("\\b([-+]?[0-9]+)\\s*"); + boost::regex rx_u("\\b([0-9]+)\\s*"); + boost::regex rx_f(R"(^\s*3\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*)"); + boost::smatch what; + + for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { + // go through the vertex properties + std::map prop_values; + for (const auto& it : vertex_props) { + switch (it.second) { + case int8: + case int16: + case int32: { + if (boost::regex_search(line, what, rx_s)) { + int v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + case uint8: + case uint16: + case uint32: { + if (boost::regex_search(line, what, rx_u)) { + int v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + case float32: + case float64: { + if (boost::regex_search(line, what, rx_d)) { + double v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + default: + return false; + } + } + + Base::Vector3f pt; + pt.x = (prop_values["x"]); + pt.y = (prop_values["y"]); + pt.z = (prop_values["z"]); + meshPoints.push_back(pt); + + if (_material && (rgb_value == MeshIO::PER_VERTEX)) { + float r = (prop_values["red"]) / 255.0F; + float g = (prop_values["green"]) / 255.0F; + float b = (prop_values["blue"]) / 255.0F; + _material->diffuseColor.emplace_back(r, g, b); + } + } + + int f1 {}, f2 {}, f3 {}; + for (std::size_t i = 0; i < f_count && std::getline(input, line); i++) { + if (boost::regex_search(line, what, rx_f)) { + f1 = boost::lexical_cast(what[1]); + f2 = boost::lexical_cast(what[2]); + f3 = boost::lexical_cast(what[3]); + meshFacets.push_back(MeshFacet(f1, f2, f3)); + } + } + } + // binary + else { + Base::InputStream is(input); + if (format == binary_little_endian) { + is.setByteOrder(Base::Stream::LittleEndian); + } + else { + is.setByteOrder(Base::Stream::BigEndian); + } + + for (std::size_t i = 0; i < v_count; i++) { + // go through the vertex properties + std::map prop_values; + for (const auto& it : vertex_props) { + switch (it.second) { + case int8: { + int8_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint8: { + uint8_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case int16: { + int16_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint16: { + uint16_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case int32: { + int32_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint32: { + uint32_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case float32: { + float v {}; + is >> v; + prop_values[it.first] = v; + } break; + case float64: { + double v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + default: + return false; + } + } + + Base::Vector3f pt; + pt.x = (prop_values["x"]); + pt.y = (prop_values["y"]); + pt.z = (prop_values["z"]); + meshPoints.push_back(pt); + + if (_material && (rgb_value == MeshIO::PER_VERTEX)) { + float r = (prop_values["red"]) / 255.0F; + float g = (prop_values["green"]) / 255.0F; + float b = (prop_values["blue"]) / 255.0F; + _material->diffuseColor.emplace_back(r, g, b); + } + } + + unsigned char n {}; + uint32_t f1 {}, f2 {}, f3 {}; + for (std::size_t i = 0; i < f_count; i++) { + is >> n; + if (n == 3) { + is >> f1 >> f2 >> f3; + if (f1 < v_count && f2 < v_count && f3 < v_count) { + meshFacets.push_back(MeshFacet(f1, f2, f3)); + } + for (auto it : face_props) { + switch (it) { + case int8: { + int8_t v {}; + is >> v; + } break; + case uint8: { + uint8_t v {}; + is >> v; + } break; + case int16: { + int16_t v {}; + is >> v; + } break; + case uint16: { + uint16_t v {}; + is >> v; + } break; + case int32: { + int32_t v {}; + is >> v; + } break; + case uint32: { + uint32_t v {}; + is >> v; + } break; + case float32: { + is >> n; + float v {}; + for (unsigned char j = 0; j < n; j++) { + is >> v; + } + } break; + case float64: { + is >> n; + double v {}; + for (unsigned char j = 0; j < n; j++) { + is >> v; + } + } break; + default: + return false; + } + } + } + } + } + + _kernel.Clear(); // remove all data before + + MeshCleanup meshCleanup(meshPoints, meshFacets); + if (_material) { + meshCleanup.SetMaterial(_material); + } + meshCleanup.RemoveInvalids(); + MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets); + meshAdj.SetFacetNeighbourhood(); + _kernel.Adopt(meshPoints, meshFacets); + + return true; +} diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.h b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h new file mode 100644 index 0000000000..4478a27213 --- /dev/null +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2024 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + + +#ifndef MESH_IO_READER_PLY_H +#define MESH_IO_READER_PLY_H + +#include +#include +#include + +namespace MeshCore +{ + +class MeshKernel; +struct Material; + +/** Loads the mesh object from data in PLY format. */ +class MeshExport ReaderPLY +{ +public: + /*! + * \brief ReaderPLY + */ + explicit ReaderPLY(MeshKernel& kernel, Material*); + /*! + * \brief Load the mesh from the input stream + * \return true on success and false otherwise + */ + bool Load(std::istream& input); + +private: + MeshKernel& _kernel; + Material* _material; +}; + +} // namespace MeshCore + + +#endif // MESH_IO_READER_PLY_H diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index ba855663bc..8e6af13c64 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -38,6 +38,7 @@ #include "IO/Reader3MF.h" #include "IO/ReaderOBJ.h" +#include "IO/ReaderPLY.h" #include "IO/Writer3MF.h" #include "IO/WriterInventor.h" #include "IO/WriterOBJ.h" @@ -657,519 +658,10 @@ bool MeshInput::LoadOFF(std::istream& input) return true; } -namespace MeshCore -{ -namespace Ply -{ -enum Number -{ - int8, - uint8, - int16, - uint16, - int32, - uint32, - float32, - float64 -}; -struct Property -{ - using first_argument_type = std::pair; - using second_argument_type = std::string; - using result_type = bool; - - bool operator()(const std::pair& x, const std::string& y) const - { - return x.first == y; - } -}; -} // namespace Ply -using namespace Ply; -} // namespace MeshCore - bool MeshInput::LoadPLY(std::istream& input) { - // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ - std::size_t v_count = 0, f_count = 0; - MeshPointArray meshPoints; - MeshFacetArray meshFacets; - - enum - { - unknown, - ascii, - binary_little_endian, - binary_big_endian - } format = unknown; - - if (!input || input.bad()) { - return false; - } - - std::streambuf* buf = input.rdbuf(); - if (!buf) { - return false; - } - - // read in the first three characters - char ply[3]; - input.read(ply, 3); - input.ignore(1); - if (!input) { - return false; - } - if ((ply[0] != 'p') || (ply[1] != 'l') || (ply[2] != 'y')) { - return false; // wrong header - } - - std::vector> vertex_props; - std::vector face_props; - std::string line, element; - - MeshIO::Binding rgb_value = MeshIO::OVERALL; - while (std::getline(input, line)) { - std::istringstream str(line); - str.unsetf(std::ios_base::skipws); - str >> std::ws; - if (str.eof()) { - continue; // empty line - } - std::string kw; - str >> kw; - if (kw == "format") { - std::string format_string, version; - char space_format_string {}, space_format_version {}; - str >> space_format_string >> std::ws >> format_string >> space_format_version - >> std::ws >> version; - if (/*!str || !str.eof() ||*/ - !std::isspace(space_format_string) || !std::isspace(space_format_version)) { - return false; - } - if (format_string == "ascii") { - format = ascii; - } - else if (format_string == "binary_big_endian") { - format = binary_big_endian; - } - else if (format_string == "binary_little_endian") { - format = binary_little_endian; - } - else { - // wrong format version - return false; - } - if (version != "1.0") { - // wrong version - return false; - } - } - else if (kw == "element") { - std::string name; - std::size_t count {}; - char space_element_name {}, space_name_count {}; - str >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count; - if (/*!str || !str.eof() ||*/ - !std::isspace(space_element_name) || !std::isspace(space_name_count)) { - return false; - } - if (name == "vertex") { - element = name; - v_count = count; - meshPoints.reserve(count); - } - else if (name == "face") { - element = name; - f_count = count; - meshFacets.reserve(count); - } - else { - element.clear(); - } - } - else if (kw == "property") { - std::string type, name; - char space {}; - if (element == "vertex") { - str >> space >> std::ws >> type >> space >> std::ws >> name >> std::ws; - - Ply::Number number {}; - if (type == "char" || type == "int8") { - number = int8; - } - else if (type == "uchar" || type == "uint8") { - number = uint8; - } - else if (type == "short" || type == "int16") { - number = int16; - } - else if (type == "ushort" || type == "uint16") { - number = uint16; - } - else if (type == "int" || type == "int32") { - number = int32; - } - else if (type == "uint" || type == "uint32") { - number = uint32; - } - else if (type == "float" || type == "float32") { - number = float32; - } - else if (type == "double" || type == "float64") { - number = float64; - } - else { - // no valid number type - return false; - } - - // store the property name and type - vertex_props.emplace_back(name, number); - } - else if (element == "face") { - std::string list, uchr; - str >> space >> std::ws >> list >> std::ws; - if (list == "list") { - str >> uchr >> std::ws >> type >> std::ws >> name >> std::ws; - } - else { - // not a 'list' - type = list; - str >> name; - } - if (name != "vertex_indices" && name != "vertex_index") { - Number number {}; - if (type == "char" || type == "int8") { - number = int8; - } - else if (type == "uchar" || type == "uint8") { - number = uint8; - } - else if (type == "short" || type == "int16") { - number = int16; - } - else if (type == "ushort" || type == "uint16") { - number = uint16; - } - else if (type == "int" || type == "int32") { - number = int32; - } - else if (type == "uint" || type == "uint32") { - number = uint32; - } - else if (type == "float" || type == "float32") { - number = float32; - } - else if (type == "double" || type == "float64") { - number = float64; - } - else { - // no valid number type - return false; - } - - // store the property name and type - face_props.push_back(number); - } - } - } - else if (kw == "end_header") { - break; // end of the header, now read the data - } - } - - // check if valid 3d points - Property property; - std::size_t num_x = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "x"); - }); - if (num_x != 1) { - return false; - } - - std::size_t num_y = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "y"); - }); - if (num_y != 1) { - return false; - } - - std::size_t num_z = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "z"); - }); - if (num_z != 1) { - return false; - } - - for (auto& it : vertex_props) { - if (it.first == "diffuse_red") { - it.first = "red"; - } - else if (it.first == "diffuse_green") { - it.first = "green"; - } - else if (it.first == "diffuse_blue") { - it.first = "blue"; - } - } - - // check if valid colors are set - std::size_t num_r = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "red"); - }); - std::size_t num_g = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "green"); - }); - std::size_t num_b = std::count_if(vertex_props.begin(), - vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "blue"); - }); - std::size_t rgb_colors = num_r + num_g + num_b; - if (rgb_colors != 0 && rgb_colors != 3) { - return false; - } - - // only if set per vertex - if (rgb_colors == 3) { - rgb_value = MeshIO::PER_VERTEX; - if (_material) { - _material->binding = MeshIO::PER_VERTEX; - _material->diffuseColor.reserve(v_count); - } - } - - if (format == ascii) { - boost::regex rx_d("(([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?))\\s*"); - boost::regex rx_s("\\b([-+]?[0-9]+)\\s*"); - boost::regex rx_u("\\b([0-9]+)\\s*"); - boost::regex rx_f(R"(^\s*3\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*)"); - boost::smatch what; - - for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { - // go through the vertex properties - std::map prop_values; - for (const auto& it : vertex_props) { - switch (it.second) { - case int8: - case int16: - case int32: { - if (boost::regex_search(line, what, rx_s)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - case uint8: - case uint16: - case uint32: { - if (boost::regex_search(line, what, rx_u)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - case float32: - case float64: { - if (boost::regex_search(line, what, rx_d)) { - double v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - default: - return false; - } - } - - Base::Vector3f pt; - pt.x = (prop_values["x"]); - pt.y = (prop_values["y"]); - pt.z = (prop_values["z"]); - meshPoints.push_back(pt); - - if (_material && (rgb_value == MeshIO::PER_VERTEX)) { - float r = (prop_values["red"]) / 255.0F; - float g = (prop_values["green"]) / 255.0F; - float b = (prop_values["blue"]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } - } - - int f1 {}, f2 {}, f3 {}; - for (std::size_t i = 0; i < f_count && std::getline(input, line); i++) { - if (boost::regex_search(line, what, rx_f)) { - f1 = boost::lexical_cast(what[1]); - f2 = boost::lexical_cast(what[2]); - f3 = boost::lexical_cast(what[3]); - meshFacets.push_back(MeshFacet(f1, f2, f3)); - } - } - } - // binary - else { - Base::InputStream is(input); - if (format == binary_little_endian) { - is.setByteOrder(Base::Stream::LittleEndian); - } - else { - is.setByteOrder(Base::Stream::BigEndian); - } - - for (std::size_t i = 0; i < v_count; i++) { - // go through the vertex properties - std::map prop_values; - for (const auto& it : vertex_props) { - switch (it.second) { - case int8: { - int8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint8: { - uint8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case int16: { - int16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint16: { - uint16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case int32: { - int32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint32: { - uint32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case float32: { - float v {}; - is >> v; - prop_values[it.first] = v; - } break; - case float64: { - double v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - default: - return false; - } - } - - Base::Vector3f pt; - pt.x = (prop_values["x"]); - pt.y = (prop_values["y"]); - pt.z = (prop_values["z"]); - meshPoints.push_back(pt); - - if (_material && (rgb_value == MeshIO::PER_VERTEX)) { - float r = (prop_values["red"]) / 255.0F; - float g = (prop_values["green"]) / 255.0F; - float b = (prop_values["blue"]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } - } - - unsigned char n {}; - uint32_t f1 {}, f2 {}, f3 {}; - for (std::size_t i = 0; i < f_count; i++) { - is >> n; - if (n == 3) { - is >> f1 >> f2 >> f3; - if (f1 < v_count && f2 < v_count && f3 < v_count) { - meshFacets.push_back(MeshFacet(f1, f2, f3)); - } - for (auto it : face_props) { - switch (it) { - case int8: { - int8_t v {}; - is >> v; - } break; - case uint8: { - uint8_t v {}; - is >> v; - } break; - case int16: { - int16_t v {}; - is >> v; - } break; - case uint16: { - uint16_t v {}; - is >> v; - } break; - case int32: { - int32_t v {}; - is >> v; - } break; - case uint32: { - uint32_t v {}; - is >> v; - } break; - case float32: { - is >> n; - float v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; - } - } break; - case float64: { - is >> n; - double v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; - } - } break; - default: - return false; - } - } - } - } - } - - this->_rclMesh.Clear(); // remove all data before - - MeshCleanup meshCleanup(meshPoints, meshFacets); - if (_material) { - meshCleanup.SetMaterial(_material); - } - meshCleanup.RemoveInvalids(); - MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets); - meshAdj.SetFacetNeighbourhood(); - this->_rclMesh.Adopt(meshPoints, meshFacets); - - return true; + ReaderPLY reader(this->_rclMesh, this->_material); + return reader.Load(input); } bool MeshInput::LoadMeshNode(std::istream& input) From 94fbf2d28c304a87ea4a1baa304f106a08970c66 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 29 Nov 2024 17:19:12 +0100 Subject: [PATCH 2/5] Mesh: Refactor ReaderPLY --- src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp | 884 ++++++++++++++----------- src/Mod/Mesh/App/Core/IO/ReaderPLY.h | 67 +- 2 files changed, 555 insertions(+), 396 deletions(-) diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp index cc8884a6f3..abc61b1da1 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp @@ -38,57 +38,14 @@ using namespace MeshCore; -namespace MeshCore::Ply -{ - -enum Number -{ - int8, - uint8, - int16, - uint16, - int32, - uint32, - float32, - float64 -}; - -struct Property -{ - using first_argument_type = std::pair; - using second_argument_type = std::string; - using result_type = bool; - - bool operator()(const std::pair& x, const std::string& y) const - { - return x.first == y; - } -}; - -} // namespace MeshCore::Ply - -using namespace MeshCore::Ply; - +// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ ReaderPLY::ReaderPLY(MeshKernel& kernel, Material* material) : _kernel(kernel) , _material(material) {} -bool ReaderPLY::Load(std::istream& input) +bool ReaderPLY::CheckHeader(std::istream& input) const { - // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ - std::size_t v_count = 0, f_count = 0; - MeshPointArray meshPoints; - MeshFacetArray meshFacets; - - enum - { - unknown, - ascii, - binary_little_endian, - binary_big_endian - } format = unknown; - if (!input || input.bad()) { return false; } @@ -99,21 +56,189 @@ bool ReaderPLY::Load(std::istream& input) } // read in the first three characters - char ply[3]; - input.read(ply, 3); + std::array ply {}; + input.read(ply.data(), ply.size()); input.ignore(1); if (!input) { return false; } - if ((ply[0] != 'p') || (ply[1] != 'l') || (ply[2] != 'y')) { - return false; // wrong header + + return ((ply[0] == 'p') && (ply[1] == 'l') && (ply[2] == 'y')); +} + +bool ReaderPLY::ReadFormat(std::istream& str) +{ + std::string format_string; + std::string version; + char space_format_string {}; + char space_format_version {}; + str >> space_format_string >> std::ws >> format_string >> space_format_version >> std::ws + >> version; + if (!std::isspace(space_format_string) || !std::isspace(space_format_version)) { + return false; + } + if (format_string == "ascii") { + format = ascii; + } + else if (format_string == "binary_big_endian") { + format = binary_big_endian; + } + else if (format_string == "binary_little_endian") { + format = binary_little_endian; + } + else { + // wrong format version + return false; } - std::vector> vertex_props; - std::vector face_props; - std::string line, element; + return (version == "1.0"); +} - MeshIO::Binding rgb_value = MeshIO::OVERALL; +bool ReaderPLY::ReadElement(std::istream& str, std::string& element) +{ + std::string name; + std::size_t count {}; + char space_element_name {}; + char space_name_count {}; + str >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count; + if (!std::isspace(space_element_name) || !std::isspace(space_name_count)) { + return false; + } + if (name == "vertex") { + element = name; + v_count = count; + meshPoints.reserve(count); + } + else if (name == "face") { + element = name; + f_count = count; + meshFacets.reserve(count); + } + else { + element.clear(); + } + + return true; +} + +bool ReaderPLY::ReadVertexProperty(std::istream& str) +{ + std::string type; + std::string name; + char space {}; + str >> space >> std::ws >> type >> space >> std::ws >> name >> std::ws; + + Number number {}; + if (type == "char" || type == "int8") { + number = int8; + } + else if (type == "uchar" || type == "uint8") { + number = uint8; + } + else if (type == "short" || type == "int16") { + number = int16; + } + else if (type == "ushort" || type == "uint16") { + number = uint16; + } + else if (type == "int" || type == "int32") { + number = int32; + } + else if (type == "uint" || type == "uint32") { + number = uint32; + } + else if (type == "float" || type == "float32") { + number = float32; + } + else if (type == "double" || type == "float64") { + number = float64; + } + else { + // no valid number type + return false; + } + + // store the property name and type + vertex_props.emplace_back(name, number); + + return true; +} + +bool ReaderPLY::ReadFaceProperty(std::istream& str) +{ + std::string type; + std::string name; + char space {}; + + std::string list; + std::string uchr; + + str >> space >> std::ws >> list >> std::ws; + if (list == "list") { + str >> uchr >> std::ws >> type >> std::ws >> name >> std::ws; + } + else { + // not a 'list' + type = list; + str >> name; + } + if (name != "vertex_indices" && name != "vertex_index") { + Number number {}; + if (type == "char" || type == "int8") { + number = int8; + } + else if (type == "uchar" || type == "uint8") { + number = uint8; + } + else if (type == "short" || type == "int16") { + number = int16; + } + else if (type == "ushort" || type == "uint16") { + number = uint16; + } + else if (type == "int" || type == "int32") { + number = int32; + } + else if (type == "uint" || type == "uint32") { + number = uint32; + } + else if (type == "float" || type == "float32") { + number = float32; + } + else if (type == "double" || type == "float64") { + number = float64; + } + else { + // no valid number type + return false; + } + + // store the property name and type + face_props.push_back(number); + } + return true; +} + +bool ReaderPLY::ReadProperty(std::istream& str, const std::string& element) +{ + if (element == "vertex") { + if (!ReadVertexProperty(str)) { + return false; + } + } + else if (element == "face") { + if (!ReadFaceProperty(str)) { + return false; + } + } + + return true; +} + +bool ReaderPLY::ReadHeader(std::istream& input) +{ + std::string line; + std::string element; while (std::getline(input, line)) { std::istringstream str(line); str.unsetf(std::ios_base::skipws); @@ -124,139 +249,18 @@ bool ReaderPLY::Load(std::istream& input) std::string kw; str >> kw; if (kw == "format") { - std::string format_string, version; - char space_format_string {}, space_format_version {}; - str >> space_format_string >> std::ws >> format_string >> space_format_version - >> std::ws >> version; - if (/*!str || !str.eof() ||*/ - !std::isspace(space_format_string) || !std::isspace(space_format_version)) { - return false; - } - if (format_string == "ascii") { - format = ascii; - } - else if (format_string == "binary_big_endian") { - format = binary_big_endian; - } - else if (format_string == "binary_little_endian") { - format = binary_little_endian; - } - else { - // wrong format version - return false; - } - if (version != "1.0") { - // wrong version + if (!ReadFormat(str)) { return false; } } else if (kw == "element") { - std::string name; - std::size_t count {}; - char space_element_name {}, space_name_count {}; - str >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count; - if (/*!str || !str.eof() ||*/ - !std::isspace(space_element_name) || !std::isspace(space_name_count)) { + if (!ReadElement(str, element)) { return false; } - if (name == "vertex") { - element = name; - v_count = count; - meshPoints.reserve(count); - } - else if (name == "face") { - element = name; - f_count = count; - meshFacets.reserve(count); - } - else { - element.clear(); - } } else if (kw == "property") { - std::string type, name; - char space {}; - if (element == "vertex") { - str >> space >> std::ws >> type >> space >> std::ws >> name >> std::ws; - - Ply::Number number {}; - if (type == "char" || type == "int8") { - number = int8; - } - else if (type == "uchar" || type == "uint8") { - number = uint8; - } - else if (type == "short" || type == "int16") { - number = int16; - } - else if (type == "ushort" || type == "uint16") { - number = uint16; - } - else if (type == "int" || type == "int32") { - number = int32; - } - else if (type == "uint" || type == "uint32") { - number = uint32; - } - else if (type == "float" || type == "float32") { - number = float32; - } - else if (type == "double" || type == "float64") { - number = float64; - } - else { - // no valid number type - return false; - } - - // store the property name and type - vertex_props.emplace_back(name, number); - } - else if (element == "face") { - std::string list, uchr; - str >> space >> std::ws >> list >> std::ws; - if (list == "list") { - str >> uchr >> std::ws >> type >> std::ws >> name >> std::ws; - } - else { - // not a 'list' - type = list; - str >> name; - } - if (name != "vertex_indices" && name != "vertex_index") { - Number number {}; - if (type == "char" || type == "int8") { - number = int8; - } - else if (type == "uchar" || type == "uint8") { - number = uint8; - } - else if (type == "short" || type == "int16") { - number = int16; - } - else if (type == "ushort" || type == "uint16") { - number = uint16; - } - else if (type == "int" || type == "int32") { - number = int32; - } - else if (type == "uint" || type == "uint32") { - number = uint32; - } - else if (type == "float" || type == "float32") { - number = float32; - } - else if (type == "double" || type == "float64") { - number = float64; - } - else { - // no valid number type - return false; - } - - // store the property name and type - face_props.push_back(number); - } + if (!ReadProperty(str, element)) { + return false; } } else if (kw == "end_header") { @@ -264,6 +268,11 @@ bool ReaderPLY::Load(std::istream& input) } } + return true; +} + +bool ReaderPLY::VerifyVertexProperty() +{ // check if valid 3d points Property property; std::size_t num_x = std::count_if(vertex_props.begin(), @@ -271,28 +280,24 @@ bool ReaderPLY::Load(std::istream& input) [&property](const std::pair& p) { return property(p, "x"); }); - if (num_x != 1) { - return false; - } std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(), [&property](const std::pair& p) { return property(p, "y"); }); - if (num_y != 1) { - return false; - } std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(), [&property](const std::pair& p) { return property(p, "z"); }); - if (num_z != 1) { - return false; - } + return ((num_x == 1) && (num_y == 1) && (num_z == 1)); +} + +bool ReaderPLY::VerifyColorProperty() +{ for (auto& it : vertex_props) { if (it.first == "diffuse_red") { it.first = "red"; @@ -306,21 +311,25 @@ bool ReaderPLY::Load(std::istream& input) } // check if valid colors are set + Property property; std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(), [&property](const std::pair& p) { return property(p, "red"); }); + std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(), [&property](const std::pair& p) { return property(p, "green"); }); + std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(), [&property](const std::pair& p) { return property(p, "blue"); }); + std::size_t rgb_colors = num_r + num_g + num_b; if (rgb_colors != 0 && rgb_colors != 3) { return false; @@ -328,223 +337,41 @@ bool ReaderPLY::Load(std::istream& input) // only if set per vertex if (rgb_colors == 3) { - rgb_value = MeshIO::PER_VERTEX; if (_material) { _material->binding = MeshIO::PER_VERTEX; _material->diffuseColor.reserve(v_count); } } - if (format == ascii) { - boost::regex rx_d("(([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?))\\s*"); - boost::regex rx_s("\\b([-+]?[0-9]+)\\s*"); - boost::regex rx_u("\\b([0-9]+)\\s*"); - boost::regex rx_f(R"(^\s*3\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*)"); - boost::smatch what; + return true; +} - for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { - // go through the vertex properties - std::map prop_values; - for (const auto& it : vertex_props) { - switch (it.second) { - case int8: - case int16: - case int32: { - if (boost::regex_search(line, what, rx_s)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - case uint8: - case uint16: - case uint32: { - if (boost::regex_search(line, what, rx_u)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - case float32: - case float64: { - if (boost::regex_search(line, what, rx_d)) { - double v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } - } break; - default: - return false; - } - } - - Base::Vector3f pt; - pt.x = (prop_values["x"]); - pt.y = (prop_values["y"]); - pt.z = (prop_values["z"]); - meshPoints.push_back(pt); - - if (_material && (rgb_value == MeshIO::PER_VERTEX)) { - float r = (prop_values["red"]) / 255.0F; - float g = (prop_values["green"]) / 255.0F; - float b = (prop_values["blue"]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } - } - - int f1 {}, f2 {}, f3 {}; - for (std::size_t i = 0; i < f_count && std::getline(input, line); i++) { - if (boost::regex_search(line, what, rx_f)) { - f1 = boost::lexical_cast(what[1]); - f2 = boost::lexical_cast(what[2]); - f3 = boost::lexical_cast(what[3]); - meshFacets.push_back(MeshFacet(f1, f2, f3)); - } - } - } - // binary - else { - Base::InputStream is(input); - if (format == binary_little_endian) { - is.setByteOrder(Base::Stream::LittleEndian); - } - else { - is.setByteOrder(Base::Stream::BigEndian); - } - - for (std::size_t i = 0; i < v_count; i++) { - // go through the vertex properties - std::map prop_values; - for (const auto& it : vertex_props) { - switch (it.second) { - case int8: { - int8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint8: { - uint8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case int16: { - int16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint16: { - uint16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case int32: { - int32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case uint32: { - uint32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - case float32: { - float v {}; - is >> v; - prop_values[it.first] = v; - } break; - case float64: { - double v {}; - is >> v; - prop_values[it.first] = static_cast(v); - } break; - default: - return false; - } - } - - Base::Vector3f pt; - pt.x = (prop_values["x"]); - pt.y = (prop_values["y"]); - pt.z = (prop_values["z"]); - meshPoints.push_back(pt); - - if (_material && (rgb_value == MeshIO::PER_VERTEX)) { - float r = (prop_values["red"]) / 255.0F; - float g = (prop_values["green"]) / 255.0F; - float b = (prop_values["blue"]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } - } - - unsigned char n {}; - uint32_t f1 {}, f2 {}, f3 {}; - for (std::size_t i = 0; i < f_count; i++) { - is >> n; - if (n == 3) { - is >> f1 >> f2 >> f3; - if (f1 < v_count && f2 < v_count && f3 < v_count) { - meshFacets.push_back(MeshFacet(f1, f2, f3)); - } - for (auto it : face_props) { - switch (it) { - case int8: { - int8_t v {}; - is >> v; - } break; - case uint8: { - uint8_t v {}; - is >> v; - } break; - case int16: { - int16_t v {}; - is >> v; - } break; - case uint16: { - uint16_t v {}; - is >> v; - } break; - case int32: { - int32_t v {}; - is >> v; - } break; - case uint32: { - uint32_t v {}; - is >> v; - } break; - case float32: { - is >> n; - float v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; - } - } break; - case float64: { - is >> n; - double v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; - } - } break; - default: - return false; - } - } - } - } +bool ReaderPLY::Load(std::istream& input) +{ + if (!CheckHeader(input)) { + return false; } + if (!ReadHeader(input)) { + return false; + } + + if (!VerifyVertexProperty()) { + return false; + } + + if (!VerifyColorProperty()) { + return false; + } + + // clang-format off + return format == ascii ? LoadAscii(input) + : LoadBinary(input); + // clang-format on +} + +void ReaderPLY::CleanupMesh() +{ _kernel.Clear(); // remove all data before MeshCleanup meshCleanup(meshPoints, meshFacets); @@ -555,6 +382,273 @@ bool ReaderPLY::Load(std::istream& input) MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets); meshAdj.SetFacetNeighbourhood(); _kernel.Adopt(meshPoints, meshFacets); +} + +bool ReaderPLY::ReadVertexes(std::istream& input) +{ + boost::regex rx_d("(([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?))\\s*"); + boost::regex rx_s("\\b([-+]?[0-9]+)\\s*"); + boost::regex rx_u("\\b([0-9]+)\\s*"); + + boost::smatch what; + std::string line; + + for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { + // go through the vertex properties + std::map prop_values; + for (const auto& it : vertex_props) { + switch (it.second) { + case int8: + case int16: + case int32: { + if (boost::regex_search(line, what, rx_s)) { + int v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + case uint8: + case uint16: + case uint32: { + if (boost::regex_search(line, what, rx_u)) { + int v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + case float32: + case float64: { + if (boost::regex_search(line, what, rx_d)) { + double v {}; + v = boost::lexical_cast(what[1]); + prop_values[it.first] = static_cast(v); + line = line.substr(what[0].length()); + } + else { + return false; + } + } break; + default: + return false; + } + } + + Base::Vector3f pt; + pt.x = (prop_values["x"]); + pt.y = (prop_values["y"]); + pt.z = (prop_values["z"]); + meshPoints.push_back(pt); + + if (_material && _material->binding == MeshIO::PER_VERTEX) { + float r = (prop_values["red"]) / 255.0F; + float g = (prop_values["green"]) / 255.0F; + float b = (prop_values["blue"]) / 255.0F; + _material->diffuseColor.emplace_back(r, g, b); + } + } return true; } + +bool ReaderPLY::ReadFaces(std::istream& input) +{ + boost::regex rx_f(R"(^\s*3\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*)"); + boost::smatch what; + std::string line; + + for (std::size_t i = 0; i < f_count && std::getline(input, line); i++) { + if (boost::regex_search(line, what, rx_f)) { + int f1 {}; + int f2 {}; + int f3 {}; + f1 = boost::lexical_cast(what[1]); + f2 = boost::lexical_cast(what[2]); + f3 = boost::lexical_cast(what[3]); + meshFacets.push_back(MeshFacet(f1, f2, f3)); + } + } + + return true; +} + +bool ReaderPLY::LoadAscii(std::istream& input) +{ + if (!ReadVertexes(input)) { + return false; + } + + if (!ReadFaces(input)) { + return false; + } + + CleanupMesh(); + return true; +} + +bool ReaderPLY::ReadVertexes(Base::InputStream& is) +{ + std::string prop_x = "x"; + std::string prop_y = "y"; + std::string prop_z = "z"; + std::string prop_r = "red"; + std::string prop_g = "gree"; + std::string prop_b = "blue"; + for (std::size_t i = 0; i < v_count; i++) { + // go through the vertex properties + std::map prop_values; + for (const auto& it : vertex_props) { + switch (it.second) { + case int8: { + int8_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint8: { + uint8_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case int16: { + int16_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint16: { + uint16_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case int32: { + int32_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case uint32: { + uint32_t v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + case float32: { + float v {}; + is >> v; + prop_values[it.first] = v; + } break; + case float64: { + double v {}; + is >> v; + prop_values[it.first] = static_cast(v); + } break; + default: + return false; + } + } + + Base::Vector3f pt; + pt.x = (prop_values[prop_x]); + pt.y = (prop_values[prop_y]); + pt.z = (prop_values[prop_z]); + meshPoints.push_back(pt); + + if (_material && _material->binding == MeshIO::PER_VERTEX) { + float r = (prop_values[prop_r]) / 255.0F; + float g = (prop_values[prop_g]) / 255.0F; + float b = (prop_values[prop_b]) / 255.0F; + _material->diffuseColor.emplace_back(r, g, b); + } + } + + return true; +} + +bool ReaderPLY::ReadFaces(Base::InputStream& is) +{ + unsigned char n {}; + uint32_t f1 {}; + uint32_t f2 {}; + uint32_t f3 {}; + for (std::size_t i = 0; i < f_count; i++) { + is >> n; + if (n == 3) { + is >> f1 >> f2 >> f3; + if (f1 < v_count && f2 < v_count && f3 < v_count) { + meshFacets.push_back(MeshFacet(f1, f2, f3)); + } + for (auto it : face_props) { + switch (it) { + case int8: { + int8_t v {}; + is >> v; + } break; + case uint8: { + uint8_t v {}; + is >> v; + } break; + case int16: { + int16_t v {}; + is >> v; + } break; + case uint16: { + uint16_t v {}; + is >> v; + } break; + case int32: { + int32_t v {}; + is >> v; + } break; + case uint32: { + uint32_t v {}; + is >> v; + } break; + case float32: { + is >> n; + float v {}; + for (unsigned char j = 0; j < n; j++) { + is >> v; + } + } break; + case float64: { + is >> n; + double v {}; + for (unsigned char j = 0; j < n; j++) { + is >> v; + } + } break; + default: + return false; + } + } + } + } + + return true; +} + +bool ReaderPLY::LoadBinary(std::istream& input) +{ + Base::InputStream is(input); + if (format == binary_little_endian) { + is.setByteOrder(Base::Stream::LittleEndian); + } + else { + is.setByteOrder(Base::Stream::BigEndian); + } + + if (!ReadVertexes(is)) { + return false; + } + + if (!ReadFaces(is)) { + return false; + } + + CleanupMesh(); + return true; +} diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.h b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h index 4478a27213..fceb08e210 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.h +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h @@ -29,6 +29,11 @@ #include #include +namespace Base +{ +class InputStream; +} + namespace MeshCore { @@ -42,7 +47,7 @@ public: /*! * \brief ReaderPLY */ - explicit ReaderPLY(MeshKernel& kernel, Material*); + explicit ReaderPLY(MeshKernel& kernel, Material* = nullptr); /*! * \brief Load the mesh from the input stream * \return true on success and false otherwise @@ -50,6 +55,66 @@ public: bool Load(std::istream& input); private: + bool CheckHeader(std::istream& input) const; + bool ReadHeader(std::istream& input); + bool VerifyVertexProperty(); + bool VerifyColorProperty(); + bool ReadFormat(std::istream& str); + bool ReadElement(std::istream& str, std::string& element); + bool ReadProperty(std::istream& str, const std::string& element); + bool ReadVertexProperty(std::istream& str); + bool ReadFaceProperty(std::istream& str); + bool ReadVertexes(std::istream& input); + bool ReadFaces(std::istream& input); + bool ReadVertexes(Base::InputStream& is); + bool ReadFaces(Base::InputStream& is); + bool LoadAscii(std::istream& input); + bool LoadBinary(std::istream& input); + void CleanupMesh(); + +private: + struct Property + { + using argument_type_1st = std::pair; + using argument_type_2nd = std::string; + using result_type = bool; + + // clang-format off + bool operator()(const argument_type_1st& x, + const argument_type_2nd& y) const + { + return x.first == y; + } + // clang-format on + }; + + enum Number + { + int8, + uint8, + int16, + uint16, + int32, + uint32, + float32, + float64 + }; + + enum Format + { + unknown, + ascii, + binary_little_endian, + binary_big_endian + } format = unknown; + + std::vector> vertex_props; + std::vector face_props; + + std::size_t v_count = 0; + std::size_t f_count = 0; + MeshPointArray meshPoints; + MeshFacetArray meshFacets; MeshKernel& _kernel; Material* _material; }; From 10dc08acb4d137b6b4080a9476f036e33508d340 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 29 Nov 2024 18:50:11 +0100 Subject: [PATCH 3/5] Mesh: Reduce time of importing binary PLY files by around 60 percent --- src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp | 120 +++++++++++++------------ src/Mod/Mesh/App/Core/IO/ReaderPLY.h | 42 ++++++--- 2 files changed, 90 insertions(+), 72 deletions(-) diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp index abc61b1da1..ff29c4e4d2 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp @@ -121,6 +121,30 @@ bool ReaderPLY::ReadElement(std::istream& str, std::string& element) return true; } +ReaderPLY::Property ReaderPLY::propertyOfName(const std::string& name) +{ + if (name == "x") { + return coord_x; + } + if (name == "y") { + return coord_y; + } + if (name == "z") { + return coord_z; + } + if (name == "red" || name == "diffuse_red") { + return color_r; + } + if (name == "green" || name == "diffuse_green") { + return color_g; + } + if (name == "blue" || name == "diffuse_blue") { + return color_b; + } + + return generic; +} + bool ReaderPLY::ReadVertexProperty(std::istream& str) { std::string type; @@ -159,7 +183,7 @@ bool ReaderPLY::ReadVertexProperty(std::istream& str) } // store the property name and type - vertex_props.emplace_back(name, number); + vertex_props.emplace_back(propertyOfName(name), number); return true; } @@ -274,23 +298,23 @@ bool ReaderPLY::ReadHeader(std::istream& input) bool ReaderPLY::VerifyVertexProperty() { // check if valid 3d points - Property property; + PropertyComp property; std::size_t num_x = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "x"); + [&property](const std::pair& p) { + return property(p, coord_x); }); std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "y"); + [&property](const std::pair& p) { + return property(p, coord_y); }); std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "z"); + [&property](const std::pair& p) { + return property(p, coord_z); }); return ((num_x == 1) && (num_y == 1) && (num_z == 1)); @@ -298,36 +322,24 @@ bool ReaderPLY::VerifyVertexProperty() bool ReaderPLY::VerifyColorProperty() { - for (auto& it : vertex_props) { - if (it.first == "diffuse_red") { - it.first = "red"; - } - else if (it.first == "diffuse_green") { - it.first = "green"; - } - else if (it.first == "diffuse_blue") { - it.first = "blue"; - } - } - // check if valid colors are set - Property property; + PropertyComp property; std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "red"); + [&property](const std::pair& p) { + return property(p, color_r); }); std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "green"); + [&property](const std::pair& p) { + return property(p, color_g); }); std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, "blue"); + [&property](const std::pair& p) { + return property(p, color_b); }); std::size_t rgb_colors = num_r + num_g + num_b; @@ -395,7 +407,7 @@ bool ReaderPLY::ReadVertexes(std::istream& input) for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { // go through the vertex properties - std::map prop_values; + PropertyArray prop_values {}; for (const auto& it : vertex_props) { switch (it.second) { case int8: @@ -441,18 +453,7 @@ bool ReaderPLY::ReadVertexes(std::istream& input) } } - Base::Vector3f pt; - pt.x = (prop_values["x"]); - pt.y = (prop_values["y"]); - pt.z = (prop_values["z"]); - meshPoints.push_back(pt); - - if (_material && _material->binding == MeshIO::PER_VERTEX) { - float r = (prop_values["red"]) / 255.0F; - float g = (prop_values["green"]) / 255.0F; - float b = (prop_values["blue"]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } + addVertexProperty(prop_values); } return true; @@ -493,17 +494,29 @@ bool ReaderPLY::LoadAscii(std::istream& input) return true; } +void ReaderPLY::addVertexProperty(const PropertyArray& prop) +{ + Base::Vector3f pt; + pt.x = (prop[coord_x]); + pt.y = (prop[coord_y]); + pt.z = (prop[coord_z]); + meshPoints.push_back(pt); + + if (_material && _material->binding == MeshIO::PER_VERTEX) { + // NOLINTBEGIN + float r = (prop[color_r]) / 255.0F; + float g = (prop[color_g]) / 255.0F; + float b = (prop[color_b]) / 255.0F; + // NOLINTEND + _material->diffuseColor.emplace_back(r, g, b); + } +} + bool ReaderPLY::ReadVertexes(Base::InputStream& is) { - std::string prop_x = "x"; - std::string prop_y = "y"; - std::string prop_z = "z"; - std::string prop_r = "red"; - std::string prop_g = "gree"; - std::string prop_b = "blue"; for (std::size_t i = 0; i < v_count; i++) { // go through the vertex properties - std::map prop_values; + PropertyArray prop_values {}; for (const auto& it : vertex_props) { switch (it.second) { case int8: { @@ -551,18 +564,7 @@ bool ReaderPLY::ReadVertexes(Base::InputStream& is) } } - Base::Vector3f pt; - pt.x = (prop_values[prop_x]); - pt.y = (prop_values[prop_y]); - pt.z = (prop_values[prop_z]); - meshPoints.push_back(pt); - - if (_material && _material->binding == MeshIO::PER_VERTEX) { - float r = (prop_values[prop_r]) / 255.0F; - float g = (prop_values[prop_g]) / 255.0F; - float b = (prop_values[prop_b]) / 255.0F; - _material->diffuseColor.emplace_back(r, g, b); - } + addVertexProperty(prop_values); } return true; diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.h b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h index fceb08e210..e4ca967ace 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.h +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.h @@ -73,21 +73,22 @@ private: void CleanupMesh(); private: - struct Property + enum Property { - using argument_type_1st = std::pair; - using argument_type_2nd = std::string; - using result_type = bool; - - // clang-format off - bool operator()(const argument_type_1st& x, - const argument_type_2nd& y) const - { - return x.first == y; - } - // clang-format on + coord_x, + coord_y, + coord_z, + color_r, + color_g, + color_b, + generic, + num_props }; + static Property propertyOfName(const std::string& name); + using PropertyArray = std::array; + void addVertexProperty(const PropertyArray& prop); + enum Number { int8, @@ -100,6 +101,21 @@ private: float64 }; + struct PropertyComp + { + using argument_type_1st = std::pair; + using argument_type_2nd = Property; + using result_type = bool; + + // clang-format off + bool operator()(const argument_type_1st& x, + const argument_type_2nd& y) const + { + return x.first == y; + } + // clang-format on + }; + enum Format { unknown, @@ -108,7 +124,7 @@ private: binary_big_endian } format = unknown; - std::vector> vertex_props; + std::vector> vertex_props; std::vector face_props; std::size_t v_count = 0; From 4440dd7aaf36d8ae4ef40c2d7a1deea551e0337e Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 29 Nov 2024 20:58:24 +0100 Subject: [PATCH 4/5] Mesh: Reduce time of importing ASCII PLY files by around 85 percent --- src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp | 88 ++++++++++++-------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp index ff29c4e4d2..1ab1537a73 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp @@ -24,7 +24,6 @@ #include "PreCompiled.h" #ifndef _PreComp_ #include -#include #include #endif @@ -398,59 +397,49 @@ void ReaderPLY::CleanupMesh() bool ReaderPLY::ReadVertexes(std::istream& input) { - boost::regex rx_d("(([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?))\\s*"); - boost::regex rx_s("\\b([-+]?[0-9]+)\\s*"); - boost::regex rx_u("\\b([0-9]+)\\s*"); - - boost::smatch what; std::string line; - for (std::size_t i = 0; i < v_count && std::getline(input, line); i++) { + std::istringstream str(line); + str.unsetf(std::ios_base::skipws); + str >> std::ws; + // go through the vertex properties PropertyArray prop_values {}; + std::size_t count_props = vertex_props.size(); for (const auto& it : vertex_props) { switch (it.second) { case int8: case int16: case int32: { - if (boost::regex_search(line, what, rx_s)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } + int v {}; + str >> v >> std::ws; + prop_values[it.first] = static_cast(v); } break; case uint8: case uint16: case uint32: { - if (boost::regex_search(line, what, rx_u)) { - int v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } + unsigned int v {}; + str >> v >> std::ws; + prop_values[it.first] = static_cast(v); + } break; + case float32: { + float v {}; + str >> v >> std::ws; + prop_values[it.first] = v; } break; - case float32: case float64: { - if (boost::regex_search(line, what, rx_d)) { - double v {}; - v = boost::lexical_cast(what[1]); - prop_values[it.first] = static_cast(v); - line = line.substr(what[0].length()); - } - else { - return false; - } + double v {}; + str >> v >> std::ws; + prop_values[it.first] = static_cast(v); } break; default: return false; } + + // does line contain all properties + if (--count_props > 0 && str.eof()) { + return false; + } } addVertexProperty(prop_values); @@ -461,20 +450,27 @@ bool ReaderPLY::ReadVertexes(std::istream& input) bool ReaderPLY::ReadFaces(std::istream& input) { - boost::regex rx_f(R"(^\s*3\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*)"); - boost::smatch what; + constexpr const std::size_t count_props = 4; std::string line; - for (std::size_t i = 0; i < f_count && std::getline(input, line); i++) { - if (boost::regex_search(line, what, rx_f)) { - int f1 {}; - int f2 {}; - int f3 {}; - f1 = boost::lexical_cast(what[1]); - f2 = boost::lexical_cast(what[2]); - f3 = boost::lexical_cast(what[3]); - meshFacets.push_back(MeshFacet(f1, f2, f3)); + std::istringstream str(line); + str.unsetf(std::ios_base::skipws); + str >> std::ws; + + std::array v_indices {}; + std::size_t index = count_props; + for (int& v : v_indices) { + str >> v >> std::ws; + if (--index > 0 && str.eof()) { + return false; + } } + + if (v_indices[0] != 3) { + return false; + } + + meshFacets.push_back(MeshFacet(v_indices[1], v_indices[2], v_indices[3])); } return true; From 9e021b7f6a5d31826510db8209b811199a0b328d Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 7 Dec 2024 13:17:53 +0100 Subject: [PATCH 5/5] Mesh: Fix linter warnings --- src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp | 162 +++++++++++++------------ 1 file changed, 87 insertions(+), 75 deletions(-) diff --git a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp index 1ab1537a73..084132421c 100644 --- a/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp +++ b/src/Mod/Mesh/App/Core/IO/ReaderPLY.cpp @@ -73,9 +73,14 @@ bool ReaderPLY::ReadFormat(std::istream& str) char space_format_version {}; str >> space_format_string >> std::ws >> format_string >> space_format_version >> std::ws >> version; - if (!std::isspace(space_format_string) || !std::isspace(space_format_version)) { + + // clang-format off + if (std::isspace(static_cast(space_format_string)) == 0 || + std::isspace(static_cast(space_format_version)) == 0) { return false; } + // clang-format on + if (format_string == "ascii") { format = ascii; } @@ -100,9 +105,14 @@ bool ReaderPLY::ReadElement(std::istream& str, std::string& element) char space_element_name {}; char space_name_count {}; str >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count; - if (!std::isspace(space_element_name) || !std::isspace(space_name_count)) { + + // clang-format off + if (std::isspace(static_cast(space_element_name)) == 0 || + std::isspace(static_cast(space_name_count)) == 0) { return false; } + // clang-format on + if (name == "vertex") { element = name; v_count = count; @@ -300,20 +310,20 @@ bool ReaderPLY::VerifyVertexProperty() PropertyComp property; std::size_t num_x = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, coord_x); + [&property](const std::pair& prop) { + return property(prop, coord_x); }); std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, coord_y); + [&property](const std::pair& prop) { + return property(prop, coord_y); }); std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, coord_z); + [&property](const std::pair& prop) { + return property(prop, coord_z); }); return ((num_x == 1) && (num_y == 1) && (num_z == 1)); @@ -325,20 +335,20 @@ bool ReaderPLY::VerifyColorProperty() PropertyComp property; std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, color_r); + [&property](const std::pair& prop) { + return property(prop, color_r); }); std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, color_g); + [&property](const std::pair& prop) { + return property(prop, color_g); }); std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(), - [&property](const std::pair& p) { - return property(p, color_b); + [&property](const std::pair& prop) { + return property(prop, color_b); }); std::size_t rgb_colors = num_r + num_g + num_b; @@ -411,26 +421,26 @@ bool ReaderPLY::ReadVertexes(std::istream& input) case int8: case int16: case int32: { - int v {}; - str >> v >> std::ws; - prop_values[it.first] = static_cast(v); + int vt {}; + str >> vt >> std::ws; + prop_values[it.first] = static_cast(vt); } break; case uint8: case uint16: case uint32: { - unsigned int v {}; - str >> v >> std::ws; - prop_values[it.first] = static_cast(v); + unsigned int vt {}; + str >> vt >> std::ws; + prop_values[it.first] = static_cast(vt); } break; case float32: { - float v {}; - str >> v >> std::ws; - prop_values[it.first] = v; + float vt {}; + str >> vt >> std::ws; + prop_values[it.first] = vt; } break; case float64: { - double v {}; - str >> v >> std::ws; - prop_values[it.first] = static_cast(v); + double vt {}; + str >> vt >> std::ws; + prop_values[it.first] = static_cast(vt); } break; default: return false; @@ -459,8 +469,8 @@ bool ReaderPLY::ReadFaces(std::istream& input) std::array v_indices {}; std::size_t index = count_props; - for (int& v : v_indices) { - str >> v >> std::ws; + for (int& vt : v_indices) { + str >> vt >> std::ws; if (--index > 0 && str.eof()) { return false; } @@ -516,44 +526,44 @@ bool ReaderPLY::ReadVertexes(Base::InputStream& is) for (const auto& it : vertex_props) { switch (it.second) { case int8: { - int8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + int8_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case uint8: { - uint8_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + uint8_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case int16: { - int16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + int16_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case uint16: { - uint16_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + uint16_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case int32: { - int32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + int32_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case uint32: { - uint32_t v {}; - is >> v; - prop_values[it.first] = static_cast(v); + uint32_t vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; case float32: { - float v {}; - is >> v; - prop_values[it.first] = v; + float vt {}; + is >> vt; + prop_values[it.first] = vt; } break; case float64: { - double v {}; - is >> v; - prop_values[it.first] = static_cast(v); + double vt {}; + is >> vt; + prop_values[it.first] = static_cast(vt); } break; default: return false; @@ -568,13 +578,13 @@ bool ReaderPLY::ReadVertexes(Base::InputStream& is) bool ReaderPLY::ReadFaces(Base::InputStream& is) { - unsigned char n {}; + unsigned char num {}; uint32_t f1 {}; uint32_t f2 {}; uint32_t f3 {}; for (std::size_t i = 0; i < f_count; i++) { - is >> n; - if (n == 3) { + is >> num; + if (num == 3) { is >> f1 >> f2 >> f3; if (f1 < v_count && f2 < v_count && f3 < v_count) { meshFacets.push_back(MeshFacet(f1, f2, f3)); @@ -582,41 +592,43 @@ bool ReaderPLY::ReadFaces(Base::InputStream& is) for (auto it : face_props) { switch (it) { case int8: { - int8_t v {}; - is >> v; + int8_t vt {}; + is >> vt; } break; case uint8: { - uint8_t v {}; - is >> v; + uint8_t vt {}; + is >> vt; } break; case int16: { - int16_t v {}; - is >> v; + int16_t vt {}; + is >> vt; } break; case uint16: { - uint16_t v {}; - is >> v; + uint16_t vt {}; + is >> vt; } break; case int32: { - int32_t v {}; - is >> v; + int32_t vt {}; + is >> vt; } break; case uint32: { - uint32_t v {}; - is >> v; + uint32_t vt {}; + is >> vt; } break; case float32: { - is >> n; - float v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; + unsigned char cnt {}; + is >> cnt; + float vt {}; + for (unsigned char j = 0; j < cnt; j++) { + is >> vt; } } break; case float64: { - is >> n; - double v {}; - for (unsigned char j = 0; j < n; j++) { - is >> v; + unsigned char cnt {}; + is >> cnt; + double vt {}; + for (unsigned char j = 0; j < cnt; j++) { + is >> vt; } } break; default: