Cálculo de distância entre locais usando coordenadas

Olá amigos do fórum.

Venho postar aqui uma duvida que quiça algum colega do fórum possa me ajudar. Peço desculpas ao moderadores se a pasta “Off-Topic” é inadequada

Bem, amigos, gostaria de implementar uma funcionalidade em um projeto que estou desenvolvendo, que é uma espécie de busca por “locais próximos”. Tenho na minha base as coordenadas dos locais possíveis de serem encontrados, e gostaria de consultar os registros usando um filtro de distância, dada uma coordenada.

Algo como “meu local é [meu endereço], quero localizar na base tudo o que está em um raio de x km daqui”. Existe alguma maneira de se fazer esse “calculo” usando a latitude e longitude?

Obrigado amigos!

Procure pela fórmula de Haversine para um cálculo de distância preciso.

Se você estiver usando um banco de dados com suporte a dados espaciais provavelmente você já tem uma função que faz o que você quer. No caso do Postgis você pode usar st_dwithin, por exemplo.

Obrigado, pessoal. Irei me aprofundar nas alternativas citadas. A base que utilizo é o MySQL, se houver uma alternativa como a que o colega wagnerfrancisco citou seria de muita ajuda.

Uma duvida que me ocorre para uma pesquisa dessa, existe uma relação de equidistancia entre coordenadas? Um exemplo tosco, se tenho uma coordenada lat 500, lng 500, em uma distancia de 500m as coordenadas seriam lat 1000, lng 1000? Desculpem a viagem, não entendo bulhufas dessa ciência. Embora se fosse assim seria fácil demais pra ser verdade :lol:

Valeu, pessoal.

[quote=alias]Obrigado, pessoal. Irei me aprofundar nas alternativas citadas. A base que utilizo é o MySQL, se houver uma alternativa como a que o colega wagnerfrancisco citou seria de muita ajuda.

Uma duvida que me ocorre para uma pesquisa dessa, existe uma relação de equidistancia entre coordenadas? Um exemplo tosco, se tenho uma coordenada lat 500, lng 500, em uma distancia de 500m as coordenadas seriam lat 1000, lng 1000? Desculpem a viagem, não entendo bulhufas dessa ciência. Embora se fosse assim seria fácil demais pra ser verdade :lol:

Valeu, pessoal.

[/quote]

De maneira alguma. Latitude e longitude são coordenadas angulares de pontos na superfície da terra. Por exemplo, a latitude é o ângulo entre o equador e o segmento de reta que passa pelo ponto que você localiza e o centro da Terra. Esse cálculo fica um pouco mais complicado se você levar em conta que a Terra não é uma esfera perfeita.

[quote=rmendes08][quote=alias]Obrigado, pessoal. Irei me aprofundar nas alternativas citadas. A base que utilizo é o MySQL, se houver uma alternativa como a que o colega wagnerfrancisco citou seria de muita ajuda.

Uma duvida que me ocorre para uma pesquisa dessa, existe uma relação de equidistancia entre coordenadas? Um exemplo tosco, se tenho uma coordenada lat 500, lng 500, em uma distancia de 500m as coordenadas seriam lat 1000, lng 1000? Desculpem a viagem, não entendo bulhufas dessa ciência. Embora se fosse assim seria fácil demais pra ser verdade :lol:

Valeu, pessoal.

[/quote]

De maneira alguma. Latitude e longitude são coordenadas angulares de pontos na superfície da terra. Por exemplo, a latitude é o ângulo entre o equador e o segmento de reta que passa pelo ponto que você localiza e o centro da Terra. Esse cálculo fica um pouco mais complicado se você levar em conta que a Terra não é uma esfera perfeita.[/quote]

Obrigado, meu velho. Santa ingenuidade a minha :lol:

Valeu novamente, galera.

[quote=wagnerfrancisco]Procure pela fórmula de Haversine para um cálculo de distância preciso.

Se você estiver usando um banco de dados com suporte a dados espaciais provavelmente você já tem uma função que faz o que você quer. No caso do Postgis você pode usar st_dwithin, por exemplo.[/quote]

Achei um conteudo na documentação do MySql ref. a dados espaciais. Valeu pelo toque, amigo. Vou estudar a coisa e posto aqui o caminho que tomei.

Valeu pessoal.

Você leu o link que passei?

Sim! :wink: …embora esteja me perguntando como passar o calculo que você citou em um “where” na base.

acho que o google tem APIs e soluções prontas para isto…
se não for trabalho acadêmico só vai perder tempo em fazer as algebraradas do capeta… usa direto a api do google e pronto…

Cara isto é muito simples! pega da sua base a coordenada de destino e de partida apenas isto. Usa a api do google para te devolver quantos km é do ponto inicial até o final…

O Google realmente disponibiliza este serviço, mas se não me engano, pra fins comerciais, é preciso usar a api premium, que é paga.

