---
title: 'Surface Templates: Geometry vs. Data'
author: neuroatlas Dev Team
date: '`r Sys.Date()`'
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Surface Templates: Geometry vs. Data}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
params:
  family: red
css: albers.css
resource_files:
- albers.css
- albers.js
includes:
  in_header: |-
    <script src="albers.js"></script>
    <script>document.addEventListener('DOMContentLoaded',function(){document.body.classList.add('palette-red');});</script>

---

```{r setup, include = FALSE}
if (requireNamespace("ggplot2", quietly = TRUE) && requireNamespace("albersdown", quietly = TRUE)) ggplot2::theme_set(albersdown::theme_albers(params$family))
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  echo = TRUE,
  eval = FALSE  # avoid downloads during CRAN builds
)

suppressWarnings(suppressMessages(library(neuroatlas)))

templateflow_ok <- FALSE
try({
  templateflow_ok <- reticulate::py_available(initialize = TRUE) &&
    reticulate::py_module_available("templateflow")
}, silent = TRUE)
```

## Why this vignette

Surface work in `neuroatlas` uses two key pieces:

- **Geometry** (mesh and topology): stored as a `neurosurf::SurfaceGeometry`.
- **Per-vertex data** (numbers or labels): stored as the `data` slot of a
  `neurosurf::NeuroSurface` (one value per vertex).

This vignette shows how to fetch surface *geometry* from TemplateFlow,
what each helper returns, and how to attach data when you need a full
`NeuroSurface`.

## Quick reference

- `get_surface_template()` → character path to a `.surf.gii` file (one
  hemi). No mesh loaded yet.
- `load_surface_template()` → `SurfaceGeometry` (mesh + graph + hemi),
  still **no per-vertex data**. Can return L/R or both as a list.
- Atlas helpers (e.g., `schaefer_surf()`, `glasser_surf()`) →
  `LabeledNeuroSurface` with integer labels in `data` and a mesh in
  `geometry`.
- Packaged fsaverage6 meshes live in `data/fsaverage.rda` and are used
  automatically by `schaefer_surf(..., space = "fsaverage6")`.

## Fetching geometry only

Note: `load_surface_template()` requires TemplateFlow. The `fsaverage` template
may have limited availability for surface files. Check `tflow_spaces()` for
available templates.

```{r get-geometry, eval=FALSE}
# fsaverage6 pial surface, left hemi (requires TemplateFlow)
geom_l <- load_surface_template(
  template_id = "fsaverage",
  surface_type = "pial",
  hemi = "L",
  density = "41k",
  resolution = "06"
)
geom_l
```

`geom_l` is a `SurfaceGeometry` with:

- `mesh`: `rgl::mesh3d` containing vertices (`vb`) and faces (`it`).
- `graph`: `igraph` adjacency of the mesh.
- `hemi`: `"left"` or `"right"`.

No per-vertex values are present yet.

### Both hemispheres at once

```{r both-hemi, eval=FALSE}
# fsLR is more commonly available in TemplateFlow than fsaverage
geoms <- load_surface_template(
  "fsLR", "inflated", hemi = "both", density = "32k"
)
str(geoms, max.level = 1)
```

Returns a named list with `L` and `R` `SurfaceGeometry` objects if the template
is available in TemplateFlow.

## Attaching per-vertex data

To get a full `NeuroSurface`, supply data explicitly:

```{r build-neurosurface, eval=FALSE}
geom_l <- load_surface_template("fsaverage", "pial", hemi = "L",
                                density = "41k", resolution = "06")

# Example: all zeros (same length as vertices)
vals <- rep(0, length(neurosurf::nodes(geom_l)))

surf_l <- neurosurf::NeuroSurface(
  geometry = geom_l,
  indices  = neurosurf::nodes(geom_l),
  data     = vals
)
```

`surf_l@data` now holds one value per vertex; you can replace `vals` with
cortical thickness, activation, etc.

