Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions io/src/ply_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@

#include <boost/algorithm/string.hpp> // for split

namespace {
bool
requiresUint32FaceListSize(const pcl::PolygonMesh& mesh)
{
return std::any_of(
mesh.polygons.cbegin(), mesh.polygons.cend(), [](const pcl::Vertices& polygon) {
return polygon.vertices.size() > std::numeric_limits<std::uint8_t>::max();
});
}
} // namespace

std::tuple<std::function<void ()>, std::function<void ()> >
pcl::PLYReader::elementDefinitionCallback (const std::string& element_name, std::size_t count)
{
Expand Down Expand Up @@ -1525,7 +1536,8 @@ void writePLYHeader (std::ostream& fs, const pcl::PolygonMesh& mesh, const std::
}
// Faces
fs << "\nelement face "<< mesh.polygons.size ();
fs << "\nproperty list uchar int vertex_indices";
fs << "\nproperty list " << (requiresUint32FaceListSize(mesh) ? "uint" : "uchar")
<< " int vertex_indices";
fs << "\nend_header\n";
}
} // namespace io
Expand Down Expand Up @@ -1710,10 +1722,17 @@ pcl::io::savePLYFileBinary (const std::string &file_name, const pcl::PolygonMesh
}

// Write down faces
const bool use_uint32_face_list_size = requiresUint32FaceListSize(mesh);
for (const pcl::Vertices& polygon : mesh.polygons)
{
auto value = static_cast<unsigned char> (polygon.vertices.size ());
fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned char));
if (use_uint32_face_list_size) {
const auto value = static_cast<std::uint32_t>(polygon.vertices.size());
fpout.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
else {
const auto value = static_cast<std::uint8_t>(polygon.vertices.size());
fpout.write(reinterpret_cast<const char*>(&value), sizeof(value));
}
for (const int value : polygon.vertices)
{
//fs << mesh.polygons[i].vertices[j] << " ";
Expand Down
86 changes: 86 additions & 0 deletions test/io/test_ply_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@
#include <pcl/test/gtest.h>
#include <fstream> // for ofstream

namespace {
std::string
readPLYHeader(const std::string& file_name)
{
std::ifstream fs(file_name, std::ios::binary);
std::string header;
for (std::string line; std::getline(fs, line);) {
header += line + '\n';
if (line == "end_header")
break;
}
return header;
}
} // namespace

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, PLYReaderWriter)
{
Expand Down Expand Up @@ -120,6 +135,77 @@ TEST (PCL, PLYReaderWriter)
remove ("test_pcl_io.ply");
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST(PCL, PLYPolygonMeshFaceListSize)
{
const std::string small_ascii_file = "test_small_polygon_ascii.ply";
const std::string small_binary_file = "test_small_polygon_binary.ply";
const std::string large_ascii_file = "test_large_polygon_ascii.ply";
const std::string large_binary_file = "test_large_polygon_binary.ply";
struct FilesCleanup {
const std::string& small_ascii;
const std::string& small_binary;
const std::string& large_ascii;
const std::string& large_binary;

~FilesCleanup()
{
remove(small_ascii.c_str());
remove(small_binary.c_str());
remove(large_ascii.c_str());
remove(large_binary.c_str());
}
} cleanup{small_ascii_file, small_binary_file, large_ascii_file, large_binary_file};

pcl::PointCloud<pcl::PointXYZ> vertices;
vertices.resize(256);
for (std::size_t i = 0; i < vertices.size(); ++i) {
vertices[i].x = static_cast<float>(i);
vertices[i].y = static_cast<float>(i % 7);
vertices[i].z = 0.0f;
}

pcl::PolygonMesh mesh;
pcl::toPCLPointCloud2(vertices, mesh.cloud);
pcl::Vertices small_polygon;
small_polygon.vertices.reserve(255);
for (std::uint32_t i = 0; i < 255; ++i)
small_polygon.vertices.push_back(i);
mesh.polygons = {small_polygon};

ASSERT_EQ(pcl::io::savePLYFile(small_ascii_file, mesh), 0);
ASSERT_EQ(pcl::io::savePLYFileBinary(small_binary_file, mesh), 0);
const std::string uchar_property = "property list uchar int vertex_indices";
EXPECT_NE(readPLYHeader(small_ascii_file).find(uchar_property), std::string::npos);
EXPECT_NE(readPLYHeader(small_binary_file).find(uchar_property), std::string::npos);
for (const std::string& file_name : {small_ascii_file, small_binary_file}) {
pcl::PolygonMesh loaded;
ASSERT_EQ(pcl::io::loadPLYFile(file_name, loaded), 0);
ASSERT_EQ(loaded.polygons.size(), mesh.polygons.size());
EXPECT_EQ(loaded.polygons[0].vertices, small_polygon.vertices);
}

pcl::Vertices large_polygon;
large_polygon.vertices.reserve(vertices.size());
for (std::size_t i = 0; i < vertices.size(); ++i)
large_polygon.vertices.push_back(static_cast<std::uint32_t>(i));
mesh.polygons.push_back(large_polygon);

ASSERT_EQ(pcl::io::savePLYFile(large_ascii_file, mesh), 0);
ASSERT_EQ(pcl::io::savePLYFileBinary(large_binary_file, mesh), 0);
const std::string uint_property = "property list uint int vertex_indices";
EXPECT_NE(readPLYHeader(large_ascii_file).find(uint_property), std::string::npos);
EXPECT_NE(readPLYHeader(large_binary_file).find(uint_property), std::string::npos);

for (const std::string& file_name : {large_ascii_file, large_binary_file}) {
pcl::PolygonMesh loaded;
ASSERT_EQ(pcl::io::loadPLYFile(file_name, loaded), 0);
ASSERT_EQ(loaded.polygons.size(), mesh.polygons.size());
EXPECT_EQ(loaded.polygons[0].vertices, small_polygon.vertices);
EXPECT_EQ(loaded.polygons[1].vertices, large_polygon.vertices);
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct PLYTest : public ::testing::Test
{
Expand Down