Клуб API Карт

Mysql и яндекс.карты. Поиск точек в полигоне.

dmitry.a.ocipov
26 июня 2014, 15:52

Доброго времени суток.

Прошу указать на ошибку тем, кто использовал мускул для указанной задачи:

Mysql Server version: 5.5.17-log

Делаю совершенно валидный запрос!

SET @poly ='Polygon((51.5979158591112 45.935922602537815,
51.58807913534905 46.08852956664947,
51.53543769673961 46.06741521728455,
51.49430912640296 45.93386266601537,
51.5979158591112 45.935922602537815))';# MySQL returned an empty result set (i.e. zero rows).

SELECT AsText(geopoint) FROM items_copy WHERE MBRWithin(GeomFromText(@poly),geopoint)

 

Извлекает 0 записей (их должны быть десятки как минимум), хотя в таблице есть в частности точка:

[51.523399353027344,46.00699996948242]

Когда вывожу её метку на сайте, она находится ровно внутри многоугольника указанного.

 

Прошу указать на ошибку. Функции

MBRContains и Contains также пробовал. Результат тот же 0 строк.

 

11 комментариев
Подписаться на комментарии к посту

А что если MBRINTERSECTS?

А что если @poly = -180,180 и тд. В том числе что простые квадраты, которые и не могут глючить?

А вообще какой MBR у этого полигона? 

SET @poly ='Polygon((-180,180))';

SELECT AsText(geopoint) FROM items_copy WHERE Contains(GeomFromText(@poly),geopoint)

 

Так же 0 строк. Понимаю, что глупо, но запросы тестировал не в консоли а через pma, что без разницы, но уже не знаю на что думать.

при этом на

SELECT AsText(geopoint), в числе результатов:

POINT(0 0)
POINT(0 0)
POINT(0 0)
POINT(51.523399353027344 46.00699996948242)

POINT(51.54545211791992 46.042362213134766)

всего в таблице порядка 50 тыс. записей, координаты есть у меньшинства, у остальных после конвертации установил POINT(0 0)

 SELECT AsText(geopoint) FROM items_copy WHERE MBRINTERSECTS(GeomFromText(@poly),geopoint) также 0 строк...

SET @poly ='Polygon((40 40, 60 40, 60 60, 40 60, 40 40))';?

SET @poly ='Polygon((40 40, 60 40, 60 60, 40 60, 40 40))';

SELECT AsText(geopoint) FROM items_copy WHERE Contains(GeomFromText(@poly),geopoint)

Оба запроса через phpmyadmin по очереди.

MySQL returned an empty result set (i.e. zero rows). ( Query took 0.0005 sec )

 Что это глюк мускула? Сейчас попробую на локальном...

MySQL 5.5.37-0ubuntu0.12.04.1

Развернул базу у себя на машине.

Результат тот же — 0 строк.

Даже удалил все значения 'Point(0 0)'

...

 Даже ещё интереснее!

Исправил 1 точку на Point(41 41) и

SELECT AsText(geopoint) FROM items_copy WHERE MBRWithin(GeomFromText('Polygon((40 40, 60 40, 60 60, 40 60, 40 40))'),geopoint)

а также contains, mbrcontains — результат 0 строк...

Есть у кого-то идеи ?:(

Даже через консоль:

mysql> SELECT AsText(geopoint) FROM items_copy WHERE MBRWithin(GeomFromText('Polygon((40 40, 60 40, 60 60, 40 60, 40 40))'),geopoint);
Empty set (0.00 sec)
mysql> SELECT AsText(geopoint) FROM items_copy LIMIT 2;
+----------------------------------------------+
| AsText(geopoint)                             |
+----------------------------------------------+
| POINT(41 41)                                 |
| POINT(51.53580093383789 45.97159957885742)   |
+----------------------------------------------+
10 rows in set (0.00 sec)

 

 

Следующий ход мыслей:

 

mysql> set @r = GeomFromText('POLYGON((0 0, 10 0, 0 10, 0 0))');
Query OK, 0 rows affected (0.00 sec)

mysql> set @p = GeomFromText('POINT(11 0)');
Query OK, 0 rows affected (0.00 sec)

mysql> select if(contains(@r, @p),'yes','no');
+---------------------------------+
| if(contains(@r, @p),'yes','no') |
+---------------------------------+
| no                              |
+---------------------------------+
1 row in set (0.00 sec)

mysql> set @p = GeomFromText('POINT(5 5)');
Query OK, 0 rows affected (0.00 sec)

mysql> select if(contains(@r, @p),'yes','no');
+---------------------------------+
| if(contains(@r, @p),'yes','no') |
+---------------------------------+
| yes                             |
+---------------------------------+
1 row in set (0.00 sec)

Ну слава Богу, не с ума сошёл сервер... ищём дальше.


mysql> set @r = GeomFromText('POLYGON((10 10, 20 10, 20 20, 15 20, 10 20, 10 10))');
Query OK, 0 rows affected (0.00 sec)

mysql> select if(contains(@r, @p),'yes','no');
+---------------------------------+
| if(contains(@r, @p),'yes','no') |
+---------------------------------+
| no                              |
+---------------------------------+
1 row in set (0.00 sec)

mysql> set @p = GeomFromText('POINT(15 15)');
Query OK, 0 rows affected (0.00 sec)

mysql> select if(contains(@r, @p),'yes','no');
+---------------------------------+
| if(contains(@r, @p),'yes','no') |
+---------------------------------+
| yes                             |
+---------------------------------+
1 row in set (0.00 sec)

И с многогранниками работает....

Database changed
mysql> UPDATE items_copy SET geopoint = GeomFromText('POINT 15 15') WHERE id = 1275777;
Query OK, 0 rows affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 1

mysql> set @r = GeomFromText('POLYGON((10 10, 20 10, 20 20, 15 20, 10 20, 10 10))');
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT id, AsText(geopoint) FROM items_copy WHERE contains(@r,geopoint);
Empty set (0.00 sec)

 Уже интересно:)

Отписываюсь для завершения темы.

 

Решение нашёл. Дело было в прокладке между монитором и креслом. Учитывая, что разобрался сам, ошибку признавать не так стыдно.

И так:

Для конвертации координат использовал запрос вида: UPDATE items SET geo = POINT(lat,len);

Перед этим создав в таблице поле типа Point и индекс на него. После этого почему-то(почему — выясню и отпишу позже) мускул не создал корректные индексы на точки координат! Вероятно это особенности типа полей геоданных или что-то в этом роде.

Запросы выше не отработали именно потому, что субд искала по индексам, что показал explain.

Вот как бы и всё. Запрос с ignore index покажет верные результаты.

Примечательно, что после удаления части записей из таблицы, мускул сохранил старые индексы для поля geopoint и не стал их также удалять... с чем и предстоит разобраться.

Спасибо всем за помощь в теме.