PostGIS: parse geometry wkb dengan OGR


8

Saya mencoba menarik LineStringgeometri dari PostGIS dan menguraikannya dengan 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()

Saya sudah mencoba:

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

dan:

SELECT ST_AsEWKB(geom) FROM points LIMIT 1

OGR tidak ingin menguraikannya. Terus memberikan kesalahan berikut:

ERROR 3: OGR Error: Unsupported geometry type

2
Kesalahan ketik pada baris ini; pastikan itu tidak ada dalam kode Anda: geom = org.CreateGeometryFromWkb(wkb)(seharusnya ogrtidak org).
Arthur

Jawaban:


10

Secara internal, PostGIS menyimpan geometri dalam spesifikasi biner, tetapi ia dipertanyakan dan dilihat di luar sebagai string yang dikodekan-hex. Ada dua variasi populer biner terkenal (WKB) :

  • EWKB (via ST_AsEWKB) - spesifikasi WKB yang diperluas yang dirancang oleh PostGIS .
  • OGC WKB (via ST_AsBinary) - ditentukan oleh OGC dan ISO. Untuk sementara itu hanya 2D, tetapi kemudian diperluas untuk mendukung Z, Mdan ZMgeometri.

Kedua spesifikasi adalah sama untuk geometri 2D, tetapi berbeda untuk geometri tingkat tinggi dengan Z, Mdan ZMkoordinat.


Versi GDAL / OGR (1.x) yang lebih lama hanya memahami EWKB untuk geometri 3D, jadi untuk ini saya sarankan menggunakan ST_AsEWKB. (Tetapi jika Anda hanya memiliki geometri 2D, formatnya baik-baik saja). Sebagai contoh:

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

Juga, perhatikan bahwa versi GDAL / OGR yang lebih lama tidak mendukung Mkoordinat, dan ini akan diuraikan tetapi diabaikan.


Dengan GDAL 2.0 dan yang terbaru , ISO WKT / WKB didukung . Ini berarti bahwa CreateGeometryFromWkbdapat membaca rasa WKB (tanpa menentukan) dan ExportToIsoWkt()menunjukkan output dengan sintaks WKT modern.

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)

Selain itu, GDAL 2.1 atau yang lebih baru akan membuat / mengekspor WKT / WKB dengan Matau ZMkoordinat seperti yang diharapkan.


1
Bagi saya itu sebaliknya. Dengan ST_AsEWKB saya mendapatkan ERROR 3: Kesalahan OGR: Jenis geometri yang tidak didukung. Tetapi dengan ST_AsBinary terbaca baik: MULTILINESTRING ((-4.625433 40.682732, -4.6275242 40.6820109, -4.6293233 40.681392, -4.6301239 40.681117))
HeikkiVesanto

9

Di dalam basis data, geometri disimpan dalam disk dalam format yang hanya digunakan oleh program PostGIS. Agar program eksternal dapat menyisipkan dan mengambil geometri yang berguna, mereka perlu dikonversi ke dalam format yang dapat dimengerti aplikasi lain. Untungnya, PostGIS mendukung memancarkan dan mengonsumsi geometri dalam banyak format:

dari Pengantar PostGIS

Dengan format WKB:

Biner terkenal (WKB):
ST_GeomFromWKB (bytea) mengembalikan geometri
ST_AsBinary (geometri) mengembalikan bytea
ST_AsEWKB (geometry) mengembalikan bytea

ogr mengenali geometri bukan hasil 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;"

Uji dengan salah satu meja saya:

tidak ada:

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

dan geometri:

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

Jadi, mari kita coba:

 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

Mengapa

Karena hasil kueri adalah string:

'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

dan bukan bytecode.

Anda perlu mendekode string ini (lihat Membuat Geometri dari WKB di Python GDAL / OGR Cookbook ).

Itulah mengapa lebih mudah digunakan:

1) format output lainnya (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) langsung osgeo.ogr ( Bagaimana mengonversi tabel PostGIS ke Shapefile dengan Python?, Misalnya)


+1 untuk solusi ST_AsGeoJSON (geom).
Michael

6

Anda ingin menggunakan ST_AsBinary(geom)untuk mengubah geometri Anda dari format internal PostGIS ke WKB yang dapat Anda baca dengan ogr:

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

Dalam istilah Postgres, hasil Anda adalah a bytea. Pustaka psycpopg2 akan memetakan ini ke memoryviewtipe Python:

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

Hanya melemparkan Anda memoryviewuntuk bytesmembaca WKB dengan OGR:

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

Jika Anda khawatir dengan ketepatan angka, pasti hindari penggunaan ST_AsText(). Fungsi itu mengubah geometri Anda menjadi WKT, memotong koordinat Anda dengan presisi yang tergantung pada versi dan platform PostGIS Anda.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.