PostGIS: analizar geometría wkb con OGR

8

Estoy tratando de extraer una LineStringgeometría de PostGIS y analizarla con 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()

He intentado:

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

y:

SELECT ST_AsEWKB(geom) FROM points LIMIT 1

OGR no quiere analizarlo. Sigue dando el siguiente error:

ERROR 3: OGR Error: Unsupported geometry type
ilia choly
fuente
2
Mistype en esta línea; asegúrese de que no está en su código: geom = org.CreateGeometryFromWkb(wkb)(debe ser ogrno org).
Arthur

Respuestas:

10

Internamente, PostGIS almacena geometrías en una especificación binaria, pero se consulta y se ve afuera como una cadena codificada en hexadecimal. Hay dos variaciones populares de binarios conocidos (WKB) :

  • EWKB (vía ST_AsEWKB): una especificación WKB extendida diseñada por PostGIS .
  • OGC WKB (vía ST_AsBinary): especificado por OGC e ISO. Durante un tiempo fue de sólo 2D, pero luego se extendió al apoyo Z, My ZMgeometrías.

Las dos especificaciones son las mismas para geometrías 2D, pero son diferentes para geometrías de orden superior con Z, My ZMcoordenadas.


Las versiones anteriores de GDAL / OGR (1.x) solo entienden el EWKB para geometrías 3D, por lo que recomiendo usarlas ST_AsEWKB. (Pero si solo tiene geometrías 2D, cualquiera de los formatos está bien). Por ejemplo:

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

Además, tenga en cuenta que las versiones anteriores de GDAL / OGR no admiten Mcoordenadas, y estas se analizarán pero se ignorarán.


Con GDAL 2.0 y más reciente , se admite ISO WKT / WKB . Esto significa que CreateGeometryFromWkbpuede leer cualquier sabor WKB (sin especificar) y ExportToIsoWkt()muestra la salida con una sintaxis WKT moderna.

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)

Además, GDAL 2.1 o posterior creará / exportará WKT / WKB con Mo ZMcoordina como se espera.

Mike T
fuente
1
Para mí es al revés. Con ST_AsEWKB obtengo ERROR 3: Error de OGR: tipo de geometría no compatible. Pero con ST_AsBinary se lee bien: MULTILINESTRING ((-4.625433 40.682732, -4.6275242 40.6820109, -4.6293233 40.681392, -4.6301239 40.681117))
HeikkiVesanto
9

Dentro de la base de datos, las geometrías se almacenan en el disco en un formato que solo usa el programa PostGIS. Para que los programas externos puedan insertar y recuperar geometrías útiles, deben convertirse a un formato que otras aplicaciones puedan entender. Afortunadamente, PostGIS admite la emisión y el consumo de geometrías en una gran cantidad de formatos:

de Introducción a PostGIS

Con el formato WKB:


Binario conocido (WKB): ST_GeomFromWKB (bytea) devuelve geometría
ST_AsBinary (geometry) devuelve bytea
ST_AsEWKB (geometry) devuelve bytea

ogr reconocer geometrías y no un resultado 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;"

Prueba con una de mis tablas:

nada:

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

y una geometría:

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

Entonces intentemos:

 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

Por qué ?

Porque el resultado de la consulta es una cadena:

'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

y no un bytecode.

Debe decodificar esta cadena (consulte Crear geometría a partir de WKB en el libro de cocina Python GDAL / OGR ).

Por eso es mucho más fácil de usar:

1) otros formatos de salida (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) directamente osgeo.ogr ( ¿Cómo convertir la tabla PostGIS a Shapefile en Python , por ejemplo)

gene
fuente
+1 para la solución ST_AsGeoJSON (geom).
Michael
6

ST_AsBinary(geom)Querrá usar para convertir su geometría del formato interno de PostGIS a WKB que puede leer con ogr:

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

En términos de Postgres, su resultado es a bytea. La biblioteca psycpopg2 asignará esto a un memoryviewtipo de Python:

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

Solo envía tu memoryviewa bytespara leer el WKB con ogr:

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

Si le preocupa la precisión numérica, definitivamente evite usarla ST_AsText(). Esa función convierte su geometría a WKT, truncando sus coordenadas con una precisión que depende de su versión y plataforma de PostGIS.

dbaston
fuente