3

我需要能够在不丢失点的情况下缩小纬度/经度数据的多边形;更重要的是,我需要在正确的方向上有效地“平滑”这些点。通常,gBuffer工作正常,但不能保证点的数量和它们的相对间距。最终,我需要保留每个点的属性,而样条曲线、平滑和其他“良好的效率”gBuffer以及多边形的增长/收缩不允许我以对 1 对 1 映射的足够置信度来保留这些属性.

例子:

library(rgeos)   # gBuffer

dat <- structure(list(x = c(6, 5.98, 5.94, 5.86, 5.75, 5.62, 5.47, 5.31, 5.13, -4.87, -5.04, -5.22, -5.39, -5.55, -5.69, -5.81, -5.9, -5.96, -6, -6, -6, -5.96, -5.9, -5.81, -5.69, -5.55, -5.39, -5.22, -5.04, -3.04, -2.87, -2.69, -2.53, -2.38, -2.25, -2.14, -2.06, -2.02, -2, -2, -1.96, -1.9, -1.81, -1.69, -1.55, -1.39, -1.22, -1.04, -0.87, 1.13, 1.31, 1.47, 1.62, 1.75, 1.86, 1.94, 1.98, 2, 2, 2, 2.04, 2.1, 2.19, 2.31, 2.45, 2.61, 2.78, 2.96, 4.96, 5.13, 5.31, 5.47, 5.62, 5.75, 5.86, 5.94, 5.98, 6), y = c(5, 5.18, 5.35, 5.51, 5.66, 5.78, 5.88, 5.95, 5.99, 5.99, 6, 5.97, 5.92, 5.83, 5.72, 5.59, 5.43, 5.27, 5.09, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, -5, -1.91, -1.73, -1.57, -1.41, -1.28, -1.17, -1.08, -1.03, -1, -1.01, -1.01, -1.05, -1.12, -1.22, -1.34, -1.49, -1.65, -1.82, -2, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, 5)), row.names = c(NA, -78L), class = "data.frame")

# "shrink-wrap"
sp <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon( as.matrix(dat) )), "dat")))
sp2 <- gBuffer(sp, width = -0.5)
dat2 <- as.data.frame(sp2@polygons[[1]]@Polygons[[1]]@coords)

c(nrow(dat), nrow(dat2))
# [1] 78 97

我们立即看到点数的变化。我认识到,大多数时候,这是 的理想特性gBuffer,因此也许rgeos不是这种转换的最佳工具。

library(ggplot2) # just for vis here
ggplot(dat, aes(x, y)) +
  geom_path() + geom_point() +
  geom_path(data = dat2, color = "red") + geom_point(data = dat2, color = "red")  

在此处输入图像描述

这个图像对我想要的整体形状有效果,但是增加了点数,这意味着我不能再依赖与原始点的一对一关系。

通常,多边形不是对称的,并且许多多边形都有这样的内切,其中许多在特定方向上“拉”点的方法会出现偏差或方向错误。

我找不到任何选项,gBuffer也找不到其他功能rgeos来保留点的数量和基本空间关系。我不需要“完美”的缩小,如果这改变了事情,但它不应该有很大的偏差。

4

2 回答 2

3

如果您对当前缩小多边形的方式感到满意,这可能会起作用。它以此为基础获得从旧(大)点到新(小)多边形的 1:1 点映射。

library(rgeos)   # gBuffer
library(sf)
library(tidyverse)
dat <- structure(list(x = c(6, 5.98, 5.94, 5.86, 5.75, 5.62, 5.47, 5.31, 5.13, -4.87, -5.04, -5.22, -5.39, -5.55, -5.69, -5.81, -5.9, -5.96, -6, -6, -6, -5.96, -5.9, -5.81, -5.69, -5.55, -5.39, -5.22, -5.04, -3.04, -2.87, -2.69, -2.53, -2.38, -2.25, -2.14, -2.06, -2.02, -2, -2, -1.96, -1.9, -1.81, -1.69, -1.55, -1.39, -1.22, -1.04, -0.87, 1.13, 1.31, 1.47, 1.62, 1.75, 1.86, 1.94, 1.98, 2, 2, 2, 2.04, 2.1, 2.19, 2.31, 2.45, 2.61, 2.78, 2.96, 4.96, 5.13, 5.31, 5.47, 5.62, 5.75, 5.86, 5.94, 5.98, 6), y = c(5, 5.18, 5.35, 5.51, 5.66, 5.78, 5.88, 5.95, 5.99, 5.99, 6, 5.97, 5.92, 5.83, 5.72, 5.59, 5.43, 5.27, 5.09, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, -5, -1.91, -1.73, -1.57, -1.41, -1.28, -1.17, -1.08, -1.03, -1, -1.01, -1.01, -1.05, -1.12, -1.22, -1.34, -1.49, -1.65, -1.82, -2, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, 5)), row.names = c(NA, -78L), class = "data.frame")

# "shrink-wrap"
sp <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon( as.matrix(dat) )), "dat")))
sp2 <- gBuffer(sp, width = -0.5)
dat2 <- as.data.frame(sp2@polygons[[1]]@Polygons[[1]]@coords)

## New methods begin here
# change objects to type `sf`
sp_sf <- st_as_sf(sp)
sp2_sf <- st_as_sf(sp2)

dat_sf <- dat %>% st_as_sf(coords = c('x', 'y'))
dat2_sf <- dat2 %>% st_as_sf(coords = c('x', 'y'))

# The plot so far, saved for building on further down
p <- ggplot() + 
  geom_sf(data = sp_sf, color = 'blue', fill = NA) + 
  geom_sf(data = dat_sf, color = 'blue') +
  geom_sf(data = sp2_sf, color = 'red', fill = NA) + 
  geom_sf(data = dat2_sf, color = 'red')




