我想要找出一组位置坐标与一组线路(道路或河流)之间的正交距离。这些点是由纬度/经度对表示的,而线路则在一个形状文件 (.shp) 中。使用maptools
或 PBSmapping
在地图上绘制它们不是问题。但我的基本问题是找到从一个位置到达道路或河流所需的最小距离。有没有办法在 R 中实现这个功能?
如果我理解正确,你可以简单地使用 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)
}
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)
看起来可以使用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, ])))
rgeos
没有任何返回最近位置的函数。你是否有建议可以提供一个这样的函数?似乎spatstat
中的project2segment()
可以实现此功能,但不幸的是它不使用sp
类对象,这将会更方便... - Josh O'Brienmaptools
包中完整套件的sp -> spatstat -> sp
转换工具。 - Josh O'BrienSLDFtoLine
函数可以将SpatialLines简化为矩阵,还有interpolatePathpoints
函数可以在顶点之间添加点以提高线条的点密度。 - Ari B. Friedman