---
title: "Getting started with a5R"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting started with a5R}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(a5R)
```

## Index a point

Map a longitude/latitude coordinate to a cell at a given resolution (0--30).
Higher resolutions produce smaller cells.

```{r}
cell <- a5_lonlat_to_cell(-3.19, 55.95, resolution = 10)
cell
```

Convert back to the cell centre point:

```{r}
a5_cell_to_lonlat(cell)
```

## Cell boundaries

Get the boundary polygon for one or more cells:

```{r boundary-plot, fig.width = 5, fig.height = 4}
boundary <- a5_cell_to_boundary(cell)
boundary

plot(boundary, col = "#206ead20", border = "#206ead", asp = 1)
```

Boundaries are returned as `wk_wkb` vectors by default (set `format = "wkt"` for
WKT). Both integrate directly with sf, terra, and other spatial tooling via the
wk package.

## Hierarchy and compaction

A5 is a hierarchical grid: every cell has a **parent** at a coarser
resolution and 4 **children** at the next finer resolution.

```{r}
parent <- a5_cell_to_parent(cell)
parent

children <- a5_cell_to_children(cell)
children
```

We can visualise the relationship: the parent (dark outline) contains
our cell (blue fill), which in turn contains its 4 children (orange):

```{r hierarchy-plot, fig.width = 8, fig.height = 8}
plot(NULL, xlim = c(-3.23, -3),  ylim = c(55.98, 55.99),               
       xlab = "", ylab = "", asp = 1
       )
plot(a5_cell_to_boundary(a5_cell_to_children(cell)),
     col = "#ad6e2020", border = "#ad6e20", add = TRUE)
plot(a5_cell_to_boundary(cell), col = "#206ead40", border = "#206ead",
     lwd = 2, add = TRUE)
plot(a5_cell_to_boundary(parent), border = "#333333", lwd = 2, add = TRUE)
```

Cell area decreases geometrically: each level is roughly 4x smaller, so
the average edge length roughly halves per level. `a5_cell_edge_length_avg()`
gives a quick sense of cell size when choosing a resolution.

```{r}
a5_cell_area(0:5)
a5_cell_edge_length_avg(0:5, units = "km")
```

### Compact and uncompact

When a complete set of siblings is present, `a5_compact()` merges them
back into their shared parent. This is the inverse of `a5_cell_to_children()`
and is useful for reducing the size of large cell sets without losing
coverage.

```{r}
children
a5_compact(children)

# round-trips back to the original
a5_uncompact(a5_compact(children), resolution = 11)
```

Many a5R functions return compacted output automatically. For example,
`a5_grid_disk()` and `a5_spherical_cap()` compact their results; use
`a5_uncompact()` when you need a uniform-resolution grid (see
[Traversal](#traversal) below).


## Traversal

Find neighbouring cells by hop count with `a5_grid_disk()`, or by
great-circle distance with `a5_spherical_cap()`:

```{r traversal, fig.width = 7}
disk <- a5_grid_disk(cell, k = 10)
cap <- a5_spherical_cap(cell, radius = 50000)

plot(a5_cell_to_boundary(cap), col = "#6ead2020", border = "#6ead20", asp = 1)
plot(a5_cell_to_boundary(disk), col = "#206ead20", border = "#206ead", asp = 1)
```

Both functions return a **compacted** cell vector: sibling groups are
merged into coarser parent cells to save space. To recover a uniform grid
at the original resolution, pass the result through `a5_uncompact()`:

```{r traversal-uncompact, fig.width = 7}
disk_grid <- a5_uncompact(disk, resolution = a5_get_resolution(cell))

plot(a5_cell_to_boundary(disk_grid), col = "#206ead20", border = "#206ead", asp = 1)
```


## Converting geometries to a5 cells

`a5_polygon_to_cells()` returns the cells whose centres lie inside a
polygon. It accepts any geometry that wk can handle (a `wk::rct()`
bounding box, a WKT or WKB polygon, an `sf` / `sfc` feature) and also
terra `SpatVector` polygons.

```{r grid-plot, fig.width = 7}
cells <- a5_polygon_to_cells(wk::rct(-3.3, 55.9, -3.1, 56.0), resolution = 12)
length(cells)

