如何仅向外缓冲一组具有公共边的多边形(从边缘,而不是内部 "frontiers")

How can I buffer a set of polygons with common edges only outwards (from the edges, not the inner "frontiers")

我正在使用 here 找到的爱尔兰共和国各县地图(直接下载)。

我想做的是将每个县的海岸向海延伸1500米,但不移动县与县之间的边界。

编辑:我还需要将沿海县的县界向大海延伸,以满足新的、延伸的“海岸线”(根据 mrhellmann 问题添加)

到目前为止我的代码:

  1. 加载包和数据

    library(tidyverse)
    library(sf)
    library(ggplot2)
    
    ireland <- st_read("~Census2011_Admin_Counties_generalised20m.shp")
    st_crs(ireland) # units are m
    
  2. 缓冲区

    ireland_buf <- ireland %>% 
      st_buffer(1500)
    
  3. 检查边界如何移动

    ggplot() + 
      geom_sf(data = ireland_buf, col = "red", fill = "lightgray") + 
      geom_sf(data = ireland, col = "black", fill = NA) + 
      theme_bw()
    

所以,基本上,红线对应缓冲地图,黑线对应原始地图。我已经在海岸线上获得了预期的效果,但是县边界会根据县的不同向内或向外移动

按问题加载数据

library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
ireland_url <- "http://census.cso.ie/censusasp/saps/boundaries/Census2011_Admin_Counties_generalised20m.zip"
download.file(ireland_url, destfile = "ireland.zip")
f <- unzip("ireland.zip")
unlink("ireland.zip")
ireland <- st_read("Census2011_Admin_Counties_generalised20m.shp")
#> Reading layer `Census2011_Admin_Counties_generalised20m' from data source `/tmp/RtmpbGVDJH/reprexfc55361dad50/Census2011_Admin_Counties_generalised20m.shp' using driver `ESRI Shapefile'
#> Simple feature collection with 34 features and 20 fields
#> geometry type:  MULTIPOLYGON
#> dimension:      XY
#> bbox:           xmin: 17491.14 ymin: 19589.93 xmax: 334558.6 ymax: 466919.3
#> projected CRS:  TM65 / Irish National Grid
unlink(f)

使用 spatstat 说明的问题:

library(spatstat)
#> Loading required package: spatstat.data
#> Loading required package: spatstat.geom
#> spatstat.geom 1.65-8
#> Loading required package: spatstat.core
#> Loading required package: nlme
#> Loading required package: rpart
#> spatstat.core 1.65-9
#> Loading required package: spatstat.linnet
#> 
#> spatstat 2.0-0       (nickname: 'Caution: contains small parts') 
#> For an introduction to spatstat, type 'beginner'
originals <- lapply(st_geometry(ireland), as.owin)
dilated <- lapply(originals, dilation, r = 1500)
bb <- do.call(boundingbox, dilated)
plot(bb, main = "", type = "n")
for(i in seq_along(dilated)){
  plot(dilated[[i]], add = TRUE)
}

单个区域的可能解决方案(你必须自己制作一个额外的循环并根据需要转换回sf格式)

dilated_coast <- dilated[[34]]
for(i in seq_along(originals)[-34]){
  dilated_coast <- setminus.owin(dilated_coast, originals[[i]])
}
plot(dilated_coast, main = "", col = 2)
plot(originals[[34]], add = TRUE, col = 1)

使用基础 shapefile,您可以通过组合、缓冲、空间采样和创建 voronoi 多边形来创建一些其他对象。通过加入和交叉这些你可以得到大部分的方式。

以下示例的问题是它缓冲到北部边界的相邻陆地,一些靠得很近的岛屿可能会造成非常小的问题。

library(sf)
library(ggplot2)
library(dplyr)
library(tmap) # for "MAP_COLORS"


path <- 'Census2011_Admin_Counties_generalised20m.shp'
ireland <- read_sf(path)

base_crs <- st_crs(ireland)

#remove county lines, keeps only an outline of the area
ireland_combined <- st_combine(ireland)  
# add buffer, fortunately the base CRS is in meters
ireland_buffered <- st_buffer(ireland_combined, 1500)   
# polygon(s) of only the buffer
buffer_only <- st_difference(ireland_buffered, ireland_combined) 

# sample points inside the buffer for voronoi polygons
# type can be random, hexagonal, or regular.
# increase size for accuracy, decrease for speed.
sampled_points <- st_sample(buffer_only, size = 5000, type = 'hexagonal')

#Create voronoi polygons from sampled points
voronoi <- sampled_points %>%
  st_union() %>%
  st_voronoi() %>%
  st_cast()

# Crop voronoi polygons to buffer area only
# plot 2 below shows voronoi polygons extend much too far for this case
voronoi_buffer <- 
  st_intersection(
    st_make_valid(voronoi),
    buffer_only
  ) %>%
  st_as_sf()

# Join polygons by proximity to counties in base shapefile
voronoi_joined <- st_join(
  voronoi_buffer,
  ireland,
  join = st_nearest_feature
)

# join voronoi polygons by countyname
vj_summarized <- voronoi_joined %>% 
  group_by(COUNTYNAME) %>%
  summarize()

#mapview was having trouble with this county name
vj_summarized$COUNTYNAME[6] <- 'Dun Laoghaire-Rathdown'
ireland$COUNTYNAME[20] <- 'Dun Laoghaire-Rathdown'

#rbind sea buffer & land, then join with group_by & summarize
buffer_and_land <- rbind(ireland %>% select(COUNTYNAME), vj_summarized) %>%
  group_by(COUNTYNAME) %>%
  summarise()


#plots
p1 <- ggplot() + 
  geom_sf(data = ireland, fill = NA) + 
  geom_sf(data = ireland_buffered, fill = NA, alpha = .4, color = 'green') +
  ggtitle(label = "Ireland counties & 1500m buffer")

p2 <- ggplot() + 
  geom_sf(data = voronoi, alpha = .2) +
  geom_sf(data = voronoi_buffer, alpha = .2, fill = NA, color = 'turquoise') +
  ggtitle(label = 'Voronoi & buffer')

# Counties & buffers joined & colored
p4 <- tm_shape(st_geometry(buffer_and_land)) + 
  tm_polygons(col = "MAP_COLORS") + 
  tm_shape(st_geometry(ireland)) + 
  tm_polygons(border.col = 'black', col = NA, alpha = 0)

p1

绿色区域显示缓冲区和缓冲到边界土地的问题。您可以通过使用整个岛屿的 shapefile 来避免这种情况。

p2

已显示完整的 voronoi。绿松石感兴趣的领域。

p4

Buffer与县相连,以县名填充。县边界以黑色覆盖。

其中一个杂乱区域的特写,增加采样点的数量可能会有所帮助。 reprex package (v1.0.0)

创建于 2021-03-22