以前所有的答案都只是部分正確。特別是在像澳大利亞這樣的地區,它們總是包含極點,甚至在10kms時也計算出一個非常大的矩形。
特別是由Jan Philip Matuschek在http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex提供的算法,對於澳大利亞的幾乎所有點都包含一個非常大的矩形(-37,-90,-180,180)。這對數據庫中的大量用戶和距離必須針對幾乎一半的所有用戶進行計算。
我發現羅切斯特理工學院Drupal API地球算法圍繞杆以及其他地方工作得更好,並且更容易實現。
https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54
使用earth_latitude_range
和earth_longitude_range
從上述算法用於計算邊界矩形
下面是實現是爪哇
/**
* Get bouding rectangle using Drupal Earth Algorithm
* @see https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54
* @param lat
* @param lng
* @param distance
* @return
*/
default BoundingRectangle getBoundingRectangleDrupalEarthAlgo(double lat, double lng, int distance) {
lng = Math.toRadians(lng);
lat = Math.toRadians(lat);
double radius = earth_radius(lat);
List<Double> retLats = earth_latitude_range(lat, radius, distance);
List<Double> retLngs = earth_longitude_range(lat, lng, radius, distance);
return new BoundingRectangle(retLats.get(0), retLats.get(1), retLngs.get(0), retLngs.get(1));
}
/**
* Calculate latitude range based on earths radius at a given point
* @param latitude
* @param longitude
* @param distance
* @return
*/
default List<Double> earth_latitude_range(double lat, double radius, double distance) {
// Estimate the min and max latitudes within distance of a given location.
double angle = distance/radius;
double minlat = lat - angle;
double maxlat = lat + angle;
double rightangle = Math.PI/2;
// Wrapped around the south pole.
if (minlat < -rightangle) {
double overshoot = -minlat - rightangle;
minlat = -rightangle + overshoot;
if (minlat > maxlat) {
maxlat = minlat;
}
minlat = -rightangle;
}
// Wrapped around the north pole.
if (maxlat > rightangle) {
double overshoot = maxlat - rightangle;
maxlat = rightangle - overshoot;
if (maxlat < minlat) {
minlat = maxlat;
}
maxlat = rightangle;
}
List<Double> ret = new ArrayList<>();
ret.add((minlat));
ret.add((maxlat));
return ret;
}
/**
* Calculate longitude range based on earths radius at a given point
* @param lat
* @param lng
* @param earth_radius
* @param distance
* @return
*/
default List<Double> earth_longitude_range(double lat, double lng, double earth_radius, int distance) {
// Estimate the min and max longitudes within distance of a given location.
double radius = earth_radius * Math.cos(lat);
double angle;
if (radius > 0) {
angle = Math.abs(distance/radius);
angle = Math.min(angle, Math.PI);
}
else {
angle = Math.PI;
}
double minlong = lng - angle;
double maxlong = lng + angle;
if (minlong < -Math.PI) {
minlong = minlong + Math.PI * 2;
}
if (maxlong > Math.PI) {
maxlong = maxlong - Math.PI * 2;
}
List<Double> ret = new ArrayList<>();
ret.add((minlong));
ret.add((maxlong));
return ret;
}
/**
* Calculate earth radius at given latitude
* @param latitude
* @return
*/
default Double earth_radius(double latitude) {
// Estimate the Earth's radius at a given latitude.
// Default to an approximate average radius for the United States.
double lat = Math.toRadians(latitude);
double x = Math.cos(lat)/6378137.0;
double y = Math.sin(lat)/(6378137.0 * (1 - (1/298.257223563)));
//Make sure earth's radius is in km , not meters
return (1/(Math.sqrt(x * x + y * y)))/1000;
}
並使用由谷歌記錄的距離計算公式映射計算距離
https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#outputting-data-as-xml-using-php
爲了通過公里而非英里搜索,與6371. 對於(緯度,經度)=(37,-122)中,用緯度列和lng一個標記表替換3959,所述式爲:
SELECT id, (3959 * acos(cos(radians(37)) * cos(radians(lat)) * cos(radians(lng) - radians(-122)) + sin(radians(37)) * sin(radians(lat)))) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;
這個問題只是直三角;我建議刪除java和算法標籤。 (如果這甚至是可能的。) – 2009-11-07 03:12:31
哦,對不起,我現在做了。 – 2009-11-07 03:15:33
需要考慮地球的球形特性。如果輸入位置是北極,你想要什麼答案? – MarkJ 2009-11-09 11:39:04