plot(a5_cell_to_boundary(cells), col = "#206ead20", border = "#206ead", asp = 1)
```

The returned vector is sorted and compacted: whenever four sibling
cells all sit inside the polygon, they are merged into their parent so
the result uses fewer slots without losing coverage. Call
`a5_uncompact()` to expand back to a uniform grid at the target
resolution:

```{r}
cells_uncom <- a5_uncompact(cells, 12)
length(cells_uncom)

plot(a5_cell_to_boundary(cells_uncom), col = "#206ead20", border = "#206ead", asp = 1)
```

By default only cells whose centre lies inside the polygon are returned,
so cells straddling the boundary are dropped and the union of the cells
does not fully cover the polygon. Pass `containment = "overlapping"` to
also keep every cell that touches the boundary, giving gap-free coverage.
The overlapping set is always a superset of the centre set.

```{r containment-plot, fig.width = 7}
covering <- a5_polygon_to_cells(wk::rct(-3.3, 55.9, -3.1, 56.0),
                                resolution = 12, containment = "overlapping")
length(covering)

plot(a5_cell_to_boundary(a5_uncompact(covering, 12)),
     col = "#ad6e2020", border = "#ad6e20", asp = 1)
plot(a5_cell_to_boundary(cells_uncom),
     col = "#206ead40", border = "#206ead", add = TRUE)
plot(wk::rct(-3.3, 55.9, -3.1, 56.0), border = "#333333", lwd = 2, add = TRUE)
```

Multi-part inputs are handled natively: a `MULTIPOLYGON` or an `sfc`
of multiple polygons returns the union of cells across all parts, and
a `POLYGON` with holes returns the outer ring's cells with the hole
cells properly subtracted.

```{r, eval = requireNamespace("sf", quietly = TRUE)}
library(sf)
demo(nc, ask = FALSE, echo = FALSE)
nca5 <- a5_polygon_to_cells(nc, resolution = 9) |>
  a5_uncompact(9)
plot(a5_cell_to_boundary(nca5), col = "#03030320", border = "#6d20adff", asp = 1)
```

## Tracing a line

`a5_linestring_to_cells()` returns the cells whose pentagons are
crossed by a great-circle polyline. Output is in discovery order along
the path. Consecutive waypoints are connected by great-circle arcs, so
antimeridian-crossing routes work transparently.

Multi-part inputs (`MULTILINESTRING` or an `sfc` of several linestrings)
are handled natively: per-feature outputs are concatenated in feature
order with first-seen deduplication.

To show what cell-by-cell tracing looks like, we can write a short
phrase as a `MULTILINESTRING` (one stroke per letter) and ask A5 to
fill in the cells:

```{r linestring-a5R, fig.width = 7, fig.height = 3}
a5R_strokes <- wk::wkt(
  "MULTILINESTRING (
    (1.8 52.5, 1.2 52.8, 0.6 52.5, 0.4 52, 0.6 51.5, 1.2 51.2, 1.8 51.5, 2 52, 1.8 52.5, 2 51.2),
    (5 53, 3.5 53, 3.5 52.2, 4 52.2, 4.7 52, 5 51.6, 4.7 51.2, 4 51, 3.5 51.1),
    (6.5 51, 6.5 53, 7.5 53, 8 52.8, 8.2 52.5, 8 52.2, 7.5 52, 6.5 52, 8.2 51)
  )"
)

cells <- a5_linestring_to_cells(a5R_strokes, resolution = 9)
length(cells)

plot(a5_cell_to_boundary(cells),
     col = "#206ead80", border = "#37af6d", asp = 1)
```

Each stroke is one continuous linestring; the function walks the
great-circle path, expanding cell neighbours along the way, and
returns the union across all strokes.

