que puntos longitud latitud google geograficas entre distancias distancia coordenadas construya con comparar como calcule calcular algoritmo math geospatial trigonometry latitude-longitude bounding-box

math - longitud - construya un algoritmo que calcule la distancia entre dos puntos



Cálculo del cuadro delimitador a cierta distancia de una coordenada lat/long en Java (7)

Dada una coordenada (lat, long), estoy tratando de calcular un cuadro delimitador cuadrado que está a una distancia determinada (por ejemplo, 50 km) de distancia de la coordenada. Así que como entrada tengo lat, long y distance y como salida me gustaría dos coordenadas; una es la esquina suroeste (esquina inferior izquierda) y una esquina noreste (esquina superior derecha). He visto un par de respuestas aquí que intentan abordar esta cuestión en Python, pero estoy buscando una implementación de Java en particular.

Solo para ser claros, tengo la intención de usar el algoritmo solo en la Tierra y por lo tanto no necesito acomodar un radio variable.

No tiene que ser muy preciso (+/- 20% está bien) y solo se usará para calcular cuadros de delimitación en distancias pequeñas (no más de 150 km). Así que estoy feliz de sacrificar algo de precisión por un algoritmo eficiente. Cualquier ayuda es muy apreciada.

Editar: Debería haber sido más claro, realmente estoy buscando un cuadrado, no un círculo. Entiendo que la distancia entre el centro de un cuadrado y varios puntos a lo largo del perímetro del cuadrado no es un valor constante como lo es con un círculo. Supongo que lo que quiero decir es un cuadrado donde si dibujas una línea desde el centro hacia cualquiera de los cuatro puntos del perímetro que da como resultado una línea perpendicular a un lado del perímetro, esas 4 líneas tienen la misma longitud.


Aquí hay una solución simple que utilicé para generar coordenadas de cuadro delimitador que uso con GeoNames citieJSON API para obtener ciudades grandes cercanas desde una coordenada decimal gps.

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

Tenía una ubicación GPS decimal y necesitaba encontrar la ciudad / estado más grande "cerca" de esa ubicación. Necesitaba un recuadro delimitador relativamente preciso para pasar al servicio web de la ciudad de GeoNamesJSON para recuperar la ciudad más grande en ese cuadro delimitador. Paso la ubicación y el "radio" en el que estoy interesado (en km) y devuelve las coordenadas decimales norte, sur, este, oeste necesarias para pasar a las ciudades JSON.

(Encontré estos recursos útiles para hacer mi investigación:

Calcule distancia, rumbo y más entre puntos de latitud / longitud.

Longitud - Wikipedia )

No es súper preciso pero lo suficientemente preciso para lo que lo estaba usando:

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


Escribí un artículo sobre cómo encontrar las coordenadas de límite:

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 la longitud mínima / máxima es inexacta).



Todas las respuestas anteriores son parcialmente correctas . Especialmente en regiones como Australia, siempre incluyen polos y calculan un rectángulo muy grande incluso para 10kms.

Especialmente el algoritmo de Jan Philip Matuschek en http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex incluía un rectángulo muy grande de (-37, -90, -180, 180) para casi todos los puntos en Australia. Esto afecta a los usuarios grandes en la base de datos y la distancia debe calcularse para todos los usuarios en casi la mitad del país.

Descubrí que el algoritmo de la Tierra Drupal API del Rochester Institute of Technology funciona mejor en los polos y 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

Utilice earth_latitude_range y earth_longitude_range del algoritmo anterior para calcular el rectángulo delimitador

Aquí está la implementación es 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 use la fórmula de cálculo de distancia documentada 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, reemplace 3959 con 6371. Para (Lat, Lng) = (37, -122) y una tabla de marcadores 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;


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

Aunque también recomendaría JTS.

Esto calcula, pero Google Earth no acepta y no asigna el modelo 3D.

/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package assetmap; public class Main { public double degrees; public double pi= 3.1416; public static double lon=80.304737; public static double lat=26.447521; public static double x1,x2,y1,y2; public static void main(String[] args) { double R = 6371; // earth radius in km 26.447521 double radius = 0.300; // km x1 = (lon - Math.toDegrees(radius / R / Math.cos(Math.toRadians(lat)))); x2 = (lon + Math.toDegrees(radius / R / Math.cos(Math.toRadians(lat)))); y1 = (lat + Math.toDegrees(radius / R)); y2 = (lat - Math.toDegrees(radius / R)); System.out.println(x1+"---|"+x2+"---|"+y1+"|---|"+y2); } }

Imprime

80.30172366789824---|80.30775033210176---|26.450218964817754|---|26.444823035182242

KML:

<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"> <Placemark> <name>United Nations Headquarters</name> <Region> <LatLonAltBox> <north>26.447251203518224</north> <south>26.447790796481772</south> <east>80.30503833321018</east> <west>80.30443566678983</west> <minAltitude>0</minAltitude> <maxAltitude>30</maxAltitude> <altitudeMode>absolute</altitudeMode> </LatLonAltBox> <Lod> <minLodPixels>128</minLodPixels> <maxLodPixels>-1</maxLodPixels> <minFadeExtent>0</minFadeExtent> <maxFadeExtent>0</maxFadeExtent> </Lod> </Region> <Model id="model_1"> <altitudeMode>absolute</altitudeMode> <Location> <longitude>80.304737</longitude> <latitude>26.447521</latitude> <altitude>0.406173708576</altitude> </Location> <Orientation> <heading>0</heading> <tilt>0</tilt> <roll>0</roll> </Orientation> <Scale> <x>10</x> <y>10</y> <z>10</z> </Scale> <Link> <href>un.dae</href> </Link> <ResourceMap> <Alias> <targetHref>_01.jpg</targetHref> <sourceHref>../images/_01.jpg</sourceHref> </Alias> <Alias> <targetHref>_02.jpg</targetHref> <sourceHref>../images/_02.jpg</sourceHref> </Alias> <Alias> <targetHref>_04.jpg</targetHref> <sourceHref>../images/_04.jpg</sourceHref> </Alias> <Alias> <targetHref>_05.jpg</targetHref> <sourceHref>../images/_05.jpg</sourceHref> </Alias> <Alias> <targetHref>_06.jpg</targetHref> <sourceHref>../images/_06.jpg</sourceHref> </Alias> <Alias> <targetHref>_07.jpg</targetHref> <sourceHref>../images/_07.jpg</sourceHref> </Alias> <Alias> <targetHref>_08.jpg</targetHref> <sourceHref>../images/_08.jpg</sourceHref> </Alias> <Alias> <targetHref>_09.jpg</targetHref> <sourceHref>../images/_09.jpg</sourceHref> </Alias> </ResourceMap> </Model> </Placemark> </kml>


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

Aunque también recomendaría JTS.


import com.vividsolutions.jts.geom.Envelope; ... Envelope env = new Envelope(centerPoint.getCoordinate()); env.expandBy(distance_in_degrees); ...

Ahora env contiene tu sobre. En realidad no es un "cuadrado" (lo que sea que eso signifique en la superficie de una esfera), pero debería funcionar.

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 km, pero en Nueva York, solo hay unos 75 km.

Lo realmente genial es que puedes mezclar todos tus puntos en un com.vividsolutions.jts.index.strtree.STRtree y luego usarlo para calcular rápidamente los puntos dentro de ese sobre.