From 473b78286368efaa78cd20caeb9612f258e8f29d Mon Sep 17 00:00:00 2001 From: rhijmans Date: Sat, 11 Nov 2023 05:18:24 +0100 Subject: [PATCH] fixes #1335 --- R/extract.R | 24 +++++++++++++++++------- src/extract.cpp | 45 +++++++++++++++++++++++++++------------------ src/spatRaster.h | 2 +- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/R/extract.R b/R/extract.R index fb6ec68b6..44fa54058 100644 --- a/R/extract.R +++ b/R/extract.R @@ -224,15 +224,21 @@ extract_table <- function(x, y, ID=FALSE, weights=FALSE, exact=FALSE, touches=FA extract_fun <- function(x, y, fun, ID=TRUE, weights=FALSE, exact=FALSE, touches=FALSE, layer=NULL, bind=FALSE, na.rm=FALSE) { - opt <- spatOptions() + nl <- nlyr(x) + nf <- length(fun) + if ((nf > 1) & (!is.null(layer))) { + error("extract", "you cannot use argument 'layer' when using multiple functions") + } + opt <- spatOptions() e <- x@cpp$extractVectorFlat(y@cpp, fun, na.rm, touches[1], "", FALSE, FALSE, weights, exact, opt) x <- messages(x, "extract") - - nl <- nlyr(x) - e <- data.frame(matrix(e, ncol=nl, byrow=TRUE)) - colnames(e) <- names(x) - + e <- data.frame(matrix(e, ncol=nl*nf, byrow=TRUE)) + if (nf == 1) { + colnames(e) <- names(x) + } else { + colnames(e) <- apply(cbind(rep(fun, each=nl), names(x)), 1, function(i) paste(i, collapse="_")) + } if (!is.null(layer)) { e <- cbind(ID=1:nrow(e), e) e <- use_layer(e, y, layer, nlyr(x)) @@ -245,6 +251,7 @@ extract_fun <- function(x, y, fun, ID=TRUE, weights=FALSE, exact=FALSE, touches= if (nrow(e) == nrow(y)) { e <- cbind(y, e) } else { + #? can this occur? warn("extract", "cannot return a SpatVector because the number of records extracted does not match he number of rows in y (perhaps you need to use a summarizing function") } } else if (ID) { @@ -288,7 +295,10 @@ function(x, y, fun=NULL, method="simple", cells=FALSE, xy=FALSE, ID=TRUE, weight } else if (!is.null(fun)) { # nothing to summarize for points txtfun <- .makeTextFun(fun) if (inherits(txtfun, "character")) { - if (txtfun == "table") { + if (any(txtfun == "table")) { + if (length(fun) > 1) { + warn("extract", "'table' cannot be combined with other functions") + } if (!is.null(layer)) { warn("extract", "argument 'layer' is ignored when 'fun=table'") } diff --git a/src/extract.cpp b/src/extract.cpp index b08b1f2da..54ba24cd6 100644 --- a/src/extract.cpp +++ b/src/extract.cpp @@ -898,7 +898,7 @@ std::vector SpatRaster::extractVectorFlat(SpatVector v, std::string fun, */ -std::vector SpatRaster::extractVectorFlat(SpatVector v, std::string fun, bool narm, bool touches, std::string method, bool cells, bool xy, bool weights, bool exact, SpatOptions &opt) { +std::vector SpatRaster::extractVectorFlat(SpatVector v, std::vector funs, bool narm, bool touches, std::string method, bool cells, bool xy, bool weights, bool exact, SpatOptions &opt) { if (!source[0].srs.is_same(v.srs, true)) { v = v.project(getSRS("wkt"), false); @@ -983,19 +983,25 @@ std::vector SpatRaster::extractVectorFlat(SpatVector v, std::string fun, SpatRaster r = geometry(1); //std::vector feats(1, 1) ; - std::function&, size_t, size_t)> efun; - std::function&, std::vector&, size_t, size_t)> wfun; + std::vector&, size_t, size_t)>> efuns; + std::vector&, std::vector&, size_t, size_t)>> wfuns; bool havefun = false; - if (!fun.empty()) { + if (!funs.empty()) { if (weights | exact) { - if (!getseWfun(wfun, fun, narm)) { - setError("not a valid function"); - return flat; + wfuns.resize(funs.size()); + for (size_t i=0; i SpatRaster::extractVectorFlat(SpatVector v, std::string fun, if (havefun) { std::vector> cvals = extractCell(cell); if (weights | exact) { - for (size_t j=0; j>> extractVector(SpatVector v, bool touches, std::string method, bool cells, bool xy, bool weights, bool exact, SpatOptions &opt); - std::vector extractVectorFlat(SpatVector v, std::string fun, bool narm, bool touches, std::string method, bool cells, bool xy, bool weights, bool exact, SpatOptions &opt); + std::vector extractVectorFlat(SpatVector v, std::vector funs, bool narm, bool touches, std::string method, bool cells, bool xy, bool weights, bool exact, SpatOptions &opt); std::vector vectCells(SpatVector v, bool touches, std::string method, bool weights, bool exact, SpatOptions &opt);