🎨 adding simplify-js to readme, adapting canvas

This commit is contained in:
Michael Straßburger 2016-11-10 06:14:20 +01:00
parent ae65f95e24
commit 2d7cff71eb
4 changed files with 29 additions and 75 deletions

View File

@ -58,10 +58,9 @@ If your terminal supports mouse events you can drag the map and use your scroll
#### Juggling the vectors and numbers
* [`earcut`](https://github.com/mapbox/earcut) for polygon triangulation
* [`rbush`](https://github.com/mourner/rbush) for 2D spatial indexing based label and mouse collision detection
* [`breseham`](https://github.com/madbence/node-bresenham) for line calculations
* [`sphericalmercator`](https://github.com/mapbox/node-sphericalmercator) for [EPSG:3857](http://spatialreference.org/ref/sr-org/6864/) <> [WGS84](http://spatialreference.org/ref/epsg/wgs-84/) conversions
* [`tilebelt`](https://github.com/mapbox/tilebelt) for some [slippy map tilename](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames) calculations
* [`rbush`](https://github.com/mourner/rbush) for 2D spatial indexing of geo and label data
* [`breseham`](https://github.com/madbence/node-bresenham) for line point calculations
* [`simplify-js`](https://github.com/mourner/simplify-js) for polyline simplifications
#### Handling the flow
* [`bluebird`](https://github.com/petkaantonov/bluebird) for all the asynchronous [Promise](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise) magic

View File

@ -35,9 +35,8 @@
"rbush": "^2.0.1",
"request": "^2.76.0",
"request-promise": "^4.1.1",
"sphericalmercator": "^1.0.5",
"simplify-js": "^1.2.1",
"term-mouse": "^0.1.1",
"tilebelt": "^1.0.1",
"userhome": "^1.0.0",
"vector-tile": "^1.3.0",
"x256": "0.0.2"

View File

@ -12,6 +12,8 @@
###
bresenham = require 'bresenham'
simplify = require 'simplify-js'
earcut = require 'earcut'
BrailleBuffer = require './BrailleBuffer'
utils = require './utils'
@ -32,11 +34,11 @@ module.exports = class Canvas
@buffer.writeText text, x, y, color, center
line: (from, to, color, width = 1) ->
@_line from, to, color, width
@_line from.x, from.y, to.x, to.y, color, width
polyline: (points, color, width = 1) ->
for i in [1...points.length]
@_line points[i-1], points[i], width, color
@_line points[i-1].x, points[i-1].y, points[i].x, points[i].y, width, color
setBackground: (color) ->
@buffer.setGlobalBackground color
@ -53,37 +55,38 @@ module.exports = class Canvas
continue if ring.length < 3
holes.push vertices.length/2
else
return if ring.length < 3
return false if ring.length < 3
for point in ring
vertices = vertices.concat point
vertices.push point.x
vertices.push point.y
try
triangles = earcut vertices, holes
catch e
return false
extract = (pointId) ->
[vertices[pointId*2], vertices[pointId*2+1]]
for i in [0...triangles.length] by 3
pa = extract(triangles[i])
pb = extract(triangles[i+1])
pc = extract(triangles[i+2])
pa = @_polygonExtract vertices, triangles[i]
pb = @_polygonExtract vertices, triangles[i+1]
pc = @_polygonExtract vertices, triangles[i+2]
@_filledTriangle pa, pb, pc, color
true
_polygonExtract: (vertices, pointId) ->
[vertices[pointId*2], vertices[pointId*2+1]]
# Inspired by Alois Zingl's "The Beauty of Bresenham's Algorithm"
# -> http://members.chello.at/~easyfilter/bresenham.html
_line: (pointA, pointB, width, color) ->
_line: (x0, y0, x1, y1, width, color) ->
# Fall back to width-less bresenham algorithm if we dont have a width
unless width = Math.max 0, width-1
return bresenham pointA[0], pointA[1], pointB[0], pointB[1],
return bresenham x0, y0, x1, y1,
(x, y) => @buffer.setPixel x, y, color
[x0, y0] = pointA
[x1, y1] = pointB
dx = Math.abs x1-x0
sx = if x0 < x1 then 1 else -1
dy = Math.abs y1-y0
@ -138,16 +141,9 @@ module.exports = class Canvas
b = @_bresenham pointA, pointC
c = @_bresenham pointA, pointB
# Filter out any points outside of the visible area
# TODO: benchmark - is it more effective to filter double points, or does
# it req more computing time than actually setting points multiple times?
last = null
points = a.concat(b).concat(c)
.filter (point) => 0 <= point.y < @height
.sort (a, b) -> if a.y is b.y then a.x - b.x else a.y-b.y
.filter (point) ->
[lastPoint, last] = [last, point]
not lastPoint or lastPoint.x isnt point.x or lastPoint.y isnt point.y
for i in [0...points.length]
point = points[i]
@ -155,8 +151,8 @@ module.exports = class Canvas
if point.y is next?.y
left = Math.max 0, point.x
right = Math.min @width, next.x
if left and right
right = Math.min @width-1, next.x
if left >= 0 and right <= @width
@buffer.setPixel x, point.y, color for x in [left..right]
else

View File

@ -4,8 +4,6 @@
methods used all around
###
mercator = new (require('sphericalmercator'))()
constants =
RADIUS: 6378137
@ -13,29 +11,14 @@ utils =
clamp: (num, min, max) ->
if num <= min then min else if num >= max then max else num
# Based on W. Randolph Franklin (WRF)'s Point Inclusion in Polygon Test
# https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
pointInPolygon: (polygon, point) ->
inside = false
j = polygon.length-1
for i in [0...polygon.length]
if (polygon[i][1]>point[1]) isnt (polygon[j][1]>point[1]) and
point[0] < (polygon[j][0]-polygon[i][0]) * (point[1]-polygon[i][1]) / (polygon[j][1]-polygon[i][1]) + polygon[i][0]
inside = !inside
j = i
inside
ll2xy: (lon, lat) ->
[
utils.deg2rad(lon)*constants.RADIUS,
Math.log(Math.tan(Math.PI/4 + utils.deg2rad(lat)/2)) * constants.RADIUS
]
deg2rad: (angle) ->
# (angle / 180) * Math.PI
angle * 0.017453292519943295
ll2tile: (lon, lat, zoom) ->
[
Math.floor (lon+180)/360*Math.pow(2, zoom)
Math.floor (1-Math.log(Math.tan(lat*Math.PI/180)+1/Math.cos(lat*Math.PI/180))/Math.PI)/2*Math.pow(2, zoom)
]
x: (lon+180)/360*Math.pow(2, zoom)
y: (1-Math.log(Math.tan(lat*Math.PI/180)+1/Math.cos(lat*Math.PI/180))/Math.PI)/2*Math.pow(2, zoom)
z: zoom
tile2ll: (x, y, zoom) ->
n = Math.PI - 2*Math.PI*y/Math.pow(2, zoom)
@ -43,32 +26,9 @@ utils =
lon: x/Math.pow(2, zoom)*360-180
lat: 180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))
geoBBox: (center, zoom, width, height) ->
[x, y] = utils.ll2xy center.lon, center.lat
meterPerPixel = utils.metersPerPixel zoom, center.lat
width *= meterPerPixel
height *= meterPerPixel
west = x - width*.5
east = x + width*.5
south = y + height*.5
north = y - height*.5
box = mercator
.inverse([west+1, south])
.concat mercator.inverse([east-1, north])
metersPerPixel: (zoom, lat = 0) ->
(Math.cos(lat * Math.PI/180) * 2 * Math.PI * constants.RADIUS) / (256 * Math.pow(2, zoom))
deg2rad: (angle) ->
# (angle / 180) * Math.PI
angle * 0.017453292519943295
rad2deg: (angle) ->
angle / Math.PI * 180
hex2rgb: (color) ->
return [255, 0, 0] unless color?.match