diff --git a/src/BrailleBuffer.coffee b/src/BrailleBuffer.coffee index 1c8f27f..d1b1f2d 100644 --- a/src/BrailleBuffer.coffee +++ b/src/BrailleBuffer.coffee @@ -27,14 +27,17 @@ module.exports = class BrailleBuffer termReset: "\x1B[39;49m" constructor: (@width, @height) -> - @pixelBuffer = new Buffer @width*@height/8 + size = @width*@height/8 + @pixelBuffer = new Buffer size + @foregroundBuffer = new Buffer size + @backgroundBuffer = new Buffer size @clear() clear: -> @pixelBuffer.fill 0 @charBuffer = [] - @foregroundBuffer = [] - @backgroundBuffer = [] + @foregroundBuffer.fill 0 + @backgroundBuffer.fill 0 setGlobalBackground: (@globalBackground) -> diff --git a/src/Canvas.coffee b/src/Canvas.coffee index e520a92..780b088 100644 --- a/src/Canvas.coffee +++ b/src/Canvas.coffee @@ -13,7 +13,6 @@ bresenham = require 'bresenham' earcut = require 'earcut' - BrailleBuffer = require './BrailleBuffer' utils = require './utils' @@ -56,14 +55,9 @@ module.exports = class Canvas # if vertices.length # continue # holes.push vertices.length/2 - + polylines.push polylines[0] for point in polylines vertices = vertices.concat point - xs[point[0]] = ys[point[1]] = true - - # Check if we actually got a valid polygon after projection and clamping - if Object.keys(xs).length is 1 or Object.keys(ys).length is 1 - return false try triangles = earcut vertices, holes @@ -78,10 +72,7 @@ module.exports = class Canvas pb = extract(triangles[i+1]) pc = extract(triangles[i+2]) - if (0 <= pa[0] < @width and 0 <= pa[1] < @height) or - (0 <= pb[0] < @width and 0 <= pb[1] < @height) or - (0 <= pc[0] < @width and 0 <= pc[1] < @height) - @_filledTriangle pa, pb, pc, color + @_filledTriangle pa, pb, pc, color # Inspired by Alois Zingl's "The Beauty of Bresenham's Algorithm" # -> http://members.chello.at/~easyfilter/bresenham.html @@ -159,13 +150,17 @@ module.exports = class Canvas [lastPoint, last] = [last, point] not lastPoint or lastPoint.x isnt point.x or lastPoint.y isnt point.y - for i, point of points + for i in [0...points.length] + point = points[i] next = points[i*1+1] if point.y is next?.y left = Math.max 0, point.x - right = Math.min @width, next?.x - @buffer.setPixel x, point.y, color for x in [left..right] + right = Math.min @width, next.x + if left and right + @buffer.setPixel x, point.y, color for x in [left..right] else @buffer.setPixel point.x, point.y, color + + break unless next diff --git a/src/Renderer.coffee b/src/Renderer.coffee index 1968417..aa9a95b 100644 --- a/src/Renderer.coffee +++ b/src/Renderer.coffee @@ -210,18 +210,19 @@ module.exports = class Renderer if feature.style.minzoom and tile.zoom < feature.style.minzoom return false + points = @_scaleAndReduce tile, feature, feature.points + switch feature.style.type when "line" - points = @_scaleAndReduce tile, feature, feature.points - width = feature.style.paint['line-width'] width = width.stops[0][1] if width instanceof Object @canvas.polyline points, feature.color, width if points.length when "fill" - vertices = (@_scaleAndReduce tile, feature, points, false for points in feature.points) - @canvas.polygon vertices[0], feature.color + @canvas.polygon points, feature.color + # if points.length is 3 + # @canvas._filledTriangle points[0], points[1], points[2], feature.color true when "symbol" @@ -242,12 +243,15 @@ module.exports = class Renderer else if @config.layers[feature.layer]?.cluster and @labelBuffer.writeIfPossible "X", point[0], point[1], feature, 3 @canvas.text "◉", point[0], point[1], feature.color + true + _seen: {} _scaleAndReduce: (tile, feature, points, filter = true) -> lastX = null lastY = null outside = false scaled = [] + #seen = {} for point in points x = Math.floor tile.position.x+(point.x/tile.scale) @@ -259,8 +263,12 @@ module.exports = class Renderer lastY = y lastX = x + # TODO: benchmark + # continue if seen[idx = (y<<8)+x] + # seen[idx] = true + if filter - if tile.xyz.z > 1 and ( + if ( x < -@tilePadding or y < -@tilePadding or x > @width+@tilePadding or @@ -277,8 +285,8 @@ module.exports = class Renderer if filter if scaled.length is 2 - if @_seen[ka = scaled[0].concat(scaled[1]).join '-'] or - @_seen[kb = scaled[1].concat(scaled[0]).join '-'] + if @_seen[ka = (scaled[0]<<8)+scaled[1]] or + @_seen[kb = (scaled[1]<<8)+scaled[0]] return [] @_seen[ka] = @_seen[kb] = true diff --git a/src/Termap.coffee b/src/Termap.coffee index 466dd7c..e85a5dc 100644 --- a/src/Termap.coffee +++ b/src/Termap.coffee @@ -23,8 +23,8 @@ module.exports = class Termap styleFile: __dirname+"/../styles/bright.json" initialZoom: null - maxZoom: 17 - zoomStep: 0.1 + maxZoom: 18 + zoomStep: 0.2 headless: false # size: @@ -154,7 +154,9 @@ module.exports = class Termap when "q" process.exit 0 - when "w" then @zoomy = true + when "w" then @zoomy = 1 + when "s" then @zoomy = -1 + when "a" then @zoomBy @config.zoomStep when "z" then @zoomBy -@config.zoomStep @@ -181,11 +183,12 @@ module.exports = class Termap .catch => @notify "renderer is busy" .then => - if @zoomy and @zoom < @config.maxZoom - @zoom += @config.zoomStep + if @zoomy + if (@zoomy > 0 and @zoom < @config.maxZoom) or (@zoomy < 0 and @zoom > @minZoom) + @zoom += @zoomy * @config.zoomStep + else + @zoomy *= -1 @_draw() - else - @zoomy = false _getFooter: -> # features = @renderer.featuresAt @mousePosition.x-1-(@view[0]>>1), @mousePosition.y-1-(@view[1]>>2) @@ -195,16 +198,11 @@ module.exports = class Termap # type: f.feature.properties.type # rank: f.feature.properties.scalerank # ).join(", ")+"] "+ - "#{@mousePosition.x} #{@mousePosition.y} " + - #"center: [#{utils.digits @center.lat, 2}, #{utils.digits @center.lng, 2}]}" + #{}"#{@mousePosition.x} #{@mousePosition.y} " + # bbox = @_getBBox() # tiles = @_tilesInBBox(bbox) + "center: #{utils.digits @center.lat, 3}, #{utils.digits @center.lon, 3} "+ "zoom: #{utils.digits @zoom, 2} " - #{}"bbox: [#{bbox.map((z) -> utils.digits(z, 2)).join(', ')}]"+ - # "tiles: "+("#{k}: #{v}" for k,v of @_tilesInBBox(bbox) when typeof v is "number").join(",") - - - #features.map((f) -> JSON.stringify f.feature.properties).join(" - ") notify: (text) -> @_write "\r\x1B[K"+text unless @config.headless diff --git a/src/Tile.coffee b/src/Tile.coffee index becdb49..b02d558 100644 --- a/src/Tile.coffee +++ b/src/Tile.coffee @@ -11,6 +11,7 @@ Promise = require 'bluebird' zlib = require 'zlib' rbush = require 'rbush' x256 = require 'x256' +earcut = require 'earcut' utils = require "./utils" @@ -46,6 +47,7 @@ class Tile for name, layer of tile.layers nodes = [] + #continue if name is "water" 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 @@ -62,7 +64,7 @@ class Tile style.paint['fill-color'] or style.paint['text-color'] - # TODO: zoom calculation todo for perfect styling + # TODO: style zoom stops handling if color instanceof Object color = color.stops[0][1] @@ -72,45 +74,34 @@ class Tile # use feature.loadGeometry() again as soon as we got a 512 extent tileset geometries = feature.loadGeometry() #@_reduceGeometry feature, 8 - # TODO: handling polygon holes, only handling outer area for now - if style.type is "fill" + for points in (if style.type is "fill" then [geometries[0]] else geometries) nodes.push @_addBoundaries id: feature.id layer: name style: style properties: feature.properties - points: geometries + points: points color: colorCode - else - for points in geometries - nodes.push @_addBoundaries - id: feature.id - layer: name - style: style - properties: feature.properties - points: points - color: colorCode - tree = rbush() + tree = rbush 18 tree.load nodes + layers[name] = tree @layers = layers _addBoundaries: (data) -> - [minX, maxX, minY, maxY] = [Infinity, -Infinity, Infinity, -Infinity] - minMax = (points) -> - for p in points - 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 + minX = Infinity + maxX = -Infinity + minY = Infinity + maxY = -Infinity - if data.points[0] instanceof Array - minMax points for points in data.points - else - minMax data.points + for p in data.points + 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 data.minX = minX data.maxX = maxX