三角形の球面過剰


15

三角形の球面過剰

ご存知のように、平面三角形の角度の合計は180度に等しくなります。

ただし、球面三角形の場合、角度の合計は常に180度より大きくなります。球面三角形の角度の合計と180度の差は球面過剰と呼ばれます。タスクは、与えられた頂点座標で三角形の球面過剰を計算することです。

いくつかの背景

球面三角形は、球の3つの大円で定義される球の一部です。

球面三角形の両側と角度は、角度測定の用語で測定されます。これは、各側面が球体と球体の中心にある頂点との平面角度の交点と見なすことができるためです。

球面三角形の説明

3つの異なる大円はそれぞれ8つの三角形を定義しますが、 適切な三角形考慮します。角度と側面の測定値が満たされる三角形

0 <a、b、c、A、B、C <\ pi

地理座標系の観点から三角形の頂点を定義すると便利です。両端の経度λと緯度Φが与えられた場合、球の弧の長さを計算するには、次の式を使用できます。

d = 2 r \ arcsin \ left(\ sqrt {\ operatorname {haversin}(\ phi_2-\ phi_1)+ \ cos(\ phi_1)\ cos(\ phi_2)\ operatorname {haversin}(\ lambda_2- \ lambda_1)} \正しい)

、 どこ

\ operatorname {haversin}(\ theta)= \ sin ^ 2 \ left(\ frac {\ theta} {2} \ right)= \ frac {1- \ cos(\ theta)} {2}

またはより明示的に:

d = 2 r \ arcsin \ left(\ sqrt {\ sin ^ 2 \ left(\ frac {\ phi_2-\ phi_1} {2} \ right)+ \ cos(\ phi_1)\ cos(\ phi_2)\ sin ^ 2 \ left(\ frac {\ lambda_2-\ lambda_1} {2} \ right)} \ right)

