地圖渲染技術(2)瓦片矢量數據格式

 

    地圖通過切割後造成了瓦片,每個編號對於一個瓦片,瓦片能夠是柵格數據也能夠是矢量數據,柵格數據就是一張正方形圖片,渲染時只須要將這張圖片做爲紋理貼到指定位置就行能夠,柵格瓦片的缺點就是數據量大,縮放時失真,不能自由配置顯示樣式。這些缺點在矢量瓦片中都得以解決,矢量瓦片中使用矢量數據描述地圖元素,經過渲染這些矢量數據造成地圖,數據量很小,縮放的時候不會失真,能夠在不一樣視角展現,能夠展現更豐富的高度信息,例如能夠拔高建築物。git

1,瓦片數據格式設計原則

 

    瓦片數據在地圖渲染的流程中包含:下載,解析,生成渲染Mesh數據,在全部,通常對瓦片數據格式的要求是,體積小,解析快,能夠配合不一樣的樣式生成不一樣的效果。github

2,瓦片中的Feature

  2.1 Feature

  Feature是幾何圖形數據和屬性的合集。例如點Feature 包含 x ,y 座標,和name等屬性。下面是Feature類型對應描述的地圖元素。shell

Feature 常見地圖元素
POI
路網,邊界,水系骨架
區域,海洋,綠地,建築物
多點 點雲,熱力圖
多線 多線相同屬性的線
多面 多個相同屬性的面
3D模型 地圖上的3D元素,例如建築物模型
   

    2.2 數據模型

      圖形數據和特性的屬性構成了數據模型,例如建築物的數據模型包含一個多邊形表明俯視輪廓,屬性中包含名稱,高度,類型(商業仍是住宅等)。不一樣地圖使用的數據模型不一樣,包含的信息豐富程度也不相同,可是基本的信息都很雷同,下面是常見的一些數據模型:json

地圖元素 模型信息
POI 點數據,文本,重要度(用於POI碰撞),商標,類型
公路 線數據,名稱,道路等級,方向性,類型
鐵路 線數據,名稱,類型
水面 名稱
綠地 名稱
建築物 名稱,高度
邊界線 類型

    2.3 數據與樣式

  在渲染實現中,一般是先不區分實際地圖元素,而是實現對每種類型Feature的渲染,而後經過不一樣的配置實現不一樣的現實效果。例如,公路,鐵路和邊界線都是線元素,只要實現線的渲染,在線的渲染實現中,線的顏色,寬度,實虛線均可以配置,這樣咱們經過不一樣的配置就能夠實現各類公路,鐵路,和邊界線的渲染。這些配置就是樣式。數據模型中屬性須要能關聯的一個特性的樣式,這樣咱們就能經過一組樣式配置來配置整個地圖了。不一樣的樣式組合就渲染出不一樣的地圖風格,例如百度地圖中的普通地圖和旅遊地圖。數據結構

 

 


 

Mapbox MVT 數據格式規格app

 

矢量瓦片標準

本文檔中的「必須」、「必須不」、「必備」、"應該"、「不該該」、「建議」、「能夠」、「可選」的含義參照RFC 2119google

1. 目標

本文檔規定了一種節省存儲空間的矢量瓦片數據編碼格式。這種格式應用於客戶端或服務端高效渲染或查詢要素信息。編碼

2. 文件格式

矢量瓦片文件採用Google Protocol Buffers進行編碼。Google Protocol Buffers是一種兼容多語言、多平臺、易擴展的數據序列化格式。spa

2.1. 文件後綴

矢量瓦片文件的後綴應該mvt。例如,vector.mvt設計

2.2 MIME類型

矢量瓦片的MIME類型應該設置爲application/vnd.mapbox-vector-tile

3. 投影和範圍

矢量瓦片表示的是投影在正方形區塊上的數據。矢量瓦片不該該包含範圍和投影信息。解碼方被假定知道矢量瓦片的範圍和投影信息。

Web Mercator是默認的投影方式,Google tile scheme是默認的瓦片編號方式。二者一塊兒完成了與任意範圍、任意精度的地理區域的一一對應,例如https://example.com/17/65535/43602.mvt

矢量瓦片能夠用來表示任意投影方式、任意瓦片編號方案的數據。

4. 內部結構

這部份內容描述矢量瓦片的數據結構。讀者須要先了解矢量瓦片protobuf編碼方案文件中的結構定義。

4.1. 圖層

矢量瓦片由一組命名的圖層構成。每一個圖層包含幾何要素和元數據信息。設計的圖層格式可以保證圖層數據可以在內存中按順序排列,由此在圖層組末尾添加一個新的圖層就不用更改已有的數據。

每塊矢量瓦片應該至少包含一個圖層。每一個圖層應該至少包含一個要素。

圖層必須包含一個version字段表示此圖層所遵照的《矢量瓦片標準》的主版本號。例如,某個圖層遵照2.1版本的標準,那麼它的version字段的值則爲整數2version字段應該設定爲圖層的第一個字段。解碼器應該首先解析version字段,以肯定是否可以解析該版本的圖層。當遇到一個未知版本的矢量瓦片圖層時,解碼器能夠嘗試去解析它,或者能夠跳過該圖層。以上兩種狀況下,解碼器都應該繼續解析後續的圖層。

