Skip to content

Commit

Permalink
Merge pull request #5033 from rouault/fix_4040
Browse files Browse the repository at this point in the history
Enable using re-entrant qhull (refs #4040)
  • Loading branch information
rouault committed Dec 23, 2021
2 parents 06ab0b9 + 8e0b7d2 commit 0cda75f
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 51 deletions.
1 change: 1 addition & 0 deletions GDALmake.opt.in
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ SFCGAL_CFLAGS = @SFCGAL_CFLAGS@

QHULL_SETTING = @QHULL_SETTING@
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL = @QHULL_INCLUDE_SUBDIR_IS_LIBQHULL@
QHULL_IS_LIBQHULL_R = @QHULL_IS_LIBQHULL_R@

# GRASS Support

Expand Down
5 changes: 4 additions & 1 deletion alg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,14 @@ if (GDAL_ENABLE_QHULL)
target_include_directories(alg PRIVATE $<TARGET_PROPERTY:qhull,SOURCE_DIR>)
else ()
target_compile_definitions(alg PRIVATE -DEXTERNAL_QHULL)
if (QHULL_INCLUDE_SUBDIR STREQUAL "libqhull")
if (QHULL_INCLUDE_SUBDIR STREQUAL "libqhull_r")
target_compile_definitions(alg PRIVATE -DQHULL_IS_LIBQHULL_R=1)
elseif (QHULL_INCLUDE_SUBDIR STREQUAL "libqhull")
target_compile_definitions(alg PRIVATE -DQHULL_INCLUDE_SUBDIR_IS_LIBQHULL=1)
else ()
target_compile_definitions(alg PRIVATE -DQHULL_INCLUDE_SUBDIR_IS_LIBQHULL=0)
endif ()
target_include_directories(alg PRIVATE ${QHULL_INCLUDE_DIR})
gdal_add_private_link_libraries(${QHULL_LIBRARY})
endif ()
endif ()
Expand Down
4 changes: 4 additions & 0 deletions alg/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ CPPFLAGS := -DHAVE_ARMADILLO $(CPPFLAGS)
endif

ifeq ($(QHULL_SETTING),external)
ifeq ($(QHULL_IS_LIBQHULL_R),1)
CPPFLAGS := -DEXTERNAL_QHULL -DQHULL_IS_LIBQHULL_R=1 $(CPPFLAGS)
else
CPPFLAGS := -DEXTERNAL_QHULL -DQHULL_INCLUDE_SUBDIR_IS_LIBQHULL=$(QHULL_INCLUDE_SUBDIR_IS_LIBQHULL) $(CPPFLAGS)
endif
endif
ifeq ($(QHULL_SETTING),internal)
CPPFLAGS := -DINTERNAL_QHULL $(CPPFLAGS)
endif
Expand Down
67 changes: 49 additions & 18 deletions alg/delaunay.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ CPL_CVSID("$Id$")

#else /* INTERNAL_QHULL */

#if !defined(QHULL_INCLUDE_SUBDIR_IS_LIBQHULL)
#if defined(QHULL_IS_LIBQHULL_R)
#include "libqhull_r/libqhull_r.h"
#include "libqhull_r/qset_r.h"
#elif !defined(QHULL_INCLUDE_SUBDIR_IS_LIBQHULL)
#include "libqhull.h"
#include "qset.h"
#elif QHULL_INCLUDE_SUBDIR_IS_LIBQHULL
Expand All @@ -79,8 +82,10 @@ CPL_CVSID("$Id$")


#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
#if !defined(QHULL_IS_LIBQHULL_R)
static CPLMutex* hMutex = NULL;
#endif
#endif

/************************************************************************/
/* GDALHasTriangulation() */
Expand All @@ -101,6 +106,14 @@ int GDALHasTriangulation()
#endif
}

#if defined(QHULL_IS_LIBQHULL_R)
#define QH_MEMBER(qh, member) qh->member
#define QH_ARG qh,
#else
#define QH_MEMBER(qh, member) qh member
#define QH_ARG
#endif

