fetch enough tiles to cover the display

This commit is contained in:
Daniel Barlow 2025-05-29 12:48:21 +01:00
parent 398693bc07
commit ab4e4857f3
3 changed files with 109 additions and 39 deletions

25
README
View File

@ -127,9 +127,28 @@ the benefit of the caching. If we're going to do that, should it also
do transformation e.g. from lat/long to x/y co-ordinates? We don't
need this bit yet though
3) alternatively we could use mapbox vector tiles, but tbh I'm
struggling to see now that helps. we don't have to transform from
lat/long but instead we have to parse a protobuf, how is that simpler?
https://git.syndicate-lang.org/tonyg/squeak-phone/raw/commit/474960ddc665ed445a1f5afb0164fe39057720f9/devices/pine64-pinephone/modem-docs/80545ST10798A_LM940_QMI_Command_Reference_Guide_r3.pdf
----
we need to extend to multiple tiles'-worth of map
* get tile for curent lat/long and request overpass data for enough
surrounding tiles to fill the screen
* I think a way is served with all its nodes whether or not they're in
the bbox, so we can just store the ids of ways we've seen and skip
them if the come up again
* render all the polylines into the widget (some day also the labels etc)
* to get it centred on the cyclist, take the tile fractional part *
256, and translate the canvas up and left by that amount
* add a cache of [x,y,z] -> polylines so that we don't keep hitting overpass

View File

@ -30,7 +30,9 @@ label.readout {
(os.difftime (os.time localt) (os.time utct))))
(local map-width 720)
(local map-height 800)
(local tile-size 256)
(fn styles []
(let [style_provider (Gtk.CssProvider)]
@ -44,8 +46,8 @@ label.readout {
(local window (Gtk.Window {
:title "Map"
:name "toplevel"
:default_width 720
:default_height 800
:default_width map-width
:default_height map-height
:on_destroy Gtk.main_quit
}))
@ -59,30 +61,65 @@ label.readout {
:speed 14
:lat 49
:lon 0
:zoom 17
:course 22
}
)
(fn merge [table1 table2]
(collect [k v (pairs table2) &into table1]
k v))
;; given lat/lon
;; we want the tile containing lat to be roughly centred
;; on the screen, and enough tiles either side of it
;; to fill the width of the screen plus a bit
(fn cairo-the-map [self g]
(let [{ : lat : lon : zoom } app-state
num-tiles-x (+ 0 (math.ceil (/ map-width tile-size)))
num-tiles-y (+ 0 (math.ceil (/ map-height tile-size)))
; _ (print app-state.lat app-state.lon)
(tile-x tile-y) (tiles.latlon->tile app-state.lat app-state.lon app-state.zoom)
min-tile-x (math.floor (- tile-x (/ num-tiles-x 2)))
max-tile-x (math.ceil (+ tile-x (/ num-tiles-x 2)))
min-tile-y (math.floor (- tile-y (/ num-tiles-y 2)))
max-tile-y (math.ceil (+ tile-y (/ num-tiles-y 2)))
left-edge (- tile-x (/ map-width 2 tile-size))
top-edge (- tile-y (/ map-height 2 tile-size))
lines []]
(for [x min-tile-x max-tile-x]
(for [y min-tile-y max-tile-y]
(merge lines (tiles.polylines x y zoom))))
;; put tile-x and tile-y in the centre of the visible area.
(g:translate (* tile-size (- min-tile-x left-edge))
(* tile-size (- min-tile-y top-edge)))
(g:set_source_rgb 0.2 0.2 0.4)
(g:set_line_width 3)
(each [_ line (pairs lines)]
(case line
[[sx sy] & more]
(do
(g:move_to (* tile-size (- sx min-tile-x))
(* tile-size (- sy min-tile-y)))
(each [_ [x y] (ipairs more)]
(let [x1 (* tile-size (- x min-tile-x))
y1 (* tile-size (- y min-tile-y))]
(g:line_to x1 y1))))))
(g:stroke)
true))
(fn osm-widget []
(let [height 256]
(Gtk.Label {
:width height :height height
:on_draw
(fn [self g]
(print app-state.lat app-state.lon )
(let [lines (tiles.polylines app-state.lat app-state.lon 17)]
(g:set_source_rgb 0.2 0.2 0.4)
(g:set_line_width 3)
(each [_ line (ipairs lines)]
(case line
[[sx sy] & more]
(do
(g:move_to sx sy)
(each [_ [x y] (ipairs more)]
(g:line_to x y)))))
(g:stroke)
true))
})))
(Gtk.Label {
:width map-width :height map-height
:on_draw cairo-the-map
}))
(fn readout [name text]
(let [w
@ -106,9 +143,7 @@ label.readout {
(expect= (hhmmss (+ 45 (* 60 12) (* 60 60 3))) "3:12:45")
(fn merge [table1 table2]
(collect [k v (pairs table2) &into table1]
k v))
(fn update-app-state [new-vals]

View File

@ -43,9 +43,10 @@
(expect= (math.floor y) 43221))
(fn overpass [lat lon]
(let [n (+ lat 0.01)
w (- lon 0.01)
(fn overpass [lat lon zoom]
(let [width (/ 360 (^ 2 zoom))
n (+ lat width) ;XXX adjust for latitude
w (- lon width)
s lat
e lon]
(->
@ -59,30 +60,45 @@
(fn canvas [elements offset-x offset-y]
(let [nodes {}
lines []]
lines {}]
(each [_ e (ipairs elements)]
(case e.type
:node (tset nodes e.id e)
:way
(table.insert
(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)
[ (* 256 (- tx offset-x)) (* 256 (- ty offset-y)) ])))))
[ tx ty ])))))
lines))
(fn polylines [lat long zoom]
(let [r
(fn polylines-from-net [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 (overpass lat long zoom) }]
query { :data o }]
(tset r.headers ":method" "POST")
(r:set_body (dict_to_query query))
(let [(headers stream) (r:go)
(tx ty) (latlon->tile lat long zoom)
(tx ty) (latlon->tile lat lon zoom)
data (json.decode (stream:get_body_as_string))]
(canvas data.elements (math.floor tx) (math.floor ty)))))
{ : polylines }
(local cache {})
(fn polylines [x y zoom]
(let [k (.. x "/" y "/" zoom)
lines (. cache k)]
(print k (not (not lines)))
(if lines
(do (print "cached! " x y zoom) lines)
(let [lines (polylines-from-net x y zoom)]
(tset cache k lines)
lines))))
{ : polylines : latlon->tile }