🚱 bringing polygon rendering back, todo: holes

This commit is contained in:
Michael Straßburger 2016-11-06 22:13:50 +01:00
parent cfd8e24342
commit e69321dfb6
6 changed files with 98 additions and 166 deletions

View File

@ -1,14 +1,15 @@
# MapSCII - the whole world in your console.
# MapSCII - The Whole World In Your Console.
No web browser around? Don't worry - and discover the planet in your console!
MapSCII is node.js based [Vector Tile](https://github.com/mapbox/vector-tile-spec) to [Braille](http://www.fileformat.info/info/unicode/block/braille_patterns/utf8test.htm) renderer for [xterm](https://en.wikipedia.org/wiki/Xterm)-compatible terminals.
<img src="http://i.imgur.com/yYVt7No.png" width="100%" />
* Discover the globe or zoom in to explore your neighbourhood
* See Point-of-Interest around any given location
* Highly customizable styling (reuse your [mapbox-gl-styles](https://github.com/mapbox/mapbox-gl-styles))
* Highly customizable layer styling with [Mapbox Styles](https://www.mapbox.com/mapbox-gl-style-spec/)
* Compatible with Linux and OSX terminals, Windows support via [PuTTY](http://www.putty.org/)
* Use the default or your own map server - or work offline with VectorTile/MBTiles
* Connect to any vector tile server - or just use my custom [OpenStreetMap](https://en.wikipedia.org/wiki/OpenStreetMap) based one
* Work offline and discover local VectorTile/MBTiles
* 100% pure Coffee-/JavaScript! :sunglasses:
## How to install
@ -123,7 +124,7 @@ If your terminal supports mouse events you can drag the map and use your scroll
* [x] filled polygons
* [x] convert polygons to triangles
* [x] use triangulation for filling
* [ ] respect fill/line style file based setting
* [x] respect fill/line style file based setting
* Tile
* [x] directly throw away features that aren't covered by any style

View File

@ -51,25 +51,19 @@ module.exports = class Canvas
xs = {}
ys = {}
#
# for points in polylines
# if vertices.length
# continue
# holes.push vertices.length/2
for points in polylines
if vertices.length
continue
holes.push vertices.length/2
for point in polylines
vertices = vertices.concat point
xs[point[0]] = ys[point[1]] = true
lastPoint = [-1, -1]
for point in points
vertices = vertices.concat point[0], point[1]
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
if vertices.length
# TODO: a line-hole - skip it for now
continue
else
# TODO: a line instead of a polygon - skip it for now
return false
# 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

View File

@ -5,7 +5,6 @@
The Console Vector Tile renderer - bäm!
###
x256 = require 'x256'
mercator = new (require('sphericalmercator'))()
tilebelt = require 'tilebelt'
Promise = require 'bluebird'
@ -98,6 +97,7 @@ module.exports = class Renderer
@isDrawing = true
@labelBuffer.clear()
@_seen = {}
if color = @styler.styleById['background']?.paint['background-color']
@canvas.setBackground x256 utils.hex2rgb color
@ -173,6 +173,7 @@ module.exports = class Renderer
maxY: (@height-position.y)*scale
features = {}
for layer in @config.drawOrder
continue unless tile.data.layers?[layer]
features[layer] = tile.data.layers[layer].search box
@ -186,7 +187,6 @@ module.exports = class Renderer
for layer in @config.drawOrder
for tile in tiles
continue unless tile.features[layer]?.length
for feature in tile.features[layer]
# continue if feature.id and drawn[feature.id]
# drawn[feature.id] = true
@ -208,10 +208,12 @@ module.exports = class Renderer
@config.tileSize / @config.projectSize / Math.pow(2, zoom-baseZoom)
_drawFeature: (tile, feature) ->
return false if feature.style.minzoom and tile.zoom < feature.style.minzoom
if feature.style.minzoom and tile.zoom < feature.style.minzoom
return false
toDraw = @_scaleAndReduce tile, feature
return false unless toDraw.length
points = @_scaleAndReduce tile, feature
unless points.length
return false
color =
feature.style.paint['line-color'] or
@ -227,12 +229,12 @@ module.exports = class Renderer
switch feature.style.type
when "line"
width = feature.style.paint['line-width']?.base*1.4 or 1
@canvas.polyline points, colorCode, width for points in toDraw
@canvas.polyline points, colorCode, width
when "fill"
@canvas.polygon toDraw, colorCode
@canvas.polygon points, colorCode
when "symbol"
when "symbola"
text = feature.properties["name_"+@config.language] or
feature.properties["name_en"] or
feature.properties["name"] or
@ -240,60 +242,53 @@ module.exports = class Renderer
#@config.icons[feature.properties.maki] or
""
# TODO: check in definition if points can actually own multiple geometries
for points in toDraw
for point in points
x = point[0] - text.length
margin = @config.layers[feature.layer]?.margin or @config.labelMargin
for point in points
x = point[0] - text.length
margin = @config.layers[feature.layer]?.margin or @config.labelMargin
if @labelBuffer.writeIfPossible text, x, point[1], feature, margin
@canvas.text text, x, point[1], colorCode
else if @config.layers[feature.layer]?.cluster and @labelBuffer.writeIfPossible "X", point[0], point[1], feature, 3
@canvas.text "", point[0], point[1], colorCode
if @labelBuffer.writeIfPossible text, x, point[1], feature, margin
@canvas.text text, x, point[1], colorCode
else if @config.layers[feature.layer]?.cluster and @labelBuffer.writeIfPossible "X", point[0], point[1], feature, 3
@canvas.text "", point[0], point[1], colorCode
_seen: {}
_scaleAndReduce: (tile, feature) ->
reduced = []
for points in feature.points
seen = {}
lastX = null
lastY = null
lastX = null
lastY = null
outside = false
scaled = []
outside = null
scaled = []
for point in feature.points
x = Math.floor tile.position.x+point.x/tile.scale
y = Math.floor tile.position.y+point.y/tile.scale
for point in points
x = Math.floor tile.position.x+point.x/tile.scale
y = Math.floor tile.position.y+point.y/tile.scale
if lastX is x and lastY is y
continue
lastY = y
lastX = x
if x < -@tilePadding or
y < -@tilePadding or
x > @width+@tilePadding or
y > @height+@tilePadding
continue if outside
outside = true
else
if outside
outside = null
scaled.push [lastX, lastY]
scaled.push [x, y]
if scaled.length is 2
if seen[ka = scaled[0].concat(scaled[1]).join '-'] or
seen[kb = scaled[1].concat(scaled[0]).join '-']
continue
seen[ka] = seen[kb] = true
unless scaled.length > 1 or feature.type is "symbol"
if lastX is x and lastY is y
continue
reduced.push scaled
lastY = y
lastX = x
#
# if x < -@tilePadding or
# y < -@tilePadding or
# x > @width+@tilePadding or
# y > @height+@tilePadding
# continue if outside
# outside = true
# else
# if outside
# outside = null
# scaled.push [lastX, lastY]
reduced
scaled.push [x, y]
if scaled.length is 2
if @_seen[ka = scaled[0].concat(scaled[1]).join '-'] or
@_seen[kb = scaled[1].concat(scaled[0]).join '-']
return []
@_seen[ka] = @_seen[kb] = true
unless scaled.length > 1 or feature.type is "symbol"
return []
scaled

View File

@ -24,9 +24,9 @@ module.exports = class Termap
initialZoom: null
maxZoom: 18
zoomStep: 0.1
zoomStep: 0.25
headless: false
# size:
# width: 40*2
# height: 10*4

View File

@ -41,29 +41,37 @@ class Tile
layers = {}
for name, layer of tile.layers
tree = rbush()
features = for i in [0...layer.length]
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
feature.properties.$type = [undefined, "Point", "LineString", "Polygon"][feature.type]
feature.properties.$type = type = [undefined, "Point", "LineString", "Polygon"][feature.type]
if @styler
style = @styler.getStyleFor name, feature
continue unless style
# TODO: monkey patching test case for tiles with a reduced extent
points = @_reduceGeometry feature, 8
# TODO: monkey patching test case for tiles with a reduced extent 4096 / 8 -> 512
# use feature.loadGeometry() again as soon as we got a 512 extent tileset
geometries = @_reduceGeometry feature, 8
data =
style: style
points: points
properties: feature.properties
id: feature.id
layer: name
if style.type is "fill"
@_addToTree tree,
id: feature.id
layer: name
style: style
properties: feature.properties
points: geometries[0]
@_addToTree tree, data
data
else
for points in geometries
@_addToTree tree,
id: feature.id
layer: name
style: style
properties: feature.properties
points: points
layers[name] = tree
@ -71,12 +79,12 @@ class Tile
_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
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
@ -89,7 +97,7 @@ class Tile
for points, i in feature.loadGeometry()
reduced = []
last = null
for point, j in points
for point in points
p =
x: Math.floor point.x/factor
y: Math.floor point.y/factor

View File

@ -33,45 +33,6 @@
"background-color": "@background"
}
},
{
"type": "fill",
"id": "landuse_overlay_national_park",
"paint": {
"fill-color": "#d8e8c8"
},
"source-layer": "landuse_overlay",
"filter": [
"==",
"class",
"national_park"
]
},
{
"type": "fill",
"id": "landuse_park",
"paint": {
"fill-color": "#d8e8c8"
},
"source-layer": "landuse",
"filter": [
"==",
"class",
"park"
]
},
{
"type": "fill",
"id": "landuse_cemetery",
"paint": {
"fill-color": "#e0e4dd"
},
"source-layer": "landuse",
"filter": [
"==",
"class",
"cemetery"
]
},
{
"type": "fill",
"id": "landuse_hospital",
@ -86,33 +47,6 @@
]
},
{
"type": "fill",
"id": "landuse_school",
"paint": {
"fill-color": "#f0e8f8"
},
"source-layer": "landuse",
"filter": [
"==",
"class",
"school"
]
},
{
"type": "fill",
"id": "landuse_wood",
"paint": {
"fill-color": "#6a4"
},
"source-layer": "landuse",
"filter": [
"==",
"class",
"wood"
]
},
{
"hide": true,
"type": "line",
"id": "waterway",
"paint": {