/************************************************************************/
/* GDALTriangulationCreateDelaunay() */
/************************************************************************/
Expand Down Expand Up @@ -128,6 +141,12 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
int* panMapQHFacetIdToFacetIdx; /* map from QHull facet ID to the index of our GDALTriFacet* array */
int curlong, totlong; /* memory remaining after qh_memfreeshort */

#if defined(QHULL_IS_LIBQHULL_R)
qhT qh_qh;
qhT *qh= &qh_qh;

QHULL_LIB_CHECK /* Check for compatible library */
#else
/* QHull is not thread safe, so we need to protect all operations with a mutex */
CPLCreateOrAcquireMutex(&hMutex, 1000);

Expand All @@ -140,12 +159,15 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
CPLReleaseMutex(hMutex);
return NULL;
}
#endif
#endif

points = (coordT*)VSI_MALLOC2_VERBOSE(sizeof(double)*2, nPoints);
if( points == NULL )
{
#if !defined(QHULL_IS_LIBQHULL_R)
CPLReleaseMutex(hMutex);
#endif
return NULL;
}
for(i=0;i<nPoints;i++)
Expand All @@ -154,13 +176,18 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
points[2*i+1] = padfY[i];
}

#if defined(QHULL_IS_LIBQHULL_R)
qh_meminit(qh, NULL);
#endif