圖層必須包含一個name字段。每塊矢量瓦片必須不包含兩個或兩個以上的圖層具備相同name值。在向一塊矢量瓦片添加一個新的圖層以前,編碼器必須檢查已有的name值以防止重複。

圖層中的每一個要素能夠包含一個或多個key-value做爲它的元數據(見下文)。全部要素的key和value被分別索引爲兩個列表——keysvalues——爲圖層中的全部要素所共享。

圖層keys字段的每一個元素都是字符串。keys字段包含了圖層中全部要素的key,而且每一個key能夠經過它在keys列表中的索引號引用,第一個key的索引號是0 。keys列表必須不包含兩個或兩個以上key是同樣的。

圖層values字段的每一個元素是多種類型的值的編碼(見下文)。values字段包含了圖層中全部要素的value,而且每一個value能夠經過它在values列表中的索引號引用,第一個value的索引號是0 。values列表必須不包含兩個或兩個以上value是同樣的。

爲了支持字符串型、布爾型、整型、浮點型多種類型的值,對value字段的編碼包含了一組optional字段。每一個value必須包含其中的一個字段。

圖層必須包含一個extent字段,表示瓦片的寬度和高度,以整數表示。矢量瓦片中的幾何座標能夠超出extent定義的範圍。超出extent範圍的幾何要素被常常用來做爲緩衝區,以渲染重疊在多塊相鄰瓦片上的要素。

例如,若是一塊瓦片的extent範圍是4096,那麼座標的單位是瓦片長寬的1/4096。座標0在瓦片的頂部或左邊緣,座標4096在瓦片的底部或右邊緣。座標從1到4095都是在瓦片內部,座標小於0或者大於4096在瓦片外部。座標(1,10)(4095,10)在瓦片內部。座標(0,10)(4096,10)在瓦片邊緣。座標(-1,10)(4097,10)在瓦片外部。

4.2. 要素

每一個要素必須包含一個geometry字段。

每一個要素必須包含一個type字段,該字段將在幾何類型章節描述(4.3.4)。

每一個要素能夠包含一個tags字段。若是存在屬於要素級別的元數據,應該存儲到tags字段中。

每一個要素能夠包含一個id字段。若是一個要素包含一個id字段,那麼id字段的值應該相對於圖層中的其餘要素是惟一的。

4.3. 幾何圖形編碼

矢量瓦片中的幾何數據被定義爲屏幕座標系。瓦片的左上角(顯示默認如此)是座標系的原點。X軸向右爲正,Y軸向下爲正。幾何圖形中的座標必須爲整數。

幾何圖形被編碼爲要素的geometry字段的一個32位無符號型整數序列。每一個整數是CommandInteger或者ParameterInteger。解碼器解析這些整數序列做爲生成幾何圖形的一系列有序操做。

指令涉及到的位置是相對於「遊標」的,即一個可重定義的點。對於要素中的第一條指令,遊標在座標系中的位置是(0,0)。有些指定可以移動遊標,於是會影響到接下來執行的指令。

4.3.1. 指令數

CommandInteger指代所要執行的操做和執行的次數,分別以command ID和command count表示。

command ID以CommandInteger最末尾的3個比特位表示,即從0到7。command count以CommandInteger剩下的29個比特位表示,即0pow(2, 29) - 1

command ID、command count、和CommandInteger三者能夠經過如下位運算相互轉換。

CommandInteger = (id & 0x7) | (count << 3)
id = CommandInteger & 0x7
count = CommandInteger >> 3

每一個command ID表示如下指令中的一種:

指令 Id 參數 參數個數
MoveTo 1 dXdY 2
LineTo 2 dXdY 2
ClosePath 7 無參數 0
指令數示例
指令 ID Count CommandInteger 二進制表示[Count][Id]
MoveTo 1 1 9 [00000000 00000000 0000000 00001][001]
MoveTo 1 120 961 [00000000 00000000 0000011 11000][001]
LineTo 2 1 10 [00000000 00000000 0000000 00001][010]
LineTo 2 3 26 [00000000 00000000 0000000 00011][010]
ClosePath 7 1 15 [00000000 00000000 0000000 00001][111]

4.3.2. 參數數

指令的全部參數緊跟在ParameterInteger以後。跟在CommandInteger以後的ParameterIntegers個數等於指令所須要參數的個數乘以指令執行的次數。例如,一條指示MoveTo指令執行3次的CommandInteger以後會跟隨6個ParameterIntegers

ParameterIntegerzigzag方式編碼獲得,以使小負數和正數都被編碼爲小整數。將參數值編碼爲ParameterInteger按如下公式轉換:

ParameterInteger = (value << 1) ^ (value >> 31)

參數值不支持大於pow(2,31) - 1-1 * (pow(2,31) - 1)的數值。

如下的公式用來將ParameterInteger解碼爲實際值:

value = ((ParameterInteger >> 1) ^ (-(ParameterInteger & 1)))

4.3.3. 指令類型

如下關於指令的描述中,遊標的初始位置定義爲座標(cX, cY),其中cX指代遊標在X軸上的位置,cY指代遊標在Y軸上的位置。