(ソース:https : //en.wikipedia.org/wiki/Haversine_formula

球面三角形を解くために使用できる2つの基本式は次のとおりです。

  • 余弦の法則:

\ cos a = \ cos b \ cos c + \ sin b \ sin c \ cos A、\ cos b = \ cos c \ cos a + \ sin c \ sin a \ cos B、\ cos c = \ cos a \ cos b + \ sin a \ sin b \ cos C

  • サインの法則:

\ frac {\ sin A} {\ sin a} = \ frac {\ sin B} {\ sin b} = \ frac {\ sin C} {\ sin c}

(ソース: https //en.wikipedia.org/wiki/Spherical_trigonometry#Cosine_rules_and_sine_rules

3つの側面がある場合、コサインルールを使用して角度を簡単に計算できます。

A = \ arccos \ frac {\ cos a-\ cos b \ cos c} {\ sin b \ sin c}、B = \ arccos \ frac {\ cos b-\ cos c \ cos a} {\ sin c \ sin a}、C = \ arccos \ frac {\ cos c-\ cos a \ cos b} {\ sin a \ sin b}

最後に、三角形の球面過剰が定義されます。

E = A + B + C-\ pi

三角形の球体過剰とその面積との関係について興味深いのは:

S = E \ cdot R ^ 2

単位球では、三角形の過剰はその三角形の面積に等しくなります!

タスク

三角形の頂点座標を指定して、三角形の球面過剰を角度で計算する関数またはプログラムを作成します。頂点座標は、地理座標系で提供されます。

各頂点はで渡す必要があります[latitude in degrees][N|S][longitude in degrees][E|W]。経度、EまたはW緯度が90の場合はスキップできます 90N90S10N100E30S20W一方で、適切な頂点記述されている80N55Sではありません。

テストケースでは、緯度と経度は常に整数です。

エラーが1度未満の回答は受け入れられます(以下の例のように)。したがって、結果は実数または整数の両方としてレンダリングできます。

入力

90N0E
0N0E
0N90E

出力

89.999989

入力

90N
0N0E
0N90E

出力

89.999989

入力

0N0E
0N179E
90N0E

出力

178.998863

入力

10N10E
70N20W  
70N40E

出力

11.969793

すべてのテストケースで、経度と緯度は整数です。頂点が単一の文字列/リテラルとして渡されなければならないので、頂点座標を解析すると、タスクの一部である、それは通過できていない80N20E四つのパラメータ/文字列として:80N20E

これにより、頂点がすべて明確になり、3つの頂点のうち2つが対pod点のペアにならないことが保証されます。

得点

これはなので、最短のコードが優先されます。


1
最初のいくつかのテストケースの正しい出力は、90度と179度です。あなたは彼らがスポットである必要はないと言っていると思いますが、精度の小数点以下の桁数はいくつ必要ですか?
レベルリバーセント

@steveverrillタスクを更新しました。1度の精度で十分です。
pawel.boczarski

@ pawel.boczarski緯度/経度は常に整数ですか?
flawr

@flawrはい、タスクを更新しました。
pawel.boczarski

回答:


4

Matlab、288 266バイト

ここで何が起こっているのかを説明するコメント付きバージョン:

                                  %parsing the input
for k=1:3;
    s=input('','s');              %request input
    if sum(s>57)<2;               %if we have only one letter, add arbitrary second coordinate
        s=[s,'0E'];
    end;
    S=1-2*(s(s>57)>80);           %calculate the sign of the coordinates
    s(s>57)=44;                   %replace letters with comma
    L(k,:)=eval(['[',s,']']).*S;  %evaluates string as list and multiply with signs
end;
i=[2,3,1];
                                  %calculate the angular distance between each pair of points
a=arrayfun(@distance,L(:,1),L(:,2),L(i,1),L(i,2))*pi/180;
                                  %evaluate the spherical excess
f=@(a,b,c)sum(acos((cos(a)-cos(b).*cos(c))./(sin(b).*sin(c))))-pi;
disp(f(a,a(i),a([3,1,2]))*180/pi)

完全にゴルフ(ラインブレークは削除可能):

for k=1:3;s=input('','s');if sum(s>57)<2;s=[s,'0E'];end;
s(s>57)=44;L(k,:)=eval([91,s,93]).*(1-2*(s(s<48)>80));end;
i=[2,3,1];p=pi/180;a=arrayfun(@distance,L(:,1),L(:,2),L(i,1),L(i,2))*p;
b=a(i);disp((sum(acos((cos(a([3,1,2]))-cos(b).*cos(a))./(sin(b).*sin(a))))-pi)/p)

3

Ruby、Rev 3 264 255バイト

主な変更点:

新しい定数r= 180 / PIが定義され、関数全体で使用されます。e+ PIに初期化する必要があったため、超過分はカウントダウンし、戻る前に無効になりました。

t[]排除:Rubyは、割り当てられたデータをt[]直接割り当てられるようにしますu,v,w.

i2つの?:タスクを実行するための単一ループ、三者演算子がタスクを切り替えます。

他の多くの小さな変更。

include Math
->s{r=180/e=PI
x=y=z=n=[]
9.times{|i|i<6?(u,v,w=eval(?[+s[i%3].gsub(/[NE]/,"/r,").gsub(/[SW]/,"/-r,")+"0]")
i%2<1&&x=y=z=1
n[i/2]=(z*=sin(u))+(y*=cos(v)*w=cos(u))+x*=w*sin(v)):e-=acos((n[i-7]-(c=n[i-6])*d=n[i-8])/sqrt((1-c*c)*(1-d*d)))}
-e*r}

Ruby、Rev 1 283 277バイト

3つの文字列の配列が必要です。

include Math 
->s{x=y=z=n=[]
6.times{|i|t=eval(?[+s[i%3].gsub(/[NE]/,k="*PI/180,").gsub(/[SW]/,"*-1"+k)+"0]")
i%2<1&&x=y=z=1
n[i/2]=(z*=sin(u=t[0]))+(y*=cos(u)*cos(v=t[1]))+(x*=cos(u)*sin(v))}
e=-PI
3.times{|i|e+=acos((n[i-1]-n[i]*d=n[i-2])/sqrt((1-n[i]**2)*(1-d**2)))}
e/PI*180}

概要

単位球上の三角形の辺の長さは、2点を表すベクトル間の角度に等しくなります。しかし、その角度を知る必要はありません。角度のコサインを知るだけで十分です。コサインは、ドット積を使用してデカルト座標から簡単に取得できます。

説明

入力文字列は配列の文字列表現に変換され、次のように評価されてに保存さtれます。2つの座標が指定されている場合、最後のゼロは不要です。緯度90のみが指定されている場合、ゼロは経度として解釈されます。

Example:  70N20W --> [70*PI/180,20*-1*PI/180,0]

ドット製品の形式は次のとおりですa.b=ax*bx+ay*by+az*bz。ベクトルはすべて単位長であるため、ドット積はベクトル間の角度の余弦に等しくなります。

それらを計算するために、入力データを2回通過するループが6回繰り返されます。偶数回の反復0、2、4では、変数x,y,zが1に設定されて新しい計算が開​​始されます。各反復で、これらの変数は、t[0],t[1](ゴルフ上の理由からに割り当てられているu,v)に格納されている経度と緯度のデータを使用して、各ベクトルのx、y、z成分で乗算されます。変数の合計は配列に書き込まれn(偶数回の繰り返しのゴミ値は奇数回の繰り返しの正しい値で上書きされます)、最後nに3つの内積が含まれます[a.b, c.a, b.c]

コサインルールでは、頂点間の3つの内包角の余弦が必要ですが、正弦も必要です。これらはとして取得されsqrt(1-cosine**2)ます。サインが乗算されると、式を再配置して、1回の呼び出しのみsqrtが必要になるようにすることができます。正弦波が正の値か負の値かはわからないという事実は重要ではありません。haversineの式は常に正の正弦を与えるからです。重要な物理量は、ポイント間の距離であり、絶対距離であり、したがって常に正です。

各反復i=0..2i-1、他の要素iとを使用して、配列要素と反対の角度の値を計算しますi-2。このような負の配列添え字はRubyで有効であり、配列の先頭にラップアラウンドします。

テストプログラムでゴルフをしていません

同じ行に3つの座標セットが必要で、それらの間にスペースが必要です。

include Math
g=->s{
  n=[]         #array for dot products
  x=y=z=1      #it's required to use these variables once before the loop, for some bizarre reason
  6.times{|i|
    t=eval(?[+s[i%3].gsub(/[NE]/,k="*PI/180,").gsub(/[SW]/,"*-1"+k)+"0]")
    i%2<1&&x=y=z=1
    n[i/2]=(z*=sin(u=t[0]))+(y*=cos(u)*cos(v=t[1]))+(x*=cos(u)*sin(v))
  }

  e=-PI        #set e to -PI and begin accumulating angles
  3.times{|i|
    e+=acos((n[i-1]-n[i]*n[i-2])/sqrt((1-n[i]**2)*(1-n[i-2]**2)))
  }

e/PI*180}      #return value

puts g[gets.split]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.