PostGIS: phân tích hình học wkb với OGR


8

Tôi đang cố gắng kéo một LineStringhình học ra khỏi PostGIS và phân tích nó bằng 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()

Tôi đã thử:

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

và:

SELECT ST_AsEWKB(geom) FROM points LIMIT 1

OGR không muốn phân tích nó. Tiếp tục đưa ra lỗi sau:

ERROR 3: OGR Error: Unsupported geometry type

2
Mistype trên dòng này; chắc chắn rằng nó không có trong mã của bạn: geom = org.CreateGeometryFromWkb(wkb)(nên ogrkhông org).
Arthur

Câu trả lời:


10

Trong nội bộ, PostGIS lưu trữ hình học trong một đặc tả nhị phân, nhưng nó được truy vấn và xem bên ngoài dưới dạng một chuỗi được mã hóa hex. Có hai biến thể phổ biến của nhị phân nổi tiếng (WKB) :

  • EWKB (thông qua ST_AsEWKB) - một đặc tả WKB mở rộng được thiết kế bởi PostGIS .
  • OGC WKB (thông qua ST_AsBinary) - được chỉ định bởi OGC và ISO. Trong một thời gian nó là 2D-chỉ, nhưng sau đó mở rộng để hỗ trợ Z, MZMhình học.

Hai thông số kỹ thuật là như nhau cho hình học 2D, nhưng khác nhau cho hình học bậc cao với Z, MZMtọa độ.


Các phiên bản cũ hơn của GDAL / OGR (1.x) chỉ hiểu EWKB cho hình học 3D, vì vậy đối với những phiên bản này tôi khuyên bạn nên sử dụng ST_AsEWKB. (Nhưng nếu bạn chỉ có hình học 2D, một trong hai định dạng đều ổn). Ví dụ:

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

Ngoài ra, lưu ý rằng các phiên bản GDAL / OGR cũ hơn không hỗ trợ Mtọa độ và những phiên bản này sẽ được phân tích cú pháp nhưng bị bỏ qua.


Với GDAL 2.0 và mới hơn , ISO WKT / WKB được hỗ trợ . Điều này có nghĩa là CreateGeometryFromWkbcó thể đọc hương vị WKB (không chỉ định) và ExportToIsoWkt()hiển thị đầu ra với cú pháp WKT hiện đại.

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)

Ngoài ra, GDAL 2.1 trở lên sẽ tạo / xuất WKT / WKB với Mhoặc ZMtọa độ như mong đợi.


1
Đối với tôi đó là cách khác. Với ST_AsEWKB tôi nhận được LRI 3: Lỗi OGR: Loại hình học không được hỗ trợ. Nhưng với ST_AsBinary nó đọc tốt: MULTILINESTRING ((-4,625433 40,682732, -4,6275242 40,6820109, -4,6293233 40,681392, -4,6301239 40,681117))
HeikkiVesanto

9

Trong cơ sở dữ liệu, hình học được lưu trữ trên đĩa theo định dạng chỉ được sử dụng bởi chương trình PostGIS. Để các chương trình bên ngoài chèn và truy xuất hình học hữu ích, chúng cần được chuyển đổi thành định dạng mà các ứng dụng khác có thể hiểu được. May mắn thay, PostGIS hỗ trợ phát và tiêu thụ hình học ở một số lượng lớn các định dạng:

từ Giới thiệu về PostGIS

Với định dạng WKB:

Nhị phân nổi tiếng (WKB):
ST_GeomFromWKB (bytea) trả về hình học
ST_AsBinary (hình học) trả về bytea
ST_AsEWKB (hình học) trả về bytea

ogr nhận ra hình học không phải là kết quả 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;"

Kiểm tra với một trong các bảng của tôi:

không có gì:

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

và một hình học:

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

Vì vậy hãy cố gắng:

 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

Tại sao ?

Bởi vì kết quả của truy vấn là một chuỗi:

'01010000208A7A0000DD2571661A9B10410CCD751AEBF70241'

và không phải là mã byte.

Bạn cần giải mã chuỗi này (xem phần Tạo hình học từ WKB trong Sách dạy nấu ăn Python GDAL / OGR ).

Đó là lý do tại sao nó dễ sử dụng hơn nhiều:

1) các định dạng đầu ra khác (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) trực tiếp osgeo.ogr (Ví dụ: Làm thế nào để chuyển đổi bảng PostGIS thành Shapefile trong Python? )


+1 cho giải pháp ST_AsGeoJSON (geom).
Michael

6

Bạn sẽ muốn sử dụng ST_AsBinary(geom)để chuyển đổi hình học của mình từ định dạng bên trong PostGIS sang WKB mà bạn có thể đọc với ogr:

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

Trong điều khoản của Postgres, kết quả của bạn là a bytea. Thư viện psycpopg2 sẽ ánh xạ điều này sang memoryviewloại Python:

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

Chỉ cần bỏ memoryviewqua bytesđể đọc WKB với ogr:

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

Nếu bạn quan tâm đến độ chính xác bằng số, chắc chắn tránh sử dụng ST_AsText(). Hàm đó chuyển đổi hình học của bạn thành WKT, cắt ngắn tọa độ của bạn với độ chính xác phụ thuộc vào phiên bản và nền tảng PostGIS của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.