Es gibt keine geospatialen Erweiterungsfunktionen in MySQL, die Breiten-/Längengrad-Entfernungsberechnungen unterstützen. Gibt es ab MySQL 5.7
.
Sie fragen nach Annäherungskreisen auf der Erdoberfläche. Sie erwähnen in Ihrer Frage, dass Sie Lat/Long-Werte für jede Zeile in Ihren flags
haben Tabelle und auch Universal Transversal Mercator
(UTM) projizierte Werte in einer von mehreren verschiedenen UTM-Zonen
. Wenn ich mich richtig an meine UK Ordnance Survey-Karten erinnere, ist UTM nützlich, um Elemente auf diesen Karten zu lokalisieren.
Es ist einfach, die Entfernung zwischen zwei Punkten in derselben Zone zu berechnen in UTM:die kartesische Distanz tut es. Aber wenn sich Punkte in verschiedenen Zonen befinden, funktioniert diese Berechnung nicht.
Dementsprechend muss für die in Ihrer Frage beschriebene Anwendung die Great Circle Distance , die mit dem Haversinus oder einer anderen geeigneten Formel berechnet wird.
MySQL, erweitert um Geodaten-Erweiterungen, unterstützt eine Möglichkeit, verschiedene planare Formen (Punkte, Polylinien, Polygone usw.) als geometrische Primitive darzustellen. MySQL 5.6 implementiert eine undokumentierte Abstandsfunktion st_distance(p1, p2)
. Diese Funktion gibt jedoch kartesische Entfernungen zurück. Also völlig ungeeignet für auf Breiten- und Längengraden basierende Berechnungen. In gemäßigten Breiten überspannt ein Breitengrad fast doppelt so viel Oberflächenentfernung (Nord-Süd) wie ein Längengrad (Ost-West), weil die Breitengradlinien in der Nähe der Pole dichter zusammenwachsen.
Daher muss eine kreisförmige Näherungsformel echte Breiten- und Längengrade verwenden.
In Ihrer Anwendung finden Sie alle flags
Punkte innerhalb von zehn Meilen von einem bestimmten latpoint,longpoint
mit einer Abfrage wie dieser:
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)
Wenn Sie nach Punkten im Umkreis von 20 km suchen möchten, ändern Sie diese Zeile der Abfrage
20.0 AS r, 69.0 AS units
dazu zum Beispiel
20.0 AS r, 111.045 AS units
r
ist der Umkreis, in dem Sie suchen möchten. units
sind die Entfernungseinheiten (Meilen, km, Furlongs, was immer Sie wollen) pro Breitengrad auf der Erdoberfläche.
Diese Abfrage verwendet zusammen mit MbrContains
eine Breiten-/Längenbegrenzung um Punkte auszuschließen, die definitiv zu weit von Ihrem Startpunkt entfernt sind, verwenden Sie dann die Großkreis-Entfernungsformel, um die Entfernungen für die verbleibenden Punkte zu berechnen. Eine Erklärung all dessen finden Sie hier
. Wenn Ihre Tabelle die MyISAM-Zugriffsmethode verwendet und einen räumlichen Index hat, MbrContains
wird diesen Index ausnutzen, um Ihnen eine schnelle Suche zu ermöglichen.
Schließlich wählt die obige Abfrage alle Punkte innerhalb des Rechtecks aus. Um dies auf nur die Punkte im Kreis einzugrenzen und sie nach Nähe zu ordnen, verpacken Sie die Abfrage wie folgt:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC