---
title: "Migrating atlas packages to sf-optional"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Migrating atlas packages to sf-optional}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r}
#| label: setup-opts
#| include: false
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r}
#| label: setup
library(ggseg.formats)
```

Since the **sf-optional** milestone (ggseg 2.2), a `ggseg_atlas` stores its 2D
geometry in a single `geom` slot that can hold either an `sf` table or the
sf-optional `brain_polygons` representation. The polygon form renders
identically through the `geom_polygon`-based path in ggseg, but carries no
dependency on the sf class machinery — so atlases keep working on wasm builds
and air-gapped installs where sf (and its GDAL/GEOS/PROJ system libraries)
cannot be installed.

This vignette is for maintainers of downstream atlas packages
(`ggsegFreeSurfer`, `ggsegSchaefer`, `ggsegGlasser`, …). Your package ships
`brain_atlas`/`ggseg_atlas` objects as `.rda` files under `data/`. Migrating
means rewriting those files once so the geometry is stored as polygons, then
dropping sf from your `DESCRIPTION`.

## The recipe

From the root of your atlas package, run:

```r
# 1. rewrite every atlas in data/ into the polygon format
ggseg.formats::migrate_atlas_files("data")

# 2. drop sf from DESCRIPTION (it is no longer needed at install or run time)
usethis::use_package("sf", type = "Suggests")

# 3. rebuild the package data documentation and reinstall
devtools::document()
```

That is the whole migration. Commit the rewritten `data/*.rda`, push, and
release.

## What `migrate_atlas_files()` does

It walks the directory, loads each `.rda`, finds every atlas object inside,
converts its `geom` to `brain_polygons`, drops any legacy `sf`/`polygons`
slots, and saves the file back with `xz` compression. Files with nothing to
migrate are left untouched, and it reports what it changed:

```r
ggseg.formats::migrate_atlas_files("data")
#> ✔ Migrated `dk.rda`.
#> ✔ Migrated `aseg.rda`.
#> ℹ Skipped `palette.rda` (nothing to migrate).
```

The conversion reads sf coordinates, so **sf must be installed on the machine
you run the migration from**. This is a one-time maintainer step; the published
package no longer needs sf.

It is idempotent — running it twice is a no-op on already-migrated files, so it
is safe to wire into a `data-raw/` build script.

### Keeping sf instead

If your atlas package genuinely needs sf geometry (for example it exposes
geometric operations), pass `keep_sf = TRUE` to normalise everything into the
single `geom` slot as sf rather than polygons:

```r
ggseg.formats::migrate_atlas_files("data", keep_sf = TRUE)
```

## Verifying the result

After migrating, the geometry is sf-optional and round-trips losslessly. You
can rehydrate sf on demand with `as_sf_atlas()`, and go back with
`as_polygon_atlas()`:

```{r}
#| label: roundtrip
poly <- as_polygon_atlas(dk())
is_atlas_polygon(poly)

atlas_labels(poly) |>
  head()
```

A migrated atlas plots through ggseg with no sf installed. If a lite-only
install meets an atlas that is *still* sf-backed, `as_polygon_atlas()` converts
it on the fly when sf is available, and otherwise aborts with a message naming
`migrate_atlas_files()` — the signal that the atlas package itself needs the
one-time migration above.
