Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Use extensões espaciais do MySQL para selecionar pontos dentro do círculo


Não há funções de extensão geoespacial no MySQL que suportem cálculos de distância de latitude/longitude. Existe a partir do MySQL 5.7 .

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