Source: https://gometry.monicz.dev/guide/choosing/

# 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)`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex "SpatialIndex") then [`query(..., predicate=...)`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex.query "query") |
| two whole collections matched row-to-row | a relational join | [`gm.join`](https://gometry.monicz.dev/api/toplevel/index-join/#gometry.join "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`](https://gometry.monicz.dev/api/toplevel/index-join/#gometry.join "join") / [`SpatialIndex.self_join`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex.self_join "self_join"), then run a graph connected-components algorithm (networkx / scipy.sparse); reserve coordinate clustering ([NumPy handoff](https://gometry.monicz.dev/ecosystem/numpy/#handing-off-to-scipy-and-scikit-learn)) for point features only |
| a cheap pre-group before exact work | bounding-box candidates only | [`SpatialIndex.candidates`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex.candidates "candidates") |

A geometry's own index is per-geometry state; [`SpatialIndex(values)`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex "SpatialIndex")
is per-collection state. For one polygon against one
large array, [`gm.contains(polygon, arr)`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.contains "contains") uses the prepared path.

## Containment: `contains`, `contains_properly`, `covers`, `within`

| Question | Predicate |
| --- | --- |
| "is the candidate inside, where boundary contact still counts?" | [`covers`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.covers "covers") |
| "is the candidate inside, with at least one interior point?" ([OGC](https://www.ogc.org/standard/sfa/) contains) | [`contains`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.contains "contains") |
| "is the candidate inside without touching my boundary at all?" | [`contains_properly`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.contains_properly "contains_properly") |
| the same questions, asked from the candidate's side | [`covered_by`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.covered_by "covered_by") / [`within`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.within "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](https://gometry.monicz.dev/guide/predicates/#boundary-points-are-not-contained).

## Intersecting a rectangle

Use [`intersection`](https://gometry.monicz.dev/api/toplevel/overlay-dissolve/#gometry.intersection "intersection") for both rectangular windows and
arbitrary masks. Build a window with [`box`](https://gometry.monicz.dev/api/toplevel/constructors-bulk-factories/#gometry.box "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`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.quantize "quantize") | every vertex, rounded; topology *not* repaired |
| snap vertices onto a fixed coordinate grid | [`snap_to_grid`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.snap_to_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`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.snap_to_grid "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`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.remove_repeated_points "remove_repeated_points") | the geometry kind, with consecutive runs collapsed |
| reduce vertex count while keeping shape | [`simplify`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.simplify "simplify") (`method='vw'` [Visvalingam–Whyatt](https://en.wikipedia.org/wiki/Visvalingam%E2%80%93Whyatt_algorithm) by default, or `method='dp'` [Douglas–Peucker](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm) 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](https://gometry.monicz.dev/api/geometry/geometry-types/#gometry.GeometryCollection "GeometryCollection") members) | a vertex subset within tolerance |
| collect the distinct vertices themselves | [`unique_points`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.unique_points "unique_points") | a [`MultiPoint`](https://gometry.monicz.dev/api/geometry/geometry-types/#gometry.MultiPoint "MultiPoint") for homogeneous survivors, or an ordered [`GeometryCollection`](https://gometry.monicz.dev/api/geometry/geometry-types/#gometry.GeometryCollection "GeometryCollection") of full-fidelity points when axes differ |
| fix actual invalidity (self-intersections, bad rings) | [`repair`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.repair "repair") | a valid geometry, rebuilt |

[`quantize`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.quantize "quantize") and [`snap_to_grid`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.snap_to_grid "snap_to_grid") can *create* invalidity on tight geometries —
pass `repair=True` to `snap_to_grid` (or follow `quantize` with
[`repair`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.repair "repair")) when downstream code needs validity, and use
[`validate`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.validate "validate") to see exactly what broke.

See the [worked simplification comparison](https://gometry.monicz.dev/guide/constructive/#simplify-and-offset)
for how tolerance removes progressively larger zigzags, and the [precision and
repeat-cleaning examples](https://gometry.monicz.dev/guide/validation/#cleaning-quantize-and-remove_repeated_points)
for coordinate cleanup. To align one geometry to another rather than to a fixed
grid, see the [worked snapping example](https://gometry.monicz.dev/guide/constructive/#snap-and-segmentize).

## Alignment between two geometries

| Goal | Operation |
| --- | --- |
| move vertices of one geometry onto a reference within a tolerance | [`snap`](https://gometry.monicz.dev/api/toplevel/constructive-validation/#gometry.snap "snap") |
| shortest connecting segment between two geometries | [`shortest_line`](https://gometry.monicz.dev/api/toplevel/measurement/#gometry.shortest_line "shortest_line") |
| the two closest points as a pair | [`nearest_points`](https://gometry.monicz.dev/api/toplevel/measurement/#gometry.nearest_points "nearest_points") |
| shared linework between two lines | [`shared_paths`](https://gometry.monicz.dev/api/toplevel/constructive-validation/#gometry.shared_paths "shared_paths") |

## Polygonal `coverage_*` vs grid cells

DGGS cell covers and polygonal coverages use different representations:

- **DGGS cells** — [`gm.h3_cover`](https://gometry.monicz.dev/api/h3/#gometry.h3_cover "h3_cover"), [`gm.s2_cover`](https://gometry.monicz.dev/api/s2/#gometry.s2_cover "s2_cover"), [`gm.geohash_cover`](https://gometry.monicz.dev/api/geohash/#gometry.geohash_cover "geohash_cover"), and
  [`gm.tile_cover`](https://gometry.monicz.dev/api/tiles/#gometry.tile_cover "tile_cover") return typed [`CellArray`](https://gometry.monicz.dev/api/grids/#gometry.CellArray "CellArray") values. Keep the source geometry
  and use the top-level predicates for exact membership.
- **A polygonal coverage** — a [`GeometryArray`](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray "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)`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_is_valid "coverage_is_valid"), simplify a valid
coverage with [`gm.coverage_simplify(values, tolerance)`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_simplify "coverage_simplify"),
or clean a near-coverage with [`gm.coverage_clean(values)`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_clean "coverage_clean").
They take a [`GeometryArray`](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray "GeometryArray") or any iterable of geometries:

```python
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)))
```

```text
valid: True
same as free fn: True
```

### Validate, inspect, then clean

[`coverage_simplify`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_simplify "coverage_simplify") requires a valid coverage and
preserves its shared boundaries. For overlaps or gaps in a near-coverage, use
[`coverage_clean`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_clean "coverage_clean") to rebuild the faces according to
`overlap_rule`; [`coverage_invalid_edges`](https://gometry.monicz.dev/api/toplevel/coverage-polygonal/#gometry.coverage_invalid_edges "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

- [Geometry](https://gometry.monicz.dev/guide/geometry/) — types and construction.
- [CRS, units & measurement](https://gometry.monicz.dev/guide/crs/) · [Predicates](https://gometry.monicz.dev/guide/predicates/) ·
  [Constructive](https://gometry.monicz.dev/guide/constructive/) — the three operation families.
- [Discrete grids](https://gometry.monicz.dev/guide/grids/) — DGGS coverages vs polygonal `coverage_*`.
- [API index](https://gometry.monicz.dev/api/) — full callable inventory.
