Найти расстояние между двумя координатами в mongodb [duplicate]

Я исправил эту проблему в Eclipse, переименовав тестовый файл Junit. В моем рабочем пространстве Eclipse у меня есть проект приложения и тестовый проект. Проект Test имеет проект App как необходимый проект на пути сборки.

Началось получение NoSuchMethodError. Затем я понял, что класс в проекте Test имеет то же имя, что и класс в проекте приложения.

App/  
  src/
     com.example/  
       Projection.java
Test/  
  src/
     com.example/
       Projection.java

После переименования теста на правильное имя «ProjectionTest.java» исключение исчезло.

296
задан Peter O. 22 November 2016 в 13:26
поделиться

24 ответа

Рассчитать расстояние между двумя координатами по широте и долготе , включая реализацию Javascript.

West и South местоположения являются отрицательными. Помните, что минуты и секунды вышли из 60, поэтому S31 30 'составляет -31,50 градусов.

Не забудьте конвертировать градусы в радианы . У многих языков есть эта функция. Или его простой расчет: radians = degrees * PI / 180.

function degreesToRadians(degrees) {
  return degrees * Math.PI / 180;
}

function distanceInKmBetweenEarthCoordinates(lat1, lon1, lat2, lon2) {
  var earthRadiusKm = 6371;

  var dLat = degreesToRadians(lat2-lat1);
  var dLon = degreesToRadians(lon2-lon1);

  lat1 = degreesToRadians(lat1);
  lat2 = degreesToRadians(lat2);

  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
          Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  return earthRadiusKm * c;
}

Вот несколько примеров использования:

distanceInKmBetweenCoordinates (0,0,0,0) // Расстояние между теми же точками должно быть 0 0 distanceInKmBetweenCoordinates (51.5, 0, 38.8, -77.1) // Из Лондона в Арлингтон 5918.185064088764

311
ответ дан ColdFire 15 August 2018 в 14:38
поделиться
  • 1
    В случае, если это не очевидно, метод toRad () является настройкой прототипа Number , например: Number.prototype.toRad = function() { return this * (Math.PI / 180); }; . Или, как указано ниже, вы можете заменить (Math.PI/2) на 0.0174532925199433 (... любую точность, которую вы сочтете необходимой) для повышения производительности. – Vinney Kelly 23 July 2013 в 07:05
  • 2
    Если кто-то, особенно те из вас, кто не ищет комментарии в конце строки, смотрят на эту формулу и ищут единицу расстояния, единица км. :) – Dylan Knowles 27 September 2013 в 19:01
  • 3
    @VinneyKelly Небольшая опечатка, но замените (Math.PI / 180) нет (Math.PI / 2), спасибо за помощь всем – Patrick Murphy 21 July 2015 в 16:44
  • 4
    @ChristianKRider Посмотрите на первую строчку. Подумайте о том, что R обычно означает в математике, затем найдите соответствующие, связанные с Землей количества, чтобы увидеть, соответствуют ли числа. – Nic Hartley 12 February 2017 в 14:01
  • 5
    Для имперских единиц (миль) вы можете изменить earthRadiusKm на var earthRadiusMiles = 3959;, fyi. – chapeljuice 9 August 2017 в 21:53

Ищите haversine с Google; вот мое решение:

#include <math.h>
#include "haversine.h"

#define d2r (M_PI / 180.0)

//calculate haversine distance for linear distance
double haversine_km(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * d2r;
    double dlat = (lat2 - lat1) * d2r;
    double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
    double c = 2 * atan2(sqrt(a), sqrt(1-a));
    double d = 6367 * c;

    return d;
}

