[英]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.