Calculate distance between two points in google maps V3
您如何计算Google Maps V3中两个标记之间的距离? (类似于V2中的
谢谢..
如果要自己计算,可以使用Haversine公式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 }; |
实际上,GMap3中似乎有一个方法。这是
它以两个
确保您包括:
1 | <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&v=3&libraries=geometry"> |
在你的头部。
电话将是:
1 | google.maps.geometry.spherical.computeDistanceBetween (latLngA, latLngB); |
新的V3几何库中有computeDistanceBetween(lat,lng)
使用2点GPS纬度/经度的示例。
1 2 3 4 5 6 | 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)); |
只需将其添加到您的JavaScript代码的开头即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } |
然后使用如下函数:
1 2 3 4 | var loc1 = new GLatLng(52.5773139, 1.3712427); var loc2 = new GLatLng(52.4788314, 1.7577444); var dist = loc2.distanceFrom(loc1); alert(dist/1000); |
1 2 3 4 5 6 | //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
但是,如果球形投影或正弦波解决方案的精度对您来说不够精确(例如,如果您靠近极点或计算距离较长),则应使用其他库。
我在这里的Wikipedia上找到了有关该主题的大多数信息。
判断任何给定算法的精度是否足够的一个技巧是填写地球的最大和最小半径,并查看差异是否可能导致您的用例出现问题。可以在本文中找到更多详细信息
最终,Google API或Haversine可以毫无问题地满足大多数目的。
这是此论坛的C#实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 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 } } |
使用PHP,您可以使用以下简单函数计算距离:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // to calculate distance between two lat & lon function 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); $miles = $dist * 60 * 1.1515; $unit = strtoupper($unit); if ($unit =="K") { return ($miles * 1.609344); } else if ($unit =="N") { return ($miles * 0.8684); } else { return $miles; } } // function ends here |
使用以Java语言实现的Vincenty算法,可以以增加处理时间为代价来获得良好的准确性。
离线解决方案-Haversine算法
In Javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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
就我而言,最好在SQL Server中进行计算,因为我想获取当前位置,然后在距当前位置一定距离内搜索所有邮政编码。我也有一个DB,其中包含邮政编码列表和它们的经纬度。干杯
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | --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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //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; } |
使用Google Distance Matrix服务非常简单
第一步是从Google API控制台激活Distance Matrix服务。
它返回一组位置之间的距离。
并应用此简单功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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 + ''; outputDiv.innerHTML += results[j].distance.text + ''; } } } }); } |
其中origin1是您的位置,destinationA是目的地位置。您可以添加两个或更多数据。
Rad完整文档和示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /** * 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%正确的版本,但插入了错误的参数,并且在使用输入时不一致,此版本已完全修复
请参阅GLatLng对象上的distanceFrom函数;在v2和v3之间,功能参数略有变化。
https://maps.googleapis.com/maps/api/directions/json?origin=Yangon&destination=Mandalay&key=YOUR_GOOGLE_MAP_API_KEY
然后检查路由[0] [0]。里面有一个估计的持续时间和估计的行进距离。
https://developers.google.com/maps/documentation/javascript/examples/distance-matrix
此代码地址名称或坐标结果
要计算Google Maps上的距离,可以使用Directions API。这将是最简单的方法之一。要从Google Server获取数据,可以使用Retrofit或Volley。两者都有自己的优势。看看下面的代码,其中我使用改造来实现它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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的代码。以下是相应的改造接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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地图距离计算器