Skip to content

Commit

Permalink
Switch to reentrant qhull 2020 8.0.2.
Browse files Browse the repository at this point in the history
(the current version)

Co-authored-by: Ian Thomas <ianthomas23@gmail.com>
  • Loading branch information
anntzer and ianthomas23 committed Jan 12, 2021
1 parent 760dd03 commit dbe44f8
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 27 deletions.
16 changes: 9 additions & 7 deletions INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,15 @@ etc., you can install the following:
FreeType and Qhull
------------------

Matplotlib depends on `FreeType <https://www.freetype.org/>`_ (>=
2.3), a font rendering library, and on `Qhull
<http://www.qhull.org/>`_ (>= 2015.2), a library for computing
triangulations. By default (except on AIX) Matplotlib downloads and
builds its own copy of FreeType (this is necessary to run the test
suite, because different versions of FreeType rasterize characters
differently), and uses its own copy of Qhull.
Matplotlib depends on FreeType_ (>= 2.3), a font rendering library, and on
Qhull_ (>= 2020.2), a library for computing triangulations. By default,
Matplotlib downloads and builds its own copies of FreeType (this is necessary
to run the test suite, because different versions of FreeType rasterize
characters differently) and of Qhull. As an exception, Matplotlib defaults to
the system version of FreeType on AIX.

.. _FreeType: https://www.freetype.org/
.. _Qhull: http://www.qhull.org/

To force Matplotlib to use a copy of FreeType or Qhull already installed in
your system, create a :file:`setup.cfg` file with the following contents:
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_triangulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ def z(x, y):
matest.assert_array_almost_equal(interpz, interp_z0[interp_key])


@image_comparison(['tri_smooth_contouring.png'], remove_text=True, tol=0.07)
@image_comparison(['tri_smooth_contouring.png'], remove_text=True, tol=0.072)
def test_tri_smooth_contouring():
# Image comparison based on example tricontour_smooth_user.
n_angles = 20
Expand Down
2 changes: 1 addition & 1 deletion lib/mpl_toolkits/tests/test_mplot3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def test_contourf3d_fill():
ax.set_zlim(-1, 1)


@mpl3d_image_comparison(['tricontour.png'])
@mpl3d_image_comparison(['tricontour.png'], tol=0.02)
def test_tricontour():
fig = plt.figure()

Expand Down
7 changes: 4 additions & 3 deletions setup.cfg.template
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ license_files = LICENSE/*
# By default, Matplotlib builds with LTO, which may be slow if you re-compile
# often, and don't need the space saving/speedup.
#enable_lto = True
# By default, Matplotlib downloads and builds its own copy of FreeType, and
# builds its own copy of Qhull. You may set the following to True to instead
# link against a system FreeType/Qhull.
# By default, Matplotlib downloads and builds its own copies of FreeType and of
# of Qhull. You may set the following to True to instead link against a system
# FreeType/Qhull. As an exception, Matplotlib defaults to the system version
# of FreeType on AIX.
#system_freetype = False
#system_qhull = False

Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def __init__(self, dist):


def _download_qhull_to(dest):
url = "http://www.qhull.org/download/qhull-2015-src-7.2.0.tgz"
sha = "78b010925c3b577adc3d58278787d7df08f7c8fb02c3490e375eab91bb58a436"
url = "http://www.qhull.org/download/qhull-2020-src-8.0.2.tgz"
sha = "b5c2d7eb833278881b952c8a52d20179eab87766b00b865000469a45c1838b7e"
if (dest / f"qhull-{LOCAL_QHULL_VERSION}").exists():
return
dest.mkdir(parents=True, exist_ok=True)
Expand Down
4 changes: 2 additions & 2 deletions setupext.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def download_or_cache(url, sha):
LOCAL_FREETYPE_VERSION = '2.6.1'
LOCAL_FREETYPE_HASH = _freetype_hashes.get(LOCAL_FREETYPE_VERSION, 'unknown')

LOCAL_QHULL_VERSION = '2015.2'
LOCAL_QHULL_VERSION = '2020.2'


# matplotlib build options, which can be altered using setup.cfg
Expand Down Expand Up @@ -517,7 +517,7 @@ def add_qhull_flags(ext):
else:
qhull_path = Path(f'extern/qhull-{LOCAL_QHULL_VERSION}/src')
ext.include_dirs.insert(0, str(qhull_path))
ext.sources.extend(map(str, sorted(qhull_path.glob('libqhull/*.c'))))
ext.sources.extend(map(str, sorted(qhull_path.glob('libqhull_r/*.c'))))
if sysconfig.get_config_var("LIBM") == "-lm":
ext.libraries.extend("m")

Expand Down
25 changes: 14 additions & 11 deletions src/qhull_wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "numpy/ndarrayobject.h"
#include "libqhull/qhull_a.h"
#include "libqhull_r/qhull_ra.h"
#include <stdio.h>


Expand All @@ -32,11 +32,11 @@ static const char* qhull_error_msg[6] = {
/* Return the indices of the 3 vertices that comprise the specified facet (i.e.
* triangle). */
static void
get_facet_vertices(const facetT* facet, int indices[3])
get_facet_vertices(qhT* qh, const facetT* facet, int indices[3])
{
vertexT *vertex, **vertexp;
FOREACHvertex_(facet->vertices)
*indices++ = qh_pointid(vertex->point);
*indices++ = qh_pointid(qh, vertex->point);
}

