tutorial que nominatim longitude latitude great example code python gis distance latitude-longitude

python - nominatim - que es great circle distance



Obtener lat/long dado el punto actual, la distancia y el rodamiento (11)

Aquí hay una versión de PHP basada en el formulario de aviación de Ed Williams. Módulo se maneja un poco diferente en PHP. Esto funciona para mí.

function get_new_waypoint ( $lat, $lon, $radial, $magvar, $range ) { // $range in nm. // $radial is heading to or bearing from // $magvar for local area. $range = $range * pi() /(180*60); $radial = $radial - $magvar ; if ( $radial < 1 ) { $radial = 360 + $radial - $magvar; } $radial = deg2rad($radial); $tmp_lat = deg2rad($lat); $tmp_lon = deg2rad($lon); $new_lat = asin(sin($tmp_lat)* cos($range) + cos($tmp_lat) * sin($range) * cos($radial)); $new_lat = rad2deg($new_lat); $new_lon = $tmp_lon - asin(sin($radial) * sin($range)/cos($new_lat))+ pi() % 2 * pi() - pi(); $new_lon = rad2deg($new_lon); return $new_lat." ".$new_lon; }

Dado un punto existente en lat / long, distancia en (en KM) y rumbo (en grados convertidos a radianes), me gustaría calcular el nuevo lat / long. This sitio aparece una y otra vez, pero no puedo conseguir que la fórmula funcione para mí.

Las fórmulas que se han tomado del enlace anterior son:

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ)) lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))

La fórmula anterior es para MSExcel donde:

asin = arc sin() d = distance (in any unit) R = Radius of the earth (in the same unit as above) and hence d/r = is the angular distance (in radians) atan2(a,b) = arc tan(b/a) θ is the bearing (in radians, clockwise from north);

Aquí está el código que tengo en Python.

import math R = 6378.1 #Radius of the Earth brng = 1.57 #Bearing is 90 degrees converted to radians. d = 15 #Distance in km #lat2 52.20444 - the lat result I''m hoping for #lon2 0.36056 - the long result I''m hoping for. lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians lat2 = math.asin( math.sin(lat1)*math.cos(d/R) + math.cos(lat1)*math.sin(d/R)*math.cos(brng)) lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1), math.cos(d/R)-math.sin(lat1)*math.sin(lat2)) print(lat2) print(lon2)

yo obtengo

lat2 = 0.472492248844 lon2 = 79.4821662373


Esta pregunta es conocida como el problema directo en el estudio de la geodesy .

Esta es de hecho una pregunta muy popular y una causa constante de confusión. La razón es que la mayoría de las personas está buscando una respuesta simple y directa. Pero no hay ninguno, porque la mayoría de las personas que hacen esta pregunta no proporcionan suficiente información, simplemente porque no son conscientes de que:

  1. La Tierra no es una esfera perfecta, ya que está aplanada / comprimida por sus polos
  2. Debido a que (1) la tierra no tiene un radio constante, R Ver here
  3. La Tierra no es perfectamente lisa (variaciones de altitud) etc.
  4. Debido al movimiento de la placa tectónica, la posición lat / lon de un punto geográfico puede cambiar varios milímetros (al menos), cada año.

Por lo tanto, hay muchos supuestos diferentes que se utilizan en los diversos modelos geométricos que se aplican de manera diferente, dependiendo de la precisión necesaria. Entonces, para responder a la pregunta, debe considerar qué precisión le gustaría obtener su resultado.

Algunos ejemplos:

  • Solo estoy buscando una ubicación aproximada a los pocos kilómetros más cercanos para distancias pequeñas ( < 100 km) en latitudes entre 0 y 0-70 deg N | S. (La tierra es ~ modelo plano.)
  • Quiero una respuesta que sea buena en cualquier parte del mundo, pero solo precisa unos pocos metros
  • Quiero un posicionamiento súper preciso que sea válido hasta escalas atómicas de nanometers [nm].
  • Quiero respuestas que sean muy rápidas y fáciles de calcular y que no sean computacionalmente intensivas.

