Source: https://gometry.monicz.dev/about/benchmarks/

# Benchmarks

These benchmarks compare gometry with Shapely, pyproj, h3-py, Mercantile, and
other Python libraries across geometry, coordinate transforms, grids, and
spatial indexes.

## API comparisons

### Array construction & I/O

| API / input | gometry | Comparator |
| --- | --- | --- |
| from\_wkb mixed EWKB 10k mixed EWKB | gometry 1.47 ms 1.67× faster | 2.47 ms Shapely |
| from\_arrow mixed GeoArrow WKB 100k mixed GeoArrow WKB / 10% missing | gometry 11.47 ms 2.26× faster | 26.24 ms GeoPandas |
| to\_wkb mixed EWKB 10k mixed EWKB | gometry 732.39 us 4.35× faster | 3.19 ms Shapely |
| coords matrix and row\_index 100k vertices / float64 matrix + int64 row index | gometry 239.41 us 2.01× faster | 480.23 us Shapely |
| points from NumPy XY 10k NumPy XY | gometry 5.50 us 203.25× faster | 1.13 ms Shapely |
| from WKT mixed geometries 10k realistic mixed WKT | gometry 4.36 ms 3.28× faster | 14.32 ms Shapely |
| from GeoJSON countries 217 countries / 2.26 MB | gometry 16.48 ms 1.59× faster | 26.35 ms Shapely |

### Geometry

| API / input | gometry | Comparator |
| --- | --- | --- |
| intersects irregular polygon points 12k interior, boundary, and exterior probes | gometry 1.44 ms 1.92× faster | 2.74 ms Shapely |
| prepared polygon contains coordinate probes 100k probes / 1,316-coordinate holed polygon | gometry 4.58 ms 1.91× faster | 8.56 ms Shapely |
| dwithin pairwise 10k pairs / 50% matches | gometry 4.73 us 55.22× faster | 263.41 us Shapely |
| area projected buildings 10k projected buildings | gometry 170.94 us 1.08× faster | 186.09 us Shapely |
| length roads 10k roads / 100k vertices | gometry 137.33 us 1.51× faster | 203.93 us Shapely |
| simplify Douglas-Peucker 10k roads / 100k vertices | gometry 772.93 us 5.35× faster | 4.13 ms Shapely |
| buffer projected points 10k projected points | gometry 828.19 us 62.35× faster | 51.45 ms Shapely |
| intersection pairwise 1k irregular polygon pairs | gometry 7.14 ms Inconclusive | 7.51 ms Shapely |
| intersects pairwise polygons 1k irregular polygon pairs | gometry 620.77 us Inconclusive | 594.60 us Shapely |
| coverage\_union\_all parcels 10k edge-matched parcels | gometry 5.30 ms Inconclusive | 6.12 ms Shapely |
| is\_valid mixed polygons 10k mixed polygons / 20% invalid | gometry 5.50 ms 1.78× faster | 9.90 ms Shapely |
| repair linework 1k invalid polygons | gometry 12.72 ms 7.32× faster | 93.74 ms Shapely |
| bounds projected buildings 10k projected buildings | gometry 147.84 us 1.21× faster | 180.83 us Shapely |
| Intersect short lines with a rectangle 10,000 three-vertex lines; 40% crossing, 40% inside, 20% outside | gometry 13.15 ms 3.45× faster | 45.60 ms Shapely |
| point\_on\_surface buildings 10k concave and holed buildings | gometry 1.01 ms 2.14× faster | 2.15 ms Shapely |

### CRS & geodesy

| API / input | gometry | Comparator |
| --- | --- | --- |
| to\_crs masked points 200k points / 10% missing ‡ | gometry 7.11 ms 11.13× faster | 78.67 ms GeoPandas |
| crs\_transform WGS84 to Web Mercator 10k EPSG:4326 to 3857 | gometry 344.88 us 2.34× faster | 807.41 us pyproj |
| geodesic distance 10k WGS84 pairs † | gometry 8.26 ms Inconclusive | 8.32 ms pyproj |
| geodesic destination 10k WGS84 destinations † | gometry 3.53 ms 1.22× faster | 4.43 ms pyproj + Shapely + GeoPandas |

