事实证明,高速公路仅沿方向行驶(请参见map_route 的传单地图.我会错过任何内容吗?这是一个可复制的示例:wd <- getwd()setwd("C:/OSRM_API5")shell(paste0("osrm-routed ", "switzerland-latest.osrm", " >nul 2>nul"), wait = F)Sys.sleep(3) # OSRM needs timesetwd(wd)k1 <- 46.99917k2 <- 8.610048k3 <- 47.05398k4 <- 8.530232r1 <- viaroute5_2(k1, k2, k3, k4)r1$routes[[1]]$duration# [1] 598.2geometry <- decode_geom(r1$routes[[1]]$geometry, 5)map_route(geometry)r2 <- viaroute5_2(k3, k4,k1, k2)r2$routes[[1]]$duration# [1] 1302geometry <- decode_geom(r2$routes[[1]]$geometry, 5)map_route(geometry)shell("TaskKill /F /IM osrm-routed.exe >nul 2>nul")以下是您需要的功能:viaroute5_2 <- function(lat1, lng1, lat2, lng2) { # address <- "http://localhost:5000" # this should work without a local server address <- "http://localhost:5000" request <- paste(address, "/route/v1/driving/", lng1, ",", lat1, ";", lng2, ",", lat2, "?overview=full", sep = "", NULL) R.utils::withTimeout({ repeat { res <- try( route <- rjson::fromJSON( file = request)) if (class(res) != "try-error") { if (!is.null(res)) { break } else { stop("???") } } } }, timeout = 1, onTimeout = "warning") if (res$code == "Ok") { return(res) } else { t_guess <- 16*60 warning("Route not found: ", paste(lat1, lng1, lat2, lng2, collapse = ", "), ". Time set to ", t_guess/60 , " min.") }}decode_geom <- function(encoded, precision = stop("a numeric, either 5 or 6")) { if (precision == 5) { scale <- 1e-5 } else if (precision == 6) { scale <- 1e-6 } else { stop("precision not set to 5 or 6") } len = stringr::str_length(encoded) encoded <- strsplit(encoded, NULL)[[1]] index = 1 N <- 100000 df.index <- 1 array = matrix(nrow = N, ncol = 2) lat <- dlat <- lng <- dlnt <- b <- shift <- result <- 0 while (index <= len) { shift <- result <- 0 repeat { b = as.integer(charToRaw(encoded[index])) - 63 index <- index + 1 result = bitops::bitOr(result, bitops::bitShiftL(bitops::bitAnd(b, 0x1f), shift)) shift = shift + 5 if (b < 0x20) break } dlat = ifelse(bitops::bitAnd(result, 1), -(result - (bitops::bitShiftR(result, 1))), bitops::bitShiftR(result, 1)) lat = lat + dlat; shift <- result <- b <- 0 repeat { b = as.integer(charToRaw(encoded[index])) - 63 index <- index + 1 result = bitops::bitOr(result, bitops::bitShiftL(bitops::bitAnd(b, 0x1f), shift)) shift = shift + 5 if (b < 0x20) break } dlng = ifelse(bitops::bitAnd(result, 1), -(result - (bitops::bitShiftR(result, 1))), bitops::bitShiftR(result, 1)) lng = lng + dlng array[df.index,] <- c(lat = lat * scale, lng = lng * scale) df.index <- df.index + 1 } geometry <- data.frame(array[1:df.index - 1,]) names(geometry) <- c("lat", "lng") return(geometry)}map <- function() { library(leaflet) m <- leaflet() %>% addTiles() %>% addProviderTiles(providers$OpenStreetMap, group = "OSM") %>% addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>% addLayersControl(baseGroups = c("OSM", "Toner Lite")) return(m)}map_route <- function(geometry) { # Which parameters make sence? osrm inside or outside? m <- map() m <- addCircleMarkers(map = m, lat = geometry$lat[1], lng = geometry$lng[1], color = imsbasics::fhs(), popup = paste("Source"), stroke = FALSE, radius = 6, fillOpacity = 0.8) %>% addCircleMarkers(lat = geometry$lat[nrow(geometry)], lng = geometry$lng[nrow(geometry)], color = imsbasics::fhs(), popup = paste("Destination"), stroke = FALSE, radius = 6, fillOpacity = 0.8) %>% addPolylines(lat = geometry$lat, lng = geometry$lng, color = "red", weight = 4) %>% addLayersControl(baseGroups = c("OSM", "Stamen.TonerLite")) return(m)}解决方案答案是:因为OSRM默认情况下会搜索最近的点并从该点搜索一条路线.如果您的坐标位于高速公路的稍微北边,那么OSRM只会向西行驶(考虑到您在欧洲的右侧行驶,因此我们会在欧洲行驶.).因此,在您的示例中,左上角点位于高速公路以北一点,因此,从该点进行搜索时,OSRM会走很多弯路.以下示例显示了这一点:osrmr::run_server("switzerland-latest", "C:/OSRM_API5")lat1 <- 46.99917lng1 <- 8.610048lat2 <- 47.05398lng2 <- 8.530232res1 <- osrmr::viaroute(lat1, lng1, lat2, lng2, instructions = TRUE, api_version = 5, localhost = TRUE)res2 <- osrmr::viaroute(lat2, lng2, lat1, lng1, instructions = TRUE, api_version = 5, localhost = TRUE)res1$routes[[1]]$duration# [1] 598.2res2$routes[[1]]$duration# [1] 1302map_route(decode_geom(res1$routes[[1]]$geometry, 5))map_route(decode_geom(res2$routes[[1]]$geometry, 5))lat1 <- 46.99917lng1 <- 8.610048lat2 <- 47.051 # setting that point a bit more south changes the results to the opposite..lng2 <- 8.530232res1 <- osrmr::viaroute(lat1, lng1, lat2, lng2, instructions = TRUE, api_version = 5, localhost = TRUE)res2 <- osrmr::viaroute(lat2, lng2, lat1, lng1, instructions = TRUE, api_version = 5, localhost = TRUE)res1$routes[[1]]$duration# [1] 1307.5res2$routes[[1]]$duration# [1] 592.7map_route(decode_geom(res1$routes[[1]]$geometry, 5))map_route(decode_geom(res2$routes[[1]]$geometry, 5))osrmr::quit_server()如您所见,将第二点设置在更南的位置会反转结果.现在,另一种方法花费的时间要长得多.例如在此处中讨论的 radiuses选项可能提供解决该问题的方法.但是,我不知道该如何将其用于您的示例.或者也许(更简单..)您想计算两个方向并采用较短的duration?什么才是最好的取决于您的算法问题.As said: it even differs by a factor of 2 in time! How is that possible?I found this issue but it seems it is still there?It turns out that the highway is only taken in on direction (See leaflet map from map_route. Do I miss anything?Here is a reproducible example:wd <- getwd()setwd("C:/OSRM_API5")shell(paste0("osrm-routed ", "switzerland-latest.osrm", " >nul 2>nul"), wait = F)Sys.sleep(3) # OSRM needs timesetwd(wd)k1 <- 46.99917k2 <- 8.610048k3 <- 47.05398k4 <- 8.530232r1 <- viaroute5_2(k1, k2, k3, k4)r1$routes[[1]]$duration# [1] 598.2geometry <- decode_geom(r1$routes[[1]]$geometry, 5)map_route(geometry)r2 <- viaroute5_2(k3, k4,k1, k2)r2$routes[[1]]$duration# [1] 1302geometry <- decode_geom(r2$routes[[1]]$geometry, 5)map_route(geometry)shell("TaskKill /F /IM osrm-routed.exe >nul 2>nul")Here are the functions you need:viaroute5_2 <- function(lat1, lng1, lat2, lng2) { # address <- "http://localhost:5000" # this should work without a local server address <- "http://localhost:5000" request <- paste(address, "/route/v1/driving/", lng1, ",", lat1, ";", lng2, ",", lat2, "?overview=full", sep = "", NULL) R.utils::withTimeout({ repeat { res <- try( route <- rjson::fromJSON( file = request)) if (class(res) != "try-error") { if (!is.null(res)) { break } else { stop("???") } } } }, timeout = 1, onTimeout = "warning") if (res$code == "Ok") { return(res) } else { t_guess <- 16*60 warning("Route not found: ", paste(lat1, lng1, lat2, lng2, collapse = ", "), ". Time set to ", t_guess/60 , " min.") }}decode_geom <- function(encoded, precision = stop("a numeric, either 5 or 6")) { if (precision == 5) { scale <- 1e-5 } else if (precision == 6) { scale <- 1e-6 } else { stop("precision not set to 5 or 6") } len = stringr::str_length(encoded) encoded <- strsplit(encoded, NULL)[[1]] index = 1 N <- 100000 df.index <- 1 array = matrix(nrow = N, ncol = 2) lat <- dlat <- lng <- dlnt <- b <- shift <- result <- 0 while (index <= len) { shift <- result <- 0 repeat { b = as.integer(charToRaw(encoded[index])) - 63 index <- index + 1 result = bitops::bitOr(result, bitops::bitShiftL(bitops::bitAnd(b, 0x1f), shift)) shift = shift + 5 if (b < 0x20) break } dlat = ifelse(bitops::bitAnd(result, 1), -(result - (bitops::bitShiftR(result, 1))), bitops::bitShiftR(result, 1)) lat = lat + dlat; shift <- result <- b <- 0 repeat { b = as.integer(charToRaw(encoded[index])) - 63 index <- index + 1 result = bitops::bitOr(result, bitops::bitShiftL(bitops::bitAnd(b, 0x1f), shift)) shift = shift + 5 if (b < 0x20) break } dlng = ifelse(bitops::bitAnd(result, 1), -(result - (bitops::bitShiftR(result, 1))), bitops::bitShiftR(result, 1)) lng = lng + dlng array[df.index,] <- c(lat = lat * scale, lng = lng * scale) df.index <- df.index + 1 } geometry <- data.frame(array[1:df.index - 1,]) names(geometry) <- c("lat", "lng") return(geometry)}map <- function() { library(leaflet) m <- leaflet() %>% addTiles() %>% addProviderTiles(providers$OpenStreetMap, group = "OSM") %>% addProviderTiles(providers$Stamen.TonerLite, group = "Toner Lite") %>% addLayersControl(baseGroups = c("OSM", "Toner Lite")) return(m)}map_route <- function(geometry) { # Which parameters make sence? osrm inside or outside? m <- map() m <- addCircleMarkers(map = m, lat = geometry$lat[1], lng = geometry$lng[1], color = imsbasics::fhs(), popup = paste("Source"), stroke = FALSE, radius = 6, fillOpacity = 0.8) %>% addCircleMarkers(lat = geometry$lat[nrow(geometry)], lng = geometry$lng[nrow(geometry)], color = imsbasics::fhs(), popup = paste("Destination"), stroke = FALSE, radius = 6, fillOpacity = 0.8) %>% addPolylines(lat = geometry$lat, lng = geometry$lng, color = "red", weight = 4) %>% addLayersControl(baseGroups = c("OSM", "Stamen.TonerLite")) return(m)} 解决方案 The answer is: Because OSRM searches by default a nearest point and searches one route from that point. If your coordinates are slightly north a highway, OSRM will only drive westbound (considering you're drive on the right side as we do in Europe..).So in your example the point upleft is just a bit north of the highway and therefore when searching from that point OSRM takes quite a bit of a detour.The following example shows this:osrmr::run_server("switzerland-latest", "C:/OSRM_API5")lat1 <- 46.99917lng1 <- 8.610048lat2 <- 47.05398lng2 <- 8.530232res1 <- osrmr::viaroute(lat1, lng1, lat2, lng2, instructions = TRUE, api_version = 5, localhost = TRUE)res2 <- osrmr::viaroute(lat2, lng2, lat1, lng1, instructions = TRUE, api_version = 5, localhost = TRUE)res1$routes[[1]]$duration# [1] 598.2res2$routes[[1]]$duration# [1] 1302map_route(decode_geom(res1$routes[[1]]$geometry, 5))map_route(decode_geom(res2$routes[[1]]$geometry, 5))lat1 <- 46.99917lng1 <- 8.610048lat2 <- 47.051 # setting that point a bit more south changes the results to the opposite..lng2 <- 8.530232res1 <- osrmr::viaroute(lat1, lng1, lat2, lng2, instructions = TRUE, api_version = 5, localhost = TRUE)res2 <- osrmr::viaroute(lat2, lng2, lat1, lng1, instructions = TRUE, api_version = 5, localhost = TRUE)res1$routes[[1]]$duration# [1] 1307.5res2$routes[[1]]$duration# [1] 592.7map_route(decode_geom(res1$routes[[1]]$geometry, 5))map_route(decode_geom(res2$routes[[1]]$geometry, 5))osrmr::quit_server()As you can see, setting the second point a bit more south inverts the results. Now the other way takes quite a bit longer.As discussed for example here the radiuses option might provide a solution to that problem. I couldn't however figure out to get that to work on your example..Or maybe (simpler..) you want to calculate both directions and take the shorter duration?What's best really depends on your algorithmic problem.. 这篇关于OSRM:为什么路线A的行驶时间-> B偏离路线的行进时间为2倍B->一种?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!