Skip to main content

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 STRtree planar nearest neighbour differs from the true geodesic nearest neighbour for 10.9% of queries; rtree-geodetic returns the geodesically correct answer with the distance already in metres (this is the correctness you would otherwise get from the PostGIS geography type, without a database round trip). The starred STRtree radius query uses an equator-equivalent degree radius, which returns the wrong set away from the equator. Second, shapely's batch API (query_nearest with 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


Download files

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

Source Distribution

rtree_geodetic-0.1.0.tar.gz (185.5 kB view details)

Uploaded Source

Built Distributions

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

rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl (251.3 kB view details)

Uploaded CPython 3.10+Windows x86-64

rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (408.2 kB view details)

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

rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl (360.1 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

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

Hashes for rtree_geodetic-0.1.0.tar.gz
Algorithm Hash digest
SHA256 353a07a3d0086d9bccfb9e85c9d508b203fbe86816967c51c825c3fc1ece07a2
MD5 d86d3f34c618354b718e48409f9f94c1
BLAKE2b-256 f0bf87cfb7f0c78077cd44ed30c91d5c8182bef26a999d467335c4a50b66a54e

See more details on using hashes here.

Provenance

The following attestation bundles were made for rtree_geodetic-0.1.0.tar.gz:

Publisher: wheels.yml on urschrei/rstar_geodetic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for rtree_geodetic-0.1.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 47995a2049c73a79e4b9f4568d5219e797add9ebc972c48352699d80dccf728d
MD5 b12e2c2b91051d6dd94bdb52b5523cec
BLAKE2b-256 915c8f30014911f965549795f5beab2e0c766a38d6eb6da7d2d70d35d768f268

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rtree_geodetic-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5d91be17756b41c6dbe987602730f35679dd7c2f35ea6037764f0309f1ec4472
MD5 2dee943f4b3146b0bca6855636e7d0b2
BLAKE2b-256 089ea2fc20c11442832fad77005bea563d1af094d894a870ac8fcb01fbea7c9d

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rtree_geodetic-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4abd018c77f97c2c9c25169cfea678abc3e688b0209584e2a6dc0577c2fa8000
MD5 74b14e6b057106b14a6ab26418cb185b
BLAKE2b-256 9e00f9741d000adb9449061550988a459e36ee2a2c834a20375cfcab4d68a47d

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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