Skip to content

Latest commit

 

History

History
889 lines (656 loc) · 42.9 KB

README.md

File metadata and controls

889 lines (656 loc) · 42.9 KB

ベクトルタイル仕様書

このドキュメントに記載されている単語 "しなければならない (MUST)"、"してはならない (MUST NOT)"、"要求されている (REQUIRED)"、"することになる (SHALL)"、"することはない (SHALL NOT)"、"する必要がある (SHOULD)"、"しないほうがよい (SHOULD NOT)"、"推奨される (RECOMMENDED)"、"してもよい (MAY)"、"選択できる (OPTIONAL)" は、 RFC 2119 に記述されているとおりに解釈されるものとする。

1. 目的

このドキュメントでは、タイル化された地理的ベクトルデータの容量効率のよい符号化フォーマットの仕様を策定する。この仕様は高速なレンダリングや地物データ検索をブラウザ及びサーバーサイドアプリケーションで実現するために設計されている。

2. ファイルフォーマット

このベクトルタイルフォーマットは、Google Protocol Buffers を符号化フォーマットとして使用する。 Protocol Buffers は、構造化されたデータを格納するための特定の言語やプラットフォームに依存しない拡張可能な仕組みである。

2.1. ファイルの拡張子

ベクトルタイルファイルの拡張子は mvt にする必要がある (SHOULD)。たとえば、あるファイルは vector.mvt となるであろう。

2.2. MIME タイプ (MIME)

ベクトルタイルを配信する際の MIME タイプは application/vnd.mapbox-vector-tile とするべきである (SHOULD)。

3. 投影法及び領域

ベクトルタイルは特定の投影法のもとでの四角い領域のデータを表現する。ベクトルタイルには、その領域や投影法に関する情報を含めないほうがよい (SHOULD NOT)。このファイル形式は、デコーダーがこれを復号化する前に領域や投影法を知っていることを前提としている。

Web メルカトル は基準となる投影法であり、the Google tile scheme は基準となるタイル領域の慣例である。これらは、特定の詳細レベルにおける特定の地理的領域と https://example.com/17/65535/43602.mvt のようなパスを 1:1 で紐付ける。

ベクトルタイルは、どのような投影法やタイル領域のスキームを用いた地理データの表現にも使用してもよい (MAY)。

4. 内部構造

この仕様書では、ベクトルタイル内のデータ構造について明らかにする。読者は Vector Tile protobuf schema document と、それが定義する構造について理解している必要がある。

4.1. レイヤー

ベクトルタイルは、名前付きのレイヤーのセットで構成されている。レイヤーは幾何属性のある地物とそのメタデータを含んでいる。レイヤのフォーマットは、ひとつのレイヤに必要なデータが記憶領域内で接するように設計されている。このようにすることによって、既存のデータを変更することなく、レイヤがベクトルタイルに追加できる。

ベクトルタイルは少なくともひとつのレイヤーを含む必要がある。レイヤーは少なくとも1つの地物を含むべきである。

レイヤーは、そのレイヤーが準拠するベクトルタイル仕様書と同じメジャーバージョン番号を持つ version フィールドを含んでいなければならない (MUST)。たとえば、あるレイヤーがバージョン 2.1 に準拠しているのであれば、整数の 2version フィールドとして含めるべきである。version フィールドは、そのレイヤーの最初のフィールドである必要がある (SHOULD)。デコーダーは、各レイヤーを確実に処理するために、まず version をパースする必要がある (SHOULD)。ベクトルタイルのコンシューマーが未知のバージョンのベクトルタイルに遭遇した場合、レイヤーを解釈するために最善の努力をするか、そのレイヤーをスキップしてもよい (MAY)。どちらの場合も、そのベクトルタイル内の後続のレイヤーの処理を続ける必要がある (SHOULD)。

レイヤーは name フィールドを含んでいなければならない (MUST)。ベクトルタイルは、同じ値 (byte-for-byte) を名前に持つ2つ以上のレイヤーを含んではならない (MUST NOT)。エンコーダーは、既存のベクトルタイルにレイヤーを追加する前に、重複を防止するために既存の name フィールドをチェックしなければならない (MUST)。

