ガイドAPIリファレンス
ガイド

ベクタータイルスキーマ - HERE Traffic Vector Tile API

このドキュメント(英語版)のキーワード「MUST (すべき)」、「MUST NOT (すべきでない)」、「REQUIRED (必須)」、「SHALL (するものとする)」、「SHALL NOT (しないものとする)」、「SHOULD (する必要がある)」、「SHOULD NOT (しないようにする)」、「RECOMMENDED (推奨)」、「MAY (場合がある)」、「OPTIONAL (任意)」は、RFC 2119の記述に従って解釈されます。

ファイル形式

ベクタータイル形式では、エンコード形式としてGoogle Protocol Buffersが使用されます。プロトコルバッファは、言語に依存しない、プラットフォームに依存しない拡張メカニズムで、構造化されたデータをシリアル化します。

図法と境界

ベクタータイルは図法内の正方形の範囲に基づいてデータを表します。ベクタータイルには、その境界および投影法に関する情報を含めることはできません。ファイル形式は、デコード前にデコーダーがベクタータイルの境界と図法を把握している前提で動作します。

Webメルカトルは基準となる図法であり、Googleタイルスキームはタイル範囲の基準となる規則です。これらを組み合わせることで、特定の地理的エリアが1対1で関連付けられ、特定レベルの詳細と、パス (https://example.com/17/65535/43602.mvtなど) が提供されます。

ベクタータイルは、あらゆる図法およびタイル範囲スキームでデータを表すために使用できます。

内部構造

このドキュメントではベクタータイル内のデータの構造について説明します。読者はベクタータイルのProtobufスキーマのドキュメントとそれが定義する構造を理解しておく必要があります。

レイヤー

ベクタータイルは、一連の名前付きレイヤーで構成されます。レイヤーには、ジオメトリーフィーチャーとそのメタデータが含まれます。レイヤー形式のデザインは、レイヤーに必要なデータがメモリ内で連続するようにするためのものであり、既存のデータを変更することなくレイヤーをベクタータイルに追加できるようになっています。

ベクタータイルには1つ以上のレイヤーを含めてください。レイヤーには1つ以上のフィーチャーを含めてください。

レイヤーには、レイヤーが準拠するベクタータイルの仕様のメジャーバージョン番号を持つversionフィールドを含める必要があります。たとえば、バージョン2.1の仕様に準拠するレイヤーには、2の整数値を持つversionフィールドを含めます。versionフィールドはレイヤー内の最初のフィールドにしてください。デコーダーは最初にversionを解析して、各レイヤーをデコードできることを確認します。ベクタータイルコンシューマが不明なバージョンのベクタータイルレイヤーに遭遇すると、そのレイヤーを解釈するために最善の努力が行われる場合もあれば、レイヤーがスキップされる場合もあります。どちらの場合もベクタータイル内の後続レイヤーの処理を継続する必要があります。

レイヤーにはnameフィールドを含めなければなりません。ベクタータイルには、name値がバイト単位で同一のレイヤーを2つ以上含めることはできません。重複を防ぐために、レイヤーを既存のベクタータイルに追加する前に、エンコーダーで既存のnameフィールドを確認する必要があります。

レイヤー内の各フィーチャーには、メタデータとしてキーと値のペアが1つ以上含まれる場合があります。キーと値はkeysおよびvaluesの2つのリストに分けられたインデックスであり、レイヤーのフィーチャー間で共有されます。

レイヤーの keys フィールドの各要素は文字列です。keys にはレイヤーで使用されるフィーチャーのすべてのキーが含まれます。各キーはこの一連の keys の位置インデックスを使用して参照される場合があります。最初のキーのインデックスは 0 になります。一連の keys には、バイト単位で同一の値を 2 つ以上含めないようにしてください。

レイヤーの values フィールドの各要素は、いくつかのタイプの値をエンコードします (以下を参照)。values はレイヤーで使用されるフィーチャーのすべての値を表します。各値はこの一連の values の位置インデックスを使用して参照される場合があります。最初の値のインデックスは 0 になります。一連の values には、バイト単位で同一の、タイプが同じ値を 2 つ以上含めないようにしてください。

文字列、ブール値、整数、浮動小数点といったさまざまな型の値をサポートするために、value フィールドの Protobuf エンコーディングは、一連の optional フィールドで構成されます。値にはこれらの任意のフィールドのいずれかのみを含める必要があります。

レイヤーにはタイルの幅と高さを整数の座標で表す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) のポイントはタイルの範囲外です。

フィーチャー

フィーチャーにはgeometryフィールドを含める必要があります。

フィーチャーには、「ジオメトリータイプ」セクションで説明するtypeフィールドを含める必要があります。

フィーチャーには tags フィールドが含まれる場合があります。フィーチャー レベルのメタデータがある場合は、tags フィールドに格納してください。

フィーチャーには id フィールドが含まれる場合があります。フィーチャーにidフィールドがある場合、idの値は親レイヤーのフィーチャー間で一意となるようにします。

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

