삼각형의 구형 초과


15

삼각형의 구형 초과

우리 모두 알다시피, 평면 삼각형의 각도의 합은 180 도입니다.

그러나 구형 삼각형의 경우 각도의 합은 항상 180 도보 다 큽니다 . 구형 삼각형 각도의 합과 180 도의 차이를 구형 초과 라고 합니다. 주어진 정점 좌표를 가진 삼각형의 구형 과잉을 계산하는 것입니다.

일부 배경

구형 삼각형은 구의 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 \ 왼쪽 (\ frac {\ lambda_2-\ lambda_1} {2} \ right)} \ right)

(출처 : https://en.wikipedia.org/wiki/Haversine_formula )

구형 삼각형을 푸는 데 사용할 수있는 두 가지 기본 공식은 다음과 같습니다.

  • 코사인의 법칙 :

\ 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 \ 왜냐하면 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]. 위도가 90 일 때 경도 및 E/ 또는 W건너 뛸 수 있습니다 . 90N, 90S, 10N100E, 30S20W동안, 적절한 정점의 설명입니다 80N또는 55S수 없습니다.

위도 및 경도는 테스트 사례에서 항상 정수입니다.

1도 미만의 오류가있는 답변이 수락됩니다 (아래 예와 같이). 결과는 실제 또는 정수로 렌더링 할 수 있으므로 편의에 따라 다릅니다.

입력

90N0E
0N0E
0N90E

산출

89.999989

입력

90N
0N0E
0N90E

산출

89.999989

입력

0N0E
0N179E
90N0E

산출

178.998863

입력

10N10E
70N20W  
70N40E

산출

11.969793

모든 테스트 사례에서 경도와 위도는 정수입니다. 정점은 단일 문자열 / 문자로 전달해야하므로 정점 좌표를 구문 분석하는 것은, 작업의 일부이며,이 통과 허용하지 않는다 80N20E네 개의 매개 변수 / 문자열로 : 80, N, 20, E.

이것은 꼭짓점이 모두 구별되고 3 개의 꼭짓점 중 2 개가 대 지점을 만들지 않는다는 것을 보장합니다.

채점

이것은 이므로 가장 짧은 코드가 승리합니다.


1
처음 몇 가지 테스트 사례의 올바른 출력은 90도 및 179 도입니다. 나는 당신이 그것들을 발견 할 필요는 없다고 말하지만, 소수점 이하 몇 자리의 정확도가 필요합니까?
Level River St

@steveverrill 작업을 업데이트했습니다. 1 도의 정확도로 충분합니다.
pawel.boczarski 20시 02 분

@ pawel.boczarski 위도 / 경도는 항상 정수입니까?
flawr

@flawr 예, 작업을 업데이트했습니다.
pawel.boczarski

답변:


4

Matlab, 288266 바이트

여기에 무슨 일이 일어나고 있는지 설명 해야하는 주석이 달린 버전이 있습니다.

                                  %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

루비, 계 3 264 255 바이트

주요 변화:

새로운 상수 r= 180 / PI가 정의되고 기능 전체에서 사용됩니다. e+ PI로 초기화해야했기 때문에 초과분은 이제 아래로 계산되어 돌아 오기 전에 무시됩니다.

t[]제거됨 : Ruby는 할당 된 데이터를 t[]직접 할당 할 수 있습니다.u,v,w.

i두 개의 ?:삼항 연산자로 작업을 수행하는 단일 루프 .

다른 많은 사소한 변경.

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}

루비, 개정판 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}

개요

단위 구의 삼각형 변의 길이는 두 점을 나타내는 벡터 간의 각도와 같습니다. 그러나 우리는 그 각도를 알 필요가 없습니다. Dot Product를 사용하여 직교 좌표에서 쉽게 얻을 수있는 각도의 코사인을 알고 있으면 충분합니다.

설명

입력 문자열은 배열의 문자열 표현으로 변환 된 다음 t아래와 같이 평가되고 저장 됩니다. 두 개의 좌표가 제공되면 마지막 0은 필요하지 않습니다. 위도 90 만 지정하면 0은 경도로 해석됩니다.

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

내적 제품은 형태 a.b=ax*bx+ay*by+az*bz입니다. 벡터가 모두 단위 길이이므로, 내적은 벡터 사이의 각도의 코사인과 같습니다.

그것들을 계산하기 위해 루프는 입력 데이터를 두 번 통과하면서 6 번 반복됩니다. 반복 0,2,4에서도 변수 x,y,z는 1로 설정되어 새 계산을 시작합니다. 반복 할 때마다이 변수에 저장된 경도 및 위도 데이터를 사용하여 각 벡터의 x, y 및 z 구성 요소가 곱해집니다 t[0],t[1](골프 목적으로도 할당 됨 u,v). 변수의 합은 배열에 기록되고 n(홀수 반복에 대한 올바른 값으로 덮어 쓰는 짝수 반복의 가비지 값) 끝에 n3 개의 내적이 포함됩니다 [a.b, c.a, b.c].

코사인 규칙의 경우 정점 사이에 포함 된 세 가지 각도의 코사인이 필요하지만 죄도 필요합니다. 이들은로 얻어진다 sqrt(1-cosine**2). 사인을 곱하면 표현을 재 배열 할 수 있으므로 한 번의 호출 만 sqrt필요합니다. 사인이 포지티브 사인인지 항상 알 수 있기 때문에 사인이 포지티브인지 네거티브인지 알 수 없다는 사실은 중요하지 않습니다. 중요한 물리량은 점 사이의 거리이며, 절대적이고 항상 양입니다.

각 반복 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.