4.3.3.1. MoveTo指令

表示MoveTo指令執行nParameterInteger必須當即接上nParameterInteger。對於(dX, dY)參數:

  1. 定義座標(pX, pY),其中pX = cX + dXpY = cY + dY
    • 對於點要素,這個座標定義了一個新的點要素。
    • 對於線要素,這個座標定義了一條新的線要素的起點。
    • 對於面要素,這個座標定義了一個新環的起點。
  2. 將遊標移至(pX, pY)
4.3.3.1. LineTo指令

表示LineTo指令執行nParameterInteger必須當即接上nParameterInteger。對於(dX, dY)參數:

  1. 定義一條以遊標位置(cX, cY)爲起點,(pX, pY)爲終點的線段,其中pX = cX + dXpY = cY + dY
    • 對於線要素,這條線段延長了當前線要素。
    • 對於面要素,這條線段延長了當前環。
  2. 將遊標移至(pX, pY)

對於任意一對(dX, dY)dXdY必須不能同時爲0.

4.3.3.3. ClosePath指令

每條ClosePath指令必須只能執行一次而且無附帶參數。這條指令經過構造一條以遊標(cX, cY)爲起點、當前環的起點爲終點的線段,閉合面要素的當前環。

這條指定不改變遊標的位置。

4.3.4. 幾何類型

要素geometry字段的type的取值必須GeomType枚舉值之一。支持的幾何類型以下:

  • UNKNOWN
  • POINT
  • LINESTRING
  • POLYGON

不支持GeometryCollection類型。

4.3.4.1. Unknown幾何類型

本標準有意設置一個Unknown幾何類型。這種幾何類型能夠用來編碼試驗性的幾何類型。解碼器能夠選擇忽略這種幾何類型的要素。

4.3.4.2. Point幾何類型

POINT幾何類型用來表示單點或多點幾何。每一個點幾何的指令序列必須包含一個MoveTo指令,而且該指令的command count大於0。

若是POINT幾何的MoveTo的command count爲1,那麼必須將其解析爲單點;不然必須解析爲多點,指令後面的每對ParameterInteger表示一個單點。

4.3.4.3. Linestring幾何類型

LINESTRING幾何類型用來表示單線或多線幾何。線幾何的指令序列必須包含一個或多個下列序列:

  1. 一個MoveTo指令,其command count爲1
  2. 一個LineTo指令,其command count大於0

若是LINESTRING的指令序列只包含1個MoveTo指令,那麼必須將其解析爲單線;不然,必須將其解析爲多線,其中的每一個MoveTo指令開始構造一條新線幾何。

4.3.4.4. Polygon幾何類型

POLYGON幾何類型表示面或多面幾何,每一個面有且只有一個外環和零個或多個內環。面幾何的指令序列包含一個或多個下列序列:

  1. 一個ExteriorRing
  2. 零個或多個InteriorRing

Each ExteriorRing and InteriorRing MUST consist of the following sequence: 每一個ExteriorRingInteriorRing必須包含如下序列:

  1. 一個MoveTo指令,其command count爲1
  2. 一個LineTo指令,其command count大於1
  3. 一個ClosePath指令

一個外環被定義爲一個線性的環,當應用surveyor's formula,以多邊形的節點在瓦片座標系下的座標計算面積時,其面積爲正。在瓦片座標系下(X向右爲正,Y向下爲正),外環節點以順時針旋轉。

一個內環被定義爲一個線性的環,當應用surveyor's formula,以多邊形的節點在瓦片座標系下的座標計算面積時,其面積爲負。在瓦片座標系下(X向右爲正,Y向下爲正),內環節點以逆時針旋轉。

若是POLYGON的指令序列只包含一個外環,那麼必須將其解析爲單面;不然,必須解析爲多面幾何,其中每一個外環表示一個新面的開始。若是面幾何包換內環,那麼必須將其編碼到所屬的外環以後。

線性環必須不包含異常點,例如自相交或自相切。在ClosePath以前的座標不該該與線性環的起始點座標相同,由於會產生零長度的線段。線性環通過surveyor's formula計算的面積不該該爲0,由於這意味着環包含有異常點。

面幾何必須不能有內環相交,而且內環必須被包圍在內環之中。

4.3.5. 幾何要素編碼示例

4.3.5.1. 點要素示例

假設示例點的座標爲:

  • (25, 17)

表示它只須要一條指令:

  • MoveTo(+25, +17)
編碼      : [ 9 50 34 ]
              | |  `> 解碼: ((34 >> 1) ^ (-(34 & 1))) = +17
              | `> 解碼: ((50 >> 1) ^ (-(50 & 1))) = +25
              | ===== 相對地 MoveTo(+25, +17) == 建立點 (25,17)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.2. 多點要素示例

假設多點要素的座標爲:

  • (5,7)
  • (3,2)

編碼須要兩條指令:

  • MoveTo(+5,+7)
  • MoveTo(-2,-5)
