R-与SpatialPolygonsDataFrame对象相交的SpatialLinesDataFrame列表的嵌套循环

时间:2018-12-16 06:21:20

标签: r for-loop spatial sp rgdal

我需要根据对象与多功能SpatialLinesDataFrame(“多边形”)中各个特征之间的关系,在一系列SpatialPolygonsDataFrame(此处为“线”)对象上完成一系列步骤)对象。简而言之,每个线列表元素都起源于单个面要素,并且可能会也可能不会穿过一个或多个其他面要素。我想更新每个线元素以将原多边形连接到该线元素相交的每个单独多边形的第一接触点。因此,每个线元素可能会成为多个新的线要素(n =相交多边形的数量)。

我想有效地做到这一点,因为我的线列表和面要素很多。我在下面提供了示例数据和逐步说明。我是R语言的新手,不是程序员,所以我不知道我提出的建议是否有效。

example lines + polygons

library(sp) 
library(rgdal)
library(raster)

###example data prep START
#example 'RDCO Regional Parks' data can be downloaded here: 
https://data-rdco.opendata.arcgis.com/datasets group_ids=1950175c56c24073bb5cef3900e19460 

parks <- readOGR("/path/to/example/data/RDCO_Regional_Parks/RDCO_Regional_Parks.shp")
plot(parks)

#subset watersheds for example
parks_sub <- parks[parks@data$Shapearea > 400000,]
plot(parks_sub, col='green', axes = T)

#create SpatialLines from scratch
pts_line1 <- cbind(c(308000, 333000), c(5522000, 5530000))
line1 <- spLines(pts_line1, crs = crs(parks_sub))
plot(line1, axes=T, add=T) #origin polygon = polyl[[4]] = OBJECTID 181

pts_line2 <- cbind(c(308000, 325000), c(5524000, 5537000))
line2 <- spLines(pts_line2, crs = crs(parks_sub))
plot(line2, axes=T, add=T) #origin polygon = polyl[[8]] = OBJECTID 1838

linel <- list()
linel[[1]] <- line1
linel[[2]] <- line2

#convert to SpatialLinesDataFrame objects
lineldf <- lapply(1:length(linel), function(i) SpatialLinesDataFrame(linel[[i]], data.frame(id=rep(i, length(linel[[i]]))), match.ID = FALSE))  

#match id field value with origin polygon
lineldf[[1]]@data$id <- 181
lineldf[[2]]@data$id <- 1838
###example data prep END

#initiate nested for loop
for (i in 1:length(lineldf)) {
  for (j in 1:length(parks_sub[j,])) {

#STEP 1:for each line list feature (NB: with ID matching origin polygon ID) 
#identify whether it intersects with a polygon list feature
    if (tryCatch(!is.null(intersect(lineldf[[i]], parks_sub[j,])), error=function(e) return(FALSE)) == 'FALSE'){
     next
    }
#if 'FALSE', go on to check intersect with next polygon in list
#if 'TRUE', go to STEP 2

#STEP 2: add intersected polygon OBJECTID value to SLDF new column in attribute table
#i.e., deal with single intersected polygon at a time
    else {
      lineldf[[i]]@data["id.2"] = parks_sub[j,]@data$OBJECTID

#STEP 3: erase portion of line overlapped by intersected SPDF
      line_erase <- erase(lineldf[[i]],parks_sub[j,])

#STEP 4: erase line feature(s) that no longer intersect with the origin polygon
#DO NOT KNOW HOW TO SELECT feature (i.e., line segment) within 'line_erase' object
      if (tryCatch(!is.null(intersect(line_erase[???], parks_sub[j,])), error=function(e) return(FALSE)) == 'FALSE'){
        line_erase[???] <- NULL}
      else {

 #STEP 5: erase line features that only intersect with origin polygon
           if (line_erase[???]@data$id.2 = parks_sub[j,]@data$OBJECTID){
             line_erase[???] <- NULL
           }
              else {
 #STEP 6: write valid line files to folder
        writeOGR(line_erase, 
                 dsn = paste0("path/to/save/folder", i, ".shp"),
                 layer = "newline",
                 driver = 'ESRI Shapefile',
                 overwrite_layer = T)
      }}}}}

1 个答案:

答案 0 :(得分:1)

这是使用sf软件包的解决方案。我将使用您创建的对象并将其转换为sf,尽管您可以将shapefile读入sf对象并从头开始创建它们,所以如果没有其他理由使用sp对象我建议。

使用以下软件包:

library(sf)
library(dplyr)

转换多边形。我要从parks_sub删除一列列,以便它可以打印得更整洁-如果需要,请不要删除它们:

p = st_as_sf(parks_sub)
p = p[,c("OBJECTID","PARK_NAME")]

转换行。我将只使用您的第一行对象,在您的列表上写一个循环来完成整个设置:

l1 = st_as_sf(lineldf[[1]])

下一步是计算线和面之间的所有交点。您必须:a)将多边形转换为线串,否则,多边形和直线的交点为直线,并且b)使用{,当直线多次穿过多边形时,将“ MULTIPOINT”交点转换为一组POINT对象{1}}:

st_cast

接下来,我们需要直线的第一点。对于您在示例中创建的数据,多边形中的线端实际上是第二点,因此我将在此处进行提取。

pts = st_cast(st_cast(st_intersection(l1,
             st_cast(p,"MULTILINESTRING")
             ),"MULTIPOINT"),"POINT")

如果在您的真实数据中第一个要点,则在其中放置first_point = st_cast(l1$geom,"POINT")[2] 。如果这取决于那是另一个小问题。

现在计算从第一个点到所有相交点的距离:

[1]

所以我们现在想要的是由相同多边形ID定义的每组点中最接近的交点。

pts$d_first = st_distance(first_point, pts)[1,]

然后,从第一个点到最近的点构建所需的线:

near_pts = pts %>% group_by(OBJECTID)  %>% filter(d_first==min(d_first))

以减小的宽度绘制多边形和线条以显示重叠:

nlines = st_cast(st_union(near_pts, first_point),"LINESTRING")

enter image description here

请注意,三行包括从第一个点到多边形所处边界的一小段(白色)-如果您不希望这样做,则可以滤除距数据框最近距离的点在构造线条之前-但假定第一个点在多边形内...

plot(p$geom) plot(nlines$geom, lwd=c(10,7,4), col=c("black","grey","white"), add=TRUE) 保留线相交的多边形的属性以及线的ID:

nlines

现在将所有内容包装到一个函数中,并循环遍历您的行并完成工作!?