double haversine_mi(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * d2r;
    double dlat = (lat2 - lat1) * d2r;
    double a = pow(sin(dlat/2.0), 2) + cos(lat1*d2r) * cos(lat2*d2r) * pow(sin(dlong/2.0), 2);
    double c = 2 * atan2(sqrt(a), sqrt(1-a));
    double d = 3956 * c; 

    return d;
}
58
ответ дан Jon Winstanley 15 August 2018 в 14:38
поделиться
  • 1
    Вы можете заменить (M_PI / 180.0) на 0.0174532925199433 для лучшей производительности. – Hlung 1 August 2011 в 10:19
  • 2
    С точки зрения производительности: можно было вычислить sin (dlat / 2.0) только один раз, сохранить его в переменной a1, а вместо pow (, 2) лучше использовать a1 * a1. То же самое для другой pow (, 2). – pms 28 October 2011 в 00:34
  • 3
    Да, или просто используйте пост-60s-компилятор. – rightfold 28 January 2014 в 12:45
  • 4
    Нет необходимости «оптимизировать». (M_PI / 180.0) до константы, которую никто не понимает без контекста. Компилятор вычисляет эти фиксированные условия для вас! – Patrick Cornelissen 19 September 2016 в 05:35
  • 5
    @ TõnuSamuel Спасибо за ваш комментарий. Я очень ценю это. Имеет смысл, что компилятор с включенной оптимизацией (-O) может предварительно вычислять операции констант, делая ручное рушительство бесполезным. Я проверю это, когда у меня будет время. – Hlung 2 January 2018 в 16:47

Версия C # для Haversine

double _eQuatorialEarthRadius = 6378.1370D;
double _d2r = (Math.PI / 180D);

private int HaversineInM(double lat1, double long1, double lat2, double long2)
{
    return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2));
}

private double HaversineInKM(double lat1, double long1, double lat2, double long2)
{
    double dlong = (long2 - long1) * _d2r;
    double dlat = (lat2 - lat1) * _d2r;
    double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D);
    double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
    double d = _eQuatorialEarthRadius * c;

    return d;
}

Вот .NET-скрипт этого , так что вы можете проверить его с помощью своего собственного Lat / Longs.

33
ответ дан Mike Chamberlain 15 August 2018 в 14:38
поделиться

// Может быть, ошибка опечатки? У нас есть неиспользуемый переменный dlon в GetDirection, я предполагаю, что

double y = Math.Sin(dlon) * Math.Cos(lat2);
// cannot use degrees in Cos ?

должен быть

double y = Math.Sin(dlon) * Math.Cos(dlat);
7
ответ дан Bo Persson 15 August 2018 в 14:38
поделиться
  • 1
    Это не ответ, это в лучшем случае комментарий. – Kevin 14 November 2012 в 06:18
  • 2
    Это «сферический закон косинусов», расчет, который является наименее точным и наиболее подверженным ошибкам методом вычисления расстояния большого круга. – John Machin 11 January 2017 в 03:30

вы можете найти реализацию этого (с некоторым хорошим объяснением) в F # на fssnip

вот важные части:


let GreatCircleDistance<[<Measure>] 'u> (R : float<'u>) (p1 : Location) (p2 : Location) =
    let degToRad (x : float<deg>) = System.Math.PI * x / 180.0<deg/rad>

    let sq x = x * x
    // take the sin of the half and square the result
    let sinSqHf (a : float<rad>) = (System.Math.Sin >> sq) (a / 2.0<rad>)
    let cos (a : float<deg>) = System.Math.Cos (degToRad a / 1.0<rad>)

    let dLat = (p2.Latitude - p1.Latitude) |> degToRad
    let dLon = (p2.Longitude - p1.Longitude) |> degToRad

    let a = sinSqHf dLat + cos p1.Latitude * cos p2.Latitude * sinSqHf dLon
    let c = 2.0 * System.Math.Atan2(System.Math.Sqrt(a), System.Math.Sqrt(1.0-a))

    R * c
2
ответ дан Carsten 15 August 2018 в 14:38
поделиться

Если вам нужно что-то более точное, тогда посмотрите на это .

Формулы Винценти - это два связанных итерационных метода, используемых в геодезии, для вычисления расстояния между двумя точками на поверхности сфероида, разработанной Таддеусом Винценти (1975а). Они основаны на предположении, что фигура Земли является сплюснутым сфероидом и, следовательно, более точна, чем методы, такие как расстояние между большими кругами, которое принимает сферическую Землю.

Первый (прямой) метод вычисляет местоположение точки, которая является заданным расстоянием и азимутом (направлением) от другой точки. Второй (обратный) метод вычисляет географическое расстояние и азимут между двумя заданными точками. Они широко используются в геодезии, поскольку они точны с точностью до 0,5 мм (0,020 дюйма) на эллипсоиде Земли.

