42

座標 (緯度、経度) を指定して、座標から特定の距離 (たとえば 50 km) 離れた正方形の境界ボックスを計算しようとしています。したがって、入力として緯度、経度、距離があり、出力として2つの座標が必要です。1 つは南西 (左下) の角で、もう 1 つは北東 (右上) の角です。ここで、Python でこの質問に対処しようとするいくつかの回答を見てきましたが、特に Java の実装を探しています。

明確にするために、私は地球上でのみアルゴリズムを使用するつもりであるため、可変半径に対応する必要はありません。

非常に正確である必要はなく (+/-20% で問題ありません)、短距離 (150km 以下) の境界ボックスを計算するためにのみ使用されます。そのため、効率的なアルゴリズムのために精度をいくらか犠牲にしてもかまいません。どんな助けでも大歓迎です。

編集:私はもっと明確にするべきでした。私は本当に円ではなく四角形を求めています。四角形の中心と四角形の周囲に沿ったさまざまな点との間の距離は、円のように一定の値ではないことを理解しています。私が言いたいのは、中心から周囲の 4 つの点のいずれかに線を引くと、周囲の辺に垂直な線になる正方形のことだと思います。これらの 4 つの線は同じ長さになります。

4

6 に答える 6

58

境界座標の検索に関する記事を書きました。

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

この記事では、数式について説明し、Java の実装も提供します。(また、最小/最大経度に対する IronMan の式が不正確である理由も示しています。)

于 2010-05-26T13:15:31.423 に答える
16
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をお勧めしますが。

于 2009-11-10T13:42:15.460 に答える
4
import com.vividsolutions.jts.geom.Envelope;

...
Envelope env = new Envelope(centerPoint.getCoordinate());
env.expandBy(distance_in_degrees); 
...

env にエンベロープが含まれるようになりました。それは実際には「正方形」ではありませんが (球の表面でそれが何を意味するにせよ)、そうすべきです。

度単位の距離は、中心点の緯度に依存することに注意してください。赤道では緯度 1 度が約 111 km ですが、ニューヨークでは約 75 km しかありません。

本当に素晴らしいことは、すべてのポイントを に投げてcom.vividsolutions.jts.index.strtree.STRtree、それを使用してそのエンベロープ内のポイントをすばやく計算できることです。

于 2009-11-06T18:21:12.037 に答える
3

以前の回答はすべて、部分的にしか正しくありません。特にオーストラリアのような地域では、常に極を含み、10km であっても非常に大きな長方形を計算します。

特にhttp://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndexのJan Philip Matuschek によるアルゴリズムには、オーストラリアのほぼすべてのポイントで (-37、-90、-180、180) の非常に大きな四角形が含まれていました。これはデータベース内の大規模なユーザーにヒットし、国のほぼ半分のすべてのユーザーについて距離を計算する必要があります。

Rochester Institute of Technologyによる Drupal API Earth Algorithmは、他の場所と同様に極周辺でもうまく機能し、実装がはるかに簡単であることがわかりました。

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 マップに記載されている距離計算式を使用して距離を計算します。

https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#outputting-data-as-xml-using-php

マイルではなくキロメートルで検索するには、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;
于 2017-08-30T01:11:05.020 に答える
0

これは、gps 10 進座標から近くの大都市を取得するためにGeoNames citieJSON APIで使用するバウンディング ボックス座標を生成するために使用した簡単なソリューションです。

これは私の GitHub リポジトリからの Java メソッドです: FusionTableModifyJava

10 進数の GPS 位置があり、その位置の「近く」で最大の都市/州を見つける必要がありました。そのバウンディング ボックスで最大の都市を取得するために、citiesJSON GeoNames Web サービスに渡す比較的正確なバウンディング ボックスが必要でした。場所と関心のある「半径」(km) を渡すと、cityJSON に渡すために必要な北、南、東、西の 10 進座標が返されます。

(これらのリソースは、私の研究を行うのに役立つことがわかりました:

緯度/経度ポイント間の距離、方位などを計算します。

経度 - ウィキペディア)

それは超正確ではありませんが、私がそれを使用していたものには十分正確です:

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

    }
于 2018-06-05T18:12:49.997 に答える