mirror of
https://github.com/rastapasta/mapscii.git
synced 2024-11-21 23:53:08 +01:00
🔮 abstracting tile handling, preparing usage of spatial indexing
This commit is contained in:
parent
0877eaca86
commit
11c2f1f544
4
main.js
4
main.js
@ -12,10 +12,12 @@ require('coffee-script/register');
|
||||
|
||||
const fs = require('fs');
|
||||
const Termap = require(__dirname+'/src/Termap');
|
||||
const Tile = require(__dirname+'/src/Tile')
|
||||
|
||||
termap = new Termap();
|
||||
|
||||
// TODO: abstracing this class, create loader class
|
||||
data = fs.readFileSync(__dirname+"/tiles/regensburg.pbf.gz");
|
||||
termap.renderer.features = termap.renderer._getFeatures(termap.renderer._parseTile(data));
|
||||
tile = new Tile(data);
|
||||
termap.renderer.features = tile.layers
|
||||
termap._draw();
|
||||
|
@ -5,9 +5,6 @@
|
||||
The Console Vector Tile renderer - bäm!
|
||||
###
|
||||
x256 = require 'x256'
|
||||
Protobuf = require 'pbf'
|
||||
VectorTile = require('vector-tile').VectorTile
|
||||
zlib = require 'zlib'
|
||||
triangulator = new (require('pnltri')).Triangulator()
|
||||
|
||||
Canvas = require './Canvas'
|
||||
@ -66,29 +63,6 @@ module.exports = class Renderer
|
||||
setSize: (@width, @height) ->
|
||||
@canvas = new Canvas @width, @height
|
||||
|
||||
_parseTile: (buffer) ->
|
||||
# extract, decode and parse a given tile buffer
|
||||
new VectorTile new Protobuf zlib.gunzipSync buffer
|
||||
|
||||
_getFeatures: (tile) ->
|
||||
features = {}
|
||||
for name,layer of tile.layers
|
||||
continue unless @config.layers[name]
|
||||
|
||||
features[name] = for i in [0...layer.length]
|
||||
feature = layer.feature i
|
||||
type = [undefined, "Point", "LineString", "Polygon"][feature.type]
|
||||
|
||||
properties = feature.properties
|
||||
properties.$type = type
|
||||
|
||||
id: feature.id
|
||||
type: type
|
||||
properties: properties
|
||||
points: feature.loadGeometry()
|
||||
|
||||
features
|
||||
|
||||
draw: (@view, @zoom) ->
|
||||
return if @isDrawing
|
||||
@isDrawing = true
|
||||
@ -118,51 +92,34 @@ module.exports = class Renderer
|
||||
process.stdout.write output
|
||||
|
||||
_drawLayers: ->
|
||||
drawn = []
|
||||
for layer in @config.drawOrder
|
||||
continue unless @features?[layer]
|
||||
|
||||
@notify "rendering #{layer}..."
|
||||
scale = Math.pow 2, @zoom
|
||||
continue unless @features?[layer]
|
||||
|
||||
if @config.layers[layer].minZoom and @zoom > @config.layers[layer].minZoom
|
||||
continue
|
||||
|
||||
@canvas.strokeStyle = @canvas.fillStyle = @config.layers[layer].color
|
||||
|
||||
for feature in @features[layer]
|
||||
if @_drawFeature layer, feature, scale
|
||||
drawn.push feature
|
||||
|
||||
drawn
|
||||
for feature in @features[layer].tree.search(minX: 0, minY: 0, maxX: 4096, maxY: 4096)
|
||||
@_drawFeature layer, feature.data, scale
|
||||
|
||||
_drawFeature: (layer, feature, scale) ->
|
||||
# TODO: this is ugly :) need to be fixed @style
|
||||
#return false if feature.properties.class is "ferry"
|
||||
feature.type = "LineString" if layer is "building" or layer is "road"
|
||||
|
||||
toDraw = []
|
||||
for idx, points of feature.points
|
||||
visible = false
|
||||
|
||||
projectedPoints = for point in points
|
||||
projectedPoint =
|
||||
x: point.x/scale
|
||||
y: point.y/scale
|
||||
|
||||
visible = true if not visible and @_isOnScreen projectedPoint
|
||||
projectedPoint
|
||||
|
||||
if idx is 0 and not visible
|
||||
return false
|
||||
|
||||
continue unless visible
|
||||
toDraw.push projectedPoints
|
||||
|
||||
# TODO: zoom level
|
||||
unless style = @styler.getStyleFor layer, feature, 14
|
||||
return false
|
||||
|
||||
color = style.paint['line-color'] or style.paint['fill-color'] or style.paint['text-color']
|
||||
|
||||
toDraw = for points in feature.points
|
||||
for point in points
|
||||
x: point.x/scale
|
||||
y: point.y/scale
|
||||
|
||||
# TODO: zoom calculation todo for perfect styling
|
||||
if color instanceof Object
|
||||
color = color.stops[0][1]
|
||||
|
@ -39,10 +39,7 @@ module.exports = class Styler
|
||||
false
|
||||
|
||||
_compileFilter: (filter) ->
|
||||
if not filter or not filter.length
|
||||
return -> true
|
||||
|
||||
switch filter[0]
|
||||
switch filter?[0]
|
||||
when "all"
|
||||
filters = (@_compileFilter subFilter for subFilter in filter[1..])
|
||||
(feature) ->
|
||||
@ -64,3 +61,6 @@ module.exports = class Styler
|
||||
(feature) ->
|
||||
return false for value in filter[2..] when feature.properties[filter[1]] is value
|
||||
true
|
||||
|
||||
else
|
||||
-> true
|
||||
|
67
src/Tile.coffee
Normal file
67
src/Tile.coffee
Normal file
@ -0,0 +1,67 @@
|
||||
###
|
||||
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'
|
||||
zlib = require 'zlib'
|
||||
Rbush = require('rbush')
|
||||
|
||||
module.exports = class Tile
|
||||
tree: null
|
||||
layers: {}
|
||||
|
||||
constructor: (buffer, @styler = null) ->
|
||||
@tree = new Rbush()
|
||||
@tile = @_loadTile buffer
|
||||
|
||||
@_loadFeatures()
|
||||
|
||||
_loadTile: (buffer) ->
|
||||
buffer = zlib.gunzipSync buffer if @_isGzipped buffer
|
||||
new VectorTile new Protobuf buffer
|
||||
|
||||
_isGzipped: (buffer) ->
|
||||
buffer.slice(0,2).indexOf(Buffer.from([0x1f, 0x8b])) is 0
|
||||
|
||||
_loadFeatures: ->
|
||||
for name, layer of @tile.layers
|
||||
tree = new Rbush()
|
||||
features = for i in [0...layer.length]
|
||||
# TODO: caching of similar attributes to avoid looking up the style each time
|
||||
continue if @styler and not @styler.getStyleFor layer, feature
|
||||
|
||||
feature = layer.feature i
|
||||
|
||||
type = feature.properties.$type =
|
||||
[undefined, "Point", "LineString", "Polygon"][feature.type]
|
||||
|
||||
data =
|
||||
points: feature.loadGeometry()
|
||||
properties: feature.properties
|
||||
id: feature.id
|
||||
type: type
|
||||
|
||||
@_addToTree tree, data
|
||||
data
|
||||
|
||||
@layers[name] = tree: tree, features: features
|
||||
|
||||
_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
|
Loading…
Reference in New Issue
Block a user