Así que puedes tener muchas opciones en qué algoritmo usar. Además, cada lenguaje de programación tiene su propia implementación o "paquete" multiplicado por la cantidad de modelos y las necesidades específicas de los desarrolladores de modelos. Para todos los propósitos prácticos aquí, vale la pena ignorar cualquier otro lenguaje aparte de javascript , ya que se parece mucho al pseudocódigo por su naturaleza. Por lo tanto, se puede convertir fácilmente a cualquier otro idioma, con cambios mínimos.

Entonces los principales modelos son:

  • Euclidian/Flat earth model : bueno para distancias muy cortas de menos de 10 km
  • Spherical model : bueno para grandes distancias longitudinales, pero con una pequeña diferencia latitudinal. Modelo popular:
    • Haversine : precisión del metro en escalas [km], código muy simple.
  • Ellipsoidal models : los más precisos en cualquier lat / lon y distancia, pero sigue siendo una aproximación numérica que depende de la precisión que necesite. Algunos modelos populares son:
    • Lambert : ~ 10 metros de precisión sobre 1000 de km .
    • Paul D. Thomas : aproximación de Andoyer-Lambert
    • Vincenty : milímetro de precisión y eficiencia computacional.
    • Kerney : precisión nanométrica

Referencias:


La biblioteca geopy soporta esto:

import geopy from geopy.distance import VincentyDistance # given: lat1, lon1, b = bearing in degrees, d = distance in kilometers origin = geopy.Point(lat1, lon1) destination = VincentyDistance(kilometers=d).destination(origin, b) lat2, lon2 = destination.latitude, destination.longitude

Encontrado a través de https://.com/a/4531227/37610


Necesario para convertir respuestas de radianes a grados. Código de trabajo a continuación:

import math R = 6378.1 #Radius of the Earth brng = 1.57 #Bearing is 90 degrees converted to radians. d = 15 #Distance in km #lat2 52.20444 - the lat result I''m hoping for #lon2 0.36056 - the long result I''m hoping for. lat1 = math.radians(52.20472) #Current lat point converted to radians lon1 = math.radians(0.14056) #Current long point converted to radians lat2 = math.asin( math.sin(lat1)*math.cos(d/R) + math.cos(lat1)*math.sin(d/R)*math.cos(brng)) lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1), math.cos(d/R)-math.sin(lat1)*math.sin(lat2)) lat2 = math.degrees(lat2) lon2 = math.degrees(lon2) print(lat2) print(lon2)


Pasé la respuesta de @David M a java si alguien quería esto ... Obtengo un resultado ligeramente diferente de 52.20462299620793, 0.360433887489931

double R = 6378.1; //Radius of the Earth double brng = 1.57; //Bearing is 90 degrees converted to radians. double d = 15; //Distance in km double lat2 = 52.20444; // - the lat result I''m hoping for double lon2 = 0.36056; // - the long result I''m hoping for. double lat1 = Math.toRadians(52.20472); //Current lat point converted to radians double lon1 = Math.toRadians(0.14056); //Current long point converted to radians lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng)); lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2)); lat2 = Math.toDegrees(lat2); lon2 = Math.toDegrees(lon2); System.out.println(lat2 + ", " + lon2);


Porté el Python a Javascript. Esto devuelve un objeto de Location Bing Maps, puedes cambiarlo a lo que quieras.

