Calculate surface distances of graph or mesh using 'Dijkstra' method.
Usage
dijkstras_surface_distance(
positions,
faces,
start_node,
face_index_start = NA,
max_search_distance = NA,
...
)
surface_path(x, target_node)
Arguments
- positions
numeric matrix with no
NA
values. The number of row is the total count of nodes (vertices), and the number of columns represent the node dimension. Each row represents a node.- faces
integer matrix with each row containing indices of nodes. For graphs,
faces
is a matrix with two columns defining the connecting edges; for '3D' mesh,faces
is a three-column matrix defining the face index of mesh triangles.- start_node
integer, row index of
positions
on where to start calculating the distances. This integer must be 1-indexed and cannot exceed the total number ofpositions
rows- face_index_start
integer, the start of the nodes in
faces
; please specify this input explicitly if the first node is not contained infaces
. Default isNA
(determined by the minimal number infaces
). The reason to set this input is because some programs use1
to represent the first node, some start from0
.- max_search_distance
numeric, maximum distance to iterate; default is
NA
, that is to iterate and search the whole mesh- ...
reserved for backward compatibility
- x
distance calculation results returned by
dijkstras_surface_distance
function- target_node
the target node number to reach (from the starting node);
target_node
is always 1-indexed.
Value
dijkstras_surface_distance
returns a list distance
table with the meta configurations. surface_path
returns a data frame
of the node ID (from start_node
to target_node
) and cumulative
distance along the shortest path.
Examples
# ---- Toy example --------------------
# Position is 2D, total 6 points
positions <- matrix(runif(6 * 2), ncol = 2)
# edges defines connected nodes
edges <- matrix(ncol = 2, byrow = TRUE, data = c(
1,2,
2,3,
1,3,
2,4,
3,4,
2,5,
4,5,
2,5,
4,6,
5,6
))
# calculate distances
ret <- dijkstras_surface_distance(
start_node = 1,
positions = positions,
faces = edges,
face_index_start = 1
)
# get shortest path from the first node to the last
path <- surface_path(ret, target_node = 6)
# plot the results
from_node <- path$path[-nrow(path)]
to_node <- path$path[-1]
plot(positions, pch = 16, axes = FALSE,
xlab = "X", ylab = "Y", main = "Dijkstra's shortest path")
segments(
x0 = positions[edges[,1],1], y0 = positions[edges[,1],2],
x1 = positions[edges[,2],1], y1 = positions[edges[,2],2]
)
points(positions[path$path,], col = "steelblue", pch = 16)
arrows(
x0 = positions[from_node,1], y0 = positions[from_node,2],
x1 = positions[to_node,1], y1 = positions[to_node,2],
col = "steelblue", lwd = 2, length = 0.1, lty = 2
)
points(positions[1,,drop=FALSE], pch = 16, col = "orangered")
points(positions[6,,drop=FALSE], pch = 16, col = "purple3")
# ---- Example with mesh ------------------------------------
if (FALSE) { # \dontrun{
# Please install the down-stream package `threeBrain`
# and call library(threeBrain)
# the following code set up the files
read.fs.surface <- internal_rave_function(
"read.fs.surface", "threeBrain")
default_template_directory <- internal_rave_function(
"default_template_directory", "threeBrain")
surface_path <- file.path(default_template_directory(),
"N27", "surf", "lh.pial")
if(!file.exists(surface_path)) {
internal_rave_function(
"download_N27", "threeBrain")()
}
# Example starts from here --->
# Load the mesh
mesh <- read.fs.surface(surface_path)
# Calculate the path with maximum radius 100
ret <- dijkstras_surface_distance(
start_node = 1,
positions = mesh$vertices,
faces = mesh$faces,
max_search_distance = 100,
verbose = TRUE
)
# get shortest path from the first node to node 43144
path <- surface_path(ret, target_node = 43144)
# plot
from_nodes <- path$path[-nrow(path)]
to_nodes <- path$path[-1]
# calculate colors
pal <- colorRampPalette(
colors = c("red", "orange", "orange3", "purple3", "purple4")
)(1001)
col <- pal[ceiling(
path$distance / max(path$distance, na.rm = TRUE) * 1000
) + 1]
oldpar <- par(mfrow = c(2, 2), mar = c(0, 0, 0, 0))
for(xdim in c(1, 2, 3)) {
if( xdim < 3 ) {
ydim <- xdim + 1
} else {
ydim <- 3
xdim <- 1
}
plot(
mesh$vertices[, xdim], mesh$vertices[, ydim],
pch = ".", col = "#BEBEBE33", axes = FALSE,
xlab = "P - A", ylab = "S - I", asp = 1
)
segments(
x0 = mesh$vertices[from_nodes, xdim],
y0 = mesh$vertices[from_nodes, ydim],
x1 = mesh$vertices[to_nodes, xdim],
y1 = mesh$vertices[to_nodes, ydim],
col = col
)
}
# plot distance map
distances <- ret$paths$distance
col <- pal[ceiling(distances / max(distances, na.rm = TRUE) * 1000) + 1]
selection <- !is.na(distances)
plot(
mesh$vertices[, 2], mesh$vertices[, 3],
pch = ".", col = "#BEBEBE33", axes = FALSE,
xlab = "P - A", ylab = "S - I", asp = 1
)
points(
mesh$vertices[selection, c(2, 3)],
col = col[selection],
pch = "."
)
# reset graphic state
par(oldpar)
} # }