16. データの投影

地球は平らでなく、平面の紙地図 (またはコンピュータ画面) に置くための簡単な方法はありません。長所と短所を持つあらゆる種類の独創的な開放を考え出しました。全てのオブジェクトが相互に相対的なサイズを持つように、面積を保存する投影があります。また、メルカトル図法のように角度を保持する (正角) ものがあります。他にも、いくつかのパラメータで歪みがほとんどない、いいとこ取りのものがあります。全ての投影法に共通するのが、球面の世界を平面のデカルト座標系に変換していることと、投影法の選択はデータをどのように使うかに依存することです。

ここまでで ニューヨーク市のデータのロード の時に投影法を目にしています (厄介な SRID 26918 を思い出して下さい)。しかしながら、時々、空間参照系間の変換を行う必要があります。PostGIS は ST_Transform(geometry, srid) 関数を使って、データの投影を変更に対応する機能が組み込まれています。ジオメトリの空間参照系識別子の管理のために PostGIS では ST_SRID(geometry)ST_SetSRID(geometry, srid) 関数が提供されています。

ST_SRID 関数でデータの SRID を確認することができます:

SELECT ST_SRID(geom) FROM nyc_streets LIMIT 1;
26918

そして "26918" の定義は何でしょう? "データロードのセクション" で見た通り、定義は spatial_ref_sys にあります。事実 二つの 定義があります。"Well-Known Text" (WKT) 定義は srtext カラムにあり、二つ目の "proj.4" フォーマットの定義は proj4text カラムにあります。

SELECT * FROM spatial_ref_sys WHERE srid = 26918;

PostGIS の投影変換エンジンは最適な投影を spatial_ref_sys テーブルから発見しようと試みます:

  • auth_name / auth_srid proj が内部カタログから妥当な "authority name" と "authority srid" を見つけられる場合には、投影の定義を生成するために、これを使います。

  • srtext 定義オブジェクトを srtext から読み込め、かつ形成できる場合には、これを使います。

  • proj4text proj は最後に proj4text を処理しようとします。

このように冗長になっていて、PostGIS 内での新しい投影法生成に必要なものは、妥当な srtext 文字列または proj4text 文字列のいずれかになります。一般的なオーソリティ名/コードのペアは既にテーブルにロードされています。

カスタム投影法を生成する時に、できれば srtext カラムを入れて下さい。GeoServer, QGIS, FME などで使われるためです。

16.1. データの比較

まとめると、座標と SRID は、地球上の位置が定義するものです。SRID なしでは、座標は抽象的な観念にすぎません。「デカルト」座標平面は、地表面上の位置の「平らな」座標系として定義されます。PostGIS 関数はこのような平面の上で動作するので、比較操作には、両方のジオメトリが同じ SRID で表現されている必要があります。

異なる SRID のジオメトリを与えると、次のようなエラーが発生します:

SELECT ST_Equals(
         ST_GeomFromText('POINT(0 0)', 4326),
         ST_GeomFromText('POINT(0 0)', 26918)
         );
ERROR:  ST_Equals: Operation on mixed SRID geometries (Point, 4326) != (Point, 26918)

注釈

オンザフライ変換で ST_Transform を使い過ぎないように注意して下さい。空間インデックスは格納されたジオメトリを使って構築されます。異なる SRID で比較された場合には、空間インデックスは (しばしば) 使用されません。データベースの全てのテーブルで 一つの SRID を選ぶのが最善策です。変換関数は、外部アプリケーションとのデータの読み書きだけで使って下さい。

16.2. データの変換

SRID 26918 の proj4 定義に戻ると、現在の投影座標系が UTM (Universal Transverse Mercator) のゾーン 18 で、計測単位はメートルであることが分かります。

SELECT srtext FROM spatial_ref_sys WHERE srid = 26918;
PROJCS["NAD83 / UTM zone 18N",
  GEOGCS["NAD83",
    DATUM["North_American_Datum_1983",
      SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],
      TOWGS84[0,0,0,0,0,0,0],
      AUTHORITY["EPSG","6269"]],
    PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],
    AUTHORITY["EPSG","4269"]],
  PROJECTION["Transverse_Mercator"],
  PARAMETER["latitude_of_origin",0],
  PARAMETER["central_meridian",-75],
  PARAMETER["scale_factor",0.9996],
  PARAMETER["false_easting",500000],
  PARAMETER["false_northing",0],
  UNIT["metre",1,AUTHORITY["EPSG","9001"]],
  AXIS["Easting",EAST],AXIS["Northing",NORTH],
  AUTHORITY["EPSG","26918"]]

データを投影座標系から地理座標系 (「経度緯度」とも言います) に変換してみましょう。

一つの SRID から他のものにデータを変換するには、最初に手持ちのジオメトリが妥当な SRID を持っていることを確認しなければなりません。既に妥当な SRID であると確認したら、次に変換先 SRID が必要です。言い換えると、地理座標系の SRID は何でしょうか?

地理座標系で最も一般的な SRID は 4326 です。これは、「WGS84 回転楕円体の経度/緯度」に対応します。定義は次のようにして見ることができます:

spatial_ref_sys テーブルから定義を得ることもできます:

SELECT srtext FROM spatial_ref_sys WHERE srid = 4326;
GEOGCS["WGS 84",
  DATUM["WGS_1984",
    SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],
    AUTHORITY["EPSG","6326"]],
  PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
  UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],
  AUTHORITY["EPSG","4326"]]

'Broad St' 地下鉄駅の座標を地理座標系に変換してみましょう:

SELECT ST_AsText(ST_Transform(geom,4326))
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(-74.01067146887341 40.70710481558761)

SRID の指定なしでデータのロードやジオメトリの生成を行う場合には、SRID 値は 0 になります。ジオメトリ を思い出して下さい。geometries テーブルを生成した時に、SRID を指定していませんでした。データベースにクエリを出す場合には、全ての nyc_ テーブルが SRID 26918 を持つことを期待されているのに、geometries テーブルは SRID はデフォルトで 0 でした。

テーブルの SRID 割当を表示するには、データベースの geometry_columns テーブルを見ます。

SELECT f_table_name AS name, srid
FROM geometry_columns;
        name         | srid
---------------------+-------
 nyc_census_blocks   | 26918
 nyc_homicides       | 26918
 nyc_neighborhoods   | 26918
 nyc_streets         | 26918
 nyc_subway_stations | 26918
 geometries          |     0

しかしながら、座標の SRID が何になるのか分かっている場合には、ジオメトリに対して事後的に ST_SetSRID を使って設定できます。そうすると、ジオメトリを他の系に変換できるようになります。

SELECT ST_AsText(
    ST_Transform(
      ST_SetSRID(geom,26918),
      4326)
    )
  FROM geometries;

16.3. 関数リスト

ST_AsText: ジオメトリ/ジオグラフィの SRID メタデータを持たない Well-Known Text (WKT) 表現を返します。

ST_SetSRID(geometry, srid): ジオメトリに指定した整数値の SRID を設定します。

ST_SRID: ST_Geometry の、spatial_ref_sys テーブルで定義されている空間参照系識別子を返します。

ST_Transform(geometry, srid): 整数パラメータで指定される SRID に座標変換した新しいジオメトリを返します。