Domanda

Questo può o non può essere chiaro, lasciami un commento se sono fuori base o hai bisogno di maggiori informazioni. Forse esiste già una soluzione per quello che voglio in PHP.

Sto cercando una funzione che aggiungerà o sottrarrà una distanza da un valore di longitudine O latitudine.

Motivo: ho un database con tutte le latitudini e longitudini e voglio formare una query per estrarre tutte le città entro X chilometri (o miglia). La mia query sarebbe simile a questa ...

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)

Sto lavorando in PHP, con un database MySql.

Aperto anche a qualsiasi suggerimento! :)

È stato utile?

Soluzione

Questa è una query MySQL che farà esattamente quello che vuoi. Tieni presente che cose come queste sono approssimazioni in generale, poiché la terra non è perfettamente sferica né tiene conto di montagne, colline, valli, ecc. Usiamo questo codice su AcademicHomes.com con PHP e MySQL, restituisce record entro $ raggio miglia di $ latitudine, $ longitudine.

$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");

Altri suggerimenti

EDIT: se hai, da qualche parte, un elenco di tutte le città del mondo insieme al loro lat. e lungo. valori, puoi fare una ricerca. In questo caso, vedi il mio primo link in basso per la formula per calcolare la larghezza di un grado longitudinale alla latitudine alt text:

alt text

Onestamente, le complicazioni alla base di questo problema sono tali che sarebbe molto meglio usare un servizio come Google Maps per ottenere i tuoi dati. In particolare, la Terra non è una sfera perfetta e la distanza tra due gradi varia man mano che ci si avvicina / allontana dall'equatore.

Vedi http://en.wikipedia.org/wiki/Geographic_coordinate_system per esempi di cosa intendo e dai un'occhiata a l'API di Google Maps .

A seconda di quante città stai includendo, puoi pre-calcolare l'elenco. Lo facciamo qui per un'applicazione interna in cui un'inesattezza di + 100m è troppo per la nostra configurazione. Funziona con una tabella a due chiavi di location1, location2, distance. Possiamo quindi ritirare molto rapidamente le posizioni x la distanza dalla posizione1.

Inoltre, poiché i calc possono essere eseguiti offline, non influisce sul funzionamento del sistema. Gli utenti ottengono anche risultati più rapidi.

Ho provato usando il codice sopra e le risposte erano troppo alte quando la distanza tra i punti era nella gamma di 20-30 miglia, e sto bene con qualche miglia di errore. Abbiamo parlato con un mio amico di mappatura e invece abbiamo pensato a questo. Il codice è Python, ma puoi tradurlo abbastanza facilmente. Per evitare la costante conversione in radianti, ho rifatto il mio database, convertendo i punti lat / lng da gradi a radianti. La parte bella di questo è che la maggior parte della matematica viene eseguita principalmente una volta.

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]);

Sembra essere molto preciso quando la distanza è piccola e entro 10 miglia circa quando la distanza cresce fino a 200 miglia, (ovviamente per allora, hai problemi con " in linea d'aria " vs " strade asfaltate " ;).

Ecco il modello ZipData che menziono sopra.

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)

Una nota in più è che puoi ottenere MOLTI dati geografici relativi ai codici postali all'indirizzo GeoNames. org e hanno anche alcune API di servizi web che puoi usare anche.

Ci sono molte (cattive opzioni)

  • Calcola la distanza usando la formula matematica (tratta X1-X2 e Y1-Y2) come vettori.

  • Crea una tabella di ricerca in anticipo con tutte le combinazioni e mantieni le distanze.

  • Prendi in considerazione l'utilizzo di un'estensione GIS specifica di MySQL. Ecco un articolo che ho trovato su questo .

lessthandot.com ha in realtà 3 modi diversi per farlo. dovrai scorrere un po 'i blog ma sono lì. http://blogs.lessthandot.com/

La funzione di seguito è tratta dalle nerddinner (applicazione di esempio ASP.NET MVC disponibile su codeplex ) database (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

Immagino che ciò possa essere utile.

Puoi usare il Teorema di Pitagora per calcolare la prossimità di due coppie di punti lat / lon.

Se hai due posizioni (Alpha e Beta) puoi calcolarne la distanza con:

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

Utilizzando l'installazione dal seguente URL, ho creato la query di seguito. (Nota che sto usando codeIgnitor per interrogare il database)

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;
    }
}

Non reinventare la ruota. Questa è una query spaziale. Usa MySQL estensioni spaziali integrate per memorizzare i dati delle coordinate di latitudine-longitudine in tipo di colonna della geometria MySQL nativa . Quindi utilizzare Distanza per interrogare punti che si trovano entro una distanza specifica l'uno dall'altro.

Disclaimer: si basa sulla lettura della documentazione, non l'ho provato da solo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top