diff --git a/INSTALL.rst b/INSTALL.rst
index 387df87e3198..e4cea0ec9ad1 100644
--- a/INSTALL.rst
+++ b/INSTALL.rst
@@ -220,13 +220,15 @@ etc., you can install the following:
FreeType and Qhull
------------------
-Matplotlib depends on `FreeType `_ (>=
-2.3), a font rendering library, and on `Qhull
-`_ (>= 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:
diff --git a/lib/matplotlib/tests/test_triangulation.py b/lib/matplotlib/tests/test_triangulation.py
index cd46b954785c..dacbfd39c154 100644
--- a/lib/matplotlib/tests/test_triangulation.py
+++ b/lib/matplotlib/tests/test_triangulation.py
@@ -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
diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py
index 34562fa1324d..20316c82a8c1 100644
--- a/lib/mpl_toolkits/tests/test_mplot3d.py
+++ b/lib/mpl_toolkits/tests/test_mplot3d.py
@@ -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()
diff --git a/setup.cfg.template b/setup.cfg.template
index 00ae11c7a4a0..19b25641ffb9 100644
--- a/setup.cfg.template
+++ b/setup.cfg.template
@@ -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
diff --git a/setup.py b/setup.py
index 0d656d277c61..99b57506cc5f 100644
--- a/setup.py
+++ b/setup.py
@@ -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)
diff --git a/setupext.py b/setupext.py
index 9e00f9be22ce..350e39ebddf9 100644
--- a/setupext.py
+++ b/setupext.py
@@ -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
@@ -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")
diff --git a/src/qhull_wrap.c b/src/qhull_wrap.c
index 8545cc3c314c..0f7b3938299c 100644
--- a/src/qhull_wrap.c
+++ b/src/qhull_wrap.c
@@ -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
@@ -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
@@ -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;
@@ -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,
@@ -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. */
@@ -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));
@@ -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]);
@@ -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);
@@ -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);