Необходимо составить запрос на выборку всех записей, которые находятся (по координатам longitude и latitude) в радиусе N метров от точки A (координаты которой известны).
P.S. До этого координаты хранил с помощью типа POINT, но после долгих поисков в интернете понял, что в MySQL очень урезаны возможности работы с этим типом, в отличие, к примеру, от PostgreSQL (PostGIS). Собственно по этому и пришлось перейти на хранение значений долготы и широты в разных полях.
Используйте функции spatial движка mysql. dev.mysql.com/doc/refman/5.1/en/spatial-extensions.html
Там есть и специальные индексы и оптимизированный поиск по ним. Вам достаточно lat,lng поля превратить в одно поле типа GeoPoint и создать на нем spatial индекс. А далее дело техники сделать выборку в пределах квадрата по индексу и через having отрезать до окружности. Лучше поступать именно так, потому что там используется специальный для этого индекс. Не знаю что там у вас урезано, но мы проверяли быстродействие при поиске по двум полям и по point полю, так последний показал в разы большую производительность.
При создании индекса ALTER TABLE `my_table` ADD SPATIAL INDEX ( `coordinates` ) ;
выдает ошибку Cannot get geometry object from data you send to the GEOMETRY field
А все, с индексом разобрался — некоторые записи в таблице имели «пустые» поля coordinates.
Теперь бы разобраться с запросом. Выборка в пределах квадрата, как я понимаю, делается так, верно? SELECT * FROM `my_table` WHERE MBRWithin(`coordinates`, GeomFromText('Polygon((50.456736 30.510540, 50.455690 30.510540, 50.455690 30.513295, 50.456736 30.513295))')) = 1;
А как теперь все это обрезать до окружности? И здесь же нужно знать координаты углов квадрата, а у нас известны только координаты точки, в радиусе которой необходимо произвести поиск, ну и собственно сам радиус.
Выборка в пределах квадрата у вас не верная, полигон нужно замкнуть на первую точку иначе не заработает функция.
Дело в том, что расстояние разное в разных частях света, но я честно говоря уже не помню как это считается, но можно сделать иначе. Допустим есть координаты человека $q=array(55,44); Тогда что бы узнать длину одного градуса долготы на его широте, проверяем функцией расстояние:
$kmInDeg = LatLngDist($q,array($q[0],$q[1]+1));
Теперь количество градусов в 1 км:
$degInKm = 1 / $kmInDeg;
Ну и для получения сторон квадрата:
$r = 3; // radius = 3km
$rdeg = $r * $degInKm;
$sq[0] = array($p[0]-$rdeg,$p[1]+$rdeg); // левый верхний
$sq[1] = array($p[0]+$rdeg,$p[1]+$rdeg); // правый верхний
$sq[2] = array($p[0]+$rdeg,$p[1]-$rdeg); // правый нижний
$sq[3] = array($p[0]-$rdeg,$p[1]-$rdeg); // левый нижний
$sq[4] = $sq[0]; // замыкаем полигон
Широта от -90 до 90, долгота от -180 до 180
значит нужно умножить штроту на 2, длина экватора 40075 км.
получается коэффициент будет 40075/360 = 111.3194444 км. = 111319.4444 м.
а конечная формула
SQRT(POW(latitude*2-latitudeA*2,2)+POW(longitude-longitudeA,2))<N *111319.4444
Вывод точек с сортировкой - "сначала те, которые ближе к точке по адресу Москва, ул Народного Ополчения."
SELECT *,
(ABS(lon-37.48488200)+ABS(lat-55.78553900)) as crd
FROM `pvz`
#WHERE `ds_full_addr` LIKE '%Народного%'
ORDER BY `crd` ASC
Если точек много и хранятся так, то можно попробовать разбить на квадраты и по координатам сначала получать квадрат и его соседей, а затем перебирать только их, ну и считать можно квадрат расстояния (корень всё-таки долго извлекать, а обойтись можно и без этого)
Я делал выборку квадрата со стороной в 2 радиуса запросом, а более точно для каждой точки считал расстояния в серверной части приложения. Так проще масштабировать и будут индексы задействованы.