R-对于具有多边形的空间线,使用raster :: inters相交的结果不正确

时间:2019-04-04 18:07:37

标签: r geospatial r-raster sp

我需要一次测试(即TRUE / FALSE)一对,SpatialLinesDataFrame元素是否与SpatialPolygonsDataFrame元素相交。如果为TRUE,则删除每个多边形中与每条线相交的部分(一次每条),然后保存到新列表中。

多边形存储在多功能SpatialPolygonsDataFrame中,线存储在单个SpatialLinesDataFrames的列表中。我创建了一个嵌套循环来遍历每个多边形和线元素。我正在使用raster::intersectraster::extentraster::erase函数。

library(sp)
library(raster)

#create  multi-feature SpatialPolygonDataFrame
p <- 
SpatialPolygons(list(Polygons(list(Polygon(cbind(c(2,4,3,2),c(2,2,4,2)))), 
"1"),

Polygons(list(Polygon(cbind(c(12,14,13,12),c(0,0,2,0)))), "2"),

Polygons(list(Polygon(cbind(c(25,24,22,25),c(22,23,22,22)))), "3"),

Polygons(list(Polygon(cbind(c(0,2,1,0),c(12,12,14,12)))), "4"),

Polygons(list(Polygon(cbind(c(5,7,6,5),c(5,5,7,5)))), "5"))) 
# Create a dataframe and display default rownames
p.df <- data.frame( ID=1:length(p)) 
rownames(p.df)
# Extract polygon ID's
pid <- sapply(slot(p, "polygons"), function(x) slot(x, "ID")) 
# Create dataframe with correct rownames
p.df <- data.frame( ID=1:length(p), row.names = pid)   
# coersion 
p <- SpatialPolygonsDataFrame(p, p.df)

#create list of single-feature SpatialLineDataFrame
l1 <- cbind(c(0,3), c(0,3))
l2 <- cbind(c(0, 13), c(0, 1))
l3 <- cbind(c(0, 24), c(0,22.5))
l4 <- cbind(c(0, 1), c(0,13))
l5 <- cbind(c(0, 6), c(0,6))

Sl1 <- Line(l1)
Sl2 <- Line(l2)
Sl3 <- Line(l3)
Sl4 <- Line(l4)
Sl5 <- Line(l5)

Sl1 <- Lines(list(Sl1), ID = "1")
Sl2 <- Lines(list(Sl2), ID = "2")
Sl3 <- Lines(list(Sl3), ID = "3")
Sl4 <- Lines(list(Sl4), ID = "4")
Sl5 <- Lines(list(Sl5), ID = "5")

Sl <- SpatialLines(list(Sl1, Sl2, Sl3, Sl4, Sl5))

# Create a dataframe and display default rownames
Sl.df <- data.frame( ID=1:length(Sl)) 
rownames(Sl.df)
# Extract polygon ID's
pidl <- sapply(slot(Sl, "lines"), function(x) slot(x, "ID")) 
# Create dataframe with correct rownames
Sl.df <- data.frame( ID=1:length(Sl), row.names = pidl)   
# coersion 
Sldf <- SpatialLinesDataFrame(Sl, Sl.df)

#convert multipart SpatialLineDataFrame feature to individual features in 
list
linel <- list()
linel[[1]] <- Sldf[1,]
linel[[2]] <- Sldf[2,]
linel[[3]] <- Sldf[3,]
linel[[4]] <- Sldf[4,]
linel[[5]] <- Sldf[5,]

#if a line intersects with a polygon, erase part of line where polygon 
#overlaps, save to new list, and add original line ID + ID of intersected 
#polygon
list1 <- list()
index=0
for (i in 1:length(linel)) {  
  for (j in 1:length(p)) {
    if (!is.null(raster::intersect(extent(p[j,]), linel[[i]]))) {
      index=index+1
      list1[[index]] <- erase(linel[[i]],p[j,])
      list1[[index]]@data["id.parent"] <- linel[[i]]@data$ID
      #add intersected polygon ID to the line attribute table 
      list1[[index]]@data["id.intersect"] <- p[j,]@data$ID
    }}}
