Getting driving distance between two points (lat, lon) using R and Google Map API

孤人 提交于 2019-12-02 15:59:06
Thomas

You need RCurl or an equivalent here.

library(XML)
library(bitops)
library(RCurl)
latlon2ft <- function(origin,destination){
  xml.url <- paste0('http://maps.googleapis.com/maps/api/distancematrix/xml?origins=',origin,'&destinations=',destination,'&mode=driving&sensor=false')
  xmlfile <- xmlParse(getURL(xml.url))
  dist <- xmlValue(xmlChildren(xpathApply(xmlfile,"//distance")[[1]])$value)
  distance <- as.numeric(sub(" km","",dist))
  ft <- distance*3.28084 # FROM METER TO FEET
  return(ft)
}

latlon2ft(origin='37.193489,-121.07395',destination='37.151616,-121.046586')

Result:

[1] 17224.41
rodazuero

I authored the gmapsdistance package to do just that. It is available on CRAN. You can use the function in the following way:

results = gmapsdistance(origin = "38.1621328+24.0029257",
                        destination = "37.9908372+23.7383394",
                        mode = "walking") results
# $Time
# [1] 30025
# 
# $Distance
# [1] 39507
# 
# $Status
# [1] "OK"

You can also include vectors of origins and destinations, and get the resulting distance matrix. It supports also directions, and has a bunch of options:

results = gmapsdistance(origin = c("Washington+DC", "New+York+NY", "Seattle+WA", "Miami+FL"), 
                        destination = c("Los+Angeles+CA", "Austin+TX", "Chicago+IL", "Philadelphia+PA"), 
                        mode = "bicycling", 
                        departure = 1514742000)
results
# $Time
#              or Time.Los+Angeles+CA Time.Austin+TX Time.Chicago+IL Time.Philadelphia+PA
# 1 Washington+DC              856621         535146          247765                54430
# 2   New+York+NY              917486         596011          308630                32215
# 3    Seattle+WA              374692         678959          674989               956702
# 4      Miami+FL              829039         416667          452035               411283
# 
# $Distance
#              or Distance.Los+Angeles+CA Distance.Austin+TX Distance.Chicago+IL Distance.Philadelphia+PA
# 1 Washington+DC                 4567470            2838519             1303067                   266508
# 2   New+York+NY                 4855086            3126136             1590684                   160917
# 3    Seattle+WA                 1982354            3562970             3588297                  5051951
# 4      Miami+FL                 4559205            2279966             2381610                  2169382
# 
# $Status
#              or status.Los+Angeles+CA status.Austin+TX status.Chicago+IL status.Philadelphia+PA
# 1 Washington+DC                    OK               OK                OK                     OK
# 2   New+York+NY                    OK               OK                OK                     OK
# 3    Seattle+WA                    OK               OK                OK                     OK
# 4      Miami+FL                    OK               OK                OK                     OK

I needed to calculate driving distances for a bunch of addresses, so I wrote a short function for it and put it in a likewise small packet. You can find it in my GitHub repo: https://github.com/JanMultmeier/GeoData/blob/master/GeoDataPackage/R/GetDist.R

This should get it to run:

require(devtools)
install_github("JanMultmeier/GeoData/GeoDataPackage")
library(GeoData)
getDist(from="1 Infinity Loop, Cupertino, CA 95014", to="1600 Amphitheatre Pkwy, Mountain View, CA 94043",modus="driving",get="distance")

It should return 14.8 km.

Barryhunter has already hinted at the usage restriction by Google, which ties the use of this API to displaying the results on a Google map.

Hope that still helps some people who stumble across this post (like me)...

I've written the googleway package to do this using Google Maps API

In particular, the google_directions() function will give you driving distances, directions, routes, legs, steps etc. And the google_distance() function will give you a distance matrix for all the origins/destinations

You need a Google API key to use their API

library(googleway)

## your valid API key
key <- "your_api_key_here"

directions <- google_directions(origin = c(37.193489,-121.07395),
                                destination = c(37.151616,-121.046586),
                                key = key, 
                                simplify = T)

