Skip to content

Choosing the right tool

Choose between similar predicates, cleanup operations, and spatial queries.

Repeated predicates: index or graph components?

You have You want Reach for
one geometry probed by many candidates the same predicate, many times the predicate itself — the geometry indexes itself after its first few probes and every later call reuses it
many geometries queried by arbitrary probes candidate retrieval + exact predicate gm.SpatialIndex(values) then query(..., predicate=...)
two whole collections matched row-to-row a relational join gm.join (inner/left semantics, any predicate)
one collection grouped by mutual relationships connected components under a geometric predicate build a pair graph with gm.join / SpatialIndex.self_join, then run a graph connected-components algorithm (networkx / scipy.sparse); reserve coordinate clustering (NumPy handoff) for point features only
a cheap pre-group before exact work bounding-box candidates only SpatialIndex.candidates

A geometry's own index is per-geometry state; SpatialIndex(values) is per-collection state. For one polygon against one large array, gm.contains(polygon, arr) uses the prepared path.

Containment: contains, contains_properly, covers, within

Question Predicate
"is the candidate inside, where boundary contact still counts?" covers
"is the candidate inside, with at least one interior point?" (OGC contains) contains
"is the candidate inside without touching my boundary at all?" contains_properly
the same questions, asked from the candidate's side covered_by / within

The boundary rule: a point on a polygon's edge is not contained — use covers for boundary-inclusive membership. See the predicate boundary rules.

Intersecting a rectangle

Use intersection for both rectangular windows and arbitrary masks. Build a window with box, using the geometry's CRS and coordinate epoch; for geographic bounds, west > east automatically selects the interval crossing the longitude seam.

Vertex cleaning: seven different jobs

Job Operation What survives
round coordinates to N decimal places (shrink WKB/WKT, stabilize comparisons) quantize every vertex, rounded; topology not repaired
snap vertices onto a fixed coordinate grid snap_to_grid grid-aligned vertices; collapsed parts become empty; output may be non-simple
snap onto a grid and guarantee validity snap_to_grid with repair=True grid-aligned, valid output (snap → repair → re-snap to a fixpoint); the geometry kind may change
drop consecutive duplicate (or near-duplicate) vertices remove_repeated_points the geometry kind, with consecutive runs collapsed
reduce vertex count while keeping shape simplify (method='vw' Visvalingam–Whyatt by default, or method='dp' Douglas–Peucker for a distance band; preserve_topology=True keeps valid polygonal components valid and simple lineal components simple, but does not preserve relationships between separate GeometryCollection members) a vertex subset within tolerance
collect the distinct vertices themselves unique_points a MultiPoint for homogeneous survivors, or an ordered GeometryCollection of full-fidelity points when axes differ
fix actual invalidity (self-intersections, bad rings) repair a valid geometry, rebuilt

quantize and snap_to_grid can create invalidity on tight geometries — pass repair=True to snap_to_grid (or follow quantize with repair) when downstream code needs validity, and use validate to see exactly what broke.

See the worked simplification comparison for how tolerance removes progressively larger zigzags, and the precision and repeat-cleaning examples for coordinate cleanup. To align one geometry to another rather than to a fixed grid, see the worked snapping example.

Alignment between two geometries

Goal Operation
move vertices of one geometry onto a reference within a tolerance snap
shortest connecting segment between two geometries shortest_line
the two closest points as a pair nearest_points
shared linework between two lines shared_paths

Polygonal coverage_* vs grid cells

DGGS cell covers and polygonal coverages use different representations:

  • DGGS cells — gm.h3_cover, gm.s2_cover, gm.geohash_cover, and gm.tile_cover return typed CellArray values. Keep the source geometry and use the top-level predicates for exact membership.
  • A polygonal coverage — a GeometryArray of polygons that tile a region without gaps or overlaps (parcels, admin boundaries). Operations on these are array methods named coverage_*.

If you are bucketing geometry into a global grid, you want those *_cover factories. For a parcel fabric, validate with gm.coverage_is_valid(values), simplify a valid coverage with gm.coverage_simplify(values, tolerance), or clean a near-coverage with gm.coverage_clean(values). They take a GeometryArray or any iterable of geometries:

import gometry as gm

grid = gm.GeometryArray([gm.box(0, 0, 1, 1), gm.box(1, 0, 2, 1)])
print("valid:", gm.coverage_is_valid(grid))
print("same as free fn:", gm.coverage_is_valid(list(grid)))
valid: True
same as free fn: True

Validate, inspect, then clean

coverage_simplify requires a valid coverage and preserves its shared boundaries. For overlaps or gaps in a near-coverage, use coverage_clean to rebuild the faces according to overlap_rule; coverage_invalid_edges shows the mismatched boundaries to inspect. Snapping is opt-in: the default grid_size=0.0 preserves existing coordinates.

two parcel rows
The two input parcels overlap along a narrow strip instead of forming a valid coverage.
invalid shared edges
Diagnostic edges mark the mismatched parcel border around the overlap.
  • input parcels
  • what the call returns
cleaned parcel coverage
Coverage cleaning aligns the shared border and leaves two non-overlapping parcel rows.
  • input parcels
  • what the call returns
coverage union
The cleaned parcels dissolve into one continuous polygon with no overlap or gap.

For geographic inputs, max_area and min_area rank rows by ellipsoidal area in square metres, while longest_border ranks shared borders by ellipsoidal arclength in metres along the retained chart-straight edges. gap_width remains in the CRS's native angular units; it is not converted to physical units. Projected and CRS-free inputs keep coordinate-space rankings.

See also