(local req (require :http.request)) (local { : dict_to_query } (require :http.util)) (local json (require :json)) (import-macros { : define-tests : expect : expect= : expect-near } :assert) (local { : view } (require :fennel)) (local f% string.format) (fn sinh [x] (/ (- 1 (math.exp (* -2 x))) (* 2 (math.exp (- x))))) (expect (< (math.abs (- (sinh 2) 3.626860407847)) 0.001)) (fn tile->latlon [xtile ytile zoom] (let [n (^ 2 zoom) lon-deg (- (/ (* xtile 360) n) 180.0) lat-rad (math.atan (sinh (* math.pi (- 1 (/ (* 2 ytile) n)))) )] (values (/ (* lat-rad 180) math.pi) lon-deg))) (let [(lat lon) (tile->latlon 0 0 0)] (expect= lon -180) (expect-near lat 85.05112877) ) (let [(lat lon) (tile->latlon 232798 103246 18)] (expect-near lon 139.699401855) (expect-near lat 35.6595278648) ) (fn latlon->tile [lat lon zoom] (let [n (^ 2 zoom) x (* n (/ (+ lon 180) 360)) t1 (/ (* lat math.pi) 180) t (math.log (+ (math.tan t1) (/ 1 (math.cos t1)))) y (* (- 1 (/ t math.pi)) (/ n 2))] (values x y))) (let [(x y) (latlon->tile 52.1234 -0.53 17)] (expect= (math.floor x) 65343) (expect= (math.floor y) 43221)) (fn overpass [lat lon] (let [n (+ lat 0.01) w (- lon 0.01) s lat e lon] (-> [ "[out:json];" (f% "way(%f,%f,%f,%f)['highway'];" s w n e) "(._;>;);" "out;" ] (table.concat "\n")))) (fn canvas [elements offset-x offset-y] (let [nodes {} lines []] (each [_ e (ipairs elements)] (case e.type :node (tset nodes e.id e) :way (table.insert lines (icollect [_ nd (ipairs e.nodes)] (let [node (. nodes nd) (tx ty) (latlon->tile node.lat node.lon 17)] ;;(print e.tags.name e.id e.name node.lat node.lon) [ (* 256 (- tx offset-x)) (* 256 (- ty offset-y)) ]))))) lines)) (fn polylines [lat long zoom] (let [r (req.new_from_uri "https://overpass-api.de/api/interpreter") query { :data (overpass lat long zoom) }] (tset r.headers ":method" "POST") (r:set_body (dict_to_query query)) (let [(headers stream) (r:go) (tx ty) (latlon->tile lat long zoom) data (json.decode (stream:get_body_as_string))] (canvas data.elements (math.floor tx) (math.floor ty))))) { : polylines }