# Using st_nearest_points original points to new small polygon
#  results in (perpendicular?) lines from old points to new small polygon
near_lines <- st_nearest_points(dat_sf, sp2_sf)

#plotted together:
p + geom_sf(data = near_lines, color = 'black')


## Zooming in on a problem area
p + geom_sf(data = near_lines, color = 'black') + 
  coord_sf(xlim = c(-3, 0), ylim = c(-2,0))


# Get only 1:1 points for shrunken polygon
# a small buffer had to be added, as some points were not showing up
# you may need to adjust the buffer, depending on your data & projection
new_points <- st_intersection(st_buffer(near_lines, .001), sp2_sf)

# All together now:
p + geom_sf(data = near_lines, color = 'black') + 
  geom_sf(data = new_points, color = 'green', size = 4) +
  coord_sf(xlim = c(-3, 0), ylim = c(-2,0))

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

于 2020-12-20T16:58:33.487 回答
2

我不知道如何使用包来完成你所要求的事情,但我已经整理了一个我认为可能会有所帮助的小例子。这种方法确实假设围绕(0, 0).

通用方法将您的笛卡尔点转换为极坐标,然后使用一些因子REDUCTION_FACTOR,您可以缩放点与原点的距离。但是,对于定义多边形凹面部分的点,您会注意到变化很小。所以我所做的是添加一个因子,该因子将更接近原点的点以不同的方式移动(根据一些任意截止值CONVEX_SHIFT_CUTOFF,它是原始多边形的极值的函数),由REDUCTION_FACTOR. CONVEX_SHIFT_CUTOFF可以通过考虑给定几何形状的点的分布来设置。

我确实不得不稍微捏造一下倍数,但我认为如果你的几何不对称的规模不是太大,你可能会为你的数据集调整它。您可能还可以做一些事情来以类似的方式或ifelse条件定位每个几何形状,以正确解释凹度的差异,但如果没有更多信息,很难说。

library(rgeos)   # gBuffer

dat <- structure(list(x = c(6, 5.98, 5.94, 5.86, 5.75, 5.62, 5.47, 5.31, 5.13, -4.87, -5.04, -5.22, -5.39, -5.55, -5.69, -5.81, -5.9, -5.96, -6, -6, -6, -5.96, -5.9, -5.81, -5.69, -5.55, -5.39, -5.22, -5.04, -3.04, -2.87, -2.69, -2.53, -2.38, -2.25, -2.14, -2.06, -2.02, -2, -2, -1.96, -1.9, -1.81, -1.69, -1.55, -1.39, -1.22, -1.04, -0.87, 1.13, 1.31, 1.47, 1.62, 1.75, 1.86, 1.94, 1.98, 2, 2, 2, 2.04, 2.1, 2.19, 2.31, 2.45, 2.61, 2.78, 2.96, 4.96, 5.13, 5.31, 5.47, 5.62, 5.75, 5.86, 5.94, 5.98, 6), y = c(5, 5.18, 5.35, 5.51, 5.66, 5.78, 5.88, 5.95, 5.99, 5.99, 6, 5.97, 5.92, 5.83, 5.72, 5.59, 5.43, 5.27, 5.09, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, -5, -1.91, -1.73, -1.57, -1.41, -1.28, -1.17, -1.08, -1.03, -1, -1.01, -1.01, -1.05, -1.12, -1.22, -1.34, -1.49, -1.65, -1.82, -2, -4.91, -5.09, -5.27, -5.43, -5.59, -5.72, -5.83, -5.92, -5.97, -6, -6, -5.99, -5.95, -5.88, -5.78, -5.66, -5.51, -5.35, -5.18, 5)), row.names = c(NA, -78L), class = "data.frame")

# "shrink-wrap"
sp <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon( as.matrix(dat) )), "dat")))
sp2 <- gBuffer(sp, width = -0.5)
dat2 <- as.data.frame(sp2@polygons[[1]]@Polygons[[1]]@coords)


REDUCTION_FACTOR <- 0.92
CONVEX_SHIFT_CUTOFF <- 0.55

x <- c()
y <- c()
max_x <- max(dat$x)
max_y <- max(dat$y)
for ( i in 1:length(dat$x)) {
  x_p <- dat$x[i]
  y_p <- dat$y[i]
  r <- sqrt(x_p^2 + y_p^2)
  theta <- atan2(y_p, x_p)
  r <- REDUCTION_FACTOR * r
  if(abs(x_p) < CONVEX_SHIFT_CUTOFF * max_x) {
    x <- c(x, r*cos(theta)*(1 + 4*(1-REDUCTION_FACTOR))  )
  } else {
    x <- c(x, r*cos(theta))
  }
  
  if(abs(y_p) < CONVEX_SHIFT_CUTOFF*max_y ) {
    y <- c(y, r*sin(theta)*(1 - 4*(1-REDUCTION_FACTOR) ))
  } else {
    y <- c(y, r*sin(theta)) 
  }
  
}

dat3 <- data.frame(x = x, y = y)

library(ggplot2) # just for vis here
ggplot(dat, aes(x, y)) +
  geom_path() + geom_point() +
  geom_path(data = dat2, color = "red") + geom_point(data = dat2, color = "red")  +
  geom_path(data = dat3, color = "blue") + geom_point(data = dat3, color = "blue")  

这种方法会产生以下缩放结果。

黑色是原始数据,红色是 gBuffer 方法,蓝色是呈现的方法

于 2020-12-19T05:02:58.683 回答