Exceso esférico de un triángulo

15

Exceso esférico de un triángulo

Como todos sabemos, la suma de los ángulos de cualquier triángulo plano es igual a 180 grados.

Sin embargo, para un triángulo esférico, la suma de los ángulos siempre es mayor que 180 grados. La diferencia entre la suma de los ángulos del triángulo esférico y 180 grados se llama exceso esférico . La tarea es calcular el exceso esférico de un triángulo con coordenadas de vértice dadas.

Algunos antecedentes

Un triángulo esférico es una parte de la esfera definida por tres grandes círculos de la esfera.

Tanto los lados como los ángulos del triángulo esférico se miden en el término de la medida del ángulo, porque cada lado puede considerarse como una intersección de la esfera y un ángulo plano con vértice en el centro de la esfera:

Triángulo esférico explicado

Cada tres círculos grandes distintos definen 8 triángulos, pero solo tomamos en cuenta los triángulos apropiados , es decir. triángulos cuyo ángulo y medidas laterales satisfacen

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

Es conveniente definir los vértices de un triángulo en términos de sistema de coordenadas geográficas. Para calcular la longitud de un arco de esfera dada la longitud λ y la latitud Φ de sus extremos, podemos usar la fórmula:

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

, dónde

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

o más explícitamente:

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)

(fuente: https://en.wikipedia.org/wiki/Haversine_formula )

Las dos fórmulas básicas que se pueden usar para resolver un triángulo esférico son:

  • la ley de cosenos:

\ 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

  • la ley de los senos

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

(fuente: https://en.wikipedia.org/wiki/Spherical_trigonometry#Cosine_rules_and_sine_rules )

Dados tres lados, es fácil calcular los ángulos usando la regla del coseno:

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}

Finalmente, se define el exceso esférico de un triángulo:

E = A + B + C - \ pi

Lo interesante de la relación entre el exceso esférico de un triángulo y su área:

S = E \ cdot R ^ 2

Entonces, en una esfera unitaria, ¡el exceso de un triángulo es igual al área de ese triángulo!

La tarea

Escriba una función o un programa que calcule el exceso esférico de un triángulo en grados, dadas las coordenadas de los vértices del triángulo. Las coordenadas de vértice se proporcionan en términos de sistema de coordenadas geográficas.

Cada vértice debe pasarse en forma [latitude in degrees][N|S][longitude in degrees][E|W]. La longitud y / Eo Wse pueden omitir cuando la latitud es 90, es decir. 90N, 90S, 10N100E, 30S20WSon descripciones adecuadas de vértices, mientras que 80N, o 55Sno lo son.

Las latitudes y longitudes son siempre enteras en los casos de prueba.

Se aceptarán las respuestas con un error inferior a un grado (como en los ejemplos a continuación). El resultado puede representarse como real o entero, por lo tanto, según su conveniencia.

Ejemplos

Entrada

90N0E
0N0E
0N90E

Salida

89.999989

Entrada

90N
0N0E
0N90E

Salida

89.999989

Entrada

0N0E
0N179E
90N0E

Salida

178.998863

Entrada

10N10E
70N20W  
70N40E

Salida

11.969793

En todos los casos de prueba, longitud y latitud son números enteros. Analizar las coordenadas de los vértices es la parte de la tarea, por lo que un vértice debe pasar como cuerda suelta / literal, no está permitido pasar 80N20Ecomo cuatro parámetros: / cuerdas 80, N, 20, E.

Esto garantiza que los vértices son todos distintos y ninguno de los tres vértices forma un par de puntos antipodales.

Puntuación

Este es el , por lo que gana el código más corto.

pawel.boczarski
fuente
1
Las salidas correctas para los primeros casos de prueba son 90 grados y 179 grados. Entiendo que estás diciendo que no tienen que ser precisos, pero ¿cuántos decimales se requieren?
Level River St
@steveverrill Actualizó la tarea. La precisión de un grado es suficiente.
pawel.boczarski
@ pawel.boczarski ¿Las latitudes / longitudes son siempre enteras?
defecto
@flawr Sí, actualicé la tarea.
pawel.boczarski

Respuestas:

4

Matlab, 288 266 bytes

Aquí la versión comentada que debería explicar lo que está sucediendo:

                                  %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)

Completamente golfizado (se pueden eliminar los saltos de línea):

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)
falla
fuente
3

Ruby, Rev 3 264 255 bytes

Cambios principales:

Nueva constante r = 180 / PI definida y utilizada en toda la función. etuvo que ser inicializado a + PI, por lo que el exceso ahora cuenta hacia abajo y se niega antes de regresar.

t[] eliminado: Ruby permite los datos que se asignaron a t[] directamente au,v,w.

Soltero i bucle para hacer el trabajo de dos ?:operadores ternarios cambia entre tareas.

Muchos otros cambios menores.

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 bytes

Requiere una matriz de 3 cuerdas.

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}

Visión general

Las longitudes de los lados del triángulo en la esfera de la unidad son iguales a los ángulos entre los vectores que describen los dos puntos. Pero no necesitamos saber ese ángulo. Es suficiente conocer el coseno del ángulo, que se obtiene fácilmente de las coordenadas cartesianas utilizando el Producto Dot.

Explicación

Las cadenas de entrada se convierten en una representación de cadena de una matriz, que luego se evalúa y almacena tcomo se muestra a continuación. El cero final no es necesario si se dan dos coordenadas. Si solo se da la latitud 90, el cero se interpreta como la longitud.

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

Los productos Dot son de la forma a.b=ax*bx+ay*by+az*bz. Como los vectores son todos de longitud unitaria, el producto escalar es igual al coseno del ángulo entre los vectores.

Para calcularlos, se itera un bucle 6 veces, pasando dos veces por los datos de entrada. En las iteraciones pares 0,2,4 las variables x,y,zse establecen en 1 para comenzar un nuevo cálculo. En cada iteración, estas variables se multiplican por los componentes x, y y z de cada vector, utilizando los datos de longitud y latitud almacenados en t[0],t[1](que también se asignan por razones de golf u,v). La suma de las variables se escribe en la matriz n(los valores de basura en las iteraciones pares se sobrescriben con los valores correctos en las iteraciones impares) para que al final ncontenga los 3 productos de puntos[a.b, c.a, b.c] .

Para la regla del coseno, necesitamos los cosenos de los tres ángulos incluidos entre vértices, pero también necesitamos los senos. Estos se obtienen como sqrt(1-cosine**2). A medida que los senos se multiplican, la expresión se puede reorganizar para que solo una llamada asqrt se requiera . El hecho de que no sepamos si el seno fue positivo o negativo no importa, ya que la fórmula de haversina siempre da el seno positivo de todos modos. La cantidad física importante es la distancia entre los puntos, que es absoluta y, por lo tanto, siempre positiva.

Para cada iteración i=0..2, calculamos el valor para el elemento de matriz opuesto al ángulo i-1usando los otros elementos iyi-2 . Los subíndices de matriz negativos como este son legales en Ruby, simplemente se ajustan al comienzo de la matriz.

Sin golf en el programa de prueba

Requiere tres conjuntos de coordenadas en la misma línea, con espacios entre ellas.

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]
Level River St
fuente