我试图找到一组位置坐标和一组线条(道路或河流)之间的正交距离。这组点是经纬度对的形式,而线是在一个shapefile(.shp)中。将它们绘制在地图上是没有问题的,使用以下两种方法之一 maptools
或 PBSmapping
. 但我的基本问题是要找到一个人从一个地点到一条路或一条河的最小距离。在R中有什么方法可以做到这一点吗?
如果我的理解正确的话,你可以简单地用以下方法来完成这个任务 gDistance
在 rgeos
包。
读作 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
函数假设笛卡尔距离。
更多讨论和示例(编辑)。
这将是整洁的线上最近的点,而不仅仅是距离,但这打开了另一个选项,这是你是否需要最近的点。统筹 沿线 交叉点 的线段比任何现有顶点更近。如果您的顶点足够密集,以至于差别并不重要,那么使用 spDistsN1
在 sp
包中的所有坐标。你必须从集合中的每条线提取所有坐标(不难,但有点丑),然后在每个兴趣点上循环计算与线顶点的距离--然后你可以找到哪个是最短的,并从顶点集合中选择该坐标,这样你就可以很容易地得到距离和坐标。也不需要投影,因为该函数可以使用椭圆距离与 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)
}
的 geosphere
软件包中的 dist2line 函数可以对 lonlat 数据进行处理。它可以使用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)
看来这可以在 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, ])))