2016-06-24 19 views
1

Iは(含まれる、または重複、互いにばらばらであってもよい)共線セグメントのセットを有します。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

一度に1つの質問をしてください、あなたのテーブルといくつかのサンプルデータを投稿してください。 – e4c5

答えて

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行は何もしています他人
  • で行うことを明らかに以下の解決策は、(そう、単一のラインストリングがまっすぐでないとき)あなたは2ポイント以上およびそれらを持っているラインストリングは同一ライン上にないていたときに、動作しません。 。

ST_Union集約関数は Sをラインストリングあなたのコリニアを分割することができます。それらを含む線の数を計算するだけで済みます。

しかし、共線性によってグループ分けはそれほど単純ではありません。(これはまだ数を計算しません)私は、このためにいかなるすぐに解決策を見つけることができませんでしたが、あなたはそれを計算することができます:

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)) 

をカウントを計算するには、分割さ行が(ST_Contains)元の線で含まれて再びJOINあなたの元のデータは、:

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 
+0

ありがとうございます。今私は実際のデータ(OpenStreetMapからのルート)を使用して最初のSQLクエリを実行しようとしましたが、エラーを受け取ります: "エラー:複合SRIDジオメトリSQL状態:XX000での操作"。 EPSGのデータベースの線形ジオメトリ:4326座標系。このエラーを修正するにはどうすればよいですか? GeoJSON形式のデータ例[link](https://github.com/spatialhast/sh.route/blob/master/union_routes_line.geojson)ありがとう! – HasT

+0

@HasT SRIDを混在させることはできません。データがある場合は、f.ex. SRID = 4326の場合、ST_SetSRID(ST_MakePoint(...)、4326) 'コール](http://www.postgis.net/docs/ST_SetSRID.html)内で' ST_MakePoint'呼び出しをラップする必要があります。 – pozs

+0

@HasT SRIDを搭載するように私のソリューションを更新しました。しかし、私は言う必要があります:あなたのサンプルデータは、それが直線だけを持っているように見えません。それらの作業だけのためのソリューション。 – pozs

関連する問題