R:计算两个地理点之间的距离

sta*_*oob 3 r geospatial shapefile

我有兴趣学习如何在 R 中使用道路网络文件。

例如,我有兴趣找出以下两个(加拿大)地址之间的驾驶距离:

  • 加拿大国家电视塔:290 Bremner Blvd, Toronto, ON M5V 3L9
  • 多伦多机场:6301 Silver Dart Dr, Mississauga, ON L5P 1B2

过去,我会使用 OpenStreetMap (OSM) 等 API:

library(tmap)


library(tmaptools)
remotes::install_github("riatelab/osrm")

q1 = geocode_OSM("6301 Silver Dart Dr, Mississauga, ON L5P 1B2")
q2 = geocode_OSM("290 Bremner Blvd, Toronto, ON M5V 3L9")

q1 = as.numeric(q1$coords)
q2 = as.numeric(q2$coords)

q1_lat = q1[1]
q1_long = q1[2]
q2_lat = q2[1]
q2_long = q2[2]

route = osrmRoute(src = c(q1[1], q1[2]) ,  dst = c(q2[1], q2[2]), osrm.profile = "car")

> route$distance
[1] 26.2836
Run Code Online (Sandbox Code Playgroud)

正如我们在这里看到的,这两点之间的行驶距离是 26.2 KM(这与从 Google 地图获得的距离非常接近)

我的问题:我现在想尝试使用道路网络文件做类似的事情。

例如,我发现以下文件包含有关道路网络的信息(https://www12.statcan.gc.ca/census-recensement/2021/geo/sip-pis/rnf-frr/index2021-eng.cfm?年=21)。然后我以 .shp 格式(即 shapefile)将其下载到我的计算机上。

基于这样一份路网文件,是否可以找出任意两个地址之间的“行驶距离”(无论是“语言地址”还是地理坐标)?

谢谢!

注意:此文件似乎相当大,我不确定我的计算机是否可以完全加载它 - 是否可以命令计算机仅导入此文件的较小部分?(例如,导入省份=安大略省,导入城市=多伦多)

Sam*_*amR 7

是的,您可以下载地图并根据这些文件中有关道路网络的信息计算距离。您已经在使用osrmR 包。这会将请求发送到远程演示服务器,该服务器正是这样做的。然而,包文档指出,

OSRM 演示服务器不允许大型查询(超过 10000 个距离或持续时间)。

相反,您可以安装osrm-backend一个用 C++ 编写的高性能路由引擎。这将允许您根据您提供的地图设置自己的路由服务器。然后,您可以从 R 内部向本地服务器发出与上述相同的请求,没有速率限制。

安装 osrm-backend 并构建地图

您可能是正确的,您无法在标准 PC 上轻松构建整个加拿大地图。如果您设置了交换文件,您也许可以,但可能需要很长时间(几小时到几天)。我使用了较小的地图,即由 geofabrik 托管的安大略省开放街道地图数据。您可以在这里下载其他地区的。

最简单的方法是使用 OSRM docker 镜像安装docker后,以下命令将下载安大略数据和 docker 镜像,并启动服务器。以下内容将在终端中输入,而不是在 R 中输入。这应该适用于 Windows(在 PowerShell 中)、Mac 或 Linux。

# Download the map - may take about 15 mins - from https://download.geofabrik.de/north-america/canada/ontario.html
wget -O ontario-latest.osm.pbf https://download.geofabrik.de/north-america/canada/ontario-latest.osm.pbf

# May take 5-10 mins to download the Docker image the first time
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/ontario-latest.osm.pbf || "osrm-extract failed"
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-partition /data/ontario-latest.osm.pbf || "osrm-partition failed"
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-customize /data/ontario-latest.osm.pbf || "osrm-customize failed"

# Run the image
docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld /data/ontario-latest.osrm
Run Code Online (Sandbox Code Playgroud)

这将在端口 5000 上启动路由引擎 HTTP 服务器。您应该看到类似以下内容的输出:

[2023-03-27T18:04:02.703986704] [info] starting up engines, v5.27.1
[2023-03-27T18:04:02.704179704] [info] Threads: 8
[2023-03-27T18:04:02.704216504] [info] IP address: 0.0.0.0
[2023-03-27T18:04:02.704250504] [info] IP port: 5000
[2023-03-27T18:04:07.973464309] [info] http 1.1 compression handled by zlib version 1.2.11
[2023-03-27T18:04:07.973828509] [info] Listening on: 0.0.0.0:5000
[2023-03-27T18:04:07.973957909] [info] running and waiting for requests
Run Code Online (Sandbox Code Playgroud)

然后您可以从 R 查询。

从 R 查询服务器

重要的是将您的主机设置osrm.server为本地主机:

library(osrm)
options("osrm.server" = "http://127.0.0.1:5000/")
options("osrm.profile" = "car") # Easiest to set this here as well
Run Code Online (Sandbox Code Playgroud)

使用您问题中的示例坐标,我们可以这样做:

osrmRoute(src = src, dst = dst)
# Simple feature collection with 1 feature and 4 fields
# Geometry type: LINESTRING
# Dimension:     XY
# Bounding box:  xmin: -79.6122 ymin: 43.61352 xmax: -79.38643 ymax: 43.68883
# Geodetic CRS:  WGS 84
#     src dst duration distance                       geometry
# 1_1   1   1 23.25667  26.2836 LINESTRING (-79.61214 43.68...
Run Code Online (Sandbox Code Playgroud)

对于多个坐标,您还可以使用osrmTable()

[2023-03-27T18:04:02.703986704] [info] starting up engines, v5.27.1
[2023-03-27T18:04:02.704179704] [info] Threads: 8
[2023-03-27T18:04:02.704216504] [info] IP address: 0.0.0.0
[2023-03-27T18:04:02.704250504] [info] IP port: 5000
[2023-03-27T18:04:07.973464309] [info] http 1.1 compression handled by zlib version 1.2.11
[2023-03-27T18:04:07.973828509] [info] Listening on: 0.0.0.0:5000
[2023-03-27T18:04:07.973957909] [info] running and waiting for requests
Run Code Online (Sandbox Code Playgroud)

一旦你停止了 osrm 服务器 Docker 容器,你只需要最后一行就可以再次运行它,即

docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld /data/ontario-latest.osrm
Run Code Online (Sandbox Code Playgroud)

如果你有大量的坐标对,你可能会碰到这个max-table-size参数。您可以通过将其作为参数传递给 来增加此值docker run,例如:

docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld --max-table-size 100000 /data/ontario-latest.osrm
Run Code Online (Sandbox Code Playgroud)

您问题的第二部分是关于将地址反向地理编码为纬度/经度。这是一个完全不同的问题,我不会在这里尝试回答它。然而,好消息是 Nominatim 有一个docker镜像,它是在后台查询的(同样有速率限制)tmaptools::geocode_OSM()您可以以类似的方式安装它 - 如果遇到问题,请询问另一个问题。