Nothing
#' Compute per-vertex surface areas
#'
#' Each triangle distributes one-third of its area to each of its three
#' vertices. Triangle area is computed via the cross-product formula.
#'
#' @param vertices Numeric matrix (n x 3) of vertex coordinates.
#' @param faces Integer matrix (m x 3) of face indices (1-indexed).
#'
#' @return Numeric vector of length `nrow(vertices)`.
#'
#' @examples
#' vertices <- matrix(c(0, 1, 0, 0, 0, 1, 0, 0, 0), nrow = 3, byrow = TRUE)
#' faces <- matrix(c(1L, 2L, 3L), nrow = 1)
#' vertex_areas(vertices, faces)
#' @export
vertex_areas <- function(vertices, faces) {
if (!is.matrix(vertices) || ncol(vertices) != 3) {
cli::cli_abort("{.arg vertices} must be a matrix with 3 columns.")
}
if (!is.matrix(faces) || ncol(faces) != 3) {
cli::cli_abort("{.arg faces} must be a matrix with 3 columns.")
}
areas <- numeric(nrow(vertices))
a <- vertices[faces[, 1], , drop = FALSE]
b <- vertices[faces[, 2], , drop = FALSE]
c <- vertices[faces[, 3], , drop = FALSE]
ab <- b - a
ac <- c - a
cross <- cbind(
ab[, 2] * ac[, 3] - ab[, 3] * ac[, 2],
ab[, 3] * ac[, 1] - ab[, 1] * ac[, 3],
ab[, 1] * ac[, 2] - ab[, 2] * ac[, 1]
)
tri_areas <- 0.5 * sqrt(rowSums(cross^2))
third_area <- tri_areas / 3
all_idx <- as.vector(faces)
all_areas <- rep(third_area, 3)
accumulated <- rowsum(all_areas, all_idx, reorder = TRUE)
areas[as.integer(rownames(accumulated))] <- as.vector(accumulated)
areas
}
#' Convert FreeSurfer annotation to GIFTI
#'
#' Reads a FreeSurfer `.annot` file and writes a GIFTI label file.
#'
#' @param annot_path Path to FreeSurfer `.annot` file.
#' @param output_path Output GIFTI path. If `NULL`, replaces the extension
#' with `.label.gii`.
#'
#' @return The output file path (invisibly).
#'
#' @references
#' Markello RD et al. (2022) Nature Methods 19:1472-1480.
#' doi:10.1038/s41592-022-01625-w
#'
#' @examples
#' \dontrun{
#' annot_to_gifti("lh.aparc.annot")
#' annot_to_gifti("lh.aparc.annot", "lh.aparc.label.gii")
#' }
#' @export
annot_to_gifti <- function(annot_path, output_path = NULL) {
rlang::check_installed(
"freesurferformats",
reason = "to read FreeSurfer annotation files"
)
if (!file.exists(annot_path)) {
cli::cli_abort("File not found: {.file {annot_path}}")
}
annot <- freesurferformats::read.fs.annot(annot_path)
labels <- annot$label_codes
if (is.null(output_path)) {
output_path <- sub("\\.[^.]+$", ".label.gii", annot_path)
}
gii <- structure(
list(
data = list(as.integer(labels)),
data_info = data.frame(
Intent = "NIFTI_INTENT_LABEL",
DataType = "NIFTI_TYPE_INT32",
n = length(labels),
Dim0 = length(labels),
stringsAsFactors = FALSE
)
),
class = "gifti"
)
gifti::write_gifti(gii, output_path)
invisible(output_path)
}
#' Convert FreeSurfer morphometry to GIFTI
#'
#' Reads a FreeSurfer morphometry file (`.curv`, `.thickness`, `.sulc`) and
#' writes a GIFTI func file.
#'
#' @param morph_path Path to FreeSurfer morphometry file.
#' @param output_path Output GIFTI path. If `NULL`, replaces the extension
#' with `.func.gii`.
#'
#' @return The output file path (invisibly).
#'
#' @references
#' Markello RD et al. (2022) Nature Methods 19:1472-1480.
#' doi:10.1038/s41592-022-01625-w
#'
#' @examples
#' \dontrun{
#' fsmorph_to_gifti("lh.thickness")
#' fsmorph_to_gifti("lh.thickness", "lh.thickness.func.gii")
#' }
#' @export
fsmorph_to_gifti <- function(morph_path, output_path = NULL) {
rlang::check_installed(
"freesurferformats",
reason = "to read FreeSurfer morphometry files"
)
if (!file.exists(morph_path)) {
cli::cli_abort("File not found: {.file {morph_path}}")
}
morph <- freesurferformats::read.fs.morph(morph_path)
if (is.null(output_path)) {
output_path <- sub("\\.[^.]+$", ".func.gii", morph_path)
}
gii <- structure(
list(
data = list(as.numeric(morph)),
data_info = data.frame(
Intent = "NIFTI_INTENT_SHAPE",
DataType = "NIFTI_TYPE_FLOAT32",
n = length(morph),
Dim0 = length(morph),
stringsAsFactors = FALSE
)
),
class = "gifti"
)
gifti::write_gifti(gii, output_path)
invisible(output_path)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.