レイヤー内の地物(以下を参照)は一つまたは複数のキーと値のペアをメタデータとして保持してもよい (MAY)。キーと値は keysvalues という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) のポイントはタイルの領域外にある。

4.2. 地物

地物は、geometry フィールドを含まなければならない (MUST)。

地物は、Geometry 型セクションで説明している type フィールドを含まなければならない (MUST)。

地物は、tags フィールドを含むことができる (MAY)。地物固有のメタデータがもしあれば、tags フィールドに保存されるべきである (SHOULD)。

地物は、id フィールドを含むことができる (MAY)。もし地物が id フィールドを持っている場合、id フィールドの値は、親レイヤーの中で地物ごとにユニークであるべきである (SHOULD)。

4.3. ジオメトリエンコーディング

ベクトルタイル内のジオメトリデータは、スクリーンの座標システムで定義される。(デフォルトで表示される)タイルの最も左上は、座標システムの原点である。X 座標は右に正であり、Y 座標は下に正である。ジオメトリ内の座標は整数でなければならない (MUST)。

ジオメトリは、地物の geometry フィールド内に、32 bit 符号なし整数のシーケンスとしてエンコードされる。各整数は、CommandIntegerParameterInteger である。デコーダはこれらをジオメトリを生成するために順番に処理するものとして解釈する。

コマンドは、"カーソル"位置を再定義可能な点である相対的な位置で参照する。地物の最初のコマンドでは、カーソルは座標システムでの (0,0) にある。一部のコマンドはカーソルを移動し、その後のコマンドに影響を与える。

4.3.1. Command Integers

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 Integers の例
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]

4.3.2. 数値パラメーター

パラメータを必要とするコマンドの後には、そのコマンドで必要とされる各パラメータのための 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)))

4.3.3. コマンドタイプ

コマンドの描写を行うための、カーソルの初期位置は (cX、cY) 座標で記述され、 cX は X 軸上のカーソルの位置であり、cYcursor を Y 軸上に移動させる。

4.3.3.1. MoveTo コマンド

コマンド回数 n を持つ MoveTo コマンドは、ParameterIntegern の値の直後に続かなければならない (MUST)。

  1. pX = cX + dXpY = cY + dY で、(pX, pY) を座標を定義する。
    • POINT ジオメトリ内のこの座標は新しいポイントを定義する。
    • LINESTRING ジオメトリ内のこの座標は新しい行の開始頂点を定義する。
    • POLYGON ジオメトリ内のこの座標は新しい線形リングの開始頂点を定義する。
  2. カーソルを (pX, pY) に移動する。
4.3.3.2. LineTo コマンド

コマンド回数 n を持つ LineTo コマンドは、ParameterIntegern の値の直後に続かなければならない (MUST)。

  1. pX = cX + dXpY = cY + dY で、(cX, cY) で始まり (pX, pY) で終わるセグメントを定義する。
    • LINESTRING ジオメトリ内のこのセグメントは現在の行を拡張する。
    • POLYGON ジオメトリ内のこのセグメントは現在の linear ring を拡張する。
  2. カーソルを (pX, pY) に移動する。

(dX, dY)dXdY のペアは、どちらも 0 であってはならない (MUST NOT)。

4.3.3.3. ClosePath コマンド

ClosePath コマンドは、パラメータなし及びコマンドカウント 1 を値として持たなくてはならない (MUST)。このコマンドは、カーソル (cX、cY)で始まり、現在の linear ring の開始頂点で終わる線分を介して POLYGON ジオメトリの現在の線形リングを閉じる。

このコマンドは、カーソル位置を変更しない。

4.3.4. ジオメトリタイプ

geometry フィールドは、GeomType 内に存在する値からなる type にて、各フィーチャーに記述されている。

  • UNKNOWN
  • POINT
  • LINESTRING
  • POLYGON

ジオメトリコレクションはサポートされていない。

4.3.4.1. 未知のジオメトリタイプ

