118 lines
3.0 KiB
Fennel
118 lines
3.0 KiB
Fennel
(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 zoom]
|
|
(let [width (/ 360 (^ 2 zoom))
|
|
n (+ lat width) ;XXX adjust for latitude
|
|
w (- lon width)
|
|
s lat
|
|
e lon]
|
|
(->
|
|
[
|
|
"[out:json];"
|
|
(f% "way(%f,%f,%f,%f)['highway'];" s w n e)
|
|
"(._;>;);"
|
|
"out;"
|
|
]
|
|
(table.concat "\n"))))
|
|
|
|
(fn canvas [elements]
|
|
(let [nodes {}
|
|
lines {}]
|
|
(each [_ e (ipairs elements)]
|
|
(case e.type
|
|
:node (tset nodes e.id e)
|
|
:way
|
|
(tset
|
|
lines
|
|
e.id
|
|
(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)
|
|
[ tx ty ])))))
|
|
lines))
|
|
|
|
|
|
(fn file-exists? [name]
|
|
(match (io.open name :r)
|
|
f (do (f:close) true)
|
|
_ false))
|
|
|
|
(fn unparsed-from-disk [x y zoom fetch-fn]
|
|
(let [k (.. x "_" y "_" zoom)
|
|
pathname (.. "/tmp/tiles/" k ".json")]
|
|
(if (file-exists? pathname)
|
|
(with-open [i (io.open pathname :r)]
|
|
(i:read "*a"))
|
|
(with-open [j (io.open pathname :w)]
|
|
(let [g (fetch-fn)]
|
|
(j:write g)
|
|
g)))))
|
|
|
|
(fn unparsed-for-xyz [x y zoom]
|
|
(let [(lat lon) (tile->latlon x y zoom)
|
|
o (overpass lat lon zoom)
|
|
r
|
|
(req.new_from_uri
|
|
"https://overpass-api.de/api/interpreter")
|
|
query { :data o }]
|
|
(tset r.headers ":method" "POST")
|
|
(r:set_body (dict_to_query query))
|
|
(let [(headers stream) (r:go)]
|
|
(stream:get_body_as_string))))
|
|
|
|
(fn polylines-from-net [x y zoom]
|
|
(let [s (unparsed-from-disk
|
|
x y zoom
|
|
(fn []
|
|
(unparsed-for-xyz x y zoom)))
|
|
;_ (print :unoparsed (s:sub 1 40))
|
|
data (json.decode s)]
|
|
(canvas data.elements)))
|
|
|
|
|
|
{ :polylines polylines-from-net : latlon->tile }
|