編碼      : [ 17 10 14 3 9 ]
               |  |  | | `> 解碼: ((9 >> 1) ^ (-(9 & 1))) = -5
               |  |  | `> 解碼: ((3 >> 1) ^ (-(3 & 1))) = -2
               |  |  | === 相對地 MoveTo(-2, -5) == 建立點 (3,2)
               |  |  `> 解碼: ((34 >> 1) ^ (-(34 & 1))) = +7
               |  `> 解碼: ((50 >> 1) ^ (-(50 & 1))) = +5
               | ===== relative MoveTo(+25, +17) == 建立點 (25,17)
               `> [00010 001] = command id 1 (MoveTo), command count 2
4.3.5.3. 線要素示例

假設示例線要素的座標爲:

  • (2,2)
  • (2,10)
  • (10,10)

編碼須要3條指令:

  • MoveTo(+2,+2)
  • LineTo(+0,+8)
  • LineTo(+8,+0)
編碼      : [ 9 4 4 18 0 16 16 0 ]
              |      |      ==== 相對地 LineTo(+8, +0) == 鏈接到點 (10, 10)
              |      | ==== 相對地 LineTo(+0, +8) == 鏈接到點 (2, 10)
              |      `> [00010 010] = command id 2 (LineTo), command count 2
              | === 相對地 MoveTo(+2, +2)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.4. Example Multi Linestring
4.3.5.4. 多線要素示例

假設示例要素的座標爲:

  • Line 1:
    • (2,2)
    • (2,10)
    • (10,10)
  • Line 2:
    • (1,1)
    • (3,5)

編碼須要如下指令:

  • MoveTo(+2,+2)
  • LineTo(+0,+8)
  • LineTo(+8,+0)
  • MoveTo(-9,-9)
  • LineTo(+2,+4)
編碼      : [ 9 4 4 18 0 16 16 0 9 17 17 10 4 8 ]
              |      |           |        | === 相對地 LineTo(+2, +4) == 鏈接到點 (3,5)
              |      |           |        `> [00001 010] = command id 2 (LineTo), command count 1
              |      |           | ===== 相對地 MoveTo(-9, -9) == 新建一條線從 (1,1)
              |      |           `> [00001 001] = command id 1 (MoveTo), command count 1
              |      |      ==== 相對地 LineTo(+8, +0) == 鏈接到點 (10, 10)
              |      | ==== 相對地 LineTo(+0, +8) == 鏈接到點 (2, 10)
              |      `> [00010 010] = command id 2 (LineTo), command count 2
              | === 相對地 MoveTo(+2, +2)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.5. 面要素示例

假設示例面要素的座標爲:

  • (3,6)
  • (8,12)
  • (20,34)
  • (3,6) 閉合

編碼須要如下指令:

  • MoveTo(3, 6)
  • LineTo(5, 6)
  • LineTo(12, 22)
  • ClosePath
編碼      : [ 9 6 12 18 10 12 24 44 15 ]
              |       |              `> [00001 111] command id 7 (ClosePath), command count 1
              |       |       ===== 相對地 LineTo(+12, +22) == 鏈接到點 (20, 34)
              |       | ===== 相對地 LineTo(+5, +6) == 鏈接到點 (8, 12)
              |       `> [00010 010] = command id 2 (LineTo), command count 2
              | ==== 相對地 MoveTo(+3, +6)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.6. 多面要素示例

示例要素包含兩個多邊形,其中一個多邊形有一個洞。多邊形中的點以下。注意,多邊形中的點環繞順序很是重要,應爲這個順序被用來區別外環和內環。

  • Polygon 1:
    • 外環:
      • (0,0)
      • (10,0)
      • (10,10)
      • (0,10)
      • (0,0) 閉合
  • Polygon 2:
    • 外環:
      • (11,11)
      • (20,11)
      • (20,20)
      • (11,20)
      • (11,11) 閉合
    • 內環:
      • (13,13)
      • (13,17)
      • (17,17)
      • (17,13)
      • (13,13) 閉合

編碼須要如下一系列指令:

  • MoveTo(+0,+0)
  • LineTo(+10,+0)
  • LineTo(+0,+10)
  • LineTo(-10,+0) // 執行這條指令後,遊標的位置在(0, 10)
  • ClosePath // Polygon 1結束
  • MoveTo(+11,+1) // 這條指令相對於上面最後一條LineTo指令!
  • LineTo(+9,+0)
  • LineTo(+0,+9)
  • LineTo(-9,+0) // 執行這條指令後,遊標的位置在(11, 20)
  • ClosePath // 這是一個新面要素,由於面積爲正
  • MoveTo(+2,-7) // 這條指令相對於上面最後一條LineTo指令!
  • LineTo(+0,+4)
  • LineTo(+4,+0)
  • LineTo(+0,-4) // 執行這條指令後,遊標的位置在(17, 13)
  • ClosePath // 這是一個內環,由於面積爲負

4.4. 要素屬性

要素屬性被編碼爲tag字段中的一對對整數。在每對tag中,第一個整數表示key在其所屬的layerkeys列表的中索引號(以0開始)。第二個整數表示value在其所屬的layervalues列表的中索引號(以0開始)。一個要素的全部key索引必須惟一,以保證要素中沒有重複的屬性項。每一個要素的tag字段必須爲偶數。要素中的tag字段包含的key索引號或value索引號必須不能大於或等於相應圖層中keysvalues列表中的元素數目。

4.5. 示例

例如,一個GeoJSON格式的要素以下:

{
    "type": "FeatureCollection",
    "features": [
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -8247861.1000836585,
                    4970241.327215323
                ]
            },
            "type": "Feature",
            "properties": {
                "hello": "world",
                "h": "world",
                "count": 1.23
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -8247861.1000836585,
                    4970241.327215323
                ]
            },
            "type": "Feature",
            "properties": {
                "hello": "again",
                "count": 2
            }
        }
    ]
}

會被結構化爲:

layers {
  version: 2
  name: "points"
  features: {
    id: 1
    tags: 0
    tags: 0
    tags: 1
    tags: 0
    tags: 2
    tags: 1
    type: Point
    geometry: 9
    geometry: 2410
    geometry: 3080
  }
  features {
    id: 2
    tags: 0
    tags: 2
    tags: 2
    tags: 3
    type: Point
    geometry: 9
    geometry: 2410
    geometry: 3080
  }
  keys: "hello"
  keys: "h"
  keys: "count"
  values: {
    string_value: "world"
  }
  values: {
    double_value: 1.23
  }
  values: {
    string_value: "again"
  }
  values: {
    int_value: 2
  }
  extent: 4096
}

注意幾何要素的實際座標取決於座標系和瓦片的範圍。

 

MapBox MVT數據格式:https://github.com/jingsam/vector-tile-spec/blob/master/2.1/README_zh.md

矢量瓦片標準

本文檔中的「必須」、「必須不」、「必備」、"應該"、「不該該」、「建議」、「能夠」、「可選」的含義參照RFC 2119

1. 目標

本文檔規定了一種節省存儲空間的矢量瓦片數據編碼格式。這種格式應用於客戶端或服務端高效渲染或查詢要素信息。

2. 文件格式

矢量瓦片文件採用Google Protocol Buffers進行編碼。Google Protocol Buffers是一種兼容多語言、多平臺、易擴展的數據序列化格式。

2.1. 文件後綴

矢量瓦片文件的後綴應該mvt。例如,vector.mvt

2.2 MIME類型

矢量瓦片的MIME類型應該設置爲application/vnd.mapbox-vector-tile

3. 投影和範圍

矢量瓦片表示的是投影在正方形區塊上的數據。矢量瓦片不該該包含範圍和投影信息。解碼方被假定知道矢量瓦片的範圍和投影信息。

Web Mercator是默認的投影方式,Google tile scheme是默認的瓦片編號方式。二者一塊兒完成了與任意範圍、任意精度的地理區域的一一對應,例如https://example.com/17/65535/43602.mvt

矢量瓦片能夠用來表示任意投影方式、任意瓦片編號方案的數據。

4. 內部結構

這部份內容描述矢量瓦片的數據結構。讀者須要先了解矢量瓦片protobuf編碼方案文件中的結構定義。

4.1. 圖層

矢量瓦片由一組命名的圖層構成。每一個圖層包含幾何要素和元數據信息。設計的圖層格式可以保證圖層數據可以在內存中按順序排列,由此在圖層組末尾添加一個新的圖層就不用更改已有的數據。

每塊矢量瓦片應該至少包含一個圖層。每一個圖層應該至少包含一個要素。

圖層必須包含一個version字段表示此圖層所遵照的《矢量瓦片標準》的主版本號。例如,某個圖層遵照2.1版本的標準,那麼它的version字段的值則爲整數2version字段應該設定爲圖層的第一個字段。解碼器應該首先解析version字段,以肯定是否可以解析該版本的圖層。當遇到一個未知版本的矢量瓦片圖層時,解碼器能夠嘗試去解析它,或者能夠跳過該圖層。以上兩種狀況下,解碼器都應該繼續解析後續的圖層。

圖層必須包含一個name字段。每塊矢量瓦片必須不包含兩個或兩個以上的圖層具備相同name值。在向一塊矢量瓦片添加一個新的圖層以前,編碼器必須檢查已有的name值以防止重複。

圖層中的每一個要素能夠包含一個或多個key-value做爲它的元數據(見下文)。全部要素的key和value被分別索引爲兩個列表——keysvalues——爲圖層中的全部要素所共享。

圖層keys字段的每一個元素都是字符串。keys字段包含了圖層中全部要素的key,而且每一個key能夠經過它在keys列表中的索引號引用,第一個key的索引號是0 。keys列表必須不包含兩個或兩個以上key是同樣的。

圖層values字段的每一個元素是多種類型的值的編碼(見下文)。values字段包含了圖層中全部要素的value,而且每一個value能夠經過它在values列表中的索引號引用,第一個value的索引號是0 。values列表必須不包含兩個或兩個以上value是同樣的。

爲了支持字符串型、布爾型、整型、浮點型多種類型的值,對value字段的編碼包含了一組optional字段。每一個value必須包含其中的一個字段。

圖層必須包含一個extent字段,表示瓦片的寬度和高度,以整數表示。矢量瓦片中的幾何座標能夠超出extent定義的範圍。超出extent範圍的幾何要素被常常用來做爲緩衝區,以渲染重疊在多塊相鄰瓦片上的要素。

例如,若是一塊瓦片的extent範圍是4096,那麼座標的單位是瓦片長寬的1/4096。座標0在瓦片的頂部或左邊緣,座標4096在瓦片的底部或右邊緣。座標從1到4095都是在瓦片內部,座標小於0或者大於4096在瓦片外部。座標(1,10)(4095,10)在瓦片內部。座標(0,10)(4096,10)在瓦片邊緣。座標(-1,10)(4097,10)在瓦片外部。

4.2. 要素

每一個要素必須包含一個geometry字段。

每一個要素必須包含一個type字段,該字段將在幾何類型章節描述(4.3.4)。

每一個要素能夠包含一個tags字段。若是存在屬於要素級別的元數據,應該存儲到tags字段中。

每一個要素能夠包含一個id字段。若是一個要素包含一個id字段,那麼id字段的值應該相對於圖層中的其餘要素是惟一的。

4.3. 幾何圖形編碼

矢量瓦片中的幾何數據被定義爲屏幕座標系。瓦片的左上角(顯示默認如此)是座標系的原點。X軸向右爲正,Y軸向下爲正。幾何圖形中的座標必須爲整數。

幾何圖形被編碼爲要素的geometry字段的一個32位無符號型整數序列。每一個整數是CommandInteger或者ParameterInteger。解碼器解析這些整數序列做爲生成幾何圖形的一系列有序操做。

指令涉及到的位置是相對於「遊標」的,即一個可重定義的點。對於要素中的第一條指令,遊標在座標系中的位置是(0,0)。有些指定可以移動遊標,於是會影響到接下來執行的指令。

4.3.1. 指令數

CommandInteger指代所要執行的操做和執行的次數,分別以command ID和command count表示。

command ID以CommandInteger最末尾的3個比特位表示,即從0到7。command count以CommandInteger剩下的29個比特位表示,即0pow(2, 29) - 1

command ID、command count、和CommandInteger三者能夠經過如下位運算相互轉換。

CommandInteger = (id & 0x7) | (count << 3)
id = CommandInteger & 0x7
count = CommandInteger >> 3

每一個command ID表示如下指令中的一種:

指令 Id 參數 參數個數
MoveTo 1 dXdY 2
LineTo 2 dXdY 2
ClosePath 7 無參數 0
指令數示例
指令 ID Count CommandInteger 二進制表示[Count][Id]
MoveTo 1 1 9 [00000000 00000000 0000000 00001][001]
MoveTo 1 120 961 [00000000 00000000 0000011 11000][001]
LineTo 2 1 10 [00000000 00000000 0000000 00001][010]
LineTo 2 3 26 [00000000 00000000 0000000 00011][010]
ClosePath 7 1 15 [00000000 00000000 0000000 00001][111]

4.3.2. 參數數

指令的全部參數緊跟在ParameterInteger以後。跟在CommandInteger以後的ParameterIntegers個數等於指令所須要參數的個數乘以指令執行的次數。例如,一條指示MoveTo指令執行3次的CommandInteger以後會跟隨6個ParameterIntegers

ParameterIntegerzigzag方式編碼獲得,以使小負數和正數都被編碼爲小整數。將參數值編碼爲ParameterInteger按如下公式轉換:

ParameterInteger = (value << 1) ^ (value >> 31)

參數值不支持大於pow(2,31) - 1-1 * (pow(2,31) - 1)的數值。

如下的公式用來將ParameterInteger解碼爲實際值:

value = ((ParameterInteger >> 1) ^ (-(ParameterInteger & 1)))

4.3.3. 指令類型

如下關於指令的描述中,遊標的初始位置定義爲座標(cX, cY),其中cX指代遊標在X軸上的位置,cY指代遊標在Y軸上的位置。

4.3.3.1. MoveTo指令

表示MoveTo指令執行nParameterInteger必須當即接上nParameterInteger。對於(dX, dY)參數:

  1. 定義座標(pX, pY),其中pX = cX + dXpY = cY + dY
    • 對於點要素,這個座標定義了一個新的點要素。
    • 對於線要素,這個座標定義了一條新的線要素的起點。
    • 對於面要素,這個座標定義了一個新環的起點。
  2. 將遊標移至(pX, pY)
4.3.3.1. LineTo指令

表示LineTo指令執行nParameterInteger必須當即接上nParameterInteger。對於(dX, dY)參數:

  1. 定義一條以遊標位置(cX, cY)爲起點,(pX, pY)爲終點的線段,其中pX = cX + dXpY = cY + dY
    • 對於線要素,這條線段延長了當前線要素。
    • 對於面要素,這條線段延長了當前環。
  2. 將遊標移至(pX, pY)

對於任意一對(dX, dY)dXdY必須不能同時爲0.

4.3.3.3. ClosePath指令

每條ClosePath指令必須只能執行一次而且無附帶參數。這條指令經過構造一條以遊標(cX, cY)爲起點、當前環的起點爲終點的線段,閉合面要素的當前環。

這條指定不改變遊標的位置。

4.3.4. 幾何類型

要素geometry字段的type的取值必須GeomType枚舉值之一。支持的幾何類型以下:

  • UNKNOWN
  • POINT
  • LINESTRING
  • POLYGON

不支持GeometryCollection類型。

4.3.4.1. Unknown幾何類型

本標準有意設置一個Unknown幾何類型。這種幾何類型能夠用來編碼試驗性的幾何類型。解碼器能夠選擇忽略這種幾何類型的要素。

4.3.4.2. Point幾何類型

POINT幾何類型用來表示單點或多點幾何。每一個點幾何的指令序列必須包含一個MoveTo指令,而且該指令的command count大於0。

若是POINT幾何的MoveTo的command count爲1,那麼必須將其解析爲單點;不然必須解析爲多點,指令後面的每對ParameterInteger表示一個單點。

4.3.4.3. Linestring幾何類型

LINESTRING幾何類型用來表示單線或多線幾何。線幾何的指令序列必須包含一個或多個下列序列:

  1. 一個MoveTo指令,其command count爲1
  2. 一個LineTo指令,其command count大於0

若是LINESTRING的指令序列只包含1個MoveTo指令,那麼必須將其解析爲單線;不然,必須將其解析爲多線,其中的每一個MoveTo指令開始構造一條新線幾何。

4.3.4.4. Polygon幾何類型

POLYGON幾何類型表示面或多面幾何,每一個面有且只有一個外環和零個或多個內環。面幾何的指令序列包含一個或多個下列序列:

  1. 一個ExteriorRing
  2. 零個或多個InteriorRing

Each ExteriorRing and InteriorRing MUST consist of the following sequence: 每一個ExteriorRingInteriorRing必須包含如下序列:

  1. 一個MoveTo指令,其command count爲1
  2. 一個LineTo指令,其command count大於1
  3. 一個ClosePath指令

一個外環被定義爲一個線性的環,當應用surveyor's formula,以多邊形的節點在瓦片座標系下的座標計算面積時,其面積爲正。在瓦片座標系下(X向右爲正,Y向下爲正),外環節點以順時針旋轉。

一個內環被定義爲一個線性的環,當應用surveyor's formula,以多邊形的節點在瓦片座標系下的座標計算面積時,其面積爲負。在瓦片座標系下(X向右爲正,Y向下爲正),內環節點以逆時針旋轉。

若是POLYGON的指令序列只包含一個外環,那麼必須將其解析爲單面;不然,必須解析爲多面幾何,其中每一個外環表示一個新面的開始。若是面幾何包換內環,那麼必須將其編碼到所屬的外環以後。

線性環必須不包含異常點,例如自相交或自相切。在ClosePath以前的座標不該該與線性環的起始點座標相同,由於會產生零長度的線段。線性環通過surveyor's formula計算的面積不該該爲0,由於這意味着環包含有異常點。

面幾何必須不能有內環相交,而且內環必須被包圍在內環之中。

4.3.5. 幾何要素編碼示例

4.3.5.1. 點要素示例

假設示例點的座標爲:

  • (25, 17)

表示它只須要一條指令:

  • MoveTo(+25, +17)
編碼      : [ 9 50 34 ]
              | |  `> 解碼: ((34 >> 1) ^ (-(34 & 1))) = +17
              | `> 解碼: ((50 >> 1) ^ (-(50 & 1))) = +25
              | ===== 相對地 MoveTo(+25, +17) == 建立點 (25,17)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.2. 多點要素示例

假設多點要素的座標爲:

  • (5,7)
  • (3,2)

編碼須要兩條指令:

  • MoveTo(+5,+7)
  • MoveTo(-2,-5)
編碼      : [ 17 10 14 3 9 ]
               |  |  | | `> 解碼: ((9 >> 1) ^ (-(9 & 1))) = -5
               |  |  | `> 解碼: ((3 >> 1) ^ (-(3 & 1))) = -2
               |  |  | === 相對地 MoveTo(-2, -5) == 建立點 (3,2)
               |  |  `> 解碼: ((34 >> 1) ^ (-(34 & 1))) = +7
               |  `> 解碼: ((50 >> 1) ^ (-(50 & 1))) = +5
               | ===== relative MoveTo(+25, +17) == 建立點 (25,17)
               `> [00010 001] = command id 1 (MoveTo), command count 2
