Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reentrant qhull #4540

Merged
merged 16 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from 15 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
2 changes: 0 additions & 2 deletions .ci/azure-pipelines/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ stages:
CC: gcc
CXX: g++
BUILD_GPU: OFF
# surface is not ready for re-entrant QHull
CMAKE_ARGS: '-DBUILD_tests_surface=OFF'
container: $[ variables['CONTAINER'] ]
timeoutInMinutes: 0
variables:
Expand Down
12 changes: 4 additions & 8 deletions cmake/Modules/FindQhull.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
# If QHULL_USE_STATIC is specified then look for static libraries ONLY else
# look for shared ones

set(QHULL_MAJOR_VERSION 6)

if(QHULL_USE_STATIC)
set(QHULL_RELEASE_NAME qhullstatic)
set(QHULL_DEBUG_NAME qhullstatic_d)
set(QHULL_RELEASE_NAME qhullstatic_r)
set(QHULL_DEBUG_NAME qhullstatic_rd)
else()
set(QHULL_RELEASE_NAME qhull_p qhull${QHULL_MAJOR_VERSION} qhull)
set(QHULL_DEBUG_NAME qhull_p_d qhull${QHULL_MAJOR_VERSION}_d qhull_d${QHULL_MAJOR_VERSION} qhull_d)
set(QHULL_RELEASE_NAME qhull_r qhull)
set(QHULL_DEBUG_NAME qhull_rd qhull_d)
endif()

find_file(QHULL_HEADER
Expand All @@ -30,10 +28,8 @@ set(QHULL_HEADER "${QHULL_HEADER}" CACHE INTERNAL "QHull header" FORCE )
if(QHULL_HEADER)
get_filename_component(qhull_header ${QHULL_HEADER} NAME_WE)
if("${qhull_header}" STREQUAL "qhull")
set(HAVE_QHULL_2011 OFF)
get_filename_component(QHULL_INCLUDE_DIR ${QHULL_HEADER} PATH)
elseif("${qhull_header}" STREQUAL "libqhull")
set(HAVE_QHULL_2011 ON)
get_filename_component(QHULL_INCLUDE_DIR ${QHULL_HEADER} PATH)
get_filename_component(QHULL_INCLUDE_DIR ${QHULL_INCLUDE_DIR} PATH)
endif()
Expand Down
2 changes: 0 additions & 2 deletions pcl_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@

#cmakedefine HAVE_QHULL 1

#cmakedefine HAVE_QHULL_2011 1

#cmakedefine HAVE_CUDA 1

#cmakedefine HAVE_ENSENSO 1
Expand Down
4 changes: 2 additions & 2 deletions surface/include/pcl/surface/convex_hull.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ namespace pcl
using PointCloudConstPtr = typename PointCloud::ConstPtr;

/** \brief Empty constructor. */
ConvexHull () : compute_area_ (false), total_area_ (0), total_volume_ (0), dimension_ (0),
ConvexHull () : compute_area_ (false), total_area_ (0), total_volume_ (0), dimension_ (0),
projection_angle_thresh_ (std::cos (0.174532925) ), qhull_flags ("qhull "),
x_axis_ (1.0, 0.0, 0.0), y_axis_ (0.0, 1.0, 0.0), z_axis_ (0.0, 0.0, 1.0)
{
};
}

/** \brief Empty destructor */
~ConvexHull () {}
Expand Down
49 changes: 27 additions & 22 deletions surface/include/pcl/surface/impl/concave_hull.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,13 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
points[i * dim_ + 2] = static_cast<coordT> (cloud_transformed[i].z);
}

qhT qh_qh;
qhT* qh = &qh_qh;
QHULL_LIB_CHECK
qh_zero(qh, errfile);

// Compute concave hull
exitcode = qh_new_qhull (dim_, static_cast<int> (cloud_transformed.size ()), points, ismalloc, flags, outfile, errfile);
exitcode = qh_new_qhull (qh, dim_, static_cast<int> (cloud_transformed.size ()), points, ismalloc, flags, outfile, errfile);

if (exitcode != 0)
{
Expand Down Expand Up @@ -227,16 +232,16 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
alpha_shape.width = alpha_shape.height = 0;
polygons.resize (0);

qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

return;
}

qh_setvoronoi_all ();
qh_setvoronoi_all (qh);

int num_vertices = qh num_vertices;
int num_vertices = qh->num_vertices;
alpha_shape.resize (num_vertices);

vertexT *vertex;
Expand All @@ -253,11 +258,11 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
++max_vertex_id;
std::vector<int> qhid_to_pcidx (max_vertex_id);

int num_facets = qh num_facets;
int num_facets = qh->num_facets;

