Рассчитать подшипник между двумя точками (широта, длинна) - PullRequest
17 голосов
/ 14 ноября 2011

Я пытаюсь разработать свой собственный движок дополненной реальности.

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

Следующая картинка из этого урока.

enter image description here

После этого я написал метод Objective-C для получения беты:

+ (float) calculateBetaFrom:(CLLocationCoordinate2D)user to:(CLLocationCoordinate2D)destination
{
    double beta = 0;
    double a, b = 0;

    a = destination.latitude - user.latitude;
    b = destination.longitude - user.longitude;

    beta = atan2(a, b) * 180.0 / M_PI;
    if (beta < 0.0)
        beta += 360.0;
    else if (beta > 360.0)
        beta -= 360;

    return beta;
}

Но, когда я пытаюсь это сделать, это не очень хорошо работает.

Итак, я проверил iPhone AR Toolkit, чтобы увидеть, как он работает (я работал с этим инструментарием, но он настолько большой для меня).

А в ARGeoCoordinate.m есть еще одна реализация получения бета-версии:

- (float)angleFromCoordinate:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second {

    float longitudinalDifference    = second.longitude - first.longitude;
    float latitudinalDifference     = second.latitude  - first.latitude;
    float possibleAzimuth           = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);

    if (longitudinalDifference > 0) 
        return possibleAzimuth;
    else if (longitudinalDifference < 0) 
        return possibleAzimuth + M_PI;
    else if (latitudinalDifference < 0) 
        return M_PI;

    return 0.0f;
}

Используется эта формула:

float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);

Почему (M_PI * .5f) в этой формуле? Я не понимаю этого.

И продолжайте поиск, я нашел еще одну страницу , рассказывающую о том, как рассчитать расстояние и пеленг 2 местоположений. На этой странице есть еще одна реализация:

/**
 * Returns the (initial) bearing from this point to the supplied point, in degrees
 *   see http://williams.best.vwh.net/avform.htm#Crs
 *
 * @param   {LatLon} point: Latitude/longitude of destination point
 * @returns {Number} Initial bearing in degrees from North
 */
LatLon.prototype.bearingTo = function(point) {
  var lat1 = this._lat.toRad(), lat2 = point._lat.toRad();
  var dLon = (point._lon-this._lon).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  var brng = Math.atan2(y, x);

  return (brng.toDeg()+360) % 360;
}

Какой из них правильный?

Ответы [ 8 ]

18 голосов
/ 20 марта 2013

Рассчитать подшипник

//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));

// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));

double dLon = (lng2-lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
brng = (360 - ((brng + 360) % 360));

Преобразование градусов в радианы

Radians = Degrees * PI / 180

Преобразование радианов в градусы

Degrees = Radians * 180 / PI
14 голосов
/ 08 декабря 2014

Я знаю, что этот вопрос старый, но вот более простое решение:

подшипник с плавающей запятой = loc1.bearingTo (loc2);

4 голосов
/ 14 ноября 2011

В формуле

float possibleAzimuth = (M_PI * .5f) - atan(latitudinalDifference / longitudinalDifference);

термин (M_PI * .5f) означает π / 2, что составляет 90 °.Это означает, что это та же самая формула, которую вы указали вначале, потому что относительно приведенного выше рисунка она имеет

β = арктан (a / b) = 90 ° - арктан (b / a).

Таким образом, обе формулы похожи, если a относится к разнице в долготе и b в разнице в широте.Последняя формула вычисляет снова то же самое, используя первую часть моего уравнения.

2 голосов
/ 06 марта 2017

Попробуйте для точного результата:

private static double degreeToRadians(double latLong) {
    return (Math.PI * latLong / 180.0);
}

private static double radiansToDegree(double latLong) {
    return (latLong * 180.0 / Math.PI);
}

public static double getBearing() {

//Source
JSONObject source = step.getJSONObject("start_location");
double lat1 = Double.parseDouble(source.getString("lat"));
double lng1 = Double.parseDouble(source.getString("lng"));

// destination
JSONObject destination = step.getJSONObject("end_location");
double lat2 = Double.parseDouble(destination.getString("lat"));
double lng2 = Double.parseDouble(destination.getString("lng"));

    double fLat = degreeToRadians(lat1);
    double fLong = degreeToRadians(lng1);
    double tLat = degreeToRadians(lat2);
    double tLong = degreeToRadians(lng2);

    double dLon = (tLong - fLong);

    double degree = radiansToDegree(Math.atan2(sin(dLon) * cos(tLat),
            cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(dLon)));

    if (degree >= 0) {
        return degree;
    } else {
        return 360 + degree;
    }
}

Вы можете проверить результат подшипника на http://www.sunearthtools.com/tools/distance.php.

2 голосов
/ 14 ноября 2011

a на диаграмме - это разница по долготе, b - это разница по широте, поэтому в методе, который вы написали, вы получили их неправильно.

a = destination.latitude - user.latitude; // should be b
b = destination.longitude - user.longitude; // should be a

Попробуйте переключить их и посмотрите, что произойдет.

См. Ответ Палунда для ответов на остальные ваши вопросы.

1 голос
/ 16 мая 2018
here is the code for calculating bearing angle between two points(startPoint, endPoint):

public float CalculateBearingAngle(double startLatitude,double startLongitude, double endLatitude, double endLongitude){
    double Phi1 = Math.toRadians(startLatitude);
    double Phi2 = Math.toRadians(endLatitude);
    double DeltaLambda = Math.toRadians(endLongitude - startLongitude);

    double Theta = atan2((sin(DeltaLambda)*cos(Phi2)) , (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda)));
    return (float)Math.toDegrees(Theta);
}

call for function:
float angle = CalculateBearingAngle(startLatitude, startLongitude, endLatitude, endLongitude);


import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
0 голосов
/ 30 мая 2019

/ * Кирит Вагела ответ был изменен .. Math.sin дает значение в радианах, поэтому для получения значения в градусах нам нужно передать Math.toRadians (значение) внутри Math.sin () или Math.cos (). * /

    double lat1 = 39.099912;
    double lat2 = 38.627089;
    double lng1 = -94.581213;
    double lng2 = -90.200203;

    double dLon = (lng2-lng1);
    double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(lat2));
    double y = Math.cos(Math.toRadians(lat1))*Math.sin(Math.toRadians(lat2)) - Math.sin(Math.toRadians(lat1))*Math.cos(Math.toRadians(lat2))*Math.cos(Math.toRadians(dLon));
    double bearing = Math.toDegrees((Math.atan2(x, y)));
    System.out.println("BearingAngle : "+bearing);
0 голосов
/ 15 ноября 2011

Если вы хотите, вы можете взглянуть на код, используемый в движке дополненной реальности mixare, он на github, а также на iPhone версии: github.com/mixare

...