getLocationXDistanceFromLocation: function(latitude, longitude, distance, bearing) { // distance in KM, bearing in degrees var R = 6378.1, // Radius of the Earth brng = Math.radians(bearing) // Convert bearing to radian lat = Math.radians(latitude), // Current coords to radians lon = Math.radians(longitude); // Do the math magic lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng)); lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance/R)-Math.sin(lat)*Math.sin(lat)); // Coords back to degrees and return return new Microsoft.Maps.Location(Math.degrees(lat), Math.degrees(lon)); },


Porté la respuesta de Brad a la respuesta de vanilla JS, sin dependencia de los mapas de Bing

https://jsfiddle.net/kodisha/8a3hcjtd/

// ---------------------------------------- // Calculate new Lat/Lng from original points // on a distance and bearing (angle) // ---------------------------------------- let llFromDistance = function(latitude, longitude, distance, bearing) { // taken from: https://.com/a/46410871/13549 // distance in KM, bearing in degrees const R = 6378.1; // Radius of the Earth const brng = bearing * Math.PI / 180; // Convert bearing to radian let lat = latitude * Math.PI / 180; // Current coords to radians let lon = longitude * Math.PI / 180; // Do the math magic lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng)); lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance / R) - Math.sin(lat) * Math.sin(lat)); // Coords back to degrees and return return [(lat * 180 / Math.PI), (lon * 180 / Math.PI)]; } let pointsOnMapCircle = function(latitude, longitude, distance, numPoints) { const points = []; for (let i = 0; i <= numPoints - 1; i++) { const bearing = Math.round((360 / numPoints) * i); console.log(bearing, i); const newPoints = llFromDistance(latitude, longitude, distance, bearing); points.push(newPoints); } return points; } const points = pointsOnMapCircle(41.890242042122836, 12.492358982563019, 0.2, 8); let geoJSON = { "type": "FeatureCollection", "features": [] }; points.forEach((p) => { geoJSON.features.push({ "type": "Feature", "properties": {}, "geometry": { "type": "Point", "coordinates": [ p[1], p[0] ] } }); }); document.getElementById(''res'').innerHTML = JSON.stringify(geoJSON, true, 2);

Además, agregué la exportación de geoJSON, así que simplemente puedes pegar el geoJSON resultante en http://geojson.io/#map=17/41.89017/12.49171 y ver los resultados al instante.

Resultado:


Puede ser un poco tarde para responder, pero después de probar las otras respuestas, parece que no funcionan correctamente. Aquí hay un código PHP que usamos para nuestro sistema. Trabajando en todas las direcciones.

Código PHP:

lat1 = latitud del punto de inicio en grados

long1 = longitud del punto de inicio en grados

d = distancia en KM

ángulo = rodamiento en grados

function get_gps_distance($lat1,$long1,$d,$angle) { # Earth Radious in KM $R = 6378.14; # Degree to Radian $latitude1 = $lat1 * (M_PI/180); $longitude1 = $long1 * (M_PI/180); $brng = $angle * (M_PI/180); $latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng)); $longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2)); # back to degrees $latitude2 = $latitude2 * (180/M_PI); $longitude2 = $longitude2 * (180/M_PI); # 6 decimal for Leaflet and other system compatibility $lat2 = round ($latitude2,6); $long2 = round ($longitude2,6); // Push in array and get back $tab[0] = $lat2; $tab[1] = $long2; return $tab; }


Simplemente intercambie los valores en la función atan2 (y, x). No atan2 (x, y)!


También tarde, pero para aquellos que puedan encontrar esto, obtendrás resultados más precisos utilizando la biblioteca de biblioteca geographiclib . Consulte las descripciones de problemas geodésicos y los ejemplos de JavaScript para obtener una introducción fácil a cómo usar la respuesta a la pregunta del tema, así como a muchas otras. Implementaciones en una variedad de lenguajes incluyendo Python. Mucho mejor que codificar el tuyo si te importa la precisión; mejor que VincentyDistance en la recomendación anterior de "usar una biblioteca". Como dice la documentación: "El énfasis está en devolver resultados precisos con errores cercanos al redondeo (alrededor de 5 a 15 nanómetros)".


lon1 y lat1 en grados

brng = rodamiento en radianes

d = distancia en km

R = radio de la Tierra en km

lat2 = math.degrees((d/R) * math.cos(brng)) + lat1 long2 = math.degrees((d/(R*math.sin(math.radians(lat2)))) * math.sin(brng)) + long1

Implementé tu algoritmo y el mío en PHP y lo comparé. Esta versión se ejecutó en aproximadamente el 50% del tiempo. Los resultados generados fueron idénticos, por lo que parece ser matemáticamente equivalente.

No probé el código de Python anterior, así que podría haber errores de sintaxis.