5
ответ дан Chad 15 August 2018 в 14:38
поделиться

Если вы используете .NET, не изобретайте колесо. См. System.Device.Location . Отметьте fnx в комментариях в другом ответе .

using System.Device.Location;

double lat1 = 45.421527862548828D;
double long1 = -75.697189331054688D;
double lat2 = 53.64135D;
double long2 = -113.59273D;

GeoCoordinate geo1 = new GeoCoordinate(lat1, long1);
GeoCoordinate geo2 = new GeoCoordinate(lat2, long2);

double distance = geo1.GetDistanceTo(geo2);
3
ответ дан Community 15 August 2018 в 14:38
поделиться
    private double deg2rad(double deg)
    {
        return (deg * Math.PI / 180.0);
    }

    private double rad2deg(double rad)
    {
        return (rad / Math.PI * 180.0);
    }

    private double GetDistance(double lat1, double lon1, double lat2, double lon2)
    {
        //code for Distance in Kilo Meter
        double theta = lon1 - lon2;
        double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
        dist = Math.Abs(Math.Round(rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344 * 1000, 0));
        return (dist);
    }

    private double GetDirection(double lat1, double lon1, double lat2, double lon2)
    {
        //code for Direction in Degrees
        double dlat = deg2rad(lat1) - deg2rad(lat2);
        double dlon = deg2rad(lon1) - deg2rad(lon2);
        double y = Math.Sin(dlon) * Math.Cos(lat2);
        double x = Math.Cos(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) - Math.Sin(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(dlon);
        double direct = Math.Round(rad2deg(Math.Atan2(y, x)), 0);
        if (direct < 0)
            direct = direct + 360;
        return (direct);
    }

    private double GetSpeed(double lat1, double lon1, double lat2, double lon2, DateTime CurTime, DateTime PrevTime)
    {
        //code for speed in Kilo Meter/Hour
        TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
        double TimeDifferenceInSeconds = Math.Round(TimeDifference.TotalSeconds, 0);
        double theta = lon1 - lon2;
        double dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta));
        dist = rad2deg(Math.Acos(dist)) * 60 * 1.1515 * 1.609344;
        double Speed = Math.Abs(Math.Round((dist / Math.Abs(TimeDifferenceInSeconds)) * 60 * 60, 0));
        return (Speed);
    }

    private double GetDuration(DateTime CurTime, DateTime PrevTime)
    {
        //code for speed in Kilo Meter/Hour
        TimeSpan TimeDifference = CurTime.Subtract(PrevTime);
        double TimeDifferenceInSeconds = Math.Abs(Math.Round(TimeDifference.TotalSeconds, 0));
        return (TimeDifferenceInSeconds);
    }
3
ответ дан Elanchezhian Babu P 15 August 2018 в 14:38
поделиться
  • 1
    Я думаю, что ваша функция GetDistance возвращает значение в метрах – Przemek 21 December 2014 в 15:11
  • 2
    Это верно? GetDirection () не использует 'dlat'. – gubby 28 January 2017 в 13:52

Думаю, ты хочешь этого по искривлению земли. Ваши две точки и центр земли находятся на плоскости. Центр Земли - это центр круга на этой плоскости, и две точки (примерно) расположены по периметру этого круга. Из этого вы можете рассчитать расстояние, узнав, что угол от одной точки к другой.

Если точки не совпадают с высотами, или если вам нужно учитывать, что земля не идеальная сфера становится немного сложнее.

2
ответ дан Guge 15 August 2018 в 14:38
поделиться

Это очень легко сделать с типом географии в SQL Server 2008.

SELECT geography::Point(lat1, lon1, 4326).STDistance(geography::Point(lat2, lon2, 4326))
-- computes distance in meters using eliptical model, accurate to the mm

4326 является SRID для модели эллипсоидальной Земли WGS84

19
ответ дан Marko Tintor 15 August 2018 в 14:38
поделиться

Это версия от «Генри Вилинского», адаптированная для MySQL и километров:

