Domanda

Dato una coordinata (lat, long), sto cercando di calcolare un rettangolo di selezione quadrata che è una certa distanza (ad esempio 50 km) di distanza dal punto. Così come input ho lat, lunga e la distanza e come uscita Vorrei due coordinate; uno è il sud-ovest angolo (in basso a sinistra) e uno che è il nord-est (in alto a destra) calcio d'angolo. Ho visto un paio di risposte su qui che cercano di affrontare la questione in Python, ma sono alla ricerca di un'implementazione Java in particolare.

Giusto per essere chiari, ho intenzione di utilizzare l'algoritmo unico sulla Terra e quindi non ho bisogno di ospitare un raggio variabile.

Non deve essere estremamente accurata (+/- 20% va bene) e sarà utilizzato esclusivamente per calcolare scatole balzando per piccole distanze (non più di 150 km). Quindi sono felice di sacrificare una certa precisione per un algoritmo efficiente. Ogni aiuto è molto apprezzato.

Edit: avrei dovuto essere più chiaro, sono davvero dopo una piazza, non un cerchio. Ho capito che la distanza tra il centro di un quadrato e vari punti lungo il perimetro del quadrato non è un valore costante come è con un cerchio. Credo che quello che dire è un quadrato dove se si traccia una linea dal centro di uno qualsiasi dei quattro punti sul perimetro che si traduce in una linea perpendicolare ad un lato del perimetro, allora quelle 4 linee hanno la stessa lunghezza.

È stato utile?

Soluzione

ho scritto un articolo su come trovare la delimitazione coordinate:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

L'articolo spiega le formule e fornisce anche un'implementazione Java. (Essa mostra anche il motivo per cui la formula di IronMan per il min / max longitudine è imprecisa.)

Altri suggerimenti

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

Anche se consiglierei anche JTS.

import com.vividsolutions.jts.geom.Envelope;

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

Ora ENV contiene la busta. Non è in realtà una "piazza" (qualunque cosa significhi sulla superficie di una sfera), ma si dovrebbe fare.

Si dovrebbe notare che la distanza in gradi dipenderà dalla latitudine del punto centrale. All'equatore, 1 grado di latitudine è di circa 111 chilometri, ma a New York, è solo circa 75 km.

La cosa veramente interessante è che si può buttare tutti i punti in una com.vividsolutions.jts.index.strtree.STRtree e poi usarlo per calcolare rapidamente i punti all'interno di quella busta.

Tutte le risposte precedenti sono solo parzialmente corrette . Specialmente nella regione come l'Australia, che includono sempre palo e calcolano un grande rettangolo anche per 10 km.

specialmente l'algoritmo di Jan Philip Matuschek a http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex incluso un grande rettangolo da (-37, -90, -180, 180) per quasi ogni punto in Australia. Questo colpisce un grande utenti nel database e la distanza deve essere calcolato per tutti gli utenti in quasi la metà del paese.

Ho trovato che il Drupal API Algoritmo Terra Rochester Institute of Technology funziona meglio intorno al polo, così come altrove, ed è molto più facile da implementare.

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

Usa earth_latitude_range e earth_longitude_range dal algoritmo di cui sopra per il calcolo rettangolo di delimitazione

Ecco l'implementazione è 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;
    }

E utilizzare il formula di calcolo della distanza documentato da mappe Google per calcolare la distanza

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

Per cercare per chilometri, invece di miglia, sostituire 3959 con 6371. Per (lat, GNL) = (37, -122) e un tavolo marcatori con colonne e lat lng , la formula è:

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;

Ecco una soluzione semplice che ho usato per generare rettangolo di selezione coordinate che uso con GeoNames citieJSON API per ottenere vicina grandi città da un decimale coordinate GPS.

Questo è un metodo Java dal mio repository GitHub: FusionTableModifyJava

Ho avuto un posizione GPS decimale e avevo bisogno di trovare la più grande città / stato "vicino" quella posizione. Avevo bisogno di un relativamente accurata rettangolo di selezione per passare al webservice citiesJSON GeoNames per tornare la città più grande in quel rettangolo di selezione. Io passo la posizione e il "raggio" Sono interessato a (in km) e dà indietro il nord, sud, est, ovest coordinate decimali necessari per passare al citiesJSON.

(Ho trovato queste risorse utili nel fare la mia ricerca:

calcolare la distanza, il cuscinetto e più dalla latitudine / longitudine punti.

Longitudine - Wikipedia )

Non è super-accurate ma abbastanza preciso per quello che stavo usando per:

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

    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top