Source: https://gometry.monicz.dev/get-started/quickstart/

# Quickstart

Find which blocks intersect a station's 500-meter radius, then cover the area
with H3 cells. We'll use three fictional blocks near the Eiffel Tower.
Requires **CPython 3.11 or newer**; see the [installation requirements](https://gometry.monicz.dev/get-started/installation/#requirements)
for supported runtimes and platforms.

## Install

**uv**

```bash
uv add gometry
```

**pip**

```bash
pip install gometry
```

## 1. A station

Create a [`Point`](https://gometry.monicz.dev/api/geometry/geometry-types/#gometry.Point "Point") for a station from its
longitude and latitude, and tag it with a CRS so gometry knows the coordinates are
degrees on the WGS 84 ellipsoid (EPSG:4326):

```python
import gometry as gm

station = gm.Point(
    2.2945,
    48.8584,
    crs=4326,
)
print(station)
```

```text
POINT (2.2945 48.8584)
```

## 2. A proximity radius

A buffer models straight-line proximity, not travel time or route distance. On a
[geographic CRS](https://gometry.monicz.dev/guide/crs/), [`buffer(500)`](https://gometry.monicz.dev/api/geometry/geometry/#gometry.Geometry.buffer "buffer") uses a local-projection radial
distance of 500 meters rather than 500 degrees; `unit='planar'` instead uses
native angular units as Cartesian coordinates:

```python
service_area = station.buffer(500)
print('service area m²:', round(service_area.area))
```

```text
service area m²: 780935
```

## 3. Ingest named tutorial blocks

[`gm.from_geojson(..., features=True)`](https://gometry.monicz.dev/api/toplevel/io-interop/#gometry.from_geojson "from_geojson") parses a GeoJSON feature collection into a [`Features`](https://gometry.monicz.dev/api/results/#gometry.Features "Features")
result with geometries in a [`GeometryArray`](https://gometry.monicz.dev/api/geometry/geometryarray/#gometry.GeometryArray "GeometryArray") and parallel
properties as ordinary Python mappings.

```python
payload = '''
{"type":"FeatureCollection","features":[
  {"type":"Feature","id":"champ-edge","properties":{"name":"Champ-de-Mars edge"},
   "geometry":{"type":"Polygon","coordinates":[[[2.290,48.855],[2.296,48.855],[2.296,48.858],[2.290,48.858],[2.290,48.855]]]}},
  {"type":"Feature","id":"trocadero-side","properties":{"name":"Trocadero side"},
   "geometry":{"type":"Polygon","coordinates":[[[2.287,48.860],[2.293,48.860],[2.293,48.864],[2.287,48.864],[2.287,48.860]]]}},
  {"type":"Feature","id":"out-of-range","properties":{"name":"Out-of-range block"},
   "geometry":{"type":"Polygon","coordinates":[[[2.305,48.865],[2.311,48.865],[2.311,48.870],[2.305,48.870],[2.305,48.865]]]}}
]}
'''
features = gm.from_geojson(payload, crs=4326, features=True)
blocks, properties, ids = features.geometries, features.properties, features.ids
names = [row['name'] for row in properties]
print(len(blocks), 'tutorial blocks loaded:', names)
```

```text
3 tutorial blocks loaded: ['Champ-de-Mars edge', 'Trocadero side', 'Out-of-range block']
```

The station, its 500 m service area, and the three tutorial blocks.

A station anchors a 500 m service area drawn over the three tutorial blocks it will be tested against.

- input
- query
- anchor

## 4. Which blocks are in reach?

Build a spatial index over the blocks, then ask which ones [`intersects`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.intersects "intersects")
the service area. The index runs a bounding-box prefilter and then an exact
geometry test; [`query`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex.query "query") returns row indices for intersecting geometries rather
than candidate envelopes, while [`SpatialIndex.candidates`](https://gometry.monicz.dev/api/spatial-index/#gometry.SpatialIndex.candidates "candidates")
returns prefilter row indices:

```python
idx = gm.SpatialIndex(blocks)
reachable = idx.query(service_area, predicate='intersects')
print('rows intersecting the radius:', reachable.tolist())
matched_names = [names[i] for i in reachable]
print('matched names:', matched_names)
```

```text
rows intersecting the radius: [0, 1]
matched names: ['Champ-de-Mars edge', 'Trocadero side']
```

Two blocks intersect the service area; the third is out of range.

The query returns the two blocks that intersect the service area and excludes the out-of-range block.

- query
- result
- excluded
- anchor

## 5. Bucket the service area into grid cells

[`gm.h3_cover`](https://gometry.monicz.dev/api/h3/#gometry.h3_cover "h3_cover") returns H3 cells for joining tiled datasets or binning at global
scale; exact membership uses the source geometry with [`gm.covers`](https://gometry.monicz.dev/api/toplevel/predicates/#gometry.covers "covers"):

```python
cells = gm.h3_cover(service_area, resolution=10)
print('H3 cells:', len(cells))
print('source covers the station:', gm.covers(service_area, station))
```

```text
H3 cells: 76
source covers the station: True
```

H3 cells cover the service area; the geometry still decides membership.

H3 cells are join keys that can extend beyond the source service area, so the source geometry decides exact membership.

- candidates
- input
- anchor

## Where to go next

| If you want to... | Read |
| --- | --- |
| understand the planar / geodesic / grid models | [The gometry mental model](https://gometry.monicz.dev/get-started/mental-model/) |
| get a specific job done | [The user guide](https://gometry.monicz.dev/guide/) |
| see why metrics follow the CRS | [CRS, units & measurement](https://gometry.monicz.dev/guide/crs/) |
| migrate existing Shapely code | [Coming from Shapely](https://gometry.monicz.dev/migrating/#coming-from-shapely) |
| replace pyproj `Transformer` / `Geod` workflows | [Coming from pyproj](https://gometry.monicz.dev/migrating/#coming-from-pyproj) |
| tune joins and candidate/refine pipelines | [Spatial indexing & joins](https://gometry.monicz.dev/guide/indexing/) |
| look up any callable | [API reference](https://gometry.monicz.dev/api/) |