directions$routes$legs
# [[1]]
# distance.text distance.value duration.text duration.value duration_in_traffic.text duration_in_traffic.value                 end_address
# 1        5.2 km           5250        3 mins            161                   3 mins                       156 I-5, Gustine, CA 95322, USA
# end_location.lat end_location.lng               start_address start_location.lat start_location.lng
# 1         37.15162        -121.0466 I-5, Gustine, CA 95322, USA           37.19349           -121.074
# steps
# 1 5.2 km, 5250, 3 mins, 161, 37.1516163, -121.0465852, Head <b>southeast</b> on <b>I-5 S</b>, ij_bFfg~aVpBgA`DkB~FeDbIwEpEgCtaAsj@nAs@lDqBxIaF~FgDlHcEjC{AdFuCrBkAhC{A|A{@|A}@bAk@rBkArBkA|A{@`DiB|A}@vDwBdAm@dAm@rBkA|A{@zA{@~J{FpC_B~A}@tBkAjHeEvGuDlMmHtBkAVO, 37.1934864, -121.0739565, DRIVING
#   traffic_speed_entry via_waypoint
#   1                NULL         NULL



google_distance(origins = list(c(37.193489,-121.07395)),
                destinations = list(c(37.151616,-121.046586)),
                key = key, 
                simplify = T,
                units = "imperial")

# $destination_addresses
# [1] "I-5, Gustine, CA 95322, USA"
# 
# $origin_addresses
# [1] "I-5, Gustine, CA 95322, USA"
# 
# $rows
# elements
# 1 3.3 mi, 5250, 3 mins, 161, 3 mins, 157, OK
# 
# $status
# [1] "OK"

Given the google_directions() function returns a polyline (the line you get on Google Maps when you search for a route), we can plot it on a Google Map

key <- 'your_map_api_key'

df_route <- decode_pl(directions$routes$overview_polyline$points)

google_map(data = df_route, key = key, height = 800, search_box = T) %>%
    add_markers()
## or you can use `add_polyline()` to view the entire line

At time of writing, Renjin (a Java-based R interpreter) does not have a lot of packages to help solve this problem. Here is an implementation that does not depend on extra packages.

# Computes the distance between two locations in meters. This uses an online
# map API and therefore an Internet connection is required for an accurate
# result. If no connection is found, this will use the Haversine formula
# to provide a rough estimate for the distance.
#
# @param src The source latitude and longitude.
# @param dst The destination latitude and longitude.
# @param mode Driving, cycling, walking, etc.
distance <- function( lat1, lon1, lat2, lon2, mode = 'driving' ) {
  lat1 = as.numeric( lat1 )
  lon1 = as.numeric( lon1 )
  lat2 = as.numeric( lat2 )
  lon2 = as.numeric( lon2 )

  # Create the URL to use to get the distance data.
  url = paste0(
    'https://maps.googleapis.com/maps/api/distancematrix/xml?',
    'origins=', lat1,
    ',', lon1,
    '&destinations=', lat2,
    ',', lon2,
    '&mode=', mode,
    '&sensor=false'
  )

  tryCatch({
    # Download the XML document with distance information.
    xml = readLines( url )

    # The <value> element immediately follows the distance element.
    value = xml[ grep( "<distance>", xml ) + 1 ]

    # Obtain the distance in meters.
    meters = sub( ".*>(.*?)<.*", "\\1", value )

    # Return the distance.
    as.numeric( meters )
  },
  warning = function( w ) {
    haversine( lat1, lon1, lat2, lon2 )
  },
  error = function( e ) {
    haversine( lat1, lon1, lat2, lon2 )
  })
}

# Computes distance using Haversine formula.
#
# Returns the result in meters.
haversine <- function( lat1, lon1, lat2, lon2, radius = 6371 ) {
  # Convert decimal degrees to radians
  lon1 = lon1 * pi / 180
  lon2 = lon2 * pi / 180
  lat1 = lat1 * pi / 180
  lat2 = lat2 * pi / 180

  # Haversine formula
  dlon = lon2 - lon1
  dlat = lat2 - lat1
  a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
  c = 2 * atan2(sqrt(a), sqrt(1-a))

  return( radius * c * 1000 )
}

Output:

distance( '44.5646', '-123.2620', '41.2861', '-124.0902' )
[1] 495892
distance( 44.5646, -123.2620, 41.2861, -124.0902, mode='walking' )
[1] 487715

Conversion from meters to feet is an exercise for the reader.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!