代码之家  ›  专栏  ›  技术社区  ›  Ryan Wheale

postgres/postgis-确保所有多边形都是闭合的

  •  5
  • Ryan Wheale  · 技术社区  · 6 年前

    我需要编写一个查询,找到任何未闭合的多边形,并通过复制第一个点和创建一个额外的端点来闭合它们。

    我可以选择无效行:

    SELECT delivery_zone_id, polygon from delivery_zone WHERE ST_IsClosed(polygon::geometry) = FALSE;
    

    我可以从每个多边形中转储各个点:

    SELECT delivery_zone_id, ST_AsText((dp).geom) FROM
        (SELECT delivery_zone_id, ST_DumpPoints(polygon::geometry) AS dp 
            FROM delivery_zone 
            WHERE ST_IsClosed(polygon::geometry) = FALSE
        ) AS coords;
    

    结果如下:

    1   POINT(-96.80037 33.09812)  ## Copy this point and add it to the set
    1   POINT(-96.80427 33.0956)
    1   POINT(-96.80401 33.09219)
    1   POINT(-96.79603 33.09222)
    1   POINT(-96.79346 33.09647)
    1   POINT(-96.80037 33.09857)
    
    4   POINT(-96.80037 33.099)    ## Copy this point and add it to the set
    4   POINT(-96.80427 33.0956)
    4   POINT(-96.80401 33.09219)
    4   POINT(-96.79603 33.09222)
    4   POINT(-96.79346 33.09647)
    4   POINT(-96.80037 33.09923)
    

    这就是我缺乏sql技能的地方。我需要一些帮助来复制第一个点并用这些数据创建一个新的端点。伪查询是受欢迎的-我只需要看看它可能是什么样子的,我可以填补空白。


    更新:最终解决方案

    由于下面来自jgh的回答,我能够创建以下更新查询。这将找到任何未闭合的多边形,并通过复制第一个点添加新的端点。

    注意:这只适用于简单的“单”多边形。如果有复杂的外部和内部多边形,则需要对此查询进行一些重大更改。

    UPDATE delivery_zone dz
    SET polygon=ST_MakePolygon(ST_AddPoint(subquery.openline, ST_PointN(subquery.openline, 1), -1))
    FROM (
      SELECT delivery_zone_id, ST_ExteriorRing(polygon::geometry) AS openline 
      FROM delivery_zone WHERE ST_IsClosed(polygon::geometry) = FALSE
    ) AS subquery
    WHERE dz.delivery_zone_id = subquery.delivery_zone_id;
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   JGH    6 年前

    可以尝试使用直线添加点,然后转换为多边形。

    让我们注意到,创建一个非闭合多边形是不可能的…不太清楚你是怎么得到的,希望你能在一开始把它们转换成一行。

    所以,我们的想法是得到这条线,然后在它的最后一个位置(-1)添加一个点。该点将与该线的第一个点(位置1)相同。最后你可以转换成多边形

    WITH src AS (
        SELECT ST_GeomFromText('LINESTRING(0 0, 0 1, 1 1, 1 0)') As openline)
    SELECT st_asText(openline), 
            st_asText(ST_MakePolygon(st_addPoint(openline,st_PointN(openline,1),-1)))
    FROM src;
    
    
    
          st_astext          |           st_astext
    -----------------------------+--------------------------------
     LINESTRING(0 0,0 1,1 1,1 0) | POLYGON((0 0,0 1,1 1,1 0,0 0))
    (1 row)