Frage

Bei einer gegebenen Koordinate (Breite, Länge) versuche ich, einen quadratischen Begrenzungsrahmen zu berechnen, der einen bestimmten Abstand hat (z. B.50 km) von der Koordinate entfernt.Als Eingabe habe ich also Lat, Long und Distance und als Ausgabe hätte ich gerne zwei Koordinaten;Eine ist die südwestliche Ecke (unten links) und eine ist die nordöstliche Ecke (oben rechts).Ich habe hier einige Antworten gesehen, die versuchen, diese Frage in Python zu beantworten, aber ich suche insbesondere nach einer Java-Implementierung.

Um es klarzustellen: Ich beabsichtige, den Algorithmus nur auf der Erde zu verwenden und muss daher keinen variablen Radius berücksichtigen.

Es muss nicht sehr genau sein (+/-20 % ist in Ordnung) und wird nur zur Berechnung von Begrenzungsrahmen über kleine Entfernungen (nicht mehr als 150 km) verwendet.Deshalb opfere ich gerne etwas Genauigkeit für einen effizienten Algorithmus.Jede Hilfe wird sehr geschätzt.

Bearbeiten:Ich hätte klarer sein sollen, ich bin wirklich auf der Suche nach einem Quadrat, nicht nach einem Kreis.Ich verstehe, dass der Abstand zwischen der Mitte eines Quadrats und verschiedenen Punkten entlang des Quadratumfangs kein konstanter Wert ist, wie es bei einem Kreis der Fall ist.Ich denke, was ich meine, ist ein Quadrat, bei dem, wenn man eine Linie von der Mitte zu einem der vier Punkte auf dem Umfang zieht, die eine Linie senkrecht zu einer Seite des Umfangs ergibt, diese vier Linien die gleiche Länge haben.

War es hilfreich?

Lösung

Ich schrieb einen Artikel über die Begrenzungs finden Koordinaten:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

Der Artikel beschreibt die Formeln und stellt auch eine Java-Implementierung. (Es zeigt auch, warum IronMan-Formel für die Min- / Max-Länge ist ungenau.)

Andere Tipps

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

Obwohl ich würde auch JTS empfehlen.

import com.vividsolutions.jts.geom.Envelope;

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

Jetzt env enthält Ihren Umschlag. Es ist nicht wirklich ein „square“ (was immer das heißt auf der Oberfläche einer Kugel), aber es sollte tun.

Sie sollten beachten, dass der Abstand in Grad auf der Breite des Mittelpunktes abhängt. Am Äquator 1 Breitengrad ist etwa 111km, aber in New York, es ist nur etwa 75km.

Die wirklich coole Sache ist, dass Sie alle Ihre Punkte in eine com.vividsolutions.jts.index.strtree.STRtree werfen können und es dann schnell Punkte innerhalb dieses Umschlags verwenden zu berechnen.

Alle bisherigen Antworten sind nur teilweise richtig.Besonders in Regionen wie Australien berücksichtigen sie immer die Stange und berechnen selbst für 10 km ein sehr großes Rechteck.

Speziell der Algorithmus von Jan Philip Matuschek at http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex enthielt ein sehr großes Rechteck von (-37, -90, -180, 180) für fast jeden Punkt in Australien.Dies betrifft eine große Benutzerdatenbank und die Entfernung muss für alle Benutzer in fast der Hälfte des Landes berechnet werden.

Ich fand das Drupal API Earth-Algorithmus vom Rochester Institute of Technology Funktioniert sowohl rund um die Stange als auch anderswo besser und ist viel einfacher zu implementieren.

https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54

Verwenden earth_latitude_range Und earth_longitude_range aus dem obigen Algorithmus zur Berechnung des Begrenzungsrechtecks

Hier ist die Implementierung 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;
    }

Und nutzen Sie die Von Google Maps dokumentierte Entfernungsberechnungsformel Entfernung berechnen

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

Um nach Kilometern statt nach Meilen zu suchen, ersetzen Sie 3959 durch 6371.Für (Lat, Lng) = (37, -122) und eine Markierungstabelle mit den Spalten lat und lng, die Formel lautet:

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;

Hier ist eine einfache Lösung, die ich Box zu erzeugen verwendet, um begrenzenden Koordinaten, die ich mit GeoNames citieJSON API bekommen in der Nähe großer Städte von einem gPS-Dezimalkoordinate.

Dies ist eine Java-Methode von meiner GitHub-Repository: FusionTableModifyJava

Ich hatte eine Dezimalzahl GPS-Position und ich brauchte die größte Stadt / Staat „in der Nähe“, dass die Lage zu finden. Ich brauchte einen relativ genauen Begrenzungsrahmen an der citiesJSON GeoNames webservice passiert die größte Stadt in dieser Zeichen-Box zu kommen. Ich gebe die Lage und den „Radius“ Ich bin an (in km) und es gibt den Norden zurück, Süden, Osten, Westen dezimale Koordinaten benötigt, um citiesJSON zu passieren.

(Ich fand diese Ressourcen sinnvoll in meiner Forschung zu tun:

Entfernung zu berechnen, Lager und mehr zwischen Breite / Länge Punkten.

Longitude - Wikipedia )

Es ist nicht super genau, aber genau genug für das, was ich benutze es für:

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

    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top