├── Dockerfile ├── Makefile ├── README.md ├── gen └── third-party │ └── vector-tile-spec │ └── 1.0.1 │ └── vector_tile.pb.go ├── install-proto.sh ├── main.go ├── third-party └── vector-tile-spec │ ├── 1.0.0 │ ├── README.md │ └── vector_tile.proto │ ├── 1.0.1 │ ├── README.md │ └── vector_tile.proto │ ├── 2.0 │ ├── README.md │ └── vector_tile.proto │ ├── 2.1 │ ├── README.md │ └── vector_tile.proto │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ └── README.md └── trees.csv /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.7 2 | MAINTAINER Jon Miller 3 | 4 | ADD install-proto.sh . 5 | RUN ./install-proto.sh 6 | 7 | RUN go get -u github.com/golang/protobuf/proto 8 | RUN go get -u github.com/golang/protobuf/protoc-gen-go 9 | RUN go get -u github.com/vicapow/go-vtile-example 10 | 11 | EXPOSE 8080 12 | 13 | WORKDIR /go/src/github.com/vicapow/go-vtile-example 14 | CMD go run main.go 15 | 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | protobuf: 2 | protoc --go_out=gen/ third-party/vector-tile-spec/1.0.1/vector_tile.proto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An example Go app for dynamically serving MapboxGL vector tiles 2 | 3 | ![](https://cloud.githubusercontent.com/assets/583385/16578797/4cbf4d8a-4251-11e6-9f4c-75820d220405.png) 4 | 5 | ## Installation 6 | 7 | To install, ensure github.com/golang/protobuf/proto is installed and available on your $GOPATH. 8 | 9 | ## To run the project 10 | 11 | `cd` into the project directory, then run: 12 | 13 | go run main.go 14 | 15 | ## Docker 16 | 17 | To install/run in Docker instead of natively: 18 | 19 | ``` 20 | docker build -t go-vtile-example . 21 | docker run -d -p 8080:8080 go-vtile-example 22 | ``` 23 | 24 | ## To view the tiles 25 | 26 | To view the tiles, you'll need to modify your MapboxGL style to add an additional vector tile layer. Here's an example: 27 | 28 | ``` 29 | var map = new mapboxgl.Map({ 30 | container: 'map', 31 | zoom: 12.5, 32 | center: [-122.45, 37.79], 33 | style: { 34 | version: 8, 35 | sources: {}, 36 | layers: [] 37 | }, 38 | hash: false 39 | }); 40 | 41 | map.on('load', function loaded() { 42 | map.addSource('custom-go-vector-tile-source', { 43 | type: 'vector', 44 | tiles: ['http://localhost:8080/tiles/{z}/{x}/{y}'] 45 | }); 46 | map.addLayer({ 47 | id: 'background', 48 | type: 'background', 49 | paint: { 50 | 'background-color': 'white' 51 | } 52 | }); 53 | map.addLayer({ 54 | "id": "custom-go-vector-tile-layer", 55 | "type": "circle", 56 | "source": "custom-go-vector-tile-source", 57 | "source-layer": "points", 58 | paint: { 59 | 'circle-radius': { 60 | stops: [[8, 0.1], [11, 0.5], [15, 3], [20, 20]] 61 | }, 62 | 'circle-color': '#e74c3c', 63 | 'circle-opacity': 1 64 | } 65 | }); 66 | }); 67 | ``` 68 | 69 | ## Data from SFGov.org 70 | 71 | https://data.sfgov.org/City-Infrastructure/Street-Tree-Map/337t-q2b4 72 | -------------------------------------------------------------------------------- /gen/third-party/vector-tile-spec/1.0.1/vector_tile.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. 2 | // source: third-party/vector-tile-spec/1.0.1/vector_tile.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package vector_tile is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | third-party/vector-tile-spec/1.0.1/vector_tile.proto 10 | 11 | It has these top-level messages: 12 | Tile 13 | */ 14 | package vector_tile 15 | 16 | import proto "github.com/golang/protobuf/proto" 17 | import fmt "fmt" 18 | import math "math" 19 | 20 | // Reference imports to suppress errors if they are not otherwise used. 21 | var _ = proto.Marshal 22 | var _ = fmt.Errorf 23 | var _ = math.Inf 24 | 25 | // This is a compile-time assertion to ensure that this generated file 26 | // is compatible with the proto package it is being compiled against. 27 | // A compilation error at this line likely means your copy of the 28 | // proto package needs to be updated. 29 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 30 | 31 | type Tile_GeomType int32 32 | 33 | const ( 34 | Tile_UNKNOWN Tile_GeomType = 0 35 | Tile_POINT Tile_GeomType = 1 36 | Tile_LINESTRING Tile_GeomType = 2 37 | Tile_POLYGON Tile_GeomType = 3 38 | ) 39 | 40 | var Tile_GeomType_name = map[int32]string{ 41 | 0: "UNKNOWN", 42 | 1: "POINT", 43 | 2: "LINESTRING", 44 | 3: "POLYGON", 45 | } 46 | var Tile_GeomType_value = map[string]int32{ 47 | "UNKNOWN": 0, 48 | "POINT": 1, 49 | "LINESTRING": 2, 50 | "POLYGON": 3, 51 | } 52 | 53 | func (x Tile_GeomType) Enum() *Tile_GeomType { 54 | p := new(Tile_GeomType) 55 | *p = x 56 | return p 57 | } 58 | func (x Tile_GeomType) String() string { 59 | return proto.EnumName(Tile_GeomType_name, int32(x)) 60 | } 61 | func (x *Tile_GeomType) UnmarshalJSON(data []byte) error { 62 | value, err := proto.UnmarshalJSONEnum(Tile_GeomType_value, data, "Tile_GeomType") 63 | if err != nil { 64 | return err 65 | } 66 | *x = Tile_GeomType(value) 67 | return nil 68 | } 69 | func (Tile_GeomType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 70 | 71 | type Tile struct { 72 | Layers []*Tile_Layer `protobuf:"bytes,3,rep,name=layers" json:"layers,omitempty"` 73 | proto.XXX_InternalExtensions `json:"-"` 74 | XXX_unrecognized []byte `json:"-"` 75 | } 76 | 77 | func (m *Tile) Reset() { *m = Tile{} } 78 | func (m *Tile) String() string { return proto.CompactTextString(m) } 79 | func (*Tile) ProtoMessage() {} 80 | func (*Tile) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 81 | 82 | var extRange_Tile = []proto.ExtensionRange{ 83 | {16, 8191}, 84 | } 85 | 86 | func (*Tile) ExtensionRangeArray() []proto.ExtensionRange { 87 | return extRange_Tile 88 | } 89 | 90 | func (m *Tile) GetLayers() []*Tile_Layer { 91 | if m != nil { 92 | return m.Layers 93 | } 94 | return nil 95 | } 96 | 97 | // Variant type encoding 98 | type Tile_Value struct { 99 | // Exactly one of these values may be present in a valid message 100 | StringValue *string `protobuf:"bytes,1,opt,name=string_value" json:"string_value,omitempty"` 101 | FloatValue *float32 `protobuf:"fixed32,2,opt,name=float_value" json:"float_value,omitempty"` 102 | DoubleValue *float64 `protobuf:"fixed64,3,opt,name=double_value" json:"double_value,omitempty"` 103 | IntValue *int64 `protobuf:"varint,4,opt,name=int_value" json:"int_value,omitempty"` 104 | UintValue *uint64 `protobuf:"varint,5,opt,name=uint_value" json:"uint_value,omitempty"` 105 | SintValue *int64 `protobuf:"zigzag64,6,opt,name=sint_value" json:"sint_value,omitempty"` 106 | BoolValue *bool `protobuf:"varint,7,opt,name=bool_value" json:"bool_value,omitempty"` 107 | proto.XXX_InternalExtensions `json:"-"` 108 | XXX_unrecognized []byte `json:"-"` 109 | } 110 | 111 | func (m *Tile_Value) Reset() { *m = Tile_Value{} } 112 | func (m *Tile_Value) String() string { return proto.CompactTextString(m) } 113 | func (*Tile_Value) ProtoMessage() {} 114 | func (*Tile_Value) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 115 | 116 | var extRange_Tile_Value = []proto.ExtensionRange{ 117 | {8, 536870911}, 118 | } 119 | 120 | func (*Tile_Value) ExtensionRangeArray() []proto.ExtensionRange { 121 | return extRange_Tile_Value 122 | } 123 | 124 | func (m *Tile_Value) GetStringValue() string { 125 | if m != nil && m.StringValue != nil { 126 | return *m.StringValue 127 | } 128 | return "" 129 | } 130 | 131 | func (m *Tile_Value) GetFloatValue() float32 { 132 | if m != nil && m.FloatValue != nil { 133 | return *m.FloatValue 134 | } 135 | return 0 136 | } 137 | 138 | func (m *Tile_Value) GetDoubleValue() float64 { 139 | if m != nil && m.DoubleValue != nil { 140 | return *m.DoubleValue 141 | } 142 | return 0 143 | } 144 | 145 | func (m *Tile_Value) GetIntValue() int64 { 146 | if m != nil && m.IntValue != nil { 147 | return *m.IntValue 148 | } 149 | return 0 150 | } 151 | 152 | func (m *Tile_Value) GetUintValue() uint64 { 153 | if m != nil && m.UintValue != nil { 154 | return *m.UintValue 155 | } 156 | return 0 157 | } 158 | 159 | func (m *Tile_Value) GetSintValue() int64 { 160 | if m != nil && m.SintValue != nil { 161 | return *m.SintValue 162 | } 163 | return 0 164 | } 165 | 166 | func (m *Tile_Value) GetBoolValue() bool { 167 | if m != nil && m.BoolValue != nil { 168 | return *m.BoolValue 169 | } 170 | return false 171 | } 172 | 173 | type Tile_Feature struct { 174 | Id *uint64 `protobuf:"varint,1,opt,name=id,def=0" json:"id,omitempty"` 175 | // Tags of this feature are encoded as repeated pairs of 176 | // integers. Even indexed values (n, beginning with 0) are 177 | // themselves indexes into the layer's keys list. Odd indexed 178 | // values (n+1) are indexes into the layer's values list. 179 | // The first (n=0) tag of a feature, therefore, has a key of 180 | // layer.keys[feature.tags[0]] and a value of 181 | // layer.values[feature.tags[1]]. 182 | Tags []uint32 `protobuf:"varint,2,rep,packed,name=tags" json:"tags,omitempty"` 183 | // The type of geometry stored in this feature. 184 | Type *Tile_GeomType `protobuf:"varint,3,opt,name=type,enum=vector_tile.Tile_GeomType,def=0" json:"type,omitempty"` 185 | // Contains a stream of commands and parameters (vertices). The 186 | // repeat count is shifted to the left by 3 bits. This means 187 | // that the command has 3 bits (0-7). The repeat count 188 | // indicates how often this command is to be repeated. Defined 189 | // commands are: 190 | // - MoveTo: 1 (2 parameters follow) 191 | // - LineTo: 2 (2 parameters follow) 192 | // - ClosePath: 7 (no parameters follow) 193 | // 194 | // Commands are encoded as uint32 varints. Vertex parameters 195 | // are encoded as deltas to the previous position and, as they 196 | // may be negative, are further "zigzag" encoded as unsigned 197 | // 32-bit ints: 198 | // 199 | // n = (n << 1) ^ (n >> 31) 200 | // 201 | // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath 202 | // Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 203 | // | | `> [00001 111] command type 7 (ClosePath), length 1 204 | // | | ===== relative LineTo(+12, +22) == LineTo(20, 34) 205 | // | | ===== relative LineTo(+5, +6) == LineTo(8, 12) 206 | // | `> [00010 010] = command type 2 (LineTo), length 2 207 | // | ==== relative MoveTo(+3, +6) 208 | // `> [00001 001] = command type 1 (MoveTo), length 1 209 | // 210 | // The original position is (0,0). 211 | Geometry []uint32 `protobuf:"varint,4,rep,packed,name=geometry" json:"geometry,omitempty"` 212 | XXX_unrecognized []byte `json:"-"` 213 | } 214 | 215 | func (m *Tile_Feature) Reset() { *m = Tile_Feature{} } 216 | func (m *Tile_Feature) String() string { return proto.CompactTextString(m) } 217 | func (*Tile_Feature) ProtoMessage() {} 218 | func (*Tile_Feature) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 1} } 219 | 220 | const Default_Tile_Feature_Id uint64 = 0 221 | const Default_Tile_Feature_Type Tile_GeomType = Tile_UNKNOWN 222 | 223 | func (m *Tile_Feature) GetId() uint64 { 224 | if m != nil && m.Id != nil { 225 | return *m.Id 226 | } 227 | return Default_Tile_Feature_Id 228 | } 229 | 230 | func (m *Tile_Feature) GetTags() []uint32 { 231 | if m != nil { 232 | return m.Tags 233 | } 234 | return nil 235 | } 236 | 237 | func (m *Tile_Feature) GetType() Tile_GeomType { 238 | if m != nil && m.Type != nil { 239 | return *m.Type 240 | } 241 | return Default_Tile_Feature_Type 242 | } 243 | 244 | func (m *Tile_Feature) GetGeometry() []uint32 { 245 | if m != nil { 246 | return m.Geometry 247 | } 248 | return nil 249 | } 250 | 251 | type Tile_Layer struct { 252 | // Any compliant implementation must first read the version 253 | // number encoded in this message and choose the correct 254 | // implementation for this version number before proceeding to 255 | // decode other parts of this message. 256 | Version *uint32 `protobuf:"varint,15,req,name=version,def=1" json:"version,omitempty"` 257 | Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` 258 | // The actual features in this tile. 259 | Features []*Tile_Feature `protobuf:"bytes,2,rep,name=features" json:"features,omitempty"` 260 | // Dictionary encoding for keys 261 | Keys []string `protobuf:"bytes,3,rep,name=keys" json:"keys,omitempty"` 262 | // Dictionary encoding for values 263 | Values []*Tile_Value `protobuf:"bytes,4,rep,name=values" json:"values,omitempty"` 264 | // The bounding box in this tile spans from 0..4095 units 265 | Extent *uint32 `protobuf:"varint,5,opt,name=extent,def=4096" json:"extent,omitempty"` 266 | proto.XXX_InternalExtensions `json:"-"` 267 | XXX_unrecognized []byte `json:"-"` 268 | } 269 | 270 | func (m *Tile_Layer) Reset() { *m = Tile_Layer{} } 271 | func (m *Tile_Layer) String() string { return proto.CompactTextString(m) } 272 | func (*Tile_Layer) ProtoMessage() {} 273 | func (*Tile_Layer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 2} } 274 | 275 | var extRange_Tile_Layer = []proto.ExtensionRange{ 276 | {16, 536870911}, 277 | } 278 | 279 | func (*Tile_Layer) ExtensionRangeArray() []proto.ExtensionRange { 280 | return extRange_Tile_Layer 281 | } 282 | 283 | const Default_Tile_Layer_Version uint32 = 1 284 | const Default_Tile_Layer_Extent uint32 = 4096 285 | 286 | func (m *Tile_Layer) GetVersion() uint32 { 287 | if m != nil && m.Version != nil { 288 | return *m.Version 289 | } 290 | return Default_Tile_Layer_Version 291 | } 292 | 293 | func (m *Tile_Layer) GetName() string { 294 | if m != nil && m.Name != nil { 295 | return *m.Name 296 | } 297 | return "" 298 | } 299 | 300 | func (m *Tile_Layer) GetFeatures() []*Tile_Feature { 301 | if m != nil { 302 | return m.Features 303 | } 304 | return nil 305 | } 306 | 307 | func (m *Tile_Layer) GetKeys() []string { 308 | if m != nil { 309 | return m.Keys 310 | } 311 | return nil 312 | } 313 | 314 | func (m *Tile_Layer) GetValues() []*Tile_Value { 315 | if m != nil { 316 | return m.Values 317 | } 318 | return nil 319 | } 320 | 321 | func (m *Tile_Layer) GetExtent() uint32 { 322 | if m != nil && m.Extent != nil { 323 | return *m.Extent 324 | } 325 | return Default_Tile_Layer_Extent 326 | } 327 | 328 | func init() { 329 | proto.RegisterType((*Tile)(nil), "vector_tile.Tile") 330 | proto.RegisterType((*Tile_Value)(nil), "vector_tile.Tile.Value") 331 | proto.RegisterType((*Tile_Feature)(nil), "vector_tile.Tile.Feature") 332 | proto.RegisterType((*Tile_Layer)(nil), "vector_tile.Tile.Layer") 333 | proto.RegisterEnum("vector_tile.Tile_GeomType", Tile_GeomType_name, Tile_GeomType_value) 334 | } 335 | 336 | func init() { 337 | proto.RegisterFile("third-party/vector-tile-spec/1.0.1/vector_tile.proto", fileDescriptor0) 338 | } 339 | 340 | var fileDescriptor0 = []byte{ 341 | // 438 bytes of a gzipped FileDescriptorProto 342 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0xcd, 0x6e, 0xd3, 0x40, 343 | 0x14, 0x85, 0xf1, 0x78, 0x92, 0x38, 0xd7, 0x4d, 0x31, 0x03, 0x12, 0x21, 0xab, 0xa8, 0x1b, 0xa2, 344 | 0xa2, 0xb8, 0x71, 0x54, 0x21, 0xe1, 0x0d, 0xa8, 0x12, 0x84, 0x88, 0xc8, 0xae, 0xc0, 0x80, 0x58, 345 | 0x55, 0x6e, 0x33, 0x0d, 0x16, 0xae, 0xc7, 0x1a, 0x8f, 0x23, 0xbc, 0xe3, 0x55, 0x78, 0x00, 0xde, 346 | 0x81, 0x47, 0xe3, 0x8e, 0x7f, 0xd4, 0x4a, 0xc5, 0x2b, 0xfb, 0xf3, 0x99, 0xb9, 0xe7, 0x9c, 0x0b, 347 | 0xa7, 0xea, 0x7b, 0x22, 0xb7, 0xf3, 0x3c, 0x96, 0xaa, 0x3a, 0xd9, 0xf3, 0x2b, 0x25, 0xe4, 0x5c, 348 | 0x25, 0x29, 0x9f, 0x17, 0x39, 0xbf, 0x3a, 0xf1, 0xdc, 0x85, 0xeb, 0xb5, 0xf8, 0x42, 0x63, 0x37, 349 | 0x97, 0x42, 0x09, 0x66, 0xdf, 0x41, 0x47, 0x7f, 0x29, 0xd0, 0x08, 0x5f, 0xd8, 0x73, 0xe8, 0xa7, 350 | 0x71, 0xc5, 0x65, 0x31, 0x36, 0xa7, 0xe6, 0xcc, 0x5e, 0x3e, 0x75, 0xef, 0x9e, 0xd4, 0x12, 0x77, 351 | 0xa3, 0xff, 0x4f, 0x7e, 0x1b, 0xd0, 0xfb, 0x12, 0xa7, 0x25, 0x67, 0x4f, 0xe0, 0xa0, 0x50, 0x32, 352 | 0xc9, 0x76, 0x17, 0x7b, 0xfd, 0x3d, 0x36, 0xa6, 0xc6, 0x6c, 0xc8, 0x1e, 0x83, 0x7d, 0x9d, 0x8a, 353 | 0x58, 0xb5, 0x90, 0x20, 0x24, 0x5a, 0xba, 0x15, 0xe5, 0x65, 0xca, 0x5b, 0x6a, 0x22, 0x35, 0xd8, 354 | 0x23, 0x18, 0x26, 0x59, 0x27, 0xa4, 0x88, 0x4c, 0xc6, 0x00, 0xca, 0x5b, 0xd6, 0x43, 0x46, 0x35, 355 | 0x2b, 0x6e, 0x59, 0x1f, 0x19, 0xd3, 0xec, 0x52, 0x88, 0xb4, 0x65, 0x03, 0x64, 0xd6, 0xb1, 0x65, 356 | 0x59, 0xce, 0x2f, 0x7c, 0xc8, 0xa4, 0x80, 0xc1, 0x3b, 0x1e, 0xab, 0x52, 0x72, 0x36, 0x02, 0x92, 357 | 0x6c, 0x6b, 0x6b, 0xd4, 0x37, 0x16, 0xcc, 0x01, 0xaa, 0xe2, 0x5d, 0x81, 0xb6, 0xcc, 0xd9, 0xe8, 358 | 0x8c, 0x38, 0x06, 0xf3, 0x90, 0x54, 0x79, 0x63, 0xe9, 0x70, 0x39, 0xb9, 0x1f, 0x7b, 0xc5, 0xc5, 359 | 0x4d, 0x84, 0x0a, 0x7f, 0xf0, 0x39, 0xf8, 0x10, 0x84, 0x5f, 0x03, 0x4c, 0x63, 0xed, 0x10, 0x72, 360 | 0x25, 0x2b, 0xb4, 0xdd, 0x5e, 0x34, 0xf9, 0x83, 0xc5, 0xd4, 0x15, 0xa1, 0xb9, 0xc1, 0x1e, 0x9b, 361 | 0x4c, 0x44, 0x36, 0x7e, 0x38, 0x25, 0xb3, 0x91, 0x6f, 0x78, 0xec, 0x00, 0x68, 0x16, 0xdf, 0xe8, 362 | 0x92, 0x08, 0x96, 0xf4, 0x02, 0xac, 0xeb, 0xc6, 0x60, 0x63, 0xc5, 0x5e, 0x3e, 0xbb, 0x3f, 0xb8, 363 | 0x8b, 0x80, 0x47, 0x7f, 0xf0, 0xaa, 0x59, 0xcc, 0x50, 0x2f, 0xaa, 0x0e, 0x5d, 0xd4, 0xa3, 0xff, 364 | 0xbb, 0xa8, 0x6e, 0x3d, 0x7d, 0xfe, 0x53, 0xf1, 0x4c, 0xd5, 0x35, 0x8e, 0x7c, 0x7a, 0xba, 0x78, 365 | 0xf5, 0x12, 0x4b, 0x72, 0x9a, 0x92, 0x8e, 0x5e, 0x83, 0xd5, 0x45, 0x63, 0x36, 0x74, 0xe1, 0x9c, 366 | 0x07, 0x6c, 0x08, 0xbd, 0xf3, 0x70, 0x1d, 0x44, 0x58, 0xce, 0x21, 0xc0, 0x66, 0x1d, 0xbc, 0xfd, 367 | 0x14, 0x7d, 0x5c, 0x07, 0x2b, 0x87, 0x68, 0xdd, 0x79, 0xb8, 0xf9, 0xb6, 0x0a, 0x03, 0xc7, 0x3c, 368 | 0xee, 0xe9, 0xab, 0xde, 0x9c, 0x91, 0xf7, 0xe6, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x47, 0x18, 369 | 0x92, 0xa2, 0x8a, 0x02, 0x00, 0x00, 370 | } 371 | -------------------------------------------------------------------------------- /install-proto.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | wget https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz 3 | tar xzf protobuf-2.6.1.tar.gz 4 | cd protobuf-2.6.1 5 | apt-get update -y 6 | apt-get install -y build-essential 7 | ./configure 8 | make 9 | make check 10 | make install 11 | ldconfig 12 | protoc --version 13 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/csv" 5 | "errors" 6 | "fmt" 7 | "io/ioutil" 8 | "log" 9 | "math" 10 | "net/http" 11 | "regexp" 12 | "strconv" 13 | "strings" 14 | 15 | "github.com/golang/protobuf/proto" 16 | "github.com/vicapow/go-vtile-example/gen/third-party/vector-tile-spec/1.0.1" 17 | ) 18 | 19 | func cmdEnc(id uint32, count uint32) uint32 { 20 | return (id & 0x7) | (count << 3) 21 | } 22 | 23 | func moveTo(count uint32) uint32 { 24 | return cmdEnc(1, count) 25 | } 26 | 27 | func lineTo(count uint32) uint32 { 28 | return cmdEnc(2, count) 29 | } 30 | 31 | func closePath(count uint32) uint32 { 32 | return cmdEnc(7, count) 33 | } 34 | 35 | func paramEnc(value int32) int32 { 36 | return (value << 1) ^ (value >> 31) 37 | } 38 | 39 | func createTileWithPoints(xyz TileID, points []LngLat) ([]byte, error) { 40 | tile := &vector_tile.Tile{} 41 | var layerVersion = vector_tile.Default_Tile_Layer_Version 42 | layerName := "points" 43 | featureType := vector_tile.Tile_POINT 44 | var extent = vector_tile.Default_Tile_Layer_Extent 45 | // Put a point in the center of the tile. 46 | var geometry []uint32 47 | var filtered [][2]float64 48 | for _, point := range points { 49 | x, y := lngLatToTileXY(point, xyz) 50 | if x >= 0 && x < 1 && y >= 0 && y < 1 { 51 | filtered = append(filtered, [2]float64{x, y}) 52 | } 53 | } 54 | if len(filtered) > 0 { 55 | cmd := moveTo(uint32(len(filtered))) 56 | geometry = append(geometry, cmd) 57 | var pX int32 58 | var pY int32 59 | for _, point := range filtered { 60 | deltaX := int32(float64(extent)*point[0]+0.5) - pX 61 | deltaY := int32(float64(extent)*point[1]+0.5) - pY 62 | geometry = append(geometry, uint32(paramEnc(deltaX))) 63 | geometry = append(geometry, uint32(paramEnc(deltaY))) 64 | pX = pX + deltaX 65 | pY = pY + deltaY 66 | } 67 | } else { 68 | // Return an empty tile if we have no points 69 | return nil, nil 70 | } 71 | tile.Layers = []*vector_tile.Tile_Layer{ 72 | &vector_tile.Tile_Layer{ 73 | Version: &layerVersion, 74 | Name: &layerName, 75 | Extent: &extent, 76 | Features: []*vector_tile.Tile_Feature{ 77 | &vector_tile.Tile_Feature{ 78 | Tags: []uint32{}, 79 | Type: &featureType, 80 | Geometry: geometry, 81 | }, 82 | }, 83 | }, 84 | } 85 | return proto.Marshal(tile) 86 | } 87 | 88 | func xyzToLngLat(tileX float64, tileY float64, tileZ float64) (float64, float64) { 89 | totalTilesX := math.Pow(2, tileZ) 90 | totalTilesY := math.Pow(2, tileZ) 91 | x := float64(tileX) / float64(totalTilesX) 92 | y := float64(tileY) / float64(totalTilesY) 93 | // lambda can go from [-pi/2, pi/2] 94 | lambda := x*math.Pi*2 - math.Pi 95 | // phi can go from [-1.4844, 1.4844] 96 | phi := 2*math.Atan(math.Exp((2*y-1)*math.Pi)) - (math.Pi / 2) 97 | lng := lambda * 180 / math.Pi 98 | lat := (math.Pi - phi) * 180 / math.Pi 99 | return lng, lat 100 | } 101 | 102 | func lngLatToTileXY(ll LngLat, tile TileID) (float64, float64) { 103 | totalTilesX := math.Pow(2, float64(tile.z)) 104 | totalTilesY := math.Pow(2, float64(tile.z)) 105 | lambda := (ll.lng + 180) / 180 * math.Pi 106 | // phi: [-pi/2, pi/2] 107 | phi := ll.lat / 180 * math.Pi 108 | tileX := lambda / (2 * math.Pi) * totalTilesX 109 | // [-1.4844, 1.4844] -> [1, 0] * totalTilesY 110 | tileY := (math.Log(math.Tan(math.Pi/4-phi/2))/math.Pi/2 + 0.5) * totalTilesY 111 | return tileX - float64(tile.x), tileY - float64(tile.y) 112 | } 113 | 114 | // Takes a string of the form `//` (for example, 1/2/3) and returns 115 | // the individual uint32 values for x, y, and z if there was no error. 116 | // Otherwise, err is set to a non `nil` value and x, y, z are set to 0. 117 | func tilePathToXYZ(path string) (TileID, error) { 118 | xyzReg := regexp.MustCompile("(?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)") 119 | matches := xyzReg.FindStringSubmatch(path) 120 | if len(matches) == 0 { 121 | return TileID{}, errors.New("Unable to parse path as tile") 122 | } 123 | x, err := strconv.ParseUint(matches[2], 10, 32) 124 | if err != nil { 125 | return TileID{}, err 126 | } 127 | y, err := strconv.ParseUint(matches[3], 10, 32) 128 | if err != nil { 129 | return TileID{}, err 130 | } 131 | z, err := strconv.ParseUint(matches[1], 10, 32) 132 | if err != nil { 133 | return TileID{}, err 134 | } 135 | return TileID{x: uint32(x), y: uint32(y), z: uint32(z)}, nil 136 | } 137 | 138 | // A LngLat is a struct that holds a longitude and latitude vale. 139 | type LngLat struct { 140 | lng float64 141 | lat float64 142 | } 143 | 144 | // TileID represents the id of the tile. 145 | type TileID struct { 146 | x uint32 147 | y uint32 148 | z uint32 149 | } 150 | 151 | // Tree a struct holder for tree information. 152 | type Tree struct { 153 | lng float64 154 | lat float64 155 | species string 156 | } 157 | 158 | func loadTrees() []Tree { 159 | content, err := ioutil.ReadFile("./trees.csv") 160 | if err != nil { 161 | log.Fatal(err) 162 | } 163 | r := csv.NewReader(strings.NewReader(string(content[:]))) 164 | records, err := r.ReadAll() 165 | if err != nil { 166 | log.Fatal(err) 167 | } 168 | // TreeID,qLegalStatus,qSpecies,qAddress,SiteOrder,qSiteInfo,PlantType,qCaretaker,qCareAssistant,PlantDate,DBH,PlotSize,PermitNotes,XCoord,YCoord,Latitude,Longitude,Location 169 | var trees []Tree 170 | for _, record := range records[1:] { 171 | lat, _ := strconv.ParseFloat(record[15], 64) 172 | lng, _ := strconv.ParseFloat(record[16], 64) 173 | species := record[2] 174 | trees = append(trees, Tree{lng: lng, lat: lat, species: species}) 175 | } 176 | return trees 177 | } 178 | 179 | func main() { 180 | trees := loadTrees() 181 | points := make([]LngLat, len(trees), len(trees)) 182 | for i, tree := range trees { 183 | points[i] = LngLat{lng: tree.lng, lat: tree.lat} 184 | } 185 | // points = points[0:1000] 186 | fmt.Println("number of points", len(points)) 187 | mux := http.NewServeMux() 188 | 189 | // Handle requests for urls of the form `/tiles/{z}/{x}/{y}` and returns 190 | // the vector tile for the even tile x, y, and z coordinates. 191 | tileBase := "/tiles/" 192 | mux.HandleFunc(tileBase, func(w http.ResponseWriter, r *http.Request) { 193 | log.Printf("url: %s", r.URL.Path) 194 | tilePart := r.URL.Path[len(tileBase):] 195 | xyz, err := tilePathToXYZ(tilePart) 196 | if err != nil { 197 | http.Error(w, "Invalid tile url", 400) 198 | return 199 | } 200 | data, err := createTileWithPoints(xyz, points) 201 | if err != nil { 202 | log.Fatal("error generating tile", err) 203 | } 204 | // All this APi to be requests from other domains. 205 | w.Header().Set("Content-Type", "application/x-protobuf") 206 | w.Header().Set("Access-Control-Allow-Origin", "*") 207 | w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") 208 | w.Write(data) 209 | }) 210 | log.Fatal(http.ListenAndServe(":8080", mux)) 211 | } 212 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/1.0.0/README.md: -------------------------------------------------------------------------------- 1 | # vector-tile-spec 2 | 3 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 4 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in 5 | this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 6 | 7 | ## 1. Purpose 8 | 9 | This specification attempts to create a standard for encoding of tiled geospatial data that can be shared across clients. 10 | 11 | ## 2. File format 12 | 13 | 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. 14 | 15 | 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). 16 | 17 | ## 3. Internal structure 18 | 19 | A vector tile can consist of one or more named layers and containing one or more features. 20 | 21 | Features contain an id, attributes, and geometries: either point, linestring, or polygon. 22 | 23 | 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 are 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. 24 | 25 | 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. 26 | 27 | For example, a GeoJSON feature like: 28 | 29 | ```json 30 | { 31 | "type": "FeatureCollection", 32 | "features": [ 33 | { 34 | "geometry": { 35 | "type": "Point", 36 | "coordinates": [ 37 | -8247861.1000836585, 38 | 4970241.327215323 39 | ] 40 | }, 41 | "type": "Feature", 42 | "properties": { 43 | "hello": "world" 44 | } 45 | } 46 | ] 47 | } 48 | ``` 49 | 50 | Would be structured like: 51 | 52 | ```js 53 | layers { 54 | name: "points" 55 | features { 56 | id: 1 57 | tags: 0 58 | tags: 0 59 | type: Point 60 | geometry: 9 61 | geometry: 2410 62 | geometry: 3080 63 | } 64 | keys: "hello" 65 | values { 66 | string_value: "world" 67 | } 68 | extent: 4096 69 | version: 2 70 | } 71 | ``` 72 | 73 | The complete and authoritative details on encoding are part of the code comments for the [vector tile protobuf schema document](vector_tile.proto). 74 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/1.0.0/vector_tile.proto: -------------------------------------------------------------------------------- 1 | // Protocol Version 1 2 | 3 | package mapnik.vector; 4 | 5 | option optimize_for = LITE_RUNTIME; 6 | 7 | message tile { 8 | enum GeomType { 9 | Unknown = 0; 10 | Point = 1; 11 | LineString = 2; 12 | Polygon = 3; 13 | } 14 | 15 | // Variant type encoding 16 | message value { 17 | // Exactly one of these values may be present in a valid message 18 | optional string string_value = 1; 19 | optional float float_value = 2; 20 | optional double double_value = 3; 21 | optional int64 int_value = 4; 22 | optional uint64 uint_value = 5; 23 | optional sint64 sint_value = 6; 24 | optional bool bool_value = 7; 25 | 26 | extensions 8 to max; 27 | } 28 | 29 | message feature { 30 | optional uint64 id = 1; 31 | 32 | // Tags of this feature. Even numbered values refer to the nth 33 | // value in the keys list on the tile message, odd numbered 34 | // values refer to the nth value in the values list on the tile 35 | // message. 36 | repeated uint32 tags = 2 [ packed = true ]; 37 | 38 | // The type of geometry stored in this feature. 39 | optional GeomType type = 3 [ default = Unknown ]; 40 | 41 | // Contains a stream of commands and parameters (vertices). The 42 | // repeat count is shifted to the left by 3 bits. This means 43 | // that the command has 3 bits (0-7). The repeat count 44 | // indicates how often this command is to be repeated. Defined 45 | // commands are: 46 | // - MoveTo: 1 (2 parameters follow) 47 | // - LineTo: 2 (2 parameters follow) 48 | // - ClosePath: 7 (no parameters follow) 49 | // 50 | // Commands are encoded as uint32 varints. Vertex parameters 51 | // are encoded as deltas to the previous position and, as they 52 | // may be negative, are further "zigzag" encoded as unsigned 53 | // 32-bit ints: 54 | // 55 | // n = (n << 1) ^ (n >> 31) 56 | // 57 | // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath 58 | // Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 59 | // | | `> [00001 111] command type 7 (ClosePath), length 1 60 | // | | ===== relative LineTo(+12, +22) == LineTo(20, 34) 61 | // | | ===== relative LineTo(+5, +6) == LineTo(8, 12) 62 | // | `> [00010 010] = command type 2 (LineTo), length 2 63 | // | ==== relative MoveTo(+3, +6) 64 | // `> [00001 001] = command type 1 (MoveTo), length 1 65 | // 66 | // The original position is (0,0). 67 | repeated uint32 geometry = 4 [ packed = true ]; 68 | } 69 | 70 | message layer { 71 | // Any compliant implementation must first read the version 72 | // number encoded in this message and choose the correct 73 | // implementation for this version number before proceeding to 74 | // decode other parts of this message. 75 | required uint32 version = 15 [ default = 1 ]; 76 | 77 | required string name = 1; 78 | 79 | // The actual features in this tile. 80 | repeated feature features = 2; 81 | 82 | // Dictionary encoding for keys 83 | repeated string keys = 3; 84 | 85 | // Dictionary encoding for values 86 | repeated value values = 4; 87 | 88 | // The bounding box in this tile spans from 0..4095 units 89 | optional uint32 extent = 5 [ default = 4096 ]; 90 | 91 | extensions 16 to max; 92 | } 93 | 94 | repeated layer layers = 3; 95 | 96 | extensions 16 to 8191; 97 | } 98 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/1.0.1/README.md: -------------------------------------------------------------------------------- 1 | # vector-tile-spec 2 | 3 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 4 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in 5 | this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 6 | 7 | ## 1. Purpose 8 | 9 | This specification attempts to create a standard for encoding of tiled geospatial data that can be shared across clients. 10 | 11 | ## 2. File format 12 | 13 | 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. 14 | 15 | 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). 16 | 17 | ## 3. Internal structure 18 | 19 | A vector tile can consist of one or more named layers and containing one or more features. 20 | 21 | Features contain an id, attributes, and geometries: either point, linestring, or polygon. 22 | 23 | Geometries are stored as a single array of integers that represent a command,x,y stream (where command is a rendering command like move_to or line_to). Commands are encoded only when they change. Geometries are 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. 24 | 25 | 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 [varint](https://developers.google.com/protocol-buffers/docs/encoding#varints) type encoding supporting both unicode strings, boolean values, and various integer and floating point types. 26 | 27 | For example, a GeoJSON feature like: 28 | 29 | ```json 30 | { 31 | "type": "FeatureCollection", 32 | "features": [ 33 | { 34 | "geometry": { 35 | "type": "Point", 36 | "coordinates": [ 37 | -8247861.1000836585, 38 | 4970241.327215323 39 | ] 40 | }, 41 | "type": "Feature", 42 | "properties": { 43 | "hello": "world" 44 | } 45 | } 46 | ] 47 | } 48 | ``` 49 | 50 | Would be structured like: 51 | 52 | ```js 53 | layers { 54 | name: "points" 55 | features { 56 | id: 1 57 | tags: 0 58 | tags: 0 59 | type: Point 60 | geometry: 9 61 | geometry: 2410 62 | geometry: 3080 63 | } 64 | keys: "hello" 65 | values { 66 | string_value: "world" 67 | } 68 | extent: 4096 69 | version: 2 70 | } 71 | ``` 72 | 73 | The complete and authoritative details on encoding are part of the code comments for the [vector tile protobuf schema document](vector_tile.proto). 74 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/1.0.1/vector_tile.proto: -------------------------------------------------------------------------------- 1 | // Protocol Version 1 2 | 3 | package vector_tile; 4 | 5 | option optimize_for = LITE_RUNTIME; 6 | 7 | message Tile { 8 | enum GeomType { 9 | UNKNOWN = 0; 10 | POINT = 1; 11 | LINESTRING = 2; 12 | POLYGON = 3; 13 | } 14 | 15 | // Variant type encoding 16 | message Value { 17 | // Exactly one of these values may be present in a valid message 18 | optional string string_value = 1; 19 | optional float float_value = 2; 20 | optional double double_value = 3; 21 | optional int64 int_value = 4; 22 | optional uint64 uint_value = 5; 23 | optional sint64 sint_value = 6; 24 | optional bool bool_value = 7; 25 | 26 | extensions 8 to max; 27 | } 28 | 29 | message Feature { 30 | optional uint64 id = 1 [ default = 0 ]; 31 | 32 | // Tags of this feature are encoded as repeated pairs of 33 | // integers. Even indexed values (n, beginning with 0) are 34 | // themselves indexes into the layer's keys list. Odd indexed 35 | // values (n+1) are indexes into the layer's values list. 36 | // The first (n=0) tag of a feature, therefore, has a key of 37 | // layer.keys[feature.tags[0]] and a value of 38 | // layer.values[feature.tags[1]]. 39 | repeated uint32 tags = 2 [ packed = true ]; 40 | 41 | // The type of geometry stored in this feature. 42 | optional GeomType type = 3 [ default = UNKNOWN ]; 43 | 44 | // Contains a stream of commands and parameters (vertices). The 45 | // repeat count is shifted to the left by 3 bits. This means 46 | // that the command has 3 bits (0-7). The repeat count 47 | // indicates how often this command is to be repeated. Defined 48 | // commands are: 49 | // - MoveTo: 1 (2 parameters follow) 50 | // - LineTo: 2 (2 parameters follow) 51 | // - ClosePath: 7 (no parameters follow) 52 | // 53 | // Commands are encoded as uint32 varints. Vertex parameters 54 | // are encoded as deltas to the previous position and, as they 55 | // may be negative, are further "zigzag" encoded as unsigned 56 | // 32-bit ints: 57 | // 58 | // n = (n << 1) ^ (n >> 31) 59 | // 60 | // Ex.: MoveTo(3, 6), LineTo(8, 12), LineTo(20, 34), ClosePath 61 | // Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 62 | // | | `> [00001 111] command type 7 (ClosePath), length 1 63 | // | | ===== relative LineTo(+12, +22) == LineTo(20, 34) 64 | // | | ===== relative LineTo(+5, +6) == LineTo(8, 12) 65 | // | `> [00010 010] = command type 2 (LineTo), length 2 66 | // | ==== relative MoveTo(+3, +6) 67 | // `> [00001 001] = command type 1 (MoveTo), length 1 68 | // 69 | // The original position is (0,0). 70 | repeated uint32 geometry = 4 [ packed = true ]; 71 | } 72 | 73 | message Layer { 74 | // Any compliant implementation must first read the version 75 | // number encoded in this message and choose the correct 76 | // implementation for this version number before proceeding to 77 | // decode other parts of this message. 78 | required uint32 version = 15 [ default = 1 ]; 79 | 80 | required string name = 1; 81 | 82 | // The actual features in this tile. 83 | repeated Feature features = 2; 84 | 85 | // Dictionary encoding for keys 86 | repeated string keys = 3; 87 | 88 | // Dictionary encoding for values 89 | repeated Value values = 4; 90 | 91 | // The bounding box in this tile spans from 0..4095 units 92 | optional uint32 extent = 5 [ default = 4096 ]; 93 | 94 | extensions 16 to max; 95 | } 96 | 97 | repeated Layer layers = 3; 98 | 99 | extensions 16 to 8191; 100 | } 101 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/2.0/README.md: -------------------------------------------------------------------------------- 1 | # Vector Tile Specification 2 | 3 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 4 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in 5 | this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 6 | 7 | ## 1. Purpose 8 | 9 | This document specifies a space-efficient encoding format for tiled geographic vector data. It is designed to be used in browsers or server-side applications for fast rendering or lookups of feature data. 10 | 11 | ## 2. File Format 12 | 13 | The Vector Tile format uses [Google Protocol Buffers](https://developers.google.com/protocol-buffers/) as a encoding format. Protocol Buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. 14 | 15 | ## 2.1. File Extension 16 | 17 | The filename extension for Vector Tile files SHOULD be `mvt`. For example, a file might be named `vector.mvt`. 18 | 19 | ## 2.2. Multipurpose Internet Mail Extensions (MIME) 20 | 21 | When serving Vector Tiles the MIME type SHOULD be `application/vnd.mapbox-vector-tile`. 22 | 23 | ## 3. Projection and Bounds 24 | 25 | A Vector Tile represents data based on a square extent within a projection. A Vector Tile SHOULD NOT contain information about its bounds and projection. The file format assumes that the decoder knows the bounds and projection of a Vector Tile before decoding it. 26 | 27 | [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator) is the projection of reference, and [the Google tile scheme](http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/) is the tile extent convention of reference. Together, they provide a 1-to-1 relationship between a specific geographical area, at a specific level of detail, and a path such as `https://example.com/17/65535/43602.mvt`. 28 | 29 | Vector Tiles MAY be used to represent data with any projection and tile extent scheme. 30 | 31 | ## 4. Internal Structure 32 | 33 | This specification describes the structure of data within a Vector Tile. The reader should have an understanding of the [Vector Tile protobuf schema document](vector_tile.proto) and the structures it defines. 34 | 35 | ### 4.1. Layers 36 | 37 | A Vector Tile consists of a set of named layers. A layer contains geometric features and their metadata. The layer format is designed so that the data required for a layer is contiguous in memory, and so that layers can be appended to a Vector Tile without modifying existing data. 38 | 39 | A Vector Tile SHOULD contain at least one layer. A layer SHOULD contain at least one feature. 40 | 41 | A layer MUST contain a `version` field with the major version number of the Vector Tile specification to which the layer adheres. For example, a layer adhering to version 2.1 of the specification contains a `version` field with the integer value `2`. The `version` field SHOULD be the first field within the layer. Decoders SHOULD parse the `version` first to ensure that they are capable of decoding each layer. When a Vector Tile consumer encounters a Vector Tile layer with an unknown version, it MAY make a best-effort attempt to interpret the layer, or it MAY skip the layer. In either case it SHOULD continue to process subsequent layers in the Vector Tile. 42 | 43 | A layer MUST contain a `name` field. A Vector Tile MUST NOT contain two or more layers whose `name` values are byte-for-byte identical. Prior to appending a layer to an existing Vector Tile, an encoder MUST check the existing `name` fields in order to prevent duplication. 44 | 45 | Each feature in a layer (see below) may have one or more key-value pairs as its metadata. The keys and values are indices into two lists, `keys` and `values`, that are shared across the layer's features. 46 | 47 | Each element in the `keys` field of the layer is a string. The `keys` include all the keys of features used in the layer, and each key may be referenced by its positional index in this set of `keys`, with the first key having an index of 0. The set of `keys` SHOULD NOT contain two or more values which are byte-for-byte identical. 48 | 49 | Each element in the `values` field of the layer encodes a value of any of several types (see below). The `values` represent all the values of features used in the layer, and each value may be referenced by its positional index in this set of `values`, with the first value having an index of 0. The set of `values` SHOULD NOT contain two or more values of the same type which are byte-for-byte identical. 50 | 51 | In order to support values of varying string, boolean, integer, and floating point types, the protobuf encoding of the `value` field consists of a set of `optional` fields. A value MUST contain exactly one of these optional fields. 52 | 53 | A layer MUST contain an `extent` that describes the width and height of the tile in integer coordinates. The geometries within the Vector Tile MAY extend past the bounds of the tile's area as defined by the `extent`. Geometries that extend past the tile's area as defined by `extent` are often used as a buffer for rendering features that overlap multiple adjacent tiles. 54 | 55 | For example, if a tile has an `extent` of 4096, values between 0 and 4095 are considered within the tile's extent. A point at `(0,10)` or `(4095,10)` is within the extent of the tile. A point at `(-1,10)` or `(4096,10)` is outside the extent of the tile. 56 | 57 | ### 4.2. Features 58 | 59 | A feature MUST contain a `geometry` field. 60 | 61 | A feature MUST contain a `type` field as described in the Geometry Types section. 62 | 63 | A feature MAY contain a `tags` field. Feature-level metadata, if any, SHOULD be stored in the `tags` field. 64 | 65 | A feature MAY contain an `id` field. If a feature has an `id` field, the value of the `id` SHOULD be unique among the features of the parent layer. 66 | 67 | ### 4.3. Geometry Encoding 68 | 69 | Geometry data in a Vector Tile is defined in a screen coordinate system. The upper left corner of the tile (as displayed by default) is the origin of the coordinate system. The X axis is positive to the right, and the Y axis is positive downward. Coordinates within a geometry MUST be integers. 70 | 71 | A geometry is encoded as a sequence of 32 bit unsigned integers in the `geometry` field of a feature. Each integer is either a `CommandInteger` or a `ParameterInteger`. A decoder interprets these as an ordered series of operations to generate the geometry. 72 | 73 | Commands refer to positions relative to a "cursor", which is a redefinable point. For the first command in a feature, the cursor is at `(0,0)` in the coordinate system. Some commands move the cursor, affecting subsequent commands. 74 | 75 | #### 4.3.1. Command Integers 76 | 77 | A `CommandInteger` indicates a command to be executed, as a command ID, and the number of times that the command will be executed, as a command count. 78 | 79 | A command ID is encoded as an unsigned integer in the least significant 3 bits of the `CommandInteger`, and is in the range 0 through 7, inclusive. A command count is encoded as an unsigned integer in the remaining 29 bits of a `CommandInteger`, and is in the range `0` through `pow(2, 29) - 1`, inclusive. 80 | 81 | A command ID, a command count, and a `CommandInteger` are related by these bitwise operations: 82 | 83 | ```javascript 84 | CommandInteger = (id & 0x7) | (count << 3) 85 | ``` 86 | 87 | ```javascript 88 | id = CommandInteger & 0x7 89 | ``` 90 | 91 | ```javascript 92 | count = CommandInteger >> 3 93 | ``` 94 | 95 | A command ID specifies one of the following commands: 96 | 97 | | Command | Id | Parameters | Parameter Count | 98 | | ------------ |:----:| ------------- | --------------- | 99 | | MoveTo | `1` | `dX`, `dY` | 2 | 100 | | LineTo | `2` | `dX`, `dY` | 2 | 101 | | ClosePath | `7` | No parameters | 0 | 102 | 103 | ##### Example Command Integers 104 | 105 | | Command | ID | Count | CommandInteger | Binary Representation `[Count][Id]` | 106 | | --------- |:----:|:-----:|:--------------:|:----------------------------------------:| 107 | | MoveTo | `1` | `1` | `9` | `[00000000 00000000 0000000 00001][001]` | 108 | | MoveTo | `1` | `120` | `961` | `[00000000 00000000 0000011 11000][001]` | 109 | | LineTo | `2` | `1` | `10` | `[00000000 00000000 0000000 00001][010]` | 110 | | LineTo | `2` | `3` | `26` | `[00000000 00000000 0000000 00011][010]` | 111 | | ClosePath | `7` | `1` | `15` | `[00000000 00000000 0000000 00001][111]` | 112 | 113 | 114 | #### 4.3.2. Parameter Integers 115 | 116 | Commands requiring parameters are followed by a `ParameterInteger` for each parameter required by that command. The number of `ParameterIntegers` that follow a `CommandInteger` is equal to the parameter count of a command multiplied by the command count of the `CommandInteger`. For example, a `CommandInteger` with a `MoveTo` command with a command count of 3 will be followed by 6 `ParameterIntegers`. 117 | 118 | A `ParameterInteger` is [zigzag](https://developers.google.com/protocol-buffers/docs/encoding#types) encoded so that small negative and positive values are both encoded as small integers. To encode a parameter value to a `ParameterInteger` the following formula is used: 119 | 120 | ```javascript 121 | ParameterInteger = (value << 1) ^ (value >> 31) 122 | ``` 123 | 124 | Parameter values greater than `pow(2,31) - 1` or less than `-1 * (pow(2,31) - 1)` are not supported. 125 | 126 | The following formula is used to decode a `ParameterInteger` to a value: 127 | 128 | ```javascript 129 | value = ((ParameterInteger >> 1) ^ (-(ParameterInteger & 1))) 130 | ``` 131 | 132 | #### 4.3.3. Command Types 133 | 134 | For all descriptions of commands the initial position of the cursor shall be described to be at the coordinates `(cX, cY)` where `cX` is the position of the cursor on the X axis and `cY` is the position of the `cursor` on the Y axis. 135 | 136 | ##### 4.3.3.1. MoveTo Command 137 | 138 | A `MoveTo` command with a command count of `n` MUST be immediately followed by `n` pairs of `ParameterInteger`s. Each pair `(dX, dY)`: 139 | 140 | 1. Defines the coordinate `(pX, pY)`, where `pX = cX + dX` and `pY = cY + dY`. 141 | * Within POINT geometries, this coordinate defines a new point. 142 | * Within LINESTRING geometries, this coordinate defines the starting vertex of a new line. 143 | * Within POLYGON geometries, this coordinate defines the starting vertex of a new linear ring. 144 | 2. Moves the cursor to `(pX, pY)`. 145 | 146 | #### 4.3.3.2. LineTo Command 147 | 148 | A `LineTo` command with a command count of `n` MUST be immediately followed by `n` pairs of `ParameterInteger`s. Each pair `(dX, dY)`: 149 | 150 | 1. Defines a segment beginning at the cursor `(cX, cY)` and ending at the coordinate `(pX, pY)`, where `pX = cX + dX` and `pY = cY + dY`. 151 | * Within LINESTRING geometries, this segment extends the current line. 152 | * Within POLYGON geometries, this segment extends the current linear ring. 153 | 2. Moves the cursor to `(pX, pY)`. 154 | 155 | For any pair of `(dX, dY)` the `dX` and `dY` SHOULD NOT both be `0`. 156 | 157 | #### 4.3.3.3. ClosePath Command 158 | 159 | A `ClosePath` command MUST have a command count of 1 and no parameters. The command closes the current linear ring of a POLYGON geometry via a line segment beginning at the cursor `(cX, cY)` and ending at the starting vertex of the current linear ring. 160 | 161 | This command does not change the cursor position. 162 | 163 | #### 4.3.4. Geometry Types 164 | 165 | The `geometry` field is described in each feature by the `type` field which must be a value in the enum `GeomType`. The following geometry types are supported: 166 | 167 | * UNKNOWN 168 | * POINT 169 | * LINESTRING 170 | * POLYGON 171 | 172 | Geometry collections are not supported. 173 | 174 | ##### 4.3.4.1. Unknown Geometry Type 175 | 176 | The specification purposefully leaves an unknown geometry type as an option. This geometry type encodes experimental geometry types that an encoder MAY choose to implement. Decoders MAY ignore any features of this geometry type. 177 | 178 | ##### 4.3.4.2. Point Geometry Type 179 | 180 | The `POINT` geometry type encodes a point or multipoint geometry. The geometry command sequence for a point geometry MUST consist of a single `MoveTo` command with a command count greater than 0. 181 | 182 | If the `MoveTo` command for a `POINT` geometry has a command count of 1, then the geometry MUST be interpreted as a single point; otherwise the geometry MUST be interpreted as a multipoint geometry, wherein each pair of `ParameterInteger`s encodes a single point. 183 | 184 | ##### 4.3.4.3. Linestring Geometry Type 185 | 186 | The `LINESTRING` geometry type encodes a linestring or multilinestring geometry. The geometry command sequence for a linestring geometry MUST consist of one or more repetitions of the following sequence: 187 | 188 | 1. A `MoveTo` command with a command count of 1 189 | 2. A `LineTo` command with a command count greater than 0 190 | 191 | If the command sequence for a `LINESTRING` geometry type includes only a single `MoveTo` command then the geometry MUST be interpreted as a single linestring; otherwise the geometry MUST be interpreted as a multilinestring geometry, wherein each `MoveTo` signals the beginning of a new linestring. 192 | 193 | ##### 4.3.4.4. Polygon Geometry Type 194 | 195 | The `POLYGON` geometry type encodes a polygon or multipolygon geometry, each polygon consisting of exactly one exterior ring that contains zero or more interior rings. The geometry command sequence for a polygon consists of one or more repetitions of the following sequence: 196 | 197 | 1. An `ExteriorRing` 198 | 2. Zero or more `InteriorRing`s 199 | 200 | Each `ExteriorRing` and `InteriorRing` MUST consist of the following sequence: 201 | 202 | 1. A `MoveTo` command with a command count of 1 203 | 2. A `LineTo` command with a command count greater than 1 204 | 3. A `ClosePath` command 205 | 206 | An exterior ring is DEFINED as a linear ring having 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 the tile coordinate system (with the Y axis positive down and X axis positive to the right) this makes the exterior ring's winding order appear clockwise. 207 | 208 | An interior ring is DEFINED as a linear ring having a negative 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 the tile coordinate system (with the Y axis positive down and X axis positive to the right) this makes the interior ring's winding order appear counterclockwise. 209 | 210 | If the command sequence for a `POLYGON` geometry type includes only a single exterior ring then the geometry MUST be interpreted as a single polygon; otherwise the geometry MUST be interpreted as a multipolygon geometry, wherein each exterior ring signals the beginning of a new polygon. If a polygon has interior rings they MUST be encoded directly after the exterior ring of the polygon to which they belong. 211 | 212 | Linear rings MUST be geometric objects that have no anomalous geometric points, such as self-intersection or self-tangency. The position of the cursor before calling the `ClosePath` command of a linear ring SHALL NOT repeat the same position as the first point in the linear ring as this would create a zero-length line segment. A linear ring SHOULD NOT have an area calculated by the surveyor's formula equal to zero, as this would signify a ring with anomalous geometric points. 213 | 214 | Polygon geometries MUST NOT have any interior rings that intersect and interior rings MUST be enclosed by the exterior ring. 215 | 216 | #### 4.3.5. Example Geometry Encodings 217 | 218 | ##### 4.3.5.1. Example Point 219 | 220 | An example encoding of a point located at: 221 | 222 | * (25,7) 223 | 224 | This would require a single command: 225 | 226 | * MoveTo(+25, +17) 227 | 228 | ``` 229 | Encoded as: [ 9 50 34 ] 230 | | | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +17 231 | | `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +25 232 | | ===== relative MoveTo(+25, +17) == create point (25,17) 233 | `> [00001 001] = command id 1 (MoveTo), length 1 234 | ``` 235 | 236 | ##### 4.3.5.2. Example Multi Point 237 | 238 | An example encoding of two points located at: 239 | 240 | * (5,7) 241 | * (3,2) 242 | 243 | This would require two commands: 244 | 245 | * MoveTo(+5,+7) 246 | * MoveTo(-2,-5) 247 | 248 | ``` 249 | Encoded as: [ 17 10 14 3 9 ] 250 | | | | | `> Decoded: ((9 >> 1) ^ (-(9 & 1))) = -5 251 | | | | `> Decoded: ((3 >> 1) ^ (-(3 & 1))) = -2 252 | | | | === relative MoveTo(-2, -5) == create point (3,2) 253 | | | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +7 254 | | `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +5 255 | | ===== relative MoveTo(+25, +17) == create point (25,17) 256 | `> [00010 001] = command id 1 (MoveTo), length 2 257 | ``` 258 | 259 | ##### 4.3.5.3. Example Linestring 260 | 261 | An example encoding of a line with the points: 262 | 263 | * (2,2) 264 | * (2,10) 265 | * (10,10) 266 | 267 | This would require three commands: 268 | 269 | * MoveTo(+2,+2) 270 | * LineTo(+0,+8) 271 | * LineTo(+8,+0) 272 | 273 | ``` 274 | Encoded as: [ 9 4 4 18 0 16 16 0 ] 275 | | | ==== relative LineTo(+8, +0) == Line to Point (10, 10) 276 | | | ==== relative LineTo(+0, +8) == Line to Point (2, 10) 277 | | `> [00010 010] = command id 2 (LineTo), length 2 278 | | === relative MoveTo(+2, +2) 279 | `> [00001 001] = command id 1 (MoveTo), length 1 280 | ``` 281 | 282 | ##### 4.3.5.4. Example Multi Linestring 283 | 284 | An example encoding of two lines with the points: 285 | 286 | * Line 1: 287 | * (2,2) 288 | * (2,10) 289 | * (10,10) 290 | * Line 2: 291 | * (1,1) 292 | * (3,5) 293 | 294 | This would require the following commands: 295 | 296 | * MoveTo(+2,+2) 297 | * LineTo(+0,+8) 298 | * LineTo(+8,+0) 299 | * MoveTo(-9,-9) 300 | * LineTo(+2,+4) 301 | 302 | ``` 303 | Encoded as: [ 9 4 4 18 0 16 16 0 9 17 17 10 4 8 ] 304 | | | | | === relative LineTo(+2, +4) == Line to Point (3,5) 305 | | | | `> [00001 010] = command id 2 (LineTo), length 1 306 | | | | ===== relative MoveTo(-9, -9) == Start new line at (1,1) 307 | | | `> [00001 001] = command id 1 (MoveTo), length 1 308 | | | ==== relative LineTo(+8, +0) == Line to Point (10, 10) 309 | | | ==== relative LineTo(+0, +8) == Line to Point (2, 10) 310 | | `> [00010 010] = command id 2 (LineTo), length 2 311 | | === relative MoveTo(+2, +2) 312 | `> [00001 001] = command id 1 (MoveTo), length 1 313 | ``` 314 | 315 | ##### 4.3.5.5. Example Polygon 316 | 317 | An example encoding of a polygon feature that has the points: 318 | 319 | * (3,6) 320 | * (8,12) 321 | * (20,34) 322 | * (3,6) *Path Closing as Last Point* 323 | 324 | Would encoded by using the following commands: 325 | 326 | * MoveTo(3, 6) 327 | * LineTo(5, 6) 328 | * LineTo(12, 22) 329 | * ClosePath 330 | 331 | ``` 332 | Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 333 | | | `> [00001 111] command id 7 (ClosePath), length 1 334 | | | ===== relative LineTo(+12, +22) == Line to Point (20, 34) 335 | | | ===== relative LineTo(+5, +6) == Line to Point (8, 12) 336 | | `> [00010 010] = command id 2 (LineTo), length 2 337 | | ==== relative MoveTo(+3, +6) 338 | `> [00001 001] = command id 1 (MoveTo), length 1 339 | ``` 340 | 341 | ##### 4.3.5.6. Example Multi Polygon 342 | 343 | An example of a more complex encoding of two polygons, one with a hole. The position of the points for the polygons are shown below. The winding order of the polygons is VERY important in this example as it signifies the difference between interior rings and a new polygon. 344 | 345 | * Polygon 1: 346 | * Exterior Ring: 347 | * (0,0) 348 | * (10,0) 349 | * (10,10) 350 | * (0,10) 351 | * (0,0) *Path Closing as Last Point* 352 | * Polygon 2: 353 | * Exterior Ring: 354 | * (11,11) 355 | * (20,11) 356 | * (20,20) 357 | * (11,20) 358 | * (11,11) *Path Closing as Last Point* 359 | * Interior Ring: 360 | * (13,13) 361 | * (13,17) 362 | * (17,17) 363 | * (17,13) 364 | * (13,13) *Path Closing as Last Point* 365 | 366 | This polygon would be encoded with the following set of commands: 367 | 368 | * MoveTo(+0,+0) 369 | * LineTo(+10,+0) 370 | * LineTo(+0,+10) 371 | * LineTo(-10,+0) // Cursor at 0,10 after this command 372 | * ClosePath // End of Polygon 1 373 | * MoveTo(+11,+1) // NOTE THAT THIS IS RELATIVE TO LAST LINETO! 374 | * LineTo(+9,+0) 375 | * LineTo(+0,+9) 376 | * LineTo(-9,+0) // Cursor at 11,20 after this command 377 | * ClosePath // This is a new polygon because area is positive! 378 | * MoveTo(+2,-7) // NOTE THAT THIS IS RELATIVE TO LAST LINETO! 379 | * LineTo(+0,+4) 380 | * LineTo(+4,+0) 381 | * LineTo(+0,-4) // Cursor at 17,13 382 | * ClosePath // This is an interior ring because area is negative! 383 | 384 | ### 4.4. Feature Attributes 385 | 386 | Feature attributes are encoded as pairs of integers in the `tag` field of a feature. The first integer in each pair represents the zero-based index of the key in the `keys` set of the `layer` to which the feature belongs. The second integer in each pair represents the zero-based index of the value in the `values` set of the `layer` to which the feature belongs. Every key index MUST be unique within that feature such that no other attribute pair within that feature has the same key index. A feature MUST have an even number of `tag` fields. A feature `tag` field MUST NOT contain a key index or value index greater than or equal to the number of elements in the layer's `keys` or `values` set, respectively. 387 | 388 | ### 4.5. Example 389 | 390 | For example, a GeoJSON feature like: 391 | 392 | ```json 393 | { 394 | "type": "FeatureCollection", 395 | "features": [ 396 | { 397 | "geometry": { 398 | "type": "Point", 399 | "coordinates": [ 400 | -8247861.1000836585, 401 | 4970241.327215323 402 | ] 403 | }, 404 | "type": "Feature", 405 | "properties": { 406 | "hello": "world", 407 | "h": "world", 408 | "count": 1.23 409 | } 410 | }, 411 | { 412 | "geometry": { 413 | "type": "Point", 414 | "coordinates": [ 415 | -8247861.1000836585, 416 | 4970241.327215323 417 | ] 418 | }, 419 | "type": "Feature", 420 | "properties": { 421 | "hello": "again", 422 | "count": 2 423 | } 424 | } 425 | ] 426 | } 427 | ``` 428 | 429 | Could be structured like: 430 | 431 | ```js 432 | layers { 433 | version: 2 434 | name: "points" 435 | features: { 436 | id: 1 437 | tags: 0 438 | tags: 0 439 | tags: 1 440 | tags: 0 441 | tags: 2 442 | tags: 1 443 | type: Point 444 | geometry: 9 445 | geometry: 2410 446 | geometry: 3080 447 | } 448 | features { 449 | id: 1 450 | tags: 0 451 | tags: 2 452 | tags: 2 453 | tags: 3 454 | type: Point 455 | geometry: 9 456 | geometry: 2410 457 | geometry: 3080 458 | } 459 | keys: "hello" 460 | keys: "h" 461 | keys: "count" 462 | values: { 463 | string_value: "world" 464 | } 465 | values: { 466 | double_value: 1.23 467 | } 468 | values: { 469 | string_value: "again" 470 | } 471 | values: { 472 | int_value: 2 473 | } 474 | extent: 4096 475 | } 476 | ``` 477 | 478 | Keep in mind the exact values for the geometry would differ based on the projection and extent of the tile. 479 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/2.0/vector_tile.proto: -------------------------------------------------------------------------------- 1 | // Protocol Version 1 2 | 3 | package vector_tile; 4 | 5 | option optimize_for = LITE_RUNTIME; 6 | 7 | message Tile { 8 | 9 | // GeomType is described in section 4.3.4 of the specification 10 | enum GeomType { 11 | UNKNOWN = 0; 12 | POINT = 1; 13 | LINESTRING = 2; 14 | POLYGON = 3; 15 | } 16 | 17 | // Variant type encoding 18 | // The use of values is described in section 4.1 of the specification 19 | message Value { 20 | // Exactly one of these values must be present in a valid message 21 | optional string string_value = 1; 22 | optional float float_value = 2; 23 | optional double double_value = 3; 24 | optional int64 int_value = 4; 25 | optional uint64 uint_value = 5; 26 | optional sint64 sint_value = 6; 27 | optional bool bool_value = 7; 28 | 29 | extensions 8 to max; 30 | } 31 | 32 | // Features are described in section 4.2 of the specification 33 | message Feature { 34 | optional uint64 id = 1 [ default = 0 ]; 35 | 36 | // Tags of this feature are encoded as repeated pairs of 37 | // integers. 38 | // A detailed description of tags is located in sections 39 | // 4.2 and 4.4 of the specification 40 | repeated uint32 tags = 2 [ packed = true ]; 41 | 42 | // The type of geometry stored in this feature. 43 | optional GeomType type = 3 [ default = UNKNOWN ]; 44 | 45 | // Contains a stream of commands and parameters (vertices). 46 | // A detailed description on geometry encoding is located in 47 | // section 4.3 of the specification. 48 | repeated uint32 geometry = 4 [ packed = true ]; 49 | } 50 | 51 | // Layers are described in section 4.1 of the specification 52 | message Layer { 53 | // Any compliant implementation must first read the version 54 | // number encoded in this message and choose the correct 55 | // implementation for this version number before proceeding to 56 | // decode other parts of this message. 57 | required uint32 version = 15 [ default = 1 ]; 58 | 59 | required string name = 1; 60 | 61 | // The actual features in this tile. 62 | repeated Feature features = 2; 63 | 64 | // Dictionary encoding for keys 65 | repeated string keys = 3; 66 | 67 | // Dictionary encoding for values 68 | repeated Value values = 4; 69 | 70 | // The bounding box in this tile spans from 0..4095 units 71 | // Although this is an "optional" field it is required by the specification. 72 | // See https://github.com/mapbox/vector-tile-spec/issues/47 73 | optional uint32 extent = 5 [ default = 4096 ]; 74 | 75 | extensions 16 to max; 76 | } 77 | 78 | repeated Layer layers = 3; 79 | 80 | extensions 16 to 8191; 81 | } 82 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/2.1/README.md: -------------------------------------------------------------------------------- 1 | # Vector Tile Specification 2 | 3 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 4 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in 5 | this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 6 | 7 | ## 1. Purpose 8 | 9 | This document specifies a space-efficient encoding format for tiled geographic vector data. It is designed to be used in browsers or server-side applications for fast rendering or lookups of feature data. 10 | 11 | ## 2. File Format 12 | 13 | The Vector Tile format uses [Google Protocol Buffers](https://developers.google.com/protocol-buffers/) as a encoding format. Protocol Buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. 14 | 15 | ### 2.1. File Extension 16 | 17 | The filename extension for Vector Tile files SHOULD be `mvt`. For example, a file might be named `vector.mvt`. 18 | 19 | ### 2.2. Multipurpose Internet Mail Extensions (MIME) 20 | 21 | When serving Vector Tiles the MIME type SHOULD be `application/vnd.mapbox-vector-tile`. 22 | 23 | ## 3. Projection and Bounds 24 | 25 | A Vector Tile represents data based on a square extent within a projection. A Vector Tile SHOULD NOT contain information about its bounds and projection. The file format assumes that the decoder knows the bounds and projection of a Vector Tile before decoding it. 26 | 27 | [Web Mercator](https://en.wikipedia.org/wiki/Web_Mercator) is the projection of reference, and [the Google tile scheme](http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/) is the tile extent convention of reference. Together, they provide a 1-to-1 relationship between a specific geographical area, at a specific level of detail, and a path such as `https://example.com/17/65535/43602.mvt`. 28 | 29 | Vector Tiles MAY be used to represent data with any projection and tile extent scheme. 30 | 31 | ## 4. Internal Structure 32 | 33 | This specification describes the structure of data within a Vector Tile. The reader should have an understanding of the [Vector Tile protobuf schema document](vector_tile.proto) and the structures it defines. 34 | 35 | ### 4.1. Layers 36 | 37 | A Vector Tile consists of a set of named layers. A layer contains geometric features and their metadata. The layer format is designed so that the data required for a layer is contiguous in memory, and so that layers can be appended to a Vector Tile without modifying existing data. 38 | 39 | A Vector Tile SHOULD contain at least one layer. A layer SHOULD contain at least one feature. 40 | 41 | A layer MUST contain a `version` field with the major version number of the Vector Tile specification to which the layer adheres. For example, a layer adhering to version 2.1 of the specification contains a `version` field with the integer value `2`. The `version` field SHOULD be the first field within the layer. Decoders SHOULD parse the `version` first to ensure that they are capable of decoding each layer. When a Vector Tile consumer encounters a Vector Tile layer with an unknown version, it MAY make a best-effort attempt to interpret the layer, or it MAY skip the layer. In either case it SHOULD continue to process subsequent layers in the Vector Tile. 42 | 43 | A layer MUST contain a `name` field. A Vector Tile MUST NOT contain two or more layers whose `name` values are byte-for-byte identical. Prior to appending a layer to an existing Vector Tile, an encoder MUST check the existing `name` fields in order to prevent duplication. 44 | 45 | Each feature in a layer (see below) may have one or more key-value pairs as its metadata. The keys and values are indices into two lists, `keys` and `values`, that are shared across the layer's features. 46 | 47 | Each element in the `keys` field of the layer is a string. The `keys` include all the keys of features used in the layer, and each key may be referenced by its positional index in this set of `keys`, with the first key having an index of 0. The set of `keys` SHOULD NOT contain two or more values which are byte-for-byte identical. 48 | 49 | Each element in the `values` field of the layer encodes a value of any of several types (see below). The `values` represent all the values of features used in the layer, and each value may be referenced by its positional index in this set of `values`, with the first value having an index of 0. The set of `values` SHOULD NOT contain two or more values of the same type which are byte-for-byte identical. 50 | 51 | In order to support values of varying string, boolean, integer, and floating point types, the protobuf encoding of the `value` field consists of a set of `optional` fields. A value MUST contain exactly one of these optional fields. 52 | 53 | A layer MUST contain an `extent` that describes the width and height of the tile in integer coordinates. The geometries within the Vector Tile MAY extend past the bounds of the tile's area as defined by the `extent`. Geometries that extend past the tile's area as defined by `extent` are often used as a buffer for rendering features that overlap multiple adjacent tiles. 54 | 55 | For example, if a tile has an `extent` of 4096, coordinate units within the tile refer to 1/4096th of its square dimensions. A coordinate of 0 is on the top or left edge of the tile, and a coordinate of 4096 is on the bottom or right edge. Coordinates from 1 through 4095 inclusive are fully within the extent of the tile, and coordinates less than 0 or greater than 4096 are fully outside the extent of the tile. A point at `(1,10)` or `(4095,10)` is within the extent of the tile. A point at `(0,10)` or `(4096,10)` is on the edge of the extent. A point at `(-1,10)` or `(4097,10)` is outside the extent of the tile. 56 | 57 | ### 4.2. Features 58 | 59 | A feature MUST contain a `geometry` field. 60 | 61 | A feature MUST contain a `type` field as described in the Geometry Types section. 62 | 63 | A feature MAY contain a `tags` field. Feature-level metadata, if any, SHOULD be stored in the `tags` field. 64 | 65 | A feature MAY contain an `id` field. If a feature has an `id` field, the value of the `id` SHOULD be unique among the features of the parent layer. 66 | 67 | ### 4.3. Geometry Encoding 68 | 69 | Geometry data in a Vector Tile is defined in a screen coordinate system. The upper left corner of the tile (as displayed by default) is the origin of the coordinate system. The X axis is positive to the right, and the Y axis is positive downward. Coordinates within a geometry MUST be integers. 70 | 71 | A geometry is encoded as a sequence of 32 bit unsigned integers in the `geometry` field of a feature. Each integer is either a `CommandInteger` or a `ParameterInteger`. A decoder interprets these as an ordered series of operations to generate the geometry. 72 | 73 | Commands refer to positions relative to a "cursor", which is a redefinable point. For the first command in a feature, the cursor is at `(0,0)` in the coordinate system. Some commands move the cursor, affecting subsequent commands. 74 | 75 | #### 4.3.1. Command Integers 76 | 77 | A `CommandInteger` indicates a command to be executed, as a command ID, and the number of times that the command will be executed, as a command count. 78 | 79 | A command ID is encoded as an unsigned integer in the least significant 3 bits of the `CommandInteger`, and is in the range 0 through 7, inclusive. A command count is encoded as an unsigned integer in the remaining 29 bits of a `CommandInteger`, and is in the range `0` through `pow(2, 29) - 1`, inclusive. 80 | 81 | A command ID, a command count, and a `CommandInteger` are related by these bitwise operations: 82 | 83 | ```javascript 84 | CommandInteger = (id & 0x7) | (count << 3) 85 | ``` 86 | 87 | ```javascript 88 | id = CommandInteger & 0x7 89 | ``` 90 | 91 | ```javascript 92 | count = CommandInteger >> 3 93 | ``` 94 | 95 | A command ID specifies one of the following commands: 96 | 97 | | Command | Id | Parameters | Parameter Count | 98 | | ------------ |:----:| ------------- | --------------- | 99 | | MoveTo | `1` | `dX`, `dY` | 2 | 100 | | LineTo | `2` | `dX`, `dY` | 2 | 101 | | ClosePath | `7` | No parameters | 0 | 102 | 103 | ##### Example Command Integers 104 | 105 | | Command | ID | Count | CommandInteger | Binary Representation `[Count][Id]` | 106 | | --------- |:----:|:-----:|:--------------:|:----------------------------------------:| 107 | | MoveTo | `1` | `1` | `9` | `[00000000 00000000 0000000 00001][001]` | 108 | | MoveTo | `1` | `120` | `961` | `[00000000 00000000 0000011 11000][001]` | 109 | | LineTo | `2` | `1` | `10` | `[00000000 00000000 0000000 00001][010]` | 110 | | LineTo | `2` | `3` | `26` | `[00000000 00000000 0000000 00011][010]` | 111 | | ClosePath | `7` | `1` | `15` | `[00000000 00000000 0000000 00001][111]` | 112 | 113 | 114 | #### 4.3.2. Parameter Integers 115 | 116 | Commands requiring parameters are followed by a `ParameterInteger` for each parameter required by that command. The number of `ParameterIntegers` that follow a `CommandInteger` is equal to the parameter count of a command multiplied by the command count of the `CommandInteger`. For example, a `CommandInteger` with a `MoveTo` command with a command count of 3 will be followed by 6 `ParameterIntegers`. 117 | 118 | A `ParameterInteger` is [zigzag](https://developers.google.com/protocol-buffers/docs/encoding#types) encoded so that small negative and positive values are both encoded as small integers. To encode a parameter value to a `ParameterInteger` the following formula is used: 119 | 120 | ```javascript 121 | ParameterInteger = (value << 1) ^ (value >> 31) 122 | ``` 123 | 124 | Parameter values greater than `pow(2,31) - 1` or less than `-1 * (pow(2,31) - 1)` are not supported. 125 | 126 | The following formula is used to decode a `ParameterInteger` to a value: 127 | 128 | ```javascript 129 | value = ((ParameterInteger >> 1) ^ (-(ParameterInteger & 1))) 130 | ``` 131 | 132 | #### 4.3.3. Command Types 133 | 134 | For all descriptions of commands the initial position of the cursor shall be described to be at the coordinates `(cX, cY)` where `cX` is the position of the cursor on the X axis and `cY` is the position of the `cursor` on the Y axis. 135 | 136 | ##### 4.3.3.1. MoveTo Command 137 | 138 | A `MoveTo` command with a command count of `n` MUST be immediately followed by `n` pairs of `ParameterInteger`s. Each pair `(dX, dY)`: 139 | 140 | 1. Defines the coordinate `(pX, pY)`, where `pX = cX + dX` and `pY = cY + dY`. 141 | * Within POINT geometries, this coordinate defines a new point. 142 | * Within LINESTRING geometries, this coordinate defines the starting vertex of a new line. 143 | * Within POLYGON geometries, this coordinate defines the starting vertex of a new linear ring. 144 | 2. Moves the cursor to `(pX, pY)`. 145 | 146 | ##### 4.3.3.2. LineTo Command 147 | 148 | A `LineTo` command with a command count of `n` MUST be immediately followed by `n` pairs of `ParameterInteger`s. Each pair `(dX, dY)`: 149 | 150 | 1. Defines a segment beginning at the cursor `(cX, cY)` and ending at the coordinate `(pX, pY)`, where `pX = cX + dX` and `pY = cY + dY`. 151 | * Within LINESTRING geometries, this segment extends the current line. 152 | * Within POLYGON geometries, this segment extends the current linear ring. 153 | 2. Moves the cursor to `(pX, pY)`. 154 | 155 | For any pair of `(dX, dY)` the `dX` and `dY` MUST NOT both be `0`. 156 | 157 | ##### 4.3.3.3. ClosePath Command 158 | 159 | A `ClosePath` command MUST have a command count of 1 and no parameters. The command closes the current linear ring of a POLYGON geometry via a line segment beginning at the cursor `(cX, cY)` and ending at the starting vertex of the current linear ring. 160 | 161 | This command does not change the cursor position. 162 | 163 | #### 4.3.4. Geometry Types 164 | 165 | The `geometry` field is described in each feature by the `type` field which must be a value in the enum `GeomType`. The following geometry types are supported: 166 | 167 | * UNKNOWN 168 | * POINT 169 | * LINESTRING 170 | * POLYGON 171 | 172 | Geometry collections are not supported. 173 | 174 | ##### 4.3.4.1. Unknown Geometry Type 175 | 176 | The specification purposefully leaves an unknown geometry type as an option. This geometry type encodes experimental geometry types that an encoder MAY choose to implement. Decoders MAY ignore any features of this geometry type. 177 | 178 | ##### 4.3.4.2. Point Geometry Type 179 | 180 | The `POINT` geometry type encodes a point or multipoint geometry. The geometry command sequence for a point geometry MUST consist of a single `MoveTo` command with a command count greater than 0. 181 | 182 | If the `MoveTo` command for a `POINT` geometry has a command count of 1, then the geometry MUST be interpreted as a single point; otherwise the geometry MUST be interpreted as a multipoint geometry, wherein each pair of `ParameterInteger`s encodes a single point. 183 | 184 | ##### 4.3.4.3. Linestring Geometry Type 185 | 186 | The `LINESTRING` geometry type encodes a linestring or multilinestring geometry. The geometry command sequence for a linestring geometry MUST consist of one or more repetitions of the following sequence: 187 | 188 | 1. A `MoveTo` command with a command count of 1 189 | 2. A `LineTo` command with a command count greater than 0 190 | 191 | If the command sequence for a `LINESTRING` geometry type includes only a single `MoveTo` command then the geometry MUST be interpreted as a single linestring; otherwise the geometry MUST be interpreted as a multilinestring geometry, wherein each `MoveTo` signals the beginning of a new linestring. 192 | 193 | ##### 4.3.4.4. Polygon Geometry Type 194 | 195 | The `POLYGON` geometry type encodes a polygon or multipolygon geometry, each polygon consisting of exactly one exterior ring that contains zero or more interior rings. The geometry command sequence for a polygon consists of one or more repetitions of the following sequence: 196 | 197 | 1. An `ExteriorRing` 198 | 2. Zero or more `InteriorRing`s 199 | 200 | Each `ExteriorRing` and `InteriorRing` MUST consist of the following sequence: 201 | 202 | 1. A `MoveTo` command with a command count of 1 203 | 2. A `LineTo` command with a command count greater than 1 204 | 3. A `ClosePath` command 205 | 206 | An exterior ring is DEFINED as a linear ring having 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 the tile coordinate system (with the Y axis positive down and X axis positive to the right) this makes the exterior ring's winding order appear clockwise. 207 | 208 | An interior ring is DEFINED as a linear ring having a negative 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 the tile coordinate system (with the Y axis positive down and X axis positive to the right) this makes the interior ring's winding order appear counterclockwise. 209 | 210 | If the command sequence for a `POLYGON` geometry type includes only a single exterior ring then the geometry MUST be interpreted as a single polygon; otherwise the geometry MUST be interpreted as a multipolygon geometry, wherein each exterior ring signals the beginning of a new polygon. If a polygon has interior rings they MUST be encoded directly after the exterior ring of the polygon to which they belong. 211 | 212 | Linear rings MUST be geometric objects that have no anomalous geometric points, such as self-intersection or self-tangency. The position of the cursor before calling the `ClosePath` command of a linear ring SHALL NOT repeat the same position as the first point in the linear ring as this would create a zero-length line segment. A linear ring SHOULD NOT have an area calculated by the surveyor's formula equal to zero, as this would signify a ring with anomalous geometric points. 213 | 214 | Polygon geometries MUST NOT have any interior rings that intersect and interior rings MUST be enclosed by the exterior ring. 215 | 216 | #### 4.3.5. Example Geometry Encodings 217 | 218 | ##### 4.3.5.1. Example Point 219 | 220 | An example encoding of a point located at: 221 | 222 | * (25,17) 223 | 224 | This would require a single command: 225 | 226 | * MoveTo(+25, +17) 227 | 228 | ``` 229 | Encoded as: [ 9 50 34 ] 230 | | | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +17 231 | | `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +25 232 | | ===== relative MoveTo(+25, +17) == create point (25,17) 233 | `> [00001 001] = command id 1 (MoveTo), command count 1 234 | ``` 235 | 236 | ##### 4.3.5.2. Example Multi Point 237 | 238 | An example encoding of two points located at: 239 | 240 | * (5,7) 241 | * (3,2) 242 | 243 | This would require two commands: 244 | 245 | * MoveTo(+5,+7) 246 | * MoveTo(-2,-5) 247 | 248 | ``` 249 | Encoded as: [ 17 10 14 3 9 ] 250 | | | | | `> Decoded: ((9 >> 1) ^ (-(9 & 1))) = -5 251 | | | | `> Decoded: ((3 >> 1) ^ (-(3 & 1))) = -2 252 | | | | === relative MoveTo(-2, -5) == create point (3,2) 253 | | | `> Decoded: ((34 >> 1) ^ (-(34 & 1))) = +7 254 | | `> Decoded: ((50 >> 1) ^ (-(50 & 1))) = +5 255 | | ===== relative MoveTo(+25, +17) == create point (25,17) 256 | `> [00010 001] = command id 1 (MoveTo), command count 2 257 | ``` 258 | 259 | ##### 4.3.5.3. Example Linestring 260 | 261 | An example encoding of a line with the points: 262 | 263 | * (2,2) 264 | * (2,10) 265 | * (10,10) 266 | 267 | This would require three commands: 268 | 269 | * MoveTo(+2,+2) 270 | * LineTo(+0,+8) 271 | * LineTo(+8,+0) 272 | 273 | ``` 274 | Encoded as: [ 9 4 4 18 0 16 16 0 ] 275 | | | ==== relative LineTo(+8, +0) == Line to Point (10, 10) 276 | | | ==== relative LineTo(+0, +8) == Line to Point (2, 10) 277 | | `> [00010 010] = command id 2 (LineTo), command count 2 278 | | === relative MoveTo(+2, +2) 279 | `> [00001 001] = command id 1 (MoveTo), command count 1 280 | ``` 281 | 282 | ##### 4.3.5.4. Example Multi Linestring 283 | 284 | An example encoding of two lines with the points: 285 | 286 | * Line 1: 287 | * (2,2) 288 | * (2,10) 289 | * (10,10) 290 | * Line 2: 291 | * (1,1) 292 | * (3,5) 293 | 294 | This would require the following commands: 295 | 296 | * MoveTo(+2,+2) 297 | * LineTo(+0,+8) 298 | * LineTo(+8,+0) 299 | * MoveTo(-9,-9) 300 | * LineTo(+2,+4) 301 | 302 | ``` 303 | Encoded as: [ 9 4 4 18 0 16 16 0 9 17 17 10 4 8 ] 304 | | | | | === relative LineTo(+2, +4) == Line to Point (3,5) 305 | | | | `> [00001 010] = command id 2 (LineTo), command count 1 306 | | | | ===== relative MoveTo(-9, -9) == Start new line at (1,1) 307 | | | `> [00001 001] = command id 1 (MoveTo), command count 1 308 | | | ==== relative LineTo(+8, +0) == Line to Point (10, 10) 309 | | | ==== relative LineTo(+0, +8) == Line to Point (2, 10) 310 | | `> [00010 010] = command id 2 (LineTo), command count 2 311 | | === relative MoveTo(+2, +2) 312 | `> [00001 001] = command id 1 (MoveTo), command count 1 313 | ``` 314 | 315 | ##### 4.3.5.5. Example Polygon 316 | 317 | An example encoding of a polygon feature that has the points: 318 | 319 | * (3,6) 320 | * (8,12) 321 | * (20,34) 322 | * (3,6) *Path Closing as Last Point* 323 | 324 | Would encoded by using the following commands: 325 | 326 | * MoveTo(3, 6) 327 | * LineTo(5, 6) 328 | * LineTo(12, 22) 329 | * ClosePath 330 | 331 | ``` 332 | Encoded as: [ 9 6 12 18 10 12 24 44 15 ] 333 | | | `> [00001 111] command id 7 (ClosePath), command count 1 334 | | | ===== relative LineTo(+12, +22) == Line to Point (20, 34) 335 | | | ===== relative LineTo(+5, +6) == Line to Point (8, 12) 336 | | `> [00010 010] = command id 2 (LineTo), command count 2 337 | | ==== relative MoveTo(+3, +6) 338 | `> [00001 001] = command id 1 (MoveTo), command count 1 339 | ``` 340 | 341 | ##### 4.3.5.6. Example Multi Polygon 342 | 343 | An example of a more complex encoding of two polygons, one with a hole. The position of the points for the polygons are shown below. The winding order of the polygons is VERY important in this example as it signifies the difference between interior rings and a new polygon. 344 | 345 | * Polygon 1: 346 | * Exterior Ring: 347 | * (0,0) 348 | * (10,0) 349 | * (10,10) 350 | * (0,10) 351 | * (0,0) *Path Closing as Last Point* 352 | * Polygon 2: 353 | * Exterior Ring: 354 | * (11,11) 355 | * (20,11) 356 | * (20,20) 357 | * (11,20) 358 | * (11,11) *Path Closing as Last Point* 359 | * Interior Ring: 360 | * (13,13) 361 | * (13,17) 362 | * (17,17) 363 | * (17,13) 364 | * (13,13) *Path Closing as Last Point* 365 | 366 | This polygon would be encoded with the following set of commands: 367 | 368 | * MoveTo(+0,+0) 369 | * LineTo(+10,+0) 370 | * LineTo(+0,+10) 371 | * LineTo(-10,+0) // Cursor at 0,10 after this command 372 | * ClosePath // End of Polygon 1 373 | * MoveTo(+11,+1) // NOTE THAT THIS IS RELATIVE TO LAST LINETO! 374 | * LineTo(+9,+0) 375 | * LineTo(+0,+9) 376 | * LineTo(-9,+0) // Cursor at 11,20 after this command 377 | * ClosePath // This is a new polygon because area is positive! 378 | * MoveTo(+2,-7) // NOTE THAT THIS IS RELATIVE TO LAST LINETO! 379 | * LineTo(+0,+4) 380 | * LineTo(+4,+0) 381 | * LineTo(+0,-4) // Cursor at 17,13 382 | * ClosePath // This is an interior ring because area is negative! 383 | 384 | ### 4.4. Feature Attributes 385 | 386 | Feature attributes are encoded as pairs of integers in the `tag` field of a feature. The first integer in each pair represents the zero-based index of the key in the `keys` set of the `layer` to which the feature belongs. The second integer in each pair represents the zero-based index of the value in the `values` set of the `layer` to which the feature belongs. Every key index MUST be unique within that feature such that no other attribute pair within that feature has the same key index. A feature MUST have an even number of `tag` fields. A feature `tag` field MUST NOT contain a key index or value index greater than or equal to the number of elements in the layer's `keys` or `values` set, respectively. 387 | 388 | ### 4.5. Example 389 | 390 | For example, a GeoJSON feature like: 391 | 392 | ```json 393 | { 394 | "type": "FeatureCollection", 395 | "features": [ 396 | { 397 | "geometry": { 398 | "type": "Point", 399 | "coordinates": [ 400 | -8247861.1000836585, 401 | 4970241.327215323 402 | ] 403 | }, 404 | "type": "Feature", 405 | "properties": { 406 | "hello": "world", 407 | "h": "world", 408 | "count": 1.23 409 | } 410 | }, 411 | { 412 | "geometry": { 413 | "type": "Point", 414 | "coordinates": [ 415 | -8247861.1000836585, 416 | 4970241.327215323 417 | ] 418 | }, 419 | "type": "Feature", 420 | "properties": { 421 | "hello": "again", 422 | "count": 2 423 | } 424 | } 425 | ] 426 | } 427 | ``` 428 | 429 | Could be structured like: 430 | 431 | ```js 432 | layers { 433 | version: 2 434 | name: "points" 435 | features: { 436 | id: 1 437 | tags: 0 438 | tags: 0 439 | tags: 1 440 | tags: 0 441 | tags: 2 442 | tags: 1 443 | type: Point 444 | geometry: 9 445 | geometry: 2410 446 | geometry: 3080 447 | } 448 | features { 449 | id: 2 450 | tags: 0 451 | tags: 2 452 | tags: 2 453 | tags: 3 454 | type: Point 455 | geometry: 9 456 | geometry: 2410 457 | geometry: 3080 458 | } 459 | keys: "hello" 460 | keys: "h" 461 | keys: "count" 462 | values: { 463 | string_value: "world" 464 | } 465 | values: { 466 | double_value: 1.23 467 | } 468 | values: { 469 | string_value: "again" 470 | } 471 | values: { 472 | int_value: 2 473 | } 474 | extent: 4096 475 | } 476 | ``` 477 | 478 | Keep in mind the exact values for the geometry would differ based on the projection and extent of the tile. 479 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/2.1/vector_tile.proto: -------------------------------------------------------------------------------- 1 | package vector_tile; 2 | 3 | option optimize_for = LITE_RUNTIME; 4 | 5 | message Tile { 6 | 7 | // GeomType is described in section 4.3.4 of the specification 8 | enum GeomType { 9 | UNKNOWN = 0; 10 | POINT = 1; 11 | LINESTRING = 2; 12 | POLYGON = 3; 13 | } 14 | 15 | // Variant type encoding 16 | // The use of values is described in section 4.1 of the specification 17 | message Value { 18 | // Exactly one of these values must be present in a valid message 19 | optional string string_value = 1; 20 | optional float float_value = 2; 21 | optional double double_value = 3; 22 | optional int64 int_value = 4; 23 | optional uint64 uint_value = 5; 24 | optional sint64 sint_value = 6; 25 | optional bool bool_value = 7; 26 | 27 | extensions 8 to max; 28 | } 29 | 30 | // Features are described in section 4.2 of the specification 31 | message Feature { 32 | optional uint64 id = 1 [ default = 0 ]; 33 | 34 | // Tags of this feature are encoded as repeated pairs of 35 | // integers. 36 | // A detailed description of tags is located in sections 37 | // 4.2 and 4.4 of the specification 38 | repeated uint32 tags = 2 [ packed = true ]; 39 | 40 | // The type of geometry stored in this feature. 41 | optional GeomType type = 3 [ default = UNKNOWN ]; 42 | 43 | // Contains a stream of commands and parameters (vertices). 44 | // A detailed description on geometry encoding is located in 45 | // section 4.3 of the specification. 46 | repeated uint32 geometry = 4 [ packed = true ]; 47 | } 48 | 49 | // Layers are described in section 4.1 of the specification 50 | message Layer { 51 | // Any compliant implementation must first read the version 52 | // number encoded in this message and choose the correct 53 | // implementation for this version number before proceeding to 54 | // decode other parts of this message. 55 | required uint32 version = 15 [ default = 1 ]; 56 | 57 | required string name = 1; 58 | 59 | // The actual features in this tile. 60 | repeated Feature features = 2; 61 | 62 | // Dictionary encoding for keys 63 | repeated string keys = 3; 64 | 65 | // Dictionary encoding for values 66 | repeated Value values = 4; 67 | 68 | // Although this is an "optional" field it is required by the specification. 69 | // See https://github.com/mapbox/vector-tile-spec/issues/47 70 | optional uint32 extent = 5 [ default = 4096 ]; 71 | 72 | extensions 16 to max; 73 | } 74 | 75 | repeated Layer layers = 3; 76 | 77 | extensions 16 to 8191; 78 | } 79 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Vector Tile Spec Changelog 2 | 3 | ### 2.1 4 | 5 | The 2.1 update of the specification is a correction to the wording in a few locations of the 2.0 specification. The wording of the specification is slightly changed in 2.1, but reflects important concepts that were improperly described by the 2.0 specification. 6 | 7 | #### Summary of Changes: 8 | 9 | - Changed the meaning of `extent` to reflect how all known implementations of the specification use extent. 10 | - Changed the wording to make it such that `LineTo(0,0)` is an invalid command by changing wording from SHOULD to MUST. 11 | - Added `CONTRIBUTING.md` file 12 | 13 | #### Issues: 14 | 15 | List of issues addressed by this version: 16 | 17 | - [#54](https://github.com/mapbox/vector-tile-spec/issues/54) 18 | - [#51](https://github.com/mapbox/vector-tile-spec/issues/51) 19 | 20 | #### Date of Release: 21 | 22 | January 19th, 2016 23 | 24 | ### 2.0 25 | 26 | The focus of version `2.0` of the Mapbox Vector Tile specification is the clarification of the intent of the intial version of the specification and the definition of interior and exterior rings within polygons. The fields within the protobuffer are more clearly defined in this version of the specification and the steps for decoders and encoders are more explicity declared. 27 | 28 | The version numbering of the specification is now more clearly defined as well as part of the `2.0` changes, migrating from a `major.minor.patch` versioning to a `major.minor` versioning. 29 | 30 | Sections to the specification have been introduced to improve readablility. There are now more examples of the geometry encoding process to ease understanding of the concepts within the specification. 31 | 32 | The file [CONTRIBUTING.md] has been added to the repository to better define a repeatable process for changing the specification. 33 | 34 | #### Summary of Changes: 35 | 36 | - 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 CW and interior rings must be oriented CCW (when viewed in screen coordinates). 37 | - Noted that first point does not have to be the same as last point prior to calling `ClosePath`. 38 | - Polygon geometries now must not have self intersections or self tangency. (Example: spikes in rings) 39 | - Addded definition of linear ring. 40 | - Clarified that `UNKNOWN` geometry types may be ignored and that it is experimental. 41 | - Required the use of the `version` field in layers. 42 | - Required that layers of a tile not have the same `name` field as any other layer. 43 | - Explained differences between geometry types. 44 | - Added explanation of how to handle multipoint, multilines, and multipolygons geometries. 45 | - Migrated the encoding logic from `proto` file to the README, adding many clarifications. 46 | - Explained the different commands used in encoding. 47 | - Added the concept of the `cursor` when encoding and decoding a vector tile. 48 | - Explained the coordinate system of a vector tile. 49 | - Made it clear that specification could be used in projections other than Mercator. 50 | - Defined more clearly feature attributes and how they are handled. 51 | - `LineTo` command should not resolve to same position - ex: `LineTo(0,0)`. 52 | - Changed the way that versioning of the specification is handled. 53 | - Updated Authors 54 | - Added `CONTRIBUTING.md` file 55 | 56 | #### Issues: 57 | 58 | List of issues addressed by this version: 59 | 60 | - [#43](https://github.com/mapbox/vector-tile-spec/issues/43) 61 | - [#41](https://github.com/mapbox/vector-tile-spec/issues/41) 62 | - [#30](https://github.com/mapbox/vector-tile-spec/issues/30) 63 | - [#29](https://github.com/mapbox/vector-tile-spec/issues/29) 64 | - [#27](https://github.com/mapbox/vector-tile-spec/issues/27) 65 | - [#25](https://github.com/mapbox/vector-tile-spec/issues/25) 66 | - [#24](https://github.com/mapbox/vector-tile-spec/issues/24) 67 | - [#18](https://github.com/mapbox/vector-tile-spec/issues/18) 68 | - [#16](https://github.com/mapbox/vector-tile-spec/issues/16) 69 | - [#15](https://github.com/mapbox/vector-tile-spec/issues/15) 70 | - [#7](https://github.com/mapbox/vector-tile-spec/issues/7) 71 | - [#5](https://github.com/mapbox/vector-tile-spec/issues/5) 72 | 73 | #### Date of Release: 74 | 75 | December 4th, 2015 76 | 77 | ### 1.0.1 78 | 79 | - Used TitleCase and UPPERCASE in `vector_tile.proto` to match Protobuf style guide (#3) 80 | - Changed namespace from `mapnik.vector` to `vector_tile` (#2) 81 | 82 | ### 1.0.0 83 | 84 | - First release 85 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Open Standard 2 | 3 | The Mapbox Vector Tile specification is an open standard maintained by [Mapbox](https://www.mapbox.com/about/open/). 4 | 5 | ## Questions and Contributing 6 | 7 | All specification development happens at the [github repository for the specification](https://github.com/mapbox/vector-tile-spec). 8 | 9 | For general questions relating to the specification please feel free to create a new [issue](https://github.com/mapbox/vector-tile-spec/issues). 10 | 11 | ### Proposing Changes 12 | 13 | Editorial changes that clarify the specification are encouraged. Edits can be submitted as a pull request to against the `master` branch of the latest version of the specification. Review and discussion of the proposed changes will take place on this pull request. Changes may warrant a bump in the `minor` version of the specification. 14 | 15 | Technical changes to the specification are an important part of the evolution of the standard. Technical changes imply new requirements for encoders and decoders of the format. Therefore a technical change requires the `major` version to be incremented and will be carefully reviewed and considered by implementors of the specification. Technical changes are best discussed in individual [issues](https://github.com/mapbox/vector-tile-spec/issues) prior to a change in the specification. Please be concise in any suggestions and read existing issues prior to posting. 16 | 17 | ### Syntax Notes 18 | 19 | Consideration should be taken over the uses of the keywords as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). The use of these words must be capitalized to stress their meaning through out the specification. 20 | 21 | The use of fields as defined in the proto file should be `highlighted`. 22 | 23 | ## Releasing A New Version 24 | 25 | The following is the suggested way to release a new version of the specification. 26 | 27 | Upon determination that a significant need for a version change is required a pull request to the specification should be opened. The branch from which the pull request originates should be named clearly to note it is a request for a new version of the specification. For example a branch of `v3.0-development` would specify the grouping of changes for the `v3.0` specification. This pull request should create a new folder for the version of the specification that will be created. For the `v3.0` specification a `3.0` folder would be created. Within this folder should be the `proto` file for the version and a `README.md` file that is a full update of the specification. The `CHANGELOG.md` should also include all relevant information on changes that are proposed. 28 | 29 | The pull request should provide a clear explanation of the intent for the new version of the specification. All associated issues should be linked in the pull request. Suggested changes to the branch of the development version will be accepted in the form of pull request to that branch. 30 | 31 | Once all issues with the pull request have been addressed, the pull request may be merged into the master branch. 32 | 33 | Update the changelog with the date of release of the official specification in a new commit to the `master` branch. Push your updates to the repository. Once this is done create an official tag of the release on github. 34 | 35 | ```sh 36 | git tag -a v2.0 -m "v2.0" 37 | git push --tags 38 | ``` 39 | 40 | ## Authors 41 | 42 | If you make a change and wish to be added to the list of authors please add yourself to the README.md. (Note: It is alphabetical by last name). 43 | 44 | -------------------------------------------------------------------------------- /third-party/vector-tile-spec/README.md: -------------------------------------------------------------------------------- 1 | # Mapbox Vector Tile Specification 2 | 3 | A specification for encoding tiled vector data. 4 | 5 | ## License 6 | 7 | The text of this specification is licensed under a 8 | [Creative Commons Attribution 3.0 United States License](http://creativecommons.org/licenses/by/3.0/us/). 9 | However, the use of this spec in products and code is entirely free: 10 | there are no royalties, restrictions, or requirements. 11 | 12 | ## [Implementations](https://github.com/mapbox/vector-tile-spec/wiki/Implementations) 13 | 14 | ## Versioning 15 | 16 | The specification is versioned based on `major.minor` notation. The `major` version will be incremented with any technical change to the specification format or way it should be interpreted. Changes to the `minor` version will be reserved for any clarification or correction of clerical errors associated with the specification language. 17 | 18 | The `major` version in the specification name is synonymous with the `version` field in a Mapbox Vector Tile layer. See the `3.1. Layers` section for more details. 19 | 20 | 21 | ## Contributing 22 | 23 | If you are interested in contributing please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file. 24 | 25 | ## Authors 26 | 27 | * Vladimir Agafonkin 28 | * John Firebaugh 29 | * Eric Fischer 30 | * Konstantin Käfer 31 | * Charlie Loyd 32 | * Tom MacWright 33 | * Artem Pavlenko 34 | * Dane Springmeyer 35 | * Blake Thompson 36 | 37 | ## Translations 38 | 39 | * [简体中文](https://github.com/jingsam/vector-tile-spec/blob/master/2.1/README_zh.md) 40 | --------------------------------------------------------------------------------