Code
library(sf)
library(dplyr)
library(ggplot2)
This figure was mostly prepared in QGIS, but an R version is provided here to show the steps involved.
Differences between the versions are due to the original being prepared across a wider extent which was then clipped down to the final extent. The input data used here are already clipped to the final extent meaning there may be anomalies near the edges.
You’ll need your own roads and buildings data. Mine came from OpenStreetMap via the QGIS QuickOSM plugin.
And a quick map to see what we’re working with.
Place points along the boundaries of each of these.
For the roads we combine all elements into a single line object and assign the same id
to every point generated.
For the buildings we wish to retain the building IDs, so we do a join based on the nearest feature in the buildings dataset.
b_pts <- bldgs |>
st_cast("MULTILINESTRING") |>
st_cast("LINESTRING") |>
# if any perimeter is < 1 then the sampling step fails
filter(st_length(geom) >= units::as_units(1, "m")) |>
st_line_sample(density = 1) |>
st_cast("POINT") |>
st_as_sf() |>
rename(geometry = x) |>
st_join(bldgs, join = st_nearest_feature) |>
mutate(id = full_id) |>
select(id)
Now combine the two into a single point dataset.
Now make a Voronoi layer from the points.
We need to clip this to the extent of the buildings data.
Now we dissolve (group_by
) on the id
attribute.
Finally, we can make a map, similar to the one in Figure 2.8 in the book.
bb <- st_bbox(extent)
ggplot() +
geom_sf(data = bldgs,
lwd = 0) +
geom_sf(data = roads |> st_buffer(2) |> st_intersection(extent),
fill = "#cc9999", lwd = 0) +
geom_sf(data = all_pts |> st_filter(extent |> st_buffer(-.1)),
colour = "black", size = 0.1) +
geom_sf(data = pts_vor,
colour = "lightgray", fill = NA, lwd = 0.35) +
geom_sf(data = diss_vor,
colour = "black", fill = NA) +
coord_sf(expand = FALSE) +
theme_void() +
theme(panel.border = element_rect(fill = NA, linewidth = 1.5))
# License (MIT)
#
# Copyright (c) 2023 David O'Sullivan
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
© 2023-24 David O’Sullivan