Получить широту / долготу с учетом текущей точки, расстояния и пеленга - PullRequest
58 голосов
/ 28 августа 2011

Учитывая существующую точку в широте / длине, расстояние в (в км) и азимут (в градусах, переведенных в радианы), я хотел бы рассчитать новый широту / длину. Этот сайт появляется снова и снова, но я просто не могу заставить формулу работать на меня.

Формулы, взятые по вышеуказанной ссылке:

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

Приведенная выше формула предназначена для MSExcel, где-

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

Вот код, который я получил на 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)

Я получаю

lat2 = 0.472492248844 
lon2 = 79.4821662373

Ответы [ 12 ]

62 голосов
/ 20 октября 2011

Необходим для преобразования ответов из радиан обратно в градусы. Рабочий код ниже:

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)
26 голосов
/ 26 марта 2012

Библиотека geopy поддерживает это:

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

Найдено через https://stackoverflow.com/a/4531227/37610

10 голосов
/ 14 ноября 2014

Может быть немного поздно для ответа, но после тестирования других ответов, кажется, что они не работают правильно.Вот код PHP, который мы используем для нашей системы.Работает во всех направлениях.

PHP-код:

lat1 = широта начальной точки в градусах

long1 = долгота начальной точки в градусах

d = расстояние в км

угол = азимут в градусах

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;
 }
9 голосов
/ 28 января 2018

Этот вопрос известен как прямая проблема при изучении геодезии .

Это действительно очень популярный вопрос, который постоянно вызывает путаницу. Причина в том, что большинство людей ищут простой и прямой ответ. Но их нет, потому что большинство людей, задающих этот вопрос, не предоставляют достаточно информации просто потому, что не знают, что:

  1. Земля не является идеальной сферой, поскольку она уплощена / сжата полюсами
  2. Из-за (1) земля не имеет постоянного радиуса, R. Смотри здесь .
  3. Земля не совсем гладкая (колебания высоты) и т. Д.
  4. Из-за движения тектонических плит положение географической точки может изменяться на несколько миллиметров (как минимум) каждый год.

Поэтому в различных геометрических моделях используется много разных допущений, которые применяются по-разному, в зависимости от вашей необходимой точности. Таким образом, чтобы ответить на вопрос, нужно учитывать, с какой точностью вы хотели бы получить свой результат.

Некоторые примеры:

  • Я просто ищу приблизительное местоположение до ближайших нескольких километров для небольших ( <</strong> 100 км) расстояний в latitudes между 0-70 deg N | S . (Земля - ​​плоская модель.)
  • Я хочу получить ответ, который был бы хорош в любой точке земного шара, но с точностью до нескольких метров
  • Я хочу сверхточное позиционирование, действительное вплоть до атомных масштабов nanometers [нм].
  • Мне нужны ответы, которые очень быстро и легко вычислить и не требуют больших вычислительных ресурсов.

Таким образом, вы можете иметь много вариантов выбора алгоритма. Кроме того, каждый язык программирования имеет свою собственную реализацию или «пакет», умноженный на количество моделей и конкретные потребности разработчиков моделей. Для всех практических целей здесь стоит игнорировать любой другой язык, кроме javascript, поскольку по своей природе он очень похож на псевдокод. Таким образом, его можно легко преобразовать в любой другой язык с минимальными изменениями.

Тогда основные модели:

  • Euclidian/Flat earth model: хорошо для очень коротких расстояний до ~ 10 км
  • Spherical model: подходит для больших продольных расстояний, но с небольшой разницей в широте. Популярная модель:
    • Haversine : метр точность по [км] шкалам, очень простой код.
  • Ellipsoidal models: Наиболее точный на любом широте и долготе и расстоянии, но все еще числовое приближение, которое зависит от того, какая точность вам нужна. Некоторые популярные модели:
    • Ламберт : ~ 10 метров точность свыше 1000-х км .
    • Пол Д. Томас : приближение Андойера-Ламберта
    • Vincenty : миллиметр точность и вычислительная эффективность
    • Керни : нанометр точность

Ссылка:

3 голосов
/ 01 июля 2013

lon1 и lat1 в градусах

brng = подшипник в радианах

d = расстояние в км

R = радиус Земли в км

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

Я реализовал ваш алгоритм и мой в PHP и протестировал его. Эта версия работала примерно в 50% случаев. Полученные результаты были идентичны, поэтому, похоже, математически эквивалентны.

Я не тестировал приведенный выше код Python, поэтому возможны синтаксические ошибки.

2 голосов
/ 05 января 2019

Быстрый способ с использованием geopy

from geopy import distance
#distance.distance(unit=15).destination((lat,lon),bering) 
#Exemples
distance.distance(nautical=15).destination((-24,-42),90) 
distance.distance(miles=15).destination((-24,-42),90)
distance.distance(kilometers=15).destination((-24,-42),90) 
2 голосов
/ 09 августа 2018

Я перенес ответ от Брэда на ванильный ответ JS, без зависимости от карт 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://stackoverflow.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);

Кроме того, я добавил экспорт geoJSON, так что вы можете просто вставить полученный geoJSON в http://geojson.io/#map=17/41.89017/12.49171 и мгновенно смотрите результаты.

Результат: geoJSON Screenshot

1 голос
/ 01 марта 2016

Просто поменяйте местами значения в функции atan2 (y, x). Не atan2 (x, y)!

1 голос
/ 25 ноября 2014

Также поздно, но для тех, кто может найти это, вы получите более точные результаты, используя библиотеку geographiclib . Ознакомьтесь с описаниями геодезических задач и примерами JavaScript, чтобы легко узнать, как их использовать, чтобы ответить на предметный вопрос, а также для многих других. Реализации на разных языках, включая Python. Намного лучше, чем кодировать свои собственные, если вы заботитесь о точности; лучше, чем VincentyDistance в более ранней рекомендации «использовать библиотеку». Как сказано в документации: «Акцент делается на возвращении точных результатов с ошибками, близкими к округлению (около 5–15 нанометров)».

0 голосов
/ 16 ноября 2018

Я портировал ответ от @David M на java, если кто-то хотел этого ... Я получаю немного другой результат: 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...