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 sorted incremental insertion, 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: ~9.5X faster than scipy's Qhull-based Delaunay
- improve 3d performance: ~1.4–1.8X faster than scipy
Build
cdinto directory- Activate virtual environment:
source .venv/bin/activate - Run
maturin develop(usematurin build --releaseto 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.015 s | 9.5× |
| 100 000 | 0.021 s | 0.20 s | 9.4× |
| 1 000 000 | 0.35 s | 3.4 s | 9.7× |
3D (Delaunay3d vs scipy.spatial.Delaunay)
| n | shull | scipy (Qhull) | speedup |
|---|---|---|---|
| 10 000 | 0.05 s | 0.07 s | 1.4× |
| 100 000 | 0.66 s | 1.19 s | 1.8× |
| 1 000 000 | 8.5 s | 14.7 s | 1.7× |
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=uint64)
3D
>>> pts = np.random.default_rng(12345).random((10000, 3))
>>> d = shull.Delaunay3d(pts)
>>> d.simplices # (n, 4) tetrahedra, like scipy.spatial.Delaunay
array([[3661, 6693, 7492, 1937],
...], dtype=uint64)
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.pointskeeps the float32 dtype). Coordinates widen to float64 exactly internally, so the result is identical to passingpoints.astype(np.float64). Other dtypes are converted to float64. - Exact duplicate points are dropped; their indices never appear in the output.
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shull-0.1.0.tar.gz.
File metadata
- Download URL: shull-0.1.0.tar.gz
- Upload date:
- Size: 43.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21a36944eeff1fafc6327e3ae825bd894520224f4229260f2dfe17e43cbd2fd2
|
|
| MD5 |
f6407b98c519a4f1ac78cb4787f1e8e6
|
|
| BLAKE2b-256 |
95b8e6cdffc3bc994577ae3581ddd2e99846d2a2845370aa0b03d45e9117289e
|
File details
Details for the file shull-0.1.0-cp38-abi3-win_amd64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-win_amd64.whl
- Upload date:
- Size: 226.7 kB
- Tags: CPython 3.8+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24a2f1dc157a02d44cad67060cfcb7533097b37cae4b143e68438c7038f349b9
|
|
| MD5 |
1b15dd1b7c27c1bf890e35859e92e05f
|
|
| BLAKE2b-256 |
a0ddb86b6c5803d2c27bc4a84f47f1f0ee2bf76d1e32d3961e57c5a94dec5ffe
|
File details
Details for the file shull-0.1.0-cp38-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 579.2 kB
- Tags: CPython 3.8+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f1c323274cede7697d3fa629d9fd712883cffd70928237a4eb49013e2778424
|
|
| MD5 |
fabf869e41feac184c98501542b13762
|
|
| BLAKE2b-256 |
56d1316f76168e327af3a91bb3c35657ea8e5c44cbc27a3b689f52927812a5f8
|
File details
Details for the file shull-0.1.0-cp38-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 545.8 kB
- Tags: CPython 3.8+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e769f5bee619b69e3d06c82da27cc04291931e312071fca183f46184e4064d50
|
|
| MD5 |
ede1b12e7c98c453cd840abf0799f35a
|
|
| BLAKE2b-256 |
f1c81a2538564262da63d3680085302655ead493899e4e658126cf6660285bd3
|
File details
Details for the file shull-0.1.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 376.3 kB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2600a4c45ccc8870b11aa146da04343a613faf083c0c57e40ab51eb67b13950b
|
|
| MD5 |
c09d536dfbba4d6f7cf7c38bfaa66c16
|
|
| BLAKE2b-256 |
cbc476f2b493e3ed938bc5ba2582f92d8bce1712396c242722139e30b477dcba
|
File details
Details for the file shull-0.1.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 369.2 kB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
536a626d313ca0512d8a0b4969a9b0f134e955fe606b438bd549b11d040539b1
|
|
| MD5 |
e1ab2f80aed86eb3792d75a3138fc119
|
|
| BLAKE2b-256 |
ad43c2e82c9445f91116e1becef66a4d60c4aaa725cd85b963b71da5b818953a
|
File details
Details for the file shull-0.1.0-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 325.6 kB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33f528a8bc30454f26289bcdd650b6f8a079c229e5b7fd48fbbecbb6006e7978
|
|
| MD5 |
e47ae7221da34da508238c0d97ef3758
|
|
| BLAKE2b-256 |
4d1b10f907bd35b883e7d2995452cc83196707e183315625cb2756ec8749d330
|
File details
Details for the file shull-0.1.0-cp38-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: shull-0.1.0-cp38-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 333.8 kB
- Tags: CPython 3.8+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7260b48158751e5128bfae08412017a0ed09c7aeb6cca3c5e8a27f5e565af2aa
|
|
| MD5 |
12f084b47c381a947284d139382c80a5
|
|
| BLAKE2b-256 |
d79da73912548623b7077231775cd9ce16c69ea2759bf3bfd7d28cf64b109fe5
|