geello 0.2.0

A tool to render geo data
Documentation
use std::collections::HashMap;

use geo::{Geometry, MultiPolygon, Polygon};
use vello::{
    kurbo::{Affine, BezPath},
    peniko::{Brush, color::palette},
};

use crate::{MagicConverter, MagicFetcher, MagicValue, PropValue, RenderedGeometry};

use super::{GeometryRenderer, LineRenderer};

pub type AreaLineRenderers = HashMap<LineKind, Vec<MagicValue<GeometryRenderer>>>;

#[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
pub enum LineKind {
    All,
    Exterior,
    Interior,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AreaRenderer {
    pub brush: MagicValue<Brush>,
    pub line_renderers: MagicValue<AreaLineRenderers>,
}

impl std::default::Default for AreaRenderer {
    fn default() -> Self {
        Self {
            brush: Brush::Solid(palette::css::SEA_GREEN).into(),
            line_renderers: HashMap::default().into(),
        }
    }
}

impl MagicFetcher for AreaRenderer {
    fn fetch(&mut self) -> Result<(), String> {
        self.brush.fetch()?;
        self.line_renderers.fetch()?;
        Ok(())
    }
}

impl MagicConverter for AreaRenderer {
    fn convert(&mut self, props: &HashMap<String, PropValue>) -> Result<(), String> {
        self.brush.convert(props)?;
        self.line_renderers.convert(props)?;
        Ok(())
    }
}

impl MagicFetcher for AreaLineRenderers {
    fn fetch(&mut self) -> Result<(), String> {
        for (_, renderers) in self.iter_mut() {
            for renderer in renderers {
                renderer.fetch()?;
            }
        }
        Ok(())
    }
}

impl MagicConverter for AreaLineRenderers {
    fn convert(&mut self, props: &HashMap<String, PropValue>) -> Result<(), String> {
        for (_, renderers) in self.iter_mut() {
            for renderer in renderers {
                renderer.convert(props)?;
            }
        }
        Ok(())
    }
}

impl AreaRenderer {
    pub fn draw_multi(
        &mut self,
        scene: &mut vello::Scene,
        transform: Affine,
        polygons: &MultiPolygon,
    ) -> Result<(), String> {
        for polygon in polygons {
            self.draw(scene, transform, polygon)?;
        }
        Ok(())
    }
    pub fn draw(
        &mut self,
        scene: &mut vello::Scene,
        transform: Affine,
        polygon: &Polygon,
    ) -> Result<(), String> {
        let brush = self.brush.as_ref();
        let line_renderers = self.line_renderers.as_mut();
        let exterior = polygon.exterior();
        let interiors = polygon.interiors();
        let exterior_path = AreaRenderer::to_shape(polygon);
        scene.fill(
            vello::peniko::Fill::NonZero,
            transform,
            brush,
            None,
            &exterior_path,
        );
        let exterior_geom: Geometry = exterior.clone().into();
        let mut exterior_geom = vec![RenderedGeometry::new_temp(
            Default::default(),
            exterior_geom,
        )];
        let interior_geoms: Vec<Geometry> = interiors
            .iter()
            .map(|interior| interior.clone().into())
            .collect();
        let mut interior_geoms: Vec<RenderedGeometry> = interior_geoms
            .iter()
            .map(|interior| RenderedGeometry::new_temp(Default::default(), interior.clone()))
            .collect();
        for (kind, renderers) in line_renderers.iter_mut() {
            match kind {
                LineKind::All => {
                    for renderer in renderers.iter_mut().map(|x| x.as_mut()) {
                        renderer.draw(scene, transform, &mut exterior_geom, None)?;
                        renderer.draw(scene, transform, &mut interior_geoms, None)?;
                    }
                }
                LineKind::Exterior => {
                    for renderer in renderers.iter_mut().map(|x| x.as_mut()) {
                        renderer.draw(scene, transform, &mut exterior_geom, None)?;
                    }
                }
                LineKind::Interior => {
                    for renderer in renderers.iter_mut().map(|x| x.as_mut()) {
                        renderer.draw(scene, transform, &mut interior_geoms, None)?;
                    }
                }
            }
        }
        Ok(())
    }
    pub fn to_shape(polygon: &Polygon) -> BezPath {
        let exterior = polygon.exterior();
        let interiors = polygon.interiors();
        let mut exterior_path = LineRenderer::to_shape(exterior);
        interiors.iter().for_each(|x| {
            let p = LineRenderer::to_shape(x);
            p.iter().for_each(|item| {
                exterior_path.push(item);
            });
        });
        exterior_path
    }
}