java - 计算球体上两个大圆之间的角度

标签 java geometry geospatial precision

我原以为这很简单,但我得到了一些奇怪的结果。如果有人能指出我做错了什么,我将不胜感激。

我在地球表面(假设是一个球体)上定义了 3 个点(A、B、C),每个点都有 [lat, long] 坐标。我需要计算由 AC 和 AB 形成的两条大弧之间的角度。

我已经有一个计算大圆距离 (GCD) 的函数,所以我决定通过获取 AC、AB 和 CA 的 GCD,将它们简化为一个单位球体,然后应用余弦球面定律来解决这个问题获得角度 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 我们在距离计算中乘以它,然后在角度计算中除以它,所以它被抵消了。

最佳答案

快速查看您的坐标,发现纬度相同而经度不同。但是纬度(赤道除外)形成的所有圆圈都不是大圆圈。如果经度不变而纬度变化,您是否尝试过您的程序?

关于java - 计算球体上两个大圆之间的角度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8075606/

相关文章:

algorithm - 这个问题的名称是什么?

geolocation - 为什么我的ElasticSearch查询没有获取位于地理边界框内的文档?

mysql - 一对多地理空间搜索

java - 在选择器线程之外的其他线程中设置 SelectionKey 的interestOps是否安全? (Java 尼奥)

java - TermQuery 没有给出预期结果作为 QueryParser - Lucene 7.4.0

java - 从action类访问jsp页面中class的值

rotation - 在处理中旋转、反转和平移 PShape 对象

c++ - 使用 boost 几何检查两条线是否有交点

java - 使用java(jdbc)在mysql中插入地理空间数据类型(multipolygon)

Java Sql 从列中选择月份