st_buffer 与 endCapStyle = "FLAT" 和 singleSide = TRUE 无法正确渲染

问题描述 投票:0回答:1

我正在尝试沿约 600 条样线制作单面缓冲区,但是缓冲区无法正常工作。

Incorrect single sided buffer

  • 我尝试在 sf (v1.0-16) 和 terra (v1.7-71) 中实现。
  • 我已从纬度/经度投影到 UTM 10 区(并尝试了 9 区,结果类似)
  • 我尝试过使用 sf_use_s2(FALSE) 和 sf_use_s2(TRUE) 来制作缓冲区
  • sf 和 terra 的实现同样都是错误的。
  • 奇怪的是,昨天代码工作得更好一些,更多的横断面获得了正确的缓冲区(但不是全部!)。

我错过了什么!?

library(sf) #v1.0 -16
library(ggplot2)
library(dplyr)
library(units)
library(terra)
library(tmap) 

#Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE

#code for building the Linestring from full dataset - multipoint saved for trouble shooting
obs_pt<-obs %>% filter(is.na(Transect_ID)==FALSE)%>%
  st_as_sf(coords = c("lon", "lat"), na.fail = FALSE, crs = "epsg:4326") %>%
  group_by(Transect_ID) %>%
  summarize() %>%
  filter(st_geometry_type(.) == "MULTIPOINT") 

obs_ls<-obs_pt %>% 
  st_cast("LINESTRING", keep=TRUE)

#switch from lat/lon to UTM for planer geometry
obs_ls_planer<-obs_ls%>%st_transform("EPSG:32610") #Zone 10= most of study area

#filter data for reproducible example:
obs_ls_125<-obs_ls_planer%>%filter(Transect_ID==125)

saveRDS(obs_ls_125,paste0(usr,dir,"obs_ls_125.rda"))

[obs_ls_125](https://www.dropbox.com/scl/fi/47c83vgxeccphb1rkjumv/obs_ls_125.rda?rlkey=c1ymlbky7iohzhke6dap2x4ep&dl=0)

obs_ls_125<-readRDS("obs_ls_125.rda")

obs_ls_125

具有 1 个特征和 5 个字段的简单特征集合 几何类型:LINESTRING 尺寸:XY 边界框:xmin:361857.1 ymin:4786302 xmax:362981.9 ymax:4787215 预计 CRS:WGS 84 / UTM 区域 10N

小标题:1×6

Transect_ID 几何 Cruise_ID 日期 条件 ObsSidePS

  •   <int>                                         <LINESTRING [m]> <chr>     <date>     <chr>     <chr>    
    

1 125 (362210.4 4786933, 362299.5 4786863, 362378.3 4786793, … 202210 2022-10-14 1 右舷

#buffer implementation in sf
obs_ls_125.b <- st_buffer(obs_ls_125, dist = 100, endCapStyle = "FLAT", singleSide = TRUE)

#buffer implementation in terra
vsp <- terra::vect(obs_ls_125)
buffer_terra <- terra::buffer(vsp, width = 100, capstyle = "FLAT", singlesided = TRUE)
buffer_terra.sf <- sf::st_as_sf(buffer_terra)

ggplot() +
  geom_sf(data = obs_ls_125.b, fill = "yellow")+
  geom_sf(data = obs_ls_125, color = "blue", linewidth = 1)+
  geom_sf(data = obs_ls_125.b%>%st_cast("POINT"), color = "orange") #points of polygon

ggplot() +
  geom_sf(data = buffer_terra.sf, fill = "pink")+
  geom_sf(data = buffer_terra.sf%>%st_cast("POINT"), color = "orange")

plot of buffer from sf

plot of buffer from terra

plot of original GPS points colored by time

r buffer terra geos
1个回答
0
投票

不是真的,它按预期工作,问题与横断面的几何形状有关。本身不是问题,但它不是一条直线,这使得事情变得更加困难。如下图所示,缓冲区是单侧的,但是线是弯曲的,因此缓冲区半径较大时,多边形会包围整条线。

a <- readRDS("~/Downloads/obs_ls_125.rda")
b <- a |>
  sf::st_buffer(dist = 30, singleSide = TRUE)

tmap::tm_shape(a) +
  tmap::tm_lines() +
  tmap::tm_shape(b) +
  tmap::tm_polygons() +
  tmap::tm_grid()

b <- a |>
  sf::st_buffer(dist = 1000, singleSide = TRUE)

tmap::tm_shape(b) +
  tmap::tm_polygons() +
  tmap::tm_shape(a) +
  tmap::tm_lines() +

这是

linestring
的详细信息:

terra::plot(a["geometry"], axes = TRUE, 
            xlim = c(362450, 362550),
            ylim = c(4786650, 4786750))

创建于 2024-03-27,使用 reprex v2.1.0

编辑

处理不直的横断面就是简化它们。您可以尝试使用足够大的

sf::st_simplify()
参数的
dTolerance = 1000
函数,但它也会移动最左/最右坐标。下面是如何在最左/右坐标之间创建线条并创建缓冲区的简单方法。 不知道您的样线来源是什么,是一种 GPS 文件吗?如果给出了线坐标,那么我们已经以某种方式处理了它;如果这是您可以选择/创建的内容,请查看
sf::st_make_grid()
函数。

a <- readRDS("~/Downloads/obs_ls_125.rda")

crd <- a |>
  sf::st_coordinates()

xleft <- crd[which(crd[, "X"] == min(crd[, "X"])), "X"]
yleft <- crd[which(crd[, "X"] == min(crd[, "X"])), "Y"]

xright <- crd[which(crd[, "X"] == max(crd[, "X"])), "X"]
yright <-  crd[which(crd[, "X"] == max(crd[, "X"])), "Y"]

l <- matrix(c(xleft, yleft, xright, yright), nrow = 2, ncol = 2, byrow = TRUE) |>
  sf::st_linestring() |>
  sf::st_sfc()

b <- l |>
  sf::st_buffer(dist = 30, singleSide = TRUE)

tmap::tm_shape(l) +
  tmap::tm_lines(lwd = 3, col = "blue") +
  tmap::tm_shape(b) +
  tmap::tm_polygons() +
  tmap::tm_grid()

创建于 2024-03-27,使用 reprex v2.1.0

© www.soinside.com 2019 - 2024. All rights reserved.