### Discrete global grids

| API / input | gometry | Comparator |
| --- | --- | --- |
| geohash encode tokens 10k WGS84 points / precision 6 | gometry 605.88 us 6.84× faster | 4.20 ms pygeohash |
| h3 cover center Brazil Brazil res5 / 32,260 cells | gometry 13.51 ms 2.35× faster | 32.13 ms h3-py |
| h3\_compact 32,260 to 1,732 cells | gometry 477.88 us Inconclusive | 487.70 us h3-py |

### Spatial index

| API / input | gometry | Comparator |
| --- | --- | --- |
| one-shot join within 10k POIs x 217 countries | gometry 44.90 ms 1.41× slower | 31.63 ms Shapely |
| index join within 10k POIs x 217 countries | gometry 14.75 ms 2.10× faster | 31.27 ms Shapely |
| index candidates 1k queries x 10k polygons | gometry 1.46 ms 3.76× faster | 5.48 ms Shapely |
| index nearest k=1 1k non-intersecting queries x 10k polygons | gometry 2.20 ms 2.42× faster | 5.34 ms Shapely |
| exact rectangle query: packed points 256 viewports / 10k projected points / varied hit counts | gometry 1.38 ms 1.21× faster | 1.70 ms Shapely |
| exact rectangle query: mixed geometries 256 viewports / 10k projected points, lines, polygons, and holes | gometry 6.96 ms 3.69× slower | 1.89 ms Shapely |
| exact rectangle query: geographic geometries 256 viewports / 10k mixed EPSG:4326 geometries away from seams and poles | gometry 7.78 ms 4.30× slower | 1.83 ms Shapely |
| index build 10k polygons | gometry 627.46 us 2.10× faster | 1.32 ms Shapely |

† geodesic/ellipsoidal metric.
‡ gometry uses its admitted in-core projection path; this is not a claim about arbitrary CRS transforms.

## Reference implementations

Ellipsoidal area and length along straight longitude/latitude edges are
compared with a Python/NumPy quadrature reference.

| API / input | gometry | Comparator |
| --- | --- | --- |
| ellipsoidal chart-edge country area 217 countries | gometry 166.90 ms 1.27× slower | 131.97 ms Python/NumPy quadrature reference |
| ellipsoidal chart-edge exterior length 1,034 exteriors / 16,135 vertices | gometry 2.50 ms 68.55× faster | 171.40 ms Python/NumPy quadrature reference |

## Scaling

Call time as input or output size grows. Whiskers show the range across paired
process blocks.

### Union of edge-matched areas

Edge-matched service areas.