ベクタータイルのジオメトリーデータは、画面の座標系で定義されます。タイルの左上隅 (デフォルトで表示) が座標系の原点です。X軸は右側が正、Y軸は下側が正です。ジオメトリー内の座標は整数である必要があります。

ジオメトリーは、フィーチャーのgeometryフィールドで、32ビットの符号なし整数のシーケンスとしてエンコードされます。それぞれの整数は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は、次のいずれかのコマンドを指定します。

コマンドIdパラメーターパラメーター数
MoveTo1dXdY2
LineTo2dXdY2
ClosePath7パラメーターなし0
コマンドの整数の例
コマンドIDCommandIntegerバイナリ表現 [Count][Id]
MoveTo119[00000000 00000000 0000000 00001][001]
MoveTo1120961[00000000 00000000 0000011 11000][001]
LineTo2110[00000000 00000000 0000000 00001][010]
LineTo2326[00000000 00000000 0000000 00011][010]
ClosePath7115[00000000 00000000 0000000 00001][111]

パラメーターの整数

パラメーターを必要とするコマンドの後に、必須パラメーターごとにParameterIntegerが続きます。CommandIntegerの後に続くParameterIntegersの数は、コマンドのパラメーター数にCommandIntegerのコマンド数をかけた値になります。たとえば、コマンド数が3のMoveToコマンドを伴うCommandIntegerの後には、6個のParameterIntegersが続きます。

小さい負の値と正の値が両方とも小さい整数としてエンコードされるように、ParameterIntegerジグザグにエンコードされます。パラメーター値を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はY軸上のcursorの位置になります。

MoveToコマンド

コマンド数 nMoveTo コマンドの直後には、n ペアの ParameterInteger を続ける必要があります。各ペア (dX, dY) は、次を行います。

  1. 座標(pX, pY)を定義します。ここでは、pX = cX + dXpY = cY + dY となります。
    • POINTジオメトリーでは、この座標によって新しい点が定義されます。
    • LINESTRINGジオメトリーでは、この座標によって新しい直線の開始頂点が定義されます。
    • POLYGONジオメトリーでは、この座標によって新しい線形リングの開始頂点が定義されます。
  2. カーソルを(pX, pY)に移動します。
LineTo コマンド

コマンド数 nLineTo コマンドの直後には、n ペアの ParameterInteger を続ける必要があります。各ペア (dX, dY) は、次を行います。

  1. カーソル (cX, cY) で始まり、座標 (pX, pY) で終わるセグメントを定義します。ここでは、pX = cX + dXpY = cY + dY となります。
    • LINESTRING ジオメトリーでは、このセグメントによって現在のラインが延長されます。
    • POLYGONジオメトリーでは、このセグメントによって現在の線形リングが延長されます。
  2. カーソルを(pX, pY)に移動します。

(dX, dY)の任意のペアについて、dXdYを両方とも0にすることはできません。

ClosePath コマンド

ClosePath コマンドのコマンド数は 1 であり、パラメーターを持つことはできません。このコマンドは、カーソル (cX, cY) の位置から現在の線形リングの開始頂点で終わる線分を介して、POLYGON ジオメトリーの現在の線形リングを閉じます。

このコマンドによってカーソルの位置が変更されることはありません。

ジオメトリータイプ

各フィーチャーのgeometryフィールドはtypeフィールドによって記述します。このフィールドは列挙型 (enum) GeomTypeの値にする必要があります。次のジオメトリータイプがサポートされています。

  • UNKNOWN
  • POINT
  • LINESTRING
  • POLYGON

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

不明なジオメトリータイプ

仕様では意図的に不明なジオメトリー タイプがオプションとして残されています。このジオメトリー タイプは、エンコーダーで実装を選択できる実験的なジオメトリー タイプをエンコードします。デコーダーによっては、このジオメトリー タイプのフィーチャーがすべて無視される場合があります。

ポイント ジオメトリー タイプ

POINT ジオメトリー タイプは、ポイントまたはマルチポイント ジオメトリーをエンコードします。ポイントジオメトリーのジオメトリーコマンドシーケンスは、0より大きいコマンド数を持つ単一のMoveToコマンドで構成されている必要があります。

POINTジオメトリーに対するMoveToコマンドのコマンド数が1の場合、そのジオメトリーをシングルポイントとして解釈する必要があります。1以外の場合は、ジオメトリーはマルチポイントジオメトリーとして解釈され、ParameterIntegerの各ペアがシングルポイントをエンコードします。

LineStringジオメトリータイプ

LINESTRING ジオメトリー タイプは、LineString ジオメトリーまたは MultilineString ジオメトリーをエンコードします。LineString ジオメトリーのジオメトリー コマンド シーケンスは、次のシーケンスの 1 つ以上の繰り返しで構成される必要があります。

  1. コマンド数が1のMoveToコマンド
  2. コマンド数が0より大きいLineToコマンド

LINESTRINGジオメトリータイプのコマンドシーケンスに単一のMoveToコマンドのみが含まれている場合は、ジオメトリーを単一のLineStringとして解釈する必要があります。複数含まれている場合は、ジオメトリーをMultilineStringジオメトリーとして解釈する必要があります。それぞれのMoveToは、新しいLineStringの開始を示します。

