Сферический избыток треугольника


15

Сферический избыток треугольника

Как мы все знаем, сумма углов любого плоского треугольника равна 180 градусам.

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

Некоторый фон

Сферический треугольник - это часть сферы, определяемая тремя большими кругами сферы.

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

Сферический треугольник объяснил

Каждые три отличных больших круга определяют 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) = \ грешить ^ 2 \ влево (\ гидроразрыва {\ Theta} {2} \ справа) = \ гидроразрыва {1- \ соз (\ 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 )

Две основные формулы, которые можно использовать для решения сферического треугольника:

  • закон косинусов:

\ 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 градусов. Я понял, что вы говорите, что они не должны быть точными, но сколько десятичных знаков точности требуется?
Уровень Река St

@steveverrill Обновил задачу. Точность одного градуса достаточно.
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.

Один 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}

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}

обзор

Длины сторон треугольника на единичной сфере равны углам между векторами, описывающими две точки. Но нам не нужно знать этот угол. Достаточно знать косинус угла, который легко получить из декартовых координат с помощью произведения точек.

объяснение

Входные строки преобразуются в строковое представление массива, который затем оценивается и сохраняется 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требовался только один вызов . Тот факт, что мы не знаем, был ли синус положительным или отрицательным, не имеет значения, так как формула haversine всегда дает положительный синус в любом случае. Важной физической величиной является расстояние между точками, которое является абсолютным и поэтому всегда положительным.

Для каждой итерации i=0..2мы вычисляем значение для угла, противоположного элементу массива, i-1используя другие элементы iи i-2. Отрицательные подписки на массивы, подобные этому, допустимы в Ruby, они просто переходят к началу массива.

Неуправляемый в тестовой программе

Требуются три набора координат на одной линии с пробелами между ними.

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.