繁体   English   中英

使用带有 R 的 sf 包从直线、圆和弧制作多边形

[英]Make a polygon from lines, circles and arcs using the sf package with R

所以我需要使用sf包用 R 制作一个多边形,而我所拥有的只是一个相对简单的数据框,我可以在其中看到构成线、弧的点(多边形边缘的某些部分是弧而不是直线) ,然后是圆圈(这些在多边形内部并且是表面上的孔)。

多边形边是线或弧,它们应该相互连接,这样我就不必使用st_convex_hull或类似的东西。 完整的圆在多边形内部,最后将是多边形中的孔。

我是使用sf的新手,但我已经想出了如何处理线条和圆圈,尽管可能有更好的方法。

我创建了包含 3 个元素的虚拟数据,每个元素一个,以及我如何构建不同的几何图形。 我实际上被弧线部分困住了。 我非常有信心这应该很容易,也许使用circularstring类型但不确定这是否是最好的方法。 显然不会有这些虚拟数据的最终多边形,但希望它能传达这个想法。

这是虚拟数据和我的代码。

library(tidyverse)
#> Warning: package 'tidyverse' was built under R version 4.0.3
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

(sample <- data.frame(number = 1,
                     name = c("Arc", "Circle", "Line"),
                     area = c(0.46, 330, NA),
                     start_angle = c(134, NA, NA),
                     angle_total = c(17, NA, NA),
                     center_x = c(974, 377, NA),
                     center_y = c(7299, 7250, NA),
                     center_z = c(0, 0, NA),
                     length = c(4.27, NA, 15),
                     radius = c(14, 10.2, NA),
                     angle = c(NA, NA, 270),
                     delta_x = c(NA, NA, 0),
                     delta_y = c(NA, NA, -15),
                     delta_z = c(NA, NA, 0),
                     start_x = c(NA, NA, 18.2),
                     start_y = c(NA, NA, 7000),
                     start_z = c(NA, NA, 0),
                     end_x = c(NA, NA, 18.2),
                     end_y = c(NA, NA, 146),
                     end_z = c(NA, NA, 0)) %>% 
  as_tibble())
#> # A tibble: 3 x 20
#>   number name    area start_angle angle_total center_x center_y center_z length
#>    <dbl> <chr>  <dbl>       <dbl>       <dbl>    <dbl>    <dbl>    <dbl>  <dbl>
#> 1      1 Arc     0.46         134          17      974     7299        0   4.27
#> 2      1 Circ~ 330             NA          NA      377     7250        0  NA   
#> 3      1 Line   NA             NA          NA       NA       NA       NA  15   
#> # ... with 11 more variables: radius <dbl>, angle <dbl>, delta_x <dbl>,
#> #   delta_y <dbl>, delta_z <dbl>, start_x <dbl>, start_y <dbl>, start_z <dbl>,
#> #   end_x <dbl>, end_y <dbl>, end_z <dbl>

line_start <- sample %>% 
  filter(name == "Line") %>% 
  select(start_x, start_y) %>% 
  rename(X = start_x, Y = start_y) %>% 
  mutate(ID = 1:nrow(.))

line_end <- sample %>% 
  filter(name == "Line") %>% 
  select(end_x, end_y) %>% 
  rename(X = end_x, Y = end_y) %>% 
  mutate(ID = 1:nrow(.))

(lines <- line_start %>% 
  bind_rows(line_end) %>%
  st_as_sf(coords = c("X", "Y")) %>%
  group_by(ID) %>%
  summarise(do_union = FALSE) %>%
  st_cast("LINESTRING"))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> Simple feature collection with 1 feature and 1 field
#> geometry type:  LINESTRING
#> dimension:      XY
#> bbox:           xmin: 18.2 ymin: 146 xmax: 18.2 ymax: 7000
#> CRS:            NA
#> # A tibble: 1 x 2
#>      ID              geometry
#>   <int>          <LINESTRING>
#> 1     1 (18.2 7000, 18.2 146)

# ggplot() +
#   geom_sf(data = lines) +
#   coord_sf(xlim = c(10, 20))

circle_centers <- sample %>% 
  filter(name == "Circle") %>% 
  select(center_x, center_y) %>% 
  rename(X = center_x, Y = center_y) %>% 
  mutate(ID = 1:nrow(.))

circle_radii <- sample %>% 
  filter(name == "Circle") %>% 
  select(radius) %>% 
  rename(R = radius) %>% 
  mutate(ID = 1:nrow(.))

