Tidak ada fungsi ekstensi geospasial di MySQL yang mendukung perhitungan jarak lintang/bujur. Ada pada MySQL 5.7
.
Anda meminta lingkaran kedekatan di permukaan bumi. Anda menyebutkan dalam pertanyaan Anda bahwa Anda memiliki nilai lintang/bujur untuk setiap baris di flags
tabel, dan juga merkator transversal universal
(UTM) memproyeksikan nilai di salah satu dari beberapa zona UTM
yang berbeda . Jika saya mengingat peta UK Ordnance Survey saya dengan benar, UTM berguna untuk menemukan item di peta tersebut.
Ini masalah sederhana untuk menghitung jarak antara dua titik di zona yang sama di UTM:jarak Cartesian berhasil. Namun, ketika titik berada di zona yang berbeda, perhitungan itu tidak akan berhasil.
Oleh karena itu, untuk aplikasi yang dijelaskan dalam pertanyaan Anda, perlu menggunakan Jarak Lingkaran Besar , yang dihitung menggunakan haversine atau formula lain yang sesuai.
MySQL, ditambah dengan ekstensi geospasial, mendukung cara untuk mewakili berbagai bentuk planar (titik, polyline, poligon, dan sebagainya) sebagai primitif geometris. MySQL 5.6 mengimplementasikan fungsi jarak tidak terdokumentasi st_distance(p1, p2)
. Namun, fungsi ini mengembalikan jarak Cartesian. Jadi itu sama sekali tidak cocok untuk perhitungan berdasarkan garis lintang dan garis bujur. Pada garis lintang sedang, satu derajat garis lintang menunjukkan jarak permukaan hampir dua kali lipat (utara-selatan) dibandingkan dengan derajat garis bujur (timur-barat), karena garis lintang tumbuh lebih dekat bersama-sama di dekat kutub.
Jadi, rumus kedekatan melingkar perlu menggunakan garis lintang dan garis bujur asli.
Dalam aplikasi Anda, Anda dapat menemukan semua flags
poin dalam jarak sepuluh mil undang-undang dari latpoint,longpoint
yang diberikan dengan pertanyaan seperti ini:
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)
Jika Anda ingin mencari titik dalam jarak 20 km, ubah baris kueri ini
20.0 AS r, 69.0 AS units
untuk ini, misalnya
20.0 AS r, 111.045 AS units
r
adalah radius di mana Anda ingin mencari. units
adalah satuan jarak (mil, km, furlong, apa pun yang Anda inginkan) per derajat garis lintang di permukaan bumi.
Kueri ini menggunakan garis lintang/bujur pembatas bersama dengan MbrContains
untuk mengecualikan titik yang pasti terlalu jauh dari titik awal Anda, maka gunakan rumus jarak lingkaran besar untuk menghasilkan jarak untuk titik yang tersisa. penjelasan tentang semua ini dapat ditemukan di sini
. Jika tabel Anda menggunakan metode akses MyISAM dan memiliki indeks spasial, MbrContains
akan mengeksploitasi indeks itu untuk membuat Anda mencari dengan cepat.
Akhirnya, kueri di atas memilih semua titik di dalam persegi panjang. Untuk mempersempitnya menjadi hanya titik-titik dalam lingkaran, dan mengurutkannya berdasarkan kedekatan, bungkus kueri seperti ini:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC