Tính khoảng cách giữa hai điểm trong google maps V3


Câu trả lời:


460

Nếu bạn muốn tự tính toán, thì bạn có thể sử dụng công thức 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
};

4
Tại sao bạn đề xuất sử dụng Math.atan2 (Math.sqrt (a), Math.sqrt (1-a)) thay vì Math.asin đơn giản nhất (Math.sqrt (a))?
Emanuele Paolini

3
@EmanuelePaolini - Về mặt toán học, atan2 (sqrt (a), sqrt (1-a)) = asin (sqrt (a)) = acos (sqrt (1-a)), nhưng phiên bản atan2 vẫn được điều chỉnh tốt hơn cho tất cả các giá trị của a.
ChrisV

23
Các bạn. Câu hỏi. Tại sao bạn thích nó rất nhiều để sử dụng 1 tên biến chữ cái giải quyết các vấn đề đòi hỏi trí tưởng tượng trong đó tên biến tốt có thể hữu ích? Chỉ cần hỏi :)
pie6k

2
Không nên là var R = 6371; cho Km?
Alexander Fradiani

5
Các hàm p1.lat()p1.lng()hàm giả định rằng dữ liệu đầu vào của bạn là google.maps.LatLngcác đối tượng. Nếu bạn chỉ có dữ liệu thô như vậy {lat: __, lon: __}thì bạn sẽ sử dụng p1.lat, ví dụ.
Don McCurdy

308

Thực sự có một phương pháp trong GMap3. Đó là một phương thức tĩnh của google.maps.geometry.sphericalkhông gian tên.

Nó lấy làm đối số hai LatLngđối tượng và sẽ sử dụng bán kính Trái đất mặc định là 6378137 mét, mặc dù bán kính mặc định có thể được ghi đè bằng giá trị tùy chỉnh nếu cần.

Đảm bảo bạn bao gồm:

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

trong phần đầu của bạn.

Cuộc gọi sẽ là:

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

10
Vậy tại sao có sự khác biệt 1% trong câu trả lời được đưa ra bởi công thức tính toán hình cầu của Google và công thức khoảng cách Haversine?
Matt S

7
@RamenRecon Tôi không chắc chắn nhưng điều tuyệt vời là họ sử dụng các giá trị khác nhau cho bán kính trái đất.
Emil Badh

11
@RamenRecon vâng, Emil đúng về điều này. Tài liệu nói: Bán kính mặc định là bán kính Trái đất là 6378137 mét. Nhưng Mike trong Haversine ở trên sử dụng 6371km thay thế.
Laszlo

Liên kết ở trên hiện đã bị hỏng, nhưng việc giải thích về phương pháp này khiến cho vấn đề đó không còn nhiều.
GChorn

2
@ ABCD.ca Đây không phải là số của tôi. Câu hỏi này là về phiên bản 3 của Thư viện Google Maps. Bạn hỏi tại sao tính toán của bạn khác với họ. Đó là bởi vì họ sử dụng một giá trị khác cho bán kính trái đất so với bạn. Các tài liệu tham khảo cho số? developers.google.com/maps/documentation/javascript/. Ngay bên dưới tiêu đề.
Emil Badh 27/2/2015

30

Ví dụ sử dụng vĩ độ / kinh độ GPS là 2 điểm.

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

3
Kết quả khoảng cách được thể hiện bằng mét.
joan16v

1
@ joan16v làm thế nào để yêu cầu google.maps.geometry trong node.js. tôi muốn sử dụng mã ở trên trong node.js. Tôi nên cài đặt mô-đun nào và những tập tin nào tôi cần.
koror

15

Chỉ cần thêm phần này vào đầu mã JavaScript của bạn:

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

và sau đó sử dụng chức năng như thế này:

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

Giải pháp xuất sắc nhưng tôi muốn biết đơn vị nào sẽ trả về kết quả. Tôi nhận được 3,013 .. là trong dặm, km ??
Gowthami Gattineni

Giá trị trả về được tính bằng mét. Do đó dist / 1000 cung cấp cho bạn giá trị tính bằng km.
Praveen Janakarajan

13
//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);              
}

3
đây là câu trả lời tốt nhất Tại sao phải thêm chức năng khi Google API đã có các chức năng
felixfbecker

Có một biến thể java có sẵn cho API này không? Tôi không thể tìm thấy nó sau rất nhiều tìm kiếm.
Sanketh

@felixfbecker, vì bạn có thể đang làm việc trong môi trường mà bạn không thể chèn API google maps vào scriptthẻ và gọi các phương thức đó. Giống như phản ứng-bản địa.
Nnanyielugo

11

Đây là cách thực hiện c # của diễn đàn này

 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
    }

}    

5
Điều này không áp dụng cho câu hỏi ban đầu về cách thực hiện trong Google Maps.
Niklas Wulff

Không có chức năng sẵn có để tính khoảng cách trực tiếp, bạn phải sử dụng các dịch vụ thư mục cho hai điểm và trích xuất khoảng cách ra khỏi XML / JSON được trả về.
Naveed Ahmad