(circle <- circle_centers %>% 
  st_as_sf(coords = c("X", "Y")) %>%
  st_buffer(circle_radii$R))
#> Simple feature collection with 1 feature and 1 field
#> geometry type:  POLYGON
#> dimension:      XY
#> bbox:           xmin: 366.8 ymin: 7239.8 xmax: 387.2 ymax: 7260.2
#> CRS:            NA
#> # A tibble: 1 x 2
#>      ID                                                                 geometry
#> * <int>                                                                <POLYGON>
#> 1     1 ((387.2 7250, 387.186 7249.466, 387.1441 7248.934, 387.0744 7248.404, 3~

# ggplot() +
#   geom_sf(data = circle)

# ggplot() +
#   geom_sf(data = rbind(lines, circle)) +
#   coord_sf(xlim = c(-500, 1000))

reprex 包(v0.3.0) 创建于 2020-12-03

唯一缺少的步骤是将所有这些几何图形组合起来,最终得到内部有孔的多边形,但是一旦我拥有所有分离的几何图形,这应该很容易。

也可能有更好的方法来处理线条和圆圈部分。 同样,我只是从sf开始,所以如果您知道的话,请随时教我更有效的方法。

提前感谢您的帮助!

那么,让我们从头开始,以及如何从我拥有的示例数据(顺便说一下,这是 autoCAD 导出数据)制作circularstring字符串。

arcs <- sample %>% 
    filter(name == "Arc") %>% 
    mutate(ID = 1:nrow(.)) %>% 
    mutate(X_1 = center_x + radius * cos(start_angle * pi / 180),
           Y_1 = center_y + radius * sin(start_angle * pi / 180),
           X_2 = center_x + radius * cos((angle_total + start_angle) * pi / 180),
           Y_2 = center_y + radius * sin((angle_total + start_angle) * pi / 180),
           X_3 = center_x + radius * cos((angle_total/2 + start_angle) * pi / 180),
           Y_3 = center_y + radius * sin((angle_total/2 + start_angle) * pi / 180))

这是通过弧的中心(黄色)、四肢(绿色和红色)和弧上的中点(蓝色)来完成大部分繁重的工作:

ggplot() +
  geom_point(aes(x = arcs$center_x, y = arcs$center_y), col = "yellow", alpha = 0.5) +
  geom_point(aes(x = arcs$X_1, y = arcs$Y_1), col = "red", alpha = 0.5) +
  geom_point(aes(x = arcs$X_2, y = arcs$Y_2), col = "green", alpha = 0.5) +
  geom_point(aes(x = arcs$X_3, y = arcs$Y_3), col = "blue", alpha = 0.5)

从那里开始构建你的circularstring是一个很好的策略:

arcs_sf <- arcs %>% 
  mutate(CIRCULARSTRING = paste0("CIRCULARSTRING(", X_1, " ", Y_1, ", ", X_3, " ", Y_3, ", ", X_2, " ", Y_2, ")")) %>% 
  pull(CIRCULARSTRING) %>% 
  as.list() %>% 
  st_as_sfc() %>% 
  st_cast("LINESTRING") %>% 
  st_as_sf()

计划检查一切是否完好:

ggplot() +
  geom_point(aes(x = arcs$center_x, y = arcs$center_y), col = "yellow", alpha = 0.5) +
  geom_point(aes(x = arcs$X_1, y = arcs$Y_1), col = "red", alpha = 0.5) +
  geom_point(aes(x = arcs$X_2, y = arcs$Y_2), col = "green", alpha = 0.5) +
  geom_point(aes(x = arcs$X_3, y = arcs$Y_3), col = "blue", alpha = 0.5) +
    geom_sf(data = arcs_sf)

现在棘手的部分是最终得到一个多边形,因为通常情况下,例如应该与一条线连接的弧形末端,这两个应该处于完全相同坐标的点(末端)实际上不是。 所以形状不接近, st_polygon不能做任何事情。 由于多边形是由弧线和线构成的(圆圈是此形状内的孔),您可以使用st_segmentize()沿线添加点,然后使用concaveman::concaveman(concavity = 0.1) ,其中concavity是您的猜测倒是自己找出来用。 我不记得所有的细节,但concaveman()只考虑点来构造多边形,而不是线或弧,因此需要在调用它之前添加点。

希望这能说明一些问题并且对某人有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM