2011-11-10 16 views
2

これは単純だと思っていましたが、私は奇妙な結果を得ています。誰かが私が間違っていることを指摘できたら、私は感謝します。球面上の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の宣言は、無関係であるので、キャンセルされます。

+0

「getDistance」コードと「RADIUS_EARTH」宣言のコードを追加する必要があります –

+0

これは大きな小数点を取って、それを二重として扱っています。 http://stackoverflow.com/questions/2173512/java-bigdecimal-trigonometric-methodsを見てください。任意の精度三角法を行う数学ライブラリを指しています –

答えて

1

あなたの座標のクイックルックは、緯度が同じであり、経度が異なることを示しています。しかし、緯度によって作られたすべての円(赤道を除く)は大きな円ではありません。経度が一定で緯度が変わった場合、あなたのプログラムを試しましたか?

+0

ありがとう、Mnementh。私はそれを逃したとは信じられません:)。 –

関連する問題