1
Nhận xét của tôi là về thực tế rằng sẽ tốt hơn nếu cung cấp giải pháp trong javascript, vì trình khởi động luồng không nói nếu anh ấy / cô ấy đang sử dụng php, .net hoặc html tĩnh.
Niklas Wulff

11

Với google bạn có thể làm điều đó bằng cách sử dụng api hình cầu , google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB);.

Tuy nhiên, nếu độ chính xác của hình chiếu hình cầu hoặc giải pháp haversine không đủ chính xác cho bạn (ví dụ: nếu bạn ở gần cực hoặc tính toán khoảng cách xa hơn), bạn nên sử dụng một thư viện khác.

Hầu hết thông tin về chủ đề tôi tìm thấy trên Wikipedia ở đây .

Một mẹo để xem độ chính xác của bất kỳ thuật toán đã cho nào là đủ hay không là điền vào bán kính tối đa và tối thiểu của trái đất và xem sự khác biệt có thể gây ra vấn đề cho trường hợp sử dụng của bạn hay không. Nhiều chi tiết có thể được tìm thấy trong bài viết này

Cuối cùng, google api hoặc haversine sẽ phục vụ hầu hết các mục đích mà không gặp vấn đề gì.


9

Sử dụng PHP, bạn có thể tính toán khoảng cách bằng hàm đơn giản này:

// để tính khoảng cách giữa hai lat & lon

hàm notify_distance ($ 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); 
  $ Dặm = $ quận * 60 * 1,1515;
  $ đơn vị = strtoupper (đơn vị $);

  if ($ đơn vị == "K") {
    return ($ dặm * 1,609344); 
  } if if ($ unit == "N") {
      return ($ dặm * 0,8684);
    } khác {
        trở $ dặm;
      }
}

// hàm kết thúc tại đây

2
Có một điều kiện trong chức năng là nếu bạn vượt qua đơn vị như vậy Kthì nó sẽ cho bạn khoảng cách tính bằng Km. Kiểm tra nó.
Người chết

chức năng này hoạt động rất tốt và nó cho khoảng cách từ vị trí sao đến tất cả các vị trí. Nó có thể đi qua một cách đầu tiên nó tìm thấy vị trí đầu tiên và nó trở thành nguồn hoặc bắt đầu và sau đó tìm vị trí gần nhất nhưng không phải là nguồn đầu tiên và v.v.
Waheed ur Rehman

8

GIẢI PHÁP OFFLINE - Thuật toán Haversine

Trong 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;
    }
}

Tham khảo: https://en.wikipedia.org/wiki/Great-circle_distance


3

Phải làm điều đó ... Cách kịch bản hành động

//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;
}

3

Trong trường hợp của tôi, tốt nhất là tính toán điều này trong SQL Server, vì tôi muốn lấy vị trí hiện tại và sau đó tìm kiếm tất cả các mã zip trong một khoảng cách nhất định từ vị trí hiện tại. Tôi cũng có một DB chứa danh sách mã zip và độ trễ của chúng. Chúc mừng

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

Không chắc chắn điều này là hiệu quả cho việc sử dụng phía khách hàng.
Nizar B.

Có thể không phải là một giải pháp mặt trước, nhưng chắc chắn là những gì tôi đang tìm kiếm. Cảm ơn.
st_stefanov

3
//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;
    }

1

Thật dễ dàng khi sử dụng dịch vụ Google Khoảng cách ma trận

Bước đầu tiên là kích hoạt dịch vụ Matrix Matrix từ bảng điều khiển API của google. nó trả về khoảng cách giữa một tập hợp các vị trí. Và áp dụng chức năng đơn giản này

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>';
              }
            }

          }
        });
      }

Trong đó origin1 là vị trí của bạn và đích đến là vị trí định mệnh. Bạn có thể thêm hai hoặc nhiều dữ liệu.

Tài liệu đầy đủ Rad với một ví dụ


1
  /**
   * 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;
  }

Tôi tìm thấy một phiên bản trực tuyến đúng 80% nhưng cắm sai tham số và không nhất quán trong việc sử dụng các đầu vào, phiên bản này đã sửa hoàn toàn


0

Để tính khoảng cách trên Google Maps, bạn có thể sử dụng API chỉ đường. Đó sẽ là một trong những cách dễ nhất để làm điều đó. Để lấy dữ liệu từ Google Server, bạn có thể sử dụng Retrofit hoặc Volley. Cả hai đều có lợi thế riêng của họ. Hãy xem đoạn mã sau nơi tôi đã sử dụng trang bị thêm để triển khai nó:

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());
        }
    });

}

Trên đây là mã của hàm build_retrofit_and_get_response để tính khoảng cách. Dưới đây là Giao diện trang bị thêm tương ứng:

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

}

Tôi hy vọng điều này giải thích truy vấn của bạn. Tất cả là tốt nhất :)

Nguồn: Máy tính khoảng cách Google Maps


Không- điều này tính toán khoảng cách di chuyển (trên đường, v.v.), không phải khoảng cách trắc địa điểm-điểm.
Yarin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.