Non ci sono funzioni di estensione geospaziale in MySQL che supportino i calcoli della distanza di latitudine/longitudine. C'è come di MySQL 5.7
.
Stai chiedendo dei cerchi di prossimità sulla superficie della terra. Nella tua domanda dici che hai valori lat/long per ogni riga nei tuoi flags
tabella e anche universal trasversale Mercator
(UTM) valori proiettati in una delle diverse zone UTM
. Se ricordo correttamente le mie mappe del Regno Unito Ordnance Survey, UTM è utile per localizzare gli oggetti su quelle mappe.
È semplice calcolare la distanza tra due punti nella stessa zona in UTM:la distanza cartesiana fa il trucco. Ma quando i punti si trovano in zone diverse, il calcolo non funziona.
Di conseguenza, per l'applicazione descritta nella tua domanda, è necessario utilizzare la Great Circle Distance , che viene calcolato utilizzando l'haversine o un'altra formula adatta.
MySQL, potenziato con estensioni geospaziali, supporta un modo per rappresentare varie forme planari (punti, polilinee, poligoni e così via) come primitive geometriche. MySQL 5.6 implementa una funzione di distanza non documentata st_distance(p1, p2)
. Tuttavia, questa funzione restituisce distanze cartesiane. Quindi è del tutto inadatto per calcoli basati su latitudine e longitudine. Alle latitudini temperate un grado di latitudine sottende quasi il doppio della distanza superficiale (nord-sud) di un grado di longitudine (est-ovest), perché le linee di latitudine si avvicinano l'una all'altra più vicino ai poli.
Quindi, una formula di prossimità circolare deve utilizzare la latitudine e la longitudine autentiche.
Nella tua applicazione puoi trovare tutti i flags
punti entro dieci miglia statutarie da un dato latpoint,longpoint
con una query come questa:
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 vuoi cercare punti entro 20 km, cambia questa riga della query
20.0 AS r, 69.0 AS units
a questo, per esempio
20.0 AS r, 111.045 AS units
r
è il raggio in cui vuoi cercare. units
sono le unità di distanza (miglia, km, stadi, qualunque cosa tu voglia) per grado di latitudine sulla superficie terrestre.
Questa query utilizza un limite lat/long insieme a MbrContains
per escludere punti che sono decisamente troppo lontani dal punto di partenza, usa la formula della distanza del cerchio massimo per generare le distanze per i punti rimanenti. Una spiegazione di tutto questo può essere trovata qui
. Se la tabella utilizza il metodo di accesso MyISAM e dispone di un indice spaziale, MbrContains
sfrutterà quell'indice per farti cercare velocemente.
Infine, la query precedente seleziona tutti i punti all'interno del rettangolo. Per restringerlo solo ai punti del cerchio e ordinarli per prossimità, avvolgi la query in questo modo:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC