|
1 | 1 | #' Compute fractional tree canopy cover of a subplot/microplot by crown overlay |
2 | 2 | #' |
3 | | -#' @param plot_radius A numeric value giving the radius of the |
| 3 | +#' @param sample_radius A numeric value giving the radius of the |
4 | 4 | #' subplot/microplot. |
5 | 5 | #' @param tree_list A data frame containing tree records for the |
6 | 6 | #' subplot/microplot. Must have columns `DIST` (stem distance from subplot |
7 | | -#' center in same units as `plot_radius`), `AZIMUTH` (horizontal angle from |
| 7 | +#' center in same units as `sample_radius`), `AZIMUTH` (horizontal angle from |
8 | 8 | #' subplot/microplot center to the stem location, in the range `0:359`) and |
9 | | -#' `CRWIDTH` (tree crown width in the same units as `plot_radius` and `DIST`). |
| 9 | +#' `CRWIDTH` (tree crown width in the same units as `sample_radius` and `DIST`). |
| 10 | +#' @param digits Optional integer number of digits to keep in the result |
| 11 | +#' (defaults to `1`, will be passed to `round()`). |
10 | 12 | #' @return |
11 | | -#' A numeric value for tree canopy cover as percent of the subplot/microplot |
| 13 | +#' An numeric value for tree canopy cover as percent of the subplot/microplot |
12 | 14 | #' covered by a vertical projection of circular crowns. |
13 | 15 | #' |
| 16 | +#' @examples |
| 17 | +#' crown_overlay_pct(24, plantation[plantation$SUBP == 1 & |
| 18 | +#' plantation$DIA >= 5, ]) |
14 | 19 | #' @export |
15 | | -crown_overlay_pct <- function(plot_radius, tree_list) { |
| 20 | +crown_overlay_pct <- function(sample_radius, tree_list, digits = 1) { |
| 21 | + if (missing(sample_radius) || is.null(sample_radius)) |
| 22 | + stop("'sample_radius' is required", call. = FALSE) |
| 23 | + |
| 24 | + if (!(is.numeric(sample_radius) && length(sample_radius) == 1)) |
| 25 | + stop("'sample_radius' must be a single numeric value", call. = FALSE) |
| 26 | + |
| 27 | + if (missing(tree_list) || is.null(tree_list)) |
| 28 | + stop("'tree_list' is required", call. = FALSE) |
| 29 | + |
| 30 | + if (!is.data.frame(tree_list)) |
| 31 | + stop("'tree_list' must be a data frame", call. = FALSE) |
| 32 | + |
| 33 | + if (any(tree_list$AZIMUTH < 0) || any(tree_list$AZIMUTH > 360)) |
| 34 | + stop("'tree_list$AZIMUTH' contains values out of range", call. = FALSE) |
| 35 | + |
| 36 | + if (is.null(digits)) |
| 37 | + digits <- 1 |
| 38 | + |
16 | 39 | x <- tree_list$DIST * sin(tree_list$AZIMUTH * (pi / 180)) |
17 | 40 | y <- tree_list$DIST * cos(tree_list$AZIMUTH * (pi / 180)) |
18 | 41 |
|
19 | 42 | crowns <- lapply(seq_len(nrow(tree_list)), \(i) { |
20 | 43 | gdalraster::g_create("POINT", c(x[i], y[i])) |> |
21 | | - gdalraster::g_buffer(tree_list$CRWIDTH[i] / 2) |
| 44 | + gdalraster::g_buffer(tree_list$CRWIDTH[i] / 2) |
22 | 45 | }) |
23 | 46 |
|
24 | 47 | crowns_poly <- gdalraster::g_build_collection(crowns) |> |
25 | | - gdalraster::g_unary_union() |
| 48 | + gdalraster::g_unary_union() |
26 | 49 |
|
27 | | - plot_poly <- gdalraster::g_buffer("POINT (0 0)", plot_radius, 90L) |
| 50 | + plot_poly <- gdalraster::g_buffer("POINT (0 0)", sample_radius, 90L) |
28 | 51 |
|
29 | | - gdalraster::g_intersection(plot_poly, crowns_poly) |> |
30 | | - gdalraster::g_area() / gdalraster::g_area(plot_poly) * 100 |
| 52 | + tcc <- gdalraster::g_intersection(plot_poly, crowns_poly) |> |
| 53 | + gdalraster::g_area() / gdalraster::g_area(plot_poly) * 100 |
| 54 | + |
| 55 | + round(tcc, digits) |
31 | 56 | } |
0 commit comments