% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/dijkstras-path.R
\name{dijkstras-path}
\alias{dijkstras-path}
\alias{dijkstras_surface_distance}
\alias{surface_path}
\title{Calculate distances along a surface}
\usage{
dijkstras_surface_distance(
  positions,
  faces,
  start_node,
  face_index_start = NA,
  max_search_distance = NA,
  ...
)

surface_path(x, target_node)
}
\arguments{
\item{positions}{numeric matrix with no \code{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.}

\item{faces}{integer matrix with each row containing indices of nodes. For
graphs, \code{faces} is a matrix with two columns defining the connecting
edges; for '3D' mesh, \code{faces} is a three-column matrix defining the
face index of mesh triangles.}

\item{start_node}{integer, row index of \code{positions} on where to start
calculating the distances. This integer must be 1-indexed and cannot exceed
the total number of \code{positions} rows}

\item{face_index_start}{integer, the start of the nodes in \code{faces};
please specify this input explicitly if the first node is not contained
in \code{faces}.
Default is \code{NA} (determined by the minimal number in \code{faces}).
The reason to set this input is because some programs use \code{1} to
represent the first node, some start from \code{0}.}

\item{max_search_distance}{numeric, maximum distance to iterate;
default is \code{NA},
that is to iterate and search the whole mesh}

\item{...}{reserved for backward compatibility}

\item{x}{distance calculation results returned by
\code{dijkstras_surface_distance} function}

\item{target_node}{the target node number to reach (from the starting node);
\code{target_node} is always 1-indexed.}
}
\value{
\code{dijkstras_surface_distance} returns a list distance
table with the meta configurations. \code{surface_path} returns a data frame
of the node ID (from \code{start_node} to \code{target_node}) and cumulative
distance along the shortest path.
}
\description{
Calculate surface distances of graph or mesh using 'Dijkstra' method.
}
\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 ------------------------------------

\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)

}






}
