I am happy to share that viewscape 3.0.0 is now available on CRAN. This version expands the package from a viewshed and viewscape-metrics workflow into a broader toolkit for visibility-based landscape analysis in R.
The package can be installed directly from CRAN:
install.packages("viewscape")
library(viewscape)
The CRAN package page is here: https://CRAN.R-project.org/package=viewscape. The source code and issue tracker are available on GitHub: https://github.com/billbillbilly/viewscape.
What is new in 3.0.0?
The main workflow is still centered on computing viewsheds from a digital surface model (DSM) or digital elevation model and one or more observer locations. The new release adds more tools around that core:
- field-of-view masking with
fov_mask() - visual magnitude analysis with
visual_magnitude() - viewscape configuration metrics, including extent, depth, relief, skyline variation, Sky View Factor, and patch-based metrics
- land-cover diversity and feature proportions inside the visible area
- pairwise intervisibility networks with
intervis_network() - panoramic view generation with
pano_view()
These functions are useful when a research question is not only “what is visible?” but also “how much does it matter in the view?”, “which viewpoints are connected?”, and “what would the visible scene look like from the observer position?”
A short example
The package includes example data, so the basic workflow can be tested without downloading any external DSM first.
library(viewscape)
library(terra)
library(sf)
dsm <- terra::rast(system.file("test_dsm.tif", package = "viewscape"))
dtm <- terra::rast(system.file("test_dtm.tif", package = "viewscape"))
viewpoints <- sf::read_sf(system.file("test_viewpoints.shp", package = "viewscape"))
viewpoint <- viewpoints[2, ]
viewshed <- viewscape::compute_viewshed(
dsm = dsm,
viewpoints = viewpoint,
offset_viewpoint = 3,
r = 800,
method = "view_tree"
)
viewshed_raster <- viewscape::visualize_viewshed(
viewshed,
outputtype = "raster"
)
terra::plot(dsm, axes = FALSE, box = FALSE, legend = FALSE)
terra::plot(viewshed_raster, add = TRUE, col = "red", axes = FALSE, box = FALSE)
terra::plot(viewpoint, add = TRUE, col = "blue", pch = 16)
The result is a standard viewshed object that can be passed to other viewscape functions.
Field of view
In real environments, people rarely experience a full 360-degree view at one time. fov_mask() subsets the viewshed by direction and angle. Angles are measured clockwise from north, where 0 is north and 90 is east.
# North-facing 120-degree field of view
sector <- viewscape::fov_mask(viewshed, c(-60, 60))
terra::plot(dsm, axes = FALSE, box = FALSE, legend = FALSE)
terra::plot(
viewscape::visualize_viewshed(sector, outputtype = "raster"),
add = TRUE,
col = "red",
axes = FALSE,
box = FALSE
)
terra::plot(viewpoint, add = TRUE, col = "blue", pch = 16)
Visual magnitude
A binary viewshed tells us whether a cell is visible. Visual magnitude estimates how much each visible cell contributes to the observer’s visual field. Nearby surfaces that face the observer tend to have larger values.
vm <- viewscape::visual_magnitude(viewshed, dsm)
terra::plot(
dsm,
axes = FALSE,
box = FALSE,
legend = FALSE,
main = "Visual magnitude over DSM"
)
terra::plot(sqrt(vm), add = TRUE, alpha = 0.8, axes = FALSE, box = FALSE)
terra::plot(viewpoint, add = TRUE, col = "red", pch = 16)
This is especially helpful when visibility needs to be weighted by visual dominance rather than treated as a simple yes/no result.
Intervisibility network
intervis_network() tests whether viewpoints can see one another. The output can be an adjacency matrix or an sf line layer.
network_lines <- viewscape::intervis_network(
viewpoints = viewpoints,
dsm = dsm,
offset_viewpoint = 10,
r = 800,
output = "lines"
)
terra::plot(dsm, axes = FALSE, box = FALSE, legend = FALSE)
terra::plot(network_lines["geometry"], add = TRUE, col = "grey60", lwd = 1)
terra::plot(network_lines[network_lines$mutual, "geometry"], add = TRUE, col = "#2171b5", lwd = 2)
terra::plot(viewpoints, add = TRUE, col = "red", pch = 16)
This can support questions about lookout points, scenic routes, landmark visibility, visual corridors, and spatial networks of mutually visible locations.
Panoramic view
The new pano_view() function generates a panoramic representation from a viewpoint. Without a semantic raster, it can create an RGB panorama using imagery. With a land-cover, canopy, or building raster, it can project semantic information into the panoramic view.
pano <- viewscape::pano_view(
dsm = dsm,
vpt = viewpoint,
h = 3,
pano_dim = c(512, 1024),
plot = TRUE
)
For land-use or land-cover analysis, a semantic raster can be added:
landuse <- terra::rast(system.file("test_landuse.tif", package = "viewscape"))
pano_landuse <- viewscape::pano_view(
dsm = dsm,
vpt = viewpoint,
h = 5,
semantic = landuse,
plot = TRUE
)
This opens up a bridge between raster-based visibility analysis and image-like representations of the observer’s visual scene.
Citation and documentation
The package documentation includes the reference manual and vignette:
- CRAN: viewscape
- Vignette: viewscape overview
- GitHub: billbillbilly/viewscape
If you use viewscape in research, please cite the package and the related methods described in the documentation. The 3.0.0 release builds on viewshed algorithms from Franklin and Ray (1994) and Wang et al. (2000), visual magnitude from Chamberlain and Meitner (2013), and viewscape configuration metrics from Tabrizian et al. (2020).