if (dim_ == 3)
{
setT *triangles_set = qh_settemp (4 * num_facets);
setT *triangles_set = qh_settemp (qh, 4 * num_facets);
if (voronoi_centers_)
voronoi_centers_->points.resize (num_facets);

Expand All @@ -283,29 +288,29 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
if (r <= alpha_)
{
// all triangles in tetrahedron are good, add them all to the alpha shape (triangles_set)
qh_makeridges (facet);
qh_makeridges (qh, facet);
facet->good = true;
facet->visitid = qh visit_id;
facet->visitid = qh->visit_id;
ridgeT *ridge, **ridgep;
FOREACHridge_ (facet->ridges)
{
facetT *neighb = otherfacet_ (ridge, facet);
if ((neighb->visitid != qh visit_id))
qh_setappend (&triangles_set, ridge);
if ((neighb->visitid != qh->visit_id))
qh_setappend (qh, &triangles_set, ridge);
}
}
else
{
// consider individual triangles from the tetrahedron...
facet->good = false;
facet->visitid = qh visit_id;
qh_makeridges (facet);
facet->visitid = qh->visit_id;
qh_makeridges (qh, facet);
ridgeT *ridge, **ridgep;
FOREACHridge_ (facet->ridges)
{
facetT *neighb;
neighb = otherfacet_ (ridge, facet);
if ((neighb->visitid != qh visit_id))
if ((neighb->visitid != qh->visit_id))
{
// check if individual triangle is good and add it to triangles_set

Expand All @@ -322,7 +327,7 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:

double r = pcl::getCircumcircleRadius (a, b, c);
if (r <= alpha_)
qh_setappend (&triangles_set, ridge);
qh_setappend (qh, &triangles_set, ridge);
}
}
}
Expand Down Expand Up @@ -354,7 +359,7 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
{
polygons[triangles].vertices.resize (3);
int vertex_n, vertex_i;
FOREACHvertex_i_ ((*ridge).vertices) //3 vertices per ridge!
FOREACHvertex_i_ (qh, (*ridge).vertices) //3 vertices per ridge!
{
if (!added_vertices[vertex->id])
{
Expand Down Expand Up @@ -383,7 +388,7 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
{
// Compute the alpha complex for the set of points
// Filters the delaunay triangles
setT *edges_set = qh_settemp (3 * num_facets);
setT *edges_set = qh_settemp (qh, 3 * num_facets);
if (voronoi_centers_)
voronoi_centers_->points.resize (num_facets);

Expand All @@ -403,12 +408,12 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
if (r <= alpha_)
{
pcl::Vertices facet_vertices; //TODO: is not used!!
qh_makeridges (facet);
qh_makeridges (qh, facet);
facet->good = true;

ridgeT *ridge, **ridgep;
FOREACHridge_ (facet->ridges)
qh_setappend (&edges_set, ridge);
qh_setappend (qh, &edges_set, ridge);

if (voronoi_centers_)
{
Expand Down Expand Up @@ -438,7 +443,7 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
std::vector<int> pcd_indices;
pcd_indices.resize (2);

FOREACHvertex_i_ ((*ridge).vertices) //in 2-dim, 2 vertices per ridge!
FOREACHvertex_i_ (qh, (*ridge).vertices) //in 2-dim, 2 vertices per ridge!
{
if (!added_vertices[vertex->id])
{
Expand Down Expand Up @@ -540,9 +545,9 @@ pcl::ConcaveHull<PointInT>::performReconstruction (PointCloud &alpha_shape, std:
voronoi_centers_->points.resize (dd);
}

qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

Eigen::Affine3d transInverse = transform1.inverse ();
pcl::transformPointCloud (alpha_shape, alpha_shape, transInverse);
Expand Down
66 changes: 34 additions & 32 deletions surface/include/pcl/surface/impl/convex_hull.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,8 @@ pcl::ConvexHull<PointInT>::performReconstruction2D (PointCloud &hull, std::vecto
// output from qh_produce_output(), use NULL to skip qh_produce_output()
FILE *outfile = nullptr;

#ifndef HAVE_QHULL_2011
if (compute_area_)
outfile = stderr;
#endif

// option flags for qhull, see qh_opt.htm
const char* flags = qhull_flags.c_str ();
Expand Down Expand Up @@ -180,40 +178,43 @@ pcl::ConvexHull<PointInT>::performReconstruction2D (PointCloud &hull, std::vecto
// This should only happen if we had invalid input
PCL_ERROR ("[pcl::%s::performReconstruction2D] Invalid input!\n", getClassName ().c_str ());
}

qhT qh_qh;
qhT* qh = &qh_qh;
QHULL_LIB_CHECK
qh_zero(qh, errfile);

// Compute convex hull
int exitcode = qh_new_qhull (dimension, static_cast<int> (indices_->size ()), points, ismalloc, const_cast<char*> (flags), outfile, errfile);
#ifdef HAVE_QHULL_2011
int exitcode = qh_new_qhull (qh, dimension, static_cast<int> (indices_->size ()), points, ismalloc, const_cast<char*> (flags), outfile, errfile);
if (compute_area_)
{
qh_prepare_output();
qh_prepare_output(qh);
}
#endif

// 0 if no error from qhull or it doesn't find any vertices
if (exitcode != 0 || qh num_vertices == 0)
if (exitcode != 0 || qh->num_vertices == 0)
{
PCL_ERROR ("[pcl::%s::performReconstrution2D] ERROR: qhull was unable to compute a convex hull for the given point cloud (%lu)!\n", getClassName ().c_str (), indices_->size ());

hull.resize (0);
hull.width = hull.height = 0;
polygons.resize (0);

qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

return;
}

// Qhull returns the area in volume for 2D
if (compute_area_)
{
total_area_ = qh totvol;
total_area_ = qh->totvol;
total_volume_ = 0.0;
}

int num_vertices = qh num_vertices;
int num_vertices = qh->num_vertices;

hull.clear();
hull.resize(num_vertices, PointInT{});
Expand All @@ -225,8 +226,8 @@ pcl::ConvexHull<PointInT>::performReconstruction2D (PointCloud &hull, std::vecto

FORALLvertices
{
hull[i] = (*input_)[(*indices_)[qh_pointid (vertex->point)]];
idx_points[i].first = qh_pointid (vertex->point);
hull[i] = (*input_)[(*indices_)[qh_pointid (qh, vertex->point)]];
idx_points[i].first = qh_pointid (qh, vertex->point);
++i;
}

Expand Down Expand Up @@ -273,9 +274,9 @@ pcl::ConvexHull<PointInT>::performReconstruction2D (PointCloud &hull, std::vecto
polygons[0].vertices[j] = static_cast<unsigned int> (j);
}

qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

hull.width = hull.size ();
hull.height = 1;
Expand All @@ -298,10 +299,8 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (
// output from qh_produce_output(), use NULL to skip qh_produce_output()
FILE *outfile = nullptr;

#ifndef HAVE_QHULL_2011
if (compute_area_)
outfile = stderr;
#endif

// option flags for qhull, see qh_opt.htm
const char *flags = qhull_flags.c_str ();
Expand All @@ -319,14 +318,17 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (
points[j + 2] = static_cast<coordT> ((*input_)[(*indices_)[i]].z);
}

qhT qh_qh;
qhT* qh = &qh_qh;
QHULL_LIB_CHECK
qh_zero(qh, errfile);

// Compute convex hull
int exitcode = qh_new_qhull (dimension, static_cast<int> (indices_->size ()), points, ismalloc, const_cast<char*> (flags), outfile, errfile);
#ifdef HAVE_QHULL_2011
int exitcode = qh_new_qhull (qh, dimension, static_cast<int> (indices_->size ()), points, ismalloc, const_cast<char*> (flags), outfile, errfile);
if (compute_area_)
{
qh_prepare_output();
qh_prepare_output(qh);
}
#endif

// 0 if no error from qhull
if (exitcode != 0)
Expand All @@ -340,18 +342,18 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (
hull.width = hull.height = 0;
polygons.resize (0);

qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

return;
}

qh_triangulate ();
qh_triangulate (qh);

int num_facets = qh num_facets;
int num_facets = qh->num_facets;

int num_vertices = qh num_vertices;
int num_vertices = qh->num_vertices;
hull.resize (num_vertices);

vertexT * vertex;
Expand All @@ -374,7 +376,7 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (
FORALLvertices
{
// Add vertices to hull point_cloud and store index
hull_indices_.indices.push_back ((*indices_)[qh_pointid (vertex->point)]);
hull_indices_.indices.push_back ((*indices_)[qh_pointid (qh, vertex->point)]);
hull[i] = (*input_)[hull_indices_.indices.back ()];

qhid_to_pcidx[vertex->id] = i; // map the vertex id of qhull to the point cloud index
Expand All @@ -383,8 +385,8 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (

if (compute_area_)
{
total_area_ = qh totarea;
total_volume_ = qh totvol;
total_area_ = qh->totarea;
total_volume_ = qh->totvol;
}

if (fill_polygon_data)
Expand All @@ -399,16 +401,16 @@ pcl::ConvexHull<PointInT>::performReconstruction3D (

// Needed by FOREACHvertex_i_
int vertex_n, vertex_i;
FOREACHvertex_i_ ((*facet).vertices)
FOREACHvertex_i_ (qh, (*facet).vertices)
//facet_vertices.vertices.push_back (qhid_to_pcidx[vertex->id]);
polygons[dd].vertices[vertex_i] = qhid_to_pcidx[vertex->id];
++dd;
}
}
// Deallocates memory (also the points)
qh_freeqhull (!qh_ALL);
qh_freeqhull (qh, !qh_ALL);
int curlong, totlong;
qh_memfreeshort (&curlong, &totlong);
qh_memfreeshort (qh, &curlong, &totlong);

hull.width = hull.size ();
hull.height = 1;
Expand Down
Loading