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, andgm.tile_coverreturn typedCellArrayvalues. Keep the source geometry and use the top-level predicates for exact membership. - A polygonal coverage — a
GeometryArrayof polygons that tile a region without gaps or overlaps (parcels, admin boundaries). Operations on these are array methods namedcoverage_*.
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.
- input parcels
- what the call returns
- input parcels
- what the call returns
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¶
- Geometry — types and construction.
- CRS, units & measurement · Predicates · Constructive — the three operation families.
- Discrete grids — DGGS coverages vs polygonal
coverage_*. - API index — full callable inventory.