これは単純だと思っていましたが、私は奇妙な結果を得ています。誰かが私が間違っていることを指摘できたら、私は感謝します。球面上の2つの大きな円の間の角度の計算
地球の表面上に3つの点(A、B、C)が定義されており、各点の座標は[lat, long]
です。 ACとABで形成された2つの大弧の間の角度を計算する必要があります。
私は既にGreat Circle Distance(GCD)を計算する関数を持っていますので、AC、AB、CAのGCDを取得し、それらを単位球に縮小し、コサインは角度BACを取得します。
これはうまくいくと思います。しかし、私は3つのポイントをすべて同じグレートサークルに入れようとしましたが、奇妙なことが起き始めました。 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);
}
残念ながら私のために、私のアプリケーションは、多くの場合、ほぼライン上の点を持つことになりますので、このような状況では精度が重要です。ここで何がうまくいかないのですか?
EDIT:要求されたように、ここで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);
}
B/C我々は、距離の計算にそれを掛け、次いで、角度計算で除算RADIUS_EARTH
の宣言は、無関係であるので、キャンセルされます。
「getDistance」コードと「RADIUS_EARTH」宣言のコードを追加する必要があります –
これは大きな小数点を取って、それを二重として扱っています。 http://stackoverflow.com/questions/2173512/java-bigdecimal-trigonometric-methodsを見てください。任意の精度三角法を行う数学ライブラリを指しています –