+ improve ply support

This commit is contained in:
wmayer 2015-09-24 23:19:33 +02:00
parent 8c38e25377
commit 202b51171c

View File

@ -42,8 +42,10 @@
#include <cmath>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace MeshCore;
@ -493,6 +495,18 @@ bool MeshInput::LoadOFF (std::istream &rstrIn)
return true;
}
namespace MeshCore {
struct MeshPly_Property : public std::binary_function<std::pair<std::string, int>,
std::string, bool>
{
bool operator()(const std::pair<std::string, int>& x,
const std::string& y) const
{
return x.first == y;
}
};
}
bool MeshInput::LoadPLY (std::istream &inp)
{
// http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
@ -503,6 +517,11 @@ bool MeshInput::LoadPLY (std::istream &inp)
enum {
ascii, binary_little_endian, binary_big_endian
} format;
enum Number {
int8, uint8, int16, uint16, int32, uint32, float32, float64
};
if (!inp || inp.bad() == true)
return false;
@ -519,10 +538,10 @@ bool MeshInput::LoadPLY (std::istream &inp)
if ((ply[0] != 'p') || (ply[1] != 'l') || (ply[2] != 'y'))
return false; // wrong header
std::vector<int> face_props;
std::vector<std::pair<std::string, Number> > vertex_props;
std::vector<Number> face_props;
std::string line, element;
bool xyz_float=false,xyz_double=false;
int xyz_coords=0;
MeshIO::Binding rgb_value = MeshIO::OVERALL;
while (std::getline(inp, line)) {
std::istringstream str(line);
@ -593,37 +612,86 @@ bool MeshInput::LoadPLY (std::istream &inp)
if (element == "vertex") {
str >> space >> std::ws
>> type >> space >> std::ws >> name >> std::ws;
if (name == "x") {
xyz_coords++;
if (type == "float" || type == "float32")
xyz_float = true;
else if (type == "double" || type == "float64")
xyz_double = true;
Number number;
if (type == "char" || type == "int8") {
number = int8;
}
else if (name == "y") {
xyz_coords++;
else if (type == "uchar" || type == "uint8") {
number = uint8;
}
else if (name == "z") {
xyz_coords++;
else if (type == "short" || type == "int16") {
number = int16;
}
else if (name == "red") {
rgb_value = MeshIO::PER_VERTEX;
if (_material) {
_material->binding = MeshIO::PER_VERTEX;
_material->diffuseColor.reserve(v_count);
}
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.push_back(std::make_pair(name, number));
}
else if (element == "face") {
std::string list, uchr;
str >> space >> std::ws
>> list >> std::ws >> uchr >> std::ws
>> type >> std::ws >> name >> std::ws;
if (name != "vertex_indices") {
if (type == "float" || type == "float32")
face_props.push_back(4);
else if (type == "double" || type == "float64")
face_props.push_back(8);
>> 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);
}
}
}
@ -632,64 +700,121 @@ bool MeshInput::LoadPLY (std::istream &inp)
}
}
// not 3d points
if (xyz_coords != 3)
// check if valid 3d points
MeshPly_Property property;
std::size_t num_x = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "x"));
if (num_x != 1)
return false;
if (format == ascii) {
boost::regex rx_p("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
boost::regex rx_c("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
"\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s*$");
boost::regex rx_f("^\\s*3\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*");
boost::cmatch what;
Base::Vector3f pt;
std::size_t num_y = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "y"));
if (num_y != 1)
return false;
if (rgb_value == MeshIO::PER_VERTEX) {
int r,g,b;
for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) {
if (boost::regex_match(line.c_str(), what, rx_c)) {
pt.x = (float)std::atof(what[1].first);
pt.y = (float)std::atof(what[4].first);
pt.z = (float)std::atof(what[7].first);
meshPoints.push_back(pt);
if (_material) {
r = std::min<int>(std::atoi(what[10].first),255);
g = std::min<int>(std::atoi(what[11].first),255);
b = std::min<int>(std::atoi(what[12].first),255);
float fr = (float)r/255.0f;
float fg = (float)g/255.0f;
float fb = (float)b/255.0f;
_material->diffuseColor.push_back(App::Color(fr, fg, fb));
}
}
else {
std::size_t num_z = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "z"));
if (num_z != 1)
return false;
// check if valid colors are set
std::size_t num_r = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "red"));
std::size_t num_g = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "green"));
std::size_t num_b = std::count_if(vertex_props.begin(), vertex_props.end(),
std::bind2nd(property, "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("^\\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(inp, line); i++) {
// go through the vertex properties
std::map<std::string, float> prop_values;
for (std::vector<std::pair<std::string, Number> >::iterator it = vertex_props.begin(); it != vertex_props.end(); ++it) {
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;
}
}
}
else {
for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) {
if (boost::regex_match(line.c_str(), what, rx_p)) {
pt.x = (float)std::atof(what[1].first);
pt.y = (float)std::atof(what[4].first);
pt.z = (float)std::atof(what[7].first);
meshPoints.push_back(pt);
}
else {
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.push_back(App::Color(r, g, b));
}
}
int f1, f2, f3;
for (std::size_t i = 0; i < f_count && std::getline(inp, line); i++) {
if (boost::regex_search(line.c_str(), what, rx_f)) {
f1 = std::atoi(what[1].first);
f2 = std::atoi(what[2].first);
f3 = std::atoi(what[3].first);
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));
}
}
@ -701,39 +826,71 @@ bool MeshInput::LoadPLY (std::istream &inp)
is.setByteOrder(Base::Stream::LittleEndian);
else
is.setByteOrder(Base::Stream::BigEndian);
int r,g,b;
if (xyz_float) {
for (std::size_t i = 0; i < v_count; i++) {
// go through the vertex properties
std::map<std::string, float> prop_values;
for (std::vector<std::pair<std::string, Number> >::iterator it = vertex_props.begin(); it != vertex_props.end(); ++it) {
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;
for (std::size_t i = 0; i < v_count; i++) {
is >> pt.x >> pt.y >> pt.z;
meshPoints.push_back(pt);
if (rgb_value == MeshIO::PER_VERTEX) {
is >> r >> g >> b;
if (_material) {
float fr = (float)r/255.0f;
float fg = (float)g/255.0f;
float fb = (float)b/255.0f;
_material->diffuseColor.push_back(App::Color(fr, fg, fb));
}
}
}
}
else if (xyz_double) {
Base::Vector3d pt;
for (std::size_t i = 0; i < v_count; i++) {
is >> pt.x >> pt.y >> pt.z;
meshPoints.push_back(Base::Vector3f((float)pt.x,(float)pt.y,(float)pt.z));
if (rgb_value == MeshIO::PER_VERTEX) {
is >> r >> g >> b;
if (_material) {
float fr = (float)r/255.0f;
float fg = (float)g/255.0f;
float fb = (float)b/255.0f;
_material->diffuseColor.push_back(App::Color(fr, fg, fb));
}
}
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.push_back(App::Color(r, g, b));
}
}
unsigned char n;
uint32_t f1, f2, f3;
for (std::size_t i = 0; i < f_count; i++) {
@ -742,18 +899,48 @@ bool MeshInput::LoadPLY (std::istream &inp)
is >> f1 >> f2 >> f3;
if (f1 < v_count && f2 < v_count && f3 < v_count)
meshFacets.push_back(MeshFacet(f1,f2,f3));
for (std::vector<int>::iterator it = face_props.begin(); it != face_props.end(); ++it) {
if (*it == 4) {
is >> n;
float f;
for (unsigned char j=0; j<n; j++)
is >> f;
}
else if (*it == 8) {
is >> n;
double d;
for (unsigned char j=0; j<n; j++)
is >> d;
for (std::vector<Number>::iterator it = face_props.begin(); it != face_props.end(); ++it) {
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;
}
}
}