list1

#check results by plotting
plot(p)
plot(list1[[1]], add=T) #parent 1-1
plot(list1[[2]], add=T) #parent 2-2
plot(list1[[3]], add=T) #parent-intersect 3-1
plot(list1[[4]], add=T) #??? p-i 3-2 BUT DOES NOT INTERSECT WITH p[2,]!
plot(list1[[5]], add=T) #parent 3-3
plot(list1[[6]], add=T) #???? p-i 3-4 BUT DOES NOT INTERSECT WITH p[4,]!
plot(list1[[7]], add=T) #p-i 3-5
plot(list1[[8]], add=T) #parent 4-4
plot(list1[[9]], add=T) #p-i 5-1
plot(list1[[10]], add=T) #parent 5-5

#test raster::intersect function on linel[[3]] based on plotted errors 
#above:
!is.null(raster::intersect(extent(p[1,]), linel[[3]])) 
#output = 'TRUE' (correct)
!is.null(raster::intersect(extent(p[2,]), linel[[3]])) 
#output = 'TRUE' (INCORRECT)
!is.null(raster::intersect(extent(p[3,]), linel[[3]])) 
#output = 'TRUE' (correct)
!is.null(raster::intersect(extent(p[4,]), linel[[3]])) 
#output = 'TRUE' (INCORRECT)
!is.null(raster::intersect(extent(p[5,]), linel[[3]])) 
#output = 'TRUE' (correct)

大多数结果与预期的一样,但是一些raster::intersect布尔结果不正确;也就是说,他们说多边形与线不相交。为什么会这样?

1 个答案:

答案 0 :(得分:1)

这是创建这些对象的简化方法

library(raster)
p1 <- cbind(c(2,4,3,2),c(2,2,4,2))
p2 <- cbind(c(12,14,13,12),c(0,0,2,0))
p3 <- cbind(c(25,24,22,25),c(22,23,22,22))
p4 <- cbind(c(0,2,1,0),c(12,12,14,12))
p5 <- cbind(c(5,7,6,5),c(5,5,7,5)) 
p <- spPolygons(p1, p2, p3, p4, p5, attr=data.frame(polID=1:5))

#create list of single-feature SpatialLineDataFrame
l1 <- cbind(c(0,3), c(0,3))
l2 <- cbind(c(0, 13), c(0, 1))
l3 <- cbind(c(0, 24), c(0,22.5))
l4 <- cbind(c(0, 1), c(0,13))
l5 <- cbind(c(0, 6), c(0,6))
Sldf <- spLines(l1, l2, l3, l4, l5, attr=data.frame(lineID=1:5))

#linel <- lapply(1:5, function(i) Sldf[i,])

为什么不一步一步做到这一点?

x <- intersect(Sldf, p)
plot(x)

data.frame(x)
#  lineID polID
#1      1     1
#2      2     2
#3      3     1
#4      3     3
#5      3     5
#6      4     4
#7      5     1
#8      5     5

您可以获得类似的结果:

result <- list()
index <- 1
for (i in 1:length(Sldf)) {  
   for (j in 1:length(p)) {
     if (is.null(raster::intersect(extent(p[j,]), extent(Sldf[i, ])))) next
     #if (is.null(raster::intersect(p[j,], Sldf[i, ]))) next
     if (!rgeos::gIntersects(p[j,], Sldf[i, ])) next
     e <- erase(Sldf[i,], p[j,])
     e$polID <-  p[j,]$polID
     result[[index]] <- e 
     index <- index + 1
}}

t(sapply(result, data.frame))
#     lineID polID
#[1,] 1      1    
#[2,] 2      2    
#[3,] 3      1    
#[4,] 3      3    
#[5,] 3      5    
#[6,] 4      4    
#[7,] 5      1    
#[8,] 5      5    

请注意,与您的代码的不同之处在于,您无需检查多边形是否与直线相交。您仅检查它是否与直线范围相交。可以快速检查一下,但不足以满足您的目的。