R/gradient.R

Defines functions gradient_noise

Documented in gradient_noise

#' Calculate the gradient of a scalar field
#'
#' The gradient of a scalar field such as those generated by the different noise
#' algorithms in ambient is a vector field encoding the direction to move to get
#' the strongest increase in value. The vectors generated have the properties of
#' being perpendicular on the contour line drawn through that point. Take note
#' that the returned vector field flows upwards, i.e. points toward the steepest
#' ascend, rather than what is normally expected in a gravitational governed
#' world.
#'
#' @inheritParams curl_noise
#' @param x,y,z,t The coordinates to generate the gradient for as unquoted expressions
#' @param seed A seed for the generator.
#'
#' @export
#'
#' @family derived values
#'
#' @examples
#' grid <- long_grid(seq(0, 1, l = 100), seq(0, 1, l = 100))
#'
#' # Use one of the generators
#' grid$gradient <- gradient_noise(gen_simplex, x = grid$x, y = grid$y)
#' plot(grid$x, grid$y, type = 'n')
#' segments(grid$x, grid$y, grid$x + grid$gradient$x / 100, grid$y + grid$gradient$y / 100)
#'
gradient_noise <- function(
  generator,
  x,
  y,
  z = NULL,
  t = NULL,
  ...,
  seed = NULL,
  delta = NULL
) {
  if (is.null(seed)) {
    seed <- random_seed()
  }
  if (is.null(delta)) {
    delta <- max(
      diff(range(x)),
      diff(range(y %||% 0)),
      diff(range(z %||% 0)),
      diff(range(t %||% 0))
    ) *
      1e-4
  }
  gradient <- list(
    x = (generator(x + delta, y, z, t, seed = seed, ...) -
      generator(x - delta, y, z, t, seed = seed, ...)) /
      (2 * delta)
  )
  if (!is.null(y)) {
    gradient$y <- (generator(x, y + delta, z, t, seed = seed, ...) -
      generator(x, y - delta, z, t, seed = seed, ...)) /
      (2 * delta)
  }
  if (!is.null(z)) {
    gradient$z <- (generator(x, y, z + delta, t, seed = seed, ...) -
      generator(x, y, z - delta, t, seed = seed, ...)) /
      (2 * delta)
  }
  if (!is.null(t)) {
    gradient$t <- (generator(x, y, z, t + delta, seed = seed, ...) -
      generator(x, y, z, t - delta, seed = seed, ...)) /
      (2 * delta)
  }
  as.data.frame(gradient)
}

Try the ambient package in your browser

Any scripts or data that you put into this service are public.

ambient documentation built on Dec. 4, 2025, 5:08 p.m.