Geopoly 模組是 R-Tree 擴充套件 的替代介面,使用 GeoJSON 表示法 (RFC-7946) 來描述二維多邊形。Geopoly 包含用於偵測一個多邊形是否包含在另一個多邊形內或與其重疊、計算多邊形所圍住的面積、對多邊形進行線性轉換、將多邊形渲染為 SVG 以及其他類似操作的函數。
Geopoly 的原始程式碼包含在 合併 中。但是,根據組態選項和您使用的特定 SQLite 版本,Geopoly 擴充套件可能預設啟用或不啟用。若要確保 Geopoly 已針對您的建置啟用,請新增 -DSQLITE_ENABLE_GEOPOLY=1 編譯時期選項。
Geopoly 在「簡單」多邊形上運作,也就是說,邊界不會與其自身相交的多邊形。因此,Geopoly 擴充了 R-Tree 擴充套件 的功能,後者只能處理矩形區域。另一方面,R-Tree 擴充套件 可以處理 1 到 5 個座標維度,而 Geopoly 則僅限於 2 維形狀。
Geopoly 模組中的每個多邊形都可以與任意數量的輔助資料欄位關聯。
GeoJSON 標準是使用 JSON 交換地理空間資訊的語法。GeoJSON 是豐富的標準,可以描述幾乎任何類型的地理空間內容。
Geopoly 模組只了解 GeoJSON 的一小部分,但卻是關鍵的一部分。特別是,GeoJSON 了解描述簡單多邊形的頂點 JSON 陣列。
多邊形由其頂點定義。每個頂點都是兩個數值 JSON 陣列,它們是頂點的 X 和 Y 座標。多邊形是至少四個這些頂點的 JSON 陣列,因此是陣列的陣列。陣列中的第一個和最後一個頂點必須相同。多邊形遵循右手定則:當從一個頂點追蹤到下一個頂點時,線條右邊的區域在多邊形外,左邊的區域在多邊形內。換句話說,頂點的淨旋轉是逆時針的。
例如,以下 JSON 描述一個等腰三角形,位於 X 軸上,面積為 0.5
[[0,0],[1,0],[0.5,1],[0,0]]
三角形有三個頂點,但三角形的 GeoJSON 描述有 4 個頂點,因為第一個和最後一個頂點是重複的。
在內部,Geopoly 以二進位格式儲存多邊形 - SQL BLOB。二進位格式的詳細資訊如下。所有 Geopoly 介面都能接受 GeoJSON 格式或二進位格式的多邊形。
geopoly 表格建立如下
CREATE VIRTUAL TABLE newtab USING geopoly(a,b,c);
以上陳述建立一個名為「newtab」的新 geopoly 表格。每個 geopoly 表格都包含內建整數「rowid」欄位和「_shape」欄位,其中包含與該表格列關聯的多邊形。以上範例也定義了三個輔助資料欄位,分別名為「a」、「b」和「c」,可以儲存應用程式需要與每個多邊形關聯的任何其他資訊。如果不需要儲存輔助資訊,則可以省略輔助欄位的清單。
使用一般 INSERT 陳述將新多邊形儲存在表格中
INSERT INTO newtab(_shape) VALUES('[[0,0],[1,0],[0.5,1],[0,0]]');
UPDATE 和 DELETE 陳述式運作方式類似。
若要使用索引地理空間搜尋來查詢 geopoly 表格,請將 geopoly_overlap() 或 geopoly_within() 函數之一用作 WHERE 子句中的布林函數,並將「_shape」欄位作為函數的第一個引數。例如
SELECT * FROM newtab WHERE geopoly_overlap(_shape, $query_polygon);
前一個範例將傳回每一列,其中 _shape 與 $query_polygon 參數中的多邊形重疊。geopoly_within() 函數運作方式類似,但只會傳回 _shape 完全包含在 $query_polygon 中的列。
WHERE 子句包含未經處理的 geopoly_overlap() 或 geopoly_within() 函數的查詢(以及 DELETE 和 UPDATE 陳述式),會利用基礎 R*Tree 資料結構快速查詢,只需檢查表格中的一小部分列。檢查的列數當然取決於 $query_polygon 的大小。大型 $query_polygon 通常需要檢查比小型 $query_polygon 更多的列。
針對 geopoly 表格的 rowid 進行的查詢也非常快速,即使是列數非常多的表格也是如此。但是,沒有任何輔助資料欄位是索引,因此針對輔助資料欄位的查詢將涉及完整表格掃描。
geopoly 模組定義了幾個新的 SQL 函數,對於處理多邊形很有用。傳遞給這些函數的所有多邊形引數都可以是 GeoJSON 格式或內部二進位格式。
如果 P1 和 P2 都是多邊形,則 geopoly_overlap(P1,P2) 函數會在 P1 和 P2 之間有任何重疊時傳回非零整數,或者如果 P1 和 P2 完全不相連,則傳回零。如果 P1 或 P2 不是多邊形,則此常式會傳回 NULL。
geopoly_overlap(P1,P2) 函數特別在於 geopoly 虛擬表格知道如何使用 R*Tree 索引來最佳化查詢,其中 WHERE 子句使用 geopoly_overlap() 作為布林函數。只有 geopoly_overlap(P1,P2) 和 geopoly_within(P1,P2) 函數有此功能。
如果 P1 和 P2 都是多邊形,則 geopoly_within(P1,P2) 函數會傳回一個非零整數,如果 P1 完全包含在 P2 內,或如果 P1 的任何部分在 P2 外部,則傳回零。如果 P1 和 P2 是相同的多邊形,則此常式會傳回非零。如果 P1 或 P2 不是多邊形,則此常式會傳回 NULL。
geopoly_within(P1,P2) 函數特別在於 geopoly 虛擬表格知道如何使用 R*Tree 索引來最佳化查詢,其中 WHERE 子句使用 geopoly_within() 作為布林函數。只有 geopoly_within(P1,P2) 和 geopoly_overlap(P1,P2) 函數有此功能。
如果 P 是多邊形,則 geopoly_area(P) 會傳回該多邊形所圍住的面積。如果 P 不是多邊形,則 geopoly_area(P) 會傳回 NULL。
如果 P 是多邊形,則 geopoly_blob(P) 會傳回該多邊形的二進位編碼,作為 BLOB。如果 P 不是多邊形,則 geopoly_blob(P) 會傳回 NULL。
如果 P 是多邊形,則 geopoly_json(P) 會傳回該多邊形的 GeoJSON 表達式,作為 TEXT 字串。如果 P 不是多邊形,則 geopoly_json(P) 會傳回 NULL。
如果 P 是多邊形,則 geopoly_svg(P,...) 會傳回一個文字字串,這個字串是該多邊形的 可縮放向量圖形 (SVG) 表示。如果有多個參數,則第二個和後續的參數會新增為每個 SVG 字形的屬性。例如
SELECT geopoly_svg($polygon,'class="poly"','style="fill:blue;"');
如果 P 不是多邊形,則 geopoly_svg(P,...) 會傳回 NULL。
請注意,geopoly 使用傳統的右手笛卡兒座標系統,原點在左下方,而 SVG 使用左手座標系統,原點在左上方。geopoly_svg() 常式不會嘗試轉換座標系統,因此顯示的影像會以鏡像顯示並旋轉。如果這不符合需求,則可以在將多邊形傳遞到 geopoly_svg() 之前,使用 geopoly_xform() 常式將輸出從笛卡兒座標轉換為 SVG 座標。
如果 P 是多邊形,則 geopoly_bbox(P) 會傳回一個新的多邊形,這個多邊形是最小的(軸對齊)矩形,且完全包圍 P。如果 P 不是多邊形,則 geopoly_bbox(P) 會傳回 NULL。
geopoly_group_bbox(P) 函數是 geopoly_bbox(P) 的聚合版本。geopoly_group_bbox(P) 函數會傳回最小的矩形,這個矩形會包圍在聚合期間看到的全部 P 值。
如果 P 是多邊形,則 geopoly_contains_point(P,X,Y) 會傳回非零整數,當且僅當座標 X,Y 在多邊形 P 的內部或邊界上。如果 P 不是多邊形,則 geopoly_contains_point(P,X,Y) 會傳回 NULL。
geopoly_xform(P,A,B,C,D,E,F) 函數會傳回一個新的多邊形,這個多邊形是多邊形 P 的仿射轉換,且轉換由值 A,B,C,D,E,F 定義。如果 P 不是有效的多邊形,則此常式會傳回 NULL。
轉換會根據下列公式轉換多邊形的每個頂點
x1 = A*x0 + B*y0 + E y1 = C*x0 + D*y0 + F
因此,例如,若要將多邊形沿著某個距離 DX、DY 移動,而不改變其形狀,請使用
geopoly_xform($polygon, 1, 0, 0, 1, $DX, $DY)
若要將多邊形繞點 0, 0 旋轉 R 弧度
geopoly_xform($polygon, cos($R), sin($R), -sin($R), cos($R), 0, 0)
請注意,翻轉多邊形的轉換可能會導致頂點順序反轉。換句話說,轉換可能會導致頂點以順時針順序循環,而不是逆時針。這可以在轉換後,透過將結果傳送至 geopoly_ccw() 函數來修正。
geopoly_regular(X,Y,R,N) 函數傳回一個凸、簡單、正則、等邊、等角的多邊形,其邊數為 N,中心點為 X,Y,外接圓半徑為 R。或者,如果 R 為負數或 N 小於 3,函數會傳回 NULL。N 值上限為 1000,因此即使 N 值大於 1000,例常程式也絕不會產生邊數超過 1000 的多邊形。
以下圖形為範例
是由這個指令碼產生的
SELECT '<svg width="600" height="300">'; WITH t1(x,y,n,color) AS (VALUES (100,100,3,'red'), (200,100,4,'orange'), (300,100,5,'green'), (400,100,6,'blue'), (500,100,7,'purple'), (100,200,8,'red'), (200,200,10,'orange'), (300,200,12,'green'), (400,200,16,'blue'), (500,200,20,'purple') ) SELECT geopoly_svg(geopoly_regular(x,y,40,n), printf('style="fill:none;stroke:%s;stroke-width:2"',color)) || printf(' <text x="%d" y="%d" alignment-baseline="central" text-anchor="middle">%d</text>',x,y+6,n) FROM t1; SELECT '</svg>';
geopoly_ccw(J) 函數傳回逆時針 (CCW) 旋轉的多邊形 J。
RFC-7946 要求多邊形使用逆時針旋轉。但規格也觀察到,許多舊版的 GeoJSON 檔案並未遵循規格,且包含順時針 (CW) 旋轉的多邊形。geopoly_ccw() 函數對於正在讀取舊版 GeoJSON 檔案的應用程式很有用。如果 geopoly_ccw() 的輸入是格式正確的多邊形,則不會進行任何變更。但是,如果輸入多邊形的循環方向是反向的,則 geopoly_ccw() 會反轉循環順序,以符合規格,並使其能與 Geopoly 模組正確運作。
geopoly 模組是 R-Tree 延伸模組 的延伸。geopoly 使用與 R-Tree 延伸模組 相同的底層邏輯和影子表格。geopoly 僅提供不同的介面,並提供一些額外的邏輯來計算多邊形解碼、重疊和包含。
Geopoly 內部使用二進制格式儲存所有多邊形。二進制多邊形包含一個 4 位元組標頭,後接一個座標對陣列,其中每個座標的每個維度都是一個 32 位元浮點數。
標頭的第一個位元組是旗標位元組。旗標位元組的最低有效位元決定標頭後的座標對是以大端序或小端序儲存。最低有效位元的值為 0 表示大端序,值為 1 表示小端序。標頭中第一個位元組的其他位元保留供未來擴充。
標頭中的下一個三個位元組以大端序整數記錄多邊形中的頂點數。因此,每個多邊形最多可有約 1600 萬個頂點。
標頭後面是座標對陣列。每個座標都是一個 32 位元浮點數。使用 32 位元浮點值表示座標表示地球表面上的任何點都可以以約 2.5 公尺解析度進行對應。如果地圖僅限於單一洲或國家,當然可以獲得更高的解析度。請注意,geopoly 模組中座標的解析度與地球表面上點由於潮汐力而產生的每日移動幅度類似。
二進制格式中的座標清單不包含任何冗餘。最後一個座標不會像 GeoJSON 那樣重複第一個座標。因此,與 GeoJSON 表示法相比,多邊形的二進制表示法中總是少一組座標對。
geopoly 模組建立在 R 樹擴充 之上,並使用相同的底層影子表和演算法。為了建立索引,每個多邊形在影子表中表示為一個矩形邊界框。底層 R 樹實作使用邊界框來限制搜尋空間。然後 geoploy_overlap() 和/或 geopoly_within() 常式進一步將搜尋範圍縮小到精確答案。
此頁面最後修改於 2023-12-05 14:43:20 UTC