如何使用R sf包从底层网格中裁剪多边形?

时间:2018-01-25 07:21:23

标签: r gis sf

我想知道是否比下面的rstats sf示例更简单,以计算底层网格中多边形shapefile的(分数)面积覆盖。到目前为止,我还没有找到一个功能,它可以为我完成这项工作。这是我的例子:

library(sf)

## create a multipolygon
p1 <- rbind(c(7, 48), c(8, 52), c(11, 49), c(9, 48), c(7, 48))
p2 <- rbind(c(8, 50), c(8, 51), c(9, 50), c(8, 50))
mpol <- st_sfc(st_multipolygon(list(list(p1, p2))), crs=st_crs(4326))

## create a half degree grid covering the multipolygon
grid <- st_make_grid(mpol, cellsize=0.5)

## Create a sf object with the required attributes
## package 'lwgeom' reqiured
area <- st_area(grid)
grid <- st_as_sf(data.frame(ID=c(1:length(area)), area=area, geometry=grid))

## check 'map' elements
plot(grid['area'])
plot(mpol, col="#FF0000AA", add=TRUE)

现在进行计算,我首先通过从边界框('bpol')中减去'mpol'来反转多边形('ipol')并计算新的覆盖区域。

## create a rectangular bounding box around the polygon
bbox <- st_bbox(mpol)
bpol <- st_sfc(st_polygon(list(rbind(c(bbox['xmin'], bbox['ymin']),
                                     c(bbox['xmax'], bbox['ymin']),
                                     c(bbox['xmax'], bbox['ymax']),
                                     c(bbox['xmin'], bbox['ymax']),
                                     c(bbox['xmin'], bbox['ymin'])))), crs=st_crs(4326))

## invert the multipolygon, by substracting it from the bounding box
ipol <- st_difference(bpol, mpol)

## substract the inverted polygon from the grid
gridinpoly <- st_difference(grid, ipol)

## calculate new 'cropped' area
gridinpoly$croppedArea = st_area(gridinpoly)
plot(gridinpoly['area'])
plot(gridinpoly['croppedArea'])

## Finally the fractional coverage is calculated:
gridinpoly$frac = gridinpoly$croppedArea / gridinpoly$area
plot(gridinpoly['frac'])

如果网格单元被覆盖两次,然后从网格中断裁剪倒置多边形,它会变得更加复杂

p3 <- rbind(c(9.75, 50.5), c(10, 51), c(10.5, 50), c(9.75, 50.5))
mpol <- st_sfc(st_multipolygon(list(list(p1, p2, p3))), crs=st_crs(4326))
ipol <- st_difference(bpol, mpol)
gridinpoly <- st_difference(grid, ipol)

错误消息:“CPL_geos_op2中的错误(op,st_geometry(x),st_geometry(y)):评估错误:TopologyException:输入geom 1无效:嵌套shell处于或接近9.75 50.5 at 9.75 50.5。”

现在我的问题是,是否有一个功能,它可以完成这项工作?我是否遗漏了文档中的内容?如何在多次裁剪网格单元时解决错误?

谢谢&amp;亲切的问候 约尔格

1 个答案:

答案 0 :(得分:2)

使用st_intersection似乎更自然/更容易。

重现和示例几乎与您的相同。唯一的区别是没有指定crs。它应该适用于任何crs但不适用于经度纬度(见下文)

library(sf)
## create a multipolygon
p1 <- rbind(c(7, 48), c(8, 52), c(11, 49), c(9, 48), c(7, 48))
p2 <- rbind(c(8, 50), c(8, 51), c(9, 50), c(8, 50))
mpol <- st_sfc(st_multipolygon(list(list(p1, p2))))

## create a half unit grid covering the multipolygon
grid <- st_make_grid(mpol, cellsize=0.5)
area <- st_area(grid)
grid <- st_as_sf(data.frame(ID=c(1:length(area)), area=area, geometry=grid))

计算多边形内网格表面的分数:

tmp <- st_intersection(grid, mpol)
tmp$area <- st_area(tmp)
tmp$frac <- tmp$area/unique(area)
plot(tmp['frac'])

# If needed, you can remove the non polygons :
tmp[tmp$area > 0,]

由于两个原因的组合,这不适用于经度纬度:

  1. 在经度纬度上使用st_area时,sf会调用另一个适用于geosphere个对象的包sp。然后,您的sf对象将动态转换为sp对象。
  2. 在您的情况下,网格和多边形的交叉结果不是多面,而是由点,线和多边形组成的复杂对象(type = Geometry)。从此类sf对象到sp的转换不起作用
  3. 但是,如果您只需要%的表面,则可能不建议在经度/纬度上测量区域,并且不需要。

    对于p3的错误消息,我不确定您要模拟的内容。如果你想要一个由p1和p3组成的多边形,在p1中有孔(p2),那么创建mpol的语法必须略有不同(并且区域计算可以正常工作):

    p3 <- rbind(c(9.75, 50.5), c(10, 51), c(10.5, 50), c(9.75, 50.5))
    mpol <- st_sfc(st_multipolygon(list(list(p1, p2), list(p3))))
    plot(mpol)
    
    tmp <- st_intersection(grid, mpol)
    tmp$area <- st_area(tmp)
    tmp$frac <- tmp$area/unique(area)
    plot(tmp['frac'])