Polygon

knitr::opts_chunk$set(echo = TRUE, warning = FALSE,message = FALSE)

library(sf)
library(dplyr)

Must not overlap

knitr::include_graphics("images/topology_rules/0_0.jpg")

In context of DE-9IM, this is a simple case. The polygon interiors should not overlap at all, everything else does not matter. Interior-Interior is the first of the 9 intersections, so the the intersection matrix as a code string would be: 2********. In the case of the example below:

set.seed(10)
nrows <- 10
circs <- data.frame(
  id = 1:nrows,
  x = rnorm(nrows),
  y = rnorm(nrows)
) %>%
  st_as_sf(coords = c(2,3)) %>%
  st_buffer(0.25)
circsplot <- ggplot(circs) + 
  geom_sf(fill = "blue",alpha = 0.3) +
  geom_sf_text(aes(label = id)) +
  theme_void()
circsplot

This gives us a sparse matrix as an output, which is esentially a list with the same length as the x, where each position is a vector of integers with the indicies of the features in y (which may equal to x) where the pattern matches.

st_relate(circs,pattern = "2********")

Setting sparse = FALSE returns a crossmatrix of all combinations.W

crossmatrix <- st_relate(circs,pattern = "2********",sparse = FALSE)
crossmatrix[1:6,1:6] # only showing 6 since this prints nicely

# Remove the diagonals since it's simply each feature tested against itself
diag(crossmatrix) <- FALSE
error <- which(crossmatrix,arr.ind = TRUE) %>%
  as.vector() %>%
  unique()


circsplot +
  geom_sf(data = circs[error,], fill = "red", alpha = 0.3)

Must not have gaps

knitr::include_graphics("images/topology_rules/0_0.jpg")

Lets cosider the North Carolina Dataset for this question.

nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)

ggplot(nc) + 
  geom_sf() +
  theme_void()

The first task is to dissolve all adjecent polygons together

nc_union <- st_union(nc)
nc_union

If the output is a multipolygon as it is the case here, it's bad news, there are gaps. To check which parts are disconnected from each other, we can cast the multipolygon to a polygon (in ArcGIS Terms "Multipart to singlepart"), add a rowname for each part and colour it by rowname.

nc_singlepart <- nc_union %>%
  st_cast("POLYGON")%>%
  st_sf() %>%
  mutate(id = 1:n())

ggplot(nc_singlepart) +
  geom_sf(aes(fill = factor(id))) +
  labs(fill = "id") +
  theme_void()

But maybe we can live with these Islands in the state of North Carolina, since this is in fact an accurate representation of reality (the gaps are a result of the Atlantic Ocean). We must now check whether the individual geometries have holes. Here we can make use of the way polygons are defined in sf:

geometry with a positive area (two-dimensional); sequence of points form a closed, non-self intersecting ring; the first ring denotes the exterior ring, zero or more subsequent rings denote holes in this exterior ring

This means that the length of each Polygon geometry must be 1. A length of 2 or more would mean that there are one (or more) holes in the geometry. We can do this with any of the functions from the apply family, I prefer purrr:

map_lgl(nc_singlepart$geometry,~length(.x)== 1)

Let's see what happens if we cut a hole into the polygons

holes <- nc_singlepart %>%
  st_union() %>%
  st_centroid() %>%
  st_buffer(0.5)

nc_holes <- st_difference(nc_singlepart,holes)

ggplot(nc_holes) + 
  geom_sf() +
  theme_void()

map_lgl(nc_holes$geometry,~length(.x)== 1)

Contains point

knitr::include_graphics("images/topology_rules/1_0.jpg")

Contains one Point

knitr::include_graphics("images/topology_rules/1_1.jpg")

Must be covered by feature class of

knitr::include_graphics("images/topology_rules/2_0.jpg")

Boundary must be covered by

knitr::include_graphics("images/topology_rules/2_1.jpg")

Must not overlap with

knitr::include_graphics("images/topology_rules/3_0.jpg")

Must be covered by

knitr::include_graphics("images/topology_rules/3_1.jpg")

Area boundary must be covered by boundary of

knitr::include_graphics("images/topology_rules/4_0.jpg")

Must cover each other

knitr::include_graphics("images/topology_rules/4_1.jpg")


arc2r/book documentation built on March 5, 2021, 2:10 p.m.