Mesh: Refactor ReaderPLY

This commit is contained in:
wmayer
2024-11-29 17:19:12 +01:00
parent 439abaf81f
commit 2437cd6de0
2 changed files with 555 additions and 396 deletions

View File

@@ -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<std::string, int>;
using second_argument_type = std::string;
using result_type = bool;
bool operator()(const std::pair<std::string, int>& 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<char, 3> 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<std::pair<std::string, Ply::Number>> vertex_props;
std::vector<Ply::Number> 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<std::string, int>& 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<std::string, int>& 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<std::string, int>& 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<std::string, int>& p) {
return property(p, "red");
});
std::size_t num_g = std::count_if(vertex_props.begin(),
vertex_props.end(),
[&property](const std::pair<std::string, int>& p) {
return property(p, "green");
});
std::size_t num_b = std::count_if(vertex_props.begin(),
vertex_props.end(),
[&property](const std::pair<std::string, int>& 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<std::string, float> 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<int>(what[1]);
prop_values[it.first] = static_cast<float>(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<int>(what[1]);
prop_values[it.first] = static_cast<float>(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<double>(what[1]);
prop_values[it.first] = static_cast<float>(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<int>(what[1]);
f2 = boost::lexical_cast<int>(what[2]);
f3 = boost::lexical_cast<int>(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<std::string, float> prop_values;
for (const auto& it : vertex_props) {
switch (it.second) {
case int8: {
int8_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint8: {
uint8_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case int16: {
int16_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint16: {
uint16_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case int32: {
int32_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint32: {
uint32_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(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<float>(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<std::string, float> 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<int>(what[1]);
prop_values[it.first] = static_cast<float>(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<int>(what[1]);
prop_values[it.first] = static_cast<float>(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<double>(what[1]);
prop_values[it.first] = static_cast<float>(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<int>(what[1]);
f2 = boost::lexical_cast<int>(what[2]);
f3 = boost::lexical_cast<int>(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<std::string, float> prop_values;
for (const auto& it : vertex_props) {
switch (it.second) {
case int8: {
int8_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint8: {
uint8_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case int16: {
int16_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint16: {
uint16_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case int32: {
int32_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(v);
} break;
case uint32: {
uint32_t v {};
is >> v;
prop_values[it.first] = static_cast<float>(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<float>(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;
}

View File

@@ -29,6 +29,11 @@
#include <Mod/Mesh/MeshGlobal.h>
#include <iosfwd>
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<std::string, int>;
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<std::pair<std::string, Number>> vertex_props;
std::vector<Number> face_props;
std::size_t v_count = 0;
std::size_t f_count = 0;
MeshPointArray meshPoints;
MeshFacetArray meshFacets;
MeshKernel& _kernel;
Material* _material;
};