/* d: Delaunay */
/* Qbb: scale last coordinate to [0,m] for Delaunay */
/* Qc: keep coplanar points with nearest facet */
/* Qz: add a point-at-infinity for Delaunay triangulation */
/* Qt: triangulated output */
if( qh_new_qhull(2, nPoints, points, FALSE /* ismalloc */,
"qhull d Qbb Qc Qz Qt", NULL, stderr) != 0 )
if( qh_new_qhull(QH_ARG
2, nPoints, points, FALSE /* ismalloc */,
"qhull d Qbb Qc Qz Qt", NULL, stderr) != 0 )
{
VSIFree(points);
CPLError(CE_Failure, CPLE_AppDefined, "Delaunay triangulation failed");
Expand All @@ -179,31 +206,31 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
#endif

/* Establish a map from QHull facet id to the index in our array of sequential facets */
panMapQHFacetIdToFacetIdx = (int*)VSI_MALLOC2_VERBOSE(sizeof(int), qh facet_id);
panMapQHFacetIdToFacetIdx = (int*)VSI_MALLOC2_VERBOSE(sizeof(int), QH_MEMBER(qh, facet_id));
if( panMapQHFacetIdToFacetIdx == NULL )
{
goto end;
}
memset(panMapQHFacetIdToFacetIdx, 0xFF, sizeof(int) * qh facet_id);
memset(panMapQHFacetIdToFacetIdx, 0xFF, sizeof(int) * QH_MEMBER(qh, facet_id));

for(j = 0, facet = qh facet_list;
for(j = 0, facet = QH_MEMBER(qh, facet_list);
facet != NULL && facet->next != NULL;
facet = facet->next)
{
if( facet->upperdelaunay != qh UPPERdelaunay )
if( facet->upperdelaunay != QH_MEMBER(qh, UPPERdelaunay) )
continue;

if( qh_setsize(facet->vertices) != 3 ||
qh_setsize(facet->neighbors) != 3 )
if( qh_setsize(QH_ARG facet->vertices) != 3 ||
qh_setsize(QH_ARG facet->neighbors) != 3 )
{
CPLError(CE_Failure, CPLE_AppDefined,
"Triangulation resulted in non triangular facet %d: vertices=%d",
facet->id, qh_setsize(facet->vertices));
facet->id, qh_setsize(QH_ARG facet->vertices));
VSIFree(panMapQHFacetIdToFacetIdx);
goto end;
}

CPLAssert(facet->id < qh facet_id);
CPLAssert(facet->id < QH_MEMBER(qh, facet_id));
panMapQHFacetIdToFacetIdx[facet->id] = j++;
}

Expand All @@ -219,20 +246,20 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
psDT->pasFacets = pasFacets;

// Store vertex and neighbor information for each triangle.
for(facet = qh facet_list;
for(facet = QH_MEMBER(qh, facet_list);
facet != NULL && facet->next != NULL;
facet = facet->next)
{
int k;
if( facet->upperdelaunay != qh UPPERdelaunay )
if( facet->upperdelaunay != QH_MEMBER(qh, UPPERdelaunay) )
continue;
k = panMapQHFacetIdToFacetIdx[facet->id];
pasFacets[k].anVertexIdx[0] =
qh_pointid(((vertexT*) facet->vertices->e[0].p)->point);
qh_pointid(QH_ARG ((vertexT*) facet->vertices->e[0].p)->point);
pasFacets[k].anVertexIdx[1] =
qh_pointid(((vertexT*) facet->vertices->e[1].p)->point);
qh_pointid(QH_ARG ((vertexT*) facet->vertices->e[1].p)->point);
pasFacets[k].anVertexIdx[2] =
qh_pointid(((vertexT*) facet->vertices->e[2].p)->point);
qh_pointid(QH_ARG ((vertexT*) facet->vertices->e[2].p)->point);
pasFacets[k].anNeighborIdx[0] =
panMapQHFacetIdToFacetIdx[((facetT*) facet->neighbors->e[0].p)->id];
pasFacets[k].anNeighborIdx[1] =
Expand All @@ -244,10 +271,12 @@ GDALTriangulation* GDALTriangulationCreateDelaunay(int nPoints,
VSIFree(panMapQHFacetIdToFacetIdx);

end:
qh_freeqhull(!qh_ALL);
qh_memfreeshort(&curlong, &totlong);
qh_freeqhull(QH_ARG !qh_ALL);
qh_memfreeshort(QH_ARG &curlong, &totlong);

#if !defined(QHULL_IS_LIBQHULL_R)
CPLReleaseMutex(hMutex);
#endif

return psDT;
#else /* HAVE_INTERNAL_OR_EXTERNAL_QHULL */
Expand Down Expand Up @@ -634,10 +663,12 @@ int GDALTriangulationFindFacetDirected(const GDALTriangulation* psDT,
void GDALTriangulationTerminate()
{
#if HAVE_INTERNAL_OR_EXTERNAL_QHULL
#if !defined(QHULL_IS_LIBQHULL_R)
if( hMutex != NULL )
{
CPLDestroyMutex(hMutex);
hMutex = NULL;
}
#endif
#endif
}
3 changes: 3 additions & 0 deletions alg/makefile.vc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ EXTRAFLAGS = $(EXTRAFLAGS) -DINTERNAL_QHULL
!ELSE
!IF "$(QHULL_SETTING)" == "EXTERNAL"
EXTRAFLAGS = $(EXTRAFLAGS) -DEXTERNAL_QHULL $(QHULL_INC)
!IF "$(QHULL_IS_LIBQHULL_R)" == "1"
EXTRAFLAGS = $(EXTRAFLAGS) -DQHULL_IS_LIBQHULL_R=1
!ENDIF
!ENDIF
!ENDIF
!ENDIF
Expand Down
27 changes: 12 additions & 15 deletions cmake/modules/packages/FindQHULL.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,26 @@
# If it's found it sets QHULL_FOUND to TRUE
# and following variables are set:
# QHULL_INCLUDE_DIR
# QHULL_INCLUDE_SUBDIR (qhull/libqhull)
# QHULL_INCLUDE_SUBDIR (libqhull_r/qhull/libqhull)
# QHULL_LIBRARY
# QHULL_NEWQHULL (TRUE/FALSE)
#

find_path(QHULL_INCLUDE_DIR qhull/libqhull.h)
find_path(QHULL_INCLUDE_DIR libqhull_r/libqhull_r.h qhull/libqhull.h libqhull/libqhull.h)
if(QHULL_INCLUDE_DIR)
if(EXISTS ${QHULL_INCLUDE_DIR}/libqhull_r/libqhull_r.h)
set(QHULL_INCLUDE_SUBDIR "libqhull_r")
elseif(EXISTS ${QHULL_INCLUDE_DIR}/qhull/libqhull.h)
set(QHULL_INCLUDE_SUBDIR "qhull")
else()
find_path(LIBQHULL_INCLUDE_DIR libqhull/libqhull.h)
if(LIBQHULL_INCLUDE_DIR)
set(QHULL_INCLUDE_SUBDIR "libqhull")
endif()
elseif(EXISTS ${QHULL_INCLUDE_DIR}/libqhull/libqhull.h)
set(QHULL_INCLUDE_SUBDIR "libqhull")
else()
message(FATAL_ERROR "Cannot guess QHULL_INCLUDE_SUBDIR from QHULL_INCLUDE_DIR=${QHULL_INCLUDE_DIR}")
endif()
endif()

find_library(QHULL_LIBRARY NAMES qhull libqhull)
find_library(QHULL_LIBRARY NAMES qhull_r qhull libqhull)
mark_as_advanced(QHULL_INCLUDE_SUBDIR QHULL_INCLUDE_DIR QHULL_LIBRARY)

include(CheckLibraryExists)
check_library_exists(qhull gqh_new_qhull ${QHULL_LIBRARY} QHULL_NEWQHULL)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QHULL
REQUIRED_VARS QHULL_LIBRARY QHULL_INCLUDE_DIR
VERSION_VAR QHULL_NEWQHULL
)
REQUIRED_VARS QHULL_LIBRARY QHULL_INCLUDE_DIR)
42 changes: 27 additions & 15 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4677,24 +4677,35 @@ if test "$with_qhull" = "no" ; then

elif test "$with_qhull" = "yes" -o "$with_qhull" = "" ; then

# Only qhull 2012 is reliable on certain datasets. Older Ubuntu have
# qhull/qhull.h
AC_CHECK_HEADERS([qhull/libqhull.h])
if test "$ac_cv_header_qhull_libqhull_h" = "yes"; then
AC_CHECK_LIB(qhull,qh_new_qhull,QHULL_SETTING=yes,QHULL_SETTING=no,)
AC_CHECK_HEADERS([libqhull_r/libqhull_r.h])
if test "$ac_cv_header_libqhull_r_libqhull_r_h" = "yes"; then
AC_CHECK_LIB(qhull_r,qh_new_qhull,QHULL_SETTING=yes,QHULL_SETTING=no,)
if test "$QHULL_SETTING" = "yes"; then
QHULL_SETTING=external
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL=0
LIBS="-lqhull $LIBS"
QHULL_IS_LIBQHULL_R=1
LIBS="-lqhull_r $LIBS"
fi
fi
AC_CHECK_HEADERS([libqhull/libqhull.h])
if test "$ac_cv_header_libqhull_libqhull_h" = "yes"; then
AC_CHECK_LIB(qhull,qh_new_qhull,QHULL_SETTING=yes,QHULL_SETTING=no,)
if test "$QHULL_SETTING" = "yes"; then
QHULL_SETTING=external
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL=1
LIBS="-lqhull $LIBS"
else
# Only qhull 2012 is reliable on certain datasets. Older Ubuntu have
# qhull/qhull.h
AC_CHECK_HEADERS([qhull/libqhull.h])
if test "$ac_cv_header_qhull_libqhull_h" = "yes"; then
AC_CHECK_LIB(qhull,qh_new_qhull,QHULL_SETTING=yes,QHULL_SETTING=no,)
if test "$QHULL_SETTING" = "yes"; then
QHULL_SETTING=external
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL=0
LIBS="-lqhull $LIBS"
fi
fi

AC_CHECK_HEADERS([libqhull/libqhull.h])
if test "$ac_cv_header_libqhull_libqhull_h" = "yes"; then
AC_CHECK_LIB(qhull,qh_new_qhull,QHULL_SETTING=yes,QHULL_SETTING=no,)
if test "$QHULL_SETTING" = "yes"; then
QHULL_SETTING=external
QHULL_INCLUDE_SUBDIR_IS_LIBQHULL=1
LIBS="-lqhull $LIBS"
fi
fi
fi

Expand All @@ -4713,6 +4724,7 @@ fi

AC_SUBST([QHULL_SETTING],$QHULL_SETTING)
AC_SUBST([QHULL_INCLUDE_SUBDIR_IS_LIBQHULL],$QHULL_INCLUDE_SUBDIR_IS_LIBQHULL)
AC_SUBST([QHULL_IS_LIBQHULL_R],$QHULL_IS_LIBQHULL_R)

dnl ---------------------------------------------------------------------------
dnl Check if opencl library is available.
Expand Down
24 changes: 24 additions & 0 deletions doc/source/build_hints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,30 @@ PROJ >= 6 is a required dependency for GDAL.
building Debug releases.


QHULL
*****

The QHULL library is used for the linear interpolation of gdal_grid. If not
found, an internal copy is used.

.. option:: QHULL_INCLUDE_DIR

Path to an include directory with the ``libqhull_r/libqhull_r.h``, ``qhull_r/libqhull.h`` or ``libqhull/libqhull.h`` header file.

.. option:: QHULL_LIBRARY

Path to a shared or static library file.

.. option:: GDAL_USE_QHULL=ON/OFF

Control whether to use QHULL. Defaults to ON when QHULL is found.

.. option:: GDAL_USE_QHULL_INTERNAL=ON/OFF

Control whether to use internal QHULL copy. Defaults to ON when external
QHULL is not found.


RASTERLITE2
***********

Expand Down
8 changes: 6 additions & 2 deletions nmake.opt
Original file line number Diff line number Diff line change
Expand Up @@ -890,12 +890,16 @@ OCI_INCLUDE = -I$(ORACLE_HOME)\oci\include

# QHull configuration. By default use internal libqhull.
# QHULL_SETTING can be set to INTERNAL, EXTERNAL or NO
# For external qhull, use qhull 2012
# For external qhull, use qhull 2012 or later
!IFNDEF QHULL_SETTING
QHULL_SETTING = INTERNAL
!ENDIF
# To be defined if QHULL_SETTING=EXTERNAL
# QHULL_INC = -I....
# To be defined if QHULL_SETTING=EXTERNAL and re-entrant qhull (qhull_r)
# QHULL_IS_LIBQHULL_R = 1
# To be defined if QHULL_SETTING=EXTERNAL
# QHULL_LIB = path_to_libqhull.lib

# Cryptopp stuff.
# Make sure cryptopp is compiled with /MD ( Properties | Configuration properties | C/C++ | Code Generation | Runtime Library: Multi-threaded DLL (/MD))
Expand Down Expand Up @@ -1185,5 +1189,5 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \
$(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \
$(LIBICONV_LIBRARY) $(WEBP_LIBS) $(TILEDB_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \
$(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) $(CHARLS_LIB) ws2_32.lib \
$(RDB_LIB) $(CRUNCH_LIB) $(OPENEXR_LIB) $(HEIF_LIB) $(LERC_LIB) $(JXL_LIB) $(BROTLI_LIB) $(BRUNSLI_LIB)\
$(RDB_LIB) $(CRUNCH_LIB) $(OPENEXR_LIB) $(HEIF_LIB) $(LERC_LIB) $(JXL_LIB) $(BROTLI_LIB) $(BRUNSLI_LIB) $(QHULL_LIB) \
kernel32.lib psapi.lib wbemuuid.lib

0 comments on commit 0cda75f

Please sign in to comment.