[R-sig-Geo] self-intersecting polygons

Dexter Locke dexter@|ocke @end|ng |rom gm@||@com
Fri Nov 12 23:23:02 CET 2021


Dear list,

I have a set of 15 and 30 minute drive-time polygons created
from mapboxapi::mb_isochrone. Ultimately I want to erase the smaller
polygons from the larger so that the polygons are non-overlapping,
concentric rings.

The whole dataset includes ~1600 polygons for each drive-time spread out
over the 50 US states plus Washington DC and Puerto Rico. 13 of them have
apparent geometry errors, but the example below includes just 4 polygons
with one self intersection in Hawaii.

script (also below) and data available here:
http://dexterlocke.com/wp-content/uploads/2021/11/reprex_files.zip (I
couldn't figure out how to get the script to load data into R from a URL)

library(sf)
library(tidyverse)

# read in data
(small <- st_read(paste0(getwd(), '/data/reprex_files/small_polys.shp')))
(large <- st_read(paste0(getwd(), '/data/reprex_files/large_polys.shp')))

# look on basemap (optional)
mapview::mapview(small, color = 'black') + mapview::mapview(large, color =
'red')

# create function to erase holes to make 'donuts'
# https://github.com/r-spatial/sf/issues/346
st_erase <- function(x, y) st_difference(x, st_union(st_combine(y)))

# apply the erasing function
donut <- large %>% st_erase(., small) # fails

# 1st option explored, turn off spherical geometry as suggested here:
# https://github.com/r-spatial/sf/issues/1762

# here
https://gis.stackexchange.com/questions/404385/r-sf-some-edges-are-crossing-in-a-multipolygon-how-to-make-it-valid-when-using/404454

# and here
#
https://stackoverflow.com/questions/68478179/how-to-resolve-spherical-geometry-failures-when-joining-spatial-data/68481205#68481205

sf_use_s2(FALSE)

donut <- large %>% st_erase(., small) # results in errors..

# are the polygons valid? Yes
small %>% st_is_valid()
large %>% st_is_valid()

# 2nd option explored, more intensive geometry cleaning, as suggested here:
#
https://stackoverflow.com/questions/68478179/how-to-resolve-spherical-geometry-failures-when-joining-spatial-data/68481205#68481205
and elsewhere
small$geometry <- small$geometry %>%
  s2::s2_rebuild() %>%
  sf::st_as_sfc()

large$geometry <- large$geometry %>%
  s2::s2_rebuild() %>%
  sf::st_as_sfc()

# re-attempt
donut <- large %>% st_erase(., small) # results in errors

# 3rd option explored, zero-distance buffer to help reset geometries
small <- small %>% st_buffer(., 0)
large <- large %>% st_buffer(., 0)

# re-attempt
donut <- large %>% st_erase(., small) # more self-intersection errors

# 4th option explored, reproject before buffering
# suggested here:
https://gis.stackexchange.com/questions/404385/r-sf-some-edges-are-crossing-in-a-multipolygon-how-to-make-it-valid-when-using/404388#404388
small <- small %>% st_transform(crs = 5070) %>% st_buffer(0) %>%
st_transform(crs = 4269)
large <- large %>% st_transform(crs = 5070) %>% st_buffer(0) %>%
st_transform(crs = 4269)

# re-attempt
donut <- large %>% st_erase(., small) # more self-intersection errors

# 5th option
small_s2 <- small %>%
  s2::s2_rebuild(.,
                 options = s2::s2_options(edge_type = "undirected",
                 duplicate_edges = FALSE,
                 split_crossing_edges = TRUE,
                 validate = TRUE)) %>%
  st_as_sf()

large_s2 <- large %>%
  s2::s2_rebuild(.,
                 options = s2::s2_options(edge_type = "undirected",
                 duplicate_edges = FALSE,
                 split_crossing_edges = TRUE,
                 validate = TRUE)) %>%
  st_as_sf()

# re-attempt
donut <- large_s2 %>% st_erase(., small_s2) # more self-intersection errors


# 6th option explored using rgeos and sp, as suggested here:
#
https://gis.stackexchange.com/questions/163445/getting-topologyexception-input-geom-1-is-invalid-which-is-due-to-self-intersec/163480#163480

# same problems..

# so where is the double-vertex?
large %>%
  filter(id == 1017) %>% # based on zooming and panning around via mapview
  st_cast('POINT') %>%
  mutate(geom_text = as.character(geometry)) %>%
  group_by(geom_text) %>%
  count() %>%
  arrange(desc(n))

# as indicated from some errors and from query directly above
bad_point <- tibble(row = 1, x = -155.056700377001,  y = 19.5963974859705)
%>%
  st_as_sf(., coords = c('x', 'y')) %>%
  st_set_crs(4269)

# take a look
large %>% mapview::mapview() + mapview::mapview(bad_point, color = 'red')

# Ok, so there are two vertices there.. how can I remove the duplicates and
get on with the rest of the analyses?

Thank you, Dexter

	[[alternative HTML version deleted]]



More information about the R-sig-Geo mailing list