구글지도 V3에서 두 지점 사이의 거리를 계산


답변:


460

직접 계산하려면 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
왜 가장 간단한 Math.asin (Math.sqrt (a)) 대신 Math.atan2 (Math.sqrt (a), Math.sqrt (1-a))를 사용하는 것이 좋습니다?
Emanuele Paolini 2016 년

3
@EmanuelePaolini-수학적으로 atan2 (sqrt (a), sqrt (1-a)) = asin (sqrt (a)) = acos (sqrt (1-a))이지만 atan2 버전은 모든 값에 대해 수치 적으로 더 나은 상태를 유지합니다. ㅏ.
ChrisV

23
여러분 질문. 좋은 변수 이름이 도움이 될 수있는 상상력이 필요한 문제를 해결하는 데 1 문자 변수 이름을 사용하는 것이 왜 그렇게 좋아합니까? 그냥 물어 :)
pie6k

2
var R = 6371이 아니어야합니다. 흠?
Alexander Fradiani

5
p1.lat()p1.lng()기능은 입력 데이터가 있다고 가정 google.maps.LatLng오브젝트. 예를 들어 원시 데이터가있는 경우 {lat: __, lon: __}대신을 사용 p1.lat합니다.
Don McCurdy

308

실제로 GMap3에는 메소드가있는 것 같습니다. 정적 방법입니다google.maps.geometry.spherical네임 스페이스 .

인수 2를 취합니다 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);

10
그렇다면 왜 구글의 구면 computeDistanceBetween과 Haversine distance 공식에 의해 1 %의 차이가 있습니까?
매트 S

7
@RamenRecon 확실하지는 않지만 지구 반경에 대해 다른 값을 사용한다는 것이 문제입니다.
Emil Badh

11
@RamenRecon 네, Emil은 이것에 맞습니다. 문서는 말합니다 : 기본 반경은 지구의 반경 6378137 미터입니다. 그러나 위의 Haversine에있는 Mike는 대신 6371km를 사용합니다.
Laszlo

위의 링크는 이제 끊어졌지만 방법에 대한 설명은 그다지 문제가되지 않습니다.
GChorn

2
@ ABCD.ca 내 번호가 아닙니다. 이 질문은 Google Maps Library 버전 3에 관한 것입니다. 계산이 왜 다른지 물었습니다. 지구 반경에 대해 다른 값을 사용하기 때문입니다. 숫자에 대한 참조? developers.google.com/maps/documentation/javascript/… 제목 바로 아래에 있습니다.
Emil Badh

30

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

3
거리 결과는 미터로 표시됩니다.
joan16v

1
@ joan16v node.js에서 google.maps.geometry가 필요한 방법. node.js에서 위의 코드를 사용하고 싶습니다. 어떤 모듈을 설치하고 어떤 파일을 필요로합니까?
kisor

15

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을 얻었다 .. 마일, km?
Gowthami Gattineni

반환 된 값은 미터입니다. 따라서 dist / 1000은 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
이것이 가장 좋은 대답입니다. 구글 API는 이미 기능이 왜 함수를 추가
felixfbecker

이 API에 사용할 수있는 Java 변형이 있습니까? 많은 검색 후 그것을 찾을 수 없습니다.
Sanketh

@felixfbecker는 Google지도 API를 script태그에 삽입 할 수없는 환경에서 작업하고 있기 때문에 해당 메소드를 호출 할 수 있기 때문 입니다. 반응 네이티브처럼.
Nnanyielugo

11

다음은이 포럼의 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
    }

}    

5
Google지도에서 수행하는 방법에 대한 원래 질문에는 적용되지 않습니다.
Niklas Wulff

거리를 직접 계산하는 내장 함수가 없으므로 두 점에 대해 디렉토리 서비스를 사용하고 리턴 된 XML / JSON에서 거리를 추출해야합니다.
Naveed Ahmad

1
내 의견은 스레드 스타터가 PHP, .net 또는 정적 HTML을 사용하고 있는지 말하지 않았기 때문에 자바 스크립트로 솔루션을 제공하는 것이 더 좋을 것이라는 사실에 대한 의견이었습니다.
Niklas Wulff

11

구글에서는 구형 API를 사용하여 할 수 있습니다 .google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB); .

그러나 구형 투영 또는 헤르 세인 솔루션의 정밀도가 정확하지 않은 경우 (예 : 극에 가까워 지거나 먼 거리를 계산하는 경우) 다른 라이브러리를 사용해야합니다.

Wikipedia 에서 찾은 주제에 대한 대부분의 정보는 여기 에서 볼 수 있습니다 .

주어진 알고리즘의 정밀도가 적절한 지 확인하는 방법은 지구의 최대 및 최소 반경을 채우고 그 차이가 사용 사례에 문제를 일으킬 수 있는지 확인하는 것입니다. 이 기사 에서 더 많은 세부 정보를 찾을 수 있습니다

결국 Google API 또는 Haversine은 문제없이 대부분의 목적을 제공합니다.


9

PHP를 사용하면 다음과 같은 간단한 함수를 사용하여 거리를 계산할 수 있습니다.

// 두 위도 및 경도 사이의 거리를 계산

calculate_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); 
  $ 마일 = $ dist * 60 * 1.1515;
  $ unit = strtoupper ($ unit);

  if ($ unit == "K") {
    귀국 ($ 마일 * 1.609344); 
  } 그렇지 않으면 ($ unit == "N") {
      귀국 ($ 마일 * 0.8684);
    } else {
        $ 마일 반환;
      }
}

// 함수는 여기서 끝납니다

2
함수에 장치를 통과 K하면 거리가 Km으로 표시되는 조건이 있습니다. 확인해 봐.
Dead Man

이 기능은 매우 잘 작동하며 별 위치에서 모든 위치까지의 거리를 제공합니다. 첫 번째로 가장 가까운 위치를 찾아서 소스 또는 시작으로 된 다음 첫 번째 소스가 아닌 가장 가까운 위치를 찾을 수 있습니까?
Waheed ur Rehman

8

오프라인 솔루션-Haversine Algorithm

자바 스크립트에서

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

씨#

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


3

해야했다 ... 액션 스크립트 방법

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

필자의 경우 현재 위치를 가져 와서 현재 위치에서 특정 거리 내의 모든 우편 번호를 검색하고 싶기 때문에 SQL Server에서 이것을 계산하는 것이 가장 좋습니다. 또한 우편 번호 목록과 위도를 포함하는 DB가 있습니다. 건배

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

이것이 클라이언트 측 사용에 효율적인지 확실하지 않습니다.
Nizar B.

프론트 엔드 솔루션은 아니지만 내가 찾고있는 것입니다. 감사.
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

Google Distance Matrix 서비스를 사용하는 것은 매우 쉽습니다.

첫 번째 단계는 Google API 콘솔에서 Distance Matrix 서비스를 활성화하는 것입니다. 위치 집합 사이의 거리를 반환합니다. 이 간단한 기능을 적용하십시오

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 전체 설명서


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

온라인 버전이 80 % 맞지만 잘못된 매개 변수에 연결되어 있고 입력을 사용하는 데 일관성이없는 버전을 찾았습니다.이 버전은 완전히 수정되었습니다.


0

Google지도에서 거리를 계산하려면 길 찾기 API를 사용할 수 있습니다. 가장 쉬운 방법 중 하나가 될 것입니다. Google 서버에서 데이터를 가져 오려면 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


아니오-지점 간 측지 거리가 아닌 이동 거리 (도로 등)를 계산합니다.
Yarin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.