commit ab4e4857f376e5f8af1f61d116133a259a99c8ee
parent 398693bc0797747eda967ee93a8fad74eb42b694
Author: Daniel Barlow <dan@telent.net>
Date: Thu, 29 May 2025 12:48:21 +0100
fetch enough tiles to cover the display
Diffstat:
3 files changed, 109 insertions(+), 39 deletions(-)
diff --git a/README b/README
@@ -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
diff --git a/pkgs/maps/main.fnl b/pkgs/maps/main.fnl
@@ -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]
diff --git a/pkgs/maps/tiles.fnl b/pkgs/maps/tiles.fnl
@@ -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 }