CREATE FUNCTION `CalculateDistanceInKm`(
  fromLatitude float,
  fromLongitude float,
  toLatitude float, 
  toLongitude float
) RETURNS float
BEGIN
  declare distance float;

  select 
    6367 * ACOS(
            round(
              COS(RADIANS(90-fromLatitude)) *
                COS(RADIANS(90-toLatitude)) +
                SIN(RADIANS(90-fromLatitude)) *
                SIN(RADIANS(90-toLatitude)) *
                COS(RADIANS(fromLongitude-toLongitude))
              ,15)
            )
    into distance;

  return  round(distance,3);
END;
3
ответ дан Maxs 15 August 2018 в 14:38
поделиться
  • 1
    MySQL сказал Something is wrong in your syntax near '' on line 8 // declare distance float; – Legionar 2 December 2014 в 14:37
  • 2
    Это «сферический закон косинусов», расчет, который является наименее точным и наиболее подверженным ошибкам методом вычисления расстояния большого круга – John Machin 11 January 2017 в 03:30

Здесь он находится в C # (lat и long в радианах):

double CalculateGreatCircleDistance(double lat1, double long1, double lat2, double long2, double radius)
{
    return radius * Math.Acos(
        Math.Sin(lat1) * Math.Sin(lat2)
        + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(long2 - long1));
}

Если ваш lat и long находятся в градусах, разделите их на 180 / PI для преобразования в радианы.

11
ответ дан Mike Chamberlain 15 August 2018 в 14:38
поделиться
  • 1
    Это «сферический закон косинусов», расчет, который является наименее точным и наиболее подверженным ошибкам методом вычисления расстояния большого круга. – John Machin 11 January 2017 в 03:27

Вот функция Haversine в Python, которую я использую:

from math import pi,sqrt,sin,cos,atan2

def haversine(pos1, pos2):
    lat1 = float(pos1['lat'])
    long1 = float(pos1['long'])
    lat2 = float(pos2['lat'])
    long2 = float(pos2['long'])

    degree_to_rad = float(pi / 180.0)

    d_lat = (lat2 - lat1) * degree_to_rad
    d_long = (long2 - long1) * degree_to_rad

    a = pow(sin(d_lat / 2), 2) + cos(lat1 * degree_to_rad) * cos(lat2 * degree_to_rad) * pow(sin(d_long / 2), 2)
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    km = 6367 * c
    mi = 3956 * c

    return {"km":km, "miles":mi}
13
ответ дан PaulMcG 15 August 2018 в 14:38
поделиться

я взял верхний ответ и использовал его в программе Scala

import java.lang.Math.{atan2, cos, sin, sqrt}

def latLonDistance(lat1: Double, lon1: Double)(lat2: Double, lon2: Double): Double = {
    val earthRadiusKm = 6371
    val dLat = (lat2 - lat1).toRadians
    val dLon = (lon2 - lon1).toRadians
    val latRad1 = lat1.toRadians
    val latRad2 = lat2.toRadians

    val a = sin(dLat / 2) * sin(dLat / 2) + sin(dLon / 2) * sin(dLon / 2) * cos(latRad1) * cos(latRad2)
    val c = 2 * atan2(sqrt(a), sqrt(1 - a))
    earthRadiusKm * c
}

. Я использовал функцию, чтобы иметь возможность легко создавать функции, у которых одно из двух мест исправлено и для получения расстояния требуется только пара lat / lon.

2
ответ дан Peter Perháč 15 August 2018 в 14:38
поделиться

Версия Scala

  def deg2rad(deg: Double) = deg * Math.PI / 180.0

  def rad2deg(rad: Double) = rad / Math.PI * 180.0

  def getDistanceMeters(lat1: Double, lon1: Double, lat2: Double, lon2: Double) = {
    val theta = lon1 - lon2
    val dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) *
      Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta))
    Math.abs(
      Math.round(
        rad2deg(Math.acos(dist)) * 60 * 1.1515 * 1.609344 * 1000)
    )
  }
1
ответ дан Przemek 15 August 2018 в 14:38
поделиться

Версия PHP:

(Удалите все deg2rad(), если ваши координаты уже находятся в радианах.)

