简体   繁体   English

R/GIS:查找位置和最近线之间的正交距离

[英]R/GIS: Find orthogonal distance between a location and nearest line

I am trying to find the orthogonal distance between a set of location coordinates and a set of lines (roads or rivers).我试图找到一组位置坐标和一组线(道路或河流)之间的正交距离。 The set of points are in the form of latitude/longitude pairs, and the lines are in a shapefile (.shp).点集采用纬度/经度对的形式,线位于 shapefile (.shp) 中。 Plotting them on a map is not a problem, using either maptools or PBSmapping .使用maptoolsPBSmapping在地图上绘制它们不是问题。 But my basic problem is to find the minimum distance one has to travel from a location to reach a road or a river.但我的基本问题是找到一个人从一个地点到达道路或河流的最小距离。 Is there any way to do this in R?有没有办法在R中做到这一点?

If I understand correctly, you can do this simply enough with gDistance in the rgeos package.如果我理解正确的话,你可以这样做只是足以与gDistancergeos包。

Read in the lines as SpatialLines/DataFrame and points as SpatialPoints/DataFrame and then loop over each point calculating the distance each time:将行读取为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)
}

Here sp.pts is the Spatial points object, and sp.lns is the Spatial lines object.这里sp.pts是空间点对象, sp.lns是空间线对象。

You must loop so that you only compare a single coordinate in sp.pts with the entirety of all lines geometries in sp.lns , otherwise you get the distance from an aggregate value across all points.您必须循环,以便仅将sp.pts的单个坐标与sp.pts中所有线几何的整体进行sp.lns ,否则您将获得与所有点的聚合值的距离。

Since your data are in latitude/longitude you should transform both the lines and points to a suitable projection since the gDistance function assumes Cartesian distance.由于您的数据位于纬度/经度,您应该将线和点都转换为合适的投影,因为gDistance函数假定笛卡尔距离。

MORE DISCUSSION AND EXAMPLE (edit)更多讨论和示例(编辑)

It would be neat to get the nearest point on the line/s rather than just the distance, but this opens another option which is whether you need the nearest coordinate along a line, or an actual intersection with a line segment that is closer than any existing vertex.获得直线上最近的点而不仅仅是距离会很整洁,但这会打开另一个选项,即您是否需要沿直线最近的坐标,或者与比任何线段都更近的线段的实际交点现有顶点。 If your vertices are dense enough that the difference doesn't matter, then use spDistsN1 in the sp package.如果您的顶点足够密集以至于差异无关紧要,则在sp包中使用spDistsN1 You'd have to extract all the coordinates from every line in the set (not hard, but a bit ugly) and then loop over each point of interest calculating the distance to the line vertices - then you can find which is the shortest and select that coordinate from the set of vertices, so you can have the distance and the coordinate easily.您必须从集合中的每一行中提取所有坐标(不难,但有点难看),然后循环遍历每个兴趣点,计算到线顶点的距离 - 然后您可以找到最短的并选择该坐标来自一组顶点,因此您可以轻松获得距离和坐标。 There's no need to project either since the function can use ellipsoidal distances with longlat = TRUE argument.也不需要投影,因为该函数可以使用带有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), ]))))

Check it out interactively, you'll have to modify this to save the coords or minimum distances.以交互方式检查它,您必须修改它以保存坐标或最小距离。 This will plot up the lines and wait for you to click anywhere in the plot, then it will draw a line from your click to the nearest vertex on a line.这将绘制线条并等待您单击图中的任意位置,然后它将从您的单击绘制一条线到一条线上最近的顶点

## 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)
}

The geosphere package has the dist2line function that does this for lon/lat data.geosphere封装具有dist2line功能,这是否为经度/纬度数据。 It can use Spatial* objects or matrices.它可以使用 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 

Illustration of the results结果说明

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)

Looks like this can be done in the sf package using the st_distance function.看起来这可以在sf包中使用st_distance函数完成。

You pass your two sf objects to the function.您将两个sf对象传递给该函数。 Same issue as with the other solutions in that you need to iterate over your points so that the function calculates the distance between every point to every point on the roadways.与其他解决方案相同的问题是,您需要迭代您的点,以便该函数计算每个点到道路上每个点之间的距离。 Then take the minimum of the resulting vector for the shortest distance.然后取最短距离的结果向量的最小值。

# 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, ])))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM