См., Если lat/long попадает в многоугольник, используя mysql

Я создал таблицу ниже

CREATE TABLE geom (g GEOMETRY);

и вставили много строк, пример ниже:

INSERT INTO geom (g)
VALUES(PolygonFromText('POLYGON((
9.190586853 45.464518970,
9.190602686 45.463993916,
9.191572471 45.464001929,
9.191613325 45.463884676,
9.192136130 45.463880767,
9.192111509 45.464095594,
9.192427961 45.464117804,
9.192417811 45.464112862,
9.192509035 45.464225851,
9.192493139 45.464371079,
9.192448471 45.464439002,
9.192387444 45.464477861,
9.192051402 45.464483037,
9.192012814 45.464643592,
9.191640825 45.464647090,
9.191622331 45.464506215,
9.190586853 45.464518970))')
);

Теперь я хочу искать все данные и возвращать записи, в которых длина lat/long падает с любого из полигонов.

Как это можно сделать с помощью mysql? или кто-нибудь знает какие-либо ссылки, которые укажут мне в правильном направлении?

Ответы

Ответ 1

MySQL с версии v5.1 поддерживает только операции с минимальными ограничивающими прямоугольниками (MBR). Хотя есть функция Contains, которая будет делать то, что вам нужно, она не полностью реализована и возвращается к использованию MBRContains

Из соответствующей страницы руководства

В настоящее время MySQL не реализует эти функции в соответствии с Спецификация. Те, которые реализованные возвращают тот же результат, что и соответствующие MBR-функции. Сюда входят функции в следующий список, кроме Distance() и Связанные().

Эти функции могут быть реализованы в будущие выпуски с полной поддержкой пространственный анализ, а не только основанный на MBR поддержка.

Что вы можете сделать, так это позволить MySQL дать вам приблизительный результат, основанный на MBR, а затем отправить его, чтобы выполнить более точный тест. Кроме того, переключитесь на PostGIS!

(Обновление май 2012 г. - спасибо Майку Тоуэсу)

MySQL 5.6.1+ предлагает функции, которые используют формы объектов, а не MBR

Первоначально MySQL реализовывала эти функции, чтобы они использовали объектных ограничивающих прямоугольников и возвращает тот же результат, что и соответствующие функции MBR. Начиная с MySQL 5.6.1, соответствующие доступны версии, которые используют точные формы объектов. Эти версии называются с префиксом ST_. Например, Contains() использует объект ограничивающие прямоугольники, тогда как ST_Contains() использует формы объектов.

Ответ 2

Если вы не можете изменить dbs на тот, у которого есть пространственные операторы, реализованные правильно, например PostgIS-расширение PostgIS Postgres http://postgis.refractions.net/, вы можете решить эту проблему, используя двухкомпонентный подход.

Сначала пусть MySQL предоставит вам результат предварительной фильтрации с ограничивающей рамкой на основе ограничивающего прямоугольника (это то, что он делает по умолчанию), используя оператор их пересечений (http://dev.mysql.com/doc/refman/5.1/en/functions-that-test-spatial-relationships-between-geometries.html#function_intersects). Если запросы выполняются медленно, убедитесь, что у вас есть индекс в поле геометрии.

Затем гидратируйте исходную геометрию, которую вы использовали в своем запросе, в объект геометрии библиотеки геометрии ГИС, такой как GEOS (http://trac.osgeo.org/geos/) (на основе С++, хотя у нее также есть привязки для разных языков, таких как Python), Shapely (http://trac.gispython.org/lab/wiki/Shapely), OGR (или Java Topology Suite (JTS) http://www.vividsolutions.com/jts/jtshome.htm).

Проверьте каждую из геометрий, которые вы возвращаете из результата запроса, используя соответствующий оператор, например внутри или , пересекается. Любая из этих библиотек даст вам логический результат.

Лично я бы посмотрел образцы для OGR, так как у него есть большое сообщество, которое готово помочь.

О да, и извините за то, что разместили такие ссылки... Думаю, поскольку я "новый", я могу опубликовать только одну ссылку (?)

Ответ 3

Функция, данная в этот пост на форумах MySQL отлично работает для меня.

Это не очень быстро, и вы должны убедиться, что параметр "mp" - это тот же тип, что и используемый вами пространственный столбец (я использовал ogr2ogr для импорта шейп файла Survey Survey в MySQL, поэтому пришлось изменить его с "MULTIPOLYGON" к "ГЕОМЕТРИИ" )

Ответ 4

Я переписал функцию, которая была дана в предыдущей статье @danherd, поэтому она может работать с реальными мультиполигонами, которые состоят из более того, что один многоугольник, Для тех из вас, кто по-прежнему используйте старую версию MySql, которая должна помочь.

Вот он:

DELIMITER //

CREATE FUNCTION GISWithin(pt POINT, mp MULTIPOLYGON) RETURNS INT(1) DETERMINISTIC

BEGIN

DECLARE str_big, str, xy LONGTEXT;
DECLARE x, y, p1x, p1y, p2x, p2y, m, xinters DECIMAL(16, 13) DEFAULT 0;
DECLARE counter INT DEFAULT 0;
DECLARE p, pb, pe, sb, se, ct DECIMAL(16, 0) DEFAULT 0;

SELECT MBRWithin(pt, mp) INTO p;
IF p != 1 OR ISNULL(p) THEN
return p;
END IF;

SELECT X(pt), Y(pt), ASTEXT(mp) INTO x, y, str_big;
SET str_big = REPLACE(str_big, 'MULTIPOLYGON(((','');
SET str_big = REPLACE(str_big, ')))', '');
SET str_big = REPLACE(str_big, ')),((', '|');
SET str_big = CONCAT(str_big, '|');

SET sb = 1;
SET se = LOCATE('|', str_big);
SET str = SUBSTRING(str_big, sb, se - sb);

WHILE se > 0 DO
SET ct = ct + 1;
SET str = SUBSTRING(str_big, sb, se - sb);

SET pb = 1;
SET pe = LOCATE(',', str);
SET xy = SUBSTRING(str, pb, pe - pb);
SET p = INSTR(xy, ' ');
SET p1x = SUBSTRING(xy, 1, p - 1);
SET p1y = SUBSTRING(xy, p + 1);
SET str = CONCAT(str, xy, ',');

WHILE pe > 0 DO
SET xy = SUBSTRING(str, pb, pe - pb);
SET p = INSTR(xy, ' ');
SET p2x = SUBSTRING(xy, 1, p - 1);
SET p2y = SUBSTRING(xy, p + 1);
IF p1y < p2y THEN SET m = p1y; ELSE SET m = p2y; END IF;
IF y > m THEN
IF p1y > p2y THEN SET m = p1y; ELSE SET m = p2y; END IF;
IF y <= m THEN
IF p1x > p2x THEN SET m = p1x; ELSE SET m = p2x; END IF;
IF x <= m THEN
IF p1y != p2y THEN
SET xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x;
END IF;
IF p1x = p2x OR x <= xinters THEN
SET counter = counter + 1;
END IF;
END IF;
END IF;
END IF;
SET p1x = p2x;
SET p1y = p2y;
SET pb = pe + 1;
SET pe = LOCATE(',', str, pb);
END WHILE; 

SET sb = se + 1;
SET se = LOCATE('|', str_big, sb);

END WHILE;

RETURN counter % 2;

END

DELIMITER ;