【问题标题】:Calculate distance between two points in google maps V3计算谷歌地图V3中两点之间的距离
【发布时间】:2010-12-02 22:06:57
【问题描述】:

如何计算 Google 地图 V3 中两个标记之间的距离? (类似于V2中的distanceFrom函数。)

谢谢..

【问题讨论】:

标签: javascript google-maps-api-3


【解决方案1】:

如果你想自己计算,那么你可以使用Haversine公式:

var rad = function(x) {
  return x * Math.PI / 180;
};

var getDistance = function(p1, p2) {
  var R = 6378137; // Earth’s mean radius in meter
  var dLat = rad(p2.lat() - p1.lat());
  var dLong = rad(p2.lng() - p1.lng());
  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) *
    Math.sin(dLong / 2) * Math.sin(dLong / 2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  var d = R * c;
  return d; // returns the distance in meter
};

【讨论】:

  • 为什么你建议使用 Math.atan2(Math.sqrt(a),Math.sqrt(1-a)) 而不是最简单的 Math.asin(Math.sqrt(a)) ?跨度>
  • @EmanuelePaolini - 数学上,atan2(sqrt(a),sqrt(1-a)) = asin(sqrt(a)) = acos(sqrt(1-a)),但 atan2 版本对于 a 的所有值,在数值上保持更好的条件。
  • 伙计们。题。为什么你这么喜欢使用 1 个字母的变量名来解决需要一些想象力的问题,而好的变量名可能会有所帮助?只是问:)
  • 不应该是 var R = 6371;公里?
  • p1.lat()p1.lng() 函数假定您的输入数据是 google.maps.LatLng 对象。例如,如果您只有 {lat: __, lon: __} 这样的原始数据,那么您将改用 p1.lat
【解决方案2】:

实际上在 GMap3 中似乎有一个方法。它是google.maps.geometry.spherical 命名空间的静态方法。

它将两个 LatLng 对象作为参数,并将使用 6378137 米的默认地球半径,但如果需要,可以使用自定义值覆盖默认半径。

确保包括:

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"></script>

在你的头部。

电话将是:

google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);

【讨论】:

  • 那么为什么谷歌的球面computeDistanceBetween和Haversine距离公式给出的答案会有1%的差异呢?
  • @RamenRecon 我不确定,但问题是他们使用不同的地球半径值。
  • @RamenRecon 是的,Emil 在这点上是正确的。文档说:默认半径是地球的半径 6378137 米。 但是上面 Haversine 中的 Mike 使用 6371km 代替。
  • 上面的链接现在已经失效了,但是对方法的解释使得这不是什么大问题。
  • @ABCD.ca 这不是我的号码。这个问题是关于谷歌地图库第 3 版的。你问为什么你的计算与他们的不同。这是因为他们使用的地球半径值与您使用的不同。编号的参考? developers.google.com/maps/documentation/javascript/… 就在标题下方。
【解决方案3】:

这里是这个论坛的c#实现

 public class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIO = 6378.16;

    /// <summary>
    /// This class cannot be instantiated.
    /// </summary>
    private DistanceAlgorithm() { }

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(
        double lon1,
        double lat1,
        double lon2,
        double lat2)
    {
        double dlon =  Radians(lon2 - lon1);
        double dlat =  Radians(lat2 - lat1);

        double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
        double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        return (angle * RADIO) * 0.62137;//distance in miles
    }

}    

【讨论】:

  • 这不适用于如何在 Google 地图中进行操作的原始问题。
  • 没有直接计算距离的内置函数,你必须使用两点的目录服务并从返回的XML/JSON中提取距离。
  • 我的评论是在 javascript 中提供解决方案会更好,因为线程启动器没有说明他/她使用的是 php、.net 还是静态 html。
【解决方案4】:

只需将其添加到 JavaScript 代码的开头即可:

