Você está pedindo círculos de proximidade na superfície da Terra. Você menciona em sua pergunta que tem valores de latitude/longitude para cada linha em seus
flags
tabela, e também universal transversal Mercator
(UTM) valores projetados em uma das várias zonas UTM
. Se me lembro corretamente dos meus mapas do UK Ordnance Survey, o UTM é útil para localizar itens nesses mapas. É simples calcular a distância entre dois pontos na mesma zona em UTM:a distância cartesiana faz o truque. Mas, quando os pontos estão em zonas diferentes, esse cálculo não funciona.
Assim, para o aplicativo descrito em sua pergunta, é necessário usar a Great Circle Distance , que é calculado usando a Havesine ou outra fórmula adequada.
O MySQL, aumentado com extensões geoespaciais, suporta uma maneira de representar várias formas planares (pontos, polilinhas, polígonos e assim por diante) como primitivas geométricas. MySQL 5.6 implementa uma função de distância não documentada
st_distance(p1, p2)
. No entanto, esta função retorna distâncias cartesianas. Portanto, é totalmente inadequado para cálculos baseados em latitude e longitude. Em latitudes temperadas, um grau de latitude subtende quase o dobro da distância da superfície (norte-sul) do que um grau de longitude (leste-oeste), porque as linhas de latitude se aproximam mais perto dos pólos. Portanto, uma fórmula de proximidade circular precisa usar latitude e longitude genuínas.
Em seu aplicativo, você pode encontrar todos os
flags
pontos dentro de dez milhas terrestres de um determinado latpoint,longpoint
com uma consulta como esta: SELECT id, coordinates, name, r,
units * DEGREES(ACOS(LEAST(1.0, COS(RADIANS(latpoint))
* COS(RADIANS(latitude))
* COS(RADIANS(longpoint) - RADIANS(longitude))
+ SIN(RADIANS(latpoint))
* SIN(RADIANS(latitude))))) AS distance
FROM flags
JOIN (
SELECT 42.81 AS latpoint, -70.81 AS longpoint,
10.0 AS r, 69.0 AS units
) AS p ON (1=1)
WHERE MbrContains(GeomFromText (
CONCAT('LINESTRING(',
latpoint-(r/units),' ',
longpoint-(r /(units* COS(RADIANS(latpoint)))),
',',
latpoint+(r/units) ,' ',
longpoint+(r /(units * COS(RADIANS(latpoint)))),
')')), coordinates)
Se você deseja pesquisar pontos em um raio de 20 km, altere esta linha da consulta
20.0 AS r, 69.0 AS units
a isso, por exemplo
20.0 AS r, 111.045 AS units
r
é o raio no qual você deseja pesquisar. units
são as unidades de distância (milhas, km, estádios, o que você quiser) por grau de latitude na superfície da Terra. Esta consulta usa uma latitude/longitude delimitadora junto com
MbrContains
para excluir pontos que estão definitivamente muito longe do seu ponto de partida, então use a fórmula da distância do grande círculo para gerar as distâncias para os pontos restantes. Uma explicação de tudo isso pode ser encontrada aqui
. Se sua tabela usa o método de acesso MyISAM e tem um índice espacial, MbrContains
irá explorar esse índice para obter uma pesquisa rápida. Por fim, a consulta acima seleciona todos os pontos dentro do retângulo. Para restringir isso apenas aos pontos no círculo e ordená-los por proximidade, enrole a consulta assim:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC