#' Coordinates of a vector"s features or a raster"s cell centers
#'
#' @description Returns the coordinates of the center of cells of a `GRaster` or coordinates of a `GVector`'s vertices. The output will be a `matrix`, `data.frame`, or `list`. If you want the output to be a "points" `GVector`, use [as.points()].
#'
#' @param x A `GVector` or a `GRaster`.
#' @param z If `TRUE` (default), return x-, y-, and z-coordinates. If `FALSE`, just return x- and y-coordinates. For 2-dimensional objects, z-coordinates will all be 0.
#' @param na.rm Logical: If `TRUE`, remove cells that are `NA` (`GRaster`s only).
#'
#' @returns A `matrix`, `data.frame`, or `list`.
#'
#' @seealso [terra::crds()]
#'
#' @example man/examples/ex_crds.r
#'
#' @aliases crds
#' @rdname crds
#' @exportMethod crds
methods::setMethod(
f = "crds",
signature = c(x = "GRaster"),
function(x, z = is.3d(x), na.rm = TRUE) {
..char <- NULL
.locationRestore(x)
.region(x)
flags <- c(.quiet(), "overwrite")
if (!na.rm) flags <- c(flags, "i")
temp <- paste0(tempfile(), ".csv")
rgrass::execGRASS("r.out.xyz", input = sources(x), output = temp, separator = "comma", flags = flags, intern = TRUE)
# see https://grass.osgeo.org/grass82/manuals/r.out.xyz.html
out <- data.table::fread(temp)
if (is.3d(x)) {
names(out) <- c("x", "y", "z", names(x))
} else {
names(out) <- c("x", "y", names(x))
}
# convert to numerics
classes <- sapply(out, class)
if (any(classes %in% "character")) {
chars <- which(classes == "character")
for (char in chars) out[ , ..char] <- as.numeric(out[ , ..char])
}
if (!faster("useDataTable")) out <- as.data.frame(out)
out
} # EOF
)
#' @aliases crds
#' @rdname crds
#' @exportMethod crds
methods::setMethod(
f = "crds",
signature = c(x = "GVector"),
function(x, z = is.3d(x)) .crdsVect(x, z = z)
)
#' @rdname crds
#' @export
st_coordinates <- function(x) {
if (inherits(x, "GSpatial")) {
.crdsVect(x, z = FALSE)
} else {
sf::st_coordinates(x)
}
}
#' Extract coordinates for vector
#'
#' @param x A GVector or [sources()] name of one.
#' @param z T/F Extract z-coordinate?
#' @param gtype Character: [geomtype()] of the vector.
#'
#' @noRd
.crdsVect <- function(x, z, gtype = NULL) {
if (inherits(x, "GVector")) {
.locationRestore(x)
gtype <- geomtype(x)
src <- sources(x)
} else {
src <- x
}
# if lines or polygons, convert to points first
if (gtype %in% c("lines", "polygons")) {
stop("crds() will only work on points vectors.")
# ####### NB seems to work on lines but disagrees with st_coordinates() and crds()
# if (z && is.3d(x)) warning("z coordinates ignored.")
# src <- .makeSourceName("points", "vect")
# rgrass::execGRASS("v.to.points", input=sources(x), output=src, use="vertex", flags=c(.quiet(), "overwrite"), intern=TRUE)
# pts <- .makeGVector(src)
# pts <- vect(pts)
# out <- terra::crds(pts)
} else if (gtype == "points") {
info <- rgrass::execGRASS(
cmd = "v.to.db",
map = src,
flags = c(.quiet(), "p"),
option = "coor",
type = "point",
intern = TRUE
)
info <- info[!grepl(info, pattern = "cat|x|y|z")]
info <- info[grepl(info, pattern = "\\|")]
# cutAt <- which(info == "Reading features...")
# if (length(cutAt) > 0L) info <- info[1L:(cutAt - 1L)]
info <- strsplit(info, split = "\\|")
info <- lapply(info, as.numeric)
out <- do.call(rbind, info)
if (z) {
out <- out[ , 2L:4L, drop = FALSE]
colnames(out) <- c("x", "y", "z")
} else {
out <- out[ , 2L:3L, drop = FALSE]
colnames(out) <- c("x", "y")
}
}
if (faster("useDataTable")) out <- data.table::as.data.table(out)
out
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.