google.maps.LatLng.prototype.distanceFrom = function(latlng) {
  var lat = [this.lat(), latlng.lat()]
  var lng = [this.lng(), latlng.lng()]
  var R = 6378137;
  var dLat = (lat[1]-lat[0]) * Math.PI / 180;
  var dLng = (lng[1]-lng[0]) * Math.PI / 180;
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
  Math.cos(lat[0] * Math.PI / 180 ) * Math.cos(lat[1] * Math.PI / 180 ) *
  Math.sin(dLng/2) * Math.sin(dLng/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return Math.round(d);
}

然后像这样使用函数:

var loc1 = new GLatLng(52.5773139, 1.3712427);
var loc2 = new GLatLng(52.4788314, 1.7577444);
var dist = loc2.distanceFrom(loc1);
alert(dist/1000);

【讨论】:

  • Excellect 解决方案,但我想知道它以什么单位返回结果。我得到了 3.013 .. 是英里,公里吗??
  • 返回值以米为单位。因此 dist/1000 为您提供以公里为单位的值。
【解决方案5】:

使用 PHP,您可以使用这个简单的函数计算距离:

// 计算两个纬度和经度之间的距离 函数计算距离($lat1,$lon1,$lat2,$lon2,$unit='N') { $theta = $lon1 - $lon2; $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $miles = $dist * 60 * 1.1515; $unit = strtoupper($unit); if ($unit == "K") { 返回 ($miles * 1.609344); } else if ($unit == "N") { 返回 ($miles * 0.8684); } 别的 { 返回 $miles; } } // 函数到此结束

【讨论】:

  • 函数中有一个条件,如果你将单位传递为K,那么它会给你以公里为单位的距离。检查一下。
  • 这个功能效果很好,它给出了从星星位置到所有位置的距离。它能否以某种方式首先遍历它找到第一个最近的位置并成为源或开始,然后找到它的下一个最近但不是第一个源,依此类推?
【解决方案6】:

不得不这样做...动作脚本方式

//just make sure you pass a number to the function because it would accept you mother in law...
public var rad = function(x:*) {return x*Math.PI/180;}

protected  function distHaversine(p1:Object, p2:Object):Number {
    var R:int = 6371; // earth's mean radius in km
    var dLat:Number = rad(p2.lat() - p1.lat());
    var dLong:Number = rad(p2.lng() - p1.lng());

    var a:Number = Math.sin(dLat/2) * Math.sin(dLat/2) +
                Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
    var c:Number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d:Number = R * c;

    return d;
}

【讨论】:

    【解决方案7】:

    通过 google,您可以使用 spherical apigoogle.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB); 来完成。

    但是,如果球面投影或半正弦解的精度对您来说不够精确(例如,如果您靠近极点或计算更长的距离),您应该使用不同的库。

    我在 Wikipedia here 上找到的有关该主题的大部分信息。

    查看任何给定算法的精度是否足够的技巧是填写地球的最大和最小半径,看看差异是否会导致您的用例出现问题。更多细节可以在this article中找到

    最终,google api 或 hasrsine 将毫无问题地服务于大多数用途。

    【讨论】:

      【解决方案8】:

      就我而言,最好在 SQL Server 中进行计算,因为我想获取当前位置,然后搜索距当前位置一定距离内的所有邮政编码。我还有一个数据库,其中包含邮政编码及其经纬度列表。干杯

      --will return the radius for a given number
      create function getRad(@variable float)--function to return rad
      returns float
      as
      begin
      declare @retval float 
      select @retval=(@variable * PI()/180)
      --print @retval
      return @retval
      end
      go
      
      --calc distance
      --drop function dbo.getDistance
      create function getDistance(@cLat float,@cLong float, @tLat float, @tLong float)
      returns float
      as
      begin
      declare @emr float
      declare @dLat float
      declare @dLong float
      declare @a float
      declare @distance float
      declare @c float
      
      set @emr = 6371--earth mean 
      set @dLat = dbo.getRad(@tLat - @cLat);
      set @dLong = dbo.getRad(@tLong - @cLong);
      set @a = sin(@dLat/2)*sin(@dLat/2)+cos(dbo.getRad(@cLat))*cos(dbo.getRad(@tLat))*sin(@dLong/2)*sin(@dLong/2);
      set @c = 2*atn2(sqrt(@a),sqrt(1-@a))
      set @distance = @emr*@c;
      set @distance = @distance * 0.621371 -- i needed it in miles
      --print @distance
      return @distance;
      end 
      go
      
      
      --get all zipcodes within 2 miles, the hardcoded #'s would be passed in by C#
      select *
      from cityzips a where dbo.getDistance(29.76,-95.38,a.lat,a.long) <3
      order by zipcode
      

      【讨论】:

      • 不确定这对客户端使用是否有效。
      • 可能不是前端解决方案,但绝对是我想要的。谢谢。
      【解决方案9】:
      //JAVA
          public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
          final int RADIUS_EARTH = 6371;
      
          double dLat = getRad(latitude2 - latitude1);
          double dLong = getRad(longitude2 - longitude1);
      
          double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
          double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
          return (RADIUS_EARTH * c) * 1000;
          }
      
          private Double getRad(Double x) {
          return x * Math.PI / 180;
          }
      

      【讨论】:

        【解决方案10】:

        使用 GPS 纬度/经度 2 点的示例。

        var latitude1 = 39.46;
        var longitude1 = -0.36;
        var latitude2 = 40.40;
        var longitude2 = -3.68;
        
        var distance = google.maps.geometry.spherical.computeDistanceBetween(new google.maps.LatLng(latitude1, longitude1), new google.maps.LatLng(latitude2, longitude2));       
        

        【讨论】:

        • 距离结果以米为单位。
        • @joan16v 如何在 node.js 中要求 google.maps.geometry。我想在 node.js 中使用上面的代码。我应该安装哪个模块,我需要什么文件。
        【解决方案11】:
        //p1 and p2 are google.maps.LatLng(x,y) objects
        
        function calcDistance(p1, p2) {
                  var d = (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
                  console.log(d);              
        }
        

        【讨论】:

        • 这是最好的答案。 Google API 已经有函数了,为什么还要添加函数
        • 此 API 是否有可用的 java 变体?找了好久都没找到。
        • @felixfbecker,因为您可能在无法将谷歌地图 API 插入 script 标记并调用这些方法的环境中工作。就像 react-native。
        【解决方案12】:

        离线解决方案 - Haversine 算法

        在 Javascript 中

        var _eQuatorialEarthRadius = 6378.1370;
        var _d2r = (Math.PI / 180.0);
        
        function HaversineInM(lat1, long1, lat2, long2)
        {
            return (1000.0 * HaversineInKM(lat1, long1, lat2, long2));
        }
        
        function HaversineInKM(lat1, long1, lat2, long2)
        {
            var dlong = (long2 - long1) * _d2r;
            var dlat = (lat2 - lat1) * _d2r;
            var a = Math.pow(Math.sin(dlat / 2.0), 2.0) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r) * Math.pow(Math.sin(dlong / 2.0), 2.0);
            var c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
            var d = _eQuatorialEarthRadius * c;
        
            return d;
        }
        
        var meLat = -33.922982;
        var meLong = 151.083853;
        
        
        var result1 = HaversineInKM(meLat, meLong, -32.236457779983745, 148.69094705162837);
        var result2 = HaversineInKM(meLat, meLong, -33.609020205923713, 150.77061469270831);
        

        C#

        using System;
        
        public class Program
        {
            public static void Main()
            {
                Console.WriteLine("Hello World");
        
                var meLat = -33.922982;
                double meLong = 151.083853;
        
        
                var result1 = HaversineInM(meLat, meLong, -32.236457779983745, 148.69094705162837);
                var result2 = HaversineInM(meLat, meLong, -33.609020205923713, 150.77061469270831);
        
                Console.WriteLine(result1);
                Console.WriteLine(result2);
            }
        
            static double _eQuatorialEarthRadius = 6378.1370D;
            static double _d2r = (Math.PI / 180D);
        
            private static int HaversineInM(double lat1, double long1, double lat2, double long2)
            {
                return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
            }
        
            private static  double HaversineInKM(double lat1, double long1, double lat2, double long2)
            {
                double dlong = (long2 - long1) * _d2r;
                double dlat = (lat2 - lat1) * _d2r;
                double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
                double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
                double d = _eQuatorialEarthRadius * c;
        
                return d;
            }
        }
        

        参考: https://en.wikipedia.org/wiki/Great-circle_distance

        【讨论】:

          【解决方案13】:

          要在 Google 地图上计算距离,您可以使用 Directions API。这将是最简单的方法之一。要从 Google Server 获取数据,您可以使用 Retrofit 或 Volley。两者都有自己的优势。看看下面我使用改造来实现它的代码:

          private void build_retrofit_and_get_response(String type) {
          
              String url = "https://maps.googleapis.com/maps/";
          
              Retrofit retrofit = new Retrofit.Builder()
                      .baseUrl(url)
                      .addConverterFactory(GsonConverterFactory.create())
                      .build();
          
              RetrofitMaps service = retrofit.create(RetrofitMaps.class);
          
              Call<Example> call = service.getDistanceDuration("metric", origin.latitude + "," + origin.longitude,dest.latitude + "," + dest.longitude, type);
          
              call.enqueue(new Callback<Example>() {
                  @Override
                  public void onResponse(Response<Example> response, Retrofit retrofit) {
          
                      try {
                          //Remove previous line from map
                          if (line != null) {
                              line.remove();
                          }
                          // This loop will go through all the results and add marker on each location.
                          for (int i = 0; i < response.body().getRoutes().size(); i++) {
                              String distance = response.body().getRoutes().get(i).getLegs().get(i).getDistance().getText();
                              String time = response.body().getRoutes().get(i).getLegs().get(i).getDuration().getText();
                              ShowDistanceDuration.setText("Distance:" + distance + ", Duration:" + time);
                              String encodedString = response.body().getRoutes().get(0).getOverviewPolyline().getPoints();
                              List<LatLng> list = decodePoly(encodedString);
                              line = mMap.addPolyline(new PolylineOptions()
                                              .addAll(list)
                                              .width(20)
                                              .color(Color.RED)
                                              .geodesic(true)
                              );
                          }
                      } catch (Exception e) {
                          Log.d("onResponse", "There is an error");
                          e.printStackTrace();
                      }
                  }
          
                  @Override
                  public void onFailure(Throwable t) {
                      Log.d("onFailure", t.toString());
                  }
              });
          
          }
          

          以上是计算距离的函数build_retrofit_and_get_response的代码。下面是对应的改造界面:

          package com.androidtutorialpoint.googlemapsdistancecalculator;
          
          
          import com.androidtutorialpoint.googlemapsdistancecalculator.POJO.Example;
          
          import retrofit.Call;
          import retrofit.http.GET;
          import retrofit.http.Query;
          
          public interface RetrofitMaps {
          
          
          /*
           * Retrofit get annotation with our URL
           * And our method that will return us details of student.
           */
          @GET("api/directions/json?key=AIzaSyC22GfkHu9FdgT9SwdCWMwKX1a4aohGifM")
          Call<Example> getDistanceDuration(@Query("units") String units, @Query("origin") String origin, @Query("destination") String destination, @Query("mode") String mode);
          

          }

          我希望这可以解释您的问题。一切顺利:)

          来源:Google Maps Distance Calculator

          【讨论】:

          • 不 - 这计算行驶距离(在道路等),而不是点到点的测地线距离。
          【解决方案14】:

          使用 Google 距离矩阵服务

          非常简单

          第一步是从谷歌 API 控制台激活距离矩阵服务。 它返回一组位置之间的距离。 并应用这个简单的功能

          function initMap() {
                  var bounds = new google.maps.LatLngBounds;
                  var markersArray = [];
          
                  var origin1 = {lat:23.0203, lng: 72.5562};
                  //var origin2 = 'Ahmedabad, India';
                  var destinationA = {lat:23.0436503, lng: 72.55008939999993};
                  //var destinationB = {lat: 23.2156, lng: 72.6369};
          
                  var destinationIcon = 'https://chart.googleapis.com/chart?' +
                      'chst=d_map_pin_letter&chld=D|FF0000|000000';
                  var originIcon = 'https://chart.googleapis.com/chart?' +
                      'chst=d_map_pin_letter&chld=O|FFFF00|000000';
                  var map = new google.maps.Map(document.getElementById('map'), {
                    center: {lat: 55.53, lng: 9.4},
                    zoom: 10
                  });
                  var geocoder = new google.maps.Geocoder;
          
                  var service = new google.maps.DistanceMatrixService;
                  service.getDistanceMatrix({
                    origins: [origin1],
                    destinations: [destinationA],
                    travelMode: 'DRIVING',
                    unitSystem: google.maps.UnitSystem.METRIC,
                    avoidHighways: false,
                    avoidTolls: false
                  }, function(response, status) {
                    if (status !== 'OK') {
                      alert('Error was: ' + status);
                    } else {
                      var originList = response.originAddresses;
                      var destinationList = response.destinationAddresses;
                      var outputDiv = document.getElementById('output');
                      outputDiv.innerHTML = '';
                      deleteMarkers(markersArray);
          
                      var showGeocodedAddressOnMap = function(asDestination) {
                        var icon = asDestination ? destinationIcon : originIcon;
                        return function(results, status) {
                          if (status === 'OK') {
                            map.fitBounds(bounds.extend(results[0].geometry.location));
                            markersArray.push(new google.maps.Marker({
                              map: map,
                              position: results[0].geometry.location,
                              icon: icon
                            }));
                          } else {
                            alert('Geocode was not successful due to: ' + status);
                          }
                        };
                      };
          
                      for (var i = 0; i < originList.length; i++) {
                        var results = response.rows[i].elements;
                        geocoder.geocode({'address': originList[i]},
                            showGeocodedAddressOnMap(false));
                        for (var j = 0; j < results.length; j++) {
                          geocoder.geocode({'address': destinationList[j]},
                              showGeocodedAddressOnMap(true));
                          //outputDiv.innerHTML += originList[i] + ' to ' + destinationList[j] + ': ' + results[j].distance.text + ' in ' +                    results[j].duration.text + '<br>';
                          outputDiv.innerHTML += results[j].distance.text + '<br>';
                        }
                      }
          
                    }
                  });
                }
          

          其中 origin1 是您的位置,destinationA 是目的地位置。您可以添加以上两个或更多数据。

          Rad Full Documentation 举个例子

          【讨论】:

            【解决方案15】:
              /**
               * Calculates the haversine distance between point A, and B.
               * @param {number[]} latlngA [lat, lng] point A
               * @param {number[]} latlngB [lat, lng] point B
               * @param {boolean} isMiles If we are using miles, else km.
               */
              function haversineDistance(latlngA, latlngB, isMiles) {
                const squared = x => x * x;
                const toRad = x => (x * Math.PI) / 180;
                const R = 6371; // Earth’s mean radius in km
            
                const dLat = toRad(latlngB[0] - latlngA[0]);
                const dLon = toRad(latlngB[1] - latlngA[1]);
            
                const dLatSin = squared(Math.sin(dLat / 2));
                const dLonSin = squared(Math.sin(dLon / 2));
            
                const a = dLatSin +
                          (Math.cos(toRad(latlngA[0])) * Math.cos(toRad(latlngB[0])) * dLonSin);
                const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
                let distance = R * c;
            
                if (isMiles) distance /= 1.609344;
            
                return distance;
              }
            

            我在网上找到一个版本,80%正确,但插入错误的参数,使用输入不一致,这个版本完全解决了这个问题

            【讨论】:

              【解决方案16】:

              首先,您是指整个路径的长度还是您只想知道位移(直线距离)?我看没有人在这里指出距离和位移之间的区别。对于距离计算 JSON/XML 数据给出的每个路线点,至于位移有一个使用Spherical 类的内置解决方案

              //calculates distance between two points in km's
              function calcDistance(p1, p2) {
                return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
              }
              

              【讨论】:

                猜你喜欢
                • 2013-09-30
                • 1970-01-01
                • 1970-01-01
                • 2011-09-21
                • 2012-04-29
                • 1970-01-01
                • 2016-04-12
                • 2014-07-12
                相关资源
                最近更新 更多