Pregunta

Dada una coordenada (lat, long), estoy tratando de calcular un cuadrado cuadro delimitador que es una distancia determinada (por ejemplo,50 km) de distancia de las coordenadas.Así que ya de entrada me han lat, long y la distancia, y como de salida, me gustaría dos coordenadas;uno es el sur-oeste (abajo-izquierda) de la esquina y uno en el norte-este (arriba a la derecha) de la esquina.He visto un par de respuestas que intentan abordar esta cuestión en Python, pero estoy buscando una implementación de Java en particular.

Para que quede claro, tengo la intención de utilizar el algoritmo en la Tierra sólo lo que no necesitan para dar cabida a un radio variable.

No tiene que ser muy precisa (+/-20% está bien) y que sólo se utiliza para calcular las cajas de contorno en distancias cortas (no más de 150 kilómetros).Así que estoy feliz a sacrificar la precisión de un algoritmo eficiente.Cualquier ayuda es muy apreciada.

Editar:Yo debería haber sido más clara, realmente estoy después de un cuadrado, no un círculo.Entiendo que la distancia entre el centro de un cuadrado y en diversos puntos a lo largo de la plaza del perímetro no es un valor constante, como lo es con un círculo.Supongo que a lo que me refiero es una plaza donde si se dibuja una línea desde el centro a cualquiera de los cuatro puntos en el perímetro que resulta en una línea perpendicular a un lado del perímetro, entonces esas 4 líneas tienen la misma longitud.

¿Fue útil?

Solución

escribí un artículo sobre la búsqueda de la delimitación Coordenadas:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

El artículo explica las fórmulas y también proporciona una implementación de Java. (También muestra por qué la fórmula de IronMan para el min / max longitud está incorrecto.)

Otros consejos

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

A pesar de que también recomiendo JTS.

import com.vividsolutions.jts.geom.Envelope;

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

Ahora env contiene el sobre. No es en realidad un "cuadrado" (lo que significa en la superficie de una esfera), pero se debe hacer.

Debe tener en cuenta que la distancia en grados dependerá de la latitud del punto central. En el ecuador, 1 grado de latitud es de aproximadamente 111 kilometros, pero en Nueva York, es sólo a unos 75 kilómetros.

Lo realmente bueno es que se puede tirar todos sus puntos en un com.vividsolutions.jts.index.strtree.STRtree y luego usarlo para calcular rápidamente los puntos dentro de ese sobre.

Todas las respuestas anteriores son sólo parcialmente correcta.Especialmente en la región como Australia, que siempre incluyen polo y calcular un rectángulo muy grande, incluso para los 10kms.

Especialmente el algoritmo por Jan Philip Matuschek en http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex incluye un gran rectángulo de (-37, -90, -180, 180) para casi todos los puntos en Australia.Este golpea a un gran número de usuarios en la base de datos y la distancia se han calculado para todos los usuarios en casi la mitad del país.

He encontrado que la La API de Drupal Tierra Algoritmo por el Instituto de Tecnología de Rochester funciona mejor alrededor de polo, así como en otros lugares y es mucho más fácil de implementar.

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

Uso earth_latitude_range y earth_longitude_range desde el anterior algoritmo para calcular el rectángulo delimitador

Aquí está la aplicación 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;
    }

Y el uso de la cálculo de la distancia de fórmula documentado por google maps para calcular la distancia

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

Para buscar por kilómetros en lugar de millas, reemplazar 3959 con 6371.Para (Lat, Lng) = (37, -122) y Marcadores de tabla con columnas lat y lng, la fórmula es:

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;

Esta es una solución simple que he usado para generar el cuadro delimitador coordenadas que utilizo con GeoNames citieJSON API para conseguir las inmediaciones de las grandes ciudades decimal coordenada GPS.

Este es un método Java desde mi repositorio GitHub: FusionTableModifyJava

Yo tenía una ubicación GPS decimal y necesitaba encontrar la mayor ciudad / estado "cerca" ese lugar. Necesitaba un cuadro de límite relativamente precisa para pasar al servicio web citiesJSON GeoNames para volver la ciudad más grande en ese cuadro delimitador. Que paso por el lugar y el "radio" Me interesa (en km) y devuelve el norte, sur, este, oeste coordenadas decimales necesarios para pasar a citiesJSON.

(He encontrado estos recursos útiles en hacer mi investigación:

calcular la distancia, cojinete y más entre la latitud / longitud puntos.

Longitud - Wikipedia )

No es muy exacto, pero lo suficientemente preciso para lo que lo estaba usando para:

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

    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top