$R = 6371; // km
$dLat = deg2rad($lat2-$lat1);
$dLon = deg2rad($lon2-$lon1);
$lat1 = deg2rad($lat1);
$lat2 = deg2rad($lat2);

$a = sin($dLat/2) * sin($dLat/2) +
     sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2); 

$c = 2 * atan2(sqrt($a), sqrt(1-$a)); 
$d = $R * $c;
9
ответ дан quape 15 August 2018 в 14:38
поделиться
  • 1
    Пожалуйста, измените lat1 и lat2 на $ lat1 nad $ lat2. – instead 31 July 2017 в 05:56

здесь реализация Swift из ответа

func degreesToRadians(degrees: Double) -> Double {
    return degrees * Double.pi / 180
}

func distanceInKmBetweenEarthCoordinates(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {

    let earthRadiusKm: Double = 6371

    let dLat = degreesToRadians(degrees: lat2 - lat1)
    let dLon = degreesToRadians(degrees: lon2 - lon1)

    let lat1 = degreesToRadians(degrees: lat1)
    let lat2 = degreesToRadians(degrees: lat2)

    let a = sin(dLat/2) * sin(dLat/2) +
    sin(dLon/2) * sin(dLon/2) * cos(lat1) * cos(lat2)
    let c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return earthRadiusKm * c
}
2
ответ дан Sai Li 15 August 2018 в 14:38
поделиться

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

function distance(lat1, lon1, lat2, lon2) {
  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((lat2 - lat1) * p)/2 + 
          c(lat1 * p) * c(lat2 * p) * 
          (1 - c((lon2 - lon1) * p))/2;

  return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

Вы можете играть с моим jsPerf и видеть результаты здесь .

Недавно мне нужно было сделать то же самое в python, так что вот реализация python:

from math import cos, asin, sqrt
def distance(lat1, lon1, lat2, lon2):
    p = 0.017453292519943295
    a = 0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p)) / 2
    return 12742 * asin(sqrt(a))

И ради полноты: Haversine на wiki.

7
ответ дан Salvador Dali 15 August 2018 в 14:38
поделиться

Это зависит от того, насколько точно вам это нужно, если вам нужна точная точность, лучше всего взглянуть на алгоритм с использованием эллипсоида, а не сферы, такой как алгоритм Винцентия, который точно соответствует миллиметру. http://en.wikipedia.org/wiki/Vincenty%27s_algorithm

15
ответ дан seanb 15 August 2018 в 14:38
поделиться

Java-версия алгоритма Хаверсина, основанная на ответе Романа Макарова на эту тему

public class HaversineAlgorithm {

    static final double _eQuatorialEarthRadius = 6378.1370D;
    static final double _d2r = (Math.PI / 180D);

    public static int HaversineInM(double lat1, double long1, double lat2, double long2) {
        return (int) (1000D * HaversineInKM(lat1, long1, lat2, long2));
    }

    public static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
        double dlong = (long2 - long1) * _d2r;
        double dlat = (lat2 - lat1) * _d2r;
        double a = Math.pow(Math.sin(dlat / 2D), 2D) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r)
                * Math.pow(Math.sin(dlong / 2D), 2D);
        double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
        double d = _eQuatorialEarthRadius * c;

        return d;
    }

}
20
ответ дан Stijn 15 August 2018 в 14:38
поделиться
  • 1
    Дает совершенно неправильный результат для меня – Radu 12 December 2016 в 17:07
  • 2
    @Radu убедитесь, что вы используете его правильно и не обмениваете места lat / log при передаче их любому методу. – Paulo Miguel Almeida 26 December 2016 в 18:48