4.3.5.3. 線要素示例

假設示例線要素的座標爲:

  • (2,2)
  • (2,10)
  • (10,10)

編碼須要3條指令:

  • MoveTo(+2,+2)
  • LineTo(+0,+8)
  • LineTo(+8,+0)
編碼      : [ 9 4 4 18 0 16 16 0 ]
              |      |      ==== 相對地 LineTo(+8, +0) == 鏈接到點 (10, 10)
              |      | ==== 相對地 LineTo(+0, +8) == 鏈接到點 (2, 10)
              |      `> [00010 010] = command id 2 (LineTo), command count 2
              | === 相對地 MoveTo(+2, +2)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.4. Example Multi Linestring
4.3.5.4. 多線要素示例

假設示例要素的座標爲:

  • Line 1:
    • (2,2)
    • (2,10)
    • (10,10)
  • Line 2:
    • (1,1)
    • (3,5)

編碼須要如下指令:

  • MoveTo(+2,+2)
  • LineTo(+0,+8)
  • LineTo(+8,+0)
  • MoveTo(-9,-9)
  • LineTo(+2,+4)
編碼      : [ 9 4 4 18 0 16 16 0 9 17 17 10 4 8 ]
              |      |           |        | === 相對地 LineTo(+2, +4) == 鏈接到點 (3,5)
              |      |           |        `> [00001 010] = command id 2 (LineTo), command count 1
              |      |           | ===== 相對地 MoveTo(-9, -9) == 新建一條線從 (1,1)
              |      |           `> [00001 001] = command id 1 (MoveTo), command count 1
              |      |      ==== 相對地 LineTo(+8, +0) == 鏈接到點 (10, 10)
              |      | ==== 相對地 LineTo(+0, +8) == 鏈接到點 (2, 10)
              |      `> [00010 010] = command id 2 (LineTo), command count 2
              | === 相對地 MoveTo(+2, +2)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.5. 面要素示例

