【发布时间】:2011-11-10 15:28:28
【问题描述】:
我希望这很简单,但我得到了一些奇怪的结果。如果有人能指出我做错了什么,我将不胜感激。
我在地球表面(假设为球体)上定义了 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我们在距离计算中乘以它,然后在角度计算中除以它,所以它被抵消了。
【问题讨论】:
-
您应该为
getDistance代码和RADIUS_EARTH声明添加代码 -
好的,所以对于一个你取一个大小数,然后把它当作一个双精度......你可能会失去准确性。看看stackoverflow.com/questions/2173512/…,它指出了一个可以执行任意精度三角函数的数学库
标签: java geometry geospatial precision