この仕様では、オプションとして意図的に未知のジオメトリタイプが残されている。このジオメトリタイプは、実験的なジオメトリタイプをエンコーダがエンコードすることもできる。デコーダはこのジオメトリタイプの特徴を無視してもよい (MAY)。

4.3.4.2. Point ジオメトリタイプ

POINTジオメトリタイプはポイントまたはマルチポイントジオメトリをエンコードする。 ポイントジオメトリのジオメトリコマンドシーケンスは、コマンドカウントが 0 より大きい単一の MoveTo コマンドで構成されなければならない (MUST)。

POINT ジオメトリの MoveTo コマンドが 1 のコマンドカウントを持つ場合、ジオメトリは単一ポイントとして解釈されなくてはならない (MUST)。 さもなければ、ジオメトリはマルチポイントジオメトリとして解釈されなければならない (MUST)。ここでは、 ParameterInteger の各ペアは単一のポイントをエンコードする。

4.3.4.3. Linestring ジオメトリ

LINESTRING ジオメトリタイプは、linestring または multilinestring ジオメトリをエンコードする。linestring ジオメトリのジオメトリコマンドシーケンスは、次のシーケンスの 1 つ以上の反復で構成されなければならない (MUST):

  1. MoveTo コマンド及び 1 のコマンドカウント
  2. LineTo コマンド及び 0 よりも大きいコマンドカウント

LINESTRING ジオメトリタイプのコマンドシーケンスが単一の MoveTo コマンドのみを含む場合、ジオメトリは単一の linestring として解釈されなければならない (MUST)。それ以外の場合は、ジオメトリを multilinestring ジオメトリとして解釈しなければならない (MUST)。それぞれの MoveTo は、新しい linestring 開始のきっかけとなる。

4.3.4.4. Polygon ジオメトリタイプ

POLYGON ジオメトリタイプは、polygon または multipolygon ジオメトリをエンコードする。それぞれの polygon は、確実に 0 またはそれ以上の内部境界を含む 1 つの外部境界から構成される。Polygon のジオメトリコマンドシーケンスは、次のシーケンスの 1 回以上の繰り返しから構成される。

  1. 単一の ExteriorRing
  2. 0 またはそれ以上の InteriorRing

それぞれの ExteriorRingInteriorRing は、以下のシーケンスから構成されなければならない。

  1. 単一の MoveTo コマンド及び 1 のコマンドカウント
  2. 単一の LineTo コマンド及び 1 以上のコマンドカウント
  3. 単一の 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)。

4.3.5. ジオメトリエンコーディングの例

4.3.5.1. Point の例

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
4.3.5.2. マルチポイントの例

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
4.3.5.3. Linestring の例

点による線のエンコーディングの例:

  • (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
4.3.5.4. Multi Linestring の例

点による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
4.3.5.5. ポリゴンの例

複数の点をもつポリゴンをエンコーディングする例:

  • (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
4.3.5.6. マルチポリゴンの例

2つのポリゴンを使用したより複雑なエンコーディングの例で一つは穴が開いている。ポリゴンの点の位置は以下のとおりである。この例では内部境界と新しいポリゴンの違いを表すためにポリゴンの巻き順が重要である。

  • Polygon 1:
    • Exterior Ring:
      • (0,0)
      • (10,0)
      • (10,10)
      • (0,10)
      • (0,0) Path Closing as Last Point
  • 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

このポリゴンは以下のコマンドの組み合わせによってエンコードされる。

  • 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!

4.4. 地物の属性

地物の属性は、地物の tag フィールド内の数字のペアによってエンコードされる。各ペアの最初の整数は地物が属する layerkeys セットのキーの 0 から始まるインデックスを表す。各ペアの第二の整数は、地物が属する layervalues セット内の 0 から始まるインデックスを表す。すべてのキーインデックスは、その地物内の他の属性のペアが同じキーインデックスを持たないように、その地物内で一意でなければならない。地物は偶数の tag フィールドを持たなければならない (MUST)。地物の tag フィールドはレイヤーの keys または values セットの要素の数以上のキーインデックスまたは値インデックスを含んではならない (MUST NOT)。

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
}

ジオメトリの正確な値は、タイルの投影法および領域によって異なる。