| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | ###
 | 
					
						
							|  |  |  |   termap - Terminal Map Viewer | 
					
						
							|  |  |  |   by Michael Strassburger <codepoet@cpan.org> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Handling of and access to single VectorTiles | 
					
						
							|  |  |  | ###
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | VectorTile = require('vector-tile').VectorTile | 
					
						
							|  |  |  | Protobuf = require 'pbf' | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  | Promise = require 'bluebird' | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | zlib = require 'zlib' | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  | rbush = require 'rbush' | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  | class Tile | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  |   layers: {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  |   load: (buffer) -> | 
					
						
							|  |  |  |     @_unzipIfNeeded buffer | 
					
						
							|  |  |  |     .then (data) => @_loadTile data | 
					
						
							|  |  |  |     .then (tile) => @_loadLayers tile | 
					
						
							|  |  |  |     .then => this | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _loadTile: (buffer) -> | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  |     @tile = new VectorTile new Protobuf buffer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _unzipIfNeeded: (buffer) -> | 
					
						
							|  |  |  |     new Promise (resolve, reject) => | 
					
						
							|  |  |  |       if @_isGzipped buffer | 
					
						
							|  |  |  |         zlib.gunzip buffer, (err, data) -> | 
					
						
							|  |  |  |           return reject err if err | 
					
						
							|  |  |  |           resolve data | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         resolve buffer | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _isGzipped: (buffer) -> | 
					
						
							|  |  |  |     buffer.slice(0,2).indexOf(Buffer.from([0x1f, 0x8b])) is 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  |   _loadLayers: (tile) -> | 
					
						
							|  |  |  |     layers = {} | 
					
						
							|  |  |  |     for name, layer of tile.layers | 
					
						
							|  |  |  |       tree = rbush() | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  |       features = for i in [0...layer.length] | 
					
						
							|  |  |  |         # TODO: caching of similar attributes to avoid looking up the style each time
 | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  |         #continue if @styler and not @styler.getStyleFor layer, feature
 | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         feature = layer.feature i | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         type = feature.properties.$type =
 | 
					
						
							|  |  |  |           [undefined, "Point", "LineString", "Polygon"][feature.type] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-06 13:15:30 +00:00
										 |  |  |         # TODO: monkey patching test case for tiles with a reduced extent
 | 
					
						
							|  |  |  |         geo = for sub, i in feature.loadGeometry() | 
					
						
							|  |  |  |           points = [] | 
					
						
							|  |  |  |           last = null | 
					
						
							|  |  |  |           for point, j in sub | 
					
						
							|  |  |  |             p =
 | 
					
						
							|  |  |  |               x: Math.floor point.x/8 | 
					
						
							|  |  |  |               y: Math.floor point.y/8 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if last and last.x is p.x and last.y is p.y | 
					
						
							|  |  |  |               continue | 
					
						
							|  |  |  |             points.push p | 
					
						
							|  |  |  |             last = p | 
					
						
							|  |  |  |           points | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  |         data =
 | 
					
						
							| 
									
										
										
										
											2016-11-06 13:15:30 +00:00
										 |  |  |           points: geo | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  |           properties: feature.properties | 
					
						
							|  |  |  |           id: feature.id | 
					
						
							|  |  |  |           type: type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @_addToTree tree, data | 
					
						
							|  |  |  |         data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  |       layers[name] = tree: tree, features: features | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @layers = layers | 
					
						
							| 
									
										
										
										
											2016-09-22 03:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   _addToTree: (tree, data) -> | 
					
						
							|  |  |  |     [minX, maxX, minY, maxY] = [Infinity, -Infinity, Infinity, -Infinity] | 
					
						
							|  |  |  |     for outer in data.points | 
					
						
							|  |  |  |       for p in outer | 
					
						
							|  |  |  |         minX = p.x if p.x < minX | 
					
						
							|  |  |  |         maxX = p.x if p.x > maxX | 
					
						
							|  |  |  |         minY = p.y if p.y < minY | 
					
						
							|  |  |  |         maxY = p.y if p.y > maxY | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tree.insert | 
					
						
							|  |  |  |       minX: minX | 
					
						
							|  |  |  |       maxX: maxX | 
					
						
							|  |  |  |       minY: minY | 
					
						
							|  |  |  |       maxY: maxY | 
					
						
							|  |  |  |       data: data | 
					
						
							| 
									
										
										
										
											2016-11-03 00:25:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | module.exports = Tile |