A geodetic R-tree with great-circle and WGS84 nearest-neighbour and radius queries
Project description
rtree-geodetic
Python bindings for rstar_geodetic, a
geodetic (longitude/latitude) R-tree with great-circle and WGS84 nearest-neighbour and
radius queries over point, linestring, and polygon geometries.
Each (lon, lat) is mapped to a unit vector on the sphere and indexed in an R-tree, so the
antimeridian and the poles are ordinary interior points: no wrapping or special cases.
Coordinates are longitude first, latitude second, in degrees; distances are returned in
metres. Queries return integer input positions (the shapely STRtree convention).
Install
pip install rtree-geodetic
Wheels are built for CPython 3.10 and newer (a single abi3 wheel per platform).
Quick start
A tree is built from any iterable of geometry-likes: (lon, lat) pairs, GeoJSON mappings,
objects exposing __geo_interface__ (shapely geometries), or a single object whose
__geo_interface__ is a collection (a geopandas GeoSeries, a shapely Multi*, a
GeometryCollection, or a FeatureCollection).
from rtree_geodetic import GeodeticPointTree
tree = GeodeticPointTree([
(-0.1278, 51.5074), # 0 London
(2.3522, 48.8566), # 1 Paris
(13.4050, 52.5200), # 2 Berlin
])
tree.nearest((4.9041, 52.3676)) # 0 (London)
tree.nearest_with_distance((4.9041, 52.3676)) # (0, 357888.0) metres
tree.within_distance((4.9041, 52.3676), 400_000.0) # [0, 1]
tree.within_distance((4.9041, 52.3676), 400_000.0, return_distance=True)
# [(0, 357888.0), (1, 430123.5)]
tree.geometry(0).__geo_interface__
# {'type': 'Point', 'coordinates': (-0.1278, 51.5074)}
Point trees also offer a longitude/latitude rectangle query. Order the corners west-then-east to cross the antimeridian (the GeoJSON RFC 7946 convention):
tree = GeodeticPointTree([(179.0, 0.0), (-178.0, 1.0), (0.0, 0.0)])
tree.in_rectangle((170.0, -10.0), (-170.0, 10.0)) # [0, 1] (the two near the seam)
Linestring and polygon trees measure the minimum great-circle distance to the geometry (zero for a query inside a polygon):
from rtree_geodetic import GeodeticLineStringTree, GeodeticPolygonTree
lines = GeodeticLineStringTree([[(0, 0), (1, 1), (2, 0)], [(10, 10), (11, 11)]])
lines.nearest((1.0, 0.5)) # 0
square = [[(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]]
polys = GeodeticPolygonTree([square])
polys.nearest_with_distance((5.0, 5.0)) # (0, 0.0) -- inside
shapely and geopandas
The geometry views expose __geo_interface__, so shapely.geometry.shape reconstructs
them, and trees accept shapely geometries and geopandas GeoSeries directly:
import geopandas as gpd
from shapely.geometry import Point, shape
from rtree_geodetic import GeodeticPointTree
series = gpd.GeoSeries([Point(-0.1278, 51.5074), Point(2.3522, 48.8566)])
tree = GeodeticPointTree(series)
index = tree.nearest(Point(2.0, 49.0)) # 1 (Paris)
geom = shape(tree.geometry(index).__geo_interface__) # a shapely Point
Distance semantics
Distances are great-circle metres. By default they use a spherical Earth (the GRS80 mean radius, 6 371 008.8 m); against an ellipsoid the error is at most about 0.5%.
GeodeticPointTree also offers exact WGS84-ellipsoid geodesic distances (Karney's method)
through nearest_wgs84, nearest_with_distance_wgs84, and within_distance_wgs84:
tree.nearest_with_distance_wgs84((4.9041, 52.3676)) # (0, 358968.7) geodesic metres
Invalid coordinates or geometry (an out-of-range longitude or latitude, a non-finite value,
too few vertices, an edge spanning half the sphere, or an unclosed ring) raise
GeodeticError, a subclass of ValueError.
Performance
Measured with benchmarks/bench.py (seeded synthetic data;
run it with uv run --group bench python benchmarks/bench.py) on an Apple M2 Pro,
Python 3.14, shapely 2.1.2 (GEOS STRtree), rtree 1.4.1 (libspatialindex), release
build. Datasets: one million points distributed uniformly on the sphere, and one
hundred thousand small linestrings and polygons, queried per call from Python.
One million points, 10,000 queries:
| Operation | rtree-geodetic | shapely STRtree | Rtree |
|---|---|---|---|
| Build | 0.79 s | 0.23 s | 1.63 s |
| Nearest neighbour, per call | 3.5 us | 7.9 us | 21.4 us |
| Nearest neighbour, WGS84 geodesic | 2.6 us | not offered | not offered |
| Within 50 km (radius query, ~16 hits) | 10.5 us | 10.3 us* | not offered |
100,000 extent geometries, 2,000 queries:
| Operation | rtree-geodetic | shapely STRtree |
|---|---|---|
| Linestring build | 0.66 s | 0.02 s |
| Linestring nearest, per call | 4.4 us | 11.1 us |
| Polygon build | 2.44 s | 0.02 s |
| Polygon nearest, per call | 7.8 us | 12.6 us |
[!NOTE] First, the planar libraries answer a different question: they index raw lon/lat degrees, so their distances are in degrees and their answers degrade as meridians converge. On the uniform global dataset above, the
STRtreeplanar nearest neighbour differs from the true geodesic nearest neighbour for 10.9% of queries;rtree-geodeticreturns the geodesically correct answer with the distance already in metres (this is the correctness you would otherwise get from the PostGISgeographytype, without a database round trip). The starredSTRtreeradius query uses an equator-equivalent degree radius, which returns the wrong set away from the equator. Second, shapely's batch API (query_nearestwith an array of geometries) amortises the Python boundary to 5.7 us per query at 1M points; rtree-geodetic currently offers per-call queries only.
Build times for rtree-geodetic include validating every coordinate and, for
extent geometries, precomputing per-edge great-circle envelopes; construction
currently traverses Python objects (__geo_interface__ or sequences): a
numpy / GeoArrow fast path is future work.
Licence
Licensed under either of Apache License, Version 2.0 or MIT licence at your option.
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 rtree_geodetic-0.1.0.tar.gz.
File metadata
- Download URL: rtree_geodetic-0.1.0.tar.gz
- Upload date:
- Size: 185.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
353a07a3d0086d9bccfb9e85c9d508b203fbe86816967c51c825c3fc1ece07a2
|
|
| MD5 |
d86d3f34c618354b718e48409f9f94c1
|
|
| BLAKE2b-256 |
f0bf87cfb7f0c78077cd44ed30c91d5c8182bef26a999d467335c4a50b66a54e
|
Provenance
The following attestation bundles were made for rtree_geodetic-0.1.0.tar.gz:
Publisher:
wheels.yml on urschrei/rstar_geodetic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rtree_geodetic-0.1.0.tar.gz -
Subject digest:
353a07a3d0086d9bccfb9e85c9d508b203fbe86816967c51c825c3fc1ece07a2 - Sigstore transparency entry: 2203717144
- Sigstore integration time:
-
Permalink:
urschrei/rstar_geodetic@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/urschrei
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Trigger Event:
push
-
Statement type:
File details
Details for the file rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 251.3 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47995a2049c73a79e4b9f4568d5219e797add9ebc972c48352699d80dccf728d
|
|
| MD5 |
b12e2c2b91051d6dd94bdb52b5523cec
|
|
| BLAKE2b-256 |
915c8f30014911f965549795f5beab2e0c766a38d6eb6da7d2d70d35d768f268
|
Provenance
The following attestation bundles were made for rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl:
Publisher:
wheels.yml on urschrei/rstar_geodetic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl -
Subject digest:
47995a2049c73a79e4b9f4568d5219e797add9ebc972c48352699d80dccf728d - Sigstore transparency entry: 2203717158
- Sigstore integration time:
-
Permalink:
urschrei/rstar_geodetic@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/urschrei
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Trigger Event:
push
-
Statement type:
File details
Details for the file rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 408.2 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d91be17756b41c6dbe987602730f35679dd7c2f35ea6037764f0309f1ec4472
|
|
| MD5 |
2dee943f4b3146b0bca6855636e7d0b2
|
|
| BLAKE2b-256 |
089ea2fc20c11442832fad77005bea563d1af094d894a870ac8fcb01fbea7c9d
|
Provenance
The following attestation bundles were made for rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
wheels.yml on urschrei/rstar_geodetic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
5d91be17756b41c6dbe987602730f35679dd7c2f35ea6037764f0309f1ec4472 - Sigstore transparency entry: 2203717150
- Sigstore integration time:
-
Permalink:
urschrei/rstar_geodetic@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/urschrei
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Trigger Event:
push
-
Statement type:
File details
Details for the file rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 360.1 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4abd018c77f97c2c9c25169cfea678abc3e688b0209584e2a6dc0577c2fa8000
|
|
| MD5 |
74b14e6b057106b14a6ab26418cb185b
|
|
| BLAKE2b-256 |
9e00f9741d000adb9449061550988a459e36ee2a2c834a20375cfcab4d68a47d
|
Provenance
The following attestation bundles were made for rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
wheels.yml on urschrei/rstar_geodetic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
4abd018c77f97c2c9c25169cfea678abc3e688b0209584e2a6dc0577c2fa8000 - Sigstore transparency entry: 2203717154
- Sigstore integration time:
-
Permalink:
urschrei/rstar_geodetic@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Branch / Tag:
refs/tags/py-v0.1.0 - Owner: https://github.com/urschrei
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@a7ed6a6ef36b4f865d77ad5dff01af42e7d5c2ce -
Trigger Event:
push
-
Statement type: