我有一组共线线段(可能相互不相交、包含或重叠)。
我想创建一组新的线段,其中线段是不相交或接触的(不重叠),并且每个线段都有覆盖它的原始线段的计数。
例如,假设原始集为(绘制为非共线图以供说明):

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实现这一点?
相关问题:假设我从一个线段表开始,而不是所有的共线,如何编写将共线线段组合在一起的整个查询,然后将解决方案应用于我的第一个问题?
谢谢你的帮助!

最佳答案

设置(用于以后的查询):

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行与其他行无关
下面的解决方案显然是行不通的,如果有超过2个点的线串,并且这些点不在同一条线上(所以当一个线串不是直线时)。
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

10-05 23:05