Skip to main content

Fast sweep-hull (S-hull) Delaunay triangulation in 2D and 3D, implemented in Rust

Project description

shull

S-hull: a fast sweep-hull routine for Delaunay triangulation by David Sinclair (see http://www.s-hull.org/) implemented in Rust with Python bindings.

The 2D case implements S-hull proper: a seed triangle with the smallest circumcircle, a radial sweep over points sorted by distance from its circumcenter, hull attachment via a linked ring with a pseudo-angle hash, and in-circle edge flipping to restore the Delaunay condition.

The 3D case generalizes Sinclair's Newton Apple Wrapper sweep-hull algorithm (arXiv 1602.04707) one dimension up: points are lifted onto a 4D paraboloid (w = x² + y² + z²), the 4D convex hull is computed by incremental insertion along a Morton (Z-order) space-filling curve — every lifted point is extreme on the paraboloid, so any insertion order is valid, and the spatially local one keeps the hull walk cache-hot — and the downward-facing facets are exactly the Delaunay tetrahedra.

In both cases all combinatorial decisions (visibility, in-circle/in-sphere tests) fall back to Shewchuk's exact adaptive predicates (the robust crate) — so the triangulation stays valid even on adversarial inputs (cospherical grids, tight clusters far apart) where plain floating point corrupts the result.

TODOs

  • implementation for the 2d case
  • generalize from 2 to N dimensions: 3D Delaunay (tetrahedra) via 4D sweep-hull
  • improve 2d performance: ~10X faster than scipy's Qhull-based Delaunay
  • improve 3d performance: ~3–5.5X faster than scipy
  • scipy-compatible API: neighbors, convex_hull, vertex_neighbor_vertices, transform, find_simplex, …

Build

  1. cd into directory
  2. Activate virtual environment: source .venv/bin/activate
  3. Run maturin develop (use maturin build --release to build wheel)

Test / benchmark

cargo test                      # Rust unit tests (incl. hull invariant checks)
python -m pytest tests/        # property tests + comparison against scipy
python bench.py                # benchmark against scipy.spatial.Delaunay

Benchmark on an Apple-silicon laptop (random uniform points, release build):

2D (Delaunay vs scipy.spatial.Delaunay)

n shull scipy (Qhull) speedup
10 000 0.002 s 0.018 s 9.8×
100 000 0.029 s 0.30 s 10.7×
1 000 000 0.46 s 5.0 s 10.9×

3D (Delaunay3d vs scipy.spatial.Delaunay)

n shull scipy (Qhull) speedup
10 000 0.031 s 0.098 s 3.2×
100 000 0.32 s 1.69 s 5.3×
1 000 000 3.8 s 20.8 s 5.5×

Usage

2D

>>> import shull
>>> import numpy as np
>>> pts = np.random.default_rng(12345).random((10000, 2))
>>> d = shull.Delaunay(pts)
>>> d.triangles          # alias: d.simplices
array([[5790, 4665, 8764],
       [4665, 9599, 8764],
       [7711,   64, 4665],
       ...,
       [2821, 8418, 1189],
       [1500, 9364, 8681],
       [5462, 1500, 8681]], dtype=int32)

3D

>>> pts = np.random.default_rng(12345).random((10000, 3))
>>> d = shull.Delaunay(pts)  # dispatches on the number of columns;
>>> d.simplices              # Delaunay3d is kept as an explicit alias
array([[3661, 6693, 7492, 1937],
       ...], dtype=int32)

scipy compatibility

shull.Delaunay aims to be a drop-in replacement for scipy.spatial.Delaunay. Beyond points and simplices (int32, like scipy) it provides the derived structures. neighbors comes straight out of the triangulation (the hull construction maintains facet adjacency anyway, so exporting it is essentially free, like qhull) and vertex_neighbor_vertices is built in Rust on first access (~2x faster than scipy's); the rest are computed lazily in numpy and cached:

  • neighbors — neighboring simplex opposite each vertex, -1 at the boundary
  • convex_hull — facets of the convex hull
  • vertex_to_simplex — a simplex containing each vertex
  • vertex_neighbor_vertices — CSR (indptr, indices) vertex adjacency
  • coplanar — points not in the triangulation (dropped exact duplicates), mapped to their kept representative; recorded by the Rust core during its dedup, not reconstructed after the fact
  • transform — barycentric transforms, same layout as scipy
  • find_simplex(xi, bruteforce=False, tol=None) — point location via a vectorized visibility walk (brute force as option/fallback)
  • npoints, nsimplex, ndim, min_bound, max_bound, furthest_site, close()

Not implemented: equations (and paraboloid_scale/paraboloid_shift, plane_distance, lift_points), incremental mode (add_points), furthest_site=True and qhull_options — the constructor accepts scipy's keyword arguments but raises NotImplementedError for non-default values. Unlike scipy, float32 points are kept as float32 (see below).

Notes (both dimensions):

  • Output simplices are positively oriented (counterclockwise triangles in 2D, positive-volume tetrahedra in 3D) and index into points.
  • float32 input is supported natively: no upcast copy is made (d.points keeps the float32 dtype). Coordinates widen to float64 exactly internally, so the result is identical to passing points.astype(np.float64). Other dtypes are converted to float64.
  • Exact duplicate points are dropped, keeping the first occurrence as the representative. scipy/Qhull likewise never includes duplicate indices in simplices (though which copy Qhull keeps is arbitrary, while shull's choice is deterministic). Dropped points are reported in coplanar (scipy's convention); the raw calculate_shull_* functions return the (dropped, kept) index pairs as a third array.
  • Degenerate input (too few distinct points, all points collinear in 2D, all points coplanar/cospherical in 3D) raises ValueError — a full-dimensional triangulation does not exist in those cases.
  • Points are triangulated after centering on their centroid (a ≤1-ulp perturbation of the coordinates), which makes the result robust to clouds positioned far from the origin.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shull-0.2.0.tar.gz (57.1 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

shull-0.2.0-cp38-abi3-win_amd64.whl (257.8 kB view details)

Uploaded CPython 3.8+Windows x86-64

shull-0.2.0-cp38-abi3-musllinux_1_2_x86_64.whl (612.1 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ x86-64

shull-0.2.0-cp38-abi3-musllinux_1_2_aarch64.whl (573.1 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

shull-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (407.9 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

shull-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (398.2 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

shull-0.2.0-cp38-abi3-macosx_11_0_arm64.whl (351.4 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

shull-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl (366.5 kB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file shull-0.2.0.tar.gz.

File metadata

  • Download URL: shull-0.2.0.tar.gz
  • Upload date:
  • Size: 57.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0.tar.gz
Algorithm Hash digest
SHA256 04e6f1195375a261246484b9cfc6c157beec378f01bb78ef1f54deb9fa1dc5f3
MD5 fa32a7e6922bab2a32e71eb6d2713857
BLAKE2b-256 9d7b112df66e4d6ff11d97f790371d9cd0470f6c3058a879d3906b4987965e23

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-win_amd64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-win_amd64.whl
  • Upload date:
  • Size: 257.8 kB
  • Tags: CPython 3.8+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7db4ab972b4f99ba064be50d68d5f4400f000fb5820b3148c971dbf3d125ac06
MD5 584a23a51d6d2c472a33bcb1ef1991f7
BLAKE2b-256 18d6db7c351c1b04fcb6bd81dc56ed833bd0ad02bebf66445851299ff40c757e

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 612.1 kB
  • Tags: CPython 3.8+, musllinux: musl 1.2+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 e51dbc9cd971bf48a6c0cbdca02a97dc88b8ec13d2d3832b6ceeff7ead02edd3
MD5 294f8e2a56454bfb4e0922eb10879660
BLAKE2b-256 58861da5d54c4a1a6398a8dc047e6ec557a1bfe88a5b1e60b3c4cef7ae0f40b5

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-musllinux_1_2_aarch64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-musllinux_1_2_aarch64.whl
  • Upload date:
  • Size: 573.1 kB
  • Tags: CPython 3.8+, musllinux: musl 1.2+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 8f45f8fc60947a96b4568ef2b1388f49cc2686fbeb146e55dd9f6e82d2ab5585
MD5 742014ef017b5cd03c24116f0e40a210
BLAKE2b-256 fe508213bb52f26d3817ac62faa14ad6b5d478e427f562b9cf7913fa669520e5

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 407.9 kB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 044ec148873b162b1f4b3f3fc529edbd49ebe578f578f86768cf66f692a1ef8c
MD5 5c9e746ac9de468485334a83c83aa132
BLAKE2b-256 489dd817df9a5a6146a557fa8acdba540ca22f47f67a8b0aa1960340c073a589

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
  • Upload date:
  • Size: 398.2 kB
  • Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2d9b562c3805b41ede0fbc809b98e1cea850b52ce2b3f79f65695e61232f404e
MD5 8a390d9df1bb83892ba451ba10ee988d
BLAKE2b-256 6e4ac6e9e7544c0b2f2b998e88ee7022cddde3531c874172bd84adf72fb92208

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 351.4 kB
  • Tags: CPython 3.8+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2826fcc6ecc00864853d8fbb1f5780352c735dfa9fe945c3af18917de48a817b
MD5 fd7b3052fa20eb3c34bd136d84549269
BLAKE2b-256 7e12bb903e20acb5e08c36275cff20ddf79b7cee067ae27824321397caf3c451

See more details on using hashes here.

File details

Details for the file shull-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: shull-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 366.5 kB
  • Tags: CPython 3.8+, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for shull-0.2.0-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 2889fc9ea0c45e874262fb13af56b724e2aab5e18d8c8876ee7e55b9ace4ec5f
MD5 17469b79d1946bffbc70deeed895b125
BLAKE2b-256 4226b5d26b97bd918be57218ad798d74fd8ce7aa8f2ce2b9916aa28af7604b54

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page