假設示例面要素的座標爲:

  • (3,6)
  • (8,12)
  • (20,34)
  • (3,6) 閉合

編碼須要如下指令:

  • MoveTo(3, 6)
  • LineTo(5, 6)
  • LineTo(12, 22)
  • ClosePath
編碼      : [ 9 6 12 18 10 12 24 44 15 ]
              |       |              `> [00001 111] command id 7 (ClosePath), command count 1
              |       |       ===== 相對地 LineTo(+12, +22) == 鏈接到點 (20, 34)
              |       | ===== 相對地 LineTo(+5, +6) == 鏈接到點 (8, 12)
              |       `> [00010 010] = command id 2 (LineTo), command count 2
              | ==== 相對地 MoveTo(+3, +6)
              `> [00001 001] = command id 1 (MoveTo), command count 1
4.3.5.6. 多面要素示例

示例要素包含兩個多邊形,其中一個多邊形有一個洞。多邊形中的點以下。注意,多邊形中的點環繞順序很是重要,應爲這個順序被用來區別外環和內環。

  • Polygon 1:
    • 外環:
      • (0,0)
      • (10,0)
      • (10,10)
      • (0,10)
      • (0,0) 閉合
  • Polygon 2:
    • 外環:
      • (11,11)
      • (20,11)
      • (20,20)
      • (11,20)
      • (11,11) 閉合
    • 內環:
      • (13,13)
      • (13,17)
      • (17,17)
      • (17,13)
      • (13,13) 閉合

編碼須要如下一系列指令:

  • MoveTo(+0,+0)
  • LineTo(+10,+0)
  • LineTo(+0,+10)
  • LineTo(-10,+0) // 執行這條指令後,遊標的位置在(0, 10)
  • ClosePath // Polygon 1結束
  • MoveTo(+11,+1) // 這條指令相對於上面最後一條LineTo指令!
  • LineTo(+9,+0)
  • LineTo(+0,+9)
  • LineTo(-9,+0) // 執行這條指令後,遊標的位置在(11, 20)
  • ClosePath // 這是一個新面要素,由於面積爲正
  • MoveTo(+2,-7) // 這條指令相對於上面最後一條LineTo指令!
  • LineTo(+0,+4)
  • LineTo(+4,+0)
  • LineTo(+0,-4) // 執行這條指令後,遊標的位置在(17, 13)
  • ClosePath // 這是一個內環,由於面積爲負

4.4. 要素屬性

要素屬性被編碼爲tag字段中的一對對整數。在每對tag中,第一個整數表示key在其所屬的layerkeys列表的中索引號(以0開始)。第二個整數表示value在其所屬的layervalues列表的中索引號(以0開始)。一個要素的全部key索引必須惟一,以保證要素中沒有重複的屬性項。每一個要素的tag字段必須爲偶數。要素中的tag字段包含的key索引號或value索引號必須不能大於或等於相應圖層中keysvalues列表中的元素數目。

4.5. 示例

例如,一個GeoJSON格式的要素以下:

{
    "type": "FeatureCollection",
    "features": [
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -8247861.1000836585,
                    4970241.327215323
                ]
            },
            "type": "Feature",
            "properties": {
                "hello": "world",
                "h": "world",
                "count": 1.23
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -8247861.1000836585,
                    4970241.327215323
                ]
            },
            "type": "Feature",
            "properties": {
                "hello": "again",
                "count": 2
            }
        }
    ]
}

會被結構化爲:

layers {
  version: 2
  name: "points"
  features: {
    id: 1
    tags: 0
    tags: 0
    tags: 1
    tags: 0
    tags: 2
    tags: 1
    type: Point
    geometry: 9
    geometry: 2410
    geometry: 3080
  }
  features {
    id: 2
    tags: 0
    tags: 2
    tags: 2
    tags: 3
    type: Point
    geometry: 9
    geometry: 2410
    geometry: 3080
  }
  keys: "hello"
  keys: "h"
  keys: "count"
  values: {
    string_value: "world"
  }
  values: {
    double_value: 1.23
  }
  values: {
    string_value: "again"
  }
  values: {
    int_value: 2
  }
  extent: 4096
}

注意幾何要素的實際座標取決於座標系和瓦片的範圍。

相關文章
相關標籤/搜索