在可及区域上建立多边形


10

我目前在等时线和基础算法领域中工作。现在引起问题的不是等位线本身的计算,而是结果的可视化。
我的等时线算法的结果是点和边。实际上,我确实有一个可行的解决方案,但是对于3873个边缘和1529个节点而言,事情似乎要花很多时间(在装有2015 Core i7 CPU和相当快的SSD的Lenovo T440s笔记本电脑上大约需要2.0秒)。而不是几秒钟,我想要的更像是msec :-)。

也许有人可以帮助我减少构建可视化可到达区域的多边形所需的计算时间。

但是等一下……第一件事!
这是等边线的计算结果,等时线计算结果(存在线串的骨架) 这些边线是我的可视化效果: 这些边线存储在PostGIS数据库表中,是简单的线串。

我要向用户显示的内容如下所示: 在此处输入图片说明 请注意图片最南端和最东端的断开区域。这些应绘制为单独的区域(因此此处不允许合并:-)

目前,我正在使用此查询:

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_MakePolygon(ST_ExteriorRing(ST_GeometryN(segments, generate_series(1, ST_NumGeometries(segments))))) AS polygons FROM (
        SELECT ST_Union(ST_Buffer("GEOMETRY", 20, 'quad_segs=2')) AS segments FROM my_edges AS a
    ) AS b
) AS c

我已经做了一些实验,并且阅读了很多文档,但是我找不到更好的解决方案。
在我眼中,最大的问题是ST_Union的用法(如docs中所述,此功能可能很慢)。有趣的是,用ST_Collect替换它似乎会减慢ST_Buffer的计算,因此以下所有查询甚至花费更长的时间,尽管它不会填充边缘之间的区域(它只会在线条周围创建缓冲区):

SELECT ST_AsGeoJson(St_Transform(ST_Multi(ST_Collect(polygons)), 4326)) AS coverage FROM (
    SELECT ST_Buffer(ST_Collect(ST_LineMerge("GEOMETRY")), 20, 'quad_segs=2') AS polygons FROM my_edges AS a
) AS b

这在我的系统上大约需要3.8秒(几乎是两倍的时间)。我从这个小小的基准测试中得出的第一个结论是,在使用MultiLineStrings时,ST_Buffer的速度出乎意料的慢(甚至比为每行创建缓冲区并合并缓冲区时的速度还要慢-在我看来这很奇怪)

我也尝试使用alpha形状(使用pgRouting的实现),但是由于没有要设置的alpha值(实际上,我现在真的不愿意将哪个值设置为这样的值),所以我只得到了一个大多边形(因此我会把南部和东部的区域作为单独的区域丢失,这不是我想要的)。
同样ST_Polygonize(这是我想到的第一件事)没有产生任何可用的结果,但是也许我在这里错过了一些东西...

有没有更好的方法来创建PostGIS中显示的区域?也许还通过使用Java代码(jts)或客户端javascript代码(jsts)?实际上,只要结果中显示的区域保持分离并且计算速度快得多,我可以忍受一些细节丢失。


您是否可以不仅仅使用ST_Exteriorring(ST_Dump(ST_Union(ST_Buffer(geom,....))))。geom认为缓冲的任何东西都将是多边形,并且ST_Union将连接所有相交的几何体,因此不需要MakePolygon或GeometryN。您可能需要测试有时在缓冲区之后由ST_Union产生的Linestrings,但是对于ST_GeometryType(geom)来说这很容易。就Java或jsts而言,您可以,但是考虑到a Postgis(GEOS)函数的很大一部分首先是JTS的C / C ++端口
John Powell

没错,这行得通,但是实际上并不能更快(大约需要3.1秒,而使用GeometryN需要2秒)。这是我使用的东西:从my_edges中选择ST_AsGeoJson(ST_Transform(ST_Exteriorring((ST_Dump(ST_Union(ST_Buffer(“ GEOMETRY”,20))))。geom),4326)))。
Nikolaus Krismer

@john-barça:哦..在尝试您的方法时,我将ST_Buffer中的quad_segs = 2部分模糊了……通过这种更改,查询是均匀的(都在2秒左右)。但是,这仍然很慢(在我眼中),还有另一种尝试方法吗?
Nikolaus Krismer

有趣的问题....您要共享一些测试数据吗?
dbaston

如果有帮助,我很乐意分享一些数据。我在这里所做的所有事情都是开源的,因此这应该不是什么大问题。首先要注意:用于测试的Web应用程序位于dbis-isochrone.uibk.ac.at:8080/testing。有关我从事的工作的更多信息,请访问dbis-isochrone.uibk.ac.at。在网站的“链接”部分中,还有其他参考(包括一些测试数据)
Nikolaus Krismer

Answers:


5

除了GeoJSON序列化,以下内容在我的笔记本电脑上大约需要6.3秒:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(geom, 20, 2)))).geom))
FROM bz_edges

查看OpenJUMP中的数据,相对于输出中所需的细节水平,我注意到街道部分有很多细节。看来,即使是对这些行的即时简化也可以在PostGIS中大大提高速度:

SELECT
  ST_MakePolygon(
    ST_ExteriorRing(
      (ST_Dump(
        ST_Union(
          ST_Buffer(ST_Simplify(geom, 10), 20, 2)))).geom))
FROM bz_edges

这使事情降到了2.3秒。我以为可以将广义几何存储在单独的列中,而不是即时进行计算,这样可能会做得更好,但是实际上并没有提供任何其他好处。

根据自己愿意编写多少代码,几乎可以肯定,在Java中可以做得更好,如果没有其他选择,因为您可以利用多个内核。(为此,JTS只需2.8秒即可完成上述操作)。一种方法可能是扩展CascadedPolygonUnion以使某些联合操作并行发生。(更新-这是一个ParallelCascadedPolygonUnion

我在示例数据中注意到,边缘是通过引用其起点和终点来存储的,即您具有一个预先构建的图形。我怀疑你可以生成这些多边形得多更快,如果你从图中,而不是使用通用的几何操作工作。例如,我认为您可以这样做:

  1. 识别图的连接组件
  2. 对于每个连接的组件,找到具有最小X坐标的节点(保证在组件的外部)
  3. 走组件的边缘,并尽可能向左(或向右)转弯。这将为您提供每个组件的外圈。
  4. 使外圈多边形化并适当缓冲。

谢谢...简化是一个很大的进步,甚至是“简单”的进步。我的笔记本电脑所需的时间减少到1.5秒。这不是我想要的地方,但是要好一点。
Nikolaus Krismer

关于建议的解决方案(第1-4点)。听起来也很简单,值得一试。我想到了类似的东西,但是我停留在point1上(太早了:-)。如何识别连接的组件(我唯一想到的是一个递归查询,它可能也很慢)。
Nikolaus Krismer

@NikolausKrismer我将JGraphTloom都用于这样的任务。如果您改写自己的图方法(对于获得最佳性能来说不是一个坏主意),则深度优先搜索将为您找到组件。(您可以在即将发布的PostGIS 2.2中找到它们,ST_ClusterIntersecting但我想您还是希望在数据库外部进行任何类型的图形处理,因此这可能没有用)。
dbaston

这些是一些很棒的提示。我查看了JGraphT,这肯定可以帮助解决我的问题。但是,我还查看了Postgis 2.2和ST_ClusterIntersecting函数->在上述情况下,识别不同的群集大约需要200-250毫秒。对我来说没关系(JGraphT当然可以做得更好)。现在,我必须处理创建外部环(ST_ExteriorRing失败,因为ST_MakePolygon说我的链接没有外壳)
Nikolaus Krismer

我看到两个复杂情况:(a)您不仅需要外环,而且还需要从该环向外延伸的任何线段,并且(b)看起来您的线实际上在某些相交处没有相交。如果要尝试根据图遍历的结果构造几何图形,则需要修复(b)。
dbaston
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.