如何从点到多边形边缘画一条线,然后在 R 中以 sf 获取线的长度?

How can I draw a line from a point to a polygon edge and then get the line's length in sf in R?

还有一些其他帖子与此相关,例如:Post 1, Post 2, . However, none of them deliver what I am hoping for. What I want is to be able to draw a line segment from a specific point (a sampling location) to the edge of a polygon fully surrounding that point (a lake border) in a specific direction ("due south" aka downward). I then want to measure the length of that line segment in between the sampling point and the polygon edge (really, it's only the distance I want, so if we can get the distance without drawing the line segment, so much the better!). Unfortunately, it doesn't seem like functionality to do this already exists within the sf package: See closed issue here

怀疑 ,不过,这可以通过修改此处提供的解决方案来实现:See copy-pasted code below, modified by me。然而,我对 sf 中的工具非常糟糕——我只制作了从点本身到多边形南部范围的线段,在某个点与多边形相交:

library(sf)
library(dplyr)

df = data.frame(
  lon = c(119.4, 119.4, 119.4, 119.5, 119.5),
  lat = c(-5.192,-5.192,-5.167,-5.167,-5.191)
)

polygon <- df %>%
  st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
  summarise(geometry = st_combine(geometry)) %>%
  st_cast("POLYGON")

plot(polygon)

df2 <- data.frame(lon = c(119.45, 119.49, 119.47),
                  lat = c(-5.172,-5.190,-5.183))

points <- df2 %>%
  st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
  summarise(geometry = st_combine(geometry)) %>%
  st_cast("MULTIPOINT")

plot(points, add = TRUE, col = "red")

# Solution via a loop

xmin <- min(df$lat)

m = list()
# Iterate and create lines
for (i in 1:3) {
  m[[i]] = st_linestring(matrix(
    c(df2[i, "lon"],
      df2[i, "lat"],
      df2[i, "lon"],
      xmin),
    nrow = 2,
    byrow = TRUE
  ))
}
test = st_multilinestring(m)

# Result is line MULTILINESTRING object

plot(test, col = "green", add = TRUE)

但现在我不知道如何使用 st_intersection 或任何此类函数来找出交点的位置。我认为,大部分问题在于我正在创建的不是 sf 对象,而且我无法弄清楚如何让它成为一个对象。我假设,如果我能找出线段与多边形相交的位置(或者理想情况下它们相交的最北时间),我可以使用 st_distance 之类的函数以某种方式测量从交点到采样点的距离.但是,由于湖泊多边形通常 确实 复杂,因此一个线段可能会多次与多边形相交(例如给定点以南有一个半岛),在这种情况下我认为我可以为每个采样点找到“最北端”的交点并使用它,或者为每个采样点取最小这样的距离。

无论如何,如果有人能告诉我我遗漏的几个步骤,那就太好了!我觉得我很近又很远...

考虑一下这种方法,大致上受到我之前 post 关于 lines from points

的启发

为了使其更具可重现性,我使用了众所周知且备受喜爱的北卡罗来纳州 shapefile,它随 {sf} 和三个 semi-random NC 城市的数据框一起提供。

代码的作用是:

  • 循环遍历城市数据框
  • 创建一条线,从每个城市(“观测点”)开始,到南极结束
  • 与已解散的北卡罗来纳州相交
  • 将交叉点爆破为单独的线串
  • 选择原点 1 米以内的线串
  • 通过sf::st_lenghth()
  • 计算长度
  • 将结果保存为名为 res(结果的缩写 :)
  • 的 {sf} 数据框

为了使结果更清晰,我在最终对象中包含了实际的行,但您可以选择省略它。

library(sf)
library(dplyr)
library(ggplot2)

shape <- st_read(system.file("shape/nc.shp", package="sf")) %>%  # included with sf package
  summarise() %>% 
  st_transform(4326) # to align CRS with cities

cities <- data.frame(name = c("Raleigh", "Greensboro", "Plymouth"),
                     x = c(-78.633333, -79.819444, -76.747778),
                     y = c(35.766667, 36.08, 35.859722)) %>% 
  st_as_sf(coords = c("x", "y"), crs = 4326)

# a quick overview
ggplot() +
   geom_sf(data = shape) + # polygon of North Carolina
   geom_sf(data = cities, color = "red") # 3 cities  

# now here's the action!!!
for (i in seq_along(cities$name)) {
  
  # create a working linestring object
  wrk_line <- st_coordinates(cities[i, ]) %>% 
    rbind(c(0, -90)) %>% 
    st_linestring() %>% 
    st_sfc(crs = 4326) %>% 
    st_intersection(shape) %>% 
    st_cast("LINESTRING") # separate individual segments of multilines
  
  first_segment <- unlist(st_is_within_distance(cities[i, ], wrk_line, dist = 1))  
  
  # a single observation
  line_data <- data.frame(
    name = cities$name[i],
    length = st_length(wrk_line[first_segment]),
    geometry = wrk_line[first_segment]
  )
  
  # bind results rows to a single object
  if (i == 1) {
    res <- line_data
    
  } else {
    res <- dplyr::bind_rows(res, line_data)
    
  } # /if - saving results
  
  
} # /for

# finalize results
res <- sf::st_as_sf(res, crs = 4326) 
  
# result object    
res
# Simple feature collection with 3 features and 2 fields
# Geometry type: LINESTRING
# Dimension:     XY
# Bounding box:  xmin: -79.81944 ymin: 33.92945 xmax: -76.74778 ymax: 36.08
# Geodetic CRS:  WGS 84
#         name        length                       geometry
# 1    Raleigh 204289.21 [m] LINESTRING (-78.63333 35.76...
# 2 Greensboro 141552.67 [m] LINESTRING (-79.81944 36.08...
# 3   Plymouth  48114.32 [m] LINESTRING (-76.74778 35.85...

# a quick overview of the lines
ggplot() +
  geom_sf(data = shape) + # polygon of North Carolina
  geom_sf(data = res, color = "red") # 3 lines