Я пытаюсь найти ортогональное расстояние между набором координат местоположения и набором линий (дорог или рек). Набор точек находится в виде пар широты/долготы, а строки находятся в шейп файле (.shp). Построение их на карте не является проблемой, используя либо maptools
, либо PBSmapping
. Но моя основная проблема заключается в том, чтобы найти минимальное расстояние, которое нужно проехать от места, чтобы добраться до дороги или реки. Есть ли способ сделать это в R?
R/GIS: найдите ортогональное расстояние между местоположением и ближайшей линией
Ответ 1
Если я правильно понимаю, вы можете сделать это достаточно просто с помощью 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([email protected], function(x1) do.call("rbind", lapply([email protected], function(x2) [email protected][-nrow([email protected]), ]))))
Проверьте это в интерактивном режиме, вам придется изменить это, чтобы сохранить координаты или минимальные расстояния. Это будет строить линии и ждать, пока вы нажмете в любом месте сюжета, затем он нарисует линию от вашего клика до ближайшей вершины на линии.
## 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)
}
Ответ 2
В пакете geosphere
есть функция dist2line, которая делает это для данных lon/lat. Он может использовать объекты 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)