From 12d02bb4c14408391c31b9c0ba1c76e03bccb389 Mon Sep 17 00:00:00 2001 From: mynickmynick mynickmynick Date: Sat, 9 Sep 2023 21:30:42 +0200 Subject: [PATCH 1/3] computeTriangleMeshArea() : calculate the area of a triangle mesh --- surface/include/pcl/surface/gp3.h | 45 ++++++++++++++++++++ surface/include/pcl/surface/impl/gp3.hpp | 53 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/surface/include/pcl/surface/gp3.h b/surface/include/pcl/surface/gp3.h index 27be42ccacc..147333e9179 100644 --- a/surface/include/pcl/surface/gp3.h +++ b/surface/include/pcl/surface/gp3.h @@ -513,6 +513,51 @@ namespace pcl } }; + /** \brief Calculate the area of a triangle mesh + * \param[in] cloud the point cloud to which the mesh is applied + * \param[in] triangleMesh a triangle mesh + * \return the mesh area + * \note example of use: + * pcl::GreedyProjectionTriangulation gp; + * ... + * gp.setInputCloud(cloud_with_normals) + * ... + * pcl::PolygonMesh pm; + * gp3.reconstruct(pm); + * calculatePolygonArea(cloud_with_normals, pm.vertices); + * gp.reconstruct(pm); + * float functArea=computeTriangleMeshArea(cloud_with_normals, pm.polygons); + * \ingroup + * common + */ + template + inline float + computeTriangleMeshArea(const shared_ptr>& cloud, + std::vector& triangleMesh); + + /** \brief Calculate the area of a triangle mesh + * \param[in] cloud the point cloud to which the mesh is applied + * \param[in] indices of the point cloud + * \param[in] triangleMesh a triangle mesh + * \return the mesh area + * \note example of use: + * pcl::GreedyProjectionTriangulation gp; + * ... + * gp.setInputCloud(cloud_with_normals) + * ... + * pcl::PolygonMesh pm; + * gp.reconstruct(pm); + * float functArea=computeTriangleMeshArea(cloud_with_normals, pm.polygons); + * \ingroup + * common + */ + + template + inline float + computeTriangleMeshArea(const shared_ptr>& cloud, + const shared_ptr& indices, + std::vector& triangleMesh); + } // namespace pcl #ifdef PCL_NO_PRECOMPILE diff --git a/surface/include/pcl/surface/impl/gp3.hpp b/surface/include/pcl/surface/impl/gp3.hpp index 5f6c4bd449e..d0392ef4f17 100644 --- a/surface/include/pcl/surface/impl/gp3.hpp +++ b/surface/include/pcl/surface/impl/gp3.hpp @@ -1667,6 +1667,59 @@ pcl::GreedyProjectionTriangulation::getTriangleList (const pcl::Polygo #define PCL_INSTANTIATE_GreedyProjectionTriangulation(T) \ template class PCL_EXPORTS pcl::GreedyProjectionTriangulation; +template +inline float +pcl::computeTriangleMeshArea(const shared_ptr>& cloud, + std::vector& triangleMesh) +{ + const pcl::PointCloud::ConstPtr input_ = cloud; + double area = 0; + for (auto& triangle_ : triangleMesh) { + if (triangle_.vertices.size() == 3) { + const Eigen::Matrix P( + (*input_)[triangle_.vertices[0]].x - (*input_)[triangle_.vertices[2]].x, + (*input_)[triangle_.vertices[0]].y - (*input_)[triangle_.vertices[2]].y, + (*input_)[triangle_.vertices[0]].z - (*input_)[triangle_.vertices[2]].z); + const Eigen::Matrix Q( + (*input_)[triangle_.vertices[1]].x - (*input_)[triangle_.vertices[2]].x, + (*input_)[triangle_.vertices[1]].y - (*input_)[triangle_.vertices[2]].y, + (*input_)[triangle_.vertices[1]].z - (*input_)[triangle_.vertices[2]].z); + area += 0.5 * P.cross(Q).norm(); + } + } + return area; +} + +template +inline float +pcl::computeTriangleMeshArea(const shared_ptr>& cloud, + const shared_ptr& indices, + std::vector& triangleMesh) +{ + const pcl::PointCloud::ConstPtr input_ = cloud; + double area = 0; + for (auto& triangle_ : triangleMesh) { + if (triangle_.vertices.size() == 3) { + const Eigen::Matrix P( + (*input_)[(*indices_)[triangle_.vertices[0]]].x - + (*input_)[(*indices_)[triangle_.vertices[2]]].x, + (*input_)[(*indices_)[triangle_.vertices[0]]].y - + (*input_)[(*indices_)[triangle_.vertices[2]]].y, + (*input_)[(*indices_)[triangle_.vertices[0]]].z - + (*input_)[(*indices_)[triangle_.vertices[2]]].z); + const Eigen::Matrix Q( + (*input_)[(*indices_)[triangle_.vertices[1]]].x - + (*input_)[(*indices_)[triangle_.vertices[2]]].x, + (*input_)[(*indices_)[triangle_.vertices[1]]].y - + (*input_)[(*indices_)[triangle_.vertices[2]]].y, + (*input_)[(*indices_)[triangle_.vertices[1]]].z - + (*input_)[(*indices_)[triangle_.vertices[2]]].z); + area += 0.5 * P.cross(Q).norm(); + } + } + return area; +} + #endif // PCL_SURFACE_IMPL_GP3_H_ From 3de7937f9015c040c90b52e4c2924b2977ce1d1a Mon Sep 17 00:00:00 2001 From: mynickmynick mynickmynick Date: Sat, 9 Sep 2023 22:23:29 +0200 Subject: [PATCH 2/3] minor corrections minor test_gp3 test sample pcd correction minor correction minor minor --- surface/include/pcl/surface/gp3.h | 47 ++++++++++----------- surface/include/pcl/surface/impl/gp3.hpp | 53 ------------------------ test/surface/test_gp3.cpp | 30 ++++++++++++++ 3 files changed, 51 insertions(+), 79 deletions(-) diff --git a/surface/include/pcl/surface/gp3.h b/surface/include/pcl/surface/gp3.h index 147333e9179..1a8a736854f 100644 --- a/surface/include/pcl/surface/gp3.h +++ b/surface/include/pcl/surface/gp3.h @@ -523,29 +523,6 @@ namespace pcl * gp.setInputCloud(cloud_with_normals) * ... * pcl::PolygonMesh pm; - * gp3.reconstruct(pm); - * calculatePolygonArea(cloud_with_normals, pm.vertices); - * gp.reconstruct(pm); - * float functArea=computeTriangleMeshArea(cloud_with_normals, pm.polygons); - * \ingroup - * common - */ - template - inline float - computeTriangleMeshArea(const shared_ptr>& cloud, - std::vector& triangleMesh); - - /** \brief Calculate the area of a triangle mesh - * \param[in] cloud the point cloud to which the mesh is applied - * \param[in] indices of the point cloud - * \param[in] triangleMesh a triangle mesh - * \return the mesh area - * \note example of use: - * pcl::GreedyProjectionTriangulation gp; - * ... - * gp.setInputCloud(cloud_with_normals) - * ... - * pcl::PolygonMesh pm; * gp.reconstruct(pm); * float functArea=computeTriangleMeshArea(cloud_with_normals, pm.polygons); * \ingroup @@ -554,9 +531,27 @@ namespace pcl template inline float - computeTriangleMeshArea(const shared_ptr>& cloud, - const shared_ptr& indices, - std::vector& triangleMesh); + computeTriangleMeshArea(const shared_ptr>& cloud, + std::vector& triangleMesh) + { + double area = 0; + pcl::PointCloud& cl = (*cloud); + for (auto& triangle_ : triangleMesh) { + if (triangle_.vertices.size() == 3) { + const Eigen::Matrix P( + cl[triangle_.vertices[0]].x - (*cloud)[triangle_.vertices[2]].x, + cl[triangle_.vertices[0]].y - (*cloud)[triangle_.vertices[2]].y, + cl[triangle_.vertices[0]].z - (*cloud)[triangle_.vertices[2]].z); + const Eigen::Matrix Q( + cl[triangle_.vertices[1]].x - (*cloud)[triangle_.vertices[2]].x, + cl[triangle_.vertices[1]].y - (*cloud)[triangle_.vertices[2]].y, + cl[triangle_.vertices[1]].z - (*cloud)[triangle_.vertices[2]].z); + area += 0.5 * P.cross(Q).norm(); + } + } + return area; + } + } // namespace pcl diff --git a/surface/include/pcl/surface/impl/gp3.hpp b/surface/include/pcl/surface/impl/gp3.hpp index d0392ef4f17..5f6c4bd449e 100644 --- a/surface/include/pcl/surface/impl/gp3.hpp +++ b/surface/include/pcl/surface/impl/gp3.hpp @@ -1667,59 +1667,6 @@ pcl::GreedyProjectionTriangulation::getTriangleList (const pcl::Polygo #define PCL_INSTANTIATE_GreedyProjectionTriangulation(T) \ template class PCL_EXPORTS pcl::GreedyProjectionTriangulation; -template -inline float -pcl::computeTriangleMeshArea(const shared_ptr>& cloud, - std::vector& triangleMesh) -{ - const pcl::PointCloud::ConstPtr input_ = cloud; - double area = 0; - for (auto& triangle_ : triangleMesh) { - if (triangle_.vertices.size() == 3) { - const Eigen::Matrix P( - (*input_)[triangle_.vertices[0]].x - (*input_)[triangle_.vertices[2]].x, - (*input_)[triangle_.vertices[0]].y - (*input_)[triangle_.vertices[2]].y, - (*input_)[triangle_.vertices[0]].z - (*input_)[triangle_.vertices[2]].z); - const Eigen::Matrix Q( - (*input_)[triangle_.vertices[1]].x - (*input_)[triangle_.vertices[2]].x, - (*input_)[triangle_.vertices[1]].y - (*input_)[triangle_.vertices[2]].y, - (*input_)[triangle_.vertices[1]].z - (*input_)[triangle_.vertices[2]].z); - area += 0.5 * P.cross(Q).norm(); - } - } - return area; -} - -template -inline float -pcl::computeTriangleMeshArea(const shared_ptr>& cloud, - const shared_ptr& indices, - std::vector& triangleMesh) -{ - const pcl::PointCloud::ConstPtr input_ = cloud; - double area = 0; - for (auto& triangle_ : triangleMesh) { - if (triangle_.vertices.size() == 3) { - const Eigen::Matrix P( - (*input_)[(*indices_)[triangle_.vertices[0]]].x - - (*input_)[(*indices_)[triangle_.vertices[2]]].x, - (*input_)[(*indices_)[triangle_.vertices[0]]].y - - (*input_)[(*indices_)[triangle_.vertices[2]]].y, - (*input_)[(*indices_)[triangle_.vertices[0]]].z - - (*input_)[(*indices_)[triangle_.vertices[2]]].z); - const Eigen::Matrix Q( - (*input_)[(*indices_)[triangle_.vertices[1]]].x - - (*input_)[(*indices_)[triangle_.vertices[2]]].x, - (*input_)[(*indices_)[triangle_.vertices[1]]].y - - (*input_)[(*indices_)[triangle_.vertices[2]]].y, - (*input_)[(*indices_)[triangle_.vertices[1]]].z - - (*input_)[(*indices_)[triangle_.vertices[2]]].z); - area += 0.5 * P.cross(Q).norm(); - } - } - return area; -} - #endif // PCL_SURFACE_IMPL_GP3_H_ diff --git a/test/surface/test_gp3.cpp b/test/surface/test_gp3.cpp index d7eed86d891..79acecaf497 100644 --- a/test/surface/test_gp3.cpp +++ b/test/surface/test_gp3.cpp @@ -238,6 +238,36 @@ TEST (PCL, UpdateMesh_With_TextureMapping) } } + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST(PCL, computeTriangleMeshArea) +{ + // Init objects + PolygonMesh triangles; + GreedyProjectionTriangulation gp3; + + // Set parameters + gp3.setInputCloud(cloud_with_normals); + gp3.setSearchMethod(tree2); + gp3.setSearchRadius(0.025); + gp3.setMu(2.5); + gp3.setMaximumNearestNeighbors(100); + gp3.setMaximumSurfaceAngle(M_PI / 4); // 45 degrees + gp3.setMinimumAngle(M_PI / 18); // 10 degrees + gp3.setMaximumAngle(2 * M_PI / 3); // 120 degrees + gp3.setNormalConsistency(false); + + // Reconstruct + gp3.reconstruct(triangles); + + float functArea = pcl::computeTriangleMeshArea(cloud_with_normals, triangles.polygons); + EXPECT_NEAR((functArea), 0.0210945, 0.001); + + +} + + /* ---[ */ int main (int argc, char** argv) From 3b7ce5f9d45491ce673d2101ba581ec27f3c9340 Mon Sep 17 00:00:00 2001 From: mynickmynick mynickmynick Date: Sun, 7 Jan 2024 11:41:08 +0100 Subject: [PATCH 3/3] completed test of computeTriangleMeshArea --- test/surface/test_gp3.cpp | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/test/surface/test_gp3.cpp b/test/surface/test_gp3.cpp index 79acecaf497..c821cab5e00 100644 --- a/test/surface/test_gp3.cpp +++ b/test/surface/test_gp3.cpp @@ -262,8 +262,83 @@ TEST(PCL, computeTriangleMeshArea) gp3.reconstruct(triangles); float functArea = pcl::computeTriangleMeshArea(cloud_with_normals, triangles.polygons); - EXPECT_NEAR((functArea), 0.0210945, 0.001); + EXPECT_NEAR((functArea), 0.021, 0.001); + + pcl::PointCloud::Ptr cloud_ (new pcl::PointCloud ()); + pcl::PointXYZ p; + p.x = p.y = p.z = 0.f; + cloud_->push_back (p); + + p.x = 1.f; + p.y = 0.f; + p.z = 0.f; + cloud_->push_back (p); + + p.x = 0.f; + p.y = 1.f; + p.z = 0.f; + cloud_->push_back (p); + + p.x = 1.f; + p.y = 1.f; + p.z = 0.f; + cloud_->push_back (p); + + p.x = 0.f; + p.y = 1.5f; + p.z = 0.5f; + cloud_->push_back (p); + + p.x = 1.f; + p.y = 1.5f; + p.z = 0.5f; + cloud_->push_back (p); + + cloud_->height = 1; + cloud_->width = cloud_->size (); + + search::KdTree::Ptr treeLoc; + // Create search tree + treeLoc.reset (new search::KdTree (false)); + treeLoc->setInputCloud (cloud_); + + // Normal estimation + NormalEstimation nLoc; + PointCloud::Ptr normalsLoc (new PointCloud ()); + nLoc.setInputCloud (cloud_); + //nLoc.setIndices (indices[B); + nLoc.setSearchMethod (treeLoc); + nLoc.setKSearch (20); + nLoc.compute (*normalsLoc); + + // Concatenate XYZ and normal information + PointCloud::Ptr cloud_with_normalsLoc (new PointCloud); + pcl::concatenateFields (*cloud_, *normalsLoc, *cloud_with_normalsLoc); + + // Create search tree + tree2.reset (new search::KdTree); + tree2->setInputCloud (cloud_with_normalsLoc); + + // Init objects + PolygonMesh trianglesLoc; + GreedyProjectionTriangulation gpLoc; + + // Set parameters + gpLoc.setInputCloud(cloud_with_normalsLoc); + gpLoc.setSearchMethod(tree2); + gpLoc.setSearchRadius(2.0); + gpLoc.setMu(2.5); + gpLoc.setMaximumNearestNeighbors(100); + gpLoc.setMaximumSurfaceAngle(M_PI / 4); // 45 degrees + gpLoc.setMinimumAngle(M_PI / 18); // 10 degrees + gpLoc.setMaximumAngle(2 * M_PI / 3); // 120 degrees + gpLoc.setNormalConsistency(false); + + // Reconstruct + gpLoc.reconstruct(trianglesLoc); + functArea = pcl::computeTriangleMeshArea(cloud_with_normalsLoc, trianglesLoc.polygons); + EXPECT_NEAR((functArea), 1.70710678, 0.1);//1+1*sqrt(0.5^2+0.5^2) Pythagoras th. }