#' Densify lines or polygons
#'
#' This function adds additional vertices to lines or polygons via linear
#' interpolation, always while keeping the original vertices. Each line segment
#' will be split into equal length sub-segments. This densification algorithm
#' treats all vertices as Euclidean points, i.e. new points will not fall on a
#' great circle between existing vertices, rather they'll be along a straight
#' line.
#'
#' This function works on matrices of points and is generally not called
#' directly. Instead, use [smooth()] with `method = "densify"` to apply this
#' smoothing algorithm to spatial features.
#'
#' @param x numeric matrix; matrix of coordinates.
#' @param wrap logical; whether the coordinates should be wrapped at the ends,
#' as for polygons and closed lines, to ensure a smooth edge.
#' @param n integer; number of times to split each line segment. Ignored if
#' `max_distance` is specified.
#' @param max_distance numeric; the maximum distance between vertices in the
#' resulting matrix. This is the Euclidean distance and not the great circle
#' distance.
#'
#' @return A matrix with the coordinates of the densified curve.
#' @export
#' @examples
#' # smooth_densify works on matrices of coordinates
#' # use the matrix of coordinates defining a line as an example
#' m <- jagged_lines$geometry[[2]][]
#' m_dense <- smooth_densify(m, n = 5)
#' class(m)
#' class(m_dense)
#' plot(m, type = "b", pch = 19, cex = 1.5, axes = FALSE, xlab = NA, ylab = NA)
#' points(m_dense, col = "red", pch = 19, cex = 0.5)
#'
#' # max_distance can be used to ensure vertices are at most a given dist apart
#' m_md <- smooth_densify(m, max_distance = 0.05)
#' plot(m, type = "b", pch = 19, cex = 1.5, axes = FALSE, xlab = NA, ylab = NA)
#' points(m_md, col = "red", pch = 19, cex = 0.5)
#'
#' # smooth is a wrapper for smooth_densify that works on spatial features
#' library(sf)
#' l <- jagged_lines$geometry[[2]]
#' l_dense <- smooth(l, method = "densify", n = 2)
#' class(l)
#' class(l_dense)
#' plot(l, lwd = 5)
#' plot(l_dense, col = "red", lwd = 2, lty = 2, add = TRUE)
#' plot(l_dense %>% st_cast("MULTIPOINT"), col = "red", pch = 19,
#' add = TRUE)
smooth_densify <- function(x, wrap = FALSE, n = 10L, max_distance) {
stopifnot(is.matrix(x), nrow(x) > 1, ncol(x) > 1)
n_pts <- nrow(x)
# set densification parameters
if (missing(max_distance)) {
stopifnot(is_count(n), n >= 1)
# n segments = n + 1 points
# repeat for each segment
n <- rep(n + 1, n_pts - 1)
} else {
stopifnot(is.numeric(max_distance), length(max_distance) == 1,
max_distance > 0)
# determine number of points based on max distance
n <- ceiling(point_distance(x) / max_distance) + 1
}
# generate evenly spaced points for each dimension
pts_dense <- NULL
for (i in seq_len(ncol(x))) {
sm <- seq_multiple(start = x[1:(n_pts - 1), i],
end = x[2:n_pts, i],
n = n)
pts_dense <- cbind(pts_dense, sm)
}
colnames(pts_dense) <- colnames(x)
# make sure start and end points are the same if wrapped
if (wrap) {
pts_dense[nrow(pts_dense), ] <- pts_dense[1, ]
}
return(pts_dense)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.