В MySQL няма функции за геопространствено разширение, поддържащи изчисления на географска ширина/дължина. Има от MySQL 5.7
.
Искате кръгове за близост на повърхността на земята. Вие споменавате във вашия въпрос, че имате стойности за ширина/дълга за всеки ред във вашите flags
таблица, както и универсален напречен Mercator
(UTM) прогнозирани стойности в една от няколко различни UTM зони
. Ако си спомням правилно моите карти от UK Ordnance Survey, UTM е полезен за намиране на елементи на тези карти.
Лесно е да се изчисли разстоянието между две точки в една и съща зона в UTM:декартовото разстояние върши работа. Но когато точките са в различни зони, това изчисление не работи.
Съответно, за приложението, описано във вашия въпрос, е необходимо да използвате Great Circle Distance , което се изчислява с помощта на хаверсина или друга подходяща формула.
MySQL, допълнен с геопространствени разширения, поддържа начин за представяне на различни равнинни форми (точки, полилинии, многоъгълници и т.н.) като геометрични примитиви. MySQL 5.6 реализира недокументирана функция за разстояние st_distance(p1, p2)
. Тази функция обаче връща декартови разстояния. Така че е напълно неподходящ за изчисления на базата на географска ширина и дължина. На умерените ширини степен на географска ширина се простира почти два пъти по-голямо повърхностно разстояние (север-юг) от градус на дължина (изток-запад), тъй като линиите на географска ширина се сближават по-близо до полюсите.
Така че формулата за кръгова близост трябва да използва истинска географска ширина и дължина.
Във вашето приложение можете да намерите всички flags
точки в рамките на десет законови мили от дадена latpoint,longpoint
със заявка като тази:
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)
Ако искате да търсите точки в рамките на 20 км, променете този ред на заявката
20.0 AS r, 69.0 AS units
към това, например
20.0 AS r, 111.045 AS units
r
е радиусът, в който искате да търсите. units
са единиците за разстояние (мили, км, фази, каквото искате) на градус на географска ширина на повърхността на земята.
Тази заявка използва ограничаваща ширина/дължина заедно с MbrContains
за да изключите точки, които определено са твърде далеч от вашата начална точка, след това използва формулата за разстояние на големия кръг, за да генерира разстоянията за останалите точки. обяснение на всичко това можете да намерите тук
. Ако вашата таблица използва метода за достъп MyISAM и има пространствен индекс, MbrContains
ще използва този индекс, за да ви накара да търсите бързо.
И накрая, заявката по-горе избира всички точки в правоъгълника. За да стесните това само до точките в кръга и да ги подредите по близост, увийте заявката по следния начин:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC