PostGIS教程十六:幾何圖形的有效性

 在90%的情況下,"爲什麼我的查詢給了我一個'TopologyException'錯誤"的問題的答案是"一個或多個輸入的幾何圖形是無效的",這就引出了這樣一個問題:幾何圖形"無效"是什麼意思?我們爲什麼要關心它?

一、什麼是有效性

    對於定義有界區域並需要大量結構的多邊形來說,它的幾何圖形有效性是最重要的。線串非常簡單,不會無效,點也不會無效。

    多邊形有效性的一些規則很明顯,而另一些規則是任意的(事實上,是任意的)。

  • 多邊形的環必須閉合
  • 定義孔洞的環應該是在外部邊界的環內
  • 環不能自相交(它們不能相互接觸,也不能交叉)
  • 環不能與其他環接觸,除非在某個點接觸

    最後兩條規則屬於任意類別。定義多邊形的其他規則也是自洽合理的,但是上面的規則是PostGIS所遵循的OGC  SFSQL標準所使用的多邊形有效性的規則。

    規則之所以重要,是因爲幾何圖形的計算依賴於輸入的幾何圖形的結構。可以構建沒有結構假設的算法,但這些程序往往非常慢,因爲任何無結構程序的第一步都是分析輸入並在其中構建結構。

    這裏有一個解釋爲什麼幾何圖形的結構重要的例子。首先這個多邊形是無效的

POLYGON((0 0, 0 1, 2 1, 2 2, 1 2, 1 0, 0 0));

    在此圖中,你可以更清楚地看到無效的原因:

_images/figure_eight.png

    這個多邊形的外環實際上是一個數字8的形狀,中間有一個自交點。圖形程序成功地渲染了多邊形填充,使其在視覺上看起來是一個"區域":兩個一個單位的正方形,因此多邊形總面積爲兩個單位的面積。

    讓我們看看PostGIS數據庫認爲多邊形的面積是多少:


 
  1. SELECT ST_Area(ST_GeometryFromText(

  2. 'POLYGON((0 0, 0 1, 1 1, 2 1, 2 2, 1 2, 1 1, 1 0, 0 0))'

  3. ));

    這裏發生了什麼?計算面積的算法假設環不自相交程序始終計算位於邊界線的一側的區域的面積

然而,在我們的(表現不佳)的數字8中,對於一個葉部分,圖形區域位於邊界線的右側,而對於另一個葉部分,圖形區域在邊界線的左側。這將導致爲每個葉部分計算的面積互相抵消(一個爲1,另一個爲-1),因此結果爲"0面積"。

 

二、檢測有效性

    在前面的示例中,我們可以輕易發現一個多邊形是無效的。然而我們如何在一個包含數百萬個幾何圖形的表中檢測無效?答案是使用ST_IsValid(geometry)函數:


 
  1. SELECT ST_IsValid(ST_GeometryFromText(

  2. 'POLYGON((0 0, 0 1, 1 1, 2 1, 2 2, 1 2, 1 1, 1 0, 0 0))'

  3. ));

     現在我們知道這個圖形是無效的,但是我們不知道爲什麼無效。我們可以使用ST_IsValidReason(geometry)函數來查找無效的原因:


 
  1. SELECT ST_IsValidReason(ST_GeometryFromText(

  2. 'POLYGON((0 0, 0 1, 1 1, 2 1, 2 2, 1 2, 1 1, 1 0, 0 0))'

  3. ));

    請注意,除了原因(自相交),圖形自相交的座標(coordinate(1 1))也被返回了。

    我們也可以使用ST_IsValid(geometry)函數來測試數據表:


 
  1. -- Find all the invalid polygons and what their problem is

  2. SELECT name, boroname, ST_IsValidReason(geom)

  3. FROM nyc_neighborhoods

  4. WHERE NOT ST_IsValid(geom);

 

三、修復無效的圖形

    首先,壞消息是:沒有100%確定的方法來修復無效的幾何圖形。最壞的情況是使用ST_IsValid(geometry)函數識別它們,然後將它們移動另一張表,導出該表,然後在外部修復它們。

    下面是SQL的一個示例,它將無效的幾何圖形從原錶轉移到另一張表中(注意,同時要:


 
  1. -- Side table of invalids

  2. CREATE TABLE nyc_neighborhoods_invalid AS

  3. SELECT * FROM nyc_neighborhoods

  4. WHERE NOT ST_IsValid(geom);

  5.  
  6. -- Remove them from the main table

  7. DELETE FROM nyc_neighborhoods

  8. WHERE NOT ST_IsValid(geom);

    在視覺上修復無效幾何圖形的一個好工具是OpenJump(http://openjump.org),它在Tools->QA->Validate Selected Layers.下包含一個驗證程序。

   現在好消息是:可以使用以下任何一種方法在數據庫中修復很大一部分的缺陷:

  • ST_MakeValid函數
  • ST_Buffer函數

3.1、ST_MakeValid

    ST_MakeValid嘗試在不對輸入幾何圖形進行更改的情況下修復缺陷。不會刪除或移動任何頂點,只需重新排列對象的結構即可。對於清晰但無效的數據來說,這個函數非常適用,對於雜亂無章且無效的數據來說,這個函數可能並不適用。


 
  1. -- Fix the invalid figure-8 polygon

  2. SELECT ST_AsText(ST_MakeValid(

  3. 'POLYGON((0 0, 0 1, 1 1, 2 1, 2 2, 1 2, 1 1, 1 0, 0 0))'

  4. ));

    ST_MakeValid成功地將幾何圖形"8"轉換爲表示相同面積的multi-polygon。

3.2、ST_Buffer

    使用緩衝區技巧清理時,可以利用緩衝區的生成方式來達到修復幾何圖形的目的:緩衝區幾何圖形是全新的幾何圖形,由關於原始圖形的偏移線構建。如果不偏移原始線(零),則新幾何圖形在結構上將與原始幾何圖形相同,但由於它是使用OGC拓撲規則構建的,因此它將是有效的。

    例如,這裏有一個典型的無效現象——"香蕉多邊形" —— 一個環,它包圍着一個區域,但彎曲着接觸自己,留下一個"孔洞(hole)",實際上並不是一個孔洞。

POLYGON((0 0, 2 0, 1 1, 2 2, 3 1, 2 0, 4 0, 4 4, 0 4, 0 0))

_images/banana.png

    在多邊形上計算零偏移緩衝區將返回有效的OGC多邊形,該多邊形由在一點接觸的外環和內環組成。


 
  1. SELECT ST_AsText(

  2. ST_Buffer(

  3. ST_GeometryFromText('POLYGON((0 0, 2 0, 1 1, 2 2, 3 1, 2 0, 4 0, 4 4, 0 4, 0 0))'),

  4. 0.0

  5. )

  6. );

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章