Usando a lei do cosseno para calcular a distância entre 2 pontos no Objetivo C?
-
20-09-2019 - |
Pergunta
Recebo algumas coordenadas de GPS do Google Maps e preciso encontrar a distância entre eles usando o objetivo C.Implementei a fórmula, mas obtenho resultados muito grandes.
Testei os valores do Google Maps, repassando-os ao Google Earth e a um serviço de geocodificação na internet e tudo confere.Agora estou começando a suspeitar que a lei dos cossenos exige que eu faça algum tipo de conversão com as coordenadas antes de transmiti-las.
Fiz uma implementação semelhante da fórmula Haversine, mas também me deu grandes resultados.Mudei então para o cosseno, pois era mais fácil de depurar e não preciso de muita precisão.
Espero que alguém possa esclarecer um pouco sobre isso ou usar o código :)
- (CGFloat) calculateDistanceBetweenPoints:(CGPoint) origin andDestination:(CGPoint) destination {
//To convert kilometers to miles, divide by 1.609
// x = latitude
// y = longitude
/* example:
Dubai : 25.248665, 55.352917
Amsterdam : 52.309071, 4.763385
Approx dist: 5,182.62 KM
Calc. dist : 8,253.33
*/
CGFloat toRad = (M_PI / 180);
CGFloat R = 6371.0f; //earth's mean radius in Km
CGFloat sinePart = sinf( origin.x * toRad ) * sinf( destination.x * toRad );
CGFloat cosinePart = cosf( origin.x * toRad ) * cosf( destination.x * toRad );
CGFloat deltaCosinePart = cosf( ( destination.y - origin.y ) * toRad );
CGFloat delta = acosf( sinePart + cosinePart * deltaCosinePart) * R;
return delta;
}
Acima calculado a partir de links referenciados aqui:pergunta sobre fluxo de pilha
Solução
O código pode estar bem, quando eu o executo em seus dados de exemplo (menos alguns lugares decimais), ele retorna 5168.3584
Outras dicas
Você já pensou em usar o método fornecido em CLLocation
:
- (CLLocationDistance)getDistanceFrom:(const CLLocation *)location
?
Há uma série de perguntas que podem ajudar, incluindo:
Dadas as duas posições, você cria um triângulo esférico com cantos A em Amsterdã, B em Dubai e C no Pólo Norte, com lados a = 90° - ϕAms, b = 90° - ϕDuplicar, e ângulo C = Δλ = λDuplicar - λAms.A resposta obrigatória é o lado c.
Usando algum material da minha resposta ao SO 389211.
(Esta é uma resposta radicalmente revisada - minha tentativa anterior usou o triângulo esférico errado e, portanto, obteve a resposta errada.)
Arte ASCII no seu pior:
+ C (North Pole)
/|
b/ |
/ |
(Amsterdam) A + | a
\ |
c\ |
\|
+ B (Dubai)
A lei básica dos cossenos para triângulos esféricos é:
cos c = cos a . cos b + sin a . sin b . cos C
Observando que cos (90º - x) = sen x e sin (90º - x) = cos x, podemos escrever:
cos c = sen ϕAms .pecado ϕDuplicar + cos ϕAms .porqueϕDuplicar .porque Δλ
O ângulo c em radianos é então convertido em uma distância multiplicando-se pelo raio da Terra.
Aplicando isso aos seus dados:
Dubai:
ϕDuplicar = 25.248665°N
, λDuplicar = 55.352917°E
Amsterdam:
ϕAms = 52.309071°N
, λAms = 4.763385°E
Δλ = 50.589532°
Trabalhando com 6 casas decimais para a trigonometria:
cos c = 0.426548 × 0.791320 + 0.904465 × 0.611402 × 0.634872
= 0.337536 + 0.351079
= 0.688615
De onde:
c = 46.479426°
= 0.811219 radians
Multiplicando isso por 6.371 km como o raio nominal da Terra resulta
c = 5168 km
Portanto, para R = 6.371 km, a distância é 0,811219 × 6.371 = 5.168 km (para 4 s.f.).
Verdadeiro Conhecimento diz que deveria ser cerca de 5.155 km.Os dados posicionais usados são comparáveis aos valores que você especificou, e a Wikipedia confirma o raio que você forneceu.Isto é razoavelmente próximo - refazer o cálculo com coordenadas idênticas e mais dígitos no cálculo produziria uma resposta melhor, mas próxima desta.
Pessoal, sinto muito :( e estou com o rosto vermelho.Eu faço alguns outros cálculos nessas coordenadas.Eu calculei a posição (x, y) para que eles posicionem a cidade corretamente em um mapa personalizado que desenhei.Essas coordenadas são calculadas como tal:
- (CGPoint) translateToPixelsFromLatitude:(CGFloat) latitude andLongitude:(CGFloat) longitude {
CGPoint position = CGPointMake(0, 0);
CGFloat mapWidth = 300.0f;
CGFloat mapHeight = 200.0f;
CGFloat offsetX = 5.0f;
CGFloat offsetY = 35.0f;
position.x = (((180 + longitude) / 360) * mapWidth) + offsetX;
position.y = (mapHeight - (((90 + latitude) / 180) * mapHeight)) + offsetY;
return position;
}
Por alguns, não deveria codificar no meio da noite e depois ir até o SO para obter ajuda de pessoas ocupadas, por acaso passo as coordenadas transformadas para o método.
Descobri isso quando percebi que ao geocodificar cidades diferentes obtive resultados muito semelhantes e então li a postagem de hic3456 e de repente fez sentido.
Eu registro e testo as coordenadas e a distância de uma classe separada para que tudo seja registrado antes que os dados errados sejam passados para o método.
Agora eu realmente espero que alguém além de mim se beneficie com isso.
Desculpe novamente e obrigado a cada um de vocês.
Bem, se eu entendo a pergunta corretamente, você não está contabilizando a curvatura da terra. A Lei Cosseno trabalha em um avião, não em uma esfera. Por exemplo: O Pólo Norte e o Pólo Sul estão localizados a ~ 20.000 km de distância se você voar, mas apenas ~ 6000 km se você cavar um túnel;)
Atenciosamente, Ari