/* Return the indices of the 3 triangles that are neighbors of the specified
Expand Down Expand Up @@ -88,6 +88,8 @@ static PyObject*
delaunay_impl(int npoints, const double* x, const double* y,
int hide_qhull_errors)
{
qhT qh_qh; /* qh variable type and name must be like */
qhT* qh = &qh_qh; /* this for Qhull macros to work correctly. */
coordT* points = NULL;
facetT* facet;
int i, ntri, max_facet_id;
Expand Down Expand Up @@ -148,7 +150,8 @@ delaunay_impl(int npoints, const double* x, const double* y,
}

/* Perform Delaunay triangulation. */
exitcode = qh_new_qhull(ndim, npoints, points, False,
qh_zero(qh, error_file);
exitcode = qh_new_qhull(qh, ndim, npoints, points, False,
"qhull d Qt Qbb Qc Qz", NULL, error_file);
if (exitcode != qh_ERRnone) {
PyErr_Format(PyExc_RuntimeError,
Expand All @@ -159,7 +162,7 @@ delaunay_impl(int npoints, const double* x, const double* y,
}

/* Split facets so that they only have 3 points each. */
qh_triangulate();
qh_triangulate(qh);

/* Determine ntri and max_facet_id.
Note that libqhull uses macros to iterate through collections. */
Expand All @@ -169,7 +172,7 @@ delaunay_impl(int npoints, const double* x, const double* y,
++ntri;
}

max_facet_id = qh facet_id - 1;
max_facet_id = qh->facet_id - 1;

/* Create array to map facet id to triangle index. */
tri_indices = (int*)malloc((max_facet_id+1)*sizeof(int));
Expand Down Expand Up @@ -204,7 +207,7 @@ delaunay_impl(int npoints, const double* x, const double* y,
FORALLfacets {
if (!facet->upperdelaunay) {
tri_indices[facet->id] = i++;
get_facet_vertices(facet, indices);
get_facet_vertices(qh, facet, indices);
*triangles_ptr++ = (facet->toporient ? indices[0] : indices[2]);
*triangles_ptr++ = indices[1];
*triangles_ptr++ = (facet->toporient ? indices[2] : indices[0]);
Expand All @@ -224,8 +227,8 @@ delaunay_impl(int npoints, const double* x, const double* y,
}

/* Clean up. */
qh_freeqhull(!qh_ALL);
qh_memfreeshort(&curlong, &totlong);
qh_freeqhull(qh, !qh_ALL);
qh_memfreeshort(qh, &curlong, &totlong);
if (curlong || totlong)
PyErr_WarnEx(PyExc_RuntimeWarning,
"Qhull could not free all allocated memory", 1);
Expand All @@ -243,8 +246,8 @@ delaunay_impl(int npoints, const double* x, const double* y,
/* Clean up. */
Py_XDECREF(triangles);
Py_XDECREF(neighbors);
qh_freeqhull(!qh_ALL);
qh_memfreeshort(&curlong, &totlong);
qh_freeqhull(qh, !qh_ALL);
qh_memfreeshort(qh, &curlong, &totlong);
/* Don't bother checking curlong and totlong as raising error anyway. */
if (hide_qhull_errors)
fclose(error_file);
Expand Down

0 comments on commit dbe44f8

Please sign in to comment.