├── .github
├── .gitignore
├── workflows
│ ├── R-CMD-check.yaml
│ ├── test-coverage.yaml
│ ├── pkgdown.yaml
│ └── progress-tracker.yml
└── template.R
├── R
├── env.R
├── crs.R
├── checks.R
├── write.R
├── utils_documentation.R
├── read.R
├── math.R
├── plot.R
├── conversion.R
├── matrix.R
├── print.R
├── installation.R
├── summary.R
├── WhiteboxClasses.R
├── terra.R
├── system.R
├── dimensions.R
├── hillshade.R
└── zzz.R
├── vignettes
└── articles
│ ├── .gitignore
│ ├── tutorials.Rmd
│ ├── FAQ.Rmd
│ └── Tutorial-2.Rmd
├── LICENSE
├── .gitignore
├── inst
├── extdata
│ ├── dem.tif
│ └── dem.tif.aux.xml
└── wbw_helpers.py
├── man
├── figures
│ ├── logo.png
│ ├── README-terra-1.png
│ └── src
│ │ └── wbw_social_preview.png
├── rd_example.Rd
├── rd_wbw_link.Rd
├── rd_input_raster.Rd
├── wbw_version.Rd
├── wbw_get_name.Rd
├── checks.Rd
├── print.wbw-colon-colon-WhiteboxRaster.Rd
├── wbw_ext.Rd
├── resolution.Rd
├── plot.wbw-colon-colon-WhiteboxRaster.Rd
├── dimensions.Rd
├── xy.coords.wbw-colon-colon-WhiteboxRaster.Rd
├── WhiteboxExtent.Rd
├── as_wbw_raster.Rd
├── io.Rd
├── as_rast.Rd
├── matrix.Rd
├── wbw_to_degrees.Rd
├── wbw_to_radians.Rd
├── WhiteboxRaster.Rd
├── print_geotiff_tags.Rd
├── datatype.Rd
├── wbw_max_procs.Rd
├── wbw_write_raster.Rd
├── wbw_gaussian_filter.Rd
├── vector.Rd
├── wbw_range_filter.Rd
├── wbw_random_sample.Rd
├── wbw_install.Rd
├── wbw_maximum_filter.Rd
├── wbw_minimum_filter.Rd
├── wbw_ruggedness_index.Rd
├── wbw_majority_filter.Rd
├── wbw_total_filter.Rd
├── wbw_download_sample_data.Rd
├── wbw_high_pass_filter.Rd
├── wbw_olympic_filter.Rd
├── wbw_adaptive_filter.Rd
├── wbw_standard_deviation_filter.Rd
├── wbw_slope.Rd
├── wbw_mean_filter.Rd
├── wbw_high_pass_median_filter.Rd
├── summarize.Rd
├── wbw_aspect.Rd
├── wbw_conservative_smoothing_filter.Rd
├── wbw_bilateral_filter.Rd
├── wbw_fill_missing_data.Rd
├── wbw_hillshade.Rd
├── wbw_median_filter.Rd
├── wbw_plan_curvature.Rd
├── wbw_multidirectional_hillshade.Rd
├── wbw_percentile_filter.Rd
├── wbw_mean_curvature.Rd
├── wbw_gaussian_curvature.Rd
├── wbw_maximal_curvature.Rd
├── wbw_minimal_curvature.Rd
└── wbw_profile_curvature.Rd
├── pkgdown
├── favicon
│ ├── favicon.ico
│ ├── favicon-96x96.png
│ ├── apple-touch-icon.png
│ ├── web-app-manifest-192x192.png
│ ├── web-app-manifest-512x512.png
│ └── site.webmanifest
└── index.md
├── tests
├── tinytest
│ ├── test_zzz.R
│ ├── test_conversions.R
│ ├── test_system.R
│ ├── test_math.R
│ ├── test_crs.R
│ ├── setup.R
│ ├── test_print.R
│ ├── test_dims.R
│ ├── test_checks.R
│ ├── test_terra.R
│ ├── test_utils_documentation.R
│ ├── test_io.R
│ ├── test_primitives.R
│ ├── test_geomorphometry.R
│ ├── test_curvature.R
│ └── test_filter.R
└── test.R
├── .Rbuildignore
├── NEWS.md
├── codecov.yml
├── LICENSE.md
├── DESCRIPTION
├── NAMESPACE
├── _pkgdown.yml
└── CONTRIBUTING.md
/.github/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 |
--------------------------------------------------------------------------------
/R/env.R:
--------------------------------------------------------------------------------
1 | wbw_env <- new.env()
2 |
--------------------------------------------------------------------------------
/vignettes/articles/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | *.R
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2025
2 | COPYRIGHT HOLDER: wbw authors
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | /playground/
3 | docs
4 | README.Rmd
--------------------------------------------------------------------------------
/inst/extdata/dem.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/inst/extdata/dem.tif
--------------------------------------------------------------------------------
/man/figures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/man/figures/logo.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/pkgdown/favicon/favicon.ico
--------------------------------------------------------------------------------
/man/figures/README-terra-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/man/figures/README-terra-1.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/pkgdown/favicon/favicon-96x96.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/pkgdown/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/man/figures/src/wbw_social_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/man/figures/src/wbw_social_preview.png
--------------------------------------------------------------------------------
/pkgdown/favicon/web-app-manifest-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/pkgdown/favicon/web-app-manifest-192x192.png
--------------------------------------------------------------------------------
/pkgdown/favicon/web-app-manifest-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atsyplenkov/wbw/HEAD/pkgdown/favicon/web-app-manifest-512x512.png
--------------------------------------------------------------------------------
/tests/tinytest/test_zzz.R:
--------------------------------------------------------------------------------
1 | # Test version string format
2 | version <- wbw_version()
3 | expect_true(is.character(version))
4 | expect_true(grepl("^\\d+\\.\\d+\\.\\d+$", version))
5 |
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^wbw\.Rproj$
2 | ^\.Rproj\.user$
3 | ^LICENSE\.md$
4 | ^playground$
5 | ^playground/
6 | /playground/
7 | ^README\.Rmd$
8 | ^\.github$
9 | ^codecov\.yml$
10 | ^CONTRIBUTING\.md$
11 | ^_pkgdown\.yml$
12 | ^docs$
13 | ^pkgdown$
14 | ^vignettes/articles$
15 | ^man/figures/src$
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # wbw 0.0.2 (2024-01-09)
2 |
3 | * Swithced from `{testthat}` to `{tinytest}` to
4 | reduce dependencies
5 |
6 | # wbw 0.0.2 (2024-01-07)
7 |
8 | * Documentation updates:
9 | - Added FAQ
10 | - Tutorial No. 2
11 | - Benchmarks
12 |
13 | # wbw 0.0.1 (2024-12-26)
14 |
15 | * MVP
16 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | comment: false
2 |
3 | coverage:
4 | status:
5 | project:
6 | default:
7 | target: auto
8 | threshold: 1%
9 | informational: true
10 | patch:
11 | default:
12 | target: auto
13 | threshold: 1%
14 | informational: true
15 |
--------------------------------------------------------------------------------
/man/rd_example.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils_documentation.R
3 | \name{rd_example}
4 | \alias{rd_example}
5 | \title{Create basic example}
6 | \usage{
7 | rd_example(foo, args = NULL)
8 | }
9 | \description{
10 | Create basic example
11 | }
12 | \keyword{internal}
13 |
--------------------------------------------------------------------------------
/man/rd_wbw_link.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils_documentation.R
3 | \name{rd_wbw_link}
4 | \alias{rd_wbw_link}
5 | \title{Create reference tags for docs}
6 | \usage{
7 | rd_wbw_link(fun_name)
8 | }
9 | \description{
10 | Links to the Whitebox Workflows for Python manual
11 | }
12 | \keyword{internal}
13 |
--------------------------------------------------------------------------------
/man/rd_input_raster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utils_documentation.R
3 | \name{rd_input_raster}
4 | \alias{rd_input_raster}
5 | \title{Create input parameter tag}
6 | \usage{
7 | rd_input_raster(param)
8 | }
9 | \description{
10 | Description of input \link{WhiteboxRaster} object
11 | }
12 | \keyword{internal}
13 |
--------------------------------------------------------------------------------
/man/wbw_version.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/zzz.R
3 | \name{wbw_version}
4 | \alias{wbw_version}
5 | \title{\code{wbw_version()}: Gets the \verb{Whitebox Workflows} version}
6 | \usage{
7 | wbw_version()
8 | }
9 | \value{
10 | character. Version Number.
11 | }
12 | \description{
13 | \code{wbw_version()}: Gets the \verb{Whitebox Workflows} version
14 | }
15 |
--------------------------------------------------------------------------------
/tests/test.R:
--------------------------------------------------------------------------------
1 | # Run package tests
2 | if (requireNamespace("tinytest", quietly = TRUE)) {
3 | # Initialize session
4 | have_wbw <- reticulate::py_module_available("whitebox_workflows")
5 | have_numpy <- reticulate::py_module_available("numpy")
6 | if (!have_wbw & !have_numpy) {
7 | wbw_install(system = TRUE)
8 | }
9 |
10 | tinytest::test_package("wbw", pattern = "^test_.*\\.[rR]$")
11 | }
--------------------------------------------------------------------------------
/man/wbw_get_name.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/read.R
3 | \name{wbw_get_name}
4 | \alias{wbw_get_name}
5 | \title{Get File Name from Path}
6 | \usage{
7 | wbw_get_name(path)
8 | }
9 | \arguments{
10 | \item{path}{\code{character}, file path}
11 | }
12 | \value{
13 | \code{character}, file name
14 | }
15 | \description{
16 | Extracts the file name from a full path string.
17 | }
18 | \keyword{internal}
19 |
--------------------------------------------------------------------------------
/tests/tinytest/test_conversions.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | slope_deg <- wbw_slope(x, units = "d")
4 | slope_rad <- wbw_slope(x, units = "r")
5 | deg_to_rad <- wbw_to_radians(slope_deg)
6 | rad_to_deg <- wbw_to_degrees(slope_rad)
7 |
8 | expect_inherits(deg_to_rad, c("wbw::WhiteboxRaster", "S7_object"))
9 | expect_inherits(rad_to_deg, c("wbw::WhiteboxRaster", "S7_object"))
10 | expect_equal(mean(slope_rad), mean(deg_to_rad))
11 | expect_equal(mean(slope_deg), mean(rad_to_deg))
12 |
--------------------------------------------------------------------------------
/inst/extdata/dem.tif.aux.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | YES
5 | 360.84683227539
6 | 167.16138323474
7 | 64.347480773926
8 | 49.205704393024
9 | 100
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/tinytest/test_system.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test invalid max_procs settings
4 | expect_error(wbw_max_procs(0))
5 | expect_error(wbw_max_procs(-20))
6 | expect_error(wbw_max_procs(1.1))
7 |
8 | # Test performance with different max_procs settings
9 | wbw_max_procs(-1)
10 | t_parallel <- system.time(wbw_slope(x))
11 |
12 | wbw_max_procs(1)
13 | t_1 <- system.time(wbw_slope(x))
14 |
15 | # Check that parallel processing is faster
16 | expect_true(t_1[3] >= t_parallel[3])
17 |
--------------------------------------------------------------------------------
/tests/tinytest/test_math.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test random sample generation
4 | expect_inherits(wbw_random_sample(x), c("wbw::WhiteboxRaster", "S7_object"))
5 | expect_inherits(
6 | wbw_random_sample(x, num_samples = 1),
7 | c("wbw::WhiteboxRaster", "S7_object")
8 | )
9 |
10 | # Test error conditions
11 | expect_error(wbw_random_sample(x, num_samples = -1))
12 | expect_error(wbw_random_sample(x, num_samples = runif(1)))
13 | expect_error(wbw_random_sample(x, num_samples = x@source$num_cells() + 1))
14 |
--------------------------------------------------------------------------------
/tests/tinytest/test_crs.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test extent extraction
4 | ext <- wbw_ext(x)
5 | expect_inherits(ext, c("wbw::WhiteboxExtent", "S7_object"))
6 |
7 | # Test individual components
8 | expect_identical(ext@west, x@source$configs$west)
9 | expect_identical(ext@east, x@source$configs$east)
10 | expect_identical(ext@south, x@source$configs$south)
11 | expect_identical(ext@north, x@source$configs$north)
12 |
13 | # Test error cases
14 | expect_error(wbw_ext("x"))
15 | expect_error(wbw_ext(NULL))
16 |
--------------------------------------------------------------------------------
/pkgdown/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "",
3 | "short_name": "",
4 | "icons": [
5 | {
6 | "src": "/web-app-manifest-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png",
9 | "purpose": "maskable"
10 | },
11 | {
12 | "src": "/web-app-manifest-512x512.png",
13 | "sizes": "512x512",
14 | "type": "image/png",
15 | "purpose": "maskable"
16 | }
17 | ],
18 | "theme_color": "#ffffff",
19 | "background_color": "#ffffff",
20 | "display": "standalone"
21 | }
--------------------------------------------------------------------------------
/man/checks.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/checks.R
3 | \name{check_package}
4 | \alias{check_package}
5 | \alias{check_env}
6 | \alias{check_input_file}
7 | \title{Check if package is installed}
8 | \usage{
9 | check_package(package)
10 |
11 | check_env(env = wbe)
12 |
13 | check_input_file(file_name, type)
14 | }
15 | \description{
16 | Check if package is installed
17 |
18 | Check if whitebox environment is present
19 |
20 | Check input file extension
21 | }
22 | \keyword{internal}
23 |
--------------------------------------------------------------------------------
/man/print.wbw-colon-colon-WhiteboxRaster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/print.R
3 | \name{print.wbw::WhiteboxRaster}
4 | \alias{print.wbw::WhiteboxRaster}
5 | \title{Print Method for WhiteboxRaster}
6 | \usage{
7 | \method{print}{`wbw::WhiteboxRaster`}(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{\link{WhiteboxRaster} object to print}
11 |
12 | \item{...}{additional arguments passed to print method}
13 | }
14 | \description{
15 | Print Method for WhiteboxRaster
16 | }
17 | \keyword{methods}
18 |
--------------------------------------------------------------------------------
/man/wbw_ext.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/crs.R
3 | \name{wbw_ext}
4 | \alias{wbw_ext}
5 | \title{Get WhiteboxExtent}
6 | \usage{
7 | wbw_ext(x)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 | }
12 | \description{
13 | Get WhiteboxExtent
14 | }
15 | \examples{
16 | f <- system.file("extdata/dem.tif", package = "wbw")
17 | wbw_read_raster(f) |>
18 | wbw_ext()
19 | }
20 | \keyword{crs}
21 |
--------------------------------------------------------------------------------
/tests/tinytest/setup.R:
--------------------------------------------------------------------------------
1 | library(tinytest)
2 | library(wbw)
3 |
4 | # Load New Zealand DEM
5 | raster_path <- system.file("extdata/dem.tif", package = "wbw")
6 | x <- wbw_read_raster(raster_path)
7 |
8 | # Path to terra's files
9 | if (requireNamespace("terra", quietly = TRUE)) {
10 | library(terra)
11 | f <- system.file("ex/elev.tif", package = "terra")
12 | }
13 |
14 | # Helper functions
15 | skip_if_not_installed <- function(pkg) {
16 | if (!requireNamespace(pkg, quietly = TRUE)) {
17 | exit_file("Package", pkg, "not available")
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/man/resolution.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dimensions.R
3 | \name{wbw_res}
4 | \alias{wbw_res}
5 | \alias{wbw_xres}
6 | \alias{wbw_yres}
7 | \title{Get WhiteboxRaster resolution (x and y)}
8 | \usage{
9 | wbw_res(x)
10 |
11 | wbw_xres(x)
12 |
13 | wbw_yres(x)
14 | }
15 | \arguments{
16 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
17 | }
18 | \value{
19 | \code{double} Vector containing x and y resolution
20 | }
21 | \description{
22 | Get WhiteboxRaster resolution (x and y)
23 | }
24 | \keyword{utils}
25 |
--------------------------------------------------------------------------------
/vignettes/articles/tutorials.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Tutorials"
3 | output:
4 | rmarkdown::html_vignette:
5 | toc: false
6 | vignette: >
7 | %\VignetteIndexEntry{Tutorials}
8 | %\VignetteEngine{knitr::rmarkdown}
9 | %\VignetteEncoding{UTF-8}
10 | ---
11 |
12 | A list of the original [Whitebox Workflows for Python](https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tutorials.html) tutorials, rewritten in R with the `{wbw}` and `{terra}` packages.
13 |
14 | ◽ Tutorial 1: Hydrological Analysis
15 | ◽ [Tutorial 2: Geomorphometric Analysis](Tutorial-2.html)
16 | ◽ Tutorial 3: Mapping Building Footprints from LiDAR
17 |
--------------------------------------------------------------------------------
/man/plot.wbw-colon-colon-WhiteboxRaster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/plot.R
3 | \name{plot.wbw::WhiteboxRaster}
4 | \alias{plot.wbw::WhiteboxRaster}
5 | \title{Plot WhiteboxRaster}
6 | \usage{
7 | \method{plot}{`wbw::WhiteboxRaster`}(x, col = grDevices::terrain.colors(100), add = FALSE, ...)
8 | }
9 | \arguments{
10 | \item{x}{WhiteboxRaster object}
11 |
12 | \item{col}{Colors to use for plotting}
13 |
14 | \item{add}{Logical, whether to add to existing plot}
15 |
16 | \item{...}{Additional arguments passed to plot}
17 | }
18 | \description{
19 | Plot WhiteboxRaster
20 | }
21 | \keyword{methods}
22 |
--------------------------------------------------------------------------------
/R/crs.R:
--------------------------------------------------------------------------------
1 | #' Get WhiteboxExtent
2 | #' @keywords crs
3 | #'
4 | #' @eval rd_input_raster("x")
5 | #'
6 | #' @examples
7 | #' f <- system.file("extdata/dem.tif", package = "wbw")
8 | #' wbw_read_raster(f) |>
9 | #' wbw_ext()
10 | #' @export
11 | wbw_ext <- S7::new_generic(
12 | name = "wbw_ext",
13 | dispatch_args = "x",
14 | fun = function(x) {
15 | # Add some input validation
16 | S7::S7_dispatch()
17 | }
18 | )
19 |
20 | S7::method(wbw_ext, WhiteboxRaster) <- function(x) {
21 | # Checks
22 | conf <- x@source$configs
23 | WhiteboxExtent(
24 | west = conf$west,
25 | east = conf$east,
26 | south = conf$south,
27 | north = conf$north
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/man/dimensions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dimensions.R
3 | \name{num_cells}
4 | \alias{num_cells}
5 | \alias{wbw_rows}
6 | \alias{wbw_cols}
7 | \title{Get dimensions of a WhiteboxRaster or WhiteboxVector object}
8 | \usage{
9 | num_cells(x)
10 |
11 | wbw_rows(x)
12 |
13 | wbw_cols(x)
14 | }
15 | \arguments{
16 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
17 | }
18 | \value{
19 | \code{integer} Number of cells in the raster
20 | }
21 | \description{
22 | Get dimensions of a WhiteboxRaster or WhiteboxVector object
23 | }
24 | \keyword{utils}
25 |
--------------------------------------------------------------------------------
/man/xy.coords.wbw-colon-colon-WhiteboxRaster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/plot.R
3 | \name{xy.coords.wbw::WhiteboxRaster}
4 | \alias{xy.coords.wbw::WhiteboxRaster}
5 | \title{Convert WhiteboxRaster to x-y coordinates}
6 | \usage{
7 | `xy.coords.wbw::WhiteboxRaster`(x, ...)
8 | }
9 | \arguments{
10 | \item{x}{WhiteboxRaster object}
11 |
12 | \item{...}{additional arguments (not used)}
13 | }
14 | \value{
15 | A list with NULL x and y components
16 | }
17 | \description{
18 | This is an internal method used by the plotting system.
19 | It returns NULL coordinates to prevent default plotting behavior.
20 | }
21 | \keyword{internal}
22 |
--------------------------------------------------------------------------------
/man/WhiteboxExtent.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/WhiteboxClasses.R
3 | \name{WhiteboxExtent}
4 | \alias{WhiteboxExtent}
5 | \title{WhiteboxExtent Class}
6 | \usage{
7 | WhiteboxExtent(
8 | west = numeric(0),
9 | east = numeric(0),
10 | south = numeric(0),
11 | north = numeric(0)
12 | )
13 | }
14 | \arguments{
15 | \item{west}{\code{double} Western boundary coordinate}
16 |
17 | \item{east}{\code{double} Eastern boundary coordinate}
18 |
19 | \item{south}{\code{double} Southern boundary coordinate}
20 |
21 | \item{north}{\code{double} Northern boundary coordinate}
22 | }
23 | \description{
24 | Defines the spatial extent of a raster dataset using coordinates for
25 | the west, east, south, and north boundaries.
26 | }
27 | \keyword{class}
28 |
--------------------------------------------------------------------------------
/man/as_wbw_raster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/terra.R
3 | \name{as_wbw_raster}
4 | \alias{as_wbw_raster}
5 | \title{Convert SpatRaster to WhiteboxRaster}
6 | \usage{
7 | as_wbw_raster(x)
8 | }
9 | \arguments{
10 | \item{x}{SpatRaster object}
11 | }
12 | \value{
13 | \link{WhiteboxRaster} object
14 | }
15 | \description{
16 | Convert SpatRaster to WhiteboxRaster
17 | }
18 | \examples{
19 | \dontrun{
20 | library(terra)
21 | f <- system.file("extdata/dem.tif", package = "wbw")
22 | rast(f) |>
23 | as_wbw_raster()
24 | }
25 | }
26 | \seealso{
27 | \code{\link[=WhiteboxRaster]{WhiteboxRaster()}}
28 | }
29 | \keyword{Converts}
30 | \keyword{SpatRaster}
31 | \keyword{[WhiteboxRaster]}
32 | \keyword{a}
33 | \keyword{object}
34 | \keyword{terra}
35 | \keyword{to}
36 |
--------------------------------------------------------------------------------
/man/io.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/read.R
3 | \name{wbw_read_raster}
4 | \alias{wbw_read_raster}
5 | \alias{wbw_read_vector}
6 | \title{Read Raster File as WhiteboxRaster}
7 | \usage{
8 | wbw_read_raster(file_name)
9 |
10 | wbw_read_vector(file_name)
11 | }
12 | \arguments{
13 | \item{file_name}{\code{character}, path to ESRI shapefile}
14 | }
15 | \value{
16 | WhiteboxRaster object
17 |
18 | WhiteboxVector object
19 | }
20 | \description{
21 | Creates a new WhiteboxRaster object by reading raster data from a file
22 | into memory.
23 |
24 | Creates a new WhiteboxVector object by reading vector data from an ESRI
25 | shapefile into memory.
26 | }
27 | \examples{
28 | f <- system.file("extdata/dem.tif", package = "wbw")
29 | wbw_read_raster(f)
30 |
31 | }
32 | \keyword{io}
33 |
--------------------------------------------------------------------------------
/man/as_rast.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/terra.R
3 | \name{as_rast}
4 | \alias{as_rast}
5 | \title{Convert WhiteboxRaster to SpatRaster}
6 | \usage{
7 | as_rast(x)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 | }
12 | \value{
13 | SpatRaster object
14 | }
15 | \description{
16 | Convert WhiteboxRaster to SpatRaster
17 | }
18 | \examples{
19 | \dontrun{
20 | f <- system.file("extdata/dem.tif", package = "wbw")
21 | wbw_read_raster(f) |>
22 | wbw_slope(units = "r") |>
23 | as_rast()
24 | }
25 | }
26 | \seealso{
27 | \code{\link[=WhiteboxRaster]{WhiteboxRaster()}}
28 | }
29 | \keyword{Converts}
30 | \keyword{SpatRaster}
31 | \keyword{[WhiteboxRaster]}
32 | \keyword{a}
33 | \keyword{object}
34 | \keyword{terra}
35 | \keyword{to}
36 |
--------------------------------------------------------------------------------
/man/matrix.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/matrix.R
3 | \name{as_matrix}
4 | \alias{as_matrix}
5 | \title{Convert WhiteboxRaster to Matrix}
6 | \usage{
7 | as_matrix(x, raw = FALSE)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{raw}{logical. Should the raw data be returned (\code{raw = TRUE}) or should
13 | NoData values be transformed to \code{NA} (\code{raw = FALSE})?}
14 | }
15 | \value{
16 | matrix containing raster values
17 | }
18 | \description{
19 | Converts a WhiteboxRaster object to a matrix. The output maintains the same
20 | dimensions and cell values as the input raster.
21 | }
22 | \examples{
23 | f <- system.file("extdata/dem.tif", package = "wbw")
24 | wbw_read_raster(f) |>
25 | as_matrix(raw = TRUE)
26 | }
27 | \keyword{transform}
28 |
--------------------------------------------------------------------------------
/tests/tinytest/test_print.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Reading geotiff tags
4 | expected_out <- c(
5 | "+-----------------------------------------------+ ",
6 | "| WhiteboxRaster |",
7 | "| dem.tif |",
8 | "|...............................................| ",
9 | "| bands : 1 |",
10 | "| dimensions : 726, 800 (nrow, ncol) |",
11 | "| resolution : 5.002392, 5.000243 (x, y) |",
12 | "| EPSG : 2193 (Linear_Meter) |",
13 | "| extent : 1925449 1929446 5582091 5585717 |",
14 | "| min value : 63.698193 |",
15 | "| max value : 361.020721 |",
16 | "+-----------------------------------------------+ "
17 | )
18 |
19 | expect_equal(
20 | paste(utils::capture.output(print(x)), collapse = "\n"),
21 | paste(expected_out, collapse = "\n")
22 | )
23 |
--------------------------------------------------------------------------------
/man/wbw_to_degrees.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/conversion.R
3 | \name{wbw_to_degrees}
4 | \alias{wbw_to_degrees}
5 | \title{Convert to degrees}
6 | \usage{
7 | wbw_to_degrees(x)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 | }
12 | \value{
13 | \link{WhiteboxRaster} object in degrees
14 | }
15 | \description{
16 | Convert to degrees
17 | }
18 | \examples{
19 | f <- system.file("extdata/dem.tif", package = "wbw")
20 | wbw_read_raster(f) |>
21 | wbw_slope(units = "r") |>
22 | wbw_to_degrees()
23 | }
24 | \seealso{
25 | \code{\link[=wbw_to_radians]{wbw_to_radians()}}, \code{\link[=wbw_slope]{wbw_slope()}}
26 | }
27 | \keyword{Converts}
28 | \keyword{[WhiteboxRaster]}
29 | \keyword{a}
30 | \keyword{conversions}
31 | \keyword{degrees}
32 | \keyword{from}
33 | \keyword{radians}
34 | \keyword{to}
35 |
--------------------------------------------------------------------------------
/man/wbw_to_radians.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/conversion.R
3 | \name{wbw_to_radians}
4 | \alias{wbw_to_radians}
5 | \title{Convert to radians}
6 | \usage{
7 | wbw_to_radians(x)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 | }
12 | \value{
13 | \link{WhiteboxRaster} object in radians
14 | }
15 | \description{
16 | Convert to radians
17 | }
18 | \examples{
19 | f <- system.file("extdata/dem.tif", package = "wbw")
20 | wbw_read_raster(f) |>
21 | wbw_slope(units = "d") |>
22 | wbw_to_radians()
23 | }
24 | \seealso{
25 | \code{\link[=wbw_to_degrees]{wbw_to_degrees()}}, \code{\link[=wbw_slope]{wbw_slope()}}
26 | }
27 | \keyword{Converts}
28 | \keyword{[WhiteboxRaster]}
29 | \keyword{a}
30 | \keyword{conversions}
31 | \keyword{degrees}
32 | \keyword{from}
33 | \keyword{radians}
34 | \keyword{to}
35 |
--------------------------------------------------------------------------------
/man/WhiteboxRaster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/WhiteboxClasses.R
3 | \name{WhiteboxRaster}
4 | \alias{WhiteboxRaster}
5 | \title{WhiteboxRaster Class}
6 | \usage{
7 | WhiteboxRaster(name = character(0), source = NULL)
8 | }
9 | \arguments{
10 | \item{name}{\code{character} Name of the raster}
11 |
12 | \item{source}{\code{any} Source data for the raster}
13 | }
14 | \description{
15 | Represents a raster dataset in Whitebox Workflows for Python (WbW) format.
16 | Provides access to raster properties including name, Python pointer, summary
17 | statistics, and min/max values.
18 | }
19 | \section{Properties}{
20 |
21 | \describe{
22 | \item{stats}{\code{character} Summary statistics for the raster}
23 | \item{min}{\code{numeric} Minimum value for the raster}
24 | \item{max}{\code{numeric} Maximum value for the raster}
25 | \item{extent}{\code{WhiteboxExtent} Spatial extent of the raster}
26 | }
27 | }
28 |
29 | \keyword{class}
30 |
--------------------------------------------------------------------------------
/man/print_geotiff_tags.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/print.R
3 | \name{print_geotiff_tags}
4 | \alias{print_geotiff_tags}
5 | \title{Print GeoTIFF Tags}
6 | \usage{
7 | print_geotiff_tags(file_name)
8 | }
9 | \arguments{
10 | \item{file_name}{\code{character}, path to raster file}
11 | }
12 | \description{
13 | Displays the tags contained within a GeoTIFF file. This is useful when
14 | importing GeoTIFF files into different software environments. The tool prints
15 | tag information to the console. Tags containing more than 100 values are
16 | truncated in the output. GeoKeys are interpreted according to the GeoTIFF
17 | specification.
18 | }
19 | \examples{
20 | \dontrun{
21 | raster_path <- system.file("extdata/dem.tif", package = "wbw")
22 | print_geotiff_tags(raster_path)
23 | }
24 |
25 | }
26 | \references{
27 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#print_geotiff_tags}
28 | }
29 | \keyword{utils}
30 |
--------------------------------------------------------------------------------
/man/datatype.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/dimensions.R
3 | \name{wbw_data_type}
4 | \alias{wbw_data_type}
5 | \alias{wbw_is_int}
6 | \alias{wbw_is_float}
7 | \alias{wbw_is_rgb}
8 | \title{Get WhiteboxRaster data type}
9 | \usage{
10 | wbw_data_type(x)
11 |
12 | wbw_is_int(x)
13 |
14 | wbw_is_float(x)
15 |
16 | wbw_is_rgb(x)
17 | }
18 | \arguments{
19 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
20 | }
21 | \value{
22 | \code{character} String representing the raster data type
23 | }
24 | \description{
25 | Get WhiteboxRaster data type
26 | }
27 | \examples{
28 | f <- system.file("extdata/dem.tif", package = "wbw")
29 | wbw_read_raster(f) |>
30 | wbw_data_type()
31 | f <- system.file("extdata/dem.tif", package = "wbw")
32 | wbw_read_raster(f) |>
33 | wbw_is_int()
34 | f <- system.file("extdata/dem.tif", package = "wbw")
35 | wbw_read_raster(f) |>
36 | wbw_is_float()
37 | f <- system.file("extdata/dem.tif", package = "wbw")
38 | wbw_read_raster(f) |>
39 | wbw_is_rgb()
40 | }
41 | \keyword{utils}
42 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2025 wbw authors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/tinytest/test_dims.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 | skip_if_not_installed("terra")
3 |
4 | r <- terra::rast(raster_path)
5 |
6 | # Test dimension functions
7 | expect_equal(num_cells(x), terra::ncell(r))
8 | expect_equal(wbw_cols(x), terra::ncol(r))
9 | expect_equal(wbw_rows(x), terra::nrow(r))
10 | expect_equal(wbw_res(x), terra::res(r))
11 | expect_equal(wbw_yres(x), terra::yres(r))
12 | expect_equal(wbw_xres(x), terra::xres(r))
13 |
14 | # Test data type detection
15 | r2 <- terra::rast(f)
16 | x2 <- wbw_read_raster(f)
17 |
18 | # Compare with terra
19 | expect_equal(wbw_is_int(x), terra::is.int(r))
20 | expect_equal(wbw_is_int(x2), terra::is.int(r2))
21 | expect_equal(wbw_data_type(x2), "RasterDataType.I16")
22 | expect_equal(wbw_data_type(x), "RasterDataType.F32")
23 |
24 | # Check output class
25 | expect_true(is.logical(wbw_is_int(x)))
26 | expect_true(is.logical(wbw_is_float(x)))
27 | expect_true(is.logical(wbw_is_rgb(x)))
28 | expect_true(is.character(wbw_data_type(x)))
29 |
30 | # Check input validation
31 | expect_error(wbw_is_int(r))
32 | expect_error(wbw_is_float(r))
33 | expect_error(wbw_is_rgb(r))
34 | expect_error(wbw_data_type(r))
35 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: wbw
2 | Title: Whitebox Workflows for R
3 | Version: 0.0.3
4 | URL: https://wbw.anatolii.nz
5 | BugReports: https://github.com/atsyplenkov/wbw/issues
6 | Authors@R: c(person(given = "Anatoly", family = "Tsyplenkov", role = c("aut", "cre"), email = "atsyplenkov@fastmail.com", comment = c(ORCID = "0000-0003-4144-8402")))
7 | Maintainer: Anatoly Tsyplenkov
8 | Description: Provides R bindings to the proprietary Whitebox Workflows Python library, developed by Whitebox Geospatial Inc. 'Whitebox Workflows' is an advanced geospatial data analysis library for Geographic Information Systems (GIS) and remote sensing analysis, as well as manipulation of raster, vector, and LiDAR data.
9 | License: MIT + file LICENSE
10 | Encoding: UTF-8
11 | Language: en-US
12 | Roxygen: list(markdown = TRUE)
13 | RoxygenNote: 7.3.2
14 | Imports:
15 | cli,
16 | checkmate,
17 | reticulate,
18 | S7 (>= 0.2.0),
19 | graphics,
20 | grDevices,
21 | stats
22 | Suggests:
23 | tinytest,
24 | terra
25 | SystemRequirements: Python (>= 3.8.0), numpy, whitebox-workflows (>= v1.3.3)
26 | Config/Needs/website: rmarkdown, waldo, bench, whitebox, ggplot2, tidyr
27 |
--------------------------------------------------------------------------------
/man/wbw_max_procs.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/system.R
3 | \name{wbw_max_procs}
4 | \alias{wbw_max_procs}
5 | \title{Set Maximum Parallel Processors}
6 | \usage{
7 | wbw_max_procs(max_procs = -1)
8 | }
9 | \arguments{
10 | \item{max_procs}{\code{integer} Number of processors to use. Use -1 for all
11 | available processors, or a positive integer to limit processor usage.}
12 | }
13 | \description{
14 | Determines the number of processors used by functions that are parallelized.
15 | If set to -1 (\code{max_procs=-1}), the default, all available processors will be
16 | used. To limit processing, set \code{max_procs} to a positive whole number less
17 | than the number of system processors.
18 | }
19 | \examples{
20 | \dontrun{
21 | raster_path <- system.file("extdata/dem.tif", package = "wbw")
22 | x <- wbw_read_raster(raster_path)
23 |
24 | # Use 1 processor
25 | wbw_max_procs(1)
26 | system.time(wbw_slope(x))
27 |
28 | # Use all available processors
29 | wbw_max_procs(-1)
30 | system.time(wbw_slope(x))
31 | }
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#max_procs}
35 | }
36 | \keyword{system}
37 |
--------------------------------------------------------------------------------
/man/wbw_write_raster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/write.R
3 | \name{wbw_write_raster}
4 | \alias{wbw_write_raster}
5 | \title{Writes an in-memory WhiteboxRaster object to file.}
6 | \usage{
7 | wbw_write_raster(x, file_name, compress = TRUE)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{file_name}{\code{character} Path to output file}
13 |
14 | \item{compress}{\code{logical} Whether to compress the output file}
15 | }
16 | \description{
17 | Writes an in-memory WhiteboxRaster object to a file in a supported raster
18 | format.
19 | }
20 | \details{
21 | Supported raster formats:
22 | \itemize{
23 | \item GeoTIFF (*.tif, *.tiff)
24 | \item Big GeoTIFF (*.tif, *.tiff)
25 | \item SAGA Binary (*.sdat, *.sgrd)
26 | \item Idrisi (*.rst, *.rdc)
27 | \item Surfer (*.grd)
28 | \item ESRI Binary (*.flt)
29 | \item ESRI BIL (*.bil)
30 | }
31 |
32 | The tool can read GeoTIFFs compressed using PackBits, DEFLATE, or LZW
33 | methods.
34 |
35 | When writing GeoTIFFs, use \code{compress=TRUE} to enable DEFLATE compression.
36 | }
37 | \references{
38 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#write_raster}
39 | }
40 | \keyword{io}
41 |
--------------------------------------------------------------------------------
/R/checks.R:
--------------------------------------------------------------------------------
1 | #' Check if package is installed
2 | #' @rdname checks
3 | #' @keywords internal
4 | check_package <- function(package) {
5 | if (!requireNamespace(package, quietly = TRUE)) {
6 | stop(paste(package, "is required but not installed."))
7 | }
8 | }
9 |
10 | #' Check if whitebox environment is present
11 | #' @rdname checks
12 | #' @keywords internal
13 | check_env <- function(env = wbe) {
14 | checkmate::assert_class(
15 | env,
16 | classes = c(
17 | "whitebox_workflows.WbEnvironment",
18 | "python.builtin.WbEnvironmentBase",
19 | "python.builtin.object"
20 | )
21 | )
22 | }
23 |
24 | #' Check input file extension
25 | #' @rdname checks
26 | #' @keywords internal
27 | check_input_file <- function(file_name, type) {
28 | type <- checkmate::matchArg(type, c("vector", "raster"))
29 |
30 | if (type == "vector") {
31 | checkmate::assertFileExists(
32 | file_name,
33 | access = "r",
34 | extension = c(".shp")
35 | )
36 | } else if (type == "raster") {
37 | checkmate::assertFileExists(
38 | file_name,
39 | access = "r",
40 | extension = c(
41 | ".tif",
42 | ".tiff",
43 | ".sdat",
44 | ".sgrd",
45 | ".rst",
46 | ".rdc",
47 | ".grd",
48 | ".flt",
49 | ".bil"
50 | )
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/man/wbw_gaussian_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_gaussian_filter}
4 | \alias{wbw_gaussian_filter}
5 | \title{Gaussian Filter}
6 | \usage{
7 | wbw_gaussian_filter(x, sigma = 0.75)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{sigma}{\code{double}, standard deviation distance parameter in
13 | \strong{units of grid cells}. Should be in the range 0.5-20.}
14 | }
15 | \value{
16 | \link{WhiteboxRaster} object containing filtered values
17 | }
18 | \description{
19 | Applies a Gaussian smoothing filter to reduce noise while better preserving
20 | image features compared to a simple mean filter.
21 | }
22 | \details{
23 | The filter applies a 2D Gaussian kernel that weights pixels based on their
24 | distance from the center. This gradual weighting makes it more effective for
25 | noise reduction than the mean filter. The filter size is controlled by the
26 | sigma parameter (0.5-20 grid cells).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_gaussian_filter(sigma = 1.5)
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#gaussian_filter}
35 | }
36 | \seealso{
37 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}
38 | }
39 | \keyword{image_processing}
40 |
--------------------------------------------------------------------------------
/R/write.R:
--------------------------------------------------------------------------------
1 | #' Writes an in-memory WhiteboxRaster object to file.
2 | #' @rdname wbw_write_raster
3 | #' @keywords io
4 | #'
5 | #' @description
6 | #' Writes an in-memory WhiteboxRaster object to a file in a supported raster
7 | #' format.
8 | #'
9 | #' @eval rd_wbw_link("write_raster")
10 | #' @eval rd_input_raster("x")
11 | #'
12 | #' @param file_name \code{character} Path to output file
13 | #' @param compress \code{logical} Whether to compress the output file
14 | #'
15 | #' @details
16 | #' Supported raster formats:
17 | #' - GeoTIFF (*.tif, *.tiff)
18 | #' - Big GeoTIFF (*.tif, *.tiff)
19 | #' - SAGA Binary (*.sdat, *.sgrd)
20 | #' - Idrisi (*.rst, *.rdc)
21 | #' - Surfer (*.grd)
22 | #' - ESRI Binary (*.flt)
23 | #' - ESRI BIL (*.bil)
24 | #'
25 | #' The tool can read GeoTIFFs compressed using PackBits, DEFLATE, or LZW
26 | #' methods.
27 | #'
28 | #' When writing GeoTIFFs, use `compress=TRUE` to enable DEFLATE compression.
29 | #'
30 | #' @export
31 | wbw_write_raster <- S7::new_generic(
32 | name = "wbw_write_raster",
33 | dispatch_args = "x",
34 | fun = function(x, file_name, compress = TRUE) {
35 | S7::S7_dispatch()
36 | }
37 | )
38 |
39 | S7::method(wbw_write_raster, WhiteboxRaster) <- function(
40 | x,
41 | file_name,
42 | compress = TRUE
43 | ) {
44 | # Checks
45 | check_env(wbe)
46 | checkmate::assert_logical(compress, len = 1)
47 | # Write
48 | wbe$write_raster(x@source, file_name = file_name, compress = compress)
49 | }
50 |
--------------------------------------------------------------------------------
/tests/tinytest/test_checks.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Package checks
4 | expect_silent(wbw:::check_package("base"))
5 | expect_error(wbw:::check_package("nonexistentpackage123"))
6 |
7 | # Environment checks
8 | mock_env <- structure(
9 | list(),
10 | class = c(
11 | "whitebox_workflows.WbEnvironment",
12 | "python.builtin.WbEnvironmentBase",
13 | "python.builtin.object"
14 | )
15 | )
16 |
17 | expect_silent(wbw:::check_env(mock_env))
18 | expect_error(wbw:::check_env(list()))
19 | expect_error(wbw:::check_env(NULL))
20 |
21 | # Vector file checks
22 | temp_shp <- tempfile(fileext = ".shp")
23 | file.create(temp_shp)
24 |
25 | expect_silent(wbw:::check_input_file(temp_shp, "vector"))
26 | expect_error(wbw:::check_input_file("nonexistent.shp", "vector"))
27 |
28 | temp_wrong <- tempfile(fileext = ".txt")
29 | file.create(temp_wrong)
30 | expect_error(wbw:::check_input_file(temp_wrong, "vector"))
31 |
32 | # Raster file checks
33 | temp_tif <- tempfile(fileext = ".tif")
34 | file.create(temp_tif)
35 |
36 | expect_silent(wbw:::check_input_file(temp_tif, "raster"))
37 | expect_error(wbw:::check_input_file("nonexistent.tif", "raster"))
38 |
39 | temp_wrong <- tempfile(fileext = ".txt")
40 | file.create(temp_wrong)
41 | expect_error(wbw:::check_input_file(temp_wrong, "raster"))
42 |
43 | # Type validation
44 | expect_error(wbw:::check_input_file(temp_file, "invalid_type"))
45 |
46 | # Cleanup
47 | unlink(temp_shp)
48 | unlink(temp_wrong)
49 | unlink(temp_tif)
50 |
--------------------------------------------------------------------------------
/man/vector.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/matrix.R
3 | \name{as_vector}
4 | \alias{as_vector}
5 | \alias{as_vector,WhiteboxRaster-method}
6 | \alias{as_vector,WhiteboxExtent-method}
7 | \title{Convert objects to vectors}
8 | \usage{
9 | \S4method{as_vector}{WhiteboxRaster}(x, raw = FALSE)
10 | \S4method{as_vector}{WhiteboxExtent}(x)
11 | }
12 | \arguments{
13 | \item{x}{Object to convert to vector. Can be:
14 | \itemize{
15 | \item A \link{WhiteboxRaster} object
16 | \item A \link{WhiteboxExtent} object
17 | }}
18 |
19 | \item{raw}{logical. For \link{WhiteboxRaster} only: Should the raw data be
20 | returned (\code{raw = TRUE}) or should NoData values be transformed
21 | to \code{NA} (\code{raw = FALSE})?}
22 | }
23 | \value{
24 | A vector, with type depending on the input:
25 | \itemize{
26 | \item For \link{WhiteboxRaster}: vector containing raster values
27 | \item For \link{WhiteboxExtent}: named vector containing extent values
28 | }
29 | }
30 | \description{
31 | Converts various Whitebox objects to vectors:
32 | \itemize{
33 | \item For \link{WhiteboxRaster}: converts raster values to a vector in row-major
34 | order
35 | \item For \link{WhiteboxExtent}: converts extent boundaries to a named vector
36 | }
37 | }
38 | \examples{
39 | f <- system.file("extdata/dem.tif", package = "wbw")
40 | x <- wbw_read_raster(f)
41 |
42 | # Return WhiteboxRaster's data:
43 | head(as_vector(x))
44 |
45 | # Return WhiteboxExtent's data:
46 | as_vector(wbw_ext(x))
47 |
48 | }
49 | \keyword{transform}
50 |
--------------------------------------------------------------------------------
/man/wbw_range_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_range_filter}
4 | \alias{wbw_range_filter}
5 | \title{Range Filter}
6 | \usage{
7 | wbw_range_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | A range filter assigns to each cell in the output grid the range
21 | (maximum - minimum) of the values contained within a moving window
22 | centred on each grid cell.
23 | }
24 | \details{
25 | Neighbourhood size, or filter size, is specified in the x and y dimensions
26 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
27 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
28 | }
29 | \examples{
30 | f <- system.file("extdata/dem.tif", package = "wbw")
31 | wbw_read_raster(f) |>
32 | wbw_range_filter(filter_size_x = 3L, filter_size_y = 3L)
33 | }
34 | \references{
35 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#range_filter}
36 | }
37 | \seealso{
38 | \code{\link[=wbw_minimum_filter]{wbw_minimum_filter()}}, \code{\link[=wbw_maximum_filter]{wbw_maximum_filter()}}
39 | }
40 | \keyword{image_processing}
41 |
--------------------------------------------------------------------------------
/man/wbw_random_sample.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/math.R
3 | \name{wbw_random_sample}
4 | \alias{wbw_random_sample}
5 | \title{Random Sample}
6 | \usage{
7 | wbw_random_sample(x, num_samples = 1000L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{num_samples}{\code{integer}, number of random samples. Must not exceed
13 | the total number of valid cells in the input raster (see \code{\link[=num_cells]{num_cells()}}).}
14 | }
15 | \value{
16 | \link{WhiteboxRaster} object
17 | }
18 | \description{
19 | Creates a random sample of grid cells from a raster. Uses the input
20 | WhiteboxRaster to determine grid dimensions and georeference information for
21 | the output.
22 |
23 | The output grid will contain the specified number of non-zero grid cells,
24 | randomly distributed throughout the raster. Each sampled cell will have a
25 | unique value from 1 to num_samples, with background cells set to zero.
26 | }
27 | \details{
28 | This tool is useful for statistical analyses of raster data where a random
29 | sampling approach is needed. The sampling process only considers valid,
30 | non-NoData cells from the input raster.
31 | }
32 | \examples{
33 | f <- system.file("extdata/dem.tif", package = "wbw")
34 | wbw_read_raster(f) |>
35 | wbw_random_sample(num_samples = 100)
36 | }
37 | \references{
38 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#random_sample}
39 | }
40 | \keyword{math}
41 |
--------------------------------------------------------------------------------
/R/utils_documentation.R:
--------------------------------------------------------------------------------
1 | #' Create reference tags for docs
2 | #'
3 | #' @description
4 | #' Links to the Whitebox Workflows for Python manual
5 | #'
6 | #' @keywords internal
7 | rd_wbw_link <- function(fun_name) {
8 | checkmate::assert_character(fun_name, min.chars = 1L)
9 | paste0(
10 | "@references For more information, see ",
11 | ""
15 | )
16 | }
17 |
18 | #' Create input parameter tag
19 | #'
20 | #' @description
21 | #' Description of input [WhiteboxRaster] object
22 | #'
23 | #' @keywords internal
24 | rd_input_raster <- function(param) {
25 | checkmate::assert_character(param, min.chars = 1L)
26 | paste0(
27 | "@param ",
28 | param,
29 | " Raster object of class [WhiteboxRaster]. ",
30 | "See [wbw_read_raster()] for more details."
31 | )
32 | }
33 |
34 | #' Create basic example
35 | #'
36 | #' @keywords internal
37 | rd_example <- function(foo, args = NULL) {
38 | checkmate::assert_character(foo, min.chars = 1L)
39 | checkmate::assert_vector(args, null.ok = TRUE)
40 | paste(
41 | "@examples",
42 | # "\\dontrun{",
43 | 'f <- system.file("extdata/dem.tif", package = "wbw")',
44 | "wbw_read_raster(f) |>",
45 | ifelse(
46 | is.null(args),
47 | paste0(" ", foo, "()"),
48 | paste0(
49 | " ",
50 | foo,
51 | "(",
52 | paste(args, collapse = ", "),
53 | ")"
54 | )
55 | ),
56 | # "}",
57 | sep = "\n"
58 | )
59 | }
60 |
--------------------------------------------------------------------------------
/man/wbw_install.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/installation.R
3 | \name{wbw_install}
4 | \alias{wbw_install}
5 | \title{Install Required Python Modules}
6 | \usage{
7 | wbw_install(system = FALSE, force = FALSE, ...)
8 | }
9 | \arguments{
10 | \item{system}{\code{boolean}, Use a \code{system()} call to
11 | \code{python -m pip install --user ...}
12 | instead of \code{reticulate::py_install()}. Default: \code{FALSE}.}
13 |
14 | \item{force}{\code{boolean}, Force update (uninstall/reinstall) and ignore
15 | existing installed packages? Default: \code{FALSE}.
16 | Applies to \code{system=TRUE}.}
17 |
18 | \item{...}{Additional arguments passed to \code{reticulate::py_install()}}
19 | }
20 | \value{
21 | \code{NULL}, or \code{try-error} (invisibly) on R code execution error.
22 | }
23 | \description{
24 | Install Required Python Modules
25 | }
26 | \details{
27 | This function provides a basic wrapper around
28 | \code{reticulate::py_install()}, except it defaults to using the Python package
29 | manager \code{pip} and virtual environment. It creates the \code{r-wbw}
30 | virtual environment in the default location
31 | (run \code{reticulate::virtualenv_root()} to find it) and installs the
32 | required python packages.
33 | }
34 | \keyword{The}
35 | \keyword{This}
36 | \keyword{\code{numpy},}
37 | \keyword{\code{pip}}
38 | \keyword{\code{whitebox-workflows}.}
39 | \keyword{default}
40 | \keyword{for}
41 | \keyword{function}
42 | \keyword{installation.}
43 | \keyword{installs}
44 | \keyword{latest}
45 | \keyword{package}
46 | \keyword{system}
47 | \keyword{the}
48 | \keyword{uses}
49 |
--------------------------------------------------------------------------------
/man/wbw_maximum_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_maximum_filter}
4 | \alias{wbw_maximum_filter}
5 | \title{Maximum Filter}
6 | \usage{
7 | wbw_maximum_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | Assigns each cell in the output grid the maximum value in a moving window
21 | centred on each grid cell in the input raster.
22 | }
23 | \details{
24 | Neighbourhood size, or filter size, is specified in the x and y dimensions
25 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
26 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_maximum_filter(filter_size_x = 3L, filter_size_y = 3L)
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#maximum_filter}
35 | }
36 | \seealso{
37 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_high_pass_filter]{wbw_high_pass_filter()}},
38 | \code{\link[=wbw_high_pass_median_filter]{wbw_high_pass_median_filter()}}
39 | }
40 | \keyword{image_processing}
41 |
--------------------------------------------------------------------------------
/man/wbw_minimum_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_minimum_filter}
4 | \alias{wbw_minimum_filter}
5 | \title{Minimum Filter}
6 | \usage{
7 | wbw_minimum_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | Assigns each cell in the output grid the minimum value in a moving window
21 | centred on each grid cell in the input raster.
22 | }
23 | \details{
24 | Neighbourhood size, or filter size, is specified in the x and y dimensions
25 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
26 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_minimum_filter(filter_size_x = 3L, filter_size_y = 3L)
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#minimum_filter}
35 | }
36 | \seealso{
37 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_high_pass_filter]{wbw_high_pass_filter()}},
38 | \code{\link[=wbw_high_pass_median_filter]{wbw_high_pass_median_filter()}}
39 | }
40 | \keyword{image_processing}
41 |
--------------------------------------------------------------------------------
/man/wbw_ruggedness_index.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geomorphometry.R
3 | \name{wbw_ruggedness_index}
4 | \alias{wbw_ruggedness_index}
5 | \title{Terrain Ruggedness Index (TRI)}
6 | \usage{
7 | wbw_ruggedness_index(dem)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 | }
12 | \value{
13 | \link{WhiteboxRaster} object containing TRI values
14 | }
15 | \description{
16 | Calculates a measure of local topographic relief. The TRI computes the
17 | root-mean-square-deviation (RMSD) for each grid cell in a DEM by calculating
18 | the residuals between a cell and its eight neighbors.
19 | }
20 | \details{
21 | Unlike the original Riley et al. (1999) TRI, this implementation normalizes
22 | for the number of cells in the local window. This modification allows for
23 | varying numbers of neighboring cells along grid edges and areas bordering
24 | NoData cells. Note that this means output values cannot be directly compared
25 | with the index ranges (level to extremely rugged terrain) provided in Riley
26 | et al. (1999).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_ruggedness_index()
32 | }
33 | \references{
34 | Riley, S. J., DeGloria, S. D., and Elliot, R. (1999). Index that quantifies
35 | topographic heterogeneity. Intermountain Journal of Sciences, 5(1-4), 23-27.
36 |
37 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#ruggedness_index}
38 | }
39 | \keyword{geomorphometry}
40 |
--------------------------------------------------------------------------------
/.github/workflows/R-CMD-check.yaml:
--------------------------------------------------------------------------------
1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
3 | on:
4 | # workflow_dispatch:
5 | push:
6 | branches: [main, master]
7 | pull_request:
8 |
9 | name: R-CMD-check.yaml
10 |
11 | permissions: read-all
12 |
13 | jobs:
14 | R-CMD-check:
15 | runs-on: ${{ matrix.config.os }}
16 |
17 | name: ${{ matrix.config.os }} (${{ matrix.config.r }})
18 |
19 | strategy:
20 | fail-fast: false
21 | matrix:
22 | config:
23 | - {os: macos-latest, r: 'release'}
24 | - {os: windows-latest, r: 'release'}
25 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
26 | - {os: ubuntu-latest, r: 'release'}
27 | - {os: ubuntu-latest, r: 'oldrel-1'}
28 |
29 | env:
30 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
31 | R_KEEP_PKG_SOURCE: yes
32 |
33 | steps:
34 | - uses: actions/checkout@v4
35 |
36 | - uses: r-lib/actions/setup-pandoc@v2
37 |
38 | - uses: r-lib/actions/setup-r@v2
39 | with:
40 | r-version: ${{ matrix.config.r }}
41 | http-user-agent: ${{ matrix.config.http-user-agent }}
42 | use-public-rspm: true
43 |
44 | - uses: r-lib/actions/setup-r-dependencies@v2
45 | with:
46 | extra-packages: any::rcmdcheck
47 | needs: check
48 |
49 | - uses: r-lib/actions/check-r-package@v2
50 | with:
51 | upload-snapshots: true
52 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
53 |
--------------------------------------------------------------------------------
/man/wbw_majority_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_majority_filter}
4 | \alias{wbw_majority_filter}
5 | \title{Majority Filter}
6 | \usage{
7 | wbw_majority_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | Assigns each cell in the output grid the most frequently occurring value
21 | (mode) in a moving window centred on each grid cell in the input raster.
22 | }
23 | \details{
24 | Neighbourhood size, or filter size, is specified in the x and y dimensions
25 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
26 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_majority_filter(filter_size_x = 3L, filter_size_y = 3L)
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#majority_filter}
35 | }
36 | \seealso{
37 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_high_pass_filter]{wbw_high_pass_filter()}},
38 | \code{\link[=wbw_high_pass_median_filter]{wbw_high_pass_median_filter()}}
39 | }
40 | \keyword{image_processing}
41 |
--------------------------------------------------------------------------------
/man/wbw_total_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_total_filter}
4 | \alias{wbw_total_filter}
5 | \title{Total Filter}
6 | \usage{
7 | wbw_total_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | A total filter assigns to each cell in the output grid the total (sum)
21 | of all values in a moving window centred on each grid cell.
22 | }
23 | \details{
24 | Neighbourhood size, or filter size, is specified in the x and y dimensions
25 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
26 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
27 | }
28 | \examples{
29 | f <- system.file("extdata/dem.tif", package = "wbw")
30 | wbw_read_raster(f) |>
31 | wbw_total_filter(filter_size_x = 3L, filter_size_y = 3L)
32 | }
33 | \references{
34 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#total_filter}
35 | }
36 | \seealso{
37 | \code{\link[=wbw_minimum_filter]{wbw_minimum_filter()}}, \code{\link[=wbw_maximum_filter]{wbw_maximum_filter()}},
38 | \code{\link[=wbw_range_filter]{wbw_range_filter()}}, \code{\link[=wbw_majority_filter]{wbw_majority_filter()}}
39 | }
40 | \keyword{image_processing}
41 |
--------------------------------------------------------------------------------
/R/read.R:
--------------------------------------------------------------------------------
1 | #' Read Raster File as WhiteboxRaster
2 | #' @rdname io
3 | #' @keywords io
4 | #'
5 | #' @description
6 | #' Creates a new WhiteboxRaster object by reading raster data from a file
7 | #' into memory.
8 | #'
9 | #' @param file_name \code{character}, path to raster file
10 | #'
11 | #' @return WhiteboxRaster object
12 | #'
13 | #' @examples
14 | #' f <- system.file("extdata/dem.tif", package = "wbw")
15 | #' wbw_read_raster(f)
16 | #'
17 | #' @export
18 | wbw_read_raster <- function(file_name) {
19 | check_env(wbe)
20 | check_input_file(file_name, "r")
21 | r <- wbe$read_raster(file_name = file_name)
22 | WhiteboxRaster(
23 | name = wbw_get_name(file_name),
24 | source = r
25 | )
26 | }
27 |
28 | #' Read Vector File as WhiteboxVector
29 | #' @rdname io
30 | #' @keywords io
31 | #'
32 | #' @description
33 | #' Creates a new WhiteboxVector object by reading vector data from an ESRI
34 | #' shapefile into memory.
35 | #'
36 | #' @param file_name \code{character}, path to ESRI shapefile
37 | #'
38 | #' @return WhiteboxVector object
39 | #'
40 | #' @export
41 | wbw_read_vector <- function(file_name) {
42 | check_env(wbe)
43 | check_input_file(file_name, "v")
44 | wbe$read_vector(file_name = file_name)
45 | }
46 |
47 | #' Get File Name from Path
48 | #'
49 | #' @description
50 | #' Extracts the file name from a full path string.
51 | #'
52 | #' @param path \code{character}, file path
53 | #' @return \code{character}, file name
54 | #'
55 | #' @keywords internal
56 | wbw_get_name <- function(path) {
57 | checkmate::assertFile(path, access = "r")
58 | names <- strsplit(path, "/")[[1]]
59 | enc2utf8(names[length(names)])
60 | }
61 |
--------------------------------------------------------------------------------
/tests/tinytest/test_terra.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | skip_if_not_installed("terra")
4 |
5 | # Test WhiteboxRaster to SpatRaster conversion
6 | r <- terra::rast(raster_path)
7 | wbwr <- as_rast(x)
8 |
9 | # Test extent
10 | expect_identical(
11 | as.vector(terra::ext(r)),
12 | as.vector(terra::ext(wbwr))
13 | )
14 |
15 | # Test content
16 | expect_identical(
17 | as.vector(r),
18 | as.vector(wbwr)
19 | )
20 |
21 | # Test resolution
22 | expect_identical(
23 | terra::res(r),
24 | terra::res(wbwr)
25 | )
26 |
27 | # Test CRS
28 | expect_identical(
29 | terra::crs(r),
30 | terra::crs(wbwr)
31 | )
32 |
33 | # Test data type
34 | expect_identical(
35 | terra::is.int(r),
36 | terra::is.int(wbwr)
37 | )
38 |
39 | # Test integer data
40 | r <- terra::rast(f)
41 | r <- terra::as.int(r)
42 | wbwr <- wbw_read_raster(f)
43 | converted <- as_rast(wbwr)
44 |
45 | expect_true(terra::is.int(converted))
46 | expect_true(terra::is.int(r))
47 | expect_equal(as.vector(converted), as.vector(r))
48 |
49 | # Test NA handling
50 | r <- terra::rast(f)
51 | r[r < mean(r[], na.rm = TRUE)] <- NA
52 | wbwr <- as_wbw_raster(r)
53 | converted <- as_rast(wbwr)
54 |
55 | expect_equal(sum(is.na(converted[])), sum(is.na(r[])))
56 | expect_equal(as.vector(converted), as.vector(r))
57 |
58 | # Test CRS conversion
59 | r <- terra::rast(f)
60 | r <- terra::project(r, "EPSG:4326")
61 | wbwr <- as_wbw_raster(r)
62 | converted <- as_rast(wbwr)
63 |
64 | expect_equal(terra::crs(converted), terra::crs(r))
65 | expect_equal(as.vector(converted), as.vector(r))
66 |
67 | # Test multilayer error
68 | r <- terra::rast(f)
69 | r2 <- c(r, r)
70 | expect_error(as_wbw_raster(r2))
71 |
--------------------------------------------------------------------------------
/tests/tinytest/test_utils_documentation.R:
--------------------------------------------------------------------------------
1 | # Test rd_wbw_link function
2 | expected <- paste0(
3 | "@references For more information, see ",
4 | ""
7 | )
8 | expect_equal(wbw:::rd_wbw_link("slope"), expected)
9 |
10 | # Test with underscores
11 | expected <- paste0(
12 | "@references For more information, see ",
13 | ""
16 | )
17 | expect_equal(wbw:::rd_wbw_link("breach_depressions"), expected)
18 |
19 | # Test rd_input_raster function
20 | expected <- paste0(
21 | "@param dem Raster object of class [WhiteboxRaster]. ",
22 | "See [wbw_read_raster()] for more details."
23 | )
24 | expect_equal(wbw:::rd_input_raster("dem"), expected)
25 |
26 | # Test rd_example function
27 | expected <- paste(
28 | "@examples",
29 | 'f <- system.file("extdata/dem.tif", package = "wbw")',
30 | "wbw_read_raster(f) |>",
31 | " slope()",
32 | sep = "\n"
33 | )
34 | expect_equal(wbw:::rd_example("slope"), expected)
35 |
36 | # Test with arguments
37 | expected <- paste(
38 | "@examples",
39 | 'f <- system.file("extdata/dem.tif", package = "wbw")',
40 | "wbw_read_raster(f) |>",
41 | " slope(units = 'degrees')",
42 | sep = "\n"
43 | )
44 | expect_equal(wbw:::rd_example("slope", "units = 'degrees'"), expected)
45 |
46 | # Test error cases
47 | expect_error(wbw:::rd_wbw_link(""))
48 | expect_error(wbw:::rd_input_raster(""))
49 | expect_error(wbw:::rd_example(""))
50 | expect_error(wbw:::rd_wbw_link(NULL))
51 | expect_error(wbw:::rd_input_raster(NULL))
52 | expect_error(wbw:::rd_example(NULL))
53 |
--------------------------------------------------------------------------------
/man/wbw_download_sample_data.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/system.R
3 | \name{wbw_download_sample_data}
4 | \alias{wbw_download_sample_data}
5 | \title{Download Sample Data}
6 | \usage{
7 | wbw_download_sample_data(data_set = NULL, path = NULL)
8 | }
9 | \arguments{
10 | \item{data_set}{\code{character}, dataset name. See Details}
11 |
12 | \item{path}{\code{character}, path to where download sample datasets. If
13 | \code{NULL}, the currect working directory is used}
14 | }
15 | \description{
16 | There are a number of available sample datasets that can be readily used
17 | to test Whitebox Workflows for Python.
18 | }
19 | \details{
20 | Available datasets:\tabular{lll}{
21 | \strong{Dataset Name} \tab \strong{Description} \tab \strong{Size} \cr
22 | Guelph_landsat \tab Landsat 5 sub-area (7 bands) \tab 10.9 MB \cr
23 | Grand_Junction \tab Small DEM in high-relief terrain \tab 5.8 MB \cr
24 | GTA_lidar \tab Airborne lidar point cloud (LAZ) \tab 54.3 MB \cr
25 | jay_brook \tab Airborne lidar point cloud (LAZ) \tab 76.3 MB \cr
26 | Jay_State_Forest \tab Lidar-derived DEM \tab 27.7 MB \cr
27 | Kitchener_lidar \tab Airborne lidar point cloud (LAZ) \tab 41.6 MB \cr
28 | London_air_photo \tab High-resolution RGB air photo \tab 87.3 MB \cr
29 | mill_brook \tab Airborne lidar point cloud (LAZ) \tab 49.9 MB \cr
30 | peterborough_drumlins \tab Lidar-derived DEM \tab 22.0 MB \cr
31 | Southern_Ontario_roads \tab Vector roads layer \tab 7.1 MB \cr
32 | StElisAk \tab Airborne lidar point cloud (LAZ) \tab 54.5 MB \cr
33 | }
34 | }
35 | \examples{
36 | \dontrun{
37 | # Download sample data
38 | wbw_download_sample_data(data_set = "Guelph_landsat", path = tempdir())
39 | }
40 | }
41 | \keyword{system}
42 |
--------------------------------------------------------------------------------
/.github/workflows/test-coverage.yaml:
--------------------------------------------------------------------------------
1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
3 | on:
4 | # workflow_dispatch:
5 | push:
6 | branches: [main, master]
7 | pull_request:
8 |
9 | name: test-coverage.yaml
10 |
11 | permissions: read-all
12 |
13 | jobs:
14 | test-coverage:
15 | runs-on: ubuntu-latest
16 | env:
17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 |
22 | - uses: r-lib/actions/setup-r@v2
23 | with:
24 | use-public-rspm: true
25 |
26 | - uses: r-lib/actions/setup-r-dependencies@v2
27 | with:
28 | extra-packages: any::covr, any::xml2
29 | needs: coverage
30 |
31 | - name: Test coverage
32 | run: |
33 | cov <- covr::package_coverage(
34 | quiet = FALSE,
35 | clean = FALSE,
36 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
37 | )
38 | covr::to_cobertura(cov)
39 | shell: Rscript {0}
40 |
41 | - uses: codecov/codecov-action@v4
42 | with:
43 | # Fail if error if not on PR, or if on PR and token is given
44 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }}
45 | file: ./cobertura.xml
46 | plugin: noop
47 | disable_search: true
48 | token: ${{ secrets.CODECOV_TOKEN }}
49 |
50 | - name: Upload test results
51 | if: failure()
52 | uses: actions/upload-artifact@v4
53 | with:
54 | name: coverage-test-failures
55 | path: ${{ runner.temp }}/package
--------------------------------------------------------------------------------
/man/wbw_high_pass_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_high_pass_filter}
4 | \alias{wbw_high_pass_filter}
5 | \title{High Pass Filter}
6 | \usage{
7 | wbw_high_pass_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | This tool performs a high-pass filter on a raster image. High-pass filters
21 | can be used to emphasize the short-range variability in an image.
22 | The algorithm operates essentially by subtracting the value at the grid
23 | cell at the centre of the window from the average value in the surrounding
24 | neighbourhood (i.e. window.)
25 | }
26 | \details{
27 | Neighbourhood size, or filter size, is specified in the x and y dimensions
28 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
29 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
30 | }
31 | \examples{
32 | f <- system.file("extdata/dem.tif", package = "wbw")
33 | wbw_read_raster(f) |>
34 | wbw_high_pass_filter(filter_size_x = 3L, filter_size_y = 3L)
35 | }
36 | \references{
37 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#high_pass_filter}
38 | }
39 | \seealso{
40 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_high_pass_median_filter]{wbw_high_pass_median_filter()}}
41 | }
42 | \keyword{image_processing}
43 |
--------------------------------------------------------------------------------
/man/wbw_olympic_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_olympic_filter}
4 | \alias{wbw_olympic_filter}
5 | \title{Olympic Filter}
6 | \usage{
7 | wbw_olympic_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | This filter is a modification of the \link{wbw_mean_filter}, whereby
21 | the highest and lowest values in the kernel are dropped, and the remaining
22 | values are averaged to replace the central pixel. The result is a
23 | low-pass smoothing filter that is more robust than the \link{wbw_mean_filter},
24 | which is more strongly impacted by the presence of outlier values.
25 | It is named after a system of scoring Olympic events.
26 | }
27 | \details{
28 | Neighbourhood size, or filter size, is specified in the x and y dimensions
29 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
30 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
31 | }
32 | \examples{
33 | f <- system.file("extdata/dem.tif", package = "wbw")
34 | wbw_read_raster(f) |>
35 | wbw_olympic_filter(filter_size_x = 3L, filter_size_y = 3L)
36 | }
37 | \references{
38 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#olympic_filter}
39 | }
40 | \seealso{
41 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}
42 | }
43 | \keyword{image_processing}
44 |
--------------------------------------------------------------------------------
/R/math.R:
--------------------------------------------------------------------------------
1 | #' Random Sample
2 | #' @keywords math
3 | #'
4 | #' @description
5 | #' Creates a random sample of grid cells from a raster. Uses the input
6 | #' WhiteboxRaster to determine grid dimensions and georeference information for
7 | #' the output.
8 | #'
9 | #' The output grid will contain the specified number of non-zero grid cells,
10 | #' randomly distributed throughout the raster. Each sampled cell will have a
11 | #' unique value from 1 to num_samples, with background cells set to zero.
12 | #'
13 | #' @details
14 | #' This tool is useful for statistical analyses of raster data where a random
15 | #' sampling approach is needed. The sampling process only considers valid,
16 | #' non-NoData cells from the input raster.
17 | #'
18 | #' @eval rd_input_raster("x")
19 | #' @param num_samples \code{integer}, number of random samples. Must not exceed
20 | #' the total number of valid cells in the input raster (see [num_cells()]).
21 | #'
22 | #' @return [WhiteboxRaster] object
23 | #'
24 | #' @eval rd_wbw_link("random_sample")
25 | #' @eval rd_example("wbw_random_sample", c("num_samples = 100"))
26 | #'
27 | #' @export
28 | wbw_random_sample <- S7::new_generic(
29 | name = "wbw_random_sample",
30 | dispatch_args = "x",
31 | fun = function(x, num_samples = 1000L) {
32 | S7::S7_dispatch()
33 | }
34 | )
35 |
36 | # !NB:
37 | # - set.seed() shouldn't work
38 | S7::method(wbw_random_sample, WhiteboxRaster) <- function(
39 | x,
40 | num_samples = 1000L
41 | ) {
42 | # Checks
43 | check_env(wbe)
44 | num_samples <- checkmate::asInteger(
45 | num_samples,
46 | lower = 1L,
47 | upper = x@source$num_cells(),
48 | len = 1L
49 | )
50 | out <- wbe$random_sample(base_raster = x@source, num_samples = num_samples)
51 | # Return Raster
52 | WhiteboxRaster(
53 | name = x@name,
54 | source = out
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/R/plot.R:
--------------------------------------------------------------------------------
1 | #' @importFrom grDevices xy.coords
2 | NULL
3 |
4 | #' @exportS3Method xy.coords wbw::WhiteboxRaster
5 | NULL
6 |
7 | #' Convert WhiteboxRaster to x-y coordinates
8 | #'
9 | #' This is an internal method used by the plotting system.
10 | #' It returns NULL coordinates to prevent default plotting behavior.
11 | #'
12 | #' @param x WhiteboxRaster object
13 | #' @param ... additional arguments (not used)
14 | #' @return A list with NULL x and y components
15 | #' @keywords internal
16 | #' @export
17 | `xy.coords.wbw::WhiteboxRaster` <- function(x, ...) {
18 | list(x = NULL, y = NULL)
19 | }
20 |
21 | #' Plot WhiteboxRaster
22 | #' @keywords methods
23 | #'
24 | #' @param x WhiteboxRaster object
25 | #' @param col Colors to use for plotting
26 | #' @param add Logical, whether to add to existing plot
27 | #' @param ... Additional arguments passed to plot
28 | #' @export
29 | `plot.wbw::WhiteboxRaster` <- function(
30 | x,
31 | col = grDevices::terrain.colors(100),
32 | add = FALSE,
33 | ...
34 | ) {
35 | # Get raster data as matrix
36 | z <- as_matrix(x, raw = FALSE)
37 |
38 | # Get extent
39 | conf <- x@source$configs
40 | ext <- c(conf$west, conf$east, conf$south, conf$north)
41 |
42 | # Create plot
43 | if (!add) {
44 | graphics::plot.new()
45 | graphics::plot.window(ext[1:2], ext[3:4], asp = 1)
46 | }
47 |
48 | # Plot raster
49 | graphics::rasterImage(
50 | grDevices::as.raster(
51 | matrix(
52 | col[cut(z, breaks = length(col))],
53 | nrow = nrow(z),
54 | ncol = ncol(z)
55 | )
56 | ),
57 | ext[1],
58 | ext[3],
59 | ext[2],
60 | ext[4]
61 | )
62 |
63 | # Add axes and box if not adding to existing plot
64 | if (!add) {
65 | graphics::box()
66 | graphics::axis(1)
67 | graphics::axis(2)
68 | }
69 |
70 | invisible(x)
71 | }
72 |
--------------------------------------------------------------------------------
/man/wbw_adaptive_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_adaptive_filter}
4 | \alias{wbw_adaptive_filter}
5 | \title{Adaptive Filter}
6 | \usage{
7 | wbw_adaptive_filter(x, filter_size_x = 11L, filter_size_y = 11L, threshold = 2)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 |
16 | \item{threshold}{\code{double}}
17 | }
18 | \value{
19 | \link{WhiteboxRaster} object containing filtered values
20 | }
21 | \description{
22 | Applies an adaptive filter to reduce random noise (shot noise) in a raster
23 | image. The filter modifies pixel values only where they differ substantially
24 | from their neighbors.
25 | }
26 | \details{
27 | The algorithm calculates the average value in a moving window centered on
28 | each grid cell. If the absolute difference between the window mean and the
29 | center cell value exceeds the user-defined threshold, the output cell is
30 | assigned the mean value. Otherwise, it retains its original value.
31 |
32 | Neighbourhood size, or filter size, is specified in the x and y dimensions
33 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
34 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
35 | }
36 | \examples{
37 | f <- system.file("extdata/dem.tif", package = "wbw")
38 | wbw_read_raster(f) |>
39 | wbw_adaptive_filter(filter_size_x = 3L, filter_size_y = 3L)
40 | }
41 | \references{
42 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#adaptive_filter}
43 | }
44 | \keyword{image_processing}
45 |
--------------------------------------------------------------------------------
/man/wbw_standard_deviation_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_standard_deviation_filter}
4 | \alias{wbw_standard_deviation_filter}
5 | \title{Standard Deviation Filter}
6 | \usage{
7 | wbw_standard_deviation_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | A standard deviation filter assigns to each cell in the output grid the
21 | standard deviation, a measure of dispersion, of the values contained within
22 | a moving window centred on each grid cell.
23 | }
24 | \details{
25 | Neighbourhood size, or filter size, is specified in the x and y dimensions
26 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
27 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
28 | }
29 | \examples{
30 | f <- system.file("extdata/dem.tif", package = "wbw")
31 | wbw_read_raster(f) |>
32 | wbw_standard_deviation_filter(filter_size_x = 3L, filter_size_y = 3L)
33 | }
34 | \references{
35 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#standard_deviation_filter}
36 | }
37 | \seealso{
38 | \code{\link[=wbw_minimum_filter]{wbw_minimum_filter()}}, \code{\link[=wbw_maximum_filter]{wbw_maximum_filter()}},
39 | \code{\link[=wbw_range_filter]{wbw_range_filter()}}, \code{\link[=wbw_majority_filter]{wbw_majority_filter()}}, \code{\link[=wbw_total_filter]{wbw_total_filter()}}
40 | }
41 | \keyword{image_processing}
42 |
--------------------------------------------------------------------------------
/man/wbw_slope.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geomorphometry.R
3 | \name{wbw_slope}
4 | \alias{wbw_slope}
5 | \title{Slope}
6 | \usage{
7 | wbw_slope(dem, units = "degrees", z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{units}{\code{character},
13 | units of slope: "radians", "degrees", or "percent"}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object containing slope values
22 | }
23 | \description{
24 | Calculates slope gradient (i.e., slope steepness in degrees, radians, or
25 | percent) for each grid cell in an input digital elevation model (DEM).
26 | }
27 | \details{
28 | The tool uses Horn's (1981) 3rd-order finite difference method to estimate
29 | slope. Given the following clock-type grid cell numbering scheme (Gallant and
30 | Wilson, 2000).
31 | }
32 | \examples{
33 | f <- system.file("extdata/dem.tif", package = "wbw")
34 | wbw_read_raster(f) |>
35 | wbw_slope(units = "radians")
36 | }
37 | \references{
38 | Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
39 | in Terrain Analysis: Principles and Applications, edited by J. P. Wilson
40 | and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J.
41 |
42 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#slope}
43 | }
44 | \seealso{
45 | \code{\link[=wbw_to_degrees]{wbw_to_degrees()}}, \code{\link[=wbw_to_radians]{wbw_to_radians()}}, \code{\link[=wbw_aspect]{wbw_aspect()}}
46 | }
47 | \keyword{geomorphometry}
48 |
--------------------------------------------------------------------------------
/.github/workflows/pkgdown.yaml:
--------------------------------------------------------------------------------
1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
2 | # and https://github.com/nwtgck/actions-netlify
3 | on:
4 | push:
5 | branches: [main, master]
6 | pull_request:
7 | branches: [main, master]
8 | release:
9 | types: [published]
10 | workflow_dispatch:
11 |
12 | name: pkgdown.yaml
13 |
14 | permissions: read-all
15 |
16 | jobs:
17 | pkgdown:
18 | runs-on: ubuntu-latest
19 | # Only restrict concurrency for non-PR jobs
20 | concurrency:
21 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
22 | env:
23 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
24 | permissions:
25 | contents: write
26 | steps:
27 | - uses: actions/checkout@v4
28 |
29 | - uses: r-lib/actions/setup-pandoc@v2
30 |
31 | - uses: r-lib/actions/setup-r@v2
32 | with:
33 | use-public-rspm: true
34 |
35 | - uses: r-lib/actions/setup-r-dependencies@v2
36 | with:
37 | extra-packages: any::pkgdown, local::.
38 | needs: website
39 |
40 | - uses: r-lib/actions/setup-tinytex@v2
41 |
42 | - name: Build site
43 | run: pkgdown::build_site(new_process = FALSE, install = FALSE)
44 | shell: Rscript {0}
45 |
46 | - name: Deploy to Netlify
47 | uses: nwtgck/actions-netlify@v3.0
48 | with:
49 | publish-dir: 'docs'
50 | production-branch: master
51 | production-deploy: true
52 | github-token: ${{ secrets.GITHUB_TOKEN }}
53 | deploy-message: "Deploy from GitHub Actions"
54 | enable-pull-request-comment: false
55 | enable-commit-comment: true
56 | overwrites-pull-request-comment: true
57 | env:
58 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
59 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
60 | timeout-minutes: 5
61 |
--------------------------------------------------------------------------------
/R/conversion.R:
--------------------------------------------------------------------------------
1 | #' Convert to radians
2 | #' @keywords conversions
3 | #'
4 | #' Converts a [WhiteboxRaster] from degrees to radians
5 | #'
6 | #' @eval rd_input_raster("x")
7 | #'
8 | #' @return [WhiteboxRaster] object in radians
9 | #'
10 | #' @seealso [wbw_to_degrees()], [wbw_slope()]
11 | #'
12 | #' @examples
13 | #' f <- system.file("extdata/dem.tif", package = "wbw")
14 | #' wbw_read_raster(f) |>
15 | #' wbw_slope(units = "d") |>
16 | #' wbw_to_radians()
17 | #' @export
18 | wbw_to_radians <- S7::new_generic(
19 | name = "wbw_to_radians",
20 | dispatch_args = "x",
21 | fun = function(x) {
22 | S7::S7_dispatch()
23 | }
24 | )
25 |
26 | S7::method(wbw_to_radians, WhiteboxRaster) <- function(x) {
27 | # Checks
28 | check_env(wbe)
29 | # Return Raster
30 | WhiteboxRaster(
31 | name = if (grepl("\\(degrees\\)", x@name)) {
32 | sub("\\(degrees\\)", "(radians)", x@name)
33 | } else {
34 | x@name
35 | },
36 | source = x@source$to_radians()
37 | )
38 | }
39 |
40 | #' Convert to degrees
41 | #' @keywords conversions
42 | #'
43 | #' Converts a [WhiteboxRaster] from radians to degrees
44 | #'
45 | #' @eval rd_input_raster("x")
46 | #'
47 | #' @return [WhiteboxRaster] object in degrees
48 | #'
49 | #' @seealso [wbw_to_radians()], [wbw_slope()]
50 | #'
51 | #' @examples
52 | #' f <- system.file("extdata/dem.tif", package = "wbw")
53 | #' wbw_read_raster(f) |>
54 | #' wbw_slope(units = "r") |>
55 | #' wbw_to_degrees()
56 | #' @export
57 | wbw_to_degrees <- S7::new_generic(
58 | name = "wbw_to_degrees",
59 | dispatch_args = "x",
60 | fun = function(x) {
61 | S7::S7_dispatch()
62 | }
63 | )
64 |
65 | S7::method(wbw_to_degrees, WhiteboxRaster) <- function(x) {
66 | # Checks
67 | check_env(wbe)
68 | # Return Raster
69 | WhiteboxRaster(
70 | name = if (grepl("\\(radians\\)", x@name)) {
71 | sub("\\(radians\\)", "(degrees)", x@name)
72 | } else {
73 | x@name
74 | },
75 | source = x@source$to_degrees()
76 | )
77 | }
78 |
--------------------------------------------------------------------------------
/man/wbw_mean_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_mean_filter}
4 | \alias{wbw_mean_filter}
5 | \title{Mean Filter}
6 | \usage{
7 | wbw_mean_filter(x, filter_size_x = 11L, filter_size_y = 11L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | Applies a mean filter (low-pass filter) to smooth an image by emphasizing
21 | longer-range variability and reducing noise.
22 | }
23 | \details{
24 | Uses an efficient integral image approach (Crow, 1984) that is independent
25 | of filter size. While commonly used, mean filters can be more aggressive in
26 | their smoothing compared to edge-preserving alternatives like the
27 | \link{wbw_bilateral_filter} or \link{wbw_gaussian_filter}.
28 |
29 | Neighbourhood size, or filter size, is specified in the x and y dimensions
30 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
31 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
32 | }
33 | \examples{
34 | f <- system.file("extdata/dem.tif", package = "wbw")
35 | wbw_read_raster(f) |>
36 | wbw_mean_filter(filter_size_x = 3L, filter_size_y = 3L)
37 | }
38 | \references{
39 | Crow, F. C. (1984, January). Summed-area tables for texture mapping.
40 | In ACM SIGGRAPH computer graphics (Vol. 18, No. 3, pp. 207-212). ACM.
41 |
42 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#mean_filter}
43 | }
44 | \seealso{
45 | \code{\link[=wbw_bilateral_filter]{wbw_bilateral_filter()}}, \code{\link[=wbw_gaussian_filter]{wbw_gaussian_filter()}}
46 | }
47 | \keyword{image_processing}
48 |
--------------------------------------------------------------------------------
/man/wbw_high_pass_median_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_high_pass_median_filter}
4 | \alias{wbw_high_pass_median_filter}
5 | \title{High Pass Median Filter}
6 | \usage{
7 | wbw_high_pass_median_filter(
8 | x,
9 | filter_size_x = 11L,
10 | filter_size_y = 11L,
11 | sig_digits = 2L
12 | )
13 | }
14 | \arguments{
15 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
16 |
17 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
18 |
19 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
20 |
21 | \item{sig_digits}{\code{integer}, default 2. Required for rounding of
22 | floating points inputs.}
23 | }
24 | \value{
25 | \link{WhiteboxRaster} object containing filtered values
26 | }
27 | \description{
28 | This tool performs a high-pass median filter on a raster image.
29 | High-pass filters can be used to emphasize the short-range variability in
30 | an image. The algorithm operates essentially by subtracting the value at
31 | the grid cell at the centre of the window from the median value in the
32 | surrounding neighbourhood (i.e. window.)
33 | }
34 | \details{
35 | Neighbourhood size, or filter size, is specified in the x and y dimensions
36 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
37 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
38 | }
39 | \examples{
40 | f <- system.file("extdata/dem.tif", package = "wbw")
41 | wbw_read_raster(f) |>
42 | wbw_high_pass_median_filter(filter_size_x = 3L, filter_size_y = 3L)
43 | }
44 | \references{
45 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#high_pass_median_filter}
46 | }
47 | \seealso{
48 | \code{\link[=wbw_median_filter]{wbw_median_filter()}}, \code{\link[=wbw_high_pass_filter]{wbw_high_pass_filter()}}
49 | }
50 | \keyword{image_processing}
51 |
--------------------------------------------------------------------------------
/man/summarize.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/summary.R
3 | \docType{methods}
4 | \name{summary.wbw::WhiteboxRaster}
5 | \alias{summary.wbw::WhiteboxRaster}
6 | \alias{max.wbw::WhiteboxRaster}
7 | \alias{mean.wbw::WhiteboxRaster}
8 | \alias{median.wbw::WhiteboxRaster}
9 | \alias{min.wbw::WhiteboxRaster}
10 | \alias{stdev}
11 | \alias{variance}
12 | \title{Summary Statistics for WhiteboxRaster}
13 | \usage{
14 | \method{summary}{`wbw::WhiteboxRaster`}(object, ...)
15 |
16 | \method{max}{`wbw::WhiteboxRaster`}(object, ...)
17 |
18 | \method{mean}{`wbw::WhiteboxRaster`}(x, ...)
19 |
20 | \method{median}{`wbw::WhiteboxRaster`}(x, na.rm = FALSE, ...)
21 |
22 | \method{min}{`wbw::WhiteboxRaster`}(object, ...)
23 |
24 | stdev(x)
25 |
26 | variance(x)
27 | }
28 | \arguments{
29 | \item{object}{WhiteboxRaster object}
30 |
31 | \item{...}{additional arguments (not used)}
32 |
33 | \item{x}{WhiteboxRaster object}
34 |
35 | \item{na.rm}{logical indicating whether NA values should
36 | be stripped (not used)}
37 | }
38 | \value{
39 | numeric value
40 | }
41 | \description{
42 | Computes summary statistics for cells in a \link{WhiteboxRaster} object.
43 | }
44 | \examples{
45 | f <- system.file("extdata/dem.tif", package = "wbw")
46 | wbw_read_raster(f) |>
47 | summary()
48 | f <- system.file("extdata/dem.tif", package = "wbw")
49 | wbw_read_raster(f) |>
50 | max()
51 | f <- system.file("extdata/dem.tif", package = "wbw")
52 | wbw_read_raster(f) |>
53 | mean()
54 | f <- system.file("extdata/dem.tif", package = "wbw")
55 | wbw_read_raster(f) |>
56 | median()
57 | f <- system.file("extdata/dem.tif", package = "wbw")
58 | wbw_read_raster(f) |>
59 | min()
60 | f <- system.file("extdata/dem.tif", package = "wbw")
61 | wbw_read_raster(f) |>
62 | stdev()
63 | f <- system.file("extdata/dem.tif", package = "wbw")
64 | wbw_read_raster(f) |>
65 | variance()
66 | }
67 | \references{
68 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#raster_summary_stats}
69 | }
70 | \keyword{stats}
71 |
--------------------------------------------------------------------------------
/.github/template.R:
--------------------------------------------------------------------------------
1 | #' Template {wbw} roxygen2 documentation
2 | #' @rdname template
3 | #' @keywords internal
4 | #'
5 | #' @description
6 | #' This is a template for generating documentation for new Whitebox Workflows
7 | #' for R functions.
8 | #'
9 | #' First, every function description should start with the
10 | #' function name, identical to the original Whitebox Workflows for Python.
11 | #'
12 | #' Then it should be followed by @rdname and @keywords tags. While the @rdname
13 | #' tag could be omitted in cases where you don't want to merge docs of several
14 | #' functions together, the @keywords tag is essential and should follow the
15 | #' grouping by topic, existing for the Whitebox Workflows for Python/QGIS.
16 | #'
17 | #' After @keywords and @rdname, it is essential to provide @description, which
18 | #' should align with the Whitebox Workflows documentation.
19 | #'
20 | #' There are several documentation helpers that can speed up
21 | #' documentation writing. Use them wisely:
22 | #' - @eval rd_input_raster("x") will generate a @param tag describing the input
23 | #' WhiteboxRaster
24 | #' - @eval rd_wbw_link("tool_name") will create a @reference tag with a web
25 | #' link to the original documentation website
26 | #' - @eval rd_example("wbw_ruggedness_index") will generate
27 | #' an @examples tag with a basic workflow inside the \dontrun{} tag.
28 | #'
29 | #' @eval rd_input_raster("dem")
30 | #'
31 | #' @return [WhiteboxRaster] object
32 | #'
33 | #' @eval rd_wbw_link("ruggedness_index")
34 | #' @eval rd_example("wbw_ruggedness_index")
35 | wbw_template <-
36 | S7::new_generic(
37 | name = "wbw_template",
38 | dispatch_args = "x",
39 | fun = function(x, another_arg = NULL) {
40 | S7::S7_dispatch()
41 | }
42 | )
43 |
44 | S7::method(wbw_template, WhiteboxRaster) <-
45 | function(x, another_arg = NULL) {
46 | # Checks
47 | check_env(wbe)
48 | # Estimate slope
49 | out <- wbe$ruggedness_index(input = x@source)
50 | # Return Raster
51 | WhiteboxRaster(
52 | name = paste0("TRI"),
53 | source = out
54 | )
55 | }
56 |
--------------------------------------------------------------------------------
/tests/tinytest/test_io.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Helper function
4 | create_temp_file <- function(ext) {
5 | tmp <- tempfile(fileext = ext)
6 | file.create(tmp)
7 | return(tmp)
8 | }
9 |
10 | # Test wbw_read_raster
11 | expect_inherits(
12 | wbw_read_raster(raster_path),
13 | c("wbw::WhiteboxRaster", "S7_object")
14 | )
15 | expect_error(wbw_read_raster("nonexistent.tif"))
16 |
17 | tmp_txt <- create_temp_file(".txt")
18 | on.exit(unlink(tmp_txt))
19 | expect_error(wbw_read_raster(tmp_txt))
20 |
21 | tmp_shp <- create_temp_file(".shp")
22 | on.exit(unlink(tmp_shp), add = TRUE)
23 | expect_error(wbw_read_vector("nonexistent.shp"))
24 | expect_error(wbw_read_vector(tmp_txt))
25 |
26 | # Test wbw_write_raster
27 | expect_error(wbw_write_raster(mtcars, file_name = tempfile(fileext = ".tif")))
28 |
29 | # Test geotiff compression
30 | tmp_tif_c <- tempfile(fileext = ".tif")
31 | tmp_tiff_c <- tempfile(fileext = ".tiff")
32 | tmp_tif <- tempfile(fileext = ".tif")
33 | tmp_tiff <- tempfile(fileext = ".tiff")
34 | on.exit(
35 | {
36 | unlink(tmp_tif_c)
37 | unlink(tmp_tiff_c)
38 | unlink(tmp_tif)
39 | unlink(tmp_tiff)
40 | },
41 | add = TRUE
42 | )
43 |
44 | wbw_write_raster(x, file_name = tmp_tif_c, compress = TRUE)
45 | wbw_write_raster(x, file_name = tmp_tiff_c, compress = TRUE)
46 | wbw_write_raster(x, file_name = tmp_tif, compress = FALSE)
47 | wbw_write_raster(x, file_name = tmp_tiff, compress = FALSE)
48 |
49 | expect_true(file.size(tmp_tif_c) < file.size(tmp_tif))
50 | expect_true(file.size(tmp_tiff_c) < file.size(tmp_tiff))
51 |
52 | # Test different raster formats
53 | formats <- c(
54 | ".tif",
55 | ".tiff",
56 | ".sgrd",
57 | ".sdat",
58 | ".rst",
59 | ".rdc",
60 | ".bil",
61 | ".flt",
62 | ".grd"
63 | )
64 | temp_files <- vapply(formats, create_temp_file, character(1))
65 | on.exit(unlink(temp_files), add = TRUE)
66 |
67 | for (file in temp_files) {
68 | wbw_write_raster(x, file_name = file)
69 | expect_true(file.exists(file))
70 | expect_inherits(wbw_read_raster(file), c("wbw::WhiteboxRaster", "S7_object"))
71 | }
72 |
--------------------------------------------------------------------------------
/man/wbw_aspect.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geomorphometry.R
3 | \name{wbw_aspect}
4 | \alias{wbw_aspect}
5 | \title{Aspect}
6 | \usage{
7 | wbw_aspect(dem, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{z_factor}{\code{double}, Z conversion factor is only important
13 | when the vertical and horizontal units are not the same in the DEM.
14 | When this is the case, the algorithm will multiply each elevation in the
15 | DEM by the Z conversion factor}
16 | }
17 | \value{
18 | \link{WhiteboxRaster} object containing aspect in degrees
19 | }
20 | \description{
21 | Calculates slope aspect (i.e., slope orientation in degrees clockwise from
22 | north) for each grid cell in an input DEM.
23 | }
24 | \details{
25 | For DEMs in projected coordinate systems, the tool uses the 3rd-order
26 | bivariate Taylor polynomial method described by Florinsky (2016). Based on a
27 | polynomial fit of elevations within the 5x5 neighborhood surrounding each
28 | cell, this method is more robust against outlier elevations (noise) than
29 | other methods.
30 |
31 | For DEMs in geographic coordinate systems (i.e., angular units), the tool
32 | uses the 3x3 polynomial fitting method for equal angle grids also described
33 | by Florinsky (2016).
34 | }
35 | \examples{
36 | f <- system.file("extdata/dem.tif", package = "wbw")
37 | wbw_read_raster(f) |>
38 | wbw_aspect()
39 | }
40 | \references{
41 | Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
42 | in Terrain Analysis: Principles and Applications, edited by J. P. Wilson
43 | and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J.
44 |
45 | Florinsky, I. (2016). Digital terrain analysis in soil science and
46 | geology. Academic Press.
47 |
48 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#aspect}
49 | }
50 | \seealso{
51 | \code{\link[=wbw_to_degrees]{wbw_to_degrees()}}, \code{\link[=wbw_to_radians]{wbw_to_radians()}}, \code{\link[=wbw_slope]{wbw_slope()}}
52 | }
53 | \keyword{geomorphometry}
54 |
--------------------------------------------------------------------------------
/tests/tinytest/test_primitives.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test as_matrix conversion
4 | m <- as_matrix(x)
5 | expect_true(is.matrix(m))
6 | expect_equal(dim(m), c(726, 800))
7 |
8 | # Test as_vector conversion
9 | v <- as_vector(x)
10 | expect_true(is.vector(v))
11 | expect_equal(length(v), num_cells(x))
12 |
13 | # Test summary stats for matrix
14 | expect_equal(max(x), max(m, na.rm = TRUE))
15 | expect_equal(min(x), min(m, na.rm = TRUE))
16 | expect_equal(mean(x), mean(m, na.rm = TRUE))
17 | expect_equal(round(median(x), 4), round(median(m, na.rm = TRUE), 4))
18 | expect_equal(round(wbw::stdev(x), 4), round(sd(m, na.rm = TRUE), 4))
19 |
20 | # Test summary stats for vector
21 | expect_equal(max(x), max(v, na.rm = TRUE))
22 | expect_equal(min(x), min(v, na.rm = TRUE))
23 | expect_equal(mean(x), mean(v, na.rm = TRUE))
24 | expect_equal(round(median(x), 4), round(median(v, na.rm = TRUE), 4))
25 | expect_equal(round(wbw::stdev(x), 4), round(sd(v, na.rm = TRUE), 4))
26 | expect_equal(round(variance(x), 1), round(var(v, na.rm = TRUE), 1))
27 |
28 | # Test summary function output
29 | s <- capture.output(summary(x))
30 | expect_true(any(grepl("minimum", s)))
31 | expect_true(any(grepl("maximum", s)))
32 | expect_true(any(grepl("average", s)))
33 | expect_true(any(grepl("standard deviation", s)))
34 |
35 | # Test NoData handling
36 | exit_if_not(requireNamespace("terra", quietly = TRUE))
37 | r <- wbw_read_raster(f)
38 |
39 | v <- as_vector(r)
40 | v_raw <- as_vector(r, raw = TRUE)
41 | m <- as_matrix(r)
42 | m_raw <- as_matrix(r, raw = TRUE)
43 |
44 | # Check dimensions
45 | expect_equal(dim(m), dim(m_raw))
46 | expect_equal(length(m), length(v_raw))
47 |
48 | # Check NA values
49 | expect_true(sum(is.na(m)) != 0)
50 | expect_true(sum(is.na(m_raw)) == 0)
51 | expect_true(sum(is.na(v)) != 0)
52 | expect_true(sum(is.na(v_raw)) == 0)
53 |
54 | # Test NA handling in summary stats
55 | r <- wbw_read_raster(f)
56 | expect_true(is.numeric(max(r)))
57 | expect_true(is.numeric(min(r)))
58 | expect_true(is.numeric(mean(r)))
59 | expect_true(is.numeric(wbw::stdev(r)))
60 | expect_true(is.numeric(median(r)))
61 | expect_true(is.numeric(variance(r)))
62 |
--------------------------------------------------------------------------------
/tests/tinytest/test_geomorphometry.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test slope failures
4 | expect_error(wbw_slope(dem = mtcars))
5 | expect_error(wbw_slope(x, units = 1))
6 | expect_error(wbw_slope(x, units = "dg"))
7 | expect_error(wbw_slope(x, z_factor = 2L))
8 | expect_error(wbw_slope(NULL))
9 |
10 | # Test aspect failures
11 | expect_error(wbw_aspect(dem = mtcars))
12 | expect_error(wbw_aspect(x, z_factor = 2L))
13 | expect_error(wbw_aspect(NULL))
14 |
15 | # Test ruggedness index failures
16 | expect_error(wbw_ruggedness_index(dem = mtcars))
17 | expect_error(wbw_ruggedness_index(1:10))
18 | expect_error(wbw_ruggedness_index(NULL))
19 |
20 | # Test fill missing data failures
21 | expect_error(wbw_fill_missing_data(x = mtcars))
22 | expect_error(wbw_fill_missing_data(x, filter_size = 2.5))
23 | expect_error(wbw_fill_missing_data(x, weight = "2.5"))
24 | expect_error(wbw_fill_missing_data(x, exclude_edge_nodata = "YES"))
25 | expect_error(wbw_fill_missing_data(NULL))
26 |
27 | # Test successful returns
28 | expect_inherits(wbw_aspect(x), c("wbw::WhiteboxRaster", "S7_object"))
29 | expect_inherits(wbw_slope(x), c("wbw::WhiteboxRaster", "S7_object"))
30 | expect_inherits(wbw_ruggedness_index(x), c("wbw::WhiteboxRaster", "S7_object"))
31 | expect_inherits(wbw_fill_missing_data(x), c("wbw::WhiteboxRaster", "S7_object"))
32 | expect_inherits(
33 | wbw_multidirectional_hillshade(x),
34 | c("wbw::WhiteboxRaster", "S7_object")
35 | )
36 | expect_inherits(wbw_hillshade(x), c("wbw::WhiteboxRaster", "S7_object"))
37 |
38 | # Test sample data download and fill missing data
39 | temp_dir <- tempdir()
40 | test_path <- wbw_download_sample_data(
41 | data_set = "Grand_Junction",
42 | path = temp_dir
43 | )
44 |
45 | expect_true(dir.exists(test_path))
46 | dem_path <- file.path(test_path, "DEM.tif")
47 | expect_true(file.exists(dem_path))
48 |
49 | dem <- wbw_read_raster(dem_path)
50 | expect_inherits(dem, c("wbw::WhiteboxRaster", "S7_object"))
51 |
52 | dem_filled <- wbw_fill_missing_data(dem)
53 | expect_inherits(dem_filled, c("wbw::WhiteboxRaster", "S7_object"))
54 |
55 | # Check if fill missing data worked
56 | m <- as_matrix(dem)
57 | m_filled <- as_matrix(dem_filled)
58 | expect_true(sum(is.na(m_filled)) <= sum(is.na(m)))
59 |
60 | # Clean up
61 | unlink(file.path(temp_dir, "Grand_Junction"), recursive = TRUE)
62 |
--------------------------------------------------------------------------------
/man/wbw_conservative_smoothing_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_conservative_smoothing_filter}
4 | \alias{wbw_conservative_smoothing_filter}
5 | \title{Conservative Smoothing Filter}
6 | \usage{
7 | wbw_conservative_smoothing_filter(x, filter_size_x = 3L, filter_size_y = 3L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 | }
16 | \value{
17 | \link{WhiteboxRaster} object containing filtered values
18 | }
19 | \description{
20 | This tool performs a conservative smoothing filter on a raster image.
21 | A conservative smoothing filter can be used to remove short-range
22 | variability in an image, effectively acting to smooth the image.
23 | It is particularly useful for eliminating local spikes and reducing the
24 | noise in an image.
25 | }
26 | \details{
27 | The algorithm operates by calculating the minimum and maximum neighbouring
28 | values surrounding a grid cell. If the cell at the centre of the
29 | kernel is greater than the calculated maximum value, it is replaced
30 | with the maximum value in the output image. Similarly, if the cell
31 | value at the kernel centre is less than the neighbouring minimum value,
32 | the corresponding grid cell in the output image is replaced with the
33 | minimum value.
34 |
35 | Neighbourhood size, or filter size, is specified in the x and y dimensions
36 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
37 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
38 | }
39 | \examples{
40 | f <- system.file("extdata/dem.tif", package = "wbw")
41 | wbw_read_raster(f) |>
42 | wbw_conservative_smoothing_filter(filter_size_x = 3L, filter_size_y = 3L)
43 | }
44 | \references{
45 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#conservative_smoothing_filter}
46 | }
47 | \seealso{
48 | \code{\link[=wbw_bilateral_filter]{wbw_bilateral_filter()}}, \code{\link[=wbw_gaussian_filter]{wbw_gaussian_filter()}},
49 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}
50 | }
51 | \keyword{image_processing}
52 |
--------------------------------------------------------------------------------
/man/wbw_bilateral_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_bilateral_filter}
4 | \alias{wbw_bilateral_filter}
5 | \title{Bilateral Filter}
6 | \usage{
7 | wbw_bilateral_filter(x, sigma_dist = 0.75, sigma_int = 1)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{sigma_dist}{\code{double}, standard deviation distance parameter in
13 | \strong{pixels}.}
14 |
15 | \item{sigma_int}{\code{double}, standard deviation intensity parameter,
16 | in the same units as z-units of input raster \code{x} (usually, meters).}
17 | }
18 | \value{
19 | \link{WhiteboxRaster} object containing filtered values
20 | }
21 | \description{
22 | Applies an edge-preserving smoothing filter that reduces noise while
23 | preserving important edges in the image.
24 | }
25 | \details{
26 | Bilateral filtering is a non-linear technique introduced by Tomasi and
27 | Manduchi (1998). The filter combines spatial and intensity domains to
28 | preserve edges while smoothing. Unlike the Gaussian filter, the bilateral
29 | filter weights pixels based on both their spatial distance and intensity
30 | similarity to the center pixel.
31 |
32 | The size of the filter is determined by setting the standard deviation
33 | distance parameter (\code{sigma_dist}); the larger the standard deviation the
34 | larger the resulting filter kernel.
35 | The standard deviation can be any number in the range
36 | 0.5-20 and is specified in the unit of pixels. The standard deviation
37 | intensity parameter (\code{sigma_int}), specified in the same units as the
38 | z-values, determines the intensity domain contribution to kernel weightings.
39 | }
40 | \examples{
41 | f <- system.file("extdata/dem.tif", package = "wbw")
42 | wbw_read_raster(f) |>
43 | wbw_bilateral_filter(sigma_dist = 1.5, sigma_int = 1.1)
44 | }
45 | \references{
46 | Tomasi, C., & Manduchi, R. (1998, January). Bilateral filtering for gray
47 | and color images. In null (p. 839). IEEE.
48 |
49 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#bilateral_filter}
50 | }
51 | \seealso{
52 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_gaussian_filter]{wbw_gaussian_filter()}}
53 | }
54 | \keyword{image_processing}
55 |
--------------------------------------------------------------------------------
/man/wbw_fill_missing_data.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geomorphometry.R
3 | \name{wbw_fill_missing_data}
4 | \alias{wbw_fill_missing_data}
5 | \title{Fill Missing Data}
6 | \usage{
7 | wbw_fill_missing_data(
8 | x,
9 | filter_size = 11L,
10 | weight = 2,
11 | exclude_edge_nodata = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
16 |
17 | \item{filter_size}{\code{integer} in \strong{grid cells} is used to determine
18 | how far the algorithm will search for valid, non-NoData values. Therefore,
19 | setting a larger filter size allows for the filling of larger gaps in
20 | the input raster.}
21 |
22 | \item{weight}{\code{double}, the IDW weight.}
23 |
24 | \item{exclude_edge_nodata}{\code{boolean}, default \code{FALSE}. It can be
25 | used to exclude NoData values that are connected to the edges of the raster.
26 | It is usually the case that irregularly shaped DEMs have large regions
27 | of NoData values along the containing raster edges. This flag can be used
28 | to exclude these regions from the gap-filling operation, leaving only
29 | interior gaps for filling.}
30 | }
31 | \value{
32 | \link{WhiteboxRaster} object
33 | }
34 | \description{
35 | This tool can be used to fill in small gaps in a raster or digital elevation
36 | model (DEM). The gaps, or holes, must have recognized NoData values.
37 | If gaps do not currently have this characteristic, use the
38 | \code{set_nodata_value} tool and ensure that the data are stored using
39 | a raster format that supports NoData values.
40 | All valid, non-NoData values in the input raster will be assigned the same
41 | value in the output image.
42 | }
43 | \details{
44 | The algorithm uses an inverse-distance weighted (IDW) scheme based on the
45 | valid values on the edge of NoData gaps to estimate gap values.
46 | The user must specify the filter size (\code{filter_size}), which
47 | determines the size of gap that is filled, and the IDW weight
48 | (\code{weight}).
49 | }
50 | \examples{
51 | f <- system.file("extdata/dem.tif", package = "wbw")
52 | wbw_read_raster(f) |>
53 | wbw_fill_missing_data()
54 | }
55 | \references{
56 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#fill_missing_data}
57 | }
58 | \keyword{geomorphometry}
59 |
--------------------------------------------------------------------------------
/man/wbw_hillshade.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/hillshade.R
3 | \name{wbw_hillshade}
4 | \alias{wbw_hillshade}
5 | \title{Hillshade}
6 | \usage{
7 | wbw_hillshade(dem, azimuth = 315, altitude = 30, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{azimuth}{\code{double}, illumination source azimuth or
13 | sun direction (0 to 360 degrees)}
14 |
15 | \item{altitude}{\code{double}, the altitude of the illumination sources.
16 | i.e. the elevation of the sun above the horizon, measured as an angle from
17 | 0 to 90 degrees}
18 |
19 | \item{z_factor}{\code{double}, Z conversion factor is only important
20 | when the vertical and horizontal units are not the same in the DEM.
21 | When this is the case, the algorithm will multiply each elevation in the
22 | DEM by the Z conversion factor}
23 | }
24 | \value{
25 | \link{WhiteboxRaster} object
26 | }
27 | \description{
28 | This tool performs a hillshade operation (also called shaded relief) on an
29 | input digital elevation model (DEM).
30 | }
31 | \details{
32 | The hillshade value (HS) of a DEM grid cell is calculate as:
33 | \deqn{HS = \frac{\tan(s)}{\sqrt{1 - \tan(s)^2}} \times
34 | [\frac{\sin(Alt)}{\tan(s)} - \cos(Alt) \times \sin(Az - a)]}
35 | where \eqn{s} and \eqn{a} are the local slope gradient and aspect
36 | (orientation) respectively and \eqn{Alt} and \eqn{Az} are the illumination
37 | source altitude and azimuth respectively. Slope and aspect are calculated
38 | using Horn's (1981) 3rd-order finate difference method.
39 |
40 | If the DEM is in the geographic coordinate system (latitude and longitude),
41 | the following equation is used:
42 | \deqn{zfactor = \frac{1.0}{111320.0 \times \cos(midlat)}}
43 |
44 | where \eqn{midlat} is the latitude of the centre of the raster,
45 | in radians.
46 | }
47 | \examples{
48 | f <- system.file("extdata/dem.tif", package = "wbw")
49 | wbw_read_raster(f) |>
50 | wbw_hillshade()
51 | }
52 | \references{
53 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#hillshade}
54 |
55 | Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
56 | in Terrain Analysis: Principles and Applications, edited by J. P. Wilson
57 | and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J.
58 | }
59 | \seealso{
60 | \code{\link[=wbw_multidirectional_hillshade]{wbw_multidirectional_hillshade()}}
61 | }
62 | \keyword{geomorphometry}
63 |
--------------------------------------------------------------------------------
/man/wbw_median_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_median_filter}
4 | \alias{wbw_median_filter}
5 | \title{Median Filter}
6 | \usage{
7 | wbw_median_filter(x, filter_size_x = 11L, filter_size_y = 11L, sig_digits = 2L)
8 | }
9 | \arguments{
10 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
13 |
14 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
15 |
16 | \item{sig_digits}{\code{integer}, default 2. Required for rounding of
17 | floating points inputs.}
18 | }
19 | \value{
20 | \link{WhiteboxRaster} object containing filtered values
21 | }
22 | \description{
23 | This tool performs a median filter on a raster image. Median filters, a
24 | type of low-pass filter, can be used to emphasize the longer-range
25 | variability in an image, effectively acting to smooth the image. This
26 | can be useful for reducing the noise in an image.
27 | }
28 | \details{
29 | The algorithm operates by calculating the median value (middle value in
30 | a sorted list) in a moving window centred on each grid cell. Specifically,
31 | this tool uses the efficient running-median filtering algorithm of
32 | Huang et al. (1979). The median value is not influenced by
33 | anomolously high or low values in the distribution to the extent
34 | that the average is. As such, the median filter is far less sensitive
35 | to shot noise in an image than the mean filter.
36 |
37 | Neighbourhood size, or filter size, is specified in the x and y dimensions
38 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
39 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
40 | }
41 | \examples{
42 | f <- system.file("extdata/dem.tif", package = "wbw")
43 | wbw_read_raster(f) |>
44 | wbw_median_filter(filter_size_x = 3L, filter_size_y = 3L)
45 | }
46 | \references{
47 | Huang, T., Yang, G.J.T.G.Y. and Tang, G., 1979. A fast two-dimensional
48 | median filtering algorithm. IEEE Transactions on Acoustics, Speech, and
49 | Signal Processing, 27(1), pp.13-18.
50 |
51 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#median_filter}
52 | }
53 | \seealso{
54 | \code{\link[=wbw_mean_filter]{wbw_mean_filter()}}, \code{\link[=wbw_high_pass_filter]{wbw_high_pass_filter()}},
55 | \code{\link[=wbw_high_pass_median_filter]{wbw_high_pass_median_filter()}}
56 | }
57 | \keyword{image_processing}
58 |
--------------------------------------------------------------------------------
/vignettes/articles/FAQ.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Frequently Asked Questions"
3 | output:
4 | rmarkdown::html_vignette:
5 | toc: false
6 | vignette: >
7 | %\VignetteIndexEntry{Frequently Asked Questions}
8 | %\VignetteEngine{knitr::rmarkdown}
9 | %\VignetteEncoding{UTF-8}
10 | %\VignetteDepends{terra}
11 | %\VignetteDepends{waldo}
12 | ---
13 |
14 | ```{r knitr_setup, include = FALSE}
15 | knitr::opts_chunk$set(
16 | collapse = TRUE,
17 | comment = "#>",
18 | warning = FALSE,
19 | message = FALSE,
20 | dpi = 150,
21 | retina = 2
22 | )
23 |
24 | requireNamespace("terra", quietly = TRUE)
25 | requireNamespace("waldo", quietly = TRUE)
26 | ```
27 |
28 | # How can I plot `WhiteboxRaster` objects?
29 |
30 | While there exists a built-in `plot` method for all `WhiteboxRaster` and `WhiteboxVector` objects, it is highly advisable to use [`{terra}`](https://rspatial.github.io/terra/index.html)'s plotting functionality by converting the `Whitebox...` objects to `SpatRaster` or `SpatVector` accordingly as follows:
31 |
32 | ```{r terra_plot, message=FALSE, warning=FALSE}
33 | library(wbw)
34 | library(terra)
35 |
36 | f <- system.file("extdata/dem.tif", package = "wbw")
37 |
38 | wbw_read_raster(f) |>
39 | wbw_multidirectional_hillshade() |>
40 | as_rast() |>
41 | plot(legend = FALSE)
42 | ```
43 |
44 | # I've noticed that raster extent differs between WhiteboxRaster and terra/GDAL
45 |
46 | Yes, that's true! Since the original Python library Whitebox Workflows for Python is [closed-source](https://www.whiteboxgeo.com/manual/wbw-user-manual/book/introduction.html#how-does-wbw-compare-with-related-whitebox-products), the reason for this behavior is unknown. One possible explanation (i.e., my guess) is that GDAL typically defines the extent based on the outer edges of the corner pixels, while WbW may define the extent based on the centers of the corner pixels.
47 |
48 | ```{r extent_difference, warning = FALSE, message = FALSE}
49 | library(wbw)
50 | library(terra)
51 |
52 | f <- system.file("extdata/dem.tif", package = "wbw")
53 |
54 | wbw_raster <- wbw_read_raster(f)
55 | terra_raster <- rast(f)
56 |
57 | # Compare extents
58 | # Mind the difference in xmax (east) and ymin (south)
59 | waldo::compare(
60 | as_vector(wbw_ext(wbw_raster)),
61 | as.vector(ext(terra_raster))
62 | )
63 | ```
64 |
65 | However, this issue is fixed when transitioning from `WhiteboxRaster` to `SpatRaster` via the `as_rast()` command:
66 |
67 | ```{r extent_difference2, warning = FALSE, message = FALSE}
68 | converted_raster <- as_rast(wbw_raster)
69 | waldo::compare(
70 | as.vector(ext(terra_raster)),
71 | as.vector(ext(converted_raster))
72 | )
73 | ```
74 |
75 |
--------------------------------------------------------------------------------
/man/wbw_plan_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_plan_curvature}
4 | \alias{wbw_plan_curvature}
5 | \title{Plan Curvature}
6 | \usage{
7 | wbw_plan_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object.
22 | }
23 | \description{
24 | This tool calculates the plan curvature (i.e. contour curvature), or
25 | the rate of change in aspect along a contour line, from a digital
26 | elevation model (\eqn{dem}). Curvature is the second derivative of the
27 | topographic surface defined by a DEM. Plan curvature characterizes the
28 | degree of flow convergence or divergence within the
29 | landscape (Gallant and Wilson, 2000).
30 | }
31 | \details{
32 | WhiteboxTools reports curvature in degrees multiplied by 100 for easier
33 | interpretation. The Z conversion factor (\eqn{z_factor}) is only important
34 | when the vertical and horizontal units are not the same in the DEM.
35 | When this is the case, the algorithm will multiply each elevation in the
36 | DEM by the Z Conversion Factor.
37 |
38 | If the DEM is in the geographic coordinate system (latitude and longitude),
39 | the following equation is used:
40 |
41 | \deqn{zfactor = \frac{1.0}{111320.0 \times \cos(midlat)}}
42 |
43 | The algorithm uses the same formula for the calculation of plan curvature
44 | as Gallant and Wilson (2000). Plan curvature is negative for diverging
45 | flow along ridges and positive for convergent areas,
46 | e.g. along valley bottoms.
47 | }
48 | \examples{
49 | f <- system.file("extdata/dem.tif", package = "wbw")
50 | wbw_read_raster(f) |>
51 | wbw_plan_curvature()
52 | }
53 | \references{
54 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#plan_curvature}
55 |
56 | Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
57 | in Terrain Analysis: Principles and Applications, edited by J. P.
58 | Wilson and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J. \if{html}{\out{
}}
59 | }
60 | \seealso{
61 | \code{\link[=wbw_profile_curvature]{wbw_profile_curvature()}}
62 | }
63 | \keyword{geomorphometry}
64 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(max,"wbw::WhiteboxRaster")
4 | S3method(max,wbw::WhiteboxRaster)
5 | S3method(mean,"wbw::WhiteboxRaster")
6 | S3method(median,"wbw::WhiteboxRaster")
7 | S3method(median,wbw::WhiteboxRaster)
8 | S3method(min,"wbw::WhiteboxRaster")
9 | S3method(min,wbw::WhiteboxRaster)
10 | S3method(plot,"wbw::WhiteboxRaster")
11 | S3method(print,"wbw::WhiteboxRaster")
12 | S3method(summary,"wbw::WhiteboxRaster")
13 | S3method(xy.coords,wbw::WhiteboxRaster)
14 | export("xy.coords.wbw::WhiteboxRaster")
15 | export(WhiteboxExtent)
16 | export(WhiteboxRaster)
17 | export(as_matrix)
18 | export(as_rast)
19 | export(as_vector)
20 | export(as_wbw_raster)
21 | export(num_cells)
22 | export(print_geotiff_tags)
23 | export(stdev)
24 | export(variance)
25 | export(wbw_adaptive_filter)
26 | export(wbw_aspect)
27 | export(wbw_bilateral_filter)
28 | export(wbw_cols)
29 | export(wbw_conservative_smoothing_filter)
30 | export(wbw_data_type)
31 | export(wbw_download_sample_data)
32 | export(wbw_ext)
33 | export(wbw_fill_missing_data)
34 | export(wbw_gaussian_curvature)
35 | export(wbw_gaussian_filter)
36 | export(wbw_high_pass_filter)
37 | export(wbw_high_pass_median_filter)
38 | export(wbw_hillshade)
39 | export(wbw_install)
40 | export(wbw_is_float)
41 | export(wbw_is_int)
42 | export(wbw_is_rgb)
43 | export(wbw_majority_filter)
44 | export(wbw_max_procs)
45 | export(wbw_maximal_curvature)
46 | export(wbw_maximum_filter)
47 | export(wbw_mean_curvature)
48 | export(wbw_mean_filter)
49 | export(wbw_median_filter)
50 | export(wbw_minimal_curvature)
51 | export(wbw_minimum_filter)
52 | export(wbw_multidirectional_hillshade)
53 | export(wbw_olympic_filter)
54 | export(wbw_percentile_filter)
55 | export(wbw_plan_curvature)
56 | export(wbw_profile_curvature)
57 | export(wbw_random_sample)
58 | export(wbw_range_filter)
59 | export(wbw_read_raster)
60 | export(wbw_read_vector)
61 | export(wbw_res)
62 | export(wbw_rows)
63 | export(wbw_ruggedness_index)
64 | export(wbw_slope)
65 | export(wbw_standard_deviation_filter)
66 | export(wbw_to_degrees)
67 | export(wbw_to_radians)
68 | export(wbw_total_filter)
69 | export(wbw_version)
70 | export(wbw_write_raster)
71 | export(wbw_xres)
72 | export(wbw_yres)
73 | importFrom(cli,cli_alert_info)
74 | importFrom(cli,cli_alert_success)
75 | importFrom(cli,cli_alert_warning)
76 | importFrom(grDevices,xy.coords)
77 | importFrom(reticulate,configure_environment)
78 | importFrom(reticulate,import)
79 | importFrom(reticulate,py_discover_config)
80 | importFrom(reticulate,py_eval)
81 | importFrom(reticulate,py_run_string)
82 | importFrom(stats,median)
83 | importFrom(utils,download.file)
84 | importFrom(utils,menu)
85 | importFrom(utils,packageVersion)
86 | importFrom(utils,unzip)
87 |
--------------------------------------------------------------------------------
/man/wbw_multidirectional_hillshade.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/hillshade.R
3 | \name{wbw_multidirectional_hillshade}
4 | \alias{wbw_multidirectional_hillshade}
5 | \title{Multidirectional Hillshade}
6 | \usage{
7 | wbw_multidirectional_hillshade(
8 | dem,
9 | altitude = 30,
10 | z_factor = 1,
11 | full_360_mode = FALSE
12 | )
13 | }
14 | \arguments{
15 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
16 |
17 | \item{altitude}{\code{double}, the altitude of the illumination sources.
18 | i.e. the elevation of the sun above the horizon, measured as an angle from
19 | 0 to 90 degrees}
20 |
21 | \item{z_factor}{\code{double}, Z conversion factor is only important
22 | when the vertical and horizontal units are not the same in the DEM.
23 | When this is the case, the algorithm will multiply each elevation in the
24 | DEM by the Z conversion factor}
25 |
26 | \item{full_360_mode}{\code{boolean}, default \code{FALSE}. I.e. whether or
27 | not to use full 360-degrees of illumination sources. When \code{FALSE}
28 | (default) the tool will perform a weighted summation of the hillshade
29 | images from four illumination azimuth positions at 225, 270, 315, and
30 | 360 (0) degrees, given weights of 0.1, 0.4, 0.4, and 0.1 respectively. When
31 | run in the full 360-degree mode, eight illumination source azimuths are
32 | used to calculate the output at 0, 45, 90, 135, 180, 225, 270, and 315
33 | degrees, with weights of 0.15, 0.125, 0.1, 0.05, 0.1, 0.125, 0.15,
34 | and 0.2 respectively.}
35 | }
36 | \value{
37 | \link{WhiteboxRaster} object
38 | }
39 | \description{
40 | This tool performs a hillshade operation (also called shaded relief) on
41 | an input digital elevation model (DEM) with multiple sources of
42 | illumination.
43 | }
44 | \details{
45 | The hillshade value (HS) of a DEM grid cell is calculate as:
46 | \deqn{HS = \frac{\tan(s)}{\sqrt{1 - \tan(s)^2}} \times
47 | [\frac{\sin(Alt)}{\tan(s)} - \cos(Alt) \times \sin(Az - a)]}
48 | where \eqn{s} and \eqn{a} are the local slope gradient and aspect
49 | (orientation) respectively and \eqn{Alt} and \eqn{Az} are the illumination
50 | source altitude and azimuth respectively. Slope and aspect are calculated
51 | using Horn's (1981) 3rd-order finate difference method.
52 | }
53 | \examples{
54 | f <- system.file("extdata/dem.tif", package = "wbw")
55 | wbw_read_raster(f) |>
56 | wbw_multidirectional_hillshade()
57 | }
58 | \references{
59 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#multidirectional_hillshade}
60 |
61 | Horn B.K.P., 1981, Hill shading and the reflectance map, Proceedings of
62 | the I.E.E.E. 69, 14
63 | }
64 | \seealso{
65 | \code{\link[=wbw_hillshade]{wbw_hillshade()}}
66 | }
67 | \keyword{geomorphometry}
68 |
--------------------------------------------------------------------------------
/man/wbw_percentile_filter.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/filters.R
3 | \name{wbw_percentile_filter}
4 | \alias{wbw_percentile_filter}
5 | \title{Percentile Filter}
6 | \usage{
7 | wbw_percentile_filter(
8 | x,
9 | filter_size_x = 11L,
10 | filter_size_y = 11L,
11 | sig_digits = 2L
12 | )
13 | }
14 | \arguments{
15 | \item{x}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
16 |
17 | \item{filter_size_x}{\code{integer}, X dimension of the neighbourhood size}
18 |
19 | \item{filter_size_y}{\code{integer}, Y dimension of the neighbourhood size}
20 |
21 | \item{sig_digits}{\code{integer}, default 2. Required for rounding of
22 | floating points inputs.}
23 | }
24 | \value{
25 | \link{WhiteboxRaster} object containing filtered values
26 | }
27 | \description{
28 | This tool calculates the percentile of the center cell in a moving filter
29 | window applied to an input image (\code{x}). This indicates the value
30 | below which a given percentage of the neighbouring values in within the
31 | filter fall. For example, the 35th percentile is the value below which 35\%
32 | of the neighbouring values in the filter window may be found. As such,
33 | the percentile of a pixel value is indicative of the relative location
34 | of the site within the statistical distribution of values contained
35 | within a filter window.
36 |
37 | When applied to input digital elevation models, percentile is a measure of
38 | local topographic position, or elevation residual.
39 | }
40 | \details{
41 | Neighbourhood size, or filter size, is specified in the x and y dimensions
42 | using \code{filter_size_x} and \code{filter_size_y} These dimensions should
43 | be odd, positive integer values (e.g. 3L, 5L, 7L, 9L, etc.).
44 |
45 | This tool takes advantage of the redundancy between overlapping,
46 | neighbouring filters to enhance computationally efficiency, using a
47 | method similar to Huang et al. (1979). This efficient method of
48 | calculating percentiles requires rounding of floating-point inputs,
49 | and therefore the user must specify the number of significant
50 | digits (\code{sig_digits}) to be used during the processing.
51 | }
52 | \examples{
53 | f <- system.file("extdata/dem.tif", package = "wbw")
54 | wbw_read_raster(f) |>
55 | wbw_percentile_filter(filter_size_x = 3L, filter_size_y = 3L)
56 | }
57 | \references{
58 | Huang, T., Yang, G.J.T.G.Y. and Tang, G., 1979. A fast two-dimensional
59 | median filtering algorithm. IEEE Transactions on Acoustics, Speech, and
60 | Signal Processing, 27(1), pp.13-18.
61 |
62 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#percentile_filter}
63 | }
64 | \seealso{
65 | \code{\link[=wbw_median_filter]{wbw_median_filter()}}
66 | }
67 | \keyword{image_processing}
68 |
--------------------------------------------------------------------------------
/R/matrix.R:
--------------------------------------------------------------------------------
1 | #' Convert WhiteboxRaster to Matrix
2 | #' @rdname matrix
3 | #' @keywords transform
4 | #'
5 | #' @description
6 | #' Converts a WhiteboxRaster object to a matrix. The output maintains the same
7 | #' dimensions and cell values as the input raster.
8 | #'
9 | #' @param raw logical. Should the raw data be returned (`raw = TRUE`) or should
10 | #' NoData values be transformed to `NA` (`raw = FALSE`)?
11 | #' @eval rd_input_raster("x")
12 | #'
13 | #' @return matrix containing raster values
14 | #'
15 | #' @eval rd_example("as_matrix", args = c("raw = TRUE"))
16 | #'
17 | #' @export
18 | as_matrix <- S7::new_generic(
19 | name = "as_matrix",
20 | dispatch_args = "x",
21 | fun = function(x, raw = FALSE) {
22 | S7::S7_dispatch()
23 | }
24 | )
25 |
26 | S7::method(as_matrix, WhiteboxRaster) <- function(x, raw = FALSE) {
27 | checkmate::assert_environment(wbw_env)
28 | m <- wbw_env$wbw_to_matrix(x@source, raw)
29 | as.matrix(m)
30 | }
31 |
32 | #' Convert objects to vectors
33 | #' @name as_vector
34 | #' @rdname vector
35 | #' @keywords transform
36 | #'
37 | #' @description
38 | #' Converts various Whitebox objects to vectors:
39 | #' * For [WhiteboxRaster]: converts raster values to a vector in row-major
40 | #' order
41 | #' * For [WhiteboxExtent]: converts extent boundaries to a named vector
42 | #'
43 | #' @param x Object to convert to vector. Can be:
44 | #' * A [WhiteboxRaster] object
45 | #' * A [WhiteboxExtent] object
46 | #' @param raw logical. For [WhiteboxRaster] only: Should the raw data be
47 | #' returned (`raw = TRUE`) or should NoData values be transformed
48 | #' to `NA` (`raw = FALSE`)?
49 | #'
50 | #' @return A vector, with type depending on the input:
51 | #' * For [WhiteboxRaster]: vector containing raster values
52 | #' * For [WhiteboxExtent]: named vector containing extent values
53 | #'
54 | #' @usage
55 | #' \S4method{as_vector}{WhiteboxRaster}(x, raw = FALSE)
56 | #' \S4method{as_vector}{WhiteboxExtent}(x)
57 | #'
58 | #' @aliases as_vector,WhiteboxRaster-method as_vector,WhiteboxExtent-method
59 | #'
60 | #' @examples
61 | #' f <- system.file("extdata/dem.tif", package = "wbw")
62 | #' x <- wbw_read_raster(f)
63 | #'
64 | #' # Return WhiteboxRaster's data:
65 | #' head(as_vector(x))
66 | #'
67 | #' # Return WhiteboxExtent's data:
68 | #' as_vector(wbw_ext(x))
69 | #'
70 | #' @export
71 | as_vector <- S7::new_generic(
72 | name = "as_vector",
73 | dispatch_args = "x"
74 | )
75 |
76 | S7::method(as_vector, WhiteboxRaster) <- function(x, raw = FALSE) {
77 | checkmate::assert_environment(wbw_env)
78 | v <- wbw_env$wbw_to_vector(x@source, raw)
79 | as.vector(v)
80 | }
81 |
82 | S7::method(as_vector, WhiteboxExtent) <- function(x) {
83 | c(
84 | "west" = x@west,
85 | "east" = x@east,
86 | "south" = x@south,
87 | "north" = x@north
88 | )
89 | }
90 |
--------------------------------------------------------------------------------
/tests/tinytest/test_curvature.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test successful filter returns
4 | expect_inherits(
5 | wbw_gaussian_curvature(x),
6 | c("wbw::WhiteboxRaster", "S7_object")
7 | )
8 | expect_inherits(
9 | wbw_maximal_curvature(x),
10 | c("wbw::WhiteboxRaster", "S7_object")
11 | )
12 | expect_inherits(
13 | wbw_minimal_curvature(x),
14 | c("wbw::WhiteboxRaster", "S7_object")
15 | )
16 | expect_inherits(
17 | wbw_mean_curvature(x),
18 | c("wbw::WhiteboxRaster", "S7_object")
19 | )
20 | expect_inherits(
21 | wbw_profile_curvature(x),
22 | c("wbw::WhiteboxRaster", "S7_object")
23 | )
24 | expect_inherits(
25 | wbw_plan_curvature(x),
26 | c("wbw::WhiteboxRaster", "S7_object")
27 | )
28 |
29 | # Test curvature alterations
30 | # Here is near-equality check is happening. If two values are close to
31 | # be equal, i.e. 2.222222226 and 2.222222225, then all.equal() returns TRUE
32 | # In other cases the function will return the mean relative difference as
33 | # a character vector
34 | true_median <- median(x)
35 |
36 | expect_true(
37 | wbw_gaussian_curvature(x) |>
38 | median() |>
39 | all.equal(true_median) |>
40 | is.character()
41 | )
42 | expect_true(
43 | wbw_gaussian_curvature(x, log_transform = TRUE) |>
44 | median() |>
45 | all.equal(true_median) |>
46 | is.character()
47 | )
48 | expect_true(
49 | wbw_maximal_curvature(x) |>
50 | median() |>
51 | all.equal(true_median) |>
52 | is.character()
53 | )
54 | expect_true(
55 | wbw_maximal_curvature(x, log_transform = TRUE) |>
56 | median() |>
57 | all.equal(true_median) |>
58 | is.character()
59 | )
60 | expect_true(
61 | wbw_minimal_curvature(x) |>
62 | median() |>
63 | all.equal(true_median) |>
64 | is.character()
65 | )
66 | expect_true(
67 | wbw_minimal_curvature(x, log_transform = TRUE) |>
68 | median() |>
69 | all.equal(true_median) |>
70 | is.character()
71 | )
72 | expect_true(
73 | wbw_mean_curvature(x) |>
74 | median() |>
75 | all.equal(true_median) |>
76 | is.character()
77 | )
78 | expect_true(
79 | wbw_mean_curvature(x, log_transform = TRUE) |>
80 | median() |>
81 | all.equal(true_median) |>
82 | is.character()
83 | )
84 | expect_true(
85 | wbw_profile_curvature(x) |>
86 | median() |>
87 | all.equal(true_median) |>
88 | is.character()
89 | )
90 | expect_true(
91 | wbw_profile_curvature(x, log_transform = TRUE) |>
92 | median() |>
93 | all.equal(true_median) |>
94 | is.character()
95 | )
96 | expect_true(
97 | wbw_plan_curvature(x) |>
98 | median() |>
99 | all.equal(true_median) |>
100 | is.character()
101 | )
102 | expect_true(
103 | wbw_plan_curvature(x, log_transform = TRUE) |>
104 | median() |>
105 | all.equal(true_median) |>
106 | is.character()
107 | )
108 |
--------------------------------------------------------------------------------
/.github/workflows/progress-tracker.yml:
--------------------------------------------------------------------------------
1 | name: Progress Tracker
2 |
3 | on:
4 | issues:
5 | types: [opened, edited]
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: read
10 |
11 | jobs:
12 | calculate-progress:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - name: Get issue content
17 | id: issue
18 | uses: actions/github-script@v6
19 | with:
20 | github-token: ${{ secrets.GITHUB_TOKEN }}
21 | script: |
22 | const issue = await github.rest.issues.get({
23 | owner: context.repo.owner,
24 | repo: context.repo.repo,
25 | issue_number: 1
26 | });
27 | core.setOutput('content', issue.data.body);
28 |
29 | - name: Calculate progress
30 | id: progress
31 | run: |
32 | python3 -c "
33 | import os
34 | content = '''${{ steps.issue.outputs.content }}'''
35 | completed = content.count('- [x]')
36 | total = completed + content.count('- [ ]')
37 | percentage = (completed / total * 100) if total > 0 else 0
38 |
39 | with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
40 | print(f'completed={completed}', file=f)
41 | print(f'total={total}', file=f)
42 | print(f'percentage={percentage:.1f}', file=f)
43 | "
44 |
45 | - name: Initialize/Update Gist
46 | uses: actions/github-script@v6
47 | with:
48 | github-token: ${{ secrets.GIST_SECRET }}
49 | script: |
50 | const gist_id = '0c46250def94614c4a3ef8b4de7460e6';
51 | const filename = 'wbw-progress.json';
52 | const content = {
53 | schemaVersion: 1,
54 | label: "WbW Tools ported",
55 | message: "${{ steps.progress.outputs.percentage }}% (${{ steps.progress.outputs.completed }}/${{ steps.progress.outputs.total }})",
56 | color: "d5ad18"
57 | };
58 |
59 | try {
60 | await github.rest.gists.update({
61 | gist_id: gist_id,
62 | files: {
63 | [filename]: {
64 | content: JSON.stringify(content)
65 | }
66 | }
67 | });
68 | } catch (error) {
69 | console.log('Error updating gist:', error);
70 | }
71 |
72 | - name: Update progress badge
73 | uses: schneegans/dynamic-badges-action@v1.6.0
74 | with:
75 | auth: ${{ secrets.GIST_SECRET }}
76 | gistID: 0c46250def94614c4a3ef8b4de7460e6
77 | filename: wbw-progress.json
78 | label: WbW Tools ported
79 | message: "${{ steps.progress.outputs.percentage }}% (${{ steps.progress.outputs.completed }}/${{ steps.progress.outputs.total }})"
80 | color: d5ad18
--------------------------------------------------------------------------------
/man/wbw_mean_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_mean_curvature}
4 | \alias{wbw_mean_curvature}
5 | \title{Mean Curvature}
6 | \usage{
7 | wbw_mean_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object.
22 | }
23 | \description{
24 | This tool calculates the mean curvature from a digital elevation
25 | model (\eqn{dem}).
26 |
27 | WhiteboxTools reports curvature in radians multiplied by 100 for easier
28 | interpretation because curvature values are typically very small.
29 | }
30 | \details{
31 | Curvature values are often very small and as such the user may opt to
32 | log-transform the output raster (\eqn{log_transform}). Transforming
33 | the values applies the equation by Shary et al. (2002):
34 |
35 | \deqn{Θ' = sign(Θ) ln(1 + 10^n|Θ|)}
36 |
37 | where \eqn{Θ} is the parameter value and \eqn{n} is dependent on the
38 | grid cell size.
39 |
40 | For DEMs in projected coordinate systems, the tool uses the
41 | 3rd-order bivariate Taylor polynomial method described by
42 | Florinsky (2016). Based on a polynomial fit of the elevations
43 | within the 5x5 neighbourhood surrounding each cell, this method
44 | is considered more robust against outlier elevations (noise)
45 | than other methods.
46 |
47 | For DEMs in geographic coordinate systems (i.e. angular units), the
48 | tool uses the 3x3 polynomial fitting method for equal angle grids also
49 | described by Florinsky (2016).
50 | }
51 | \examples{
52 | f <- system.file("extdata/dem.tif", package = "wbw")
53 | wbw_read_raster(f) |>
54 | wbw_mean_curvature()
55 | }
56 | \references{
57 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#mean_curvature}
58 |
59 | Florinsky, I. (2016). Digital terrain analysis in soil science and
60 | geology. Academic Press. \if{html}{\out{
}}
61 | Florinsky, I. V. (2017). An illustrated introduction to general
62 | geomorphometry. Progress in Physical Geography, 41(6), 723-752. \if{html}{\out{
}}
63 | Shary P. A., Sharaya L. S. and Mitusov A. V. (2002) Fundamental
64 | quantitative methods of land surface analysis. Geoderma 107: 1–32. \if{html}{\out{
}}
65 | }
66 | \seealso{
67 | \code{\link[=wbw_gaussian_curvature]{wbw_gaussian_curvature()}}, \code{\link[=wbw_maximal_curvature]{wbw_maximal_curvature()}}
68 | }
69 | \keyword{geomorphometry}
70 |
--------------------------------------------------------------------------------
/R/print.R:
--------------------------------------------------------------------------------
1 | #' Print Method for WhiteboxRaster
2 | #' @keywords methods
3 | #'
4 | #' @param x [WhiteboxRaster] object to print
5 | #' @param ... additional arguments passed to print method
6 | #' @export
7 | `print.wbw::WhiteboxRaster` <- function(x, ...) {
8 | conf <- x@source$configs
9 | name <- if (nchar(conf$title) == 0) x@name else conf$title
10 | epsg <- if (conf$epsg_code != 0) conf$epsg_code else ""
11 |
12 | # Create content
13 | lines <- c(
14 | sub("^.*::", "", class(x)[1]),
15 | name,
16 | sprintf("bands : %d", conf$bands),
17 | sprintf("dimensions : %d, %d (nrow, ncol)", conf$rows, conf$columns),
18 | sprintf(
19 | "resolution : %f, %f (x, y)",
20 | conf$resolution_x,
21 | conf$resolution_y
22 | ),
23 | sprintf("EPSG : %s (%s)", epsg, conf$xy_units),
24 | sprintf(
25 | "extent : %1.0f %1.0f %1.0f %1.0f",
26 | conf$west,
27 | conf$east,
28 | conf$south,
29 | conf$north
30 | ),
31 | sprintf("min value : %f", x@min),
32 | sprintf("max value : %f", x@max)
33 | )
34 |
35 | # Find the longest line
36 | width <- max(nchar(lines))
37 |
38 | # Create box elements with ASCII
39 | horizontal_line <- paste0("+", paste(rep("-", width + 2), collapse = ""), "+")
40 | dotted_line <- paste0("|", paste(rep(".", width + 2), collapse = ""), "|")
41 |
42 | # Print boxed content
43 | cat(horizontal_line, "\n")
44 |
45 | # Print class name and file name
46 | padded_class <- format(lines[1], width = width)
47 | padded_name <- format(lines[2], width = width)
48 | cat("| ", padded_class, " |\n", sep = "")
49 | cat("| ", padded_name, " |\n", sep = "")
50 |
51 | # Print separator
52 | cat(dotted_line, "\n")
53 |
54 | # Print rest of the content (skip first two lines as they're already printed)
55 | for (line in lines[-(1:2)]) {
56 | padded_line <- format(line, width = width)
57 | cat("| ", padded_line, " |\n", sep = "")
58 | }
59 |
60 | cat(horizontal_line, "\n")
61 |
62 | invisible(x)
63 | }
64 |
65 | #' Print GeoTIFF Tags
66 | #' @keywords utils
67 | #'
68 | #' @description
69 | #' Displays the tags contained within a GeoTIFF file. This is useful when
70 | #' importing GeoTIFF files into different software environments. The tool prints
71 | #' tag information to the console. Tags containing more than 100 values are
72 | #' truncated in the output. GeoKeys are interpreted according to the GeoTIFF
73 | #' specification.
74 | #'
75 | #' @param file_name \code{character}, path to raster file
76 | #'
77 | #' @eval rd_wbw_link("print_geotiff_tags")
78 | #'
79 | #' @examples
80 | #' \dontrun{
81 | #' raster_path <- system.file("extdata/dem.tif", package = "wbw")
82 | #' print_geotiff_tags(raster_path)
83 | #' }
84 | #'
85 | #' @export
86 | print_geotiff_tags <- function(file_name) {
87 | check_env(wbe)
88 | check_input_file(file_name, "r")
89 | wbe$print_geotiff_tags(file_name)
90 | }
91 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | # landing page is build from pkgdown/index.md, NOT README.md
2 | # This is done to support builtin Github Formatting of callouts
3 |
4 | url: https://wbw.anatolii.nz
5 |
6 | repo:
7 | url:
8 | home: https://github.com/atsyplenkov/wbw
9 | source: https://github.com/atsyplenkov/wbw/tree/master
10 | issues: https://github.com/atsyplenkov/wbw/issues
11 |
12 | authors:
13 | Anatolii Tsyplenkov:
14 | href: https://anatolii.nz
15 |
16 | template:
17 | bootstrap: 5
18 | light-switch: true
19 | math-rendering: mathjax
20 | bslib:
21 | base_font: {google: "Inter"}
22 | heading_font: {google: "Recursive"}
23 | code_font: {google: "Fira Code"}
24 |
25 | navbar:
26 | components:
27 | faq:
28 | text: FAQ
29 | href: articles/FAQ.html
30 | tutorials:
31 | text: Tutorials
32 | href: articles/tutorials.html
33 | menu:
34 | - text: Tutorial 1
35 | - text: Tutorial 2
36 | href: articles/Tutorial-2.html
37 | - text: Tutorial 3
38 | articles:
39 | text: Articles
40 | menu:
41 | - text: Benchmarks
42 | href: articles/benchmarks.html
43 | - text: wbw and terra
44 | structure:
45 | left: [faq, reference, tutorials, articles, news]
46 | right: [search, github, lightswitch]
47 |
48 | footer:
49 | structure:
50 | left: [attribution]
51 | components:
52 | attribution: "R bindings to the ['Whitebox Workflows for Python'](https://www.whiteboxgeo.com/whitebox-workflows-for-python/)"
53 |
54 | reference:
55 | - title: "Input/Output"
56 | desc: "Functions for reading and writing data"
57 | contents:
58 | - has_keyword("io")
59 | - wbw_read_raster
60 | - wbw_write_raster
61 | - print_geotiff_tags
62 |
63 | - title: "{terra}"
64 | desc: "Functions for conversion between wbw and terra"
65 | contents:
66 | - has_keyword("terra")
67 |
68 | - title: "Raster Operations"
69 | desc: "Functions for raster manipulation"
70 | contents:
71 | - has_keyword("conversions")
72 | - has_keyword("raster")
73 | - has_keyword("crs")
74 | - has_keyword("utils")
75 | - has_keyword("math")
76 | - has_keyword("transform")
77 |
78 | - title: "Stats"
79 | desc: "Summary and zonal statistics for raster and vector data"
80 | contents:
81 | - has_keyword("stats")
82 |
83 | - title: "System"
84 | desc: "System utilities"
85 | contents:
86 | - has_keyword("system")
87 | - wbw_version
88 |
89 | - title: "Geomorphometry"
90 | desc: "Tools for geomorphometric analysis of digital elevation models"
91 | contents:
92 | - has_keyword("geomorphometry")
93 |
94 | - title: "Image Processing"
95 | contents:
96 | - has_keyword("image_processing")
97 |
98 | - title: "Classes"
99 | desc: "Introduced S7 classes"
100 | contents:
101 | - has_keyword("class")
102 |
103 | - title: "Methods"
104 | desc: "S3 methods for WhiteboxRaster and WhiteboxVector objects"
105 | contents:
106 | - has_keyword("methods")
107 |
--------------------------------------------------------------------------------
/man/wbw_gaussian_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_gaussian_curvature}
4 | \alias{wbw_gaussian_curvature}
5 | \title{Gaussian Curvature}
6 | \usage{
7 | wbw_gaussian_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object in units of \eqn{m^{-2}}.
22 | }
23 | \description{
24 | This tool calculates the Gaussian curvature from a digital elevation
25 | model (\eqn{dem}). Gaussian curvature is the product of maximal and
26 | minimal curvatures, and retains values in each point of the topographic
27 | surface after its bending without breaking, stretching, and
28 | compressing (Florinsky, 2017).
29 |
30 | Gaussian curvature is measured in units of \eqn{m^{-2}}.
31 | }
32 | \details{
33 | Curvature values are often very small and as such the user may opt to
34 | log-transform the output raster (\eqn{log_transform}). Transforming
35 | the values applies the equation by Shary et al. (2002):
36 |
37 | \deqn{Θ' = sign(Θ) ln(1 + 10^n|Θ|)}
38 |
39 | where \eqn{Θ} is the parameter value and \eqn{n} is dependent on the
40 | grid cell size.
41 |
42 | For DEMs in projected coordinate systems, the tool uses the
43 | 3rd-order bivariate Taylor polynomial method described by
44 | Florinsky (2016). Based on a polynomial fit of the elevations
45 | within the 5x5 neighbourhood surrounding each cell, this method
46 | is considered more robust against outlier elevations (noise)
47 | than other methods.
48 |
49 | For DEMs in geographic coordinate systems (i.e. angular units), the
50 | tool uses the 3x3 polynomial fitting method for equal angle grids also
51 | described by Florinsky (2016).
52 | }
53 | \examples{
54 | f <- system.file("extdata/dem.tif", package = "wbw")
55 | wbw_read_raster(f) |>
56 | wbw_gaussian_curvature()
57 | }
58 | \references{
59 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#gaussian_curvature}
60 |
61 | Florinsky, I. (2016). Digital terrain analysis in soil science and
62 | geology. Academic Press. \if{html}{\out{
}}
63 | Florinsky, I. V. (2017). An illustrated introduction to general
64 | geomorphometry. Progress in Physical Geography, 41(6), 723-752. \if{html}{\out{
}}
65 | Shary P. A., Sharaya L. S. and Mitusov A. V. (2002) Fundamental
66 | quantitative methods of land surface analysis. Geoderma 107: 1–32. \if{html}{\out{
}}
67 | }
68 | \seealso{
69 | \code{\link[=wbw_maximal_curvature]{wbw_maximal_curvature()}}, \code{\link[=wbw_minimal_curvature]{wbw_minimal_curvature()}}
70 | }
71 | \keyword{geomorphometry}
72 |
--------------------------------------------------------------------------------
/man/wbw_maximal_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_maximal_curvature}
4 | \alias{wbw_maximal_curvature}
5 | \title{Maximal Curvature}
6 | \usage{
7 | wbw_maximal_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object in units of \eqn{m^{-1}}.
22 | }
23 | \description{
24 | This tool calculates the maximal curvature from a digital elevation model
25 | (\eqn{dem}). Maximal curvature is the curvature of a principal section
26 | with the highest value of curvature at a given point of the topographic
27 | surface (Florinsky, 2017). The values of this curvature are unbounded,
28 | and positive values correspond to ridge positions while negative values
29 | are indicative of closed depressions (Florinsky, 2016).
30 |
31 | Maximal curvature is measured in units of \eqn{m^{-1}}.
32 | }
33 | \details{
34 | Curvature values are often very small and as such the user may opt to
35 | log-transform the output raster (\eqn{log_transform}). Transforming
36 | the values applies the equation by Shary et al. (2002):
37 |
38 | \deqn{Θ' = sign(Θ) ln(1 + 10^n|Θ|)}
39 |
40 | where \eqn{Θ} is the parameter value and \eqn{n} is dependent on the
41 | grid cell size.
42 |
43 | For DEMs in projected coordinate systems, the tool uses the
44 | 3rd-order bivariate Taylor polynomial method described by
45 | Florinsky (2016). Based on a polynomial fit of the elevations
46 | within the 5x5 neighbourhood surrounding each cell, this method
47 | is considered more robust against outlier elevations (noise)
48 | than other methods.
49 |
50 | For DEMs in geographic coordinate systems (i.e. angular units), the
51 | tool uses the 3x3 polynomial fitting method for equal angle grids also
52 | described by Florinsky (2016).
53 | }
54 | \examples{
55 | f <- system.file("extdata/dem.tif", package = "wbw")
56 | wbw_read_raster(f) |>
57 | wbw_maximal_curvature()
58 | }
59 | \references{
60 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#maximal_curvature}
61 |
62 | Florinsky, I. (2016). Digital terrain analysis in soil science and
63 | geology. Academic Press. \if{html}{\out{
}}
64 | Florinsky, I. V. (2017). An illustrated introduction to general
65 | geomorphometry. Progress in Physical Geography, 41(6), 723-752. \if{html}{\out{
}}
66 | Shary P. A., Sharaya L. S. and Mitusov A. V. (2002) Fundamental
67 | quantitative methods of land surface analysis. Geoderma 107: 1–32. \if{html}{\out{
}}
68 | }
69 | \seealso{
70 | \code{\link[=wbw_gaussian_curvature]{wbw_gaussian_curvature()}}, \code{\link[=wbw_minimal_curvature]{wbw_minimal_curvature()}}
71 | }
72 | \keyword{geomorphometry}
73 |
--------------------------------------------------------------------------------
/man/wbw_minimal_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_minimal_curvature}
4 | \alias{wbw_minimal_curvature}
5 | \title{Minimal Curvature}
6 | \usage{
7 | wbw_minimal_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object in units of \eqn{m^{-1}}.
22 | }
23 | \description{
24 | This tool calculates the minimal curvature from a digital elevation model
25 | (\eqn{dem}). Minimal curvature is the curvature of a principal section
26 | with the highest value of curvature at a given point of the topographic
27 | surface (Florinsky, 2017). The values of this curvature are unbounded,
28 | and positive values correspond to ridge positions while negative values
29 | are indicative of closed depressions (Florinsky, 2016).
30 |
31 | Minimal curvature is measured in units of \eqn{m^{-1}}.
32 | }
33 | \details{
34 | Curvature values are often very small and as such the user may opt to
35 | log-transform the output raster (\eqn{log_transform}). Transforming
36 | the values applies the equation by Shary et al. (2002):
37 |
38 | \deqn{Θ' = sign(Θ) ln(1 + 10^n|Θ|)}
39 |
40 | where \eqn{Θ} is the parameter value and \eqn{n} is dependent on the
41 | grid cell size.
42 |
43 | For DEMs in projected coordinate systems, the tool uses the
44 | 3rd-order bivariate Taylor polynomial method described by
45 | Florinsky (2016). Based on a polynomial fit of the elevations
46 | within the 5x5 neighbourhood surrounding each cell, this method
47 | is considered more robust against outlier elevations (noise)
48 | than other methods.
49 |
50 | For DEMs in geographic coordinate systems (i.e. angular units), the
51 | tool uses the 3x3 polynomial fitting method for equal angle grids also
52 | described by Florinsky (2016).
53 | }
54 | \examples{
55 | f <- system.file("extdata/dem.tif", package = "wbw")
56 | wbw_read_raster(f) |>
57 | wbw_minimal_curvature()
58 | }
59 | \references{
60 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#minimal_curvature}
61 |
62 | Florinsky, I. (2016). Digital terrain analysis in soil science and
63 | geology. Academic Press. \if{html}{\out{
}}
64 | Florinsky, I. V. (2017). An illustrated introduction to general
65 | geomorphometry. Progress in Physical Geography, 41(6), 723-752. \if{html}{\out{
}}
66 | Shary P. A., Sharaya L. S. and Mitusov A. V. (2002) Fundamental
67 | quantitative methods of land surface analysis. Geoderma 107: 1–32. \if{html}{\out{
}}
68 | }
69 | \seealso{
70 | \code{\link[=wbw_gaussian_curvature]{wbw_gaussian_curvature()}}, \code{\link[=wbw_maximal_curvature]{wbw_maximal_curvature()}}
71 | }
72 | \keyword{geomorphometry}
73 |
--------------------------------------------------------------------------------
/man/wbw_profile_curvature.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/curvature.R
3 | \name{wbw_profile_curvature}
4 | \alias{wbw_profile_curvature}
5 | \title{Profile Curvature}
6 | \usage{
7 | wbw_profile_curvature(dem, log_transform = FALSE, z_factor = 1)
8 | }
9 | \arguments{
10 | \item{dem}{Raster object of class \link{WhiteboxRaster}. See \code{\link[=wbw_read_raster]{wbw_read_raster()}} for more details.}
11 |
12 | \item{log_transform}{\code{logical}, default \code{FALSE}. Wheter
13 | log-transform the output raster or not. See details.}
14 |
15 | \item{z_factor}{\code{double}, Z conversion factor is only important
16 | when the vertical and horizontal units are not the same in the DEM.
17 | When this is the case, the algorithm will multiply each elevation in the
18 | DEM by the Z conversion factor}
19 | }
20 | \value{
21 | \link{WhiteboxRaster} object.
22 | }
23 | \description{
24 | This tool calculates the profile curvature from a digital elevation
25 | model (\eqn{dem}), or the rate of change in slope along a flow line.
26 |
27 | Curvature is the second derivative of the topographic surface defined
28 | by a DEM. Profile curvature characterizes the degree of downslope
29 | acceleration or deceleration within the
30 | landscape (Gallant and Wilson, 2000).
31 |
32 | WhiteboxTools reports curvature in radians multiplied by 100 for easier
33 | interpretation because curvature values are typically very small.
34 | }
35 | \details{
36 | Curvature values are often very small and as such the user may opt to
37 | log-transform the output raster (\eqn{log_transform}). Transforming
38 | the values applies the equation by Shary et al. (2002):
39 |
40 | \deqn{Θ' = sign(Θ) ln(1 + 10^n|Θ|)}
41 |
42 | where \eqn{Θ} is the parameter value and \eqn{n} is dependent on the
43 | grid cell size.
44 |
45 | For DEMs in projected coordinate systems, the tool uses the
46 | 3rd-order bivariate Taylor polynomial method described by
47 | Florinsky (2016). Based on a polynomial fit of the elevations
48 | within the 5x5 neighbourhood surrounding each cell, this method
49 | is considered more robust against outlier elevations (noise)
50 | than other methods.
51 |
52 | For DEMs in geographic coordinate systems (i.e. angular units), the
53 | tool uses the 3x3 polynomial fitting method for equal angle grids also
54 | described by Florinsky (2016).
55 | }
56 | \examples{
57 | f <- system.file("extdata/dem.tif", package = "wbw")
58 | wbw_read_raster(f) |>
59 | wbw_profile_curvature()
60 | }
61 | \references{
62 | For more information, see \url{https://www.whiteboxgeo.com/manual/wbw-user-manual/book/tool_help.html#profile_curvature}
63 |
64 | Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
65 | in Terrain Analysis: Principles and Applications, edited by J. P.
66 | Wilson and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J. \if{html}{\out{
}}
67 | Florinsky, I. (2016). Digital terrain analysis in soil science and
68 | geology. Academic Press. \if{html}{\out{
}}
69 | Florinsky, I. V. (2017). An illustrated introduction to general
70 | geomorphometry. Progress in Physical Geography, 41(6), 723-752. \if{html}{\out{
}}
71 | Shary P. A., Sharaya L. S. and Mitusov A. V. (2002) Fundamental
72 | quantitative methods of land surface analysis. Geoderma 107: 1–32. \if{html}{\out{
}}
73 | }
74 | \seealso{
75 | \code{\link[=wbw_gaussian_curvature]{wbw_gaussian_curvature()}}, \code{\link[=wbw_mean_curvature]{wbw_mean_curvature()}}
76 | }
77 | \keyword{geomorphometry}
78 |
--------------------------------------------------------------------------------
/vignettes/articles/Tutorial-2.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Tutorial 2: Geomorphometric Analysis"
3 | output:
4 | rmarkdown::html_vignette:
5 | toc: true
6 | vignette: >
7 | %\VignetteIndexEntry{Tutorial 2: Geomorphometric Analysis}
8 | %\VignetteEngine{knitr::rmarkdown}
9 | %\VignetteEncoding{UTF-8}
10 | %\VignetteDepends{terra, waldo}
11 | ---
12 |
13 | ```{r knitr_setup, include = FALSE}
14 | knitr::opts_chunk$set(
15 | collapse = TRUE,
16 | comment = "#>",
17 | warning = FALSE,
18 | message = FALSE,
19 | dpi = 150,
20 | retina = 2
21 | )
22 |
23 | requireNamespace("terra", quietly = TRUE)
24 | requireNamespace("waldo", quietly = TRUE)
25 | ```
26 |
27 | > NB! This tutorial is based on the [Whitebox Workflows for Python (WbW) Tutorial 2: Geomorphometric Analysis](https://github.com/jblindsay/jblindsay.github.io/blob/master/WhiteboxTutorials/WbW_tutorials/WbW_tutorial2.ipynb)
28 |
29 | # 1. Download sample data
30 |
31 | ```{r load_layers}
32 | library(wbw)
33 |
34 | # Download sample dataset
35 | sample <-
36 | wbw_download_sample_data(
37 | data_set = "Grand_Junction",
38 | path = tempdir()
39 | )
40 |
41 | # Load as WhiteboxRaster
42 | dem <- wbw_read_raster(file.path(sample, "DEM.tif"))
43 | dem
44 | ```
45 |
46 | # 2. Fill missing data
47 |
48 | However, there are some missing values presented in the DEM.
49 | ```{r plot_one}
50 | library(terra)
51 |
52 | dem |>
53 | as_rast() |>
54 | plot()
55 |
56 | ```
57 |
58 | To fill them, one can use `wbw_fill_missing_data` function:
59 | ```{r fill_nodata}
60 | dem_filled <-
61 | wbw_fill_missing_data(dem, filter_size = 35, exclude_edge_nodata = TRUE)
62 |
63 | dem_filled |>
64 | as_rast() |>
65 | plot()
66 | ```
67 |
68 | # 3. Vizualization
69 |
70 | To properly vizualize the DEM, let's create a hillshade map of the relief:
71 |
72 | ```{r hillshade}
73 | dem_hillshade <- wbw_multidirectional_hillshade(dem_filled)
74 |
75 | dem_hillshade |>
76 | as_rast() |>
77 | plot(col = gray.colors(10), legend = FALSE)
78 | ```
79 |
80 | # 4. Raster summary stats
81 |
82 | One can get `WhiteboxRaster` summary statistics by running familiar functions from base R (and `{terra}`):
83 |
84 | ```{r summary_stats}
85 | # Raw DEM
86 | wbw_cols(dem) # Number of columns
87 | wbw_rows(dem) # Number of rows
88 | num_cells(dem) # Number of cells
89 | wbw_res(dem) # Raster resolution
90 |
91 | # NA-Filled DEM
92 | wbw_cols(dem_filled) # Number of columns
93 | wbw_rows(dem_filled) # Number of rows
94 | num_cells(dem_filled) # Number of cells
95 | wbw_res(dem_filled) # Raster resolution
96 |
97 | # Number of NoData values:
98 | waldo::compare(
99 | sum(is.na(as_vector(dem))),
100 | sum(is.na(as_vector(dem_filled)))
101 | )
102 | ```
103 |
104 | # 5. Extracting land-surface parameters (LSPs)
105 | Now let's extract some common land-surface parameters (LSPs), the basic building blocks of a geomorphometric analysis.
106 |
107 | ## Slope and Aspect
108 | ```{r slope_and_aspect}
109 | # Slope
110 | slope <- wbw_slope(dem_filled)
111 | aspect <- wbw_aspect(dem_filled)
112 |
113 | # Set up a 1x2 plotting layout
114 | par(mfrow = c(1, 2))
115 |
116 | # Plot the first raster (Slope)
117 | plot(as_rast(slope),
118 | main = "Slope",
119 | legend = FALSE,
120 | col = terrain.colors(100),
121 | mar=c(1,1,1,1))
122 |
123 | # Plot the second raster (Aspect)
124 | plot(as_rast(aspect),
125 | main = "Aspect",
126 | legend = FALSE,
127 | mar=c(1,1,1,1))
128 |
129 | ```
--------------------------------------------------------------------------------
/inst/wbw_helpers.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 |
4 | def wbw_to_vector(wbw_raster, raw=False):
5 | """
6 | Converts a Whitebox Raster object to a 1d numpy array, column-wise.
7 |
8 | Args:
9 | wbw_raster: A Whitebox Raster object
10 | raw: If False (default), replaces NoData values with None/np.nan. If True, keeps original values.
11 |
12 | Returns:
13 | A 1d numpy array with values arranged column by column.
14 | """
15 | # First get the data as a matrix
16 | matrix = wbw_to_matrix(wbw_raster, raw=raw)
17 |
18 | # Convert to 1D array column-wise (Fortran-style ordering)
19 | return matrix.flatten(order="C")
20 |
21 |
22 | def wbw_to_matrix(wbw_raster, raw=False):
23 | """
24 | Converts a Whitebox Raster object to a 2d numpy array.
25 |
26 | Args:
27 | wbw_raster: A Whitebox Raster object
28 | raw: If False (default), replaces NoData values with None/np.nan. If True, keeps original values.
29 |
30 | Returns:
31 | A 2d numpy array.
32 | """
33 | nrows = wbw_raster.configs.rows
34 | ncols = wbw_raster.configs.columns
35 | dtype = raster_dtype(wbw_raster)
36 |
37 | # For integer types, convert to float64 if we need to represent NoData
38 | if not raw and np.issubdtype(dtype, np.integer):
39 | dtype = np.float64
40 |
41 | matrix = np.zeros((nrows, ncols), dtype=dtype)
42 |
43 | for i in range(nrows):
44 | matrix[i] = wbw_raster.get_row_data(i)
45 |
46 | if not raw:
47 | nodata = wbw_raster.configs.nodata
48 | matrix[matrix == nodata] = np.nan
49 |
50 | return matrix
51 |
52 |
53 | def matrix_to_wbw(matrix, wbw_raster):
54 | """
55 | Writes a 2d numpy array to a Whitebox Raster object.
56 |
57 | Args:
58 | matrix: A 2d numpy array with values to write
59 | wbw_raster: A Whitebox Raster object to write the data to
60 |
61 | Returns:
62 | None. The wbw_raster is modified in place.
63 | """
64 | if matrix.shape != (wbw_raster.configs.rows, wbw_raster.configs.columns):
65 | raise ValueError(
66 | f"Matrix shape {matrix.shape} does not match raster dimensions "
67 | f"({wbw_raster.configs.rows}, {wbw_raster.configs.columns})"
68 | )
69 |
70 | # Ensure matrix data type matches raster
71 | target_dtype = raster_dtype(wbw_raster)
72 | if matrix.dtype != target_dtype:
73 | matrix = matrix.astype(target_dtype)
74 |
75 | # Write data row by row
76 | for i in range(wbw_raster.configs.rows):
77 | wbw_raster.set_row_data(i, matrix[i])
78 |
79 |
80 | def raster_dtype(wbw_raster):
81 | dtype_mapping = {
82 | "RasterDataType.F64": np.float64,
83 | "RasterDataType.F32": np.float32,
84 | "RasterDataType.I64": np.int64,
85 | "RasterDataType.U64": np.uint64,
86 | "RasterDataType.RGB48": np.uint16, # Typically represented as unsigned 16-bit
87 | "RasterDataType.I32": np.int32,
88 | "RasterDataType.U32": np.uint32,
89 | "RasterDataType.RGB24": np.uint8, # Typically represented as unsigned 8-bit
90 | "RasterDataType.RGBA32": np.uint8, # Assuming RGBA32 as unsigned 8-bit per channel
91 | "RasterDataType.I16": np.int16,
92 | "RasterDataType.U16": np.uint16,
93 | "RasterDataType.I8": np.int8,
94 | "RasterDataType.U8": np.uint8,
95 | }
96 |
97 | dt = str(wbw_raster.configs.data_type)
98 |
99 | return dtype_mapping.get(dt, None)
100 |
--------------------------------------------------------------------------------
/R/installation.R:
--------------------------------------------------------------------------------
1 | #' Install Required Python Modules
2 | #' @keywords system
3 | #'
4 | #' This function installs the latest \code{numpy}, \code{whitebox-workflows}.
5 | #' The default uses \code{pip} for package installation.
6 | #'
7 | #' @param system \code{boolean}, Use a \code{system()} call to
8 | #' \code{python -m pip install --user ...}
9 | #' instead of \code{reticulate::py_install()}. Default: \code{FALSE}.
10 | #' @param force \code{boolean}, Force update (uninstall/reinstall) and ignore
11 | #' existing installed packages? Default: \code{FALSE}.
12 | #' Applies to \code{system=TRUE}.
13 | #' @param ... Additional arguments passed to `reticulate::py_install()`
14 | #'
15 | #' @details This function provides a basic wrapper around
16 | #' `reticulate::py_install()`, except it defaults to using the Python package
17 | #' manager \code{pip} and virtual environment. It creates the \code{r-wbw}
18 | #' virtual environment in the default location
19 | #' (run `reticulate::virtualenv_root()` to find it) and installs the
20 | #' required python packages.
21 | #'
22 | #' @return `NULL`, or `try-error` (invisibly) on R code execution error.
23 | #'
24 | #' @export
25 | wbw_install <- function(system = FALSE, force = FALSE, ...) {
26 | args <- list(...)
27 |
28 | venv_name <- "r-wbw"
29 | venv_exists <- try(
30 | reticulate::virtualenv_exists(venv_name),
31 | silent = TRUE
32 | )
33 |
34 | # Check if venv exists
35 | if (venv_exists && !system) {
36 | # Check if `whitebox-workflows` is installed
37 | reticulate::use_virtualenv(venv_name)
38 | wbw_version <- wbw_version()
39 | }
40 |
41 | # Install `whitebox-workflows`
42 | if (venv_exists && is.null(wbw_version) && !system) {
43 | # venv exists but whitebox is not installed
44 | # install it from https://pypi.org/project/whitebox-workflows/
45 | reticulate::use_virtualenv(virtualenv = venv_name)
46 | reticulate::virtualenv_install(
47 | packages = c("numpy", "whitebox-workflows==1.3.3"),
48 | envname = venv_name
49 | )
50 | .success_message(wbw_version())
51 | } else if (!venv_exists && !system) {
52 | # nothing is installed, create venv and install deps
53 | # from https://pypi.org/project/whitebox-workflows/
54 | reticulate::virtualenv_create(
55 | envname = venv_name,
56 | version = ">= 3.8"
57 | )
58 | reticulate::use_virtualenv(
59 | virtualenv = venv_name
60 | )
61 | reticulate::virtualenv_install(
62 | packages = c("numpy", "whitebox-workflows==1.3.3"),
63 | envname = venv_name
64 | )
65 | .success_message(wbw_version())
66 | cli::cli_alert_info(
67 | c(
68 | "Please, restart you R session"
69 | )
70 | )
71 | } else if (venv_exists && !is.null(wbw_version) && !system) {
72 | .success_message(wbw_version())
73 | }
74 |
75 | if (system) {
76 | fp <- .find_python()
77 | if (nchar(fp) > 0) {
78 | return(
79 | invisible(
80 | system(
81 | paste(
82 | shQuote(fp),
83 | "-m pip install --user",
84 | ifelse(force, "-U --force", ""),
85 | "whitebox-workflows==1.3.3 numpy"
86 | )
87 | )
88 | )
89 | )
90 | }
91 | }
92 | }
93 |
94 | .success_message <- function(wbw_version) {
95 | cli::cli_alert_success(
96 | c(
97 | "You're all set! The Python library {.code whitebox-workflows} ",
98 | "v{wbw_version} has been found!"
99 | )
100 | )
101 | }
102 |
--------------------------------------------------------------------------------
/R/summary.R:
--------------------------------------------------------------------------------
1 | #' @importFrom stats median
2 | NULL
3 |
4 | #' @exportS3Method max wbw::WhiteboxRaster
5 | #' @exportS3Method min wbw::WhiteboxRaster
6 | #' @exportS3Method median wbw::WhiteboxRaster
7 | NULL
8 |
9 | #' Summary Statistics for WhiteboxRaster
10 | #' @rdname summarize
11 | #' @docType methods
12 | #' @keywords stats
13 | #'
14 | #' @description
15 | #' Computes summary statistics for cells in a [WhiteboxRaster] object.
16 | #'
17 | #' @param object [WhiteboxRaster] object
18 | #' @param ... additional arguments passed to summary
19 | #'
20 | #' @eval rd_example("summary")
21 | #' @eval rd_wbw_link("raster_summary_stats")
22 | #'
23 | #' @export
24 | `summary.wbw::WhiteboxRaster` <- function(object, ...) {
25 | cat(
26 | wbe$raster_summary_stats(object@source)
27 | )
28 | }
29 |
30 | #' @rdname summarize
31 | #' @docType methods
32 | #'
33 | #' @param object WhiteboxRaster object
34 | #' @param ... additional arguments (not used)
35 | #' @return numeric value
36 | #'
37 | #' @eval rd_example("max")
38 | #'
39 | #' @export
40 | `max.wbw::WhiteboxRaster` <- function(object, ...) {
41 | check_env(wbe)
42 | stats <- wbe$raster_summary_stats(object@source)
43 | extract_stat(stats, "maximum")
44 | }
45 |
46 | #' @rdname summarize
47 | #' @docType methods
48 | #'
49 | #' @param x WhiteboxRaster object
50 | #' @param ... additional arguments (not used)
51 | #'
52 | #' @eval rd_example("mean")
53 | #'
54 | #' @export
55 | `mean.wbw::WhiteboxRaster` <- function(x, ...) {
56 | x@source$calculate_mean()
57 | }
58 |
59 | #' @rdname summarize
60 | #' @docType methods
61 | #'
62 | #' @param x WhiteboxRaster object
63 | #' @param na.rm logical indicating whether NA values should
64 | #' be stripped (not used)
65 | #' @param ... additional arguments (not used)
66 | #'
67 | #' @eval rd_example("median")
68 | #'
69 | #' @export
70 | `median.wbw::WhiteboxRaster` <- function(x, na.rm = FALSE, ...) {
71 | x@source$calculate_clip_values(percent = 50)[[1]]
72 | }
73 |
74 | #' @rdname summarize
75 | #' @docType methods
76 | #'
77 | #' @param object WhiteboxRaster object
78 | #' @param ... additional arguments (not used)
79 | #'
80 | #' @eval rd_example("min")
81 | #'
82 | #' @export
83 | `min.wbw::WhiteboxRaster` <- function(object, ...) {
84 | check_env(wbe)
85 | stats <- wbe$raster_summary_stats(object@source)
86 | extract_stat(stats, "minimum")
87 | }
88 |
89 | #' @rdname summarize
90 | #' @docType methods
91 | #'
92 | #' @param x WhiteboxRaster object
93 | #'
94 | #' @eval rd_example("stdev")
95 | #'
96 | #' @export
97 | stdev <- S7::new_generic(
98 | name = "stdev",
99 | dispatch_args = "x",
100 | fun = function(x) {
101 | S7::S7_dispatch()
102 | }
103 | )
104 |
105 | S7::method(stdev, WhiteboxRaster) <- function(x) {
106 | check_env(wbe)
107 | stats <- wbe$raster_summary_stats(x@source)
108 | extract_stat(stats, "standard deviation")
109 | }
110 |
111 | #' @rdname summarize
112 | #' @docType methods
113 | #'
114 | #' @param x WhiteboxRaster object
115 | #'
116 | #' @eval rd_example("variance")
117 | #'
118 | #' @export
119 | variance <- S7::new_generic(
120 | name = "variance",
121 | dispatch_args = "x",
122 | fun = function(x) {
123 | S7::S7_dispatch()
124 | }
125 | )
126 |
127 | S7::method(variance, WhiteboxRaster) <- function(x) {
128 | check_env(wbe)
129 | stats <- wbe$raster_summary_stats(x@source)
130 | extract_stat(stats, "variance")
131 | }
132 |
133 | # Helper function to extract numeric value from a specific stat line
134 | extract_stat <- function(stats_text, pattern) {
135 | line <- grep(pattern, strsplit(stats_text, "\n")[[1]], value = TRUE)
136 | as.numeric(sub(".*: ", "", line))
137 | }
138 |
--------------------------------------------------------------------------------
/R/WhiteboxClasses.R:
--------------------------------------------------------------------------------
1 | #' WhiteboxExtent Class
2 | #' @keywords class
3 | #'
4 | #' @description
5 | #' Defines the spatial extent of a raster dataset using coordinates for
6 | #' the west, east, south, and north boundaries.
7 | #'
8 | #' @param west \code{double} Western boundary coordinate
9 | #' @param east \code{double} Eastern boundary coordinate
10 | #' @param south \code{double} Southern boundary coordinate
11 | #' @param north \code{double} Northern boundary coordinate
12 | #'
13 | #' @export
14 | WhiteboxExtent <- S7::new_class(
15 | name = "WhiteboxExtent",
16 | package = "wbw",
17 | properties = list(
18 | west = S7::new_property(
19 | class = S7::class_double,
20 | validator = function(value) {
21 | if (length(value) != 1) {
22 | return("'west' must be a single numeric value")
23 | }
24 | }
25 | ),
26 | east = S7::new_property(
27 | class = S7::class_double,
28 | validator = function(value) {
29 | if (length(value) != 1) {
30 | return("'east' must be a single numeric value")
31 | }
32 | }
33 | ),
34 | south = S7::new_property(
35 | class = S7::class_double,
36 | validator = function(value) {
37 | if (length(value) != 1) {
38 | return("'south' must be a single numeric value")
39 | }
40 | }
41 | ),
42 | north = S7::new_property(
43 | class = S7::class_double,
44 | validator = function(value) {
45 | if (length(value) != 1) {
46 | return("'north' must be a single numeric value")
47 | }
48 | }
49 | )
50 | )
51 | )
52 |
53 | #' WhiteboxRaster Class
54 | #' @keywords class
55 | #'
56 | #' @description
57 | #' Represents a raster dataset in Whitebox Workflows for Python (WbW) format.
58 | #' Provides access to raster properties including name, Python pointer, summary
59 | #' statistics, and min/max values.
60 | #'
61 | #' @param name \code{character} Name of the raster
62 | #' @param source \code{any} Source data for the raster
63 | #'
64 | #' @section Properties:
65 | #' \describe{
66 | #' \item{stats}{\code{character} Summary statistics for the raster}
67 | #' \item{min}{\code{numeric} Minimum value for the raster}
68 | #' \item{max}{\code{numeric} Maximum value for the raster}
69 | #' \item{extent}{\code{WhiteboxExtent} Spatial extent of the raster}
70 | #' }
71 | #' @export
72 | WhiteboxRaster <- S7::new_class(
73 | name = "WhiteboxRaster",
74 | package = "wbw",
75 | properties = list(
76 | name = S7::class_character,
77 | source = S7::class_any,
78 | stats = S7::new_property(
79 | class = S7::class_character,
80 | getter = function(self) {
81 | check_env(wbe)
82 | wbe$raster_summary_stats(self@source)
83 | }
84 | ),
85 | min = S7::new_property(
86 | class = S7::class_double,
87 | getter = function(self) {
88 | extract_stat(self@stats, "minimum")
89 | },
90 | validator = function(value) {
91 | if (!is.numeric(value) || length(value) != 1) {
92 | return("@min must be a single numeric value")
93 | }
94 | }
95 | ),
96 | max = S7::new_property(
97 | class = S7::class_double,
98 | getter = function(self) {
99 | extract_stat(self@stats, "maximum")
100 | },
101 | validator = function(value) {
102 | if (!is.numeric(value) || length(value) != 1) {
103 | return("@max must be a single numeric value")
104 | }
105 | }
106 | )
107 | # extent = S7::new_property(
108 | # class = WhiteboxExtent,
109 | # getter = function(self) {
110 | # conf <- self@source$configs
111 | # WhiteboxExtent(
112 | # west = conf$west,
113 | # east = conf$east,
114 | # south = conf$south,
115 | # north = conf$north
116 | # )
117 | # }
118 | # )
119 | )
120 | )
121 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to wbw
2 |
3 | This outlines how to propose a change to wbw.
4 | For a detailed discussion on contributing to this and other tidyverse packages, please see the [development contributing guide](https://rstd.io/tidy-contrib) and our [code review principles](https://code-review.tidyverse.org/).
5 |
6 | ## Fixing typos
7 |
8 | You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file.
9 | This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file.
10 | You can find the `.R` file that generates the `.Rd` by reading the comment in the first line.
11 |
12 | ## Bigger changes
13 |
14 | If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed.
15 | If you’ve found a bug, please file an issue that illustrates the bug with a minimal
16 | [reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed).
17 | See our guide on [how to create a great issue](https://code-review.tidyverse.org/issues/) for more advice.
18 |
19 | ### Pull request process
20 |
21 | * Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("atsyplenkov/wbw", fork = TRUE)`.
22 |
23 | * Install all development dependencies with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`.
24 | If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing.
25 | * Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`.
26 |
27 | * Make your changes, commit to git, and then create a PR by running `usethis::pr_push()`, and following the prompts in your browser.
28 | The title of your PR should briefly describe the change.
29 | The body of your PR should contain `Fixes #issue-number`.
30 |
31 | * For user-facing changes, add a bullet to the top of `NEWS.md` (i.e. just below the first header). Follow the style described in .
32 |
33 | ### Code style
34 |
35 | * New code should follow the tidyverse [style guide](https://style.tidyverse.org).
36 | You can use the [air](https://github.com/posit-dev/air) to apply these styles, but please don't restyle code that has nothing to do with your PR.
37 |
38 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation.
39 |
40 | * We use [tinytest](https://cran.r-project.org/package=tinytest) for unit tests.
41 | Contributions with test cases included are easier to accept.
42 |
43 | ### Writing S7 documentation
44 |
45 | The `{wbw}` package uses several [S7
46 | classes](https://rconsortium.github.io/S7/articles/classes-objects.html) which
47 | should be documented properly. There's a function documentation [template](https://github.com/atsyplenkov/wbw/blob/main/.github/template.R)
48 | available in the `.github` folder, which we advise you to use when creating or
49 | editing new functions.
50 |
51 | ### Git message format
52 |
53 | This repo adheres to the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) convention.
54 |
55 | #### Used prefixes
56 |
57 | - **chore**: Changes that affect the build system or external dependencies
58 | - **ci**: Changes to our CI configuration files and scripts
59 | - **docs**: Documentation only changes
60 | - **feat**: A new feature
61 | - **fix**: A bug fix
62 | - **perf**: A code change that improves performance
63 | - **refactor**: A code change that neither fixes a bug nor adds a feature
64 | - **lint**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
65 | - **test**: Adding missing tests or correcting existing tests
66 | - **revert**: When reverting a commit
67 | - **release**: All related to changeset (pre exit...)
68 |
69 | For example:
70 |
71 | ```
72 | docs: Added documentation for wbw_slope() function
73 | ```
74 |
75 | ## Code of Conduct
76 |
77 | Please note that the wbw project is released with a
78 | [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this
79 | project you agree to abide by its terms.
80 |
--------------------------------------------------------------------------------
/R/terra.R:
--------------------------------------------------------------------------------
1 | #' Convert WhiteboxRaster to SpatRaster
2 | #' @keywords terra
3 | #'
4 | #' Converts a [WhiteboxRaster] to a SpatRaster object
5 | #'
6 | #' @eval rd_input_raster("x")
7 | #'
8 | #' @return SpatRaster object
9 | #'
10 | #' @seealso [WhiteboxRaster()]
11 | #'
12 | #' @examples
13 | #' \dontrun{
14 | #' f <- system.file("extdata/dem.tif", package = "wbw")
15 | #' wbw_read_raster(f) |>
16 | #' wbw_slope(units = "r") |>
17 | #' as_rast()
18 | #' }
19 | #' @export
20 | as_rast <- S7::new_generic(
21 | name = "as_rast",
22 | dispatch_args = "x",
23 | fun = function(x) {
24 | S7::S7_dispatch()
25 | }
26 | )
27 |
28 | S7::method(as_rast, WhiteboxRaster) <- function(x) {
29 | # Checks
30 | check_env(wbe)
31 |
32 | # Prepare data
33 | v <- as_vector(x)
34 | wbw_nodata <- x@source$configs$nodata
35 | # TODO:
36 | # Depending on the x@source$configs$data_type,
37 | # Use either NA_integer_ or NA_real_
38 | v[v == wbw_nodata] <- NA
39 |
40 | # Prepare CRS and Extent
41 | ext <- c(
42 | # Note the differences in east and south between reading by
43 | # GDAL (i.e. terra) and WhiteboxTools
44 | x@source$configs$west,
45 | x@source$configs$east + wbw_xres(x),
46 | x@source$configs$south - wbw_yres(x),
47 | x@source$configs$north
48 | )
49 | crs <- if (x@source$configs$epsg_code == 0) {
50 | x@source$configs$coordinate_ref_system_wkt
51 | } else {
52 | terra::crs(paste0("epsg:", x@source$configs$epsg_code))
53 | }
54 |
55 | # Convert
56 | new_rast <- terra::rast(
57 | vals = v,
58 | nlyrs = 1L,
59 | crs = crs,
60 | extent = ext,
61 | resolution = wbw_res(x),
62 | names = x@name
63 | )
64 |
65 | # Convert to integer if necessary
66 | if (wbw_is_int(x)) {
67 | new_rast <- terra::as.int(new_rast)
68 | }
69 |
70 | # Return
71 | new_rast
72 | }
73 |
74 | #' Convert SpatRaster to WhiteboxRaster
75 | #' @keywords terra
76 | #'
77 | #' Converts a SpatRaster to a [WhiteboxRaster] object
78 | #'
79 | #' @param x SpatRaster object
80 | #'
81 | #' @return [WhiteboxRaster] object
82 | #'
83 | #' @seealso [WhiteboxRaster()]
84 | #'
85 | #' @examples
86 | #' \dontrun{
87 | #' library(terra)
88 | #' f <- system.file("extdata/dem.tif", package = "wbw")
89 | #' rast(f) |>
90 | #' as_wbw_raster()
91 | #' }
92 | #' @export
93 | as_wbw_raster <- function(x) {
94 | # Checks
95 | checkmate::assert_class(x, "SpatRaster")
96 | checkmate::assert_class(
97 | wbw,
98 | classes = c(
99 | "python.builtin.module",
100 | "python.builtin.object"
101 | )
102 | )
103 | checkmate::assert_true(
104 | terra::nlyr(x) == 1
105 | )
106 |
107 | # SpatRaster information
108 | na_terra <- terra::NAflag(x)
109 | nodata_value <- if (is.nan(na_terra)) {
110 | -9999
111 | } else {
112 | na_terra
113 | }
114 | res_terra <- terra::res(x)
115 | name_terra <- names(x)
116 | type_terra <- any(
117 | c(
118 | terra::is.int(x),
119 | terra::is.bool(x),
120 | terra::is.factor(x)
121 | )
122 | )
123 | ext_terra <- terra::ext(x)
124 | data_terra <- as.matrix(x, wide = TRUE)
125 | data_terra[is.na(data_terra)] <- nodata_value
126 |
127 | # Create new RasterConfigs
128 | new_config <- wbw$RasterConfigs()
129 | new_config$title <- name_terra
130 |
131 | # Dimensions
132 | new_config$bands <- as.integer(terra::nlyr(x))
133 | new_config$columns <- as.integer(terra::ncol(x))
134 | new_config$rows <- as.integer(terra::nrow(x))
135 | new_config$west <- as.double(ext_terra[1])
136 | ## Note the differences in east and south between reading by
137 | ## GDAL (i.e. terra) and WhiteboxTools
138 | new_config$east <- as.double(ext_terra[2]) - res_terra[1]
139 | new_config$south <- as.double(ext_terra[3]) + res_terra[2]
140 | new_config$north <- as.double(ext_terra[4])
141 |
142 | # CRS
143 | new_config$coordinate_ref_system_wkt <- terra::crs(x)
144 | new_config$resolution_x <- res_terra[1]
145 | new_config$resolution_y <- res_terra[2]
146 |
147 | # Data type
148 | new_config$nodata <- nodata_value
149 | new_config$data_type <- if (type_terra) {
150 | wbw$RasterDataType$I16
151 | } else {
152 | wbw$RasterDataType$F32
153 | }
154 |
155 | # Create WhiteboxRaster
156 | new_raster <- wbe$new_raster(new_config)
157 | wbw_env$matrix_to_wbw(data_terra, new_raster)
158 |
159 | WhiteboxRaster(
160 | name = name_terra,
161 | source = new_raster
162 | )
163 | }
164 |
--------------------------------------------------------------------------------
/tests/tinytest/test_filter.R:
--------------------------------------------------------------------------------
1 | source("setup.R")
2 |
3 | # Test successful filter returns
4 | expect_inherits(
5 | wbw_adaptive_filter(x),
6 | c("wbw::WhiteboxRaster", "S7_object")
7 | )
8 | expect_inherits(
9 | wbw_bilateral_filter(x),
10 | c("wbw::WhiteboxRaster", "S7_object")
11 | )
12 | expect_inherits(
13 | wbw_conservative_smoothing_filter(x),
14 | c("wbw::WhiteboxRaster", "S7_object")
15 | )
16 | expect_inherits(
17 | wbw_gaussian_filter(x),
18 | c("wbw::WhiteboxRaster", "S7_object")
19 | )
20 | expect_inherits(
21 | wbw_high_pass_filter(x),
22 | c("wbw::WhiteboxRaster", "S7_object")
23 | )
24 | expect_inherits(
25 | wbw_high_pass_median_filter(x),
26 | c("wbw::WhiteboxRaster", "S7_object")
27 | )
28 | expect_inherits(
29 | wbw_majority_filter(x),
30 | c("wbw::WhiteboxRaster", "S7_object")
31 | )
32 | expect_inherits(
33 | wbw_maximum_filter(x),
34 | c("wbw::WhiteboxRaster", "S7_object")
35 | )
36 | expect_inherits(
37 | wbw_mean_filter(x),
38 | c("wbw::WhiteboxRaster", "S7_object")
39 | )
40 | expect_inherits(
41 | wbw_median_filter(x),
42 | c("wbw::WhiteboxRaster", "S7_object")
43 | )
44 | expect_inherits(
45 | wbw_minimum_filter(x),
46 | c("wbw::WhiteboxRaster", "S7_object")
47 | )
48 | expect_inherits(
49 | wbw_olympic_filter(x),
50 | c("wbw::WhiteboxRaster", "S7_object")
51 | )
52 | expect_inherits(
53 | wbw_percentile_filter(x),
54 | c("wbw::WhiteboxRaster", "S7_object")
55 | )
56 | expect_inherits(
57 | wbw_range_filter(x),
58 | c("wbw::WhiteboxRaster", "S7_object")
59 | )
60 | expect_inherits(
61 | wbw_total_filter(x),
62 | c("wbw::WhiteboxRaster", "S7_object")
63 | )
64 | expect_inherits(
65 | wbw_standard_deviation_filter(x),
66 | c("wbw::WhiteboxRaster", "S7_object")
67 | )
68 |
69 | # Test filter alterations
70 | # Here is near-equality check is happening. If two values are close to
71 | # be equal, i.e. 2.222222226 and 2.222222225, then all.equal() returns TRUE
72 | # In other cases the function will return the mean relative difference as
73 | # a character vector
74 | true_median <- median(x)
75 |
76 | expect_true(
77 | wbw_adaptive_filter(
78 | x,
79 | filter_size_x = 51,
80 | filter_size_y = 51
81 | ) |>
82 | median() |>
83 | all.equal(true_median) |>
84 | is.character()
85 | )
86 | expect_true(
87 | wbw_bilateral_filter(
88 | x,
89 | sigma_dist = 3
90 | ) |>
91 | median() |>
92 | all.equal(true_median) |>
93 | is.character()
94 | )
95 | expect_true(
96 | wbw_conservative_smoothing_filter(x) |>
97 | median() |>
98 | all.equal(true_median) |>
99 | is.character()
100 | )
101 | expect_true(
102 | wbw_gaussian_filter(x, sigma = 1.5) |>
103 | median() |>
104 | all.equal(true_median) |>
105 | is.character()
106 | )
107 | expect_true(
108 | wbw_high_pass_filter(x) |>
109 | median() |>
110 | all.equal(true_median) |>
111 | is.character()
112 | )
113 | expect_true(
114 | wbw_high_pass_median_filter(x) |>
115 | median() |>
116 | all.equal(true_median) |>
117 | is.character()
118 | )
119 | expect_true(
120 | wbw_majority_filter(x) |>
121 | median() |>
122 | all.equal(true_median) |>
123 | is.character()
124 | )
125 | expect_true(
126 | wbw_maximum_filter(x) |>
127 | median() |>
128 | all.equal(true_median) |>
129 | is.character()
130 | )
131 | expect_true(
132 | wbw_mean_filter(x) |>
133 | median() |>
134 | all.equal(true_median) |>
135 | is.character()
136 | )
137 | expect_true(
138 | wbw_median_filter(x) |>
139 | median() |>
140 | all.equal(true_median) |>
141 | is.character()
142 | )
143 | expect_true(
144 | wbw_minimum_filter(x) |>
145 | median() |>
146 | all.equal(true_median) |>
147 | is.character()
148 | )
149 | expect_true(
150 | wbw_olympic_filter(x) |>
151 | median() |>
152 | all.equal(true_median) |>
153 | is.character()
154 | )
155 | expect_true(
156 | wbw_percentile_filter(x) |>
157 | median() |>
158 | all.equal(true_median) |>
159 | is.character()
160 | )
161 | expect_true(
162 | wbw_range_filter(x) |>
163 | median() |>
164 | all.equal(true_median) |>
165 | is.character()
166 | )
167 | expect_true(
168 | wbw_total_filter(x) |>
169 | median() |>
170 | all.equal(true_median) |>
171 | is.character()
172 | )
173 | expect_true(
174 | wbw_standard_deviation_filter(x) |>
175 | median() |>
176 | all.equal(true_median) |>
177 | is.character()
178 | )
179 |
--------------------------------------------------------------------------------
/R/system.R:
--------------------------------------------------------------------------------
1 | #' Set Maximum Parallel Processors
2 | #' @keywords system
3 | #'
4 | #' @description
5 | #' Determines the number of processors used by functions that are parallelized.
6 | #' If set to -1 (`max_procs=-1`), the default, all available processors will be
7 | #' used. To limit processing, set `max_procs` to a positive whole number less
8 | #' than the number of system processors.
9 | #'
10 | #' @param max_procs \code{integer} Number of processors to use. Use -1 for all
11 | #' available processors, or a positive integer to limit processor usage.
12 | #'
13 | #' @eval rd_wbw_link("max_procs")
14 | #'
15 | #' @examples
16 | #' \dontrun{
17 | #' raster_path <- system.file("extdata/dem.tif", package = "wbw")
18 | #' x <- wbw_read_raster(raster_path)
19 | #'
20 | #' # Use 1 processor
21 | #' wbw_max_procs(1)
22 | #' system.time(wbw_slope(x))
23 | #'
24 | #' # Use all available processors
25 | #' wbw_max_procs(-1)
26 | #' system.time(wbw_slope(x))
27 | #' }
28 | #' @export
29 | wbw_max_procs <- function(max_procs = -1) {
30 | check_env(wbe)
31 | max_procs <- checkmate::asInteger(
32 | max_procs,
33 | len = 1
34 | )
35 | checkmate::assert_true(
36 | max_procs >= -1 && max_procs != 0
37 | )
38 | wbe$max_procs <- max_procs
39 | }
40 |
41 | #' Download Sample Data
42 | #' @keywords system
43 | #'
44 | #' @description
45 | #' There are a number of available sample datasets that can be readily used
46 | #' to test Whitebox Workflows for Python.
47 | #'
48 | #' @param data_set \code{character}, dataset name. See Details
49 | #' @param path \code{character}, path to where download sample datasets. If
50 | #' \code{NULL}, the currect working directory is used
51 | #'
52 | #' @details
53 | #' Available datasets:
54 | #'
55 | #' | **Dataset Name** | **Description** | **Size** |
56 | #' |-----------------|-----------------|-----------|
57 | #' | Guelph_landsat | Landsat 5 sub-area (7 bands) | 10.9 MB |
58 | #' | Grand_Junction | Small DEM in high-relief terrain | 5.8 MB |
59 | #' | GTA_lidar | Airborne lidar point cloud (LAZ) | 54.3 MB |
60 | #' | jay_brook | Airborne lidar point cloud (LAZ) | 76.3 MB |
61 | #' | Jay_State_Forest | Lidar-derived DEM | 27.7 MB |
62 | #' | Kitchener_lidar | Airborne lidar point cloud (LAZ) | 41.6 MB |
63 | #' | London_air_photo | High-resolution RGB air photo | 87.3 MB |
64 | #' | mill_brook | Airborne lidar point cloud (LAZ) | 49.9 MB |
65 | #' | peterborough_drumlins | Lidar-derived DEM | 22.0 MB |
66 | #' | Southern_Ontario_roads | Vector roads layer | 7.1 MB |
67 | #' | StElisAk | Airborne lidar point cloud (LAZ) | 54.5 MB |
68 | #'
69 | #' @examples
70 | #' \dontrun{
71 | #' # Download sample data
72 | #' wbw_download_sample_data(data_set = "Guelph_landsat", path = tempdir())
73 | #' }
74 | #' @export
75 | #' @importFrom utils download.file unzip
76 | wbw_download_sample_data <- function(data_set = NULL, path = NULL) {
77 | # Set Download Path if NULL
78 | if (is.null(path)) {
79 | path <- getwd()
80 | }
81 | checkmate::assert_directory(
82 | path,
83 | access = "w"
84 | )
85 |
86 | # Select Dataset
87 | data_set <- checkmate::matchArg(
88 | data_set,
89 | choices = c(
90 | "Guelph_landsat",
91 | "Grand_Junction",
92 | "GTA_lidar",
93 | "jay_brook",
94 | "Jay_State_Forest",
95 | "Kitchener_lidar",
96 | "London_air_photo",
97 | "mill_brook",
98 | "peterborough_drumlins",
99 | "Southern_Ontario_roads",
100 | "StElisAk"
101 | )
102 | )
103 |
104 | # Create sub-directory if it doesn't exist
105 | download_path <- file.path(path, data_set)
106 | if (!dir.exists(download_path)) {
107 | dir.create(download_path)
108 | }
109 |
110 | # Download Data
111 | base_url <- "https://www.whiteboxgeo.com/sample_data/"
112 | data_url <- paste0(base_url, data_set, ".zip")
113 | download.file(
114 | data_url,
115 | destfile = file.path(download_path, paste0(data_set, ".zip"))
116 | )
117 |
118 | # Unzip Data
119 | temp_dir <- file.path(download_path, "temp_extract")
120 | dir.create(temp_dir)
121 |
122 | unzip(
123 | file.path(download_path, paste0(data_set, ".zip")),
124 | exdir = temp_dir
125 | )
126 |
127 | # Check if data_set folder exists inside the extracted contents
128 | dataset_folder <- file.path(temp_dir, data_set)
129 | if (dir.exists(dataset_folder)) {
130 | # If dataset folder exists, move its contents to download_path
131 | files_to_move <- list.files(dataset_folder, full.names = TRUE)
132 | file.copy(files_to_move, download_path, recursive = TRUE)
133 | } else {
134 | # If no specific dataset folder, move all contents except __MACOSX
135 | all_contents <- list.files(temp_dir, full.names = TRUE)
136 | files_to_move <- all_contents[!grepl("__MACOSX", all_contents)]
137 | file.copy(files_to_move, download_path, recursive = TRUE)
138 | }
139 |
140 | # Clean up
141 | unlink(temp_dir, recursive = TRUE)
142 | unlink(file.path(download_path, paste0(data_set, ".zip")))
143 |
144 | # Return download path
145 | cli::cli_alert_success(
146 | c(
147 | "Sample dataset '{.val {data_set}}' ",
148 | "downloaded to: {.file {download_path}}"
149 | )
150 | )
151 | return(download_path)
152 | }
153 |
--------------------------------------------------------------------------------
/R/dimensions.R:
--------------------------------------------------------------------------------
1 | #' Get dimensions of a WhiteboxRaster or WhiteboxVector object
2 | #' @rdname dimensions
3 | #' @keywords utils
4 | #'
5 | #' @eval rd_input_raster("x")
6 | #'
7 | #' @return \code{integer} Number of cells in the raster
8 | #'
9 | #' @export
10 | num_cells <- S7::new_generic(
11 | name = "num_cells",
12 | dispatch_args = "x",
13 | fun = function(x) {
14 | S7::S7_dispatch()
15 | }
16 | )
17 |
18 | S7::method(num_cells, WhiteboxRaster) <- function(x) {
19 | # Checks
20 | check_env(wbe)
21 | x@source$num_cells()
22 | }
23 |
24 | #' @rdname dimensions
25 | #' @keywords utils
26 | #'
27 | #' @export
28 | wbw_rows <- S7::new_generic(
29 | name = "wbw_rows",
30 | dispatch_args = "x",
31 | fun = function(x) {
32 | S7::S7_dispatch()
33 | }
34 | )
35 |
36 | S7::method(wbw_rows, WhiteboxRaster) <- function(x) {
37 | # Checks
38 | check_env(wbe)
39 | x@source$configs$rows
40 | }
41 |
42 | #' @rdname dimensions
43 | #' @keywords utils
44 | #'
45 | #' @export
46 | wbw_cols <- S7::new_generic(
47 | name = "wbw_cols",
48 | dispatch_args = "x",
49 | fun = function(x) {
50 | S7::S7_dispatch()
51 | }
52 | )
53 |
54 | S7::method(wbw_cols, WhiteboxRaster) <- function(x) {
55 | # Checks
56 | check_env(wbe)
57 | x@source$configs$columns
58 | }
59 |
60 | #' Get WhiteboxRaster resolution (x and y)
61 | #' @rdname resolution
62 | #' @keywords utils
63 | #'
64 | #' @eval rd_input_raster("x")
65 | #'
66 | #' @return \code{double} Vector containing x and y resolution
67 | #'
68 | #' @export
69 | wbw_res <- S7::new_generic(
70 | name = "wbw_res",
71 | dispatch_args = "x",
72 | fun = function(x) {
73 | S7::S7_dispatch()
74 | }
75 | )
76 |
77 | S7::method(wbw_res, WhiteboxRaster) <- function(x) {
78 | # Checks
79 | check_env(wbe)
80 | c(
81 | x@source$configs$resolution_x,
82 | x@source$configs$resolution_y
83 | )
84 | }
85 |
86 | #' @rdname resolution
87 | #' @keywords utils
88 | #'
89 | #' @export
90 | wbw_xres <- S7::new_generic(
91 | name = "wbw_xres",
92 | dispatch_args = "x",
93 | fun = function(x) {
94 | S7::S7_dispatch()
95 | }
96 | )
97 |
98 | S7::method(wbw_xres, WhiteboxRaster) <- function(x) {
99 | # Checks
100 | check_env(wbe)
101 | x@source$configs$resolution_x
102 | }
103 |
104 | #' @rdname resolution
105 | #' @keywords utils
106 | #'
107 | #' @export
108 | wbw_yres <- S7::new_generic(
109 | name = "wbw_yres",
110 | dispatch_args = "x",
111 | fun = function(x) {
112 | S7::S7_dispatch()
113 | }
114 | )
115 |
116 | S7::method(wbw_yres, WhiteboxRaster) <- function(x) {
117 | # Checks
118 | check_env(wbe)
119 | x@source$configs$resolution_y
120 | }
121 |
122 | #' Get WhiteboxRaster data type
123 | #' @rdname datatype
124 | #' @keywords utils
125 | #'
126 | #' @eval rd_input_raster("x")
127 | #' @eval rd_example("wbw_data_type")
128 | #'
129 | #' @return \code{character} String representing the raster data type
130 | #'
131 | #' @export
132 | wbw_data_type <- S7::new_generic(
133 | name = "wbw_data_type",
134 | dispatch_args = "x",
135 | fun = function(x) {
136 | S7::S7_dispatch()
137 | }
138 | )
139 |
140 | S7::method(wbw_data_type, WhiteboxRaster) <- function(x) {
141 | as.character(x@source$configs$data_type)
142 | }
143 |
144 | #' @rdname datatype
145 | #' @keywords utils
146 | #'
147 | #' @eval rd_input_raster("x")
148 | #' @eval rd_example("wbw_is_int")
149 | #'
150 | #' @export
151 | wbw_is_int <- S7::new_generic(
152 | name = "wbw_is_int",
153 | dispatch_args = "x",
154 | fun = function(x) {
155 | S7::S7_dispatch()
156 | }
157 | )
158 |
159 | S7::method(wbw_is_int, WhiteboxRaster) <- function(x) {
160 | wbw_type <- as.character(x@source$configs$data_type)
161 |
162 | any(
163 | wbw_type == "RasterDataType.I32",
164 | wbw_type == "RasterDataType.U32",
165 | wbw_type == "RasterDataType.I64",
166 | wbw_type == "RasterDataType.U64",
167 | wbw_type == "RasterDataType.I16",
168 | wbw_type == "RasterDataType.I8",
169 | wbw_type == "RasterDataType.U16",
170 | wbw_type == "RasterDataType.U8"
171 | )
172 | }
173 |
174 | #' @rdname datatype
175 | #' @keywords utils
176 | #'
177 | #' @eval rd_input_raster("x")
178 | #' @eval rd_example("wbw_is_float")
179 | #'
180 | #' @export
181 | wbw_is_float <- S7::new_generic(
182 | name = "wbw_is_float",
183 | dispatch_args = "x",
184 | fun = function(x) {
185 | S7::S7_dispatch()
186 | }
187 | )
188 |
189 | S7::method(wbw_is_float, WhiteboxRaster) <- function(x) {
190 | wbw_type <- as.character(x@source$configs$data_type)
191 |
192 | any(
193 | wbw_type == "RasterDataType.F32",
194 | wbw_type == "RasterDataType.F64"
195 | )
196 | }
197 |
198 | #' @rdname datatype
199 | #' @keywords utils
200 | #'
201 | #' @eval rd_input_raster("x")
202 | #' @eval rd_example("wbw_is_rgb")
203 | #'
204 | #' @export
205 | wbw_is_rgb <- S7::new_generic(
206 | name = "wbw_is_rgb",
207 | dispatch_args = "x",
208 | fun = function(x) {
209 | S7::S7_dispatch()
210 | }
211 | )
212 |
213 | S7::method(wbw_is_rgb, WhiteboxRaster) <- function(x) {
214 | wbw_type <- as.character(x@source$configs$data_type)
215 |
216 | any(
217 | wbw_type == "RasterDataType.RGB48",
218 | wbw_type == "RasterDataType.RGB24",
219 | wbw_type == "RasterDataType.RGBA32"
220 | )
221 | }
222 |
--------------------------------------------------------------------------------
/R/hillshade.R:
--------------------------------------------------------------------------------
1 | #' Multidirectional Hillshade
2 | #' @keywords geomorphometry
3 | #'
4 | #' @description
5 | #' This tool performs a hillshade operation (also called shaded relief) on
6 | #' an input digital elevation model (DEM) with multiple sources of
7 | #' illumination.
8 | #'
9 | #' @details
10 | #' The hillshade value (HS) of a DEM grid cell is calculate as:
11 | #' \deqn{HS = \frac{\tan(s)}{\sqrt{1 - \tan(s)^2}} \times
12 | #' [\frac{\sin(Alt)}{\tan(s)} - \cos(Alt) \times \sin(Az - a)]}
13 | #' where \eqn{s} and \eqn{a} are the local slope gradient and aspect
14 | #' (orientation) respectively and \eqn{Alt} and \eqn{Az} are the illumination
15 | #' source altitude and azimuth respectively. Slope and aspect are calculated
16 | #' using Horn's (1981) 3rd-order finate difference method.
17 | #'
18 | #' @eval rd_input_raster("dem")
19 | #' @param altitude \code{double}, the altitude of the illumination sources.
20 | #' i.e. the elevation of the sun above the horizon, measured as an angle from
21 | #' 0 to 90 degrees
22 | #' @param z_factor \code{double}, Z conversion factor is only important
23 | #' when the vertical and horizontal units are not the same in the DEM.
24 | #' When this is the case, the algorithm will multiply each elevation in the
25 | #' DEM by the Z conversion factor
26 | #' @param full_360_mode \code{boolean}, default \code{FALSE}. I.e. whether or
27 | #' not to use full 360-degrees of illumination sources. When \code{FALSE}
28 | #' (default) the tool will perform a weighted summation of the hillshade
29 | #' images from four illumination azimuth positions at 225, 270, 315, and
30 | #' 360 (0) degrees, given weights of 0.1, 0.4, 0.4, and 0.1 respectively. When
31 | #' run in the full 360-degree mode, eight illumination source azimuths are
32 | #' used to calculate the output at 0, 45, 90, 135, 180, 225, 270, and 315
33 | #' degrees, with weights of 0.15, 0.125, 0.1, 0.05, 0.1, 0.125, 0.15,
34 | #' and 0.2 respectively.
35 | #'
36 | #' @return [WhiteboxRaster] object
37 | #'
38 | #' @eval rd_wbw_link("multidirectional_hillshade")
39 | #' @references
40 | #' Horn B.K.P., 1981, Hill shading and the reflectance map, Proceedings of
41 | #' the I.E.E.E. 69, 14
42 | #'
43 | #' @seealso [wbw_hillshade()]
44 | #'
45 | #' @eval rd_example("wbw_multidirectional_hillshade")
46 | #'
47 | #' @export
48 | wbw_multidirectional_hillshade <- S7::new_generic(
49 | name = "wbw_multidirectional_hillshade",
50 | dispatch_args = "dem",
51 | fun = function(dem, altitude = 30, z_factor = 1, full_360_mode = FALSE) {
52 | S7::S7_dispatch()
53 | }
54 | )
55 |
56 | S7::method(wbw_multidirectional_hillshade, WhiteboxRaster) <- function(
57 | dem,
58 | altitude = 30,
59 | z_factor = 1,
60 | full_360_mode = FALSE
61 | ) {
62 | # Checks
63 | check_env(wbe)
64 | checkmate::assert_double(altitude, len = 1, lower = 0, upper = 90)
65 | checkmate::assert_double(z_factor, len = 1)
66 | checkmate::assert_logical(full_360_mode, len = 1)
67 |
68 | # WBT
69 | out <- wbe$multidirectional_hillshade(
70 | dem = dem@source,
71 | altitude = altitude,
72 | z_factor = z_factor,
73 | full_360_mode = full_360_mode
74 | )
75 |
76 | # Return
77 | WhiteboxRaster(
78 | name = paste0(dem@name, "(Hillshade)"),
79 | source = out
80 | )
81 | }
82 |
83 | #' Hillshade
84 | #' @keywords geomorphometry
85 | #'
86 | #' @description
87 | #' This tool performs a hillshade operation (also called shaded relief) on an
88 | #' input digital elevation model (DEM).
89 | #'
90 | #' @details
91 | #' The hillshade value (HS) of a DEM grid cell is calculate as:
92 | #' \deqn{HS = \frac{\tan(s)}{\sqrt{1 - \tan(s)^2}} \times
93 | #' [\frac{\sin(Alt)}{\tan(s)} - \cos(Alt) \times \sin(Az - a)]}
94 | #' where \eqn{s} and \eqn{a} are the local slope gradient and aspect
95 | #' (orientation) respectively and \eqn{Alt} and \eqn{Az} are the illumination
96 | #' source altitude and azimuth respectively. Slope and aspect are calculated
97 | #' using Horn's (1981) 3rd-order finate difference method.
98 | #'
99 | #' If the DEM is in the geographic coordinate system (latitude and longitude),
100 | #' the following equation is used:
101 | #' \deqn{zfactor = \frac{1.0}{111320.0 \times \cos(midlat)}}
102 | #'
103 | #' where \eqn{midlat} is the latitude of the centre of the raster,
104 | #' in radians.
105 | #'
106 | #' @eval rd_input_raster("dem")
107 | #' @param azimuth \code{double}, illumination source azimuth or
108 | #' sun direction (0 to 360 degrees)
109 | #' @param altitude \code{double}, the altitude of the illumination sources.
110 | #' i.e. the elevation of the sun above the horizon, measured as an angle from
111 | #' 0 to 90 degrees
112 | #' @param z_factor \code{double}, Z conversion factor is only important
113 | #' when the vertical and horizontal units are not the same in the DEM.
114 | #' When this is the case, the algorithm will multiply each elevation in the
115 | #' DEM by the Z conversion factor
116 | #'
117 | #' @return [WhiteboxRaster] object
118 | #'
119 | #' @eval rd_wbw_link("hillshade")
120 | #' @references
121 | #' Gallant, J. C., and J. P. Wilson, 2000, Primary topographic attributes,
122 | #' in Terrain Analysis: Principles and Applications, edited by J. P. Wilson
123 | #' and J. C. Gallant pp. 51-86, John Wiley, Hoboken, N.J.
124 | #'
125 | #' @seealso [wbw_multidirectional_hillshade()]
126 | #'
127 | #' @eval rd_example("wbw_hillshade")
128 | #'
129 | #' @export
130 | wbw_hillshade <- S7::new_generic(
131 | name = "wbw_hillshade",
132 | dispatch_args = "dem",
133 | fun = function(dem, azimuth = 315, altitude = 30, z_factor = 1) {
134 | S7::S7_dispatch()
135 | }
136 | )
137 |
138 | S7::method(wbw_hillshade, WhiteboxRaster) <- function(
139 | dem,
140 | azimuth = 315,
141 | altitude = 30,
142 | z_factor = 1
143 | ) {
144 | # Checks
145 | check_env(wbe)
146 | checkmate::assert_double(azimuth, len = 1, lower = 0, upper = 360)
147 | checkmate::assert_double(altitude, len = 1, lower = 0, upper = 90)
148 | checkmate::assert_double(z_factor, len = 1)
149 |
150 | # WBT
151 | out <- wbe$hillshade(
152 | dem = dem@source,
153 | azimuth = azimuth,
154 | altitude = altitude,
155 | z_factor = z_factor
156 | )
157 |
158 | # Return
159 | WhiteboxRaster(
160 | name = paste0(dem@name, "(Hillshade)"),
161 | source = out
162 | )
163 | }
164 |
--------------------------------------------------------------------------------
/R/zzz.R:
--------------------------------------------------------------------------------
1 | # Used https://github.com/brownag/rgeedim/blob/main/R/AAAA.R and
2 | # https://github.com/JosiahParry/pyfns as an examples.
3 | # Thanks guys!
4 |
5 | wbw <- NULL
6 | wbe <- NULL
7 |
8 | #' `wbw_version()`: Gets the `Whitebox Workflows` version
9 | #' @return character. Version Number.
10 | #' @export
11 | #' @importFrom reticulate py_eval
12 | wbw_version <- function() {
13 | try(
14 | reticulate::py_run_string("from importlib.metadata import version"),
15 | silent = TRUE
16 | )
17 | version <- try(
18 | reticulate::py_eval("version('whitebox_workflows')"),
19 | silent = TRUE
20 | )
21 | if (!inherits(version, "try-error")) {
22 | version
23 | }
24 | }
25 |
26 | #' @importFrom reticulate import
27 | #' @importFrom reticulate py_run_string
28 | .loadModules <- function() {
29 | if (is.null(wbw)) {
30 | try(
31 | {
32 | reticulate::use_virtualenv(virtualenv = "r-wbw")
33 | wbw <<- reticulate::import(
34 | "whitebox_workflows",
35 | delay_load = TRUE
36 | )
37 | },
38 | silent = TRUE
39 | )
40 | }
41 |
42 | if (is.null(wbe)) {
43 | try(wbe <<- wbw$WbEnvironment(), silent = TRUE)
44 | }
45 |
46 | # note: requires Python >= 3.8;
47 | # but is not essential for functioning of package
48 | try(
49 | reticulate::source_python(
50 | system.file("wbw_helpers.py", package = "wbw"),
51 | envir = wbw_env
52 | ),
53 | silent = TRUE
54 | )
55 |
56 | !is.null(wbe)
57 | }
58 |
59 | #' @importFrom reticulate py_discover_config
60 | .has_python3 <- function() {
61 | # get reticulate python information
62 | # NB: reticulate::py_config() calls configure_environment() etc.
63 | # .:. use py_discover_config()
64 | x <- try(reticulate::py_discover_config(), silent = TRUE)
65 |
66 | # need python 3 for reticulate
67 | # need python 3.8+ for whitebox_workflows
68 | if (length(x) > 0 && !inherits(x, "try-error")) {
69 | if (numeric_version(x$version) >= "3.8") {
70 | return(TRUE)
71 | } else if (numeric_version(x$version) >= "3.0") {
72 | return(FALSE)
73 | }
74 | }
75 | FALSE
76 | }
77 |
78 | .has_wbw <- function() {
79 | if (reticulate::virtualenv_exists("r-wbw")) {
80 | reticulate::use_virtualenv("r-wbw")
81 | have_wbw <- reticulate::py_module_available("whitebox_workflows")
82 | have_numpy <- reticulate::py_module_available("numpy")
83 | } else {
84 | have_wbw <- reticulate::py_module_available("whitebox_workflows")
85 | have_numpy <- reticulate::py_module_available("numpy")
86 | }
87 |
88 | all(have_wbw, have_numpy)
89 | }
90 |
91 | #' @importFrom reticulate configure_environment
92 | #' @importFrom cli cli_alert_info cli_alert_success cli_alert_warning
93 | #' @importFrom utils menu
94 | .onLoad <- function(libname, pkgname) {
95 | S7::methods_register()
96 |
97 | if (.has_python3() && !.has_wbw()) {
98 | if (interactive()) {
99 | cli::cli_alert_warning(
100 | "Library {.code whitebox-workflows} is required but not found."
101 | )
102 | choice <- utils::menu(
103 | c(
104 | "Install dependencies in a virtual environment (recommended)",
105 | "Install dependencies system-wide",
106 | "Do nothing"
107 | )
108 | )
109 |
110 | if (choice == 1) {
111 | cli::cli_alert_info(
112 | "Installing dependencies in virtual environment..."
113 | )
114 | i <- try(wbw_install(), silent = TRUE)
115 | if (!inherits(i, "try-error")) {
116 | cli::cli_alert_success(
117 | c(
118 | "All done! Please, restart you R session"
119 | )
120 | )
121 | } else {
122 | cli::cli_alert_danger(
123 | c(
124 | "Oups, something went wrong :-(\n",
125 | "Please try to install dependencies manually by running ",
126 | "{.run wbw::wbw_install()}"
127 | )
128 | )
129 | }
130 | } else if (choice == 2) {
131 | cli::cli_alert_info(
132 | "Installing dependencies system-wide..."
133 | )
134 | i <- try(wbw_install(system = TRUE), silent = TRUE)
135 | if (!inherits(i, "try-error")) {
136 | cli::cli_alert_success(
137 | c(
138 | "All done!"
139 | )
140 | )
141 | } else {
142 | cli::cli_alert_danger(
143 | c(
144 | "Oups, something went wrong :-(\n",
145 | "Please try to install dependencies manually by running ",
146 | "{.run wbw::wbw_install()}"
147 | )
148 | )
149 | }
150 | }
151 | } else {
152 | # Non-interactive: install system-wide
153 | wbw_install(system = TRUE)
154 | }
155 | }
156 |
157 | # Try loading modules after potential installation
158 | if (.has_python3() && .has_wbw()) {
159 | if (!.loadModules()) {
160 | x <- try(reticulate::configure_environment(pkgname), silent = TRUE)
161 | if (!inherits(x, "try-error")) {
162 | .loadModules()
163 | }
164 | }
165 | }
166 | }
167 |
168 | #' @importFrom utils packageVersion
169 | .onAttach <- function(libname, pkgname) {
170 | wbwv <- wbw_version()
171 | suppress <- !grepl(
172 | "suppressed",
173 | Sys.getenv("wbw.message"),
174 | ignore.case = TRUE
175 | )
176 |
177 | if (is.null(wbwv) && suppress && interactive()) {
178 | cli::cli_alert_warning(
179 | c(
180 | "Python package `whitebox-workflows` cannot be found.",
181 | "Run {.code wbw::wbw_install()} and reload R session."
182 | )
183 | )
184 | } else if (!is.null(wbwv) && suppress) {
185 | cli::cli_alert_success(
186 | c(
187 | "wbw v{utils::packageVersion('wbw')} -- using whitebox-workflows v{wbwv}"
188 | )
189 | )
190 | }
191 | }
192 |
193 | .find_python <- function() {
194 | # find python
195 | py_path <- Sys.which("python")
196 | if (nchar(py_path) == 0) {
197 | py_path <- Sys.which("python3")
198 | }
199 | py_path
200 | }
201 |
--------------------------------------------------------------------------------
/pkgdown/index.md:
--------------------------------------------------------------------------------
1 | # Whitebox Workflows for R `{wbw}`
2 |
3 |
4 | [](https://www.repostatus.org/#wip)
7 | [](https://github.com/atsyplenkov/wbw/issues/1)
9 | [](https://github.com/atsyplenkov/wbw/actions/workflows/R-CMD-check.yaml)
10 | [](https://app.codecov.io/gh/atsyplenkov/wbw)
12 | 
14 |
15 |
16 | The `{wbw}` package provides R bindings for the [Whitebox Workflows for
17 | Python](https://www.whiteboxgeo.com/manual/wbw-user-manual/book/preface.html)
18 | — a powerful and fast library for advanced geoprocessing, with focus on
19 | hydrological, geomorphometric and remote sensing analysis of raster,
20 | vector and LiDAR data.
21 |
22 | ## Basic workflow
23 |
24 | The `{wbw}` R package introduces several new S7 classes, including
25 | `WhiteboxRaster` and `WhiteboxVector` which serves as a bridge between
26 | Python and R.
27 |
28 | ``` r
29 | library(wbw)
30 |
31 | raster_path <- system.file("extdata/dem.tif", package = "wbw")
32 | dem <- wbw_read_raster(raster_path)
33 | dem
34 | #> +------------------------------------------+
35 | #> | WhiteboxRaster |
36 | #> | dem.tif |
37 | #> |..........................................|
38 | #> | bands : 1 |
39 | #> | dimensions : 726, 800 (nrow, ncol) |
40 | #> | resolution : 5.002392, 5.000243 (x, y) |
41 | #> | EPSG : 2193 (Linear_Meter) |
42 | #> | min value : 63.698193 |
43 | #> | max value : 361.020721 |
44 | #> +------------------------------------------+
45 | ```
46 |
47 | The true power of `{wbw}` unleashes when there’s a need to run several
48 | operations sequentially, i.e., in a pipeline. Unlike the original
49 | Whitebox Tools, WbW [stores files in
50 | memory](https://www.whiteboxgeo.com/manual/wbw-user-manual/book/introduction.html#how-does-wbw-compare-with-related-whitebox-products),
51 | reducing the amount of intermediate I/O operations.
52 |
53 | For example, a DEM can be smoothed (or filtered), and then the slope can
54 | be estimated as follows:
55 |
56 | ``` r
57 | dem |>
58 | wbw_mean_filter() |>
59 | wbw_slope(units = "d")
60 | #> +------------------------------------------+
61 | #> | WhiteboxRaster |
62 | #> | Slope (degrees) |
63 | #> |..........................................|
64 | #> | bands : 1 |
65 | #> | dimensions : 726, 800 (nrow, ncol) |
66 | #> | resolution : 5.002392, 5.000243 (x, y) |
67 | #> | EPSG : 2193 (Linear_Meter) |
68 | #> | min value : 0.005972 |
69 | #> | max value : 50.069439 |
70 | #> +------------------------------------------+
71 | ```
72 |
73 | ## Yet Another RSpatial Package? Why?
74 |
75 | The above example may remind you of the `{terra}` package, and it is not
76 | a coincidence. The `{wbw}` package is designed to be fully compatible
77 | with `{terra}`, and the conversion between `WhiteboxRaster` and
78 | `SpatRaster` objects happens in milliseconds (well, depending on the
79 | raster size, of course).
80 |
81 | ``` r
82 | library(terra)
83 |
84 | wbw_read_raster(raster_path) |>
85 | wbw_gaussian_filter(sigma = 1.5) |>
86 | wbw_aspect() |>
87 | as_rast() |> # Conversion to SpatRaster
88 | plot(main = "Aspect")
89 | ```
90 |
91 |
92 |
93 | Even though `{wbw}` can be faster than `{terra}` in some cases, it is by
94 | no means intended to replace it.
95 |
96 | ``` r
97 | requireNamespace("bench", quietly = TRUE)
98 |
99 | bench::mark(
100 | terra = {
101 | s <-
102 | raster_path |>
103 | rast() |>
104 | terrain("slope", unit = "radians") |>
105 | focal(w = 15, "mean") |>
106 | global(\(x) median(x, na.rm = TRUE))
107 |
108 | round(s$global, 2)
109 |
110 | },
111 | wbw = {
112 | raster_path |>
113 | wbw_read_raster() |>
114 | wbw_slope("radians") |>
115 | wbw_mean_filter(15, 15) |>
116 | median() |>
117 | round(2)
118 | },
119 | check = TRUE,
120 | iterations = 11L
121 | )
122 | #> # A tibble: 2 × 6
123 | #> expression min median `itr/sec` mem_alloc `gc/sec`
124 | #>
125 | #> 1 terra 290.7ms 291.5ms 3.43 28.58MB 17.2
126 | #> 2 wbw 37.5ms 39.1ms 25.5 3.72KB 0
127 | ```
128 |
129 | ## Installation
130 |
131 | You can install the development version of `{wbw}` from
132 | [GitHub](https://github.com/) with:
133 |
134 | ``` r
135 | # install.packages("pak")
136 | pak::pak("atsyplenkov/wbw")
137 | ```
138 |
139 | > [!TIP]
140 | > The `{wbw}` package requires the `whitebox-workflows` Python library
141 | > v1.3.3+. However, you should not worry about it, as the package
142 | > is designed to install all dependencies automatically on the first run.
143 |
144 | Your machine should have **Python 3.8+** installed with `pip` and `venv` configured. Usually, these requirements are met on all modern computers. However, clean Debian installs may require the installation of system dependencies:
145 |
146 |
147 | ```bash
148 | apt update
149 | apt install python3 python3-pip python3-venv -y
150 | ```
151 |
152 | ## Contributing
153 |
154 | Contributions are welcome! Please see our [contributing
155 | guidelines](CONTRIBUTING.md) for details. There is an open issue for the
156 | `{wbw}` package [here](https://github.com/atsyplenkov/wbw/issues/1) that
157 | contains a list of functions yet to be implemented. This is a good place
158 | to start.
159 |
160 | ## See also
161 |
162 | Geomorphometric and hydrological analysis in R can be also done with:
163 |
164 | - [`{whitebox}`](https://github.com/opengeos/whiteboxR) — An R frontend for the [WhiteboxTools](https://www.whiteboxgeo.com) standalone runner.
165 | - [`{traudem}`](https://github.com/lucarraro/traudem/) — R bindings to [TauDEM](https://hydrology.usu.edu/taudem/taudem5/) (Terrain Analysis Using Digital Elevation Models) command-line interface.
166 | - [`{RSagacmd}`](https://github.com/stevenpawley/Rsagacmd/) and [`{RSAGA}`](https://github.com/r-spatial/RSAGA) — Links R with [SAGA GIS](https://sourceforge.net/projects/saga-gis/).
167 | - [`{rivnet}`](https://github.com/lucarraro/rivnet) — river network extraction from DEM using TauDEM.
--------------------------------------------------------------------------------