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);