find_roi_boundaries: Find Boundaries of ROIs Defined on a Surface

View source: R/boundaries.R

find_roi_boundariesR Documentation

Find Boundaries of ROIs Defined on a Surface

Description

This function identifies the boundaries between regions of interest (ROIs) on a surface mesh. It supports multiple methods for boundary detection, including using faces, midpoints of edges, centroids of faces, edge vertices, and edge faces.

Usage

find_roi_boundaries(vertices, faces, vertex_id, boundary_method = "midpoint")

Arguments

vertices

A numeric matrix of vertex coordinates (n_vertices x 3).

faces

An integer matrix of face indices (n_faces x 3). Indices are 1-based.

vertex_id

An integer vector of ROI IDs for each vertex (length n_vertices).

boundary_method

A character string specifying the boundary detection method. Options are "faces", "midpoint", "centroid", "edge_vertices", and "edge_faces". Default is "midpoint".

Details

This function identifies the boundaries between different regions of interest (ROIs) on a surface mesh. The algorithm works by analyzing the connectivity between vertices and faces with different ROI assignments.

The input must satisfy the following conditions:

  • 'vertices' is a non-empty numeric matrix with three columns.

  • 'faces' contains vertex indices between '1' and 'nrow(vertices)'.

  • 'vertex_id' has length equal to 'nrow(vertices)'.

The boundary detection process follows these general steps:

  1. Identify all edges in the mesh from the face definitions

  2. Determine which edges cross between different ROIs

  3. For each ROI, find connected components of boundary edges

  4. Trace the boundary path for each component using graph theory algorithms

The different boundary_method options produce different boundary representations:

"faces"

Simply identifies faces that contain vertices from multiple ROIs.

"midpoint"

Creates boundaries using midpoints of edges between different ROIs. This produces smooth boundaries that run between vertices.

"centroid"

Creates boundaries using centroids of faces along the boundary. This produces boundaries that run through the centers of triangular faces.

"edge_vertices"

Uses the actual vertices on ROI boundaries. This produces boundaries that follow the original mesh vertices.

"edge_faces"

Complex method that follows face relationships. This can produce more detailed boundaries but may be less stable.

The function relies on graph theory algorithms to find and trace boundary paths, using adjacency matrices and shortest path algorithms to ensure boundaries form complete cycles around each ROI component. The structure of the return value depends on boundary_method:

"faces"

boundary is a logical vector marking boundary faces. Other entries in the list are NULL.

"midpoint"

boundary contains coordinate matrices traced through edge midpoints and boundary_verts gives the vertex pairs used.

"centroid"

Boundaries are matrices of face centroid coordinates; boundary_verts is NULL.

"edge_vertices"

Boundaries follow original vertices and the indices are stored in boundary_verts.

"edge_faces"

Similar to "edge_vertices" but based on face relationships; both boundary and boundary_verts are lists.

Example structure returned by the "faces" method:

list(
  boundary = logical(n_faces),
  boundary_roi_id = NULL,
  roi_components = NULL,
  boundary_verts = NULL
)

Example for path-based methods:

list(
  boundary = list(matrix(nrow, 3), ...),
  boundary_roi_id = integer(),
  roi_components = integer(),
  boundary_verts = list(matrix(nrow, 2), ...)
)

Value

A list containing:

boundary

The boundaries of the ROIs. The format depends on boundary_method.

boundary_roi_id

A vector indicating to which ROI each boundary belongs.

roi_components

For each ROI, indicates how many components make it up.

boundary_verts

Vertices defining the boundaries, depends on boundary_method.

Examples


# Create a simple toy mesh: a cube with 8 vertices and 12 triangular faces
# Define vertices (corners of a cube)
vertices <- matrix(c(
  0, 0, 0,  # vertex 1
  1, 0, 0,  # vertex 2
  1, 1, 0,  # vertex 3
  0, 1, 0,  # vertex 4
  0, 0, 1,  # vertex 5
  1, 0, 1,  # vertex 6
  1, 1, 1,  # vertex 7
  0, 1, 1   # vertex 8
), ncol = 3, byrow = TRUE)

# Define faces (12 triangular faces making a cube)
faces <- matrix(c(
  # bottom face (z=0)
  1, 2, 3,
  1, 3, 4,
  # top face (z=1)
  5, 6, 7,
  5, 7, 8,
  # front face (y=0)
  1, 2, 6,
  1, 6, 5,
  # back face (y=1)
  3, 4, 8,
  3, 8, 7,
  # left face (x=0)
  1, 4, 8,
  1, 8, 5,
  # right face (x=1)
  2, 3, 7,
  2, 7, 6
), ncol = 3, byrow = TRUE)

# Define two ROIs: vertices 1-4 in ROI 1, vertices 5-8 in ROI 2
# This creates a boundary between the bottom half and top half of the cube
vertex_id <- c(1, 1, 1, 1, 2, 2, 2, 2)

# Find the boundaries between ROIs using midpoint method
boundary_result <- find_roi_boundaries(
  vertices = vertices,
  faces = faces,
  vertex_id = vertex_id,
  boundary_method = "midpoint"
)

# The result contains:
# - boundary: List of coordinate matrices for each boundary
# - boundary_roi_id: ROI ID for each boundary
# - roi_components: Number of components per ROI
# - boundary_verts: Vertices used to define each boundary

# To visualize (if rgl package is installed):
if (requireNamespace("rgl", quietly = TRUE)) {
  # Plot the mesh
  mesh <- rgl::tmesh3d(
    vertices = t(vertices),
    indices = t(faces),
    homogeneous = FALSE
  )
  rgl::open3d()
  rgl::shade3d(mesh, col = vertex_id)
  
  # Plot the boundary
  for (i in seq_along(boundary_result$boundary)) {
    boundary_coords <- boundary_result$boundary[[i]]
    rgl::lines3d(
      boundary_coords[,1], 
      boundary_coords[,2], 
      boundary_coords[,3], 
      col = "black", 
      lwd = 3
    )
  }
}



bbuchsbaum/neurosurf documentation built on June 10, 2025, 8:22 p.m.