Ontem em uma conversa com um de nossos clientes, acabamos recebendo o relato de um problema para achar os locais mais próximos pela longitude e latitude.
Com isso em mente, pesquisamos um pouco como resolver isso de forma simples. Após algumas pesquisas, achamos vários sites explicando os cálculos que devem ser realizados e uma query para o MySQL que faz as devidas conversões, e nos retorna a distância entre os pontos. Segue abaixo os testes que realizamos para ver o funcionamento da query.
Solução do problema
No nosso exemplo, gostaríamos de encontrar os pontos do mapa acima que estivessem mais próximos do escritório da Vizir, na Rua Boa Vista, 254 em São Paulo. Para fazer esta simulação fizemos os seguintes passos:
- Criamos uma tabela para armazenar os endereços;
- Inserimos os endereços com latitude e longitude;
- Executamos a query para retornar os endereços mais próximos.
Tabela e insert com os endereços
CREATE TABLE endereco ( id int(11) NOT NULL AUTO_INCREMENT, nome varchar(45) DEFAULT NULL, longitude varchar(45) DEFAULT NULL, latitude varchar(45) DEFAULT NULL, PRIMARY KEY (`id`) ) -- Endereços para teste INSERT INTO endereco(nome, longitude, latitude) VALUES('Terminal Mercado', '-46.62913200000003', '-23.5471634'); INSERT INTO endereco(nome, longitude, latitude) VALUES('Viaduto do Chá', '-46.63797820000002', '-23.5464833'); INSERT INTO endereco(nome, longitude, latitude) VALUES('Largo da Memória, 2-56', '-46.63892820000001', '-23.548348'); INSERT INTO endereco(nome, longitude, latitude) VALUES('Praça da República', '-46.64323139999999', '-23.5426444'); INSERT INTO endereco(nome, longitude, latitude) VALUES('Praça da Sé', '-46.63431400000002', '-23.5503342');
Executando a query
Utilizamos variáveis do MySQL para facilitar a reprodução do exemplo.
-- Select -- Parâmetros de entrada -- (Endereço da Vizir Rua Boa Vista 254) set @orig_lat= abs(-23.5454668); set @orig_lon= abs(-46.633525399999996); set @distancia=10; SELECT *, ((3956 * 2 * ASIN( SQRT(POWER(SIN((@orig_lat - abs(dest.latitude)) * pi()/180 / 2),2) + COS(@orig_lat * pi()/180 ) * COS(abs(dest.latitude) * pi()/180) * POWER(SIN((@orig_lon - abs(dest.longitude)) * pi()/180 / 2), 2)) ) ) * 1.609344) as distancia FROM endereco dest having distancia < @distancia ORDER BY distancia limit 100;
Pronto, a query retornou os endereços ordenados por distância (em quilômetros).
Resultados obtidos | ||||
Id | Nome | Longitude | Latitude | Distância (km) |
2 | Viaduto do Chá | -4663797820000000 | -235464833 | 0.46744009397678077 |
1 | Terminal Mercado | -4662913200000000 | -235471634 | 0.4856225533942553 |
5 | Praça da Sé | -4663431400000000 | -235503342 | 0.5467863930519828 |
3 | Largo da Memória, 2-56 | -4663892820000000 | -23548348 | 0.636702383775552 |
4 | Praça da República | -4664323139999990 | -235426444 | 1.0372715478873693 |
Se você quiser saber mais detalhes sobre a fórmula de Haversine, usada pra obter a distância mínima entre dois pontos, veja os links abaixo, que contém também uma apresentação explicando em detalhes como fazer o cálculo usando o MySQL.
Fonte
[1] http://en.wikipedia.org/wiki/Haversine_formula
[2] http://pt.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Recentes
-
Web Summit 2019 – Quarto Dia
Presidente de Portugal no encerramento No último dia aconteceu a trilha FullSTK, focada...
-
Festa julina de 10 anos
Eita, sô! Chegamos ao décimo aniversário da Vizir! Chegamos em um momento...
-
Web Summit 2019 – Terceiro Dia
Terceiro dia de evento. Fila para entrar, muita gente de novo, mas faz parte! Tudo...
-
Impressões do Web Summit – primeiro e segundo dia
Palco principal do WebSummit, as luzes dele são legais! No primeiro dia, ou melhor,...
-
Venha fazer parte da Vizir, estamos contratando…
Estamos contratando Desenvolvedores(as)! Apaixonados por resolver problemas reais e que...