このドキュメントに記載されている単語 "しなければならない (MUST)"、"してはならない (MUST NOT)"、"要求されている (REQUIRED)"、"することになる (SHALL)"、"することはない (SHALL NOT)"、"する必要がある (SHOULD)"、"しないほうがよい (SHOULD NOT)"、"推奨される (RECOMMENDED)"、"してもよい (MAY)"、"選択できる (OPTIONAL)" は、 RFC 2119 に記述されているとおりに解釈されるものとする。
このドキュメントでは、タイル化された地理的ベクトルデータの容量効率のよい符号化フォーマットの仕様を策定する。この仕様は高速なレンダリングや地物データ検索をブラウザ及びサーバーサイドアプリケーションで実現するために設計されている。
このベクトルタイルフォーマットは、Google Protocol Buffers を符号化フォーマットとして使用する。 Protocol Buffers は、構造化されたデータを格納するための特定の言語やプラットフォームに依存しない拡張可能な仕組みである。
ベクトルタイルファイルの拡張子は mvt
にする必要がある (SHOULD)。たとえば、あるファイルは vector.mvt
となるであろう。
ベクトルタイルを配信する際の MIME タイプは application/vnd.mapbox-vector-tile
とするべきである (SHOULD)。
ベクトルタイルは特定の投影法のもとでの四角い領域のデータを表現する。ベクトルタイルには、その領域や投影法に関する情報を含めないほうがよい (SHOULD NOT)。このファイル形式は、デコーダーがこれを復号化する前に領域や投影法を知っていることを前提としている。
Web メルカトル は基準となる投影法であり、the Google tile scheme は基準となるタイル領域の慣例である。これらは、特定の詳細レベルにおける特定の地理的領域と https://example.com/17/65535/43602.mvt
のようなパスを 1:1 で紐付ける。
ベクトルタイルは、どのような投影法やタイル領域のスキームを用いた地理データの表現にも使用してもよい (MAY)。
この仕様書では、ベクトルタイル内のデータ構造について明らかにする。読者は Vector Tile protobuf schema document と、それが定義する構造について理解している必要がある。
ベクトルタイルは、名前付きのレイヤーのセットで構成されている。レイヤーは幾何属性のある地物とそのメタデータを含んでいる。レイヤのフォーマットは、ひとつのレイヤに必要なデータが記憶領域内で接するように設計されている。このようにすることによって、既存のデータを変更することなく、レイヤがベクトルタイルに追加できる。
ベクトルタイルは少なくともひとつのレイヤーを含む必要がある。レイヤーは少なくとも1つの地物を含むべきである。
レイヤーは、そのレイヤーが準拠するベクトルタイル仕様書と同じメジャーバージョン番号を持つ version
フィールドを含んでいなければならない (MUST)。たとえば、あるレイヤーがバージョン 2.1 に準拠しているのであれば、整数の 2
を version
フィールドとして含めるべきである。version
フィールドは、そのレイヤーの最初のフィールドである必要がある (SHOULD)。デコーダーは、各レイヤーを確実に処理するために、まず version
をパースする必要がある (SHOULD)。ベクトルタイルのコンシューマーが未知のバージョンのベクトルタイルに遭遇した場合、レイヤーを解釈するために最善の努力をするか、そのレイヤーをスキップしてもよい (MAY)。どちらの場合も、そのベクトルタイル内の後続のレイヤーの処理を続ける必要がある (SHOULD)。
レイヤーは name
フィールドを含んでいなければならない (MUST)。ベクトルタイルは、同じ値 (byte-for-byte) を名前に持つ2つ以上のレイヤーを含んではならない (MUST NOT)。エンコーダーは、既存のベクトルタイルにレイヤーを追加する前に、重複を防止するために既存の name
フィールドをチェックしなければならない (MUST)。
レイヤー内の地物(以下を参照)は一つまたは複数のキーと値のペアをメタデータとして保持してもよい (MAY)。キーと値は keys
と values
という2つのリストのインデックスで、レイヤーの地物をまたがって共有される。
keys
フィールド内の個々の要素は文字列である。keys
は、レイヤー内で使用される地物のすべてのキーを含んでおり、それぞれのキーは位置インデックスによって参照され、最初のキーは 0 というインデックスをもっている。keys
のセットは、2つ以上の同じ値 (byte-for-byte) を含まないほうがよい (SHOULD NOT)。
values
フィールド内のそれぞれの要素は、あらゆるデータ型がエンコードされている(以下を参照)。values
は、レイヤー内で使用されるすべての値が再現されており、それぞれのキーは位置インデックスによって参照され、最初のキーは 0 というインデックスをもっている。values
のセットは、2つ以上の同じ値 (byte-for-byte) を含まないほうがよい (SHOULD NOT)。
boolean 型、integer 型、そして浮動小数点型などの異なるデータ型をサポートするために、value
フィールドの Protocol Buffers エンコーディングは、optional
フィールドのセットで構成されている。値はこれらのオプションフィールドのうちの一つだけが含まれなければならない (MUST)。
レイヤーはタイルの幅と高さを記述するための整数による座標 extent
を含んでいなければならない (MUST)。ベクタータイル内のジオメトリは、extent
で定義されたタイル領域の境界を越えて延びてもよい (MAY)。extent
で定義されたタイル領域を越えて延びるジオメトリは、隣接する複数のタイルに重なる地物をレンダリングするためのバッファとして使用されることが多い。
たとえば、あるタイルが 4096 という値の extent
を持っている場合、タイル内の座標は正方形の 1/4096 となる。座標 0 はタイルの左上の角にあり、4096 は右下の角にある。1 から 4095 までの座標は完全にタイルの領域内にあり、0 より小さいか 4096 より大きい座標はタイルの領域外である。座標 (1,10)
または (4095,10)
のポイントはタイルの領域内にあり、(0,10)
または (4096,10)
のポイントはタイルの領域の端にある。(-1,10)
または (4097,10)
のポイントはタイルの領域外にある。
地物は、geometry
フィールドを含まなければならない (MUST)。
地物は、Geometry 型セクションで説明している type
フィールドを含まなければならない (MUST)。
地物は、tags
フィールドを含むことができる (MAY)。地物固有のメタデータがもしあれば、tags
フィールドに保存されるべきである (SHOULD)。
地物は、id
フィールドを含むことができる (MAY)。もし地物が id
フィールドを持っている場合、id
フィールドの値は、親レイヤーの中で地物ごとにユニークであるべきである (SHOULD)。
ベクトルタイル内のジオメトリデータは、スクリーンの座標システムで定義される。(デフォルトで表示される)タイルの最も左上は、座標システムの原点である。X 座標は右に正であり、Y 座標は下に正である。ジオメトリ内の座標は整数でなければならない (MUST)。
ジオメトリは、地物の geometry
フィールド内に、32 bit 符号なし整数のシーケンスとしてエンコードされる。各整数は、CommandInteger
か ParameterInteger
である。デコーダはこれらをジオメトリを生成するために順番に処理するものとして解釈する。
コマンドは、"カーソル"位置を再定義可能な点である相対的な位置で参照する。地物の最初のコマンドでは、カーソルは座標システムでの (0,0)
にある。一部のコマンドはカーソルを移動し、その後のコマンドに影響を与える。
CommandInteger
は、コマンド ID で実行されるコマンドを指示し、コマンドカウントで実行されるコマンドの実行回数を指示する。
コマンド ID は、CommandInteger
の最下位 3 ビットの符号なし整数として符号化され、0〜7 の範囲内にある。 コマンドカウントは、CommandInteger
の残りの29ビットの符号なし整数として符号化され、0
から pow(2, 29)- 1
の範囲内にある。
コマンド ID、コマンドカウント、および CommandInteger
は、これらのビット操作によって関連付けられる:
CommandInteger = (id & 0x7) | (count << 3)
id = CommandInteger & 0x7
count = CommandInteger >> 3
コマンド ID は、以下のコマンドのうちの一つを指定する:
Command | Id | Parameters | Parameter Count |
---|---|---|---|
MoveTo | 1 |
dX , dY |
2 |
LineTo | 2 |
dX , dY |
2 |
ClosePath | 7 |
No parameters | 0 |
Command | ID | Count | CommandInteger | Binary Representation [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] |
パラメータを必要とするコマンドの後には、そのコマンドで必要とされる各パラメータのための ParameterInteger
がつづく。CommandInteger
につづく ParameterIntegers
の数は、 CommandInteger
のコマンドカウントを掛けたコマンドのパラメータ数に等しい。たとえば、コマンドカウントが3の MoveTo
コマンドを含む CommandInteger
の後に6つの ParameterIntegers
が続く。
数値パラメータは ZigZag でエンコードされており、小さな正と負の両方の整数がそれぞれ小さな整数としてエンコードされる。数値パラメータの値を ParameterInteger
にエンコードするには以下の数式を使用する。
ParameterInteger = (value << 1) ^ (value >> 31)
pow(2,31) - 1
よりも大きい、または -1 * (pow(2,31) - 1)
よりも小さいパラメータはサポートされていない。
以下の関数は、ParameterInteger
を値にデコードするものである。
value = ((ParameterInteger >> 1) ^ (-(ParameterInteger & 1)))
コマンドの描写を行うための、カーソルの初期位置は (cX、cY)
座標で記述され、 cX
は X 軸上のカーソルの位置であり、cY
は cursor
を Y 軸上に移動させる。
コマンド回数 n
を持つ MoveTo
コマンドは、ParameterInteger
の n
の値の直後に続かなければならない (MUST)。
pX = cX + dX
とpY = cY + dY
で、(pX, pY)
を座標を定義する。- POINT ジオメトリ内のこの座標は新しいポイントを定義する。
- LINESTRING ジオメトリ内のこの座標は新しい行の開始頂点を定義する。
- POLYGON ジオメトリ内のこの座標は新しい線形リングの開始頂点を定義する。
- カーソルを
(pX, pY)
に移動する。
コマンド回数 n
を持つ LineTo
コマンドは、ParameterInteger
の n
の値の直後に続かなければならない (MUST)。
pX = cX + dX
とpY = cY + dY
で、(cX, cY)
で始まり(pX, pY)
で終わるセグメントを定義する。- LINESTRING ジオメトリ内のこのセグメントは現在の行を拡張する。
- POLYGON ジオメトリ内のこのセグメントは現在の linear ring を拡張する。
- カーソルを
(pX, pY)
に移動する。
(dX, dY)
の dX
と dY
のペアは、どちらも 0 であってはならない (MUST NOT)。
ClosePath
コマンドは、パラメータなし及びコマンドカウント 1 を値として持たなくてはならない (MUST)。このコマンドは、カーソル (cX、cY)
で始まり、現在の linear ring の開始頂点で終わる線分を介して POLYGON ジオメトリの現在の線形リングを閉じる。
このコマンドは、カーソル位置を変更しない。
geometry
フィールドは、GeomType
内に存在する値からなる type
にて、各フィーチャーに記述されている。
- UNKNOWN
- POINT
- LINESTRING
- POLYGON
ジオメトリコレクションはサポートされていない。
この仕様では、オプションとして意図的に未知のジオメトリタイプが残されている。このジオメトリタイプは、実験的なジオメトリタイプをエンコーダがエンコードすることもできる。デコーダはこのジオメトリタイプの特徴を無視してもよい (MAY)。
POINT
ジオメトリタイプはポイントまたはマルチポイントジオメトリをエンコードする。 ポイントジオメトリのジオメトリコマンドシーケンスは、コマンドカウントが 0 より大きい単一の MoveTo
コマンドで構成されなければならない (MUST)。
POINT
ジオメトリの MoveTo
コマンドが 1 のコマンドカウントを持つ場合、ジオメトリは単一ポイントとして解釈されなくてはならない (MUST)。 さもなければ、ジオメトリはマルチポイントジオメトリとして解釈されなければならない (MUST)。ここでは、 ParameterInteger
の各ペアは単一のポイントをエンコードする。
LINESTRING
ジオメトリタイプは、linestring または multilinestring ジオメトリをエンコードする。linestring ジオメトリのジオメトリコマンドシーケンスは、次のシーケンスの 1 つ以上の反復で構成されなければならない (MUST):
MoveTo
コマンド及び 1 のコマンドカウントLineTo
コマンド及び 0 よりも大きいコマンドカウント
LINESTRING
ジオメトリタイプのコマンドシーケンスが単一の MoveTo
コマンドのみを含む場合、ジオメトリは単一の linestring として解釈されなければならない (MUST)。それ以外の場合は、ジオメトリを multilinestring ジオメトリとして解釈しなければならない (MUST)。それぞれの MoveTo
は、新しい linestring 開始のきっかけとなる。
POLYGON
ジオメトリタイプは、polygon または multipolygon ジオメトリをエンコードする。それぞれの polygon は、確実に 0 またはそれ以上の内部境界を含む 1 つの外部境界から構成される。Polygon のジオメトリコマンドシーケンスは、次のシーケンスの 1 回以上の繰り返しから構成される。
- 単一の
ExteriorRing
- 0 またはそれ以上の
InteriorRing
それぞれの ExteriorRing
と InteriorRing
は、以下のシーケンスから構成されなければならない。
- 単一の
MoveTo
コマンド及び 1 のコマンドカウント - 単一の
LineTo
コマンド及び 1 以上のコマンドカウント - 単一の
ClosePath
コマンド
外部境界は、linear ring として定義される。この linear ring は、surveyor's formula をタイル座標のポリゴンの頂点に適用することによって計算される正のエリアをもつ。タイル座標系(Y 軸が下向きの正方向、X 軸が右向きの正方向)では、これにより外部境界の線の順序が時計回りになる。
内部境界は、この linear ring は、surveyor's formula をタイル座標のポリゴンの頂点に適用することによって計算される負のエリアをもつ。タイル座標系(Y 軸が下向きの正方向、X 軸が右向きの正方向)では、これにより外部境界の線の順序が反時計回りになる。
POLYGON
ジオメトリタイプのコマンドシーケンスが単一の外部境界のみを含んでいる場合、そのジオメトリは単一のポリゴンとして解釈されなければならない (MUST)。そうでなければ、そのジオメトリは multipolygon ジオメトリとして解釈されなければならない (MUST)。その場合、それぞれの外部境界が出現することがあ新しいポリゴンの開始を意味する。ポリゴンが内部境界を保つ場合、その内部境界はそれが属するポリゴンの外部境界の直後で符号化されなければならない(MUST)。
Linear rings は、self-intersection や self-tangency などの変則なジオメトリックポイントを持たないジオメトリックオブジェクトであるべきである。linear ring の ClosePath
コマンドを呼び出す前のカーソル位置は、長さが 0 にならないようにするために linear ring の最初の点と同じ位置になることはない (SHALL NOT)。
Polygon ジオメトリは、交差する内部境界を持ってはならない (MUST NOT)。内部境界を外部境界で囲まなければならない (MUST)。
Point のエンコーディングの例:
- (25,17)
これは以下の単一のコマンドを必要とする:
- MoveTo(+25, +17)
Encoded as: [ 9 50 34 ]
| | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +17
| `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +25
| ===== relative MoveTo(+25, +17) == create point (25,17)
`> [00001 001] = command id 1 (MoveTo), command count 1
2つのポイントのエンコーディングの例:
- (5,7)
- (3,2)
これは2つのコマンドを必要とする:
- MoveTo(+5,+7)
- MoveTo(-2,-5)
Encoded as: [ 17 10 14 3 9 ]
| | | | `> Decoded: ((9 >> 1) ^ (-(9 & 1))) = -5
| | | `> Decoded: ((3 >> 1) ^ (-(3 & 1))) = -2
| | | === relative MoveTo(-2, -5) == create point (3,2)
| | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +7
| `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +5
| ===== relative MoveTo(+25, +17) == create point (25,17)
`> [00010 001] = command id 1 (MoveTo), command count 2
点による線のエンコーディングの例:
- (2,2)
- (2,10)
- (10,10)
これは3つのコマンドを必要とする:
- MoveTo(+2,+2)
- LineTo(+0,+8)
- LineTo(+8,+0)
Encoded as: [ 9 4 4 18 0 16 16 0 ]
| | ==== relative LineTo(+8, +0) == Line to Point (10, 10)
| | ==== relative LineTo(+0, +8) == Line to Point (2, 10)
| `> [00010 010] = command id 2 (LineTo), command count 2
| === relative MoveTo(+2, +2)
`> [00001 001] = command id 1 (MoveTo), command count 1
点による2本の線のエンコーディングの例:
- 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)
Encoded as: [ 9 4 4 18 0 16 16 0 9 17 17 10 4 8 ]
| | | | === relative LineTo(+2, +4) == Line to Point (3,5)
| | | `> [00001 010] = command id 2 (LineTo), command count 1
| | | ===== relative MoveTo(-9, -9) == Start new line at (1,1)
| | `> [00001 001] = command id 1 (MoveTo), command count 1
| | ==== relative LineTo(+8, +0) == Line to Point (10, 10)
| | ==== relative LineTo(+0, +8) == Line to Point (2, 10)
| `> [00010 010] = command id 2 (LineTo), command count 2
| === relative MoveTo(+2, +2)
`> [00001 001] = command id 1 (MoveTo), command count 1
複数の点をもつポリゴンをエンコーディングする例:
- (3,6)
- (8,12)
- (20,34)
- (3,6) Path Closing as Last Point
これは以下のコマンドでエンコードされる:
- MoveTo(3, 6)
- LineTo(5, 6)
- LineTo(12, 22)
- ClosePath
Encoded as: [ 9 6 12 18 10 12 24 44 15 ]
| | `> [00001 111] command id 7 (ClosePath), command count 1
| | ===== relative LineTo(+12, +22) == Line to Point (20, 34)
| | ===== relative LineTo(+5, +6) == Line to Point (8, 12)
| `> [00010 010] = command id 2 (LineTo), command count 2
| ==== relative MoveTo(+3, +6)
`> [00001 001] = command id 1 (MoveTo), command count 1
2つのポリゴンを使用したより複雑なエンコーディングの例で一つは穴が開いている。ポリゴンの点の位置は以下のとおりである。この例では内部境界と新しいポリゴンの違いを表すためにポリゴンの巻き順が重要である。
- Polygon 1:
- Exterior Ring:
- (0,0)
- (10,0)
- (10,10)
- (0,10)
- (0,0) Path Closing as Last Point
- Exterior Ring:
- Polygon 2:
- Exterior Ring:
- (11,11)
- (20,11)
- (20,20)
- (11,20)
- (11,11) Path Closing as Last Point
- Interior Ring:
- (13,13)
- (13,17)
- (17,17)
- (17,13)
- (13,13) Path Closing as Last Point
- Exterior Ring:
このポリゴンは以下のコマンドの組み合わせによってエンコードされる。
- MoveTo(+0,+0)
- LineTo(+10,+0)
- LineTo(+0,+10)
- LineTo(-10,+0) // Cursor at 0,10 after this command
- ClosePath // End of Polygon 1
- MoveTo(+11,+1) // NOTE THAT THIS IS RELATIVE TO LAST LINETO!
- LineTo(+9,+0)
- LineTo(+0,+9)
- LineTo(-9,+0) // Cursor at 11,20 after this command
- ClosePath // This is a new polygon because area is positive!
- MoveTo(+2,-7) // NOTE THAT THIS IS RELATIVE TO LAST LINETO!
- LineTo(+0,+4)
- LineTo(+4,+0)
- LineTo(+0,-4) // Cursor at 17,13
- ClosePath // This is an interior ring because area is negative!
地物の属性は、地物の tag
フィールド内の数字のペアによってエンコードされる。各ペアの最初の整数は地物が属する layer
の keys
セットのキーの 0 から始まるインデックスを表す。各ペアの第二の整数は、地物が属する layer
の values
セット内の 0 から始まるインデックスを表す。すべてのキーインデックスは、その地物内の他の属性のペアが同じキーインデックスを持たないように、その地物内で一意でなければならない。地物は偶数の tag
フィールドを持たなければならない (MUST)。地物の tag
フィールドはレイヤーの keys
または values
セットの要素の数以上のキーインデックスまたは値インデックスを含んではならない (MUST NOT)。
たとえば以下のような 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
}
ジオメトリの正確な値は、タイルの投影法および領域によって異なる。