如何处理MySQL多边形重叠查询?

TIM*_*MEX 16 mysql database

例如,我有一个用户表.每个用户都是地图上的"方形"(或圆圈).

我想找到地图上另一个方块重叠的用户.MySQL 5.6目前是否支持此功能?(MySQL的开发版本怎么样?)

请注意,我不是在寻找"在这个广场内找到一个点的用户".我正在寻找"找到方形与这个方块重叠的用户(不一定包含;只要两个方块都触摸 - 它很好)".

如果某人可以提供INSERTING记录的示例,然后使用ST_INTERSECT多边形对它们进行查询,那将会非常有用.

Fox*_*Fox 27

SQL小提琴 多边形演示

使用多边形列创建表

请注意,要使用空间索引,您不能使用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;
Run Code Online (Sandbox Code Playgroud)

获得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));
Run Code Online (Sandbox Code Playgroud)

选择与左下角的小方块相交的所有内容 (紫色方块#1)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
        )
;
Run Code Online (Sandbox Code Playgroud)

选择与从左下角到右下角到右上角的三角形相交的所有内容 (正方形#1和#2以及三角形#4.)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
        )
;
Run Code Online (Sandbox Code Playgroud)

选择我们图像之外的正方形中的所有内容 (无)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(`poly`,
            GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
        )
;
Run Code Online (Sandbox Code Playgroud)

编辑#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`
        )
;
Run Code Online (Sandbox Code Playgroud)

选择完全在正方形内的所有内容(从下面开始#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`
        )
;
Run Code Online (Sandbox Code Playgroud)

编辑#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
;
Run Code Online (Sandbox Code Playgroud)

(只是注意,你应该删除AND s1.id < s2.id,如果你正在使用CONTAINS,如CONTAINS(a,b) <> CONTAINS(b,a)同时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))
Run Code Online (Sandbox Code Playgroud)

(结果很长,所以我不会在这里发布)它实际上创建了表示缓冲区的多边形 - 在这种情况下(和我的MariaDB)结果是126点多边形,它使一个圆形变为近似.使用这样的多边形,您可以像处理任何其他多边形一样工作.所以应该没有性能损失.

因此,如果您想要选择落入圆圈的所有多边形,您可以冲洗并重复前面的示例(这将只找到方形#3)

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Contains(
          Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
          `poly`
        )
;
Run Code Online (Sandbox Code Playgroud)

选择与圆相交的所有多边形

SELECT id,AsText(poly) FROM  `spatial` 
    WHERE 
        ST_Intersects(
          Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
          `poly`
        )
;
Run Code Online (Sandbox Code Playgroud)

使用与矩形不同的形状时,应使用这些ST_*函数.函数不ST_使用边界矩形.因此,前面的示例选择三角形#4,即使它不在圆圈中.

由于Buffer()创建了相当大的多边形,因此使用该ST_Distance()方法肯定会有一些性能损失.不幸的是我无法量化它.你将不得不做一些基准测试.

将圆圈添加到第一个示例

另一种通过距离查找对象的方法是使用该ST_Distance()函数.

从表中选择所有元素并计算它们与点POINT的距离(6 15)

SELECT id, AsText(`poly`), 
    ST_Distance(poly, GeomFromText('POINT(6 15)')) 
    FROM `spatial`
;
Run Code Online (Sandbox Code Playgroud)

您也可以使用ST_Distancein 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
;
Run Code Online (Sandbox Code Playgroud)

尽管距离是从最近点到最近点计算的.使它类似于ST_Intersect.所以上面的例子将选择#2,即使它不完全适合圆圈.

是的,第二个参数(0)GeomFromText(text,srid),没有任何作用,你可以放心地忽略它.我从一些样本中捡起它,这有点困在我的答案中.我在以后的编辑中将其遗漏了.

顺便说一句.phpMyAdmin对空间扩展的支持并不完美,但它有助于查看数据库中的内容.用我附上的这些图片帮助了我.