Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

.nornir/maptrait-for-idiots.md

maptrait — the selectable Map trait — for idiots

Class: idiot. Every step, nothing assumed. Goal: understand what "one trait, all maps" means and see it work, from a cold shell. Know Rust already? Read maptrait-guide.md instead.

The idea in one picture

A map is just layers of stuff drawn on top of each other:

Old way: every app wrote its own map drawing. New way: there is one kind of thing, a MapLayer — a "source of stuff to draw". You can have as many as you like, stack them, and turn each one on or off with a checkbox. One shared drawer paints them all. That is "one trait, all maps".

Why "selectable"

You might have the same roads from two places: OpenStreetMap and the Swedish road authority (Trafikverket). Both become a WaysLayer — the same kind of layer, just with a different name ("osm-streets" vs "trafikverket-roads"). At runtime you tick whichever one you trust. That is selecting the data to draw.

Why it can rotate and tilt (like a car sat-nav)

The camera (MapView) has two extra dials:

It is still a flat 2D map underneath; the dials just change how it's drawn.

See it work (no data needed)

cd /home/rickard/git/facett
cargo test -p facett-map layer     # the 11 tests that prove the trait, the rotation and the toggling

You'll see tests like bearing_rotates_the_map, tilt_foreshortens_the_vertical_axis, and selecting_data_to_draw_via_layer_toggle pass. That's the whole idea, checked.

Where it lives

Why a map that isn't moving costs nothing now

Drawing a map means deciding, for every road and lake, whether it is on screen, what colour it is, and what order to paint it in (water under buildings, small things over big ones). That last step is a sort of the whole list, and it was being redone sixty times a second — even when nobody had touched the map and the answer could not possibly have changed.

Now the map remembers the answer, and throws the memory away the moment anything it depended on moves: you turn a layer off, you pan, you zoom, you resize the window, or the GPU takes some of the drawing over. Nothing else can change the answer, so nothing else needs to.

Counted on oden: hold a 20 000-road map still for 501 frames and the old code sorted the list 501 times and worked out 10 020 000 paint orders. The new code does it once — 1 sort, 20 000 paint orders. Panning still costs what it always did, because when you pan the answer really is different.

We count the work rather than time it on purpose. This box runs many builds at once, and the very same test on the very same code measured 15.9 ms one minute and 36.8 ms four minutes later — that number is about how busy the machine was, not about the map. A count of "how many times did it do the work" cannot be fooled that way.

The honest catch: the trick only helps when the map is standing still. Drag it, spin it, or leave the idle auto-rotate spinning and every frame is a new picture that has to be worked out from scratch.

You can check it yourself — the test counts how many times the work actually happened:

cd /home/rickard/git/facett
cargo test -p facett-map --release --test draw_list_memo -- --nocapture