## Getting labeled surfaces (parcellations)

If you want labels already attached, use the atlas helpers; they combine
geometry with per-vertex label IDs:

```{r schaefer-surf, eval=FALSE}
atl <- schaefer_surf(parcels = 200, networks = 7,
                     space = "fsaverage6", surf = "inflated")

class(atl$lh_atlas)
#> "LabeledNeuroSurface" "NeuroSurface" ...

head(slot(atl$lh_atlas, "data"))
# integer labels per vertex
```

`slot(atl$lh_atlas, "data")` holds parcel IDs; metadata in `atl$labels`
maps those IDs to names.

## When TemplateFlow is required

- Any call that specifies `template_id`/`space` not packaged (e.g.,
  fsaverage, fsaverage5/6, fsLR) needs TemplateFlow plus network access
  on first use.
- fsaverage6 geometry is bundled; set `space = "fsaverage6"` in
  `schaefer_surf()` to avoid TemplateFlow.

## Common patterns

- Get a mesh path only (no R object): `get_surface_template(...)`.
- Get a mesh object: `load_surface_template(...)`.
- Get mesh + labels: `schaefer_surf()` / `glasser_surf()`.
- Add your own values: wrap the geometry with `NeuroSurface(...)`.

## Sanity check: surface renders

We generate a small snapshot to prove the geometry loads and is
displayable. This chunk only runs when TemplateFlow is available; the PNG
is written to `figures/` and then shown below.

```{r snapshot, eval=FALSE, cache=TRUE}
dir.create("figures", showWarnings = FALSE)
png_path <- file.path("figures", "fslr32k_inflated_L.png")
geom_l <- load_surface_template(
  "fsLR",
  "inflated",
  hemi = "L",
  density = "32k"
)
neurosurf::snapshot_surface(geom_l, file = png_path)
png_path
```

```{r snapshot-show, echo=FALSE, eval=FALSE, fig.alt="fsLR 32k inflated left hemisphere surface snapshot"}
knitr::include_graphics(file.path("figures", "fslr32k_inflated_L.png"))
```

If the image renders, the template fetched correctly.

## Template roster & snapshots

Below are the surface templates we currently target in code/tests. Densities
are TemplateFlow defaults; surface types are those exposed by
`get_surface_template()` (and used by our atlas helpers).

| template_id | density/res | surface types                   | packaged? |
|-------------|-------------|---------------------------------|-----------|
| fsaverage   | 164k        | white, pial, inflated, midthickness, sphere | TF       |
| fsaverage6  | 41k (`res-06`) | white, pial, inflated              | **yes** (bundled) |
| fsaverage5  | 10k (`res-05`) | white, pial, inflated              | TF       |
| fsLR        | 32k          | white, pial, inflated, midthickness, sphere | TF       |

### Batch snapshot script (run locally)

To create a thumbnail per template/hemisphere/type for quick QA:

```{r snapshot-batch, eval=FALSE}
templates <- list(
  list(id = "fsaverage",  den = "164k", res = NULL, types = c("pial", "inflated")),
  list(id = "fsaverage6", den = "41k",  res = "06",  types = c("pial", "inflated")),
  list(id = "fsaverage5", den = "10k",  res = "05",  types = c("pial")),
  list(id = "fsLR",       den = "32k",  res = NULL,  types = c("pial", "inflated"))
)

for (tpl in templates) {
  for (stype in tpl$types) {
    geom_l <- load_surface_template(
      template_id = tpl$id,
      surface_type = stype,
      hemi = "L",
      density = tpl$den,
      resolution = tpl$res
    )
    fname <- sprintf("%s_%s_L.png", tpl$id, stype)
    neurosurf::snapshot_surface(geom_l, file = fname)
  }
}
```

Enable and run locally to generate PNGs you can embed or eyeball to verify
each template is present and renderable.

That’s it—use geometry-only helpers when you want maximal control, and
atlas helpers when you want labeled surfaces out of the box.
