PostGIS:OGRでジオメトリWKBを解析


8

LineStringPostGISからジオメトリを引き出してOGR(python bindinds)で解析しようとしています。

from osgeo import ogr
import psycopg2

connection = psycopg2.connect("...")
cursor = connection.cursor()

query = "SELECT geom FROM points LIMIT 1"

cursor.execute(query)
row = cursor.fetchone()

wkb = row[0]
geom = ogr.CreateGeometryFromWkb(wkb)

cursor.close()
connection.close()

私はもう試した:

wkb = bin(int(row[0], 16))

そして:

SELECT ST_AsEWKB(geom) FROM points LIMIT 1

OGRはそれを解析したくありません。次のエラーを出し続けます:

ERROR 3: OGR Error: Unsupported geometry type

2
この行のタイプミス。あなたのコードにないことを確認してください:(ないgeom = org.CreateGeometryFromWkb(wkb)はずです)。ogrorg
アーサー

回答:


10

内部的には、PostGISはジオメトリをバイナリ仕様で格納しますが、クエリされ、外部で16進エンコードされた文字列として表示されます。よく知られているバイナリ(WKB)の 2つの一般的なバリエーションがあります。

  • EWKB(経由ST_AsEWKB-PostGIS によって設計された拡張WKB仕様。
  • OGC WKB(via ST_AsBinary)-OGCおよびISOによって指定されています。それは2次元のみであったが、後にサポートするように拡張しながらためZMおよびZMジオメトリ。

2つの仕様は2Dジオメトリの場合と同じですがZMZM座標を持つ高次のジオメトリでは異なります。


古いバージョンのGDAL / OGR(1.x)は、3DジオメトリのEWKBしか理解しないため、これらのバージョンではを使用することをお勧めしST_AsEWKBます。(ただし、2Dジオメトリしかない場合は、どちらの形式でも問題ありません)。例えば:

import psycopg2
from osgeo import ogr

ogr.UseExceptions()    
conn = psycopg2.connect('dbname=postgis user=postgres')
curs = conn.cursor()

curs.execute("select ST_AsEWKB('POINT Z (1 2 3)'::geometry) AS g")
b = bytes(curs.fetchone()[0])
print(b.encode('hex'))  # 0101000080000000000000f03f00000000000000400000000000000840
g = ogr.CreateGeometryFromWkb(b)
print(g.ExportToWkt())  # POINT (1 2 3)

curs.execute("select ST_AsBinary('POINT Z (1 2 3)'::geometry) AS g")
b = bytes(curs.fetchone()[0])
print(b.encode('hex'))  # 01e9030000000000000000f03f00000000000000400000000000000840
g = ogr.CreateGeometryFromWkb(b)
# RuntimeError: OGR Error: Unsupported geometry type

また、古いGDAL / OGRバージョンはM座標をサポートしていないため、これらは解析されますが無視されます。


GDAL 2.0以降ではISO WKT / WKBがサポートされています。つまり、CreateGeometryFromWkbどちらのWKBフレーバーも(指定せずに)読み取ることができExportToIsoWkt()、最新のWKT構文で出力を表示します。

import psycopg2
from osgeo import ogr

ogr.UseExceptions()
conn = psycopg2.connect('dbname=postgis user=postgres')
curs = conn.cursor()

curs.execute("select ST_AsEWKB('POINT Z (1 2 3)'::geometry) AS g")
b = bytes(curs.fetchone()[0])
print(b.encode('hex'))  # 0101000080000000000000f03f00000000000000400000000000000840
g = ogr.CreateGeometryFromWkb(b)
print(g.ExportToIsoWkt())  # POINT Z (1 2 3)

curs.execute("select ST_AsBinary('POINT Z (1 2 3)'::geometry) AS g")
b = bytes(curs.fetchone()[0])
print(b.encode('hex'))  # 01e9030000000000000000f03f00000000000000400000000000000840
g = ogr.CreateGeometryFromWkb(b)
print(g.ExportToIsoWkt())  # POINT Z (1 2 3)

また、GDAL 2.1以降が作成されます/エクスポートWKT /とWKB MまたはZM座標を予想通り。


1
私にとってそれは逆です。ST_AsEWKBを使用すると、エラー3が発生します。OGRエラー:サポートされていないジオメトリタイプです。しかし、ST_AsBinaryを使用すると、正常に読み取られます:MULTILINESTRING((-4.625433 40.682732、-4.6275242 40.6820109、-4.6293233 40.681392、-4.6301239 40.681117))
HeikkiVesanto

9

データベース内では、ジオメトリはPostGISプログラムでのみ使用される形式でディスクに保存されます。外部プログラムが有用なジオメトリを挿入および取得するには、それらを他のアプリケーションが理解できる形式に変換する必要があります。さいわい、PostGISは多数のフォーマットでジオメトリの放出と消費をサポートしています。

以下からの紹介のPostGISへ

WKB形式の場合:

既知のバイナリ(WKB):
ST_GeomFromWKB(bytea)はジオメトリを返します
ST_AsBinary(geometry)はbyteaを返します
ST_AsEWKB(geometry)はbyteaを返します

ogrは、byteaの結果ではなくジオメトリを認識します(ST_AsEWKB()

# result -> bytea format:
query = "SELECT ST_AsEWKB(geom) FROM points LIMIT 1"
# result -> geometry from bytea:
query = "SELECT ST_GeomFromWKB(ST_AsEWKB(geom)) from points LIMIT 1;"

テーブルの1つでテストします。

何も:

query = """SELECT ST_AsText(ST_AsEWKB(geom)) from mytable;"""
cur = conn.cursor()
cur.execute(query)
row = cur.fetchone()
print row[0]
'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

とジオメトリ:

query = """SELECT ST_AsText(ST_GeomFromWKB(ST_AsEWKB(geom))) from mytable;"""
# result
cur.execute(query)
row = cur.fetchone()
print row
('POINT(272070.600041 155389.38792)',)

だから、試してみましょう:

 query = """SELECT ST_AsText(ST_GeomFromWKB(ST_AsEWKB(geom))) from mytable;"""
 cur = conn.cursor()
 cur.execute(query)
 row = cur.fetchone()    
 wkb = row[0];
 geom = ogr.CreateGeometryFromWkb(wkb)
 ERROR 3: OGR Error: Unsupported geometry type

どうして ?

クエリの結果が文字列であるため:

'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

バイトコードではありません。

この文字列をデコードする必要があります(Python GDAL / OGRクックブックの WKBからジオメトリを作成するをご覧ください)。

そのため、使用がはるかに簡単です。

1)その他の出力形式(WKT、GeoJSONなど)

 query = """SELECT ST_AsGeoJSON(geom) from mytable;"""  
 cur.execute(query)
 row = cur.fetchone()
 point = ogr.CreateGeometryFromJson(row[0])
 print "%d,%d" % (point.GetX(), point.GetY())
 272070,155389

2)直接osgeo.ogr(たとえば、PythonでPostGISテーブルをShapefileに変換する方法?


ST_AsGeoJSON(geom)ソリューションの+1。
Michael

6

を使用ST_AsBinary(geom)して、ジオメトリをPostGIS内部形式からogrで読み取れるWKBに変換します。

cur.execute('SELECT ST_AsBinary(geom) FROM mytable LIMIT 1')
result = cur.fetchone()

Postgresの用語では、結果はbyteaです。psycpopg2ライブラリは、これをmemoryviewPythonタイプにマッピングします。

>>>> type(result[0])
<class 'memoryview'>

ちょうどあなたをキャストmemoryviewするbytesOGRとWKBを読むために:

>>>>geom = ogr.CreateGeometryFromWkb(bytes(result[0]))
<osgeo.ogr.Geometry; proxy of <Swig Object of type 'OGRGeometryShadow *' at 0x0000000002D179F0> >

数値の精度が気になる場合は、絶対にを使用しないでくださいST_AsText()。この関数は、ジオメトリをWKTに変換し、PostGISのバージョンとプラットフォームに応じた精度で座標を切り捨てます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.