创建一个已知区域的圆圈

Creating a Circle of Known Area

我想创建一个面积为 100 的圆作为 sf 对象。我以为 st_buffer() 会做,但面积是 略小于 100.

pt.df   <- data.frame(pt = 1, x = 20, y = 20)
pt.sf   <- st_as_sf(pt.df, coords = c("x", "y")) 
circle1 <- st_buffer(pt.sf, dist = sqrt(100 / pi))
st_area(circle1)  # 99.95431 on my PC

我可以用软糖因子乘以半径,我得到了我想要的。

fudge    <- sqrt( 100 / st_area(circle1) )
circle2  <- st_buffer(pt.sf, dist = fudge * sqrt(100 / pi))
st_area(circle2)  # 100

但使用软糖因素似乎很愚蠢。

有没有办法在 sf 包内创建一个已知区域的圆而不用 st_buffer 中的软糖因素 ?

用圆周率的截断形式计算半径是一个浮点精度问题。这将导致一个圆圈略小于您想要的输出。可以看到pi只能存储到机器精度:

.Machine$double.eps
# 2.22044604925031e-16

pi
# 3.14159265358979

如果你想修正它,你可以在你想要的区域使用线性修正。请注意,这仍然是一个近似值,但它应该让您更接近您想要的结果。

radius <- function(area){
    A <- area + (area * 0.000457099999999997)
    return(sqrt(A / pi))
}

system.file("shape/nc.shp", package="sf") %>% 
        st_read() %>% 
        st_centroid() %>% 
        st_transform(st_crs(5070)) %>% 
        st_buffer(radius(100)) %>%
        st_area()

主要问题是 st_buffer 在内部使用多边形,而不是圆形。增加 nQuadSegs 参数(默认值=30)允许您使用更好的圆近似值,以内存和计算时间为代价(不知道这对您是否重要):

library(sf)
pt.df   <- data.frame(pt = 1, x = 20, y = 20)
pt.sf   <- st_as_sf(pt.df, coords = c("x", "y")) 
get_area <- function(nq) {
  circle1 <- st_buffer(pt.sf, dist = sqrt(100 / pi), nQuadSegs=nq)
  st_area(circle1)
}
sapply(c(30,100,300,1000), get_area)
## [1] 99.95431 99.99589 99.99954 99.99996

如果你真的想要 恰好 100 的区域,那么你的问题(和@AdamTrevisan 的回答)建议的 'fudge' 是可行的方法(随着增加一百万的段数仍然只能让您到达 99.99999999997200461621 的区域)。要真正聪明,您可以使用area of an inscribed polygon的公式得出校正因子...