Сферичний надлишок трикутника


15

Сферичний надлишок трикутника

Як ми всі знаємо, сума кутів будь-якого плоского трикутника дорівнює 180 градусам.

Однак для сферичного трикутника сума кутів завжди більша за 180 градусів. Різниця між сумою кутів кулястого трикутника і 180 градусів називається сферичним надлишком . Завдання - обчислити сферичний надлишок трикутника із заданими вершинними координатами.

Якесь тло

Сферичний трикутник - це частина сфери, визначена трьома великими колами сфери.

Обидві сторони і кути сферичного трикутника вимірюються в терміні вимірювання кута, оскільки кожну сторону можна розглядати як перетин сфери і деякий плоский кут з вершиною в центрі сфери:

Пояснюється сферичний трикутник

Кожні три чіткі великі кола визначають 8 трикутників, але ми беремо до уваги лише правильні трикутники , тобто. трикутники, кут і бічні міри яких задовольняють

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

Зручно визначати вершини трикутника за географічною системою координат. Для обчислення довжини кулі дуги, враховуючи довготу λ та широту ends її кінців, ми можемо використовувати формулу:

d = 2 r \ arcsin \ зліва (\ sqrt {\ ім'я оператора {haversin} (\ phi_2 - \ phi_1) + \ cos (\ phi_1) \ cos (\ phi_2) \ ім'я оператора {haversin} (\ lambda_2- \ lambda_1)} \ праворуч)

, де

\ operatorname {haversin} (\ theta) = \ sin ^ 2 \ ліворуч (\ frac {\ theta} {2} \ праворуч) = \ frac {1- \ cos (\ theta)} {2}

або більш чітко:

d = 2 r \ arcsin \ зліва (\ sqrt {\ sin ^ 2 \ зліва (\ frac {\ phi_2 - \ phi_1} {2} \ праворуч) + \ cos (\ phi_1) \ cos (\ phi_2) \ sin ^ 2 \ ліворуч (\ frac {\ lambda_2 - \ lambda_1} {2} \ праворуч)} \ праворуч)

(джерело: 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 \ 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 )

Враховуючи три сторони, легко обчислити кути за допомогою правила косинуса:

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, тобто. 90N, 90S, 10N100E, 30S20WЄ відповідними описами вершин, в той час 80Nабо 55Sнемає.

Широти та довготи завжди є цілими у тестових випадках.

Відповіді з помилкою менше ніж на один ступінь будуть прийняті (як у прикладах нижче). Таким чином, результат може бути відображений як реальний, так і цілий, відповідно до вашої зручності.

Приклади

Вхідні дані

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.

Це гарантується, що вершини всі виразні, і жодна з трьох вершин не складає пари антиподальних точок.

Оцінка балів

Це , тому найкоротший код виграє.


1
Правильні результати для перших кількох тестових випадків - 90 градусів і 179 градусів. Я вважаю, що ви говорите, що вони не повинні бути на місці, але скільки знаків у точності потрібно?
Річка Рівня Св.

@steveverrill Оновлено завдання. Точності одного ступеня достатньо.
pawel.boczarski

@ pawel.boczarski Чи є широти / довготи завжди цілими?
flawr

@flawr Так, я оновив завдання.
pawel.boczarski

Відповіді:


4

Матлаб, 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, об. 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}

Огляд

Довжини сторін трикутника на одиничній сфері дорівнюють кутам між векторами, що описують дві точки. Але нам не потрібно знати цей кут. Досить знати косинус кута, який легко отримується з декартових координат за допомогою крапкового добутку.

Пояснення

Рядки введення перетворюються в рядкове представлення масиву, який потім оцінюється і зберігається в t, як показано нижче. Кінцевий нуль не потрібен, якщо вказано дві координати. Якщо задано лише широту 90, нуль трактується як довгота.

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(значення сміття на парних ітераціях переписуються правильними значеннями на непарних ітераціях), щоб в кінці nмістилися 3 крапки [a.b, c.a, b.c].

Для правила косинусів нам потрібні косинуси з трьох включених кутів між вершинами, але нам також потрібні синуси. Вони отримуються як sqrt(1-cosine**2). Коли синуси множиться разом, вираз можна переставити так, що потрібно лише один виклик sqrt. Те, що ми не знаємо, чи був синус позитивним чи негативним, не має значення, оскільки формула гаверсину завжди дає позитивний синус. Важливою фізичною величиною є відстань між точками, яке є абсолютним і тому завжди позитивним.

Для кожної ітерації i=0..2обчислюємо значення для кута, протилежного елемента масиву, i-1використовуючи інші елементи iта i-2. Негативні підписи на масив, подібні цій, є законними в Ruby, вони просто обгортаються до початку масиву.

Ungolfed в тестовій програмі

Потрібні три набори координат на одній прямій з пробілами між ними.

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]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.