![Union of edge-matched areas. Median call times — 64 geometries: gometry 690.81 us, Shapely 1.78 ms; 256 geometries: gometry 3.18 ms, Shapely 7.27 ms; 1024 geometries: gometry 13.85 ms, Shapely 28.34 ms.](https://gometry.monicz.dev/assets/benchmark-overlay-input-count-light.6147bc9f7a7100cb.svg)

### Union of disjoint polygons

Disjoint unit squares on a grid.

![Union of disjoint polygons. Median call times — 1000 geometries: gometry 2.61 ms, Shapely 28.68 ms; 4000 geometries: gometry 11.75 ms, Shapely 146.94 ms; 16000 geometries: gometry 49.94 ms, Shapely 728.01 ms.](https://gometry.monicz.dev/assets/benchmark-overlay-disjoint-input-count-light.e3096efd83891693.svg)

### Intersection with many holes

Square shell with square holes, cut by a box.

![Intersection with many holes. Median call times — 250 holes: gometry 541.12 us, Shapely 768.20 us; 1000 holes: gometry 2.43 ms, Shapely 3.01 ms; 4000 holes: gometry 9.79 ms, Shapely 12.65 ms.](https://gometry.monicz.dev/assets/benchmark-overlay-hole-count-light.50150178ef0881c3.svg)

### Point-in-polygon queries

Repeated coordinate queries against a prepared polygon with three holes.

![Point-in-polygon queries. Median call times — 1000 probes: gometry 32.56 us, Shapely 67.67 us; 10000 probes: gometry 773.04 us, Shapely 1.55 ms; 100000 probes: gometry 4.72 ms, Shapely 9.27 ms.](https://gometry.monicz.dev/assets/benchmark-prepared-point-in-polygon-light.becb5842a85bb9c8.svg)

### Tile cover by output size

Brazil bounding box.

![Tile cover by output size. Median call times — 990 tiles: gometry 20.47 us, Mercantile 235.22 us; 3960 tiles: gometry 62.69 us, Mercantile 987.73 us; 15340 tiles: gometry 212.62 us, Mercantile 4.21 ms.](https://gometry.monicz.dev/assets/benchmark-grid-cover-output-count-light.f9553b40216213bb.svg)

### Index queries as the index grows

1,000 queries against a growing polygon index.

Bounding-box candidates, without exact predicate refinement.

![Index queries as the index grows. Median call times — 1000 polygons: gometry 86.53 us, Shapely 69.12 us; 5000 polygons: gometry 96.63 us, Shapely 97.45 us; 10000 polygons: gometry 97.49 us, Shapely 111.25 us.](https://gometry.monicz.dev/assets/benchmark-spatial-index-cardinality-light.4d1636718d2b3f60.svg)

### Index queries by hit rate

1,000 queries against 10,000 indexed polygons.

Bounding-box candidates, without exact predicate refinement.

![Index queries by hit rate. Median call times — 0.01 fraction: gometry 23.93 us, Shapely 13.86 us; 0.1 fraction: gometry 29.51 us, Shapely 22.32 us; 0.5 fraction: gometry 58.55 us, Shapely 59.98 us.](https://gometry.monicz.dev/assets/benchmark-spatial-index-selectivity-light.27f22a996e4dbb48.svg)

### Index queries returning more candidates

One query returning a growing number of candidates.

Bounding-box candidates, without exact predicate refinement.

![Index queries returning more candidates. Median call times — 1 pairs/query: gometry 972.7 ns, Shapely 647.4 ns; 10 pairs/query: gometry 992.0 ns, Shapely 967.2 ns; 100 pairs/query: gometry 1.59 us, Shapely 1.82 us.](https://gometry.monicz.dev/assets/benchmark-spatial-index-result-amplification-light.b23bf8fff5c24ae5.svg)

## Methodology

Each workload uses six to twelve paired measurements after warm-up, alternating
which library runs first. Outputs are checked for equivalent rows, types,
coordinates, and topology before timing.

Ratios summarize paired call times. Labels use confidence intervals with at
least 95% coverage and a 3% practical-equivalence margin:

| Label | Meaning |
| --- | --- |
| Faster / slower | The entire interval is beyond the 3% margin. |
| Similar | The entire interval is within the margin. |
| Inconclusive | The interval is too wide or crosses a decision boundary. |

Measurements used one pinned CPU with the powersave governor and concurrent
host activity.

## Run environment

Measured on AMD Ryzen 9 5950X 16-Core Processor with Linux 7.2.9 and CPython 3.15.0. Benchmark harness commit: `d801b232`.
Gometry producer source commit: `d801b232` (bound to the loaded wheel by its receipt).

Versions: GeoPandas 1.2.0, h3-py 4.5.0, Mercantile 1.2.1, NumPy 2.5.4, pyarrow 26.0.0, pygeohash 3.5.1, pyproj 3.8.0, Shapely 2.2.0, GEOS 3.14.1, PROJ 9.8.1.

[Raw measurements](https://gometry.monicz.dev/assets/benchmark-runs/b050e93edccfcd081372dec5a59d383e9ef4da16ccecfc1890be6188b7623813/run.json) · [Build provenance](https://gometry.monicz.dev/assets/benchmark-runs/b050e93edccfcd081372dec5a59d383e9ef4da16ccecfc1890be6188b7623813/receipts/index.json).
