我正在尝试创建一个包含大型面数据集的 web 地图。为了提高性能,我希望在缩小时减少多边形细节。
MySQL是否能够简化多边形和其他几何形状作为查询的一部分?
编辑:正如James指出的那样,从5.7开始,MySQL确实支持ST_Simplify。
恐怕MySQL空间中没有简化功能。五年前,我将其作为功能请求提交,您可以看到从那时起它就没有受到任何关注。
您有许多选项,具体取决于您是要一次性执行此操作,还是具有动态数据。
1(. 使用 PointN 函数编写一个快速而脏的函数来访问您的点,只取每 5 个点,创建一个表示简化几何的 WKT 字符串,然后使用 GeomFromText 函数重新创建几何。
2(. 将多边形转储为 WKT,使用 AsText(geom( 到 csv。使用COPY命令(相当于LOAD DATA INFILE(导入Postgres/Postgis,并在那里使用ST_Simplify函数,然后反向该过程以重新导入MySQL。
3(. 使用 ogr2ogr 转储为 shp 格式,然后使用 mapshaper 等工具来简化它,输出到 shp,然后使用 ogr2ogr 再次导入。Mapshaper 很好,因为您可以了解算法的工作原理,并且可能会使用它来实现您自己的算法,而不是选项 1。
还有其他选项,例如如果您使用的是Java服务器端,请使用Java Topology Suite,但我希望这能让您了解如何继续。
很抱歉,最初的答案是否定的。几年前我经历了这个问题,最终永久切换到Postgres/Postgis,因为它在空间工作中的功能更加充分。
MySQL 5.7包含ST_Simplify
简化几何形状的功能。
从 https://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html:
ST_Simplify(g, max_distance)
使用 Douglas-Peucker 算法简化几何图形,并返回相同类型的简化值,如果任何参数为 NULL,则返回 NULL。
与 5.6 相比,MySQL 5.7 对空间功能进行了重大修改,现在从 5.7.9 开始处于正式发布状态。
我有一个用例,我想使用ST_Simplify
,但代码必须在MySQL 5.6上运行(它没有它(。因此,我开发了一个解决方案,就像约翰鲍威尔在另一个答案中提出的解决方案一样。
不幸的是,MySQL不提供任何聚合,您可以通过逐步向其添加点来创建几何图形(即没有ST_AddPoint
或类似(。撰写几何图形的唯一方法是逐步将其构建为 WKT 字符串,然后最终将完成的字符串转换为几何图形。
下面是一个存储函数的示例,它接受一个MultiLineString
,并通过只保留每个第 n 个点来简化其中的每个LineString
,确保始终保留起点和终点。这是通过遍历多线字符串中的线串,然后遍历每个点(根据需要跳过(并在 WKT 字符串中累积手数来完成的,最后使用 ST_GeomCollFromText
将其转换为几何图形。
-- geometryCollection: MultiLineString collection to simplify
-- skip: Number of points to remove between every two points
CREATE FUNCTION `sp_CustomSimplify`(gc geometrycollection, skip INT) RETURNS geometrycollection
BEGIN
DECLARE i, j,numLineStrings, numPoints INT;
DECLARE ls LineString;
DECLARE pt, lastPt Point;
DECLARE ls LineString;
DECLARE lastPt Point;
DECLARE txt VARCHAR(20000);
DECLARE digits INT;
SET digits = 4;
-- Start WKT string:
SET txt = 'MULTILINESTRING(';
-- Loop through the LineStrings in the geometry (which is a MultiLineString)
SET i = 1;
SET numLineStrings = ST_NumGeometries(gc);
loopLineStrings: LOOP
IF i > numLineStrings THEN LEAVE loopLineStrings; END IF;
SET ls = ST_GeometryN(gc, i);
-- Add first point to LineString:
SET pt = ST_StartPoint(ls);
SET txt = CONCAT(txt, '(', TRUNCATE(ST_X(pt),digits), ' ', TRUNCATE(ST_Y(pt),digits));
-- For each LineString, loop through points, skipping
-- points as we go, adding them to a running text string:
SET numPoints = ST_NumPoints(ls);
SET j = skip;
loopPoints: LOOP
IF j > numPoints THEN LEAVE loopPoints; END IF;
SET pt = ST_PointN(ls, j);
-- For each point, add it to a text string:
SET txt = CONCAT(txt, ',', TRUNCATE(ST_X(pt),digits), ' ', TRUNCATE(ST_Y(pt),digits));
SET j = j + skip;
END LOOP loopPoints;
-- Add last point to LineString:
SET lastPt = ST_EndPoint(ls);
SET txt = CONCAT(txt, ',', TRUNCATE(ST_X(lastPt),digits), ' ', TRUNCATE(ST_Y(lastPt),digits));
-- Close LineString WKT:
SET txt = CONCAT(txt, ')');
IF(i < numLineStrings) THEN
SET txt = CONCAT(txt, ',');
END IF;
SET i = i + 1;
END LOOP loopLineStrings;
-- Close MultiLineString WKT:
SET txt = CONCAT(txt, ')');
RETURN ST_GeomCollFromText(txt);
END
(通过将位提取到单独的函数中,这可能会更漂亮。