Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
Signed-off-by: Ken Museth <[email protected]>
  • Loading branch information
kmuseth committed Nov 24, 2024
1 parent 932e65a commit 9aba3d1
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 150 deletions.
196 changes: 46 additions & 150 deletions openvdb_cmd/vdb_tool/include/Geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,10 @@ void Geometry::readPLY(std::istream &is)
return 0;
};

// check header
if (!test(0, {"ply"})) error("vdb_tool::readPLY: not a ply file");

// check file format
int format = -1;// 0 is ascii, 1 is little endian and 2 is big endian
tokens = tokenize_line();
if (!(test(0, {"format"}) && test(2, {"1.0"})) ) {
Expand All @@ -663,77 +666,34 @@ void Geometry::readPLY(std::istream &is)
}
const bool reverseBytes = format && format != (isLittleEndian() ? 1 : 2);
// header: https://www.mathworks.com/help/vision/ug/the-ply-format.html
size_t vtxCount = 0, polyCount = 0, sizeOfVertex = 0, vertexStride=0;
struct Triplet {int offset, id, size; } xyz[3];// byte offset, id, size
struct Skip {int count, bytes;} vtx_skip[2]={{0,0},{0,0}}, ply_skip[2]={{0,0},{0,0}};// head, {x,y,z}, tail
size_t vtxCount = 0, faceCount = 0;
int vtxStride=0, vtxProps=0;// byte size of all vtx properties, number of vertex properties
struct Triplet {int offset, id, size;} xyz[3];// byte offset, id#, byte size
struct Skip {int count, bytes;} faceSkip[2]={{0,0},{0,0}};// head, {faces}, tail
tokens = tokenize_line();
bool run = true;
while(run) {
if ( test(0, {"element"}) ) {
if ( test(1, {"vertex"}) ) {
vtxCount = std::stoll(tokens[2]);
int offset = 0, count = 0;
int n = 0;
const std::string axis[3] = {"x", "y", "z"};
while(true) {
const int m = n>0 ? 1 : 0;// indicates before and after vertices
tokens = tokenize_line();
if ( test(0, {"end_header"}) ) {
run = false;
break;
} else if ( test(0, {"element"}) ) {
break;
} else if ( test(0, {"property"}) ) {
#ifdef MY_CLEAN_VERSION
Triplet t{offset, count++, sizeOf(1)};
Triplet t{vtxStride, vtxProps++, sizeOf(1)};
for (int i=0; i<3; ++i) if (test(2, {axis[i]})) xyz[i] = t;
vertexStride = (offset += t.size);
vtxStride += t.size;
}
}
for (int i=0; i<3; ++i) if (xyz[i].size!=4 && xyz[i].size!=8) error("vdb_tool::readPLY: missing "+axis[i]+
" vertex coordinates or unsupported size "+std::to_string(xyz[i].size));
#else
if ( test(1, {"float", "float32"}) ) {
if ( test(2, {"x", "y", "z"}) ) {// vertex coordinates
if (sizeOfVertex == sizeof(double)) error("vdb_tool::readPLY: mixed float and double precision of vertices is not allowed");
sizeOfVertex = sizeof(float);
if (n>2 || !test(2, {axis[n++]}) ) error("vdb_tool::readPLY: expected x or y or z");
} else {// e.g. nx, ny, nz, intensity, s, t etc
if (n!=0 && n!=3) error("vdb_tool::readPLY: vertex float property interlaced with coordinates");
vtx_skip[m].count += 1;
vtx_skip[m].bytes += static_cast<int>(sizeof(float));
}
} else if ( test(1, {"double", "float64"}) ) {
if ( test(2, {"x", "y", "z"}) ) {// vertex coordinates
if (sizeOfVertex == sizeof(float)) error("vdb_tool::readPLY: mixed float and double precision of vertices is not allowed");
sizeOfVertex = sizeof(double);
if (n>2 || !test(2, {axis[n++]}) ) error("vdb_tool::readPLY: expected x or y or z");
} else {// e.g. nx, ny, nz, intensity, s, t etc
if (n!=0 && n!=3) error("vdb_tool::readPLY: vertex float property interlaced with coordinates");
vtx_skip[m].count += 1;
vtx_skip[m].bytes += static_cast<int>(sizeof(double));
}
} else if ( test(1, {"int16", "uint16"}) ) {// e.g. material_index etc
if (n!=0 && n!=3) error("vdb_tool::readPLY: vertex int16 property interlaced with coordinates is not supported");
vtx_skip[m].count += 1;
vtx_skip[m].bytes += static_cast<int>(sizeof(int16_t));
} else if ( test(1, {"int", "int32"}) ) {// e.g. material_index etc
if (n!=0 && n!=3) error("vdb_tool::readPLY: vertex int32 property interlaced with coordinates is not supported");
vtx_skip[m].count += 1;
vtx_skip[m].bytes += static_cast<int>(sizeof(int32_t));
} else if ( test(1, {"uchar", "int8"}) ) {// eg red, green, blue, alpha
if (n!=0 && n!=3) error("vdb_tool::readPLY: vertex int8 property interlaced with coordinates is not supported");
vtx_skip[m].count += 1;
vtx_skip[m].bytes += static_cast<int>(sizeof(unsigned char));
} else {
error("vdb_tool::readPLY: invalid vertex property");
}
}
}
if (n!=3) error("vdb_tool::readPLY: missing vertex coordinates");
#endif
} else if ( test(1, {"face"}) ) {
polyCount = std::stoll(tokens[2]);
faceCount = std::stoll(tokens[2]);
int n = 0;
while (true) {
tokens = tokenize_line();
Expand All @@ -743,14 +703,14 @@ void Geometry::readPLY(std::istream &is)
} else if (test(0, {"element"}) ) {
break;
} else if (test(0, {"property"}) ) {
if (test(1, {"list"}) &&
test(2, {"uchar", "uint8"}) &&
test(3, {"int", "uint", "int32"}) &&
if (test(1, {"list"}) &&// list of vertex ID belonging to a polygon
test(2, {"uchar", "uint8"}) &&// size of polygon, e.g. 3 or 4
test(3, {"int", "uint", "int32"}) &&// type of vertex id
test(4, {"vertex_index", "vertex_indices"}) ) {
n = 1;
} else if ( test(1, {"uchar", "uint8"}) ) {
ply_skip[n].count += 1;
ply_skip[n].bytes += 1;
faceSkip[n].count += 1;
faceSkip[n].bytes += 1;
} else {
error("vdb_tool::readPLY: invalid face properties");
}
Expand Down Expand Up @@ -779,133 +739,69 @@ void Geometry::readPLY(std::istream &is)
// read vertex coordinates
mVtx.resize(vtxCount);
if (format) {// binary
#ifdef MY_CLEAN_VERSION
if (xyz[0].offset==0 && xyz[1].offset==4 && xyz[2].offset==8 && vertexStride==12) {
if (xyz[0].offset==0 && xyz[1].offset==4 && xyz[2].offset==8 && vtxStride==12) {// most common case
is.read((char *)(mVtx.data()), vtxCount * 3 * sizeof(float));
if (reverseBytes) for (Vec3f &v : mVtx) swapBytes(&v[0], 3);
} else {
char *buffer = static_cast<char*>(std::malloc(vtxCount*vertexStride)), *p=buffer;// uninitialized
char *buffer = static_cast<char*>(std::malloc(vtxCount*vtxStride)), *p = buffer;// uninitialized
if (buffer==nullptr) throw std::invalid_argument("Geometry::readPLY: failed to allocate buffer");
is.read(buffer, vtxCount*vertexStride);
is.read(buffer, vtxCount*vtxStride);
for (Vec3f &vtx : mVtx) {
for (int i=0; i<3; ++i) {
float* v = (float*)(p + xyz[i].offset);
vtx[i] = (xyz[i].size == 4) ? *v : float(*(double*)(v));
}
p += vertexStride;
}
std::free(buffer);
}
#else
if (vtx_skip[0].count == 0 && vtx_skip[1].count == 0) {//faster
if (sizeOfVertex == sizeof(float)) {
is.read((char *)(mVtx.data()), vtxCount * 3 * sizeof(float));
} else if (sizeOfVertex == sizeof(double)) {
double *buffer = new double[vtxCount * 3], *ptr = buffer;
if (buffer==nullptr) throw std::invalid_argument("Geometry::readPLY: failed to allocate double buffer");
is.read((char *)(buffer), vtxCount * 3 * sizeof(double));
for (size_t i=0; i<vtxCount; ++i) {
mVtx[i][0] = float(*ptr++);
mVtx[i][1] = float(*ptr++);
mVtx[i][2] = float(*ptr++);
if (xyz[i].size == 4) {
float v = *(float*)(p + xyz[i].offset);
vtx[i] = reverseBytes ? swapBytes(v) : v;
} else {
double v = *(double*)(p + xyz[i].offset);
vtx[i] = float(reverseBytes ? swapBytes(v) : v);
}
}
std::cout << "Geometry::readPLY: Warning, vertex coordinates in binary ply file were stored in double but got converted to float\n";
delete [] buffer;
} else throw std::invalid_argument("Geometry::readPLY: expected float or double precision vertex coordinates");
} else {
const size_t bSize = vtx_skip[0].bytes + 3*sizeOfVertex + vtx_skip[1].bytes;
char *buffer = static_cast<char*>(std::malloc(vtxCount*bSize));// uninitialized
if (buffer==nullptr) throw std::invalid_argument("Geometry::readPLY: failed to allocate buffer");
is.read(buffer, vtxCount*bSize);
for (size_t i=0; i<vtxCount; ++i) {
if (sizeOfVertex == sizeof(float)) {
const float *p = reinterpret_cast<const float*>(buffer + i*bSize + vtx_skip[0].bytes);
mVtx[i] = Vec3f(p);
} else if (sizeOfVertex == sizeof(double)) {
const double *p = reinterpret_cast<const double*>(buffer + i*bSize + vtx_skip[0].bytes);
mVtx[i] = Vec3f(float(p[0]), float(p[1]), float(p[2]));
} else throw std::invalid_argument("Geometry::readPLY: expected float or double precision vertex coordinates");
p += vtxStride;
}
std::cout << "Geometry::readPLY: Warning, vertex coordinates in binary ply file were stored in double but got converted to float\n";
std::free(buffer);
}
#endif
if (reverseBytes) {
auto flipBytes = [](float v)->float{
float tmp;
char *p = (char*)&v, *q = (char*)&tmp;
q[0] = p[3];
q[1] = p[2];
q[2] = p[1];
q[3] = p[0];
return tmp;
};// flipBytes in float
for (size_t i = 0; i < mVtx.size(); ++i) {
auto &p = mVtx[i];
p[0] = flipBytes(p[0]);
p[1] = flipBytes(p[1]);
p[2] = flipBytes(p[2]);
}
}
} else {// ascii

} else {// ascii vertices
for (auto &v : mVtx) {
tokens = tokenize_line();
if (static_cast<int>(tokens.size()) != vtx_skip[0].count + 3 + vtx_skip[1].count) {
error("vdb_tool::readPLY: error reading ascii vertex coordinates");
}
for (int i = 0; i<3; ++i) {
v[i] = std::stof(tokens[i + vtx_skip[0].count]);
}
if (int(tokens.size()) != vtxProps) error("vdb_tool::readPLY: error reading ascii vertex coordinates");
for (int i = 0; i<3; ++i) v[i] = std::stof(tokens[xyz[0].id]);
}// loop over vertices
}

// read polygon vertex lists
uint32_t vtx[4];
if (format) {// binary
auto flipBytes = [&](int n){
uint32_t tmp;
char *q = (char*)&tmp;
for (int i=0; i<n; ++i) {
char *p = (char*)(vtx+i);
q[0] = p[3];
q[1] = p[2];
q[2] = p[1];
q[3] = p[0];
vtx[i] = tmp;
}
};// flipBytes in uint32_t
char *buffer = static_cast<char*>(std::malloc(ply_skip[0].bytes + 1));// uninitialized
char *buffer = static_cast<char*>(std::malloc(faceSkip[0].bytes + 1));// uninitialized
if (buffer==nullptr) throw std::invalid_argument("Geometry::readPLY: failed to allocate buffer");
for (size_t i=0; i<polyCount; ++i) {
is.read(buffer, ply_skip[0].bytes + 1);
const unsigned int n = (unsigned int)buffer[ply_skip[0].bytes];
for (size_t i=0; i<faceCount; ++i) {
is.read(buffer, faceSkip[0].bytes + 1);// polygon size is encoded as a single char
const unsigned int n = (unsigned int)buffer[faceSkip[0].bytes];// char -> unsigned int
switch (n) {
case 3:
is.read((char *)(&vtx), 3*sizeof(uint32_t));
if (reverseBytes) flipBytes(3);
is.read((char*)vtx, 3*sizeof(uint32_t));
if (reverseBytes) swapBytes(vtx, 3);
mTri.emplace_back(vtx);
break;
case 4:
is.read((char *)(&vtx), 4*sizeof(uint32_t));
if (reverseBytes) flipBytes(4);
is.read((char*)vtx, 4*sizeof(uint32_t));
if (reverseBytes) swapBytes(vtx, 4);
mQuad.emplace_back(vtx);
break;
default:
throw std::invalid_argument("Geometry::readPLY: binary " + std::to_string(n) + "-gons are not supported");
break;
}
is.ignore(ply_skip[1].bytes);
is.ignore(faceSkip[1].bytes);
}// loop over polygons
std::free(buffer);
} else {// ascii format
for (size_t i=0; i<polyCount; ++i) {
} else {// ascii format faces
for (size_t i=0; i<faceCount; ++i) {
tokens = tokenize_line();
const int n = std::stoi(tokens[ply_skip[0].count]);
if (n!=3 && n!=4) {
throw std::invalid_argument("Geometry::readPLY: ascii " + std::to_string(n)+"-gons are not supported");
}
for (int i = 0; i<n; ++i) {
vtx[i] = static_cast<uint32_t>(std::stoll(tokens[i + 1 + ply_skip[0].count]));
}
const std::string polySize = tokens[faceSkip[0].count];
const int n = std::stoi(polySize);
if (n!=3 && n!=4) throw std::invalid_argument("Geometry::readPLY: ascii " + polySize + "-gons are not supported");
for (int i = 0, j=1+faceSkip[0].count; i<n; ++i, ++j) vtx[i] = static_cast<uint32_t>(std::stoll(tokens[j]));
if (n==3) {
mTri.emplace_back(vtx);
} else {
Expand Down
28 changes: 28 additions & 0 deletions openvdb_cmd/vdb_tool/include/Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,34 @@ inline bool isLittleEndian()
return (*(char *)&tmp == 1);
}

/// @brief invert endianess of a type
/// @tparam T Template type to be inverted
/// @param val value to be inverted
/// @return value with reverse bytes
template <typename T>
inline T swapBytes(T val)
{
T tmp;
char *src=(char*)&val, *dst=(char*)(&tmp) + sizeof(T) - 1, *end=src + sizeof(T);
while (src != end) *dst-- = *src++;
return tmp;
}

/// @brief invert endianess of an array of values of a specific type
/// @tparam T Template type to be inverted
/// @param val pointer to array with values to be inverted
/// @param n number of elements in the array
template <typename T>
inline void swapBytes(T *val, int n)
{
T tmp, *stop = val + n;
while(val < stop) {
char *src=(char*)val, *dst=(char*)(&tmp) + sizeof(T) - 1, *end=src + sizeof(T);
while (src != end) *dst-- = *src++;
*val++ = tmp;
}
}

/// @brief return a pseudo random uuid string.
///
/// @details this function approximates a uuid version 4, variant 1 as detailed
Expand Down
46 changes: 46 additions & 0 deletions openvdb_cmd/vdb_tool/src/unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,52 @@ TEST_F(Test_vdb_tool, Util)
}
EXPECT_EQ(size, tmp.size());
}

{//swapBytes
const int i = 4, j = openvdb::vdb_tool::swapBytes(i);
EXPECT_NE(i, j);
EXPECT_EQ(i, openvdb::vdb_tool::swapBytes(j));

const float a = 4, b = openvdb::vdb_tool::swapBytes(a);
EXPECT_NE(a, b);
EXPECT_EQ(a, openvdb::vdb_tool::swapBytes(b));

const double x = 4, y = openvdb::vdb_tool::swapBytes(x);
EXPECT_NE(x, y);
EXPECT_EQ(x, openvdb::vdb_tool::swapBytes(y));

int vec_i[3]={3,4,5}, vec_j[3];
for (int n=0; n<3; ++n) {
vec_j[n] = openvdb::vdb_tool::swapBytes(vec_i[n]);
EXPECT_NE(vec_i[n], vec_j[n]);
}
openvdb::vdb_tool::swapBytes(vec_j, 3);
for (int n=0; n<3; ++n) EXPECT_EQ(vec_i[n], vec_j[n]);

float vec_a[3]={3,4,5}, vec_b[3];
for (int n=0; n<3; ++n) {
vec_b[n] = openvdb::vdb_tool::swapBytes(vec_a[n]);
EXPECT_NE(vec_a[n], vec_b[n]);
}
openvdb::vdb_tool::swapBytes(vec_b, 3);
for (int n=0; n<3; ++n) EXPECT_EQ(vec_a[n], vec_b[n]);

double vec_x[3]={3,4,5}, vec_y[3];
for (int n=0; n<3; ++n) {
vec_y[n] = openvdb::vdb_tool::swapBytes(vec_x[n]);
EXPECT_NE(vec_x[n], vec_y[n]);
}
openvdb::vdb_tool::swapBytes(vec_y, 3);
for (int n=0; n<3; ++n) EXPECT_EQ(vec_x[n], vec_y[n]);
}
{// weird pointer behaviour
float vec[4], *p = vec;
EXPECT_EQ(vec, p);// of course
EXPECT_EQ((char*)(vec), (char*)p);// sure
EXPECT_EQ((char*)(&vec), (char*)p);// wait, what?!
EXPECT_NE((char*)(vec), (char*)(&p));// yep
EXPECT_NE((char*)(&p), (char*)p);// of course
}
}// Util

TEST_F(Test_vdb_tool, getArgs)
Expand Down

0 comments on commit 9aba3d1

Please sign in to comment.