R/GIS: 寻找位置与最近线之间的直角距离

14

我想要找出一组位置坐标与一组线路(道路或河流)之间的正交距离。这些点是由纬度/经度对表示的,而线路则在一个形状文件 (.shp) 中。使用maptoolsPBSmapping 在地图上绘制它们不是问题。但我的基本问题是找到从一个位置到达道路或河流所需的最小距离。有没有办法在 R 中实现这个功能?

3个回答

22

如果我理解正确,你可以简单地使用 rgeos 包中的 gDistance 来完成这个问题。

将线读入为 SpatialLines/DataFrame ,将点读入为 SpatialPoints/DataFrame ,然后循环遍历每个点,每次计算距离:

require(rgeos)
## untested code
shortest.dists <- numeric(nrow(sp.pts))
for (i in seq_len(nrow(sp.pts)) {
    shortest.dists[i] <- gDistance(sp.pts[i,], sp.lns)
}

这里sp.pts是空间点对象,sp.lns是空间线对象。

你必须循环遍历才能将sp.pts中的单个坐标与sp.lns中所有几何图形进行比较,否则会得到跨越所有点的聚合值距离。

由于数据在纬度/经度中,因此应将线和点都转换为适当的投影方式,因为gDistance函数假定笛卡尔距离。

更多讨论和示例(编辑)

获得线上最近点而不仅仅是距离是一个好主意,但这打开了另一个选项,即您是否需要沿线获取最近的 坐标 ,还是一个实际的交点与比任何现有顶点更接近的线段。如果您的顶点足够密集,差异并不重要,则可以在 sp 包中使用 spDistsN1 。您必须从集合中提取所有线中的所有坐标(不难,但有点丑),然后循环遍历每个感兴趣的点计算到线顶点的距离-然后您可以找到哪个是最短的,并从顶点集合中选择该坐标,因此可以轻松获得距离和坐标。无需进行投影,因为函数可以使用longlat = TRUE参数进行椭球面距离计算。

library(maptools)

## simple global data set, which we coerce to Lines
data(wrld_simpl)

wrld_lines <- as(wrld_simpl, "SpatialLinesDataFrame")

## get every coordinate as a simple matrix (scary but quick)
wrld_coords <- do.call("rbind", lapply(wrld_lines@lines, function(x1) do.call("rbind", lapply(x1@Lines, function(x2) x2@coords[-nrow(x2@coords), ]))))

交互式检查一下,您需要修改此内容以保存坐标或最小距离。这将绘制出线条并等待您在图中的任何位置单击,然后它会从您的单击位置到最近的线上顶点绘制一条线。

## no out of bounds clicking . . .
par(mar = c(0, 0, 0, 0), xaxs = "i", yaxs = "i") 

plot(wrld_lines, asp = "")

n <- 5

for (i in seq_len(n)) {
xy <- matrix(unlist(locator(1)), ncol = 2)
    all.dists <- spDistsN1(wrld_coords, xy, longlat = TRUE)
    min.index <- which.min(all.dists)
    points(xy, pch = "X")
lines(rbind(xy, wrld_coords[min.index, , drop = FALSE]), col = "green", lwd = 2)
}

很好的且富有信息量的回答。谢谢你。看起来 rgeos 没有任何返回最近位置的函数。你是否有建议可以提供一个这样的函数?似乎 spatstat 中的 project2segment() 可以实现此功能,但不幸的是它不使用 sp 类对象,这将会更方便... - Josh O'Brien
我会更新,我再想一下,有几个微妙之处。 - mdsumner
在你的“更多讨论”部分有一个很棒的演示。我希望每个对此感兴趣的人都能花一分钟运行那段代码。另外,感谢指向maptools包中完整套件的sp -> spatstat -> sp转换工具。 - Josh O'Brien
@mdsumner 很棒的回答。taRifx.geo有SLDFtoLine函数可以将SpatialLines简化为矩阵,还有interpolatePathpoints函数可以在顶点之间添加点以提高线条的点密度。 - Ari B. Friedman
@AriB.Friedman:“‘taRifx.geo’软件包已从CRAN存储库中删除” - Rodrigo
显示剩余2条评论

4

geosphere包中有dist2line函数可以计算经纬度数据到直线的距离。它可以使用Spatial*对象或矩阵。

line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60))
pnts <- rbind(c(-170,0), c(-75,0), c(-70,-10), c(-80,20), c(-100,-50), 
         c(-100,-60), c(-100,-40), c(-100,-20), c(-100,-10), c(-100,0))
d <- dist2Line(pnts, line)
d 

结果的说明

plot( makeLine(line), type='l')
points(line)
points(pnts, col='blue', pch=20)
points(d[,2], d[,3], col='red', pch='x')
for (i in 1:nrow(d)) lines(gcIntermediate(pnts[i,], d[i,2:3], 10), lwd=2)

1

看起来可以使用sf包中的st_distance函数来完成此操作。

将两个sf对象传递给该函数。与其他解决方案一样,您需要迭代遍历您的点,以便函数计算每个点到道路上每个点之间的距离。然后从结果向量中取最小值即为最短距离。

# Solution for one point
min(st_distance(roads_sf, points_sf[1, ]))

# Iterate over all points using sapply
sapply(1:nrow(points_sf), function(x) min(st_distance(roads_sf, points_sf[x, ])))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接