From 72b83ea8971aca2f2e868520cba9c2ff75158cc7 Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Wed, 2 Dec 2015 11:45:40 +0100 Subject: [PATCH 1/5] Fix is_dense flag not properly set --- io/src/ply_io.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/io/src/ply_io.cpp b/io/src/ply_io.cpp index c01c2a325c0..602aa09a8d1 100644 --- a/io/src/ply_io.cpp +++ b/io/src/ply_io.cpp @@ -59,7 +59,7 @@ pcl::PLYReader::elementDefinitionCallback (const std::string& element_name, std: cloud_->width = static_cast (count); cloud_->height = 1; } - cloud_->is_dense = false; + cloud_->is_dense = true; cloud_->point_step = 0; cloud_->row_step = 0; vertex_count_ = 0; @@ -267,6 +267,9 @@ namespace pcl template void PLYReader::vertexScalarPropertyCallback (Scalar value) { + if (!pcl_isfinite (value)) + cloud_->is_dense = false; + memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_], &value, sizeof (Scalar)); From 782eca3b049432bdd8b928d8b60ea3a053b9a08b Mon Sep 17 00:00:00 2001 From: Victor Lamoine Date: Wed, 2 Dec 2015 12:00:28 +0100 Subject: [PATCH 2/5] Re-enable is_dense check in PLY io tests --- test/io/test_io.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/io/test_io.cpp b/test/io/test_io.cpp index d6ba92d987f..c3d72f8b8dc 100644 --- a/test/io/test_io.cpp +++ b/test/io/test_io.cpp @@ -941,7 +941,7 @@ TEST_F (PLYTest, LoadPLYFileColoredASCIIIntoBlob) EXPECT_EQ (cloud_blob.point_step, 16); EXPECT_EQ (cloud_blob.row_step, 16 * 4); EXPECT_EQ (cloud_blob.data.size(), 16 * 4); - // EXPECT_TRUE (cloud_blob.is_dense); // this is failing and it shouldn't? + EXPECT_TRUE (cloud_blob.is_dense); // scope blob data ps = cloud_blob.point_step; @@ -989,7 +989,7 @@ TEST_F (PLYTest, LoadPLYFileColoredASCIIIntoPolygonMesh) EXPECT_EQ (mesh.cloud.point_step, 16); EXPECT_EQ (mesh.cloud.row_step, 16 * 4); EXPECT_EQ (mesh.cloud.data.size(), 16 * 4); - // EXPECT_TRUE (mesh.cloud.is_dense); // this is failing and it shouldn't? + EXPECT_TRUE (mesh.cloud.is_dense); // scope blob data ps = mesh.cloud.point_step; @@ -1033,7 +1033,7 @@ TYPED_TEST (PLYPointCloudTest, LoadPLYFileColoredASCIIIntoPointCloud) EXPECT_EQ (cloud_rgb.height, 1); EXPECT_EQ (cloud_rgb.width, 4); EXPECT_EQ (cloud_rgb.points.size(), 4); - // EXPECT_TRUE (cloud_rgb.is_dense); // this is failing and it shouldn't? + EXPECT_TRUE (cloud_rgb.is_dense); // scope cloud data ASSERT_EQ (cloud_rgb[0].rgba, PLYTest::rgba_1_); From dc68e36295b786e5086d01b0a8e5fdba2180f540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Agostinho?= Date: Fri, 8 Dec 2017 14:41:56 +0000 Subject: [PATCH 3/5] Add finite check to list values --- io/src/ply_io.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/io/src/ply_io.cpp b/io/src/ply_io.cpp index 602aa09a8d1..27bbc87c85e 100644 --- a/io/src/ply_io.cpp +++ b/io/src/ply_io.cpp @@ -294,6 +294,9 @@ namespace pcl template void PLYReader::vertexListPropertyContentCallback (ContentType value) { + if (!pcl_isfinite (value)) + cloud_->is_dense = false; + memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_], &value, sizeof (ContentType)); From d58e79cf3e1c74cbd70d64e7d653bba403bf3f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Agostinho?= Date: Fri, 8 Dec 2017 14:48:17 +0000 Subject: [PATCH 4/5] Clarify is_dense definition --- common/include/pcl/point_cloud.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/include/pcl/point_cloud.h b/common/include/pcl/point_cloud.h index f0d01f27881..28b91d29859 100644 --- a/common/include/pcl/point_cloud.h +++ b/common/include/pcl/point_cloud.h @@ -414,7 +414,7 @@ namespace pcl /** \brief The point cloud height (if organized as an image-structure). */ uint32_t height; - /** \brief True if no points are invalid (e.g., have NaN or Inf values). */ + /** \brief True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields). */ bool is_dense; /** \brief Sensor acquisition pose (origin/translation). */ From 316c26de7f185b302bab952a36ffabd7b3a693d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Agostinho?= Date: Fri, 8 Dec 2017 17:29:17 +0000 Subject: [PATCH 5/5] Add unit tests validating is_dense inference by PLYReader --- test/io/CMakeLists.txt | 5 + test/io/test_io.cpp | 234 ------------------- test/io/test_ply_io.cpp | 482 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 487 insertions(+), 234 deletions(-) create mode 100644 test/io/test_ply_io.cpp diff --git a/test/io/CMakeLists.txt b/test/io/CMakeLists.txt index 1872e6b354f..4483a330a2b 100644 --- a/test/io/CMakeLists.txt +++ b/test/io/CMakeLists.txt @@ -25,6 +25,11 @@ if (build) FILES test_grabbers.cpp LINK_WITH pcl_gtest pcl_io ARGUMENTS "${PCL_SOURCE_DIR}/test/grabber_sequences") + + PCL_ADD_TEST(io_ply_io test_ply_io + FILES test_ply_io.cpp + LINK_WITH pcl_gtest pcl_io) + # Uses VTK readers to verify if (VTK_FOUND AND NOT ANDROID) include_directories(${VTK_INCLUDE_DIRS}) diff --git a/test/io/test_io.cpp b/test/io/test_io.cpp index c3d72f8b8dc..22ab1b420d0 100644 --- a/test/io/test_io.cpp +++ b/test/io/test_io.cpp @@ -808,240 +808,6 @@ TEST (PCL, ASCIIReader) } -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TEST (PCL, PLYReaderWriter) -{ - pcl::PCLPointCloud2 cloud_blob, cloud_blob2; - PointCloud cloud, cloud2; - - cloud.width = 640; - cloud.height = 480; - cloud.resize (cloud.width * cloud.height); - cloud.is_dense = true; - - srand (static_cast (time (NULL))); - size_t nr_p = cloud.size (); - // Randomly create a new point cloud - for (size_t i = 0; i < nr_p; ++i) - { - cloud[i].x = static_cast (1024 * rand () / (RAND_MAX + 1.0)); - cloud[i].y = static_cast (1024 * rand () / (RAND_MAX + 1.0)); - cloud[i].z = static_cast (1024 * rand () / (RAND_MAX + 1.0)); - cloud[i].intensity = static_cast (i); - } - - // Convert from data type to blob - toPCLPointCloud2 (cloud, cloud_blob); - - EXPECT_EQ (cloud_blob.width, cloud.width); // test for toPCLPointCloud2 () - EXPECT_EQ (cloud_blob.height, cloud.height); // test for toPCLPointCloud2 () - EXPECT_EQ (cloud_blob.is_dense, cloud.is_dense); // test for toPCLPointCloud2 () - EXPECT_EQ (cloud_blob.data.size (), - cloud_blob.width * cloud_blob.height * sizeof (PointXYZI)); - - // test for toPCLPointCloud2 () - PLYWriter writer; - writer.write ("test_pcl_io.ply", cloud_blob, Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), true, true); - - PLYReader reader; - reader.read ("test_pcl_io.ply", cloud_blob2); - //PLY DOES preserve organiziation - EXPECT_EQ (cloud_blob.width * cloud_blob.height, cloud_blob2.width * cloud_blob2.height); - EXPECT_EQ (cloud_blob.is_dense, cloud.is_dense); - EXPECT_EQ (size_t (cloud_blob2.data.size ()), // PointXYZI is 16*2 (XYZ+1, Intensity+3) - cloud_blob2.width * cloud_blob2.height * sizeof (PointXYZ)); // test for loadPLYFile () - - // Convert from blob to data type - fromPCLPointCloud2 (cloud_blob2, cloud2); - - // EXPECT_EQ (cloud.width, cloud2.width); // test for fromPCLPointCloud2 () - // EXPECT_EQ (cloud.height, cloud2.height); // test for fromPCLPointCloud2 () - // EXPECT_EQ (cloud.is_dense, cloud2.is_dense); // test for fromPCLPointCloud2 () - EXPECT_EQ (cloud.size (), cloud2.size ()); // test for fromPCLPointCloud2 () - - for (uint32_t counter = 0; counter < cloud.size (); ++counter) - { - EXPECT_FLOAT_EQ (cloud[counter].x, cloud2[counter].x); // test for fromPCLPointCloud2 () - EXPECT_FLOAT_EQ (cloud[counter].y, cloud2[counter].y); // test for fromPCLPointCloud2 () - EXPECT_FLOAT_EQ (cloud[counter].z, cloud2[counter].z); // test for fromPCLPointCloud2 () - EXPECT_FLOAT_EQ (cloud[counter].intensity, cloud2[counter].intensity); // test for fromPCLPointCloud2 () - } -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -class PLYTest : public ::testing::Test -{ - protected: - - PLYTest () : mesh_file_ply_("ply_color_mesh.ply") - { - std::ofstream fs; - fs.open (mesh_file_ply_.c_str ()); - fs << "ply\n" - "format ascii 1.0\n" - "element vertex 4\n" - "property float x\n" - "property float y\n" - "property float z\n" - "property uchar red\n" - "property uchar green\n" - "property uchar blue\n" - "property uchar alpha\n" - "element face 2\n" - "property list uchar int vertex_indices\n" - "end_header\n" - "4.23607 0 1.61803 255 0 0 255\n" - "2.61803 2.61803 2.61803 0 255 0 0\n" - "0 1.61803 4.23607 0 0 255 128\n" - "0 -1.61803 4.23607 255 255 255 128\n" - "3 0 1 2\n" - "3 1 2 3\n"; - fs.close (); - - // Test colors from ply_benchmark.ply - rgba_1_ = static_cast (255) << 24 | static_cast (255) << 16 | - static_cast (0) << 8 | static_cast (0); - rgba_2_ = static_cast (0) << 24 | static_cast (0) << 16 | - static_cast (255) << 8 | static_cast (0); - rgba_3_ = static_cast (128) << 24 | static_cast (0) << 16 | - static_cast (0) << 8 | static_cast (255); - rgba_4_ = static_cast (128) << 24 | static_cast (255) << 16 | - static_cast (255) << 8 | static_cast (255); - } - - virtual - ~PLYTest () { remove (mesh_file_ply_.c_str ()); } - - std::string mesh_file_ply_; - uint32_t rgba_1_; - uint32_t rgba_2_; - uint32_t rgba_3_; - uint32_t rgba_4_; -}; - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TEST_F (PLYTest, LoadPLYFileColoredASCIIIntoBlob) -{ - int res; - uint32_t rgba; - - PCLPointCloud2 cloud_blob; - uint32_t ps; - int32_t offset = -1; - - // check if loading is ok - res = loadPLYFile (mesh_file_ply_, cloud_blob); - ASSERT_EQ (res, 0); - - // blob has proper structure - EXPECT_EQ (cloud_blob.height, 1); - EXPECT_EQ (cloud_blob.width, 4); - EXPECT_EQ (cloud_blob.fields.size(), 4); - EXPECT_FALSE (cloud_blob.is_bigendian); - EXPECT_EQ (cloud_blob.point_step, 16); - EXPECT_EQ (cloud_blob.row_step, 16 * 4); - EXPECT_EQ (cloud_blob.data.size(), 16 * 4); - EXPECT_TRUE (cloud_blob.is_dense); - - // scope blob data - ps = cloud_blob.point_step; - for (size_t i = 0; i < cloud_blob.fields.size (); ++i) - if (cloud_blob.fields[i].name == std::string("rgba")) - offset = static_cast (cloud_blob.fields[i].offset); - - ASSERT_GE (offset, 0); - - // 1st point - rgba = *reinterpret_cast (&cloud_blob.data[offset]); - ASSERT_EQ (rgba, rgba_1_); - - // 2th point - rgba = *reinterpret_cast (&cloud_blob.data[ps + offset]); - ASSERT_EQ (rgba, rgba_2_); - - // 3th point - rgba = *reinterpret_cast (&cloud_blob.data[2 * ps + offset]); - ASSERT_EQ (rgba, rgba_3_); - - // 4th point - rgba = *reinterpret_cast (&cloud_blob.data[3 * ps + offset]); - ASSERT_EQ (rgba, rgba_4_); -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TEST_F (PLYTest, LoadPLYFileColoredASCIIIntoPolygonMesh) -{ - int res; - uint32_t rgba; - PolygonMesh mesh; - uint32_t ps; - int32_t offset = -1; - - // check if loading is ok - res = loadPLYFile (mesh_file_ply_, mesh); - ASSERT_EQ (res, 0); - - // blob has proper structure - EXPECT_EQ (mesh.cloud.height, 1); - EXPECT_EQ (mesh.cloud.width, 4); - EXPECT_EQ (mesh.cloud.fields.size(), 4); - EXPECT_FALSE (mesh.cloud.is_bigendian); - EXPECT_EQ (mesh.cloud.point_step, 16); - EXPECT_EQ (mesh.cloud.row_step, 16 * 4); - EXPECT_EQ (mesh.cloud.data.size(), 16 * 4); - EXPECT_TRUE (mesh.cloud.is_dense); - - // scope blob data - ps = mesh.cloud.point_step; - for (size_t i = 0; i < mesh.cloud.fields.size (); ++i) - if (mesh.cloud.fields[i].name == std::string("rgba")) - offset = static_cast (mesh.cloud.fields[i].offset); - - ASSERT_GE (offset, 0); - - // 1st point - rgba = *reinterpret_cast (&mesh.cloud.data[offset]); - ASSERT_EQ (rgba, rgba_1_); - - // 2th point - rgba = *reinterpret_cast (&mesh.cloud.data[ps + offset]); - ASSERT_EQ (rgba, rgba_2_); - - // 3th point - rgba = *reinterpret_cast (&mesh.cloud.data[2 * ps + offset]); - ASSERT_EQ (rgba, rgba_3_); - - // 4th point - rgba = *reinterpret_cast (&mesh.cloud.data[3 * ps + offset]); - ASSERT_EQ (rgba, rgba_4_); -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -template class PLYPointCloudTest : public PLYTest { }; -typedef ::testing::Types RGBPointTypes; -TYPED_TEST_CASE (PLYPointCloudTest, RGBPointTypes); -TYPED_TEST (PLYPointCloudTest, LoadPLYFileColoredASCIIIntoPointCloud) -{ - int res; - PointCloud cloud_rgb; - - // check if loading is ok - res = loadPLYFile (PLYTest::mesh_file_ply_, cloud_rgb); - ASSERT_EQ (res, 0); - - // cloud has proper structure - EXPECT_EQ (cloud_rgb.height, 1); - EXPECT_EQ (cloud_rgb.width, 4); - EXPECT_EQ (cloud_rgb.points.size(), 4); - EXPECT_TRUE (cloud_rgb.is_dense); - - // scope cloud data - ASSERT_EQ (cloud_rgb[0].rgba, PLYTest::rgba_1_); - ASSERT_EQ (cloud_rgb[1].rgba, PLYTest::rgba_2_); - ASSERT_EQ (cloud_rgb[2].rgba, PLYTest::rgba_3_); - ASSERT_EQ (cloud_rgb[3].rgba, PLYTest::rgba_4_); -} - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct PointXYZFPFH33 diff --git a/test/io/test_ply_io.cpp b/test/io/test_ply_io.cpp new file mode 100644 index 00000000000..b169dbe4587 --- /dev/null +++ b/test/io/test_ply_io.cpp @@ -0,0 +1,482 @@ +/* + * Software License Agreement (BSD License) + * + * Point Cloud Library (PCL) - www.pointclouds.org + * Copyright (c) 2017-, Open Perception, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the copyright holder(s) nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST (PCL, PLYReaderWriter) +{ + using pcl::PointXYZI; + using pcl::PointXYZ; + + pcl::PCLPointCloud2 cloud_blob, cloud_blob2; + pcl::PointCloud cloud, cloud2; + + cloud.width = 640; + cloud.height = 480; + cloud.resize (cloud.width * cloud.height); + cloud.is_dense = true; + + srand (static_cast (time (NULL))); + size_t nr_p = cloud.size (); + // Randomly create a new point cloud + for (size_t i = 0; i < nr_p; ++i) + { + cloud[i].x = static_cast (1024 * rand () / (RAND_MAX + 1.0)); + cloud[i].y = static_cast (1024 * rand () / (RAND_MAX + 1.0)); + cloud[i].z = static_cast (1024 * rand () / (RAND_MAX + 1.0)); + cloud[i].intensity = static_cast (i); + } + + // Convert from data type to blob + toPCLPointCloud2 (cloud, cloud_blob); + + EXPECT_EQ (cloud_blob.width, cloud.width); // test for toPCLPointCloud2 () + EXPECT_EQ (cloud_blob.height, cloud.height); // test for toPCLPointCloud2 () + EXPECT_EQ (cloud_blob.is_dense, cloud.is_dense); // test for toPCLPointCloud2 () + EXPECT_EQ (cloud_blob.data.size (), + cloud_blob.width * cloud_blob.height * sizeof (PointXYZI)); + + // test for toPCLPointCloud2 () + pcl::PLYWriter writer; + writer.write ("test_pcl_io.ply", cloud_blob, Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), true, true); + + pcl::PLYReader reader; + reader.read ("test_pcl_io.ply", cloud_blob2); + //PLY DOES preserve organiziation + EXPECT_EQ (cloud_blob.width * cloud_blob.height, cloud_blob2.width * cloud_blob2.height); + EXPECT_EQ (cloud_blob.is_dense, cloud.is_dense); + EXPECT_EQ (size_t (cloud_blob2.data.size ()), // PointXYZI is 16*2 (XYZ+1, Intensity+3) + cloud_blob2.width * cloud_blob2.height * sizeof (PointXYZ)); // test for loadPLYFile () + + // Convert from blob to data type + fromPCLPointCloud2 (cloud_blob2, cloud2); + + // EXPECT_EQ (cloud.width, cloud2.width); // test for fromPCLPointCloud2 () + // EXPECT_EQ (cloud.height, cloud2.height); // test for fromPCLPointCloud2 () + EXPECT_EQ (cloud.is_dense, cloud2.is_dense); // test for fromPCLPointCloud2 () + EXPECT_EQ (cloud.size (), cloud2.size ()); // test for fromPCLPointCloud2 () + + for (uint32_t counter = 0; counter < cloud.size (); ++counter) + { + EXPECT_FLOAT_EQ (cloud[counter].x, cloud2[counter].x); // test for fromPCLPointCloud2 () + EXPECT_FLOAT_EQ (cloud[counter].y, cloud2[counter].y); // test for fromPCLPointCloud2 () + EXPECT_FLOAT_EQ (cloud[counter].z, cloud2[counter].z); // test for fromPCLPointCloud2 () + EXPECT_FLOAT_EQ (cloud[counter].intensity, cloud2[counter].intensity); // test for fromPCLPointCloud2 () + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +struct PLYTest : public ::testing::Test +{ + PLYTest () : mesh_file_ply_("ply_file.ply") + {} + + virtual + ~PLYTest () { remove (mesh_file_ply_.c_str ()); } + + std::string mesh_file_ply_; +}; + +struct PLYColorTest : public PLYTest +{ + void SetUp () + { + // Test colors from ply_benchmark.ply + clr_1_.r = 255; + clr_1_.g = 0; + clr_1_.b = 0; + clr_1_.a = 255; + + clr_2_.r = 0; + clr_2_.g = 255; + clr_2_.b = 0; + clr_2_.a = 0; + + clr_3_.r = 0; + clr_3_.g = 0; + clr_3_.b = 255; + clr_3_.a = 128; + + clr_4_.r = 255; + clr_4_.g = 255; + clr_4_.b = 255; + clr_4_.a = 128; + + std::ofstream fs; + fs.open (mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float x\n" + "property float y\n" + "property float z\n" + "property uchar red\n" + "property uchar green\n" + "property uchar blue\n" + "property uchar alpha\n" + "element face 2\n" + "property list uchar int vertex_indices\n" + "end_header\n" + "4.23607 0 1.61803 " + << unsigned (clr_1_.r) << ' ' + << unsigned (clr_1_.g) << ' ' + << unsigned (clr_1_.b) << ' ' + << unsigned (clr_1_.a) << "\n" + "2.61803 2.61803 2.61803 " + << unsigned (clr_2_.r) << ' ' + << unsigned (clr_2_.g) << ' ' + << unsigned (clr_2_.b) << ' ' + << unsigned (clr_2_.a) << "\n" + "0 1.61803 4.23607 " + << unsigned (clr_3_.r) << ' ' + << unsigned (clr_3_.g) << ' ' + << unsigned (clr_3_.b) << ' ' + << unsigned (clr_3_.a) << "\n" + "0 -1.61803 4.23607 " + << unsigned (clr_4_.r) << ' ' + << unsigned (clr_4_.g) << ' ' + << unsigned (clr_4_.b) << ' ' + << unsigned (clr_4_.a) << "\n" + "3 0 1 2\n" + "3 1 2 3\n"; + fs.close (); + } + + pcl::RGB clr_1_; + pcl::RGB clr_2_; + pcl::RGB clr_3_; + pcl::RGB clr_4_; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST_F (PLYColorTest, LoadPLYFileColoredASCIIIntoBlob) +{ + int res; + uint32_t rgba; + + pcl::PCLPointCloud2 cloud_blob; + uint32_t ps; + int32_t offset = -1; + + // check if loading is ok + res = pcl::io::loadPLYFile (mesh_file_ply_, cloud_blob); + ASSERT_EQ (res, 0); + + // blob has proper structure + EXPECT_EQ (cloud_blob.height, 1); + EXPECT_EQ (cloud_blob.width, 4); + EXPECT_EQ (cloud_blob.fields.size(), 4); + EXPECT_FALSE (cloud_blob.is_bigendian); + EXPECT_EQ (cloud_blob.point_step, 16); + EXPECT_EQ (cloud_blob.row_step, 16 * 4); + EXPECT_EQ (cloud_blob.data.size(), 16 * 4); + EXPECT_TRUE (cloud_blob.is_dense); + + // scope blob data + ps = cloud_blob.point_step; + for (size_t i = 0; i < cloud_blob.fields.size (); ++i) + if (cloud_blob.fields[i].name == std::string("rgba")) + offset = static_cast (cloud_blob.fields[i].offset); + + ASSERT_GE (offset, 0); + + // 1st point + rgba = *reinterpret_cast (&cloud_blob.data[offset]); + ASSERT_EQ (rgba, clr_1_.rgba); + + // 2th point + rgba = *reinterpret_cast (&cloud_blob.data[ps + offset]); + ASSERT_EQ (rgba, clr_2_.rgba); + + // 3th point + rgba = *reinterpret_cast (&cloud_blob.data[2 * ps + offset]); + ASSERT_EQ (rgba, clr_3_.rgba); + + // 4th point + rgba = *reinterpret_cast (&cloud_blob.data[3 * ps + offset]); + ASSERT_EQ (rgba, clr_4_.rgba); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST_F (PLYColorTest, LoadPLYFileColoredASCIIIntoPolygonMesh) +{ + int res; + uint32_t rgba; + pcl::PolygonMesh mesh; + uint32_t ps; + int32_t offset = -1; + + // check if loading is ok + res = pcl::io::loadPLYFile (mesh_file_ply_, mesh); + ASSERT_EQ (res, 0); + + // blob has proper structure + EXPECT_EQ (mesh.cloud.height, 1); + EXPECT_EQ (mesh.cloud.width, 4); + EXPECT_EQ (mesh.cloud.fields.size(), 4); + EXPECT_FALSE (mesh.cloud.is_bigendian); + EXPECT_EQ (mesh.cloud.point_step, 16); + EXPECT_EQ (mesh.cloud.row_step, 16 * 4); + EXPECT_EQ (mesh.cloud.data.size(), 16 * 4); + EXPECT_TRUE (mesh.cloud.is_dense); + + // scope blob data + ps = mesh.cloud.point_step; + for (size_t i = 0; i < mesh.cloud.fields.size (); ++i) + if (mesh.cloud.fields[i].name == std::string("rgba")) + offset = static_cast (mesh.cloud.fields[i].offset); + + ASSERT_GE (offset, 0); + + // 1st point + rgba = *reinterpret_cast (&mesh.cloud.data[offset]); + ASSERT_EQ (rgba, clr_1_.rgba); + + // 2th point + rgba = *reinterpret_cast (&mesh.cloud.data[ps + offset]); + ASSERT_EQ (rgba, clr_2_.rgba); + + // 3th point + rgba = *reinterpret_cast (&mesh.cloud.data[2 * ps + offset]); + ASSERT_EQ (rgba, clr_3_.rgba); + + // 4th point + rgba = *reinterpret_cast (&mesh.cloud.data[3 * ps + offset]); + ASSERT_EQ (rgba, clr_4_.rgba); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template class PLYPointCloudTest : public PLYColorTest { }; +typedef ::testing::Types RGBPointTypes; +TYPED_TEST_CASE (PLYPointCloudTest, RGBPointTypes); +TYPED_TEST (PLYPointCloudTest, LoadPLYFileColoredASCIIIntoPointCloud) +{ + int res; + pcl::PointCloud cloud_rgb; + + // check if loading is ok + res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud_rgb); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_EQ (cloud_rgb.height, 1); + EXPECT_EQ (cloud_rgb.width, 4); + EXPECT_EQ (cloud_rgb.points.size(), 4); + EXPECT_TRUE (cloud_rgb.is_dense); + + // scope cloud data + ASSERT_EQ (cloud_rgb[0].rgba, PLYColorTest::clr_1_.rgba); + ASSERT_EQ (cloud_rgb[1].rgba, PLYColorTest::clr_2_.rgba); + ASSERT_EQ (cloud_rgb[2].rgba, PLYColorTest::clr_3_.rgba); + ASSERT_EQ (cloud_rgb[3].rgba, PLYColorTest::clr_4_.rgba); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct PLYCoordinatesIsDenseTest : public PLYTest {}; + +typedef ::testing::Types XYZPointTypes; +TYPED_TEST_CASE (PLYCoordinatesIsDenseTest, XYZPointTypes); + +TYPED_TEST (PLYCoordinatesIsDenseTest, NaNInCoordinates) +{ + // create file + std::ofstream fs; + fs.open (PLYTest::mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float x\n" + "property float y\n" + "property float z\n" + "end_header\n" + "4.23607 NaN 1.61803 \n" + "2.61803 2.61803 2.61803 \n" + "0 1.61803 4.23607 \n" + "0 -1.61803 4.23607 \n"; + fs.close (); + + // Set up cloud + pcl::PointCloud cloud; + + // check if loading is ok + const int res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_FALSE (cloud.is_dense); +} + +TYPED_TEST (PLYCoordinatesIsDenseTest, nanInCoordinates) +{ + // create file + std::ofstream fs; + fs.open (PLYTest::mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float x\n" + "property float y\n" + "property float z\n" + "end_header\n" + "4.23607 0 1.61803 \n" + "2.61803 2.61803 2.61803 \n" + "nan 1.61803 4.23607 \n" + "0 -1.61803 4.23607 \n"; + fs.close (); + + // Set up cloud + pcl::PointCloud cloud; + + // check if loading is ok + const int res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_FALSE (cloud.is_dense); +} + +TYPED_TEST (PLYCoordinatesIsDenseTest, InfInCoordinates) +{ + // create file + std::ofstream fs; + fs.open (PLYTest::mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float x\n" + "property float y\n" + "property float z\n" + "end_header\n" + "4.23607 0 1.61803 \n" + "2.61803 2.61803 Inf \n" + "0 1.61803 4.23607 \n" + "0 -1.61803 4.23607 \n"; + fs.close (); + + // Set up cloud + pcl::PointCloud cloud; + + // check if loading is ok + const int res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_FALSE (cloud.is_dense); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +template +struct PLYNormalsIsDenseTest : public PLYTest {}; + +typedef ::testing::Types NormalPointTypes; +TYPED_TEST_CASE (PLYNormalsIsDenseTest, NormalPointTypes); + +TYPED_TEST (PLYNormalsIsDenseTest, NaNInNormals) +{ + // create file + std::ofstream fs; + fs.open (PLYTest::mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float normal_x\n" + "property float normal_y\n" + "property float normal_z\n" + "end_header\n" + "4.23607 0 1.61803 \n" + "2.61803 2.61803 NaN \n" + "0 1.61803 4.23607 \n" + "0 -1.61803 4.23607 \n"; + fs.close (); + + // Set up cloud + pcl::PointCloud cloud; + + // check if loading is ok + const int res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_FALSE (cloud.is_dense); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST_F (PLYTest, NaNInIntensity) +{ + // create file + std::ofstream fs; + fs.open (mesh_file_ply_.c_str ()); + fs << "ply\n" + "format ascii 1.0\n" + "element vertex 4\n" + "property float x\n" + "property float y\n" + "property float z\n" + "property float intensity\n" + "end_header\n" + "4.23607 0 1.61803 3.13223\n" + "2.61803 2.61803 0 3.13223\n" + "0 1.61803 4.23607 NaN\n" + "0 -1.61803 4.23607 3.13223\n"; + fs.close (); + + // Set up cloud + pcl::PointCloud cloud; + + // check if loading is ok + const int res = pcl::io::loadPLYFile (PLYTest::mesh_file_ply_, cloud); + ASSERT_EQ (res, 0); + + // cloud has proper structure + EXPECT_FALSE (cloud.is_dense); +} + +/* ---[ */ +int +main (int argc, char** argv) +{ + testing::InitGoogleTest (&argc, argv); + return (RUN_ALL_TESTS ()); +} +/* ]--- */