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 fs = require('fs');
|
||||||
const Termap = require(__dirname+'/src/Termap');
|
const Termap = require(__dirname+'/src/Termap');
|
||||||
|
const Tile = require(__dirname+'/src/Tile')
|
||||||
|
|
||||||
termap = new Termap();
|
termap = new Termap();
|
||||||
|
|
||||||
// TODO: abstracing this class, create loader class
|
// TODO: abstracing this class, create loader class
|
||||||
data = fs.readFileSync(__dirname+"/tiles/regensburg.pbf.gz");
|
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();
|
termap._draw();
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
The Console Vector Tile renderer - bäm!
|
The Console Vector Tile renderer - bäm!
|
||||||
###
|
###
|
||||||
x256 = require 'x256'
|
x256 = require 'x256'
|
||||||
Protobuf = require 'pbf'
|
|
||||||
VectorTile = require('vector-tile').VectorTile
|
|
||||||
zlib = require 'zlib'
|
|
||||||
triangulator = new (require('pnltri')).Triangulator()
|
triangulator = new (require('pnltri')).Triangulator()
|
||||||
|
|
||||||
Canvas = require './Canvas'
|
Canvas = require './Canvas'
|
||||||
@ -66,29 +63,6 @@ module.exports = class Renderer
|
|||||||
setSize: (@width, @height) ->
|
setSize: (@width, @height) ->
|
||||||
@canvas = new Canvas @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) ->
|
draw: (@view, @zoom) ->
|
||||||
return if @isDrawing
|
return if @isDrawing
|
||||||
@isDrawing = true
|
@isDrawing = true
|
||||||
@ -118,51 +92,34 @@ module.exports = class Renderer
|
|||||||
process.stdout.write output
|
process.stdout.write output
|
||||||
|
|
||||||
_drawLayers: ->
|
_drawLayers: ->
|
||||||
drawn = []
|
|
||||||
for layer in @config.drawOrder
|
for layer in @config.drawOrder
|
||||||
|
continue unless @features?[layer]
|
||||||
|
|
||||||
@notify "rendering #{layer}..."
|
@notify "rendering #{layer}..."
|
||||||
scale = Math.pow 2, @zoom
|
scale = Math.pow 2, @zoom
|
||||||
continue unless @features?[layer]
|
|
||||||
|
|
||||||
if @config.layers[layer].minZoom and @zoom > @config.layers[layer].minZoom
|
if @config.layers[layer].minZoom and @zoom > @config.layers[layer].minZoom
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@canvas.strokeStyle = @canvas.fillStyle = @config.layers[layer].color
|
for feature in @features[layer].tree.search(minX: 0, minY: 0, maxX: 4096, maxY: 4096)
|
||||||
|
@_drawFeature layer, feature.data, scale
|
||||||
for feature in @features[layer]
|
|
||||||
if @_drawFeature layer, feature, scale
|
|
||||||
drawn.push feature
|
|
||||||
|
|
||||||
drawn
|
|
||||||
|
|
||||||
_drawFeature: (layer, feature, scale) ->
|
_drawFeature: (layer, feature, scale) ->
|
||||||
# TODO: this is ugly :) need to be fixed @style
|
# TODO: this is ugly :) need to be fixed @style
|
||||||
#return false if feature.properties.class is "ferry"
|
#return false if feature.properties.class is "ferry"
|
||||||
feature.type = "LineString" if layer is "building" or layer is "road"
|
feature.type = "LineString" if layer is "building" or layer is "road"
|
||||||
|
|
||||||
toDraw = []
|
# TODO: zoom level
|
||||||
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
|
|
||||||
|
|
||||||
unless style = @styler.getStyleFor layer, feature, 14
|
unless style = @styler.getStyleFor layer, feature, 14
|
||||||
return false
|
return false
|
||||||
|
|
||||||
color = style.paint['line-color'] or style.paint['fill-color'] or style.paint['text-color']
|
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
|
# TODO: zoom calculation todo for perfect styling
|
||||||
if color instanceof Object
|
if color instanceof Object
|
||||||
color = color.stops[0][1]
|
color = color.stops[0][1]
|
||||||
|
@ -39,10 +39,7 @@ module.exports = class Styler
|
|||||||
false
|
false
|
||||||
|
|
||||||
_compileFilter: (filter) ->
|
_compileFilter: (filter) ->
|
||||||
if not filter or not filter.length
|
switch filter?[0]
|
||||||
return -> true
|
|
||||||
|
|
||||||
switch filter[0]
|
|
||||||
when "all"
|
when "all"
|
||||||
filters = (@_compileFilter subFilter for subFilter in filter[1..])
|
filters = (@_compileFilter subFilter for subFilter in filter[1..])
|
||||||
(feature) ->
|
(feature) ->
|
||||||
@ -64,3 +61,6 @@ module.exports = class Styler
|
|||||||
(feature) ->
|
(feature) ->
|
||||||
return false for value in filter[2..] when feature.properties[filter[1]] is value
|
return false for value in filter[2..] when feature.properties[filter[1]] is value
|
||||||
true
|
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