Melhor método para trabalhar fora locais num raio de ponto de partida
-
19-09-2019 - |
Pergunta
Eu estou com o objetivo de criar um recurso no meu mais recente projeto de preferência usando PHP. Quando cada usuário se inscrever eles vão inserir seu código postal. Então eu espero que irá ser converter isso para latitude / longitude usando o Open Street Map.
De qualquer forma, eu quero ser capaz de descobrir outros usuários localizados perto do usuário atual. Eu vi um monte de gente usando a fórmula Haversine, no entanto, isso significaria que o usuário consultado detalhes de todos os outros usuários para trabalhar a distância. Eu poderia armazenar em cache este mas seu breve vai se tornar ultrapassada à medida que novos usuários se inscrever.
Que tipo de efeito seria executando a seguinte consulta tem no meu sistema?
sql = "SELECT zipcode, ( 3959 * acos( cos( radians( {$coords['latitude']} ) )
* cos( radians( latitude ) ) * cos( radians( longitude )
- radians( {$coords['longitude']} ) )
+ sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) )
AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";
Isso é puxado do blog de alguém.
Eu não tenho quaisquer valores para a taxa de inscrição ou a quantidade de usuários, uma vez que ainda está em desenvolvimento.
Eu gostaria de receber qualquer feedback ou outros métodos que eu poderia usar para encontrar usuários correspondentes dentro de um raio específico.
Solução
Existem GIS e Extensões Espacias ao MySQL na versão 4.1, consulte aqui . A partir da descrição que você vai encontrar, que é usado para problemas como você tem aqui:
A GIS (Sistema de Informação Geográfica) lojas e olha para cima objectos que têm um ou mais atributos espaciais, tais como o tamanho ea posição, e é usado para processar esses objectos. Um exemplo simples seria um sistema que armazena endereços em uma cidade usando geográfica coordenadas. Se isso bastante estática dados foi, em seguida, combinado com outra informações, como a localização de um táxi, em seguida, esses dados poderiam ser usados para encontrar o táxi mais próximo a um certo localização.
Ele adiciona várias coisas para MySql como:
-
chaves espacial e o tipo de ponto:
CREATE TABLE endereço ( CHAR endereço (80) não nulo, address_loc PONTO NOT NULL, PRIMARY KEY (endereço), ESPACIAL KEY (address_loc) );
-
rotinas de conversão
valores de endereço INSERT INTO ( 'Foobar rua 12', GeomFromText ( 'POINT (2671 2500)') );
-
funções de cálculo GIS
SELECIONAR c.cabdriver, ROUND ( GLength (LineStringFromWKB (LineString (asBinary (c.cab_loc), AsBinary (a.address_loc)))) ) distância AS Da cabina c, o endereço de um ORDER BY distância ASC LIMIT 1;
(Exemplos feita de ligação acima)
Outras dicas
O problema pode ser muito simplificada se você estiver disposto a afrouxar a definição de "dentro de um determinado raio" a não ser especificamente um círculo. Se você simplificar a um "quadrado", você pode encontrar todos os localização dentro do "raio" with 2 simples "entre" cláusulas (uma para um lat por muito tempo). por exemplo:
SELECT * FROM location WHERE
lat BETWEEN (my_lat - radius) AND (my_lat + radius)
AND long BETWEEN (my_long - radius) AND (my_long + radius);
Claro, isso poderia ser usado para selecionar um subconjunto de seus locais antes de usar um método mais preciso para calcular a distância real para eles.
É certo que este é Javascript não PHP, mas seria trivial para converter eu imagino.
Ele calcula a distância entre dois pontos, representando a curvatura da Terra. É usado-o em uma logística app um tempo atrás antes de substituí-lo com o código que faz isso usando uma rota adequada.
pode ser de utilidade para você ....
<script type="text/javascript">
function getDistance(lat1,lng1,lat2,lng2)
{
p1 = new VELatLong(lat1,lng1);
p2 = new VELatLong(lat2,lng2);
miles = true;
p1.Latitude= latLonToRadians(p1.Latitude);
p1.Longitude= latLonToRadians(p1.Longitude);
p2.Latitude= latLonToRadians(p2.Latitude);
p2.Longitude= latLonToRadians(p2.Longitude);
var R = 6371; // earth's mean radius in km
var dLat = p2.Latitude- p1.Latitude;
var dLong = p2.Longitude- p1.Longitude;
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(p1.Latitude) * Math.cos(p2.Latitude) * Math.sin(dLong/2) *
Math.sin(dLong/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var disKm = R * c;
var disMiles = disKm * 0.6214;
alert (miles ? disMiles : disKm);
}
// convert lat/long in degrees to radians
function latLonToRadians( point )
{
return point * Math.PI / 180;
}
</script>
Oh, e objetos VELatLong vêm da API do Virtual Earth ( http://msdn.microsoft.com/en-us/library/bb412519.aspx ), mas são basicamente um glorificado struct, então você deve ser capaz de encontrar um substituto adequado