PostGIS: Geometrie wkb mit OGR analysieren

8

Ich versuche, eine LineStringGeometrie aus PostGIS zu ziehen und sie mit OGR (Python Bindinds) zu analysieren.

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

Ich habe es versucht:

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

und:

SELECT ST_AsEWKB(geom) FROM points LIMIT 1

OGR will es nicht analysieren. Gibt weiterhin den folgenden Fehler aus:

ERROR 3: OGR Error: Unsupported geometry type
ilia choly
quelle
2
Fehler in dieser Zeile; Stellen Sie sicher, dass es nicht in Ihrem Code enthalten ist: geom = org.CreateGeometryFromWkb(wkb)(sollte ogrnicht sein org).
Arthur

Antworten:

10

Intern speichert PostGIS Geometrien in einer binären Spezifikation, wird jedoch abgefragt und außerhalb als hexadezimal codierte Zeichenfolge angezeigt. Es gibt zwei beliebte Varianten der bekannten Binärdatei (WKB) :

  • EWKB (via ST_AsEWKB) - eine erweiterte WKB-Spezifikation von PostGIS .
  • OGC WKB (via ST_AsBinary) - spezifiziert von OGC und ISO. Eine Zeit lang war es 2D-nur, aber später auf Unterstützung erweitert Z, Mund ZMGeometrien.

Die beiden Spezifikationen sind die gleichen für die 2D - Geometrien, aber sind unterschiedlich für höherer Ordnung Geometrien mit Z, Mund ZMKoordinaten.


Ältere Versionen von GDAL / OGR (1.x) verstehen die EWKB nur für 3D-Geometrien, daher empfehle ich für diese die Verwendung ST_AsEWKB. (Wenn Sie jedoch nur 2D-Geometrien haben, sind beide Formate in Ordnung). Zum Beispiel:

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

Beachten Sie außerdem, dass ältere GDAL / OGR-Versionen keine MKoordinaten unterstützen und diese analysiert, aber ignoriert werden.


Mit GDAL 2.0 und neueren Versionen wird ISO WKT / WKB unterstützt . Dies bedeutet, dass CreateGeometryFromWkbentweder die WKB-Variante (ohne Angabe) gelesen werden kann und ExportToIsoWkt()die Ausgabe mit einer modernen WKT-Syntax angezeigt wird.

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)

Zusätzlich erstellt / exportiert GDAL 2.1 oder höher WKT / WKB mit Moder ZMKoordinaten wie erwartet.

Mike T.
quelle
1
Für mich ist es umgekehrt. Mit ST_AsEWKB erhalte ich FEHLER 3: OGR-Fehler: Nicht unterstützter Geometrietyp. Aber mit ST_AsBinary liest es gut: MULTILINESTRING ((-4.625433 40.682732, -4.6275242 40.6820109, -4.6293233 40.681392, -4.6301239 40.681117))
HeikkiVesanto
9

Innerhalb der Datenbank werden Geometrien in einem Format auf der Festplatte gespeichert, das nur vom PostGIS-Programm verwendet wird. Damit externe Programme nützliche Geometrien einfügen und abrufen können, müssen sie in ein Format konvertiert werden, das andere Anwendungen verstehen können. Glücklicherweise unterstützt PostGIS das Senden und Konsumieren von Geometrien in einer Vielzahl von Formaten:

von der Einführung in PostGIS

Mit dem WKB-Format:

Bekannte Binärdatei (WKB):
ST_GeomFromWKB (bytea) gibt Geometrie zurück
ST_AsBinary (Geometrie) gibt bytea zurück
ST_AsEWKB (Geometrie) gibt bytea zurück

ogr Geometrien erkennen und kein Bytea-Ergebnis ( 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;"

Test mit einem meiner Tische:

nichts:

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

und eine Geometrie:

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

Lass es uns versuchen:

 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

Warum ?

Weil das Ergebnis der Abfrage eine Zeichenfolge ist:

'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

und kein Bytecode.

Sie müssen diese Zeichenfolge dekodieren (siehe Geometrie aus WKB erstellen im Python GDAL / OGR-Kochbuch ).

Deshalb ist es viel einfacher zu bedienen:

1) andere Ausgabeformate (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) direkt osgeo.ogr ( Wie konvertiere ich beispielsweise eine PostGIS-Tabelle in Shapefile in Python? )

Gen
quelle
+1 für die ST_AsGeoJSON (geom) -Lösung.
Michael
6

Sie möchten verwenden ST_AsBinary(geom), um Ihre Geometrie aus dem internen PostGIS-Format in WKB zu konvertieren, das Sie mit ogr lesen können:

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

In Postgres-Begriffen ist Ihr Ergebnis a bytea. Die psycpopg2-Bibliothek ordnet dies einem memoryviewPython-Typ zu:

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

Wirf einfach deine memoryview, bytesum die WKB mit ogr zu lesen:

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

Wenn Sie sich mit numerischer Genauigkeit beschäftigen, vermeiden Sie auf jeden Fall die Verwendung ST_AsText(). Diese Funktion konvertiert Ihre Geometrie in WKT und schneidet Ihre Koordinaten mit einer Genauigkeit ab, die von Ihrer PostGIS-Version und -Plattform abhängt.

dbaston
quelle