計算のバウンディングボックスに一定の距離から緯度経度の座標Java
-
18-09-2019 - |
質問
与えられ座標(緯度、長)が、私の計算スのバウンディングボックスは指定距離など50kmから距離を置いてください。ように入力してい経度、緯度、長距離-出力としてい座;されているのは、南西(左下)のコーナーがついては、北東(右上)。からの回答をこちらうようにこの問題の解決にはPythonでは、がんのためのJava実装です。
を明らかにしたいと考えていますの使用のアルゴリズムは地球上のみんなへの対応の必変数分の距離です。
いきなお絶大な精度(+/-20%カメラ-tv付きオートロックでのみ算出に使用したバウンディングボックス小距離(以150km).なので嬉しいのいくつかを犠牲に精度で効率的なアルゴリズムです。協力をよろしくお願いいたします。
編集:いてより明確にし、私は午後四角、円です。を解決するために必要となる距離にセンターの広場は、様々なポイントのスクエアの周囲には一定値ようになっております。思うのであるスクエアが線を引く中心からずれかのポイントの周囲に評価されている線に垂直な側面の外周、これらの4行と同じ長さです。
解決
私は、境界座標を見つけることについての記事を書きました。
http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinatesする
の記事は、数式を説明し、またJava実装を提供します。 (最小/最大経度のためのアイアンマンの式は不正確である理由も示している。)
他のヒント
double R = 6371; // earth radius in km
double radius = 50; // km
double x1 = lon - Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));
double x2 = lon + Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));
double y1 = lat + Math.toDegrees(radius/R);
double y2 = lat - Math.toDegrees(radius/R);
私もJTSをお勧めしますが。
import com.vividsolutions.jts.geom.Envelope;
...
Envelope env = new Envelope(centerPoint.getCoordinate());
env.expandBy(distance_in_degrees);
...
今envがあなたの封筒が含まれています。それは(それが球の表面にあらゆる手段を)実際に「四角」ではないのですが、それは行う必要があります。
あなたは度で距離が中心点の緯度に依存することに注意すべきです。赤道では、緯度の1度は約111キロですが、ニューヨークでは、それは約75キロです。
本当にクールなことは、あなたがcom.vividsolutions.jts.index.strtree.STRtree
にすべてのあなたのポイントを投げるし、その後すぐにその封筒の内側の点を計算するために使用することができるということです。
以前の回答はすべて部分的にのみ正しいです. 。特にオーストラリアのような地域では、常に極を含めて、10km であっても非常に大きな長方形を計算します。
特に Jan Philip Matuschek によるアルゴリズムは次のとおりです。 http://janmatuschek.de/LatitudeLongitudeBoundingCoowned#UsingIndex オーストラリアのほぼすべての地点に (-37、-90、-180、180) の非常に大きな長方形が含まれていました。これはデータベース内の大規模なユーザーに影響を与えるため、国のほぼ半分のすべてのユーザーについて距離を計算する必要があります。
私は、 ロチェスター工科大学による Drupal API Earth アルゴリズム ポールの周りだけでなく他の場所でもうまく機能し、実装がはるかに簡単です。
https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54
使用 earth_latitude_range
そして earth_longitude_range
外接四角形を計算するための上記のアルゴリズムから
ここでの実装はJavaです
/**
* 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;
}
そして、 Googleマップで文書化された距離計算式 距離を計算する
マイルではなくキロメートルで検索するには、3959 を 6371 に置き換えます。(Lat, Lng) = (37, -122) および列 lat と lng を持つマーカー テーブルの場合, 、式は次のとおりです。
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;
ここでは簡単に解決する私の生成に使用するバウンディングボックス座標を使うと GeoNames citieJSON API 得近くの大都市からgps小数点の座標
このJavaメソッドからのGitHubリポジトリ: FusionTableModifyJava
私は小数GPSの位置およびIア最大の都市国家"近い"について高く評価されていますも比較的精度バウンディングボックスに渡すcitiesJSON GeoNames webserviceンバーの最大都市そのバウンディングボックス。していただくための場所を"半径"か(キロ)で、南北、東、西小数点の座標は必要にcitiesJSON.
ったこれらの資源を有し、または自分の研究:
で正確なスーパーが正確でなかったのに使用す:
// Compute bounding Box coordinates for use with Geonames API.
class BoundingBox
{
public double north, south, east, west;
public BoundingBox(String location, float km)
{
//System.out.println(location + " : "+ km);
String[] parts = location.replaceAll("\\s","").split(","); //remove spaces and split on ,
double lat = Double.parseDouble(parts[0]);
double lng = Double.parseDouble(parts[1]);
double adjust = .008983112; // 1km in degrees at equator.
//adjust = 0.008983152770714983; // 1km in degrees at equator.
//System.out.println("deg: "+(1.0/40075.017)*360.0);
north = lat + ( km * adjust);
south = lat - ( km * adjust);
double lngRatio = 1/Math.cos(Math.toRadians(lat)); //ratio for lng size
//System.out.println("lngRatio: "+lngRatio);
east = lng + (km * adjust) * lngRatio;
west = lng - (km * adjust) * lngRatio;
}
}