[OSGeoJapan-discuss] PostGIS用の便利なファンクション

Hiroo Imaki hiroo @ angeli.org
2010年 7月 22日 (木) 02:52:21 EDT


リストの皆様、

先日、pgRoutingを使ったダムから河口までの距離計算について質問した今木です。しばらくこの問題と格闘している間に、いくつか便利なファンクションを書いたので(といっても誰かの書いたものを取り込んだり、改善したりしたものですが)皆さんのお役に立てばと思いポストします。

一つ目は、複数の点(POINT)を線(LINESTRING)にスナップするファンクションです。これは、Paul
Ramseyのブログからメインのコードを拝借してファンクションにしたものです。使い方は、
SELECT * FROM points_snap2lines
   ('SELECT gid AS id, the_geom AS geom FROM point_table',
    'SELECT gid AS id, the_geom AS geom FROM line_table',
     0.0001);
のようにして、最後に地図の単位でスナップの許容度を入力します。このファンクションを実行するとポイント、ラインのそれぞれのIDとスナップ後のジオメトリーが帰ってきます。

2つ目は、複数の点を使って複数の線をクリップするファンクションです。これは、
http://postgis.refractions.net/pipermail/postgis-users/2007-September/017159.htmlの歩スティングにあったファンクションを書き換えたものです。このポスティングのままでは私のpostgresql8.3.3ではうまく動かなかったので、手直ししたのと、ST_DWithin()を使って多少、点が線からずれていてもクリップできるようにしたのと、基本的なループ上のエラーを直したものです。使い方は、
SELECT * FROM split_lines2('SELECT gid AS id, the_geom AS geom FROM
line_table',
                           'SELECT the_geom AS geom FROM point_table',
0.0001);
のようにして、 ST_DWithinの距離パラメターを最後に入力します。

私の環境(WindowsXP,
PostgreSQL8.3.3)ではうまく動きました。改良、バグなどありましたら連絡ください。使った感想などもお聞かせください。

いまき

CREATE OR REPLACE FUNCTION points_snap2lines (in pt_q text, in ln_q text, in
torelance float4, out p_id int, out l_id int, out p_geom geometry)
RETURNS SETOF RECORD AS
$$
DECLARE
  snap_q text;
  pointrec record;
BEGIN
 EXECUTE 'CREATE TEMP TABLE line_tmp as '|| ln_q;
 EXECUTE 'CREATE TEMP TABLE point_tmp as '|| pt_q;
snap_q :='
SELECT
  pt_id,
  ln_id,
  ST_line_interpolate_point(
    ln_geom,
    ST_line_locate_point(ln_geom, pt_geom)
  ) AS the_geom
FROM
  (
    SELECT DISTINCT ON (pt.id)
      ln.the_geom AS ln_geom,
      pt.the_geom AS pt_geom,
      ln.id AS ln_id,
      pt.id AS pt_id
    FROM
      point_tmp pt INNER JOIN
      line_tmp ln
    ON
      ST_DWithin(pt.the_geom, ln.the_geom, '||cast(torelance as text) ||')
    ORDER BY
      pt.id,ST_Distance(ln.the_geom, pt.the_geom)
  ) as foo' ;
 FOR pointrec in EXECUTE snap_q LOOP
   p_id   := pointrec.pt_id;
   l_id   := pointrec.ln_id;
   p_geom := pointrec.the_geom;
   RETURN NEXT;
 END LOOP;
 DROP TABLE line_tmp;
 DROP TABLE point_tmp;
 RETURN;
END;
$$
LANGUAGE plpgsql;



CREATE OR REPLACE FUNCTION split_lines2(in lineq text, in pointq text, in
torelance float4, out lineid int, out the_geom geometry)
RETURNS SETOF RECORD AS
$$
DECLARE
  linerec record;
  pointrec record;
  linepos float;
  start_ float;
  end_ float;
  loopqry text;
BEGIN
  EXECUTE 'CREATE TEMP TABLE line_tmp as '|| lineq;
  EXECUTE 'CREATE TEMP TABLE point_tmp as '|| pointq;
  FOR linerec in EXECUTE 'SELECT * FROM line_tmp ORDER BY id' LOOP
  start_ := 0;
  end_   := 0;
  loopqry := '
    SELECT
        *, ST_line_locate_point('''||cast(linerec.geom as text)||''',geom)
AS frac
    FROM point_tmp
    WHERE ST_DWithin(geom,'''||cast(linerec.geom as text)||''',
'||torelance||')
    ORDER BY ST_line_locate_point('''||cast(linerec.geom as
text)||''',geom)';
      FOR pointrec in EXECUTE loopqry LOOP
          end_   := pointrec.frac;
          lineid := linerec.id;
          the_geom   := ST_line_substring(linerec.geom, start_, end_);
          start_ := end_;
        RETURN NEXT;
      END LOOP;
      lineid := linerec.id;
      the_geom:= ST_line_substring(linerec.geom, end_,1.0);
      RETURN NEXT;
  END LOOP;
  DROP TABLE line_tmp;
  DROP TABLE point_tmp;
  RETURN;
END;
$$
LANGUAGE plpgsql;



-- 
Hiroo Imaki
hiroo @ angeli.org
http://www.geopacific.org
-------------- next part --------------
HTML¤ÎźÉÕ¥Õ¥¡¥¤¥ë¤¬½üµî¤µ¤ì¤Þ¤·¤¿.
URL: http://lists.osgeo.org/pipermail/osgeojapan-discuss/attachments/20100721/f97c05af/attachment.html


OSGeoJapan-discuss メーリングリストの案内