hittekaart 0.2.0

Generates OSM heatmap tiles from GPX tracks
Documentation
//! Actual rendering functions for tile hunts.
//!
//! This renders a tile as "transparent green" if any track passes through it.
//!
//! Note that is version of "tile hunt" is a bit silly, as the tile size changes with the zoom
//! level. For a better version, the "tile hunt size" should be fixed to a given zoom.
use crossbeam_channel::Sender;
use fnv::FnvHashSet;

use super::{
    super::{
        error::Result,
        gpx::Coordinates,
        layer::{TILE_HEIGHT, TILE_WIDTH},
    },
    RenderedTile,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Renderer;

impl super::Renderer for Renderer {
    type Prepared = FnvHashSet<(u64, u64)>;

    fn prepare(
        &self,
        zoom: u32,
        tracks: &[Vec<Coordinates>],
        tick: Sender<()>,
    ) -> Result<Self::Prepared> {
        let mut marked = FnvHashSet::default();

        for track in tracks {
            for point in track {
                let merc = point.web_mercator(zoom);
                let tile_x = merc.0 / TILE_WIDTH;
                let tile_y = merc.1 / TILE_HEIGHT;
                marked.insert((tile_x, tile_y));
            }

            tick.send(()).unwrap();
        }

        Ok(marked)
    }

    fn colorize(&self, layer: Self::Prepared, tx: Sender<RenderedTile>) -> Result<()> {
        // The tile is hand-crafted to be very small. See
        // <https://www.mjt.me.uk/posts/smallest-png/> for a reference, and of course the actual
        // PNG specification <http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html>.
        static IMAGE_DATA: &[u8] = include_bytes!("tile-marked.png");
        for (tile_x, tile_y) in layer {
            tx.send(RenderedTile {
                x: tile_x,
                y: tile_y,
                data: IMAGE_DATA.to_vec(),
            })?;
        }
        Ok(())
    }

    fn tile_count(&self, layer: &Self::Prepared) -> Result<u64> {
        Ok(layer.len().try_into().unwrap())
    }
}