矢量數據空間查詢


版權聲明:本文爲博主原創文章,轉載請註明原文出處!

作者:阿振

寫作時間:2020-06-14 周天


開篇

在前面四篇博客中我們主要講了對於空間矢量數據的屬性數據的增刪改查,在這篇博文中我們要講解空間查詢–GIS系統很重要的一項功能。空間查詢就是根據地物的空間位置進行查詢的一種數據檢索方式。比如,我們要查詢一條河流經的城市;一個公園內的所有路燈;離當前位置最近的公共衛生間等等都屬於常用的空間查詢。

OGC簡單要素規範定義了空間幾何體之間的空間關係,包括Equals,Disjoint,Intersects,Touches,Crosses,Within,Contains,Overlaps,Relate,LocateAlong,LocateBetween。感興趣的同學可以從OGC官網下載下來看看。

現有的空間數據庫例如Oracle Spatial,PostGIS,SQL Server都根據OGC簡單要素規範提供了對空間查詢的支持,他們有差異地在標準SQL語句中添加了空間關係查詢的功能。

本文主要介紹如何使用GDAL庫對空間數據進行空間查詢,常用的方法可以概括爲三大類:

  1. 第一類就是使用支持空間查詢的SQL語句進行查詢,但是這種方式只對某些特定種類的數據源可以使用,有些數據源不一定支持。
  2. 第二類是使用GDAL提供的SetSpatialFilter()方法增加過濾條件。但是這種方式只能是選擇給定範圍的空間地位,類似於Within或者Contains的功能,不能實現其他類型的空間關係查詢。
  3. 第三類就是讀取每個Feature要素包含的Geometry對象,根據Geometry的空間關係手動進行篩選。因爲GDAL中的Geometry對象基本上實現了OGC簡單要素規範定義的空間關係,所以這種方式最靈活,本文主要介紹如何使用這種方式進行空間查詢。

案例一

案例說明

我們現在有省的面狀數據以及每個城市的點數據,我們需要找到湖北省內的所有城市。

實現思路是先從省的面狀數據中找出湖北省,然後遍歷城市的點數據看是否落在湖北省境內。

代碼演示

import ogr
ogr.UseExceptions()

ds_province: ogr.DataSource = ogr.Open('../data/Provinces.shp')
l_province: ogr.Layer = ds_province.GetLayer()
# 使用filter()方法找出湖北省
f_hubei: ogr.Feature = next(filter(lambda f: '湖北' in f.GetField('NAME'), l_province))

ds_city: ogr.DataSource = ogr.Open('../data/Cities.shp')
l_city: ogr.Layer = ds_city.GetLayer()
# 使用filter()方法過濾出落在湖北省境內的所有市
selected = filter(lambda f: f.GetGeometryRef().Within(f_hubei.GetGeometryRef()), l_city)
for city in selected:
    print(city.GetField('name'))
del ds_province
del ds_city

方法總結

  1. 使用ogr.Open()函數讀取Shapefile數據,使用GetLayer()獲取當前圖層,圖層中包含了所有的Feature要素。
  2. 使用Python的內置filter()函數對省進行過濾,通過NAME字段找出湖北省。filter()函數的第一個參數是一個自定義函數,第二個參數是一個可迭代對象iterable。該函數會遍歷可迭代對象將滿足第一個自定義函數的值過濾出來。通過next()方法拿到迭代器的當前值,即湖北省的Feature對象。
  3. 繼續使用filter()函數對城市的點數據進行篩選,這裏通過Feature的GetGeometryRef()方法獲得要素代表的幾何體,然後調用Geometry的Within()方法判斷該城市是否落在湖北省對應的Geometry中。

案例二

案例說明

我們將使用城市的點數據獲取離武漢市最近的三座城市。

實現的思路是首先從數據中找到武漢市,然後計算每個城市到武漢市的距離並排序,對排好序的Feature選擇前三即可。

代碼演示

import ogr
ogr.UseExceptions()

ds: ogr.DataSource = ogr.Open('../data/Cities.shp')
cities: ogr.Layer = ds.GetLayer()
# 使用filter()方法找出武漢市
city: ogr.Feature = next(filter(lambda f: '武漢' in f.GetField('name'), cities))
# 調用ResetReading()方法特別重要,如果不ResetReading的話後面的對Feature的遍歷會出錯
cities.ResetReading()
# 根據每個市到武漢市的距離進行排序
selected = sorted(cities, key=lambda f: f.GetGeometryRef().Distance(city.GetGeometryRef()))
for i in range(1, 4):
    print(selected[i].GetField('name'))
del ds

方法總結

  1. 跟案例一一樣,我們使用Python的內置filter()函數對市進行過濾,通過NAME字段找出武漢市。
  2. 需要特別注意了,當我們遍歷完一遍Layer的Feature以後需要調用ResetReading()對迭代器重新歸位,否則後面要繼續進行要素遍歷的話會出錯。
  3. 接着我們使用Python內置函數sorted()根據每個城市到武漢市的距離進行排序。sorted()函數包含三個參數(後兩個可選),第一個參數是一個可迭代對象iterable,第二個參數是用於自定義排序的函數,第三個參數指定是否逆序。sorted()函數的返回值是一個list對象。
  4. 對於距離的計算,我們首先使用GetGeometryRef()函數獲得要素對應的空間幾何體,然後再使用Geometry對象的Distance()函數進行。
  5. 計算完以後我們從第二個元素進行輸出,因爲第一個元素肯定是武漢市,武漢市到武漢市的距離爲0,爲最小距離。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章