【问题标题】:Getting driving distance between two points (lat, lon) using R and Google Map API使用 R 和 Google Map API 获取两点(纬度、经度)之间的行驶距离
【发布时间】:2013-05-27 14:43:20
【问题描述】:

我试图在给定纬度/经度的情况下获得两点之间的行驶距离。 我可以手动将它们放入谷歌地图并获取行驶距离,但我想以编程方式完成所有这些。

我猜想 JavaScript 是最好的语言。但是,我不懂 JavaScript,而且我对使用 R 相当熟悉。我更喜欢在 R 中进行,因为我在 R 中进行所有数据分析。

我正在寻找沿路的距离,而不是乌鸦飞行的距离。经过几个小时的尝试,我在 R 中编写了以下函数(Thisthis one 帮助)。你有没有更好的方法来获得这个函数内的距离或任何非常简单的方法?

library(XML)
latlon2ft <- function(origin,destination)
{

xml.url <- paste0('http://maps.googleapis.com/maps/api/distancematrix/xml?origins=',origin,'&destinations=',destination,'&mode=driving&sensor=false')

xmlfile <- xmlTreeParse(xml.url)
xmltop = xmlRoot(xmlfile)
distance <- xmltop[['row']][[1]][5][1][['distance']][['value']][[1]]
distance <- as.numeric(unclass(distance)[['value']])
ft <- distance*3.28084 # FROM METER TO FEET
return(ft)
}

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

结果 = 17224.41

【问题讨论】:

标签: xml r google-maps-api-3 driving-distance


【解决方案1】:

我编写了 gmapsdistance 包来做到这一点。它在 CRAN 上可用。您可以通过以下方式使用该功能:

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

您还可以包含起点和终点的向量,并获得生成的距离矩阵。它还支持方向,并且有很多选项:

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

【讨论】:

    【解决方案2】:

    您需要RCurl 或此处的等效项。

    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')
    

    结果:

    [1] 17224.41
    

    【讨论】:

    • 请注意,就像谷歌地图一样,这将采用几乎任何形式的地址,您可以将其扔给它:邮政编码、完整地址、部分地址......托马斯,你的解决方案让我很开心,谢谢!现在我只需要调整它,这样我就可以让它以小时为单位产生持续时间。
    • 你的每日请求是否达到极限?
    • 是的,我知道了,后来删除了我的评论。我将重新编写我的代码以最小化查询。 ;)
    • 顺便说一句,要以英里和英尺为单位,您还可以在xml.url 末尾使用units=imperial 参数。
    【解决方案3】:

    我需要计算一堆地址的行驶距离,所以我为它写了一个简短的函数并将它放在一个同样小的数据包中。您可以在我的 GitHub 存储库中找到它:https://github.com/JanMultmeier/GeoData/blob/master/GeoDataPackage/R/GetDist.R

    这应该让它运行:

    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")
    

    应该返回 14.8 公里。

    Barryhunter 已经暗示了 Google 的使用限制,该限制将此 API 的使用与在 Google 地图上显示结果联系在一起。

    希望仍然可以帮助一些偶然发现这篇文章的人(比如我)...

    【讨论】:

      【解决方案4】:

      我已经使用 Google Maps API 编写了 googleway 包来执行此操作

      特别是,google_directions() 函数将为您提供行驶距离、方向、路线、腿、步数等。 google_distance() 函数将为您提供所有起点/终点的距离矩阵

      您需要一个 Google API 密钥才能使用他们的 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"
      

      鉴于google_directions() 函数返回一条折线(您在谷歌地图上搜索路线时得到的线),我们可以在谷歌地图上绘制它

      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
      

      【讨论】:

        【解决方案5】:

        在撰写本文时,Renjin(一个基于 Java 的 R 解释器)并没有很多包来帮助解决这个问题。这是一个不依赖额外包的实现。

        # 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 )
        }
        

        输出:

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

        从米到英尺的转换是读者的练习。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-10-25
          • 2015-05-14
          • 1970-01-01
          • 2011-04-11
          • 2012-10-13
          • 1970-01-01
          相关资源
          最近更新 更多