ポリゴンジオメトリータイプ

POLYGONジオメトリータイプは、ポリゴンまたはマルチポリゴンのジオメトリーをエンコードします。各ポリゴンは、0個以上の内部リングを含む1つの外部リングのみで構成されます。ポリゴンのジオメトリーコマンドシーケンスは、次のシーケンスの1つ以上の繰り返しで構成されます。

  1. 1 つの ExteriorRing
  2. ゼロ個以上のInteriorRing

ExteriorRingおよびInteriorRingは、次のシーケンスで構成されている必要があります。

  1. コマンド数が1のMoveToコマンド
  2. コマンド数が1より大きいLineToコマンド
  3. ClosePath コマンド

外部リングは、タイル座標のポリゴンの頂点に座標法を適用して計算された、正の領域を持つ線形リングとして定義されます。タイル座標系では (Y 軸は下が正、X 軸は右が正)、外部リングの屈曲の順序が時計回りになります。

内部リングは、タイル座標のポリゴンの頂点に座標法を適用して計算された、負の領域を持つ線形リングとして定義されます。タイル座標系では (Y軸は下が正、X軸は右が正)、内側のリングの屈曲の順序が反時計回りになります。

POLYGONジオメトリータイプのコマンドシーケンスに単一の外部リングのみが含まれている場合は、ジオメトリーをシングルポリゴンとして解釈する必要があります。複数含まれている場合は、ジオメトリーはマルチポイントジオメトリーとして解釈され、それぞれの外部リングは新しいポリゴンの開始を示します。ポリゴンに内部リングがある場合は、その内部リングが属するポリゴンの外部リングの直後にエンコードする必要があります。

線形リングは、自己交差や自己接線などの異常なジオメトリーポイントを持たないジオメトリーオブジェクトである必要があります。線形リングのClosePathコマンドを呼び出す前のカーソルの位置は、線形リングの最初の点と同じ位置にしてはなりません。このようにすると、長さ0の線分が作成されます。異常なジオメトリーポイントを持つリングを意味することになるため、線形リングでは、座標法で算出される領域が0にならないようにしてください。

ポリゴン ジオメトリーには、交差する内部リングがないようにし、また、内部リングは外部リングで囲む必要があります。

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

ポイントの例

次の場所にあるポイントのエンコード例:

  • (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(+5, +7) == create point (5,7)
               `> [00010 001] = command id 1 (MoveTo), command count 2
LineString の例

ポイントを持つ1つのラインのエンコード例:

  • (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
複数の LineString の例

ポイントを持つ2つのラインのエンコード例:

  • ライン 1:
    • (2,2)
    • (2,10)
    • (10,10)
  • ライン 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) 最終ポイントとしてのパスの終了

次のコマンドを使用してエンコードされます。

  • 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つのポリゴンのより複雑なエンコーディングの例。一方には穴があります。ポリゴンのポイントの位置を以下に示します。この例では、内部リングと新しいポリゴンの違いを示すため、ポリゴンの屈曲の順序が非常に重要です。

  • ポリゴン1:
    • 外部リング:
      • (0,0)
      • (10,0)
      • (10,10)
      • (0,10)
      • (0,0) 最終ポイントとしてのパスの終了
  • ポリゴン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 // ポリゴン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 // 領域が負であるため、これは内部リングです!
Encoded as: [ 9 0 0 26 20 0 0 20 19 0 15 9 22 2 26 18 0 0 18 17 0 15 9 4 13 26 0 8 8 0 0 7 15 ]
              |      |                |  |       |                |  |       |              `> [00001 111] (ClosePath)
              |      |                |  |       |                |  |       `> [00011 010] = (LineTo), command count 3
              |      |                |  |       |                |  `> [00001 001] = command id 1 (MoveTo), command count 1
              |      |                |  |       |                `> [00001 111] (ClosePath)
              |      |                |  |       `> [00011 010] = (LineTo), command count 3
              |      |                | `> [00001 001] = command id 1 (MoveTo), command count 1
              |      |                `> [00001 111] (ClosePath)
              |      `> [00011 010] = (LineTo), command count 3
              `> [00001 001] = command id 1 (MoveTo), command count 1

4.4.フィーチャーの属性

フィーチャーの属性は、整数のペアとしてフィーチャーの tag フィールドにエンコードされます。各ペアの最初の整数は、そのフィーチャーが属する layerkeys セットのゼロから始まるインデックスを表します。各ペアの 2 番目の整数は、フィーチャーが属する layervalues セットの値のゼロから始まるインデックスを表します。そのフィーチャー内の他の属性ペアが同じキー インデックスを持たないようにするために、すべてのキー インデックスはそのフィーチャー内で一意である必要があります。フィーチャーには偶数の tag フィールドが必要です。フィーチャーの tag フィールドには、それぞれレイヤーの keys セットまたは values セットの要素の数以上のキー インデックスまたは値インデックスを含めてはなりません。

たとえば、次のような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
}

ジオメトリーの正確な値はタイルの図法と範囲によって異なります。