Мне нужно было реализовать это в PowerShell, надеюсь, что это может помочь кому-то другому. Некоторые примечания об этом методе

  1. Не разделяйте ни одну из строк, или вычисление будет неправильным
  2. Для вычисления в KM удалите * 1000 при расчете $ distance
  3. Измените $ earthsRadius = 3963.19059 и удалите * 1000 при расчете $ distance, чтобы вычислить расстояние в милях
  4. Я использую Haversine, поскольку другие сообщения указывают на формулы Винценти гораздо точнее
    Function MetresDistanceBetweenTwoGPSCoordinates($latitude1, $longitude1, $latitude2, $longitude2)  
    {  
      $Rad = ([math]::PI / 180);  
    
      $earthsRadius = 6378.1370 # Earth's Radius in KM  
      $dLat = ($latitude2 - $latitude1) * $Rad  
      $dLon = ($longitude2 - $longitude1) * $Rad  
      $latitude1 = $latitude1 * $Rad  
      $latitude2 = $latitude2 * $Rad  
    
      $a = [math]::Sin($dLat / 2) * [math]::Sin($dLat / 2) + [math]::Sin($dLon / 2) * [math]::Sin($dLon / 2) * [math]::Cos($latitude1) * [math]::Cos($latitude2)  
      $c = 2 * [math]::ATan2([math]::Sqrt($a), [math]::Sqrt(1-$a))  
    
      $distance = [math]::Round($earthsRadius * $c * 1000, 0) #Multiple by 1000 to get metres  
    
      Return $distance  
    }
    
2
ответ дан TheLukeMcCarthy 15 August 2018 в 14:38
поделиться

я. Что касается метода «Breadcrumbs»

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

Ниже приведена функция в C, которая учитывает # 1 и # 2:

double   calcDistanceByHaversine(double rLat1, double rLon1, double rHeading1,
       double rLat2, double rLon2, double rHeading2){
  double rDLatRad = 0.0;
  double rDLonRad = 0.0;
  double rLat1Rad = 0.0;
  double rLat2Rad = 0.0;
  double a = 0.0;
  double c = 0.0;
  double rResult = 0.0;
  double rEarthRadius = 0.0;
  double rDHeading = 0.0;
  double rDHeadingRad = 0.0;

  if ((rLat1 < -90.0) || (rLat1 > 90.0) || (rLat2 < -90.0) || (rLat2 > 90.0)
              || (rLon1 < -180.0) || (rLon1 > 180.0) || (rLon2 < -180.0)
              || (rLon2 > 180.0)) {
        return -1;
  };

  rDLatRad = (rLat2 - rLat1) * DEGREE_TO_RADIANS;
  rDLonRad = (rLon2 - rLon1) * DEGREE_TO_RADIANS;
  rLat1Rad = rLat1 * DEGREE_TO_RADIANS;
  rLat2Rad = rLat2 * DEGREE_TO_RADIANS;

  a = sin(rDLatRad / 2) * sin(rDLatRad / 2) + sin(rDLonRad / 2) * sin(
              rDLonRad / 2) * cos(rLat1Rad) * cos(rLat2Rad);

  if (a == 0.0) {
        return 0.0;
  }

  c = 2 * atan2(sqrt(a), sqrt(1 - a));
  rEarthRadius = 6378.1370 - (21.3847 * 90.0 / ((fabs(rLat1) + fabs(rLat2))
              / 2.0));
  rResult = rEarthRadius * c;

  // Chord to Arc Correction based on Heading changes. Important for routes with many turns and U-turns

  if ((rHeading1 >= 0.0) && (rHeading1 < 360.0) && (rHeading2 >= 0.0)
              && (rHeading2 < 360.0)) {
        rDHeading = fabs(rHeading1 - rHeading2);
        if (rDHeading > 180.0) {
              rDHeading -= 180.0;
        }
        rDHeadingRad = rDHeading * DEGREE_TO_RADIANS;
        if (rDHeading > 5.0) {
              rResult = rResult * (rDHeadingRad / (2.0 * sin(rDHeadingRad / 2)));
        } else {
              rResult = rResult / cos(rDHeadingRad);
        }
  }
  return rResult;
}

II.

Средняя скорость.

Trip_distance = Trip_average_speed * Trip_time

Поскольку скорость GPS определяется эффектом Допплера и не имеет прямого отношения к [Lon, Lat], его можно, по крайней мере, считать вторичным (резервное копирование или исправление), если не как метод расчета основного расстояния.

4
ответ дан Tod Samay 15 August 2018 в 14:38
поделиться

Недавно мне пришлось сделать то же самое. Я нашел этот сайт очень полезным, объясняя сферический триггер примерами, с которыми легко было следовать.

2
ответ дан Twotymz 15 August 2018 в 14:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: