From 2ed1ad505c1fba2391cbe4b494985d2bf66d1f71 Mon Sep 17 00:00:00 2001 From: Michael Sumner <mdsumner@gmail.com> Date: Fri, 3 Nov 2023 11:34:04 +1100 Subject: [PATCH] tweaks --- NEWS.md | 7 +++++++ R/fasterize.R | 25 ++++++++++++++++++++----- man/fasterize.Rd | 5 +++-- src/check_inputs.cpp | 2 +- tests/testthat/test-01-inputcheck.R | 6 ++++-- tests/testthat/test-05-by.R | 3 ++- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9ad62a7..61f9ef0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,12 @@ # fasterize 1.0.5 +* Input geometries may now be of type "sfc_GEOMETRY" or other mixed types. Any non polygon + geometry is dropped with a message. + +* 'field' may now be a numeric, integer, or factor vector or (as before) a name of a column in + the input data frame. This means we can `fasterize(vec, r, field = seq_along(vec))` or + `fasterize(df, r, field = seq_len(dim(df)[1L]))` or with any values we like. + * Now supporting any geometry or dataframe input supported by wk (wkb, wkt, geos, as well as sf). * Namespaced documentation fixes thanks to CRAN. diff --git a/R/fasterize.R b/R/fasterize.R index 6006477..ad0a3db 100644 --- a/R/fasterize.R +++ b/R/fasterize.R @@ -25,9 +25,10 @@ make_sf <- function(x, attr = NULL) { #' Can be created with [raster::raster()]. #' The fasterize package provides a method to create a raster object from #' an polygon dataset. -#' @param field character. The name of a column in `sf`, +#' @param field character (or numeric vector). The name of a column in `sf`, #' providing a value for each of the polygons rasterized. If NULL (default), -#' all polygons will be given a value of 1. +#' all polygons will be given a value of 1. If a numeric vector this value +#' will be used as the value given to the pixel. (No recyling is done). #' @param fun character. The name of a function by which to combine overlapping #' polygons. Currently takes "sum", "first", "last", "min", "max", "count", or #' "any". Future versions may include more functions or the ability to pass @@ -61,18 +62,32 @@ make_sf <- function(x, attr = NULL) { #' @export fasterize <- function(sf, raster, field = NULL, fun = "last", background = NA_real_, by = NULL) { + ## check the types up here + types <- wk::wk_meta(sf)$geometry_type + bad <- ! types %in% c(3, 6) + ## ok so we get geometry from anything wk can handle geom <- wk::wk_handle(sf, wk::sfc_writer()) + if (any(bad)) { + if (all(bad)) stop("no polygon geometries to fasterize") + geom <- geom[!bad, ] + message(sprintf("removing %i geometries that are not polygon or multipolygon equivalent", sum(bad))) + } + sf1 <- make_sf(geom) - if (inherits(sf, "data.frame") && !is.null(field)) { - sf1[[field]] <- sf[[field]] + if ( !is.null(field)) { + if (length(field) == 1L) { + sf1[[field]] <- sf[[field]] + } else if (length(field) == dim(sf1)[1L]) { + sf1[["field"]] <- field + field <- "field" + } } if (inherits(sf, "data.frame") && !is.null(by)) { sf1[[by]] <- sf[[by]] } - fasterize_cpp(sf1, raster, field, fun, background, by) } diff --git a/man/fasterize.Rd b/man/fasterize.Rd index 16e4afa..4c457bd 100644 --- a/man/fasterize.Rd +++ b/man/fasterize.Rd @@ -22,9 +22,10 @@ Can be created with \code{\link[raster:raster]{raster::raster()}}. The fasterize package provides a method to create a raster object from an polygon dataset.} -\item{field}{character. The name of a column in \code{sf}, +\item{field}{character (or numeric vector). The name of a column in \code{sf}, providing a value for each of the polygons rasterized. If NULL (default), -all polygons will be given a value of 1.} +all polygons will be given a value of 1. If a numeric vector this value +will be used as the value given to the pixel. (No recyling is done).} \item{fun}{character. The name of a function by which to combine overlapping polygons. Currently takes "sum", "first", "last", "min", "max", "count", or diff --git a/src/check_inputs.cpp b/src/check_inputs.cpp index 6a1d6a9..cb5e95e 100644 --- a/src/check_inputs.cpp +++ b/src/check_inputs.cpp @@ -20,7 +20,7 @@ void check_inputs(Rcpp::DataFrame &sf, polygons = sf[Rcpp::as<std::string>(sf.attr("sf_column"))]; if(!(Rf_inherits(polygons, "sfc_MULTIPOLYGON") | - Rf_inherits(polygons, "sfc_POLYGON"))) { + Rf_inherits(polygons, "sfc_POLYGON") | Rf_inherits(polygons, "sfc_GEOMETRY"))) { err_msg << "sf geometry must be POLYGON or MULTIPOLYGON" << std::endl; } diff --git a/tests/testthat/test-01-inputcheck.R b/tests/testthat/test-01-inputcheck.R index 3565bde..d82a5b0 100644 --- a/tests/testthat/test-01-inputcheck.R +++ b/tests/testthat/test-01-inputcheck.R @@ -34,13 +34,15 @@ test_that("fasterize needs polygons", { geometry = st_sfc(lapply(list(p1, p2, p3), function(x) st_linestring(x[[1]])))) expect_error(fasterize(lines, r1), - "sf geometry must be POLYGON or MULTIPOLYGON") + "no polygon geometries to fasterize") lines_wkb <- data.frame(value = c(1,2,3), geometry = wk::as_wkb(sf::st_cast(pols$geometry, "MULTILINESTRING"))) expect_error(fasterize(lines_wkb, r1), - "geometry must be POLYGON or MULTIPOLYGON") + "no polygon geometries to fasterize") + + }) diff --git a/tests/testthat/test-05-by.R b/tests/testthat/test-05-by.R index 738d84f..245d289 100644 --- a/tests/testthat/test-05-by.R +++ b/tests/testthat/test-05-by.R @@ -24,9 +24,10 @@ test_that("'by' argument works", { test_that("'by' layers are equivalent to layers generated separately", { rba <- fasterize(pols, r1, field="value", fun="sum", by ="value") - for(i in nrow(pols)) + for(i in 1:nrow(pols)) { expect_equal(as.raster(rba[[i]]), as.raster(fasterize(pols[i,], r1, field="value", fun="sum"))) + } }) test_that("'by' can handle non-character fields", {