Ответ 1
Создать таблицу с многоугольным столбцом
Обратите внимание, что для использования пространственных индексов вы не можете использовать InnoDB. Вы можете использовать геометрию без пространственных индексов, но производительность ухудшается, как обычно.
CREATE TABLE IF NOT EXISTS `spatial` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`poly` geometry NOT NULL,
UNIQUE KEY `id` (`id`),
SPATIAL INDEX `poly` (`poly`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Получить 3 квадрата и вставленный треугольник
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((10 50,50 50,50 10,10 10,10 50))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((1 15,5 15,5 11,1 11,1 15))',0));
INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((11 5,15 5,15 1,11 5))',0));
Выберите все, что пересекает небольшой квадрат в левом нижнем углу (фиолетовый квадрат № 1)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
)
;
Выберите все, что пересекает треугольник, начиная от нижнего левого угла до нижнего правого угла до верхнего правого угла) (квадраты # 1 и # 2 и треугольник # 4.)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
)
;
Выбирает все в квадрате, которое находится за пределами нашего изображения (Ничего)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(`poly`,
GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
)
;
Изменить # 1:
Я перечитал вопрос, и я думаю, что у вас пространственные отношения немного смущены. Если вы хотите найти все, что подходит ко всему внутри квадрата (многоугольник), тогда вам нужно использовать Contains/ST_Contains. Пожалуйста, смотрите пространственные функции в документации MySQL, чтобы узнать, какая функция выполняет эту работу для вас. Обратите внимание на следующее различие между функциями ST/MBR:
Выбирает все, что находится внутри квадрата (# 0 снизу) (квадраты # 1, # 2, треугольник # 4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Выбирает все, что находится внутри квадрата (# 0 снизу) и не имеет границ (квадрат № 2, треугольник № 4)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
`poly`
)
;
Изменить # 2:
Очень приятное дополнение от @StephanB (скрипт SQL)
Чтобы перечислить все пересечения, присоедините таблицу к себе и отфильтруйте обратное пересечение
Выбрать любые перекрывающиеся объекты
SELECT s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)
FROM `spatial` s1, `spatial` s2
WHERE
ST_Intersects(s1.poly, s2.poly)
AND s1.id < s2.id
;
(просто отметьте, что вы должны удалить AND s1.id < s2.id
, если вы работаете с CONTAINS
, как CONTAINS(a,b) <> CONTAINS(b,a)
while Intersects(a,b) = Intersects(b,a)
)
На следующем рисунке (неисчерпывающий список):
-
2 пересекает # 6.
-
6 пересекает # 2
-
0 пересекает # 1, # 2, # 3, # 4, # 5
-
1 пересекает # 0, # 5
-
0 содержит # 1, # 3, # 4 и # 5 (# 1, # 3, # 4 и # 5 находятся в пределах # 0)
-
1 содержит # 5 (# 5 находится в пределах # 1)
-
0 st_contains # 3, # 4 и # 5
-
1 st_contains # 5
Редактировать # 3: Поиск по расстоянию/Работа в (с) кругах
MySQL не поддерживает прямой круг как геометрию, но вы можете использовать пространственную функцию Buffer(geometry,distance)
, чтобы обойти ее. Что делает Buffer()
, создает буфер указанного расстояния вокруг геометрии. Если вы начинаете с точки геометрии, буфер действительно представляет собой круг.
Вы можете увидеть, какой буфер фактически выполняет, просто позвонив:
SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))
(результат довольно длинный, поэтому я не буду публиковать его здесь). Он фактически создает многоугольник, который представляет буфер - в этом случае (и мой MariaDB) результатом является 126-точечный многоугольник, который аппроксимирует круг. С таким полигоном вы можете работать так же, как и с любым другим полигоном. Таким образом, не должно быть штрафа за производительность.
Итак, если вы хотите выбрать все полигоны, которые попадают в круг, вы можете полоскать и повторить предыдущий пример (это найдет только квадрат # 3)
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Contains(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
Выберите все полигоны, которые пересекаются с кружком
SELECT id,AsText(poly) FROM `spatial`
WHERE
ST_Intersects(
Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
`poly`
)
;
При работе с фигурами, отличными от прямоугольников, вы должны использовать функции ST_*
. Функции без ST_
используют ограничивающий прямоугольник. Таким образом, предыдущий пример выбирает треугольник # 4, хотя он не находится в круге.
Так как Buffer()
создает довольно большие полигоны, определенная производительность может быть снижена с использованием метода ST_Distance()
. К сожалению, я не могу ее количественно оценить. Вам нужно будет провести бенчмаркинг.
Другой способ поиска объектов по расстоянию - использовать функцию ST_Distance()
.
Выберите все элементы из таблицы и вычислите их расстояние от точки POINT (6 15)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
;
Вы можете использовать ST_Distance
в разделе WHERE
.
Выберите все элементы, расстояние от которых POINT (0 0) меньше или равно 10 (выбирает # 1, # 2 и # 3)
SELECT id, AsText(`poly`),
ST_Distance(poly, GeomFromText('POINT(6 15)'))
FROM `spatial`
WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
;
Хотя расстояние вычисляется от ближайшей точки до ближайшей точки. Сделать его похожим на ST_Intersect
. Таким образом, приведенный выше пример будет выбирать # 2, даже если он не полностью помещается внутри круга.
И да, второй аргумент (0) для GeomFromText(text,srid)
, не играет никакой роли, вы можете смело игнорировать его. Я выбрал его из какого-то образца, и он застрял в моем ответе. Я оставил это в моих последних изменениях.
кстати. phpMyAdmin поддержка пространственного расширения не безупречна, но это помогает совсем немного узнать, что находится в вашей базе данных. Помог мне с этими изображениями, которые я приложил.