Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.0.2 draft #36

Closed
wants to merge 11 commits into from
87 changes: 87 additions & 0 deletions 1.0.2-draft/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# vector-tile-spec

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in
this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).

## 1. Purpose

This specification attempts to create a standard for encoding of tiled geospatial data that can be shared across clients.

## 2. File format

The vector tile encoding scheme encodes vector data for a tile in a space efficient manner. It is designed to be used in browsers or serverside applications for fast rendering or lookups of feature data.

Vector Tiles use [Google Protocol buffers](https://developers.google.com/protocol-buffers/) as a container format. It is exclusively geared towards square pixel tiles in [Spherical Mercator projection](http://wiki.openstreetmap.org/wiki/Mercator).

## 3. Internal structure

A vector tile can consist of one or more named layers and containing one or more features.

Features contain an id, attributes, geometries (either point, linestring, or polygon) and an optional raster. It is expected that that either the `raster` field is set or the `geometry` field has repeated data, but not both.

### 3.1. Geometry Encoding

Geometries are stored as an a single array of integers that represent an command,x,y stream (where command is a rendering command like `move_to` or `line_to`). Commands are encoded only when they change.

Geometries with multiple parts (multipoint, multiline, or multipolygon) should be encoded one after another in the same `geometry` field and therefore are "flattened". Geometries with only a single part will have only a single `move_to` present. For multipoints and multilines a repeated `move_to` will indicate another part of a multipart geometry. For polygons a repeated `move_to` will indicate either either another exterior of a new polygon part or an interior ring of of the previous polygon part. The winding order should be used to distinguish between the two types: polygon interior rings (holes) must be oriented with the opposite winding order than their parent exterior rings and all interior rings must directly follow the exterior ring they belong to.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For polygons a repeated move_to will indicate either either another exterior of a new polygon part or an interior ring of of the previous polygon part.

In the fourth sentence, should either either and of of just be one either and one of?


The exterior ring shall have a positive area as calculated by applying the [surveyor's formula](https://en.wikipedia.org/wiki/Shoelace_formula) to the vertices of the polygon in tile coordinates. In screen coordinates (with the Y axis positive down) this makes the exterior ring's winding order appear clockwise. In a frame where the Y axis is positive up, this would make the winding order appear counter clockwise.

Geometry collections are not supported.

Geometries should be clipped, reprojected into spherical mercator, converted to screen coordinates, and [delta](http://en.wikipedia.org/wiki/Delta_encoding) and [zigzag](https://developers.google.com/protocol-buffers/docs/encoding#types) encoded.

### 3.2. Feature Attributes

Feature attributes are encoded as key:value pairs which are dictionary encoded at the layer level for compact storage of any repeated keys or values. Values use [variant](https://developers.google.com/protocol-buffers/docs/encoding#varints) type encoding supporting both unicode strings, boolean values, and various integer and floating point types.

### 3.3. Example

For example, a GeoJSON feature like:

```json
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
-8247861.1000836585,
4970241.327215323
]
},
"type": "Feature",
"properties": {
"hello": "world"
}
}
]
}
```

Would be structured like:

```js
layers {
name: "points"
features {
id: 1
tags: 0
tags: 0
type: Point
geometry: 9
geometry: 2410
geometry: 3080
}
keys: "hello"
values {
string_value: "world"
}
extent: 4096
version: 2
}
```

The complete and authoritative details on encoding are part of the code comments for the [vector tile protobuf schema document](vector_tile.proto).
102 changes: 102 additions & 0 deletions 1.0.2-draft/vector_tile.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Protocol Version 1

package vector_tile;

option optimize_for = LITE_RUNTIME;

message Tile {
enum GeomType {
UNKNOWN = 0;
POINT = 1;
LINESTRING = 2;
POLYGON = 3;
}

// Variant type encoding
message Value {
// Exactly one of these values may be present in a valid message
optional string string_value = 1;
optional float float_value = 2;
optional double double_value = 3;
optional int64 int_value = 4;
optional uint64 uint_value = 5;
optional sint64 sint_value = 6;
optional bool bool_value = 7;

extensions 8 to max;
}

message Feature {
optional uint64 id = 1 [ default = 0 ];

// Tags of this feature are encoded as repeated pairs of
// integers. Even indexed values (n, beginning with 0) are
// themselves indexes into the layer's keys list. Odd indexed
// values (n+1) are indexes into the layer's values list.
// The first (n=0) tag of a feature, therefore, has a key of
// layer.keys[feature.tags[0]] and a value of
// layer.values[feature.tags[1]].
repeated uint32 tags = 2 [ packed = true ];

// The type of geometry stored in this feature.
optional GeomType type = 3 [ default = UNKNOWN ];

// Contains a stream of commands and parameters (vertices). The
// repeat count is shifted to the left by 3 bits. This means
// that the command has 3 bits (0-7). The repeat count
// indicates how often this command is to be repeated. Defined
// commands are:
// - MoveTo: 1 (2 parameters follow)
// - LineTo: 2 (2 parameters follow)
// - ClosePath: 7 (no parameters follow)
//
// Commands are encoded as uint32 varints. Vertex parameters
// are encoded as deltas to the previous position and, as they
// may be negative, are further "zigzag" encoded as unsigned
// 32-bit ints:
//
// n = (n << 1) ^ (n >> 31)
//
// Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath
// Encoded as: [ 9 6 12 18 10 12 24 44 15 ]
// | | `> [00001 111] command type 7 (ClosePath), length 1
// | | ===== relative LineTo(+12, +22) == LineTo(20, 34)
// | | ===== relative LineTo(+5, +6) == LineTo(8, 12)
// | `> [00010 010] = command type 2 (LineTo), length 2
// | ==== relative MoveTo(+3, +6)
// `> [00001 001] = command type 1 (MoveTo), length 1
//
// The original position is (0,0).
repeated uint32 geometry = 4 [ packed = true ];

optional bytes raster = 5;
}

message Layer {
// Any compliant implementation must first read the version
// number encoded in this message and choose the correct
// implementation for this version number before proceeding to
// decode other parts of this message.
required uint32 version = 15 [ default = 1 ];

required string name = 1;

// The actual features in this tile.
repeated Feature features = 2;

// Dictionary encoding for keys
repeated string keys = 3;

// Dictionary encoding for values
repeated Value values = 4;

// The bounding box in this tile spans from 0..4095 units
optional uint32 extent = 5 [ default = 4096 ];

extensions 16 to max;
}

repeated Layer layers = 3;

extensions 16 to 8191;
}
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Vector Tile Spec Changelog

### 1.0.2-draft

- Clarification of how polygon exterior and interior rings should be oriented and ordered: If present, any polygon interior rings (holes) must be oriented with the opposite winding order than their parent exterior rings and all interior rings must directly follow the exterior ring they belong too. Exterior rings must be oriented CCW and interior rings must be oriented CW (when viewed from the "top").
- Added optional `raster` field on feature intended to store encoded image data representing exact and unbuffered tile extents for a layer.

### 1.0.1

- Used TitleCase and UPPERCASE in `vector_tile.proto` to match Protobuf style guide (#3)
Expand Down