Pergunta

Esta pode ou não ser claro, me deixe um comentário se eu estou fora da base, ou você precisa de mais informações. Talvez haja uma solução lá fora, já para o que eu quero em PHP.

Eu estou procurando uma função que irá adicionar ou subtrair uma distância de uma longitude ou valor de latitude.

Motivo: Eu tenho um banco de dados com todas as latitudes e longitudes nele e quer formar uma consulta para extrair todas as cidades dentro quilômetros X (ou milhas). Minha consulta seria algo parecido com isto ...

Select * From Cities Where (Longitude > X1 and Longitude < X2) And (Latitude > Y1 and Latitude < Y2)

 Where X1 = Longitude - (distance)
 Where X2 = Longitude + (distance)

 Where Y1 = Latitude - (distance)
 Where Y2 = Latitude + (distance)

Eu estou trabalhando em PHP, com um banco de dados MySQL.

aberto a sugestões também! :)

Foi útil?

Solução

Esta é uma consulta de MySQL que vai fazer exatamente o que você quer. Tenha em mente coisas como esta são aproximações em geral, como a Terra não é uma esfera perfeita, nem faz isso ter em conta montanhas, colinas, vales, etc .. Nós usamos este código em AcademicHomes.com com PHP e MySQL, ele retorna registros dentro $ milhas raio de US $ latitude, longitude $.

$res = mysql_query("SELECT
    * 
FROM
    your_table
WHERE
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) ASC");

Outras dicas

EDIT: Se você tem, em algum lugar, uma lista de todas as cidades do mundo, juntamente com a sua lat. e longo. valores, você pode fazer uma pesquisa. Neste caso, ver a primeira ligação abaixo para a fórmula para calcular a largura de um grau longitudinal na latitude :

text alt

Honestamente, as complicações por trás deste problema são tais que você seria muito melhor fora de usar um serviço como o Google Maps para obter seus dados. Especificamente, a Terra não é uma esfera perfeita, ea distância entre dois graus varia quanto você está mais perto / mais longe do equador.

Consulte http://en.wikipedia.org/wiki/Geographic_coordinate_system para exemplos de o que quero dizer, e confira o Google Maps API .

Dependendo de quantas cidades você está incluindo, você pode precompute lista. Fazemos isso aqui para uma aplicação interna, onde uma imprecisão de + 100m é demais para a nossa configuração. Ele funciona por ter uma tabela de duas chaves de location1, location2, distância. Podemos, então, puxar para trás locais x distância location1 muito rapidamente.

Também desde as calcs pode ser feito off-line, não tem impacto sobre o funcionamento do sistema. Os usuários também obter resultados mais rápidos.

Eu tentei usar o código acima, e as respostas foram fora por demais quando a distância entre os pontos foi na faixa de 20-30 milhas, e estou ok com algumas milhas de erro. Falou com um amigo mapeamento da mina e que surgiu com este lugar. O código é python, mas você pode traduzi-lo com bastante facilidade. A fim de evitar a conversão constante para radianos, eu refiz meu banco de dados, convertendo os pontos / GNL lat de graus em radianos. A parte boa sobre isso é que a maior parte da matemática é feito principalmente uma vez.

ra = 3963.1906 # radius @ equator in miles, change to km  if you want distance in km
rb = 3949.90275  # radius @ poles in miles, change to km  if you want distance in km
ra2 = ra * ra
rb2 = rb * rb

phi = self.lat

big_ol_constant = (math.pow(ra2*math.cos(phi), 2) + pow(rb2*math.sin(phi), 2))/ (pow(ra*math.cos(phi), 2) + pow(rb*math.sin(phi), 2))

sqlWhere = "%(distance)g > sqrt((power(lat - %(lat)g,2) + power(lng-%(lng)g,2)) * %(big_ol_constant)g)" % {
    'big_ol_constant': big_ol_constant, 'lat': self.lat, 'lng': self.lng, 'distance': distance}

# This is the Django portion of it, where the ORM kicks in.  sqlWhere is what you would put after the WHERE part of your SQL Query.
qs = ZipData.objects.extra(where=[sqlWhere]);

Parece ser muito preciso quando distância que os separa é pequena, e dentro de 10 milhas ou assim como a distância aumenta para 200 milhas, (claro que até lá, você tem problemas com "em linha recta" vs "estradas pavimentadas") .

Aqui está o modelo ZipData que eu mencionei acima.

class ZipData(models.Model):
    zipcode = ZipCodeField(null=False, blank=False, verbose_name="ZipCode", primary_key=True)
    city = models.CharField(max_length=32, null=False, blank=False)
    state = models.CharField(max_length=2)
    lat = models.FloatField(null=False, blank=False)
    lng = models.FloatField(null=False, blank=False)

Uma nota extra, é que você pode recebe grandes quantidades de dados geo relacionados com códigos postais em GeoNames. org e eles ainda têm algumas APIs webservice que você pode usar também.

Existem muitas opções (maus)

  • Calcular a distância utilizando a fórmula matemática (mimo X1-X2 e Y1-Y2) como vectores.

  • Criar uma tabela de pesquisa com antecedência, com todas as combinações e manter as distâncias.

  • Considere o uso de uma extensão específica de GIS do MySQL. Aqui está um artigo eu encontrei sobre este .

lessthandot.com realmente tem 3 maneiras diferentes de fazer isso. você terá que percorrer os blogs um pouco, mas eles estão lá. http://blogs.lessthandot.com/

A função é abaixo do NerdDinner 's (aplicação ASP.NET MVC amostra disponível no CodePlex) do banco de dados (MSSQL).

ALTER FUNCTION [dbo].[DistanceBetween] (@Lat1 as real,
                @Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
                 * COS (@dLat2InRad)
                 * SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END

Eu estou supondo que isso poderia ser útil.

Você pode usar Pitágoras Teorema para calcular a proximidade de dois pares de pontos de lat / lon.

Se você tem dois locais (alfa e beta) você pode calcular sua distância distante com:

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )

Usando a configuração a partir do seguinte URL, Ive construiu a consulta abaixo. (Por favor, note Im usando CodeIgnitor para consultar o banco de dados)

http: / /howto-use-mysql-spatial-ext.blogspot.com/2007/11/using-circular-area-selection.html

function getRadius($point="POINT(-29.8368 30.9096)", $radius=2)
{
    $km = 0.009;
    $center = "GeomFromText('$point')";
    $radius = $radius*$km;
    $bbox = "CONCAT('POLYGON((',
        X($center) - $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) - $radius, '
    ))')";

    $query = $this->db->query("
    SELECT id, AsText(latLng) AS latLng, (SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )))/0.009 AS distance
    FROM crime_listing
    WHERE Intersects( latLng, GeomFromText($bbox) )
    AND SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )) < $radius
    ORDER BY distance
        ");

    if($query->num_rows()>0){
        return($query->result());
    }else{
        return false;
    }
}

Não reinventar a roda. Esta é uma consulta espacial. Use MySQL é built-in extensões espaciais para armazenar a latitude-longitude coordenar dados no nativa geometria MySQL tipo de coluna . Em seguida, use o função Distância para consulta de pontos que estão dentro de uma determinada distância um do outro.

Disclaimer:. Isso é baseado em ler a documentação, eu não tentei isso mesmo

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top