Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a3dbe67
Fix link to LICENSE
adamlilith Jun 20, 2025
92aca1b
Update logo.png
adamlilith Jun 20, 2025
a2123f6
Harmonized `sf` object CRS to rasters'
adamlilith Aug 21, 2025
bc435c7
Update DESCRIPTION
adamlilith Aug 21, 2025
341702c
Update NEWS.md
adamlilith Aug 21, 2025
768db4e
Can use `+` on any type of `GVector`s
adamlilith Aug 21, 2025
835a5b8
Can start with **GRASS** connected
adamlilith Aug 21, 2025
3622143
Formatting
adamlilith Aug 21, 2025
2d5fd7a
More intuitive matching (for dev)
adamlilith Aug 21, 2025
e473b96
Update mask.r
adamlilith Aug 21, 2025
30cada2
Update help
adamlilith Aug 21, 2025
d26a88d
Test if addon available, remove before re-install
adamlilith Oct 18, 2025
79ea086
Update backdoor.r
adamlilith Oct 18, 2025
6a4a2f3
Update fillNAs.r
adamlilith Oct 18, 2025
1049080
Throw error when `w` is too large
adamlilith Oct 18, 2025
61c1a89
Works when `mode = 2`
adamlilith Oct 18, 2025
d19dcfe
Update ruggedness.r
adamlilith Oct 18, 2025
ba2916b
Works when `center` and/or `scale` is numeric
adamlilith Oct 18, 2025
bb5ee36
Update NEWS.md
adamlilith Oct 18, 2025
fd6d43a
Update README.md
adamlilith Oct 18, 2025
81b06f8
Update help
adamlilith Oct 18, 2025
8becc41
Fix `nyley()` bug
adamlilith Oct 24, 2025
8d47a22
Check for `names` file and add `GRaster` name if present
adamlilith Oct 30, 2025
0a4a5bd
`rbind()` data tables only if `ngeom()` and `nrow()` are the same
adamlilith Oct 30, 2025
add65ae
Prep for CRAN update
adamlilith Nov 18, 2025
9489793
Removed empty `item`
adamlilith Nov 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ CODE_OF_CONDUCT.md
^\.vscode
^README\.Rmd$
^.lintr$
^fasterRaster.code-workspace
^_pkgdown\.yml$
^docs$
^pkgdown$
^\.github$
^\vignettes\^junk
junk
fasterRaster_workspace.code-workspace
workspace_fasterRaster.code-workspace
^doc$
^Meta$
2 changes: 2 additions & 0 deletions .Rproj.user/shared/notebooks/paths
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
C:/Kaji/R/fasterRaster/DESCRIPTION="BE5F8589"
C:/Kaji/R/fasterRaster/NEWS.md="B2E56A81"
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: fasterRaster
Type: Package
Title: Faster Raster and Spatial Vector Processing Using 'GRASS'
Version: 8.4.1.0
Date: 2025-06-19
Version: 8.4.1.1
Date: 2025-11-18
Authors@R:
c(
person(
Expand Down Expand Up @@ -47,4 +47,4 @@ VignetteBuilder: knitr
Encoding: UTF-8
LazyData: true
LazyLoad: yes
RoxygenNote: 7.3.2
RoxygenNote: 7.3.3
16 changes: 16 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# fasterRaster 8.4.1.1 (2025-11-18)
### New functions and functionality
o `+` can now combine any two `GVector`s with the same geometry type (points, lines, polygons).
o `installAddon()` checks to see if addon is already installed, and if so, uninstalls it before re-installing.
o Minor documentation updates.

### Bug fixes
o `fast()` correctly adds names to `GRaster`s loaded from disk when a `_names.csv` file exists.
o `geomorphons()` now works when `mode = '2'`.
o `rbind()` combines `GVector` data tables when each vecto has the same number of rows in its table as geometries.
o `scale()` and `scalepop()` work when `center` and/or `scale` are numeric.
o `sf` example data objects (`madCoast0`, `madCoast4`, and `madRivers`) have had their CRSs harmonized with the example raster objects. This had caused some of the examples not to work.

### Other
o Added error checking in `fragmentation()` related to limits on size of window `w` for calculation of fragmentation indices.

# fasterRaster 8.4.1.0 (2025-06-17)

### Code-breaking changes
Expand Down
12 changes: 10 additions & 2 deletions R/04_arithmetic.r
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#' `*` operator: Same as [intersect()]\cr
#' `/` operator: Same as [xor()]\cr
#'
#' @param e1,e2 `GRaster`s, `numeric`s, `integer`s, or `logical`s.
#' @param e1,e2 `GRaster`s, `GVector`s, `numeric`s, `integer`s, or `logical`s.
#'
#' @return A `GRaster`.
#'
Expand Down Expand Up @@ -428,13 +428,21 @@ methods::setMethod(
signature(e1 = "GVector", e2 = "GVector"),
function(e1, e2) {

gtype1 <- geomtype(e1)
gtype2 <- geomtype(e2)
if (gtype1 != gtype2) stop("Vectors must be of the same type (polygons, lines, or points).")

compareGeom(e1, e2)
.locationRestore(e1)

oper <- as.vector(.Generic)[1L]

if (oper == "+") {
out <- union(e1, e2)
if (gtype1 == "polygons" & gtype2 == "polygons") {
out <- union(e1, e2)
} else {
out <- rbind(e1, e2)
}
} else if (oper == "-") {
out <- erase(e1, e2)
} else if (oper == "*") {
Expand Down
11 changes: 10 additions & 1 deletion R/addons.r
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,24 @@ addons <- function(x = NULL) {
installAddon <- function(x, check = TRUE) {

if (check) {

# is it available?
avails <- rgrass::execGRASS("g.extension", flags = c("l", .quiet()), intern = TRUE)
if (!(x %in% avails)) {

warning("The addon is not available on the official GRASS addon repository.")
return(invisible(FALSE))

}
}

# remove addon before re-installing
if (addons(x)) removeAddon(x, check = FALSE)

rgrass::execGRASS("g.extension", operation = "add", extension = x, flags = .quiet())
invisible(TRUE)
success <- addons(x)
if (!success) warning("Addon could not be installed.")
invisible(success)

}

Expand Down
16 changes: 13 additions & 3 deletions R/backdoor.r
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,32 @@
#'
#' This is a secret function to be used for faster development of **fasterRaster**. It calls [faster()] to set the install directory for **GRASS**, increases default memory, and number of cores. The function assumes development is on a Windows machine.
#'
#' @param start Logical: If `TRUE`, start the **GRASS** session by creating the `madElev` `GRaster`.
#' @param ver Character: **GRASS**: e.g., "83" or "84".
#'
#' @returns `TRUE` (invisibly).
#'
#' @keywords internal
.backdoor <- function(ver = "84") {
.backdoor <- function(start = FALSE, ver = "84") {

verNice <- paste0(substr(ver, 1L, 1L), ".", substr(ver, 2L, 2L))

faster(
grassDir = paste0("C:/Program Files/GRASS GIS ", verNice),
addonsDir = 'C:/Users/adame/AppData/Roaming/GRASS8/addons',
addonsDir = "C:/Users/adame/AppData/Roaming/GRASS8/addons",
memory = 1024 * 8,
cores = 2,
useDataTable = TRUE,
verbose = TRUE
)
invisible(TRUE)

if (start) {
madElev <- fastData("madElev")
elev <- fast(madElev)
out <- elev
} else {
out <- TRUE
}

invisible(out)
}
9 changes: 9 additions & 0 deletions R/fast.r
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,16 @@ methods::setMethod(

xRast <- terra::rast(x)
nLayers <- terra::nlyr(xRast)

xNames <- names(xRast)
fileExtension <- .fileExt(x)
nc <- nchar(fileExtension) + 1
namesFile <- substr(x, 1, nchar(x) - nc)
namesFile <- paste0(namesFile, '_names.csv')
if (file.exists(namesFile)) {
xNames <- utils::read.csv(namesFile)
xNames <- xNames$name
}

location <- .locationFind(xRast, match = "crs")

Expand Down
28 changes: 14 additions & 14 deletions R/fastData.r
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@
#' @param x The name of the raster or spatial vector to get. All of these represent a portion of the eastern coast of Madagascar.
#'
#' Spatial vectors (objects of class `sf` from the **sf** package):
#' * [madCoast0]: Outline of the region (polygon)
#' * [madCoast4]: Outlines of the Fokontanies (Communes) of the region (polygons)
#' * [madDypsis]: Records of plants of the genus *Dypsis* (points)
#' * [madRivers]: Major rivers (lines)
#' * [madCoast0][madCoast0]: Outline of the region (polygon)
#' * [madCoast4][madCoast4]: Outlines of the Fokontanies (Communes) of the region (polygons)
#' * [madDypsis][madDypsis]: Records of plants of the genus *Dypsis* (points)
#' * [madRivers][madRivers]: Major rivers (lines)
#'
#' Rasters (objects of class `SpatRaster` from the **terra** package, saved as GeoTIFF files):
#' * [madChelsa]: Bioclimatic variables
#' * [madCover]: Land cover
#' * [`madElev`][madElev]: Elevation
#' * [madForest2000]: Forest cover in year 2000
#' * [madForest2014]: Forest cover in year 2014
#' * [madLANDSAT]: Surface reflectance in 2023
#' * [madPpt], [madTmin], [madTmax]: Rasters of mean monthly precipitation, and minimum and maximum temperature.
#' * [madChelsa][madChelsa]: Bioclimatic variables
#' * [madCover][madCover]: Land cover
#' * [madElev][madElev]: Elevation
#' * [madForest2000][madForest2000]: Forest cover in year 2000
#' * [madForest2014][madForest2014]: Forest cover in year 2014
#' * [madLANDSAT][madLANDSAT]: Surface reflectance in 2023
#' * [madPpt][madPpt], [madTmin][madTmin], [madTmax][madTmax]: Rasters of mean monthly precipitation, and minimum and maximum temperature.
#'
#' Data frames
#' * [appFunsTable]: Table of functions usable by [app()]
#' * [madCoverCats]: Land cover values and categories for [madCover]
#' * [vegIndices]: Vegetation indices that can be calculated with [vegIndex()]
#' * [appFunsTable][appFunsTable]: Table of functions usable by [app()]
#' * [madCoverCats][madCoverCats]: Land cover values and categories for `madCover`
#' * [vegIndices][vegIndices]: Vegetation indices that can be calculated with [vegIndex()]
#'
#' @return A `SpatRaster`, `sf` spatial vector, or a `data.frame`.
#'
Expand Down
10 changes: 5 additions & 5 deletions R/fasterRaster.r
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,11 @@
#' * Vignette on **fasterRaster** hidden functions: `vignette("hidden_functions", package = "fasterRaster")`
#'
#' ## Classes
#' * [`GLocation`]: Fundamental class; points to a "location/project" in **GRASS**
#' * [`GSpatial`]: Basic class of any spatial object
#' * [`GRegion`]: Points to a "region" of a "location/project" in **GRASS**
#' * [`GRaster`]: Raster class
#' * [`GVector`]: Spatial vector class
#' * [GLocation][GLocation]: Fundamental class; points to a "location/project" in **GRASS**
#' * [GSpatial][GSpatial]: Basic class of any spatial object
#' * [GRegion][GRegion]: Points to a "region" of a "location/project" in **GRASS**
#' * [GRaster][GRaster]: Raster class
#' * [GVector][GVector]: Spatial vector class
#'
#' @author Adam B. Smith
#' @name fasterRaster
Expand Down
2 changes: 1 addition & 1 deletion R/fillNAs.r
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@ methods::setMethod(
.makeGRaster(srcs, names(x))

} # EOF
)
)
34 changes: 19 additions & 15 deletions R/fragmentation.r
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#' * 5: Undetermined (not possible to obtain when `w = 3`)
#' * 6: Interior
#'
#' @param x A `SpatRaster` or `GRaster`.
#' @param x A `SpatRaster` or `GRaster` wherein the habitat type has cell values of 1, and non-focal habitat type has cell values of 0 or `NA`
#'
#' @param w An odd, positive integer: Size of the window across which fragmentation is calculated (in units of "rows" and "columns"). The default is 3, meaning the function uses a 3x3 moving window to calculate fragmentation. For large rasters, compute time is ~*O*(`N`) + *O*(`N * w^2`), where `N` is the number of cells in the raster. So, even a small increase in `w` can increase compute time by a lot.
#' @param w An odd integer between 3 and 25: Size of the window across which fragmentation is calculated (in units of "rows" and "columns"). The default is 3, meaning the function uses a 3x3 moving window to calculate fragmentation. For large rasters, compute time is ~*O*(`N`) + *O*(`N * w^2`), where `N` is the number of cells in the raster. So, even a small increase in `w` can increase compute time by a lot. Values >25 will fail. A workaround might be to use [aggregate()] with `fun = 'mode'`, apply `fragmentation()`, then `resample()` to the original resolution.
#'
#' @param undet Character: How to assign the "undetermined" case. Valid values are `"perforated"` (default), `"edge"`, and `"undetermined"`. Partial matching is used. If `Pf` is the proportional density raster cell value and `Pff` the proportional connectivity raster cell value, the undetermined case occurs when `Pf` > 0.6 and `Pf == Pff`.
#'
Expand All @@ -42,7 +42,7 @@ methods::setMethod(
function(x, w = 3, undet = "undetermined", none = NA, na.rm = TRUE, cores = faster("cores"), verbose = TRUE) {

# errors?
if (!omnibus::is.wholeNumber(w) || w < 1L || w %% 2 == 0) stop("Argument `w` must be an odd, positive integer.")
if (w > 25 | !omnibus::is.wholeNumber(w) | w < 1L | w %% 2 == 0) stop("Argument `w` must be an odd, positive integer in the range from 3 to 25.")
undet <- omnibus::pmatchSafe(undet, c("undetermined", "perforated", "edge"), nmax = 1L)

# setup
Expand Down Expand Up @@ -307,7 +307,7 @@ methods::setMethod(
}

# for each layer
nSteps <- nLayers * (1 + length(offsets) + 6)
nSteps <- nLayers * (2 + length(offsets) + 6) + 1
if (verbose | faster("verbose")) {
pb <- utils::txtProgressBar(min = 0, max = nSteps, initial = 0, style = 3, width = 30)
}
Expand All @@ -330,13 +330,14 @@ methods::setMethod(
created <- c(created, srcXZeros)

### connectivities (for Pff)
srcConnectivities <- .makeSourceName("fragmentation_connectivities", "raster", n = length(offsets))
srcEither <- .makeSourceName("fragmentation_either", "raster", n = length(offsets))
srcBoth <- .makeSourceName("fragmentation_both", n = length(offsets))
n <- length(offsets)
srcConnectivities <- paste0('c', 1:n) # .makeSourceName("frag_connect", "raster", n = length(offsets))
srcEither <- paste0('e', 1:n) # .makeSourceName("frag_either", "raster", n = length(offsets))
srcBoth <- paste0('b', 1:n) # .makeSourceName("frag_both", n = length(offsets))
for (j in seq_along(offsets)) {

steps <- steps + 1
if (verbose | faster("verbose")) utils::setTxtProgressBar(pb, steps)
if (verbose || faster("verbose")) utils::setTxtProgressBar(pb, steps)

# tally occurrences of habitat in each pair of cells
y1 <- offsets[[j]][1L]
Expand All @@ -346,26 +347,25 @@ methods::setMethod(
x2 <- offsets[[j]][4L]

# sum of pairs of cells
ex <- paste0(srcConnectivities[j], " = ", srcXZeros, "[", y1, ",", x1, "] + ", srcXZeros, "[", y2, ",", x2, "]")
ex <- paste0(srcConnectivities[j], " = ", srcXZeros, "[", y1, ",", x1, "]+", srcXZeros, "[", y2, ",", x2, "]")
rgrass::execGRASS("r.mapcalc", expression = ex, flags = c(.quiet(), "overwrite"))

# does either cell in a pair have habitat?
ex <- paste0(srcEither[j], " = if(", srcConnectivities[j], " >= 1)")
ex <- paste0(srcEither[j], " = if(", srcConnectivities[j], ">= 1)")
rgrass::execGRASS("r.mapcalc", expression = ex, flags = c(.quiet(), "overwrite"))

# do both cells have habitat?
ex <- paste0(srcBoth[j], " = if(", srcConnectivities[j], " == 2)")
ex <- paste0(srcBoth[j], " = if(", srcConnectivities[j], "==2)")
rgrass::execGRASS("r.mapcalc", expression = ex, flags = c(.quiet(), "overwrite"))

}
created <- c(created, srcConnectivities, srcEither, srcBoth)


# number of neighbor cell pairs with at least one with habitat
steps <- steps + 1
if (verbose | faster("verbose")) utils::setTxtProgressBar(pb, steps)
srcNumEithers <- .makeSourceName("fragmentation_sum_eithers", "raster")
ex <- paste0(srcNumEithers, " = ", paste(srcEither, collapse = " + "))
ex <- paste0(srcNumEithers, " = ", paste(srcEither, collapse = "+"))
rgrass::execGRASS("r.mapcalc", expression = ex, flags = c(.quiet(), "overwrite"))

created <- c(created, srcNumEithers)
Expand Down Expand Up @@ -486,13 +486,17 @@ methods::setMethod(

# }

srcs[i] <- src

steps <- steps + 1
if (verbose | faster("verbose")) utils::setTxtProgressBar(pb, steps)
.rm(created, type = "raster", warn = FALSE)
created <- character()

srcs[i] <- src

} # next layer

steps <- steps + 1
if (verbose | faster("verbose")) utils::setTxtProgressBar(pb, steps)
if (verbose | faster("verbose")) close(pb)

levs <- .fragmentationLevels(undet = undet, none = none)
Expand Down
16 changes: 9 additions & 7 deletions R/geomorphons.r
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ methods::setMethod(
) {

unit <- omnibus::pmatchSafe(unit, c("cells", "meters"), nmax = 1L)
comparison <- omnibus::pmatchSafe(mode, c("1", "2", "2d"), nmax = 1L)
comparison <-if (comparison == "1") {
"anglev1"
} else if (comparison == "2") {
"anglev2"
} else if (comparison == "2d") {
"anglev2_distance"
mode <- as.character(mode)
if (mode == "1") {
comparison <- "anglev1"
} else if (mode == "2") {
comparison <- "anglev2"
} else if (mode == "2d") {
comparison <- "anglev2_distance"
} else {
stop("Argument `mode` can only be `1`, `2`, or `2d`.")
}

if (nlyr(x) > 1L) stop("This function requires `x` to have just one layer.")
Expand Down
Loading