Вычисление угла между двумя большими кругами на сфере - PullRequest
2 голосов
/ 10 ноября 2011

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

У меня есть 3 точки (A, B, C), определенные на поверхности Земли (предполагается, что сфера) с [lat, long] координаты для каждой точки.Мне нужно вычислить угол между двумя Великими Дугами, образованными AC и AB.

У меня уже есть функция, которая вычисляет Расстояние по Большому Кругу (GCD), поэтому я решил решить эту проблему, получив GCD дляAC, AB и CA, сводя их к единичной сфере, а затем применяя сферический закон косинусов, чтобы получить угол BAC.

Это сработало и дало мне разумные углы.Однако затем я попытался поставить все три точки на одном и том же Большом круге, и началась странная вещь.Если B и C были в пределах 1 градуса, результаты были разумными, но когда я начал перемещать B и C дальше друг от друга вдоль того же Великого круга, угол начал расти!

Например:

A = 49, 1
B = 49, 10     => Angle: 0.0378
C = 49, 10.1

A = 49, 1
B = 49, 10     => Angle: 0.2270
C = 49, 10.6

A = 49, 1
B = 49, 10     => Angle: 3.7988
C = 49, 20

A = 49, 1
B = 49, 10     => Angle: 99.1027
C = 49, 200

Это какая-то ошибка точности, или моя формула неверна?

Вот код (getDistance(), как известно, работает):

  public static BigDecimal getAngle(
      final BigDecimal commonLat, final BigDecimal commonLong,
      final BigDecimal p1Lat, final BigDecimal p1Long,
      final BigDecimal p2Lat, final BigDecimal p2Long) {

    // Convert real distances to unit sphere distances
    //
    double a = getDistance(p1Lat, p1Long, commonLat, commonLong).doubleValue() / RADIUS_EARTH;
    double b = getDistance(p2Lat, p2Long, commonLat, commonLong).doubleValue() / RADIUS_EARTH;
    double c = getDistance(p1Lat, p1Long, p2Lat, p2Long).doubleValue() / RADIUS_EARTH;

    // Use the Spherical law of cosines to get at the angle between a and b
    //
    double numerator = Math.cos(c) - Math.cos(a) * Math.cos(b);
    double denominator = Math.sin(a) * Math.sin(b);
    double theta = Math.acos(numerator / denominator);

    // Back to degrees
    //
    double angleInDegrees = Math.toDegrees(theta);

    return new BigDecimal(angleInDegrees);
  }

К сожалению для меня,мое приложение часто будет иметь точки почти на одной линии, поэтому важна точность в этой ситуации.Что здесь не так?

РЕДАКТИРОВАТЬ: В соответствии с запросом, вот код для getDistance():

public static BigDecimal getDistance(final BigDecimal endLat, final BigDecimal endLong, 
    final BigDecimal startLat, final BigDecimal startLong) {

  final double latDiff = Math.toRadians(endLat.doubleValue() - startLat.doubleValue());
  final double longDiff = Math.toRadians(endLong.doubleValue() - startLong.doubleValue());

  final double lat1 = Math.toRadians(startLat.doubleValue());
  final double lat2 = Math.toRadians(endLat.doubleValue());

  double a =
      Math.sin(latDiff / 2) * Math.sin(latDiff / 2) + 
      Math.sin(longDiff / 2) * Math.sin(longDiff / 2) * Math.cos(lat1) * Math.cos(lat2);
  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  double d = RADIUS_EARTH * c;

  return new BigDecimal(d);
}

Объявление RADIUS_EARTH не имеет значения, b / c мы умножаем наэто при расчете расстояния, а затем поделить на него при расчете угла, чтобы оно было исключено.

1 Ответ

1 голос
/ 10 ноября 2011

Беглый взгляд на ваши координаты говорит, что широта одинакова, а долгота меняется. Но все круги по широте (кроме экватора) не являются большими кругами. Вы пробовали свою программу, если долгота постоянна, а широта меняется?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...