【问题标题】:Postgis reorder mixed up linestring chunks / max_segment_length(linestring)?Postgis重新排序混合的线串块/ max_segment_length(linestring)?
【发布时间】:2012-04-24 22:52:42
【问题描述】:

我将大约 1000 条路径从某处导入我的 postgis 数据库到线串字段。

(EDIT) 我的桌子是这样的

+---------+---------------+------------------+
| id(int) | name(varchar) | path(LINESTRING) |
+---------+---------------+------------------+
| 123     | foo           | 000002...        |
| 124     | bar           | 000002...        |

我遇到的问题是每个路径都被分成块,并且在某些情况下这些块被混淆了。

假设一个线串在点号 50 和 70 处被分割:

  1. A 块:1-50 分
  2. 块 B:点 51-70
  3. C 块:71-100 分

当我将它迁移到我的数据库中时,它们混合在一起,因此结果线串可能会像这样结束:

  1. A 块:1-50 分
  2. C 块:71-100 分
  3. 块 B:点 51-70

所以这会产生从 50 到 71 的跳跃和另一个从 100 到 51 的跳跃

(EDIT) 当我导入这些分成块的路径时,我认为它们是有序的,但事实是有些是混合的,这使得我的一些线串与它们的点是有序的像第二个例子。

我希望能够重新排序这些(点)块,因此我想构建一个 SQL 查询来检测哪些路径具有混合点,然后我可以手动(使用使用 openlayers 制作的工具)重新排列它们。

最好有一个 SQL 更新查询来解决这个问题,但我认为检测更容易(我假设有大约 5% 或更少的路径有错误)

EDIT3:我认为检测脚本可以检查路径是否包含距离太远的一对连续点。也许从包含最长段的路径排序路径的 SQL 会很好。

如何创建一个函数来获取线串中最大段的长度?

这里我举一个例子: 这是它在数据库中的样子

这就是我想要修复的方式

EDIT4:就像我在 EDIT3 上计划的那样,可以编写一个函数来查找线串中两个连续点之间的最长距离,该函数使用 ST_NPoints()ST_PointN() 遍历线串的点,然后可以进行查询以对具有最长距离的路径进行排序。这个距离太长的线串很可能会出现所描述的问题。这样我就可以检测到它们,并手动修复它们。

检测 SQL 的结果是这样的:

                                             |ordered by this|
+---------+---------------+------------------+---------------+
| id(int) | name(varchar) | path(LINESTRING) |  msbtcp(int)  |
+---------+---------------+------------------+---------------+
| 123     | foo           | 000002...        | 1000          |
| 124     | bar           | 000002...        | 800           |

*msbtcp 将是函数的结果:max_separation_between_two_consecutive_points(path)

【问题讨论】:

    标签: sql postgresql postgis multilinestring


    【解决方案1】:

    你想知道的是段是如何链接的,所以你需要将每个段的第一个和最后一个点与所有其他段进行比较:

    SELECT foo.gid as segment_a, bar.gid as segment_b
        FROM 
            segments AS foo, 
            (SELECT the_geom, gid FROM segments) AS bar
        WHERE 
            bar.gid != foo.gid AND ( -- avoid same segments  
            ST_DWithin( 
                    ST_GeometryN(foo.the_geom,  ST_NumGeometries(foo.the_geom)) , -- last from foo
                    ST_GeometryN(bar.the_geom,  ST_NumGeometries(bar.the_geom)) , -- last from bar
                    0.00005 ) OR -- precision, depends of your SRID
            ST_DWithin( 
                    ST_GeometryN(foo.the_geom,  1) , -- first from foo (start = 1 index)
                    ST_GeometryN(bar.the_geom,  ST_NumGeometries(bar.the_geom)) , -- last from bar
                    0.00005 ) OR -- precision, depends of your SRID
            ST_DWithin( 
                    ST_GeometryN(foo.the_geom,  ST_NumGeometries(foo.the_geom)) , -- last from foo
                    ST_GeometryN(bar.the_geom,  1) , -- first from bar
                    0.00005 ) OR -- precision, depends of your SRID
            ST_DWithin( 
                    ST_GeometryN(foo.the_geom,  1) , -- first from foo 
                    ST_GeometryN(bar.the_geom,  1) , -- first from bar
                    0.00005 ) ) -- precision, depends of your SRID
    

    瞧……! 您可以将此链接保存在新表中,并使用 ST_Union 连接链接的段。

    【讨论】:

    • 我认为如果表中的每个线串都是一个段,那么代码就可以工作。我要解释的是,每个线串(只有一个字段)都与自身混合。当我说“段”时,我的意思是线串的一部分,这样,一个段将是例如ST_pointN(linestring, 1) -- ST_PointN(linestring, 2)
    • 类型将是 LINESTRING,我将用更多信息编辑问题,抱歉 :)
    • 好的,所以在迁移后的线串示例中,段的最后一点(块 A 的点 50)离下一段的第一个点(表示相同的位置)很近(代表相同的位置)块 B 的第 51 点)或它们之间的距离是随机的(随机的,因为根据线串的形状,它可能很近但也可能很远)?
    • 使用该解释,距离是随机的,但在 90% 的情况下是相对较远的。我发布了一个屏幕截图以便更好地理解。
    【解决方案2】:

    这听起来有点令人费解,但是如果您刚好在线串中两个连续点之间的最大距离之后:

    CREATE OR REPLACE FUNCTION max_distance_in_linestring(line geometry) RETURNS float as $BODY$
    DECLARE
        i integer;
        n integer;
        d float;
        m float;
    BEGIN
        d := 0;
        n := ST_NPoints(line);
        i := 2;
        LOOP
            EXIT WHEN i >= n;
            m := ST_Distance(ST_PointN(line,i-1),ST_PointN(line,i));
            -- use for lon,lats:
            -- m := ST_Distance(ST_PointN(line,i-1)::geography,ST_PointN(line,i)::geography);
            IF m > d THEN
                d := m;
            END IF;
            i := i + 1;
        END LOOP;
        RETURN d;
    END;
    $BODY$
    LANGUAGE plpgsql;
    
    SELECT max_distance_in_linestring('LINESTRING(0 0, 1 1, 2 2)'::geometry);
    SELECT max_distance_in_linestring('LINESTRING(0 0, 4 3, 2 2)'::geometry);
    

    您可能希望将 ST_PointN 调用重新投射到 ::geography 以获取以米为单位的距离。

    SQL 应该是这样的:

    SELECT
      name, path 
    FROM
      paths
    ORDER BY
      max_distance_in_linestring(path) DESC
    

    【讨论】:

    • line geometry(LINESTRING) 抛出错误,所以我将其更改为 line geometry。就像检测的魅力一样。
    • 啊,我用的是 PostGIS-2.0;你必须在 1.5 上?
    猜你喜欢
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多