alias, como eu mencionei antes, o postgis tem uma função que faz exatamente o que tu precisa. Dado um conjunto de pontos (que você armazenará em uma tabela, por exemplo), você pode buscar todos que estejam ao redor de um ponto qualquer (sendo que você especifica o raio). A consulta seria mais ou menos assim:

select * from points where st_dwithin(st_geometry_from_text('POINT(10 10)'), the_geom, 100);

st_geometry_from_text é uma função que cria um objeto espacial, mas este valor poderia vir de outro lugar (por exemplo, uma subconsulta). the_geom é o nome da coluna que contem dados espaciais na tabela points e 100 é o raio que você quer buscar.

Tem, inclusive uma extensão do Hibernate pra trabalhar com este tipo de dado, o Hibernate Spatial (http://www.hibernatespatial.org/).

Nunca usei MySQL pra trabalhar com este tipo de informação, mas na documentação do Hibernate Spatial tá escrito que há suporte. Não sei se é 100%, vale a pena checar…

Falou!

Valeu novamente, wagnerfrancisco…caramba, se eu soubesse que ia precisar disso, teria usado o Postgre! O framework que voce citou não dá suporte 100% às funcionalidades de dados espaciais no Mysql, simplesmente pq…algumas funções ainda nem estão implementadas no Mysql! :lol: …em especial a função distance

Obrigado pela luz, cara, estou encontrando alguns “workarounds” internet afora…achei umas procedures que fazem aquele calculo que o Vini citou tambem! :shock:

Valeu pessoal.

[quote=wagnerfrancisco]O Google realmente disponibiliza este serviço, mas se não me engano, pra fins comerciais, é preciso usar a api premium, que é paga.

alias, como eu mencionei antes, o postgis tem uma função que faz exatamente o que tu precisa. Dado um conjunto de pontos (que você armazenará em uma tabela, por exemplo), você pode buscar todos que estejam ao redor de um ponto qualquer (sendo que você especifica o raio). A consulta seria mais ou menos assim:

select * from points where st_dwithin(st_geometry_from_text('POINT(10 10)'), the_geom, 100);

st_geometry_from_text é uma função que cria um objeto espacial, mas este valor poderia vir de outro lugar (por exemplo, uma subconsulta). the_geom é o nome da coluna que contem dados espaciais na tabela points e 100 é o raio que você quer buscar.

Tem, inclusive uma extensão do Hibernate pra trabalhar com este tipo de dado, o Hibernate Spatial (http://www.hibernatespatial.org/).

Nunca usei MySQL pra trabalhar com este tipo de informação, mas na documentação do Hibernate Spatial tá escrito que há suporte. Não sei se é 100%, vale a pena checar…

Falou![/quote]

Prezado wagnerfrancisco, já estou considerando migrar minha base para o Postgree dada essa limitação do MySQL. Sabe dizer se o PostGIS é um “complemento” do Postgree, é um produto à parte, ou o suporte a dados espaciais, e essas funções que citou, já são instaladas por padrão?

Obrigado!

Legal cara, tu vai gostar.

O PostgreSQL tem suporte à alguns dados espaciais, mas estas funções mais complexas estão no PostGIS, que, como você disse, é um complemento. No Linux você pode instalar o postgis por meio de algum repositório da tua distribuição. No Windows, tem uma ferramenta chamada StackBuilder que vem junto quando tu instala o PostgreSQL. É só usar ela pra instalar o PostGIS.

Depois, quando tudo tiver instalado, você cria uma nova base de dados usando uma base do postgis como template (pode ser tudo pelo pgAdmin mesmo).

Falou!

[quote=wagnerfrancisco]Legal cara, tu vai gostar.

O PostgreSQL tem suporte à alguns dados espaciais, mas estas funções mais complexas estão no PostGIS, que, como você disse, é um complemento. No Linux você pode instalar o postgis por meio de algum repositório da tua distribuição. No Windows, tem uma ferramenta chamada StackBuilder que vem junto quando tu instala o PostgreSQL. É só usar ela pra instalar o PostGIS.

Depois, quando tudo tiver instalado, você cria uma nova base de dados usando uma base do postgis como template (pode ser tudo pelo pgAdmin mesmo).

Falou!
[/quote]

Ih mano, isso pode ser um problema. Eu teria que pedir ao administrador do meu host para instalar esse complemento. Quer dizer, o host permite instalar bases Postgree, mas não sei se esse complemento está disponível. Se não estiver e a empresa se recusar a instalar, fodeu :cry:

Dadas as limitações do MySQL encontrei algumas funções e procedures internet afora que, pra calcular a distância, algumas utilizam a formula que o Vini passou e outras a formula de Haversine que você havia citado. Em ultimo caso meu plano é customizar essas funções e adequa-las a minha base, ia ficar sujinho mas fazer o que :lol: . Se tudo der certo eu vou de Postgree, se não…

Valeu mesmo pelas informações, cara. Brigadão.

Já pensou em utilizar bancos de dados NoSQL? Uma das aplicações mais comuns é o georeferenciamento, muitos deles já possuem suporte nativo.

Olha como é simples uma consulta no MongoDB, por exemplo:

db.places.find( { loc : { $near : [50,50] , $maxDistance : 5 } } ).limit(20)

fonte: http://www.mongodb.org/display/DOCS/Geospatial+Indexing

[quote=fabiocsilva]Já pensou em utilizar bancos de dados NoSQL? Uma das aplicações mais comuns é o georeferenciamento, muitos deles já possuem suporte nativo.

Olha como é simples uma consulta no MongoDB, por exemplo:

db.places.find( { loc : { $near : [50,50] , $maxDistance : 5 } } ).limit(20)

fonte: http://www.mongodb.org/display/DOCS/Geospatial+Indexing[/quote]

Cara valeu pela dica! Eu havia mesmo lido em algum lugar que o MongoDB suportava geo-indexação. É uma alternativa interessante, mas utiliza-lo teria muito impacto na minha aplicação, penso eu. Você concorda? Hoje já tenho as entidades todas mapeadas no Hibernate, usando o MySQL. Pra usar o Postgree (como eu tinha dito antes) seria só alterar a config do Hibernate…você acha que seria viável utilizar duas bases, mantendo o legado que tenho hoje e usando o MongoDB para armazenar os dados espaciais? Se bem que ainda que seja viável ia dar um trabalho pra implementar…

O seu exemplo me trouxe uma duvida que talvez possa ajudar, e tambem voltando a esse exemplo que o colega wagnerfrancisco havia mostrado:

No caso do MongoDB, essa distancia passada como filtro é em milhas? Prezado wagner, sabe dizer qual é a medida utilizada no Postgree?

Obrigado!

[quote=alias][quote=fabiocsilva]Já pensou em utilizar bancos de dados NoSQL? Uma das aplicações mais comuns é o georeferenciamento, muitos deles já possuem suporte nativo.

Olha como é simples uma consulta no MongoDB, por exemplo:

db.places.find( { loc : { $near : [50,50] , $maxDistance : 5 } } ).limit(20)

fonte: http://www.mongodb.org/display/DOCS/Geospatial+Indexing[/quote]

Cara valeu pela dica! Eu havia mesmo lido em algum lugar que o MongoDB suportava geo-indexação. É uma alternativa interessante, mas utiliza-lo teria muito impacto na minha aplicação, penso eu. Você concorda? Hoje já tenho as entidades todas mapeadas no Hibernate, usando o MySQL. Pra usar o Postgree (como eu tinha dito antes) seria só alterar a config do Hibernate…você acha que seria viável utilizar duas bases, mantendo o legado que tenho hoje e usando o MongoDB para armazenar os dados espaciais? Se bem que ainda que seja viável ia dar um trabalho pra implementar…

O seu exemplo me trouxe uma duvida que talvez possa ajudar, e tambem voltando a esse exemplo que o colega wagnerfrancisco havia mostrado:

No caso do MongoDB, essa distancia passada como filtro é em milhas? Prezado wagner, sabe dizer qual é a medida utilizada no Postgree?

Obrigado![/quote]

Quanto ao esforço de (re)implementação, não cabe a mim julgar. Em relação a unidade de medida, vai depender do tipo de coordenada. Se for convencional(considerando o espaço plano), a medida vai ser meramente ilustrativa. Se for utilizado o modelo esférico(que considera a curvatura da terra), o resultado será em milhas ou quilômetros. No link que passei anteriormente explica tudo.

Ops, me desculpe se o ofendi ou desrespeitei. Não foi de maneira alguma minha intenção. Novamente obrigado pela valiosa dica! Já tô montando uma POC aqui com um tal framework chamado Morphia e o MongoDB pra ver qual que é! :stuck_out_tongue:

Amigos, colocando a “solução” que encontrei…ao menos por enquanto, mas imagino que vou ficar com essa mesmo.

A extensão PostGis que o colega wagnerfrancisco citou (obrigado mesmo cara!) não está instalada no host que utilizo, eu teria que pagar um servidor dedicado para o banco (na real o valor nem é caro, mas não tô numas de gastar mais, hehe). Chorei, esperneei com o pessoal do host, mas não rolou, então deixei quieto o uso do PostgreeSQL por enquanto. Acredito que seria o mais adequado mas vai ficar pro futuro.

Quanto ao uso do MongoDB que o colega fabiocsilva citou, cara valeu pela dica fiz uns testes e gostei bastante, mas exigiria um esforço de implementação da minha parte que também não posso fazer agora, fora que eu nem entendi como seria a instalação da bagaça em um servidor hehe. Vou estudar mais o MongoDB antes de partir pro uso, mas recomendo!

Minha solução foi uma função para o MySQL que achei internet afora, que calcula a formula da Haversine para determinar a distancia entre dois pontos. Adaptei a função para calcular a distancia em quilometros, e beleza! tá funfando, só preciso fazer um teste com alguns milhares de registros pra testar melhor a performance. Mas foi isso, caso alguem necessite dessa funcionalidade no MySQL eu posto aqui o que fiz.

Valeu galera, obrigado a todos!