PostGIS:一组共线线段的交叉点,带有计数

时间:2016-06-24 15:23:18

标签: postgresql gis postgis

我有一组共线线段(可能是相互不相交,包含或重叠)。

我想制作一组新的线段,其中线段不相交或接触(不重叠),每个线段都有一个覆盖它的原始线段的计数。

例如,假设原始集合(非共线绘制以用于说明):

A----------------------B
        C---------------------------D
            E-----F
                                           G-------------H
                                                         I-------J

所需的新集合将是:

A-------C---E-----F-----B-----------D      G-------------H-------J
    1     2    3     2        1                    1         1

(只有点坐标很重要,新集合不与旧集合共享点对象)

如何使用PostGIS实现这一目标?

相关问题:假设我从一个线段表开始,而不是所有共线,我如何编写将共线段组合在一起的整个查询,然后将解决方案应用于我的第一个问题?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

设置(供以后查询):

create table lines (
  id        serial               primary key,
  label     text                 not null,
  line_data geometry(linestring) not null
);

insert into lines(label, line_data)
values ('A-B', ST_MakeLine(ST_MakePoint(-3, -6), ST_MakePoint( 1,  2))),
       ('D-C', ST_MakeLine(ST_MakePoint( 2,  4), ST_MakePoint(-2, -4))),
       ('E-F', ST_MakeLine(ST_MakePoint(-1, -2), ST_MakePoint( 0,  0))),
       ('G-H', ST_MakeLine(ST_MakePoint( 3,  6), ST_MakePoint( 4,  8))),
       ('I-J', ST_MakeLine(ST_MakePoint( 4,  8), ST_MakePoint( 5, 10))),
       ('P-L', ST_MakeLine(ST_MakePoint( 1,  0), ST_MakePoint( 2,  2))),
       ('X-Y', ST_MakeLine(ST_MakePoint( 2,  2), ST_MakePoint( 0,  4)));

备注

  • 我故意切换你的D和C点以证明需要矢量否定
  • P-L行与您的示例行平行(但不是共线)
  • X-Y行与其他人
  • 无关
  • 下面的解决方案显然不会起作用,当你的线串 s超过2点并且那些不在同一条线上时(所以当一个线串< / em>不直)。

ST_Union聚合函数可以拆分共线线串。您只需要计算包含这些行的行数。

然而,通过共线性进行分组并不那么简单。我没有找到任何开箱即用的解决方案,但你可以计算它(这还不计算数量):

select   string_agg(label, ','), ST_AsText(ST_Multi(ST_Union(line_data)))
from     lines
group by (
  select case
           when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
           when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
           when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
           else (
             select  row(
                       ST_SRID(s),
                       (select case
                          when ST_Y(rv) < 0
                          then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
                          else rv
                        end), -- normalized vector (negated when necessary, but same for all parallel lines)
                       (ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
                     )
             from    coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
                     ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
           )
         end
  from   ST_StartPoint(line_data) s,
         ST_EndPoint(line_data) e
)

将产生:

X-Y                 | MULTILINESTRING((2 2,0 4))
P-L                 | MULTILINESTRING((1 0,2 2))
E-F,A-B,I-J,G-H,D-C | MULTILINESTRING((-3 -6,-2 -4),(-2 -4,-1 -2),(-1 -2,0 0),(0 0,1 2),(2 4,1 2),(3 6,4 8),(4 8,5 10))

要再次计算您的原始数据的计数JOIN,其中分割的行包含(ST_Contains)原始行:

select    ST_AsText(splitted_line), count(line_data)
from      (select   ST_Multi(ST_Union(line_data)) ml
           from     lines
           group by (
             select case
               when ST_SRID(s) <> ST_SRID(e) then row(ST_SRID(s), s, null)
               when ST_X(s) = ST_X(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(ST_X(s), 1.0), ST_SRID(s)), null)
               when ST_Y(s) = ST_Y(e) then row(ST_SRID(s), ST_SetSRID(ST_MakePoint(1.0, ST_Y(e)), ST_SRID(s)), null)
               else (
                 select  row(
                           ST_SRID(s),
                           (select case
                              when ST_Y(rv) < 0
                              then ST_SetSRID(ST_MakePoint(-ST_X(rv), -ST_Y(rv)), ST_SRID(s))
                              else rv
                            end), -- normalized vector (negated when necessary, but same for all parallel lines)
                           (ST_X(e) * ST_Y(s) - ST_X(s) * ST_Y(e)) / (ST_X(e) - ST_X(s)) -- solution of the linear equaltion, where x=0
                         )
                 from    coalesce(1.0 / nullif(ST_Distance(s, e), 0), 0) dmi, -- distance's multiplicative inverse
                         ST_TransScale(e, -ST_X(s), -ST_Y(s), dmi, dmi) rv -- raw vector (translated and scaled)
               )
             end
             from   ST_StartPoint(line_data) s,
                    ST_EndPoint(line_data) e)) al,
          generate_series(1, ST_NumGeometries(ml)) i,
          ST_GeometryN(ml, i) splitted_line
left join lines on ST_Contains(line_data, splitted_line)
group by  splitted_line

将返回:

LINESTRING(-3 -6,-2 -4) | 1
LINESTRING(-2 -4,-1 -2) | 2
LINESTRING(-1 -2,0 0)   | 3
LINESTRING(0 0,1 2)     | 2
LINESTRING(2 2,0 4)     | 1
LINESTRING(1 0,2 2)     | 1
LINESTRING(2 4,1 2)     | 1
LINESTRING(3 6,4 8)     | 1
LINESTRING(4 8,5 10)    | 1