vizkit 0.1.2

A rendering-agnostic kit for data visualization
use std::collections::VecDeque;

use super::{PathCommand, PathCurve};

pub(super) struct Step {
    state: u8,
    is_closed: bool,
    tension: f32,
    x: f32,
    y: f32,
}

impl Step {
    pub(super) fn new(tension: f32, is_closed: bool) -> Self {
        Self {
            tension: tension.clamp(0., 1.),
            state: 0,
            is_closed,
            x: f32::NAN,
            y: f32::NAN,
        }
    }

    fn update(&mut self, [x, y]: [f32; 2]) {
        self.x = x;
        self.y = y;
    }
}

impl PathCurve for Step {
    fn point(&mut self, point: [f32; 2], buffer: &mut VecDeque<PathCommand>) {
        match self.state {
            0 => {
                self.state = 1;
                if self.is_closed {
                    buffer.push_back(PathCommand::LineTo(point))
                } else {
                    buffer.push_back(PathCommand::MoveTo(point))
                }
            }
            _ => {
                self.state = 2;
                let [x, y] = point;
                if self.tension <= 0. {
                    buffer.push_back(PathCommand::LineTo([self.x, y]));
                    buffer.push_back(PathCommand::LineTo(point))
                } else {
                    let x1 = self.x * (1. - self.tension) + x * self.tension;
                    buffer.push_back(PathCommand::LineTo([x1, self.y]));
                    buffer.push_back(PathCommand::LineTo([x1, y]));
                }
            }
        }
        self.update(point);
    }

    fn end(&mut self, buffer: &mut VecDeque<PathCommand>) {
        if self.state == 2 {
            buffer.push_back(PathCommand::LineTo([self.x, self.y]))
        }
        if self.is_closed {
            buffer.push_back(PathCommand::ClosePath);
        }
        self.tension = 1. - self.tension;
        self.state = 0;
    }
}