R/GIS: найдите ортогональное расстояние между местоположением и ближайшей линией

Я пытаюсь найти ортогональное расстояние между набором координат местоположения и набором линий (дорог или рек). Набор точек находится в виде пар широты/долготы, а строки находятся в шейп файле (.shp). Построение их на карте не является проблемой, используя либо maptools, либо PBSmapping. Но моя основная проблема заключается в том, чтобы найти минимальное расстояние, которое нужно проехать от места, чтобы добраться до дороги или реки. Есть ли способ сделать это в R?

Ответ 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)