1+ # ' Display modeled tree crowns vertically projected on subplot boundaries
2+ # '
3+ # ' `plot_crowns()` draws vertically projected tree crowns as discs overlaid on
4+ # ' subplot or microplot boundaries. The full four-subplot cluster, or
5+ # ' individual subplots, can be displayed with trees `>= 5.0` in. (`12.7` cm)
6+ # ' diameter, or individual microplots can be display with saplings (i.e., trees
7+ # ' `< 5` in. diameter).
8+ # '
9+ # ' @param tree_list A data frame with tree records for one FIA plot. Must have
10+ # ' columns `SUBP` (FIA subplot number), `STATUSCD` (FIA integer tree status,
11+ # ' `1` = live), `DIA` (tree diameter), `HT` (tree height), `ACTUALHT` (tree
12+ # ' actual height, `ACTUALHT < HT` indicating a broken top), `DIST` (stem
13+ # ' distance from subplot/microplot center), `AZIMUTH` (horizontal angle from
14+ # ' subplot/microplot center to the stem location, in the range `0:359`), and
15+ # ' `CRWIDTH` (tree crown width).
16+ # ' @param subplot Optional integer subplot number in the range `1:4` indicating
17+ # ' a specific subplot for display. May be `NULL` or `NA` to display the full
18+ # ' four-point cluster.
19+ # ' @param microplot A logical value, `TRUE` to display the modeled crowns of
20+ # ' saplings overlaid of the microplot boundary of `subplot = n`. The default is
21+ # ' `FALSE`. Ignored if `subplot` is not specified.
22+ # ' @param linear_unit An optional character string specifying the linear
23+ # ' distance unit. Defaults to the native FIA unit of `"ft"`, but may be set to
24+ # ' `"m"` instead (or `"meter"` / `"metre"`), in which case subplot boundaries
25+ # ' will be display in meters, tree heights and crown widths are assumed to be
26+ # ' given in meters, and tree diameters are assumed to be given in centimeters.
27+ # ' **TODO: not currently implemented**
28+ # ' @param main Character string giving the main plot title (on top).
29+ # ' @return
30+ # ' The input, invisibly.
31+ # '
32+ # ' @examples
33+ # ' trees <- within(plantation, CRWIDTH <- predict_crwidth(plantation))
34+ # '
35+ # ' plot_crowns(trees, main = "plantation plot")
36+ # '
37+ # ' plot_crowns(trees, subplot = 4, main = "plantation subplot 4")
38+ # '
39+ # ' plot_crowns(trees, subplot = 4, microplot = TRUE,
40+ # ' main = "plantation microplot 4")
141# ' @export
242plot_crowns <- function (tree_list , subplot = NULL , microplot = FALSE ,
343 linear_unit = " ft" , main = " " ) {
444
45+ if (is.null(linear_unit ))
46+ linear_unit <- " ft"
47+ else if (! (is.character(linear_unit ) && length(linear_unit ) == 1 ))
48+ stop(" 'linear_unit' must be a single character string" , call. = FALSE )
49+ else
50+ linear_unit <- tolower(linear_unit )
51+
52+ if (! (linear_unit %in% c(" ft" , " foot" , " m" , " meter" , " metre" )))
53+ stop(" 'linear_unit' is invalid" , call. = FALSE )
54+
555 if (is.null(subplot ) || is.na(subplot ))
656 subplot <- FALSE
757
58+ if (subplot ) {
59+ if (! is.numeric(subplot ) && subplot %in% 1 : 4 )
60+ stop(" 'subplot' must be a numeric value in the range 1:4" ,
61+ call. = FALSE )
62+ }
63+
64+ if (is.null(microplot ) || is.na(microplot ))
65+ microplot <- FALSE
66+
67+ if (! (is.logical(microplot ) && length(microplot ) == 1 ))
68+ stop(" 'microplot' must be a single logical value" , call. = FALSE )
69+
870 if (subplot && microplot ) {
971 trees_in <- tree_list [tree_list $ STATUSCD == 1 &
1072 tree_list $ SUBP == subplot &
@@ -24,31 +86,33 @@ plot_crowns <- function(tree_list, subplot = NULL, microplot = FALSE,
2486 if (subplot ) {
2587 pts <- vector(mode = " list" , length = 2 )
2688 names(pts ) <- c(" x" , " y" )
27- pts $ x <- tree_list $ DIST * sin(tree_list $ AZIMUTH * (pi / 180 ))
28- pts $ y <- tree_list $ DIST * cos(tree_list $ AZIMUTH * (pi / 180 ))
89+ pts $ x <- trees_in $ DIST * sin(trees_in $ AZIMUTH * (pi / 180 ))
90+ pts $ y <- trees_in $ DIST * cos(trees_in $ AZIMUTH * (pi / 180 ))
2991 } else {
3092 pts <- .get_tree_list_xy(trees_in )
3193 }
3294
3395 crowns <- lapply(seq_len(nrow(trees_in )), \(i ) {
3496 gdalraster :: g_create(" POINT" , c(pts $ x [i ], pts $ y [i ])) | >
35- gdalraster :: g_buffer(trees_in $ CRWIDTH [i ] / 2 )
36- })
37-
38- rct <- as.list(gdalraster :: g_build_collection(crowns ) | >
39- gdalraster :: g_envelope())
40- names(rct ) <- c(" xmin" , " xmax" , " ymin" , " ymax" )
97+ gdalraster :: g_buffer(trees_in $ CRWIDTH [i ] / 2 )})
4198
4299 if (subplot ) {
43- fia_poly <- gdalraster :: g_buffer(" POINT (0 0)" , 24 )
100+ if (microplot ) {
101+ fia_poly <- gdalraster :: g_buffer(" POINT (0 0)" , 6.8 )
102+ } else {
103+ fia_poly <- gdalraster :: g_buffer(" POINT (0 0)" , 24 )
104+ }
44105 stems <- lapply(seq_len(nrow(trees_in )), \(i ) {
45106 gdalraster :: g_create(" POINT" , c(pts $ x [i ], pts $ y [i ])) | >
46- gdalraster :: g_buffer(trees_in $ dia_ft [i ] / 2 )
47- })
107+ gdalraster :: g_buffer(trees_in $ dia_ft [i ] / 2 )})
48108 } else {
49109 fia_poly <- .get_fia_plot_geom(linear_unit = linear_unit )
50110 }
51111
112+ rct <- as.list(gdalraster :: g_build_collection(c(crowns , list (fia_poly ))) | >
113+ gdalraster :: g_envelope())
114+ names(rct ) <- c(" xmin" , " xmax" , " ymin" , " ymax" )
115+
52116 xlab <- paste0(" x (" , linear_unit , " )" )
53117 ylab <- paste0(" y (" , linear_unit , " )" )
54118 gdalraster :: plot_geom(fia_poly , xlab , ylab , main , border = " gray62" ,
@@ -64,5 +128,8 @@ plot_crowns <- function(tree_list, subplot = NULL, microplot = FALSE,
64128 }
65129 }
66130
67- invisible (NULL )
131+ border_col <- grDevices :: adjustcolor(" gray62" , alpha.f = 0.2 )
132+ gdalraster :: plot_geom(fia_poly , border = border_col , lwd = 3 , add = TRUE )
133+
134+ invisible (tree_list )
68135}
0 commit comments