kitkat 1.1.1

The classic kit kat clock utility.
/*
 * kitkat
 *
 * Copyright 2021 - Manos Pitsidianakis
 *
 * This file is part of kitkat.
 *
 * kitkat is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * kitkat is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with kitkat. If not, see <http://www.gnu.org/licenses/>.
 */

pub struct Buffer<'v> {
    pub vec: &'v mut Vec<u8>,
    pub row_width: usize,
    pub height: usize,
}

pub fn plot(buffer: &'_ mut Buffer<'_>, (x, y): (i64, i64)) {
    if x < 0 || y < 0 {
        eprintln!("invalid plot() coors: ({}, {})", x, y);
        return;
    }
    //eprintln!("plot() coors: ({}, {})", x, y);
    let (x, y) = (x as usize, y as usize);
    let row_width = buffer.row_width.wrapping_div(8)
        + if buffer.row_width.wrapping_rem(8) > 0 {
            1
        } else {
            0
        };
    //std::dbg!(x.wrapping_div(8));
    //std::dbg!(x.wrapping_rem(8));
    let byte_column = x.wrapping_div(8) + 1;
    let bit_column = x.wrapping_rem(8) as u32;
    //std::dbg!(byte_column);
    //std::dbg!(bit_column);
    if let Some(cell) = buffer.vec.get_mut(y * row_width + byte_column) {
        *cell |= 0x01_u8 << bit_column;
    }
}

pub fn plot_line_with_width(
    buffer: &'_ mut Buffer<'_>,
    point_a: (i64, i64),
    point_b: (i64, i64),
    wd: f64,
) {
    let width2 = wd / 2.0;
    plot_line_width(buffer, point_a, point_b, 1.0);
    for w in ((-1.0 * width2) as i64)..(width2 as i64) {
        plot_line_width(
            buffer,
            (point_a.0 + w, point_a.1),
            (point_b.0 + w, point_b.1),
            1.0,
        );
    }
}

pub fn plot_line_width(
    buffer: &'_ mut Buffer<'_>,
    (mut x0, mut y0): (i64, i64),
    (x1, y1): (i64, i64),
    wd: f64,
) {
    //eprintln!(
    //    "plot_line_width: ({}, {}), ({}, {}) width = {}",
    //    x0, y0, x1, y1, wd
    //);
    /* Bresenham's line algorithm */
    let dx = (x1 - x0).abs();
    let sx = if x0 < x1 { 1 } else { -1 };
    let dy = (y1 - y0).abs();
    let sy = if y0 < y1 { 1 } else { -1 };
    let mut err = dx - dy;
    /* error value e_xy */
    let mut e2: i64;
    let mut x2: i64;
    let mut y2: i64;
    let ed: f64 = if (dx + dy) == 0 {
        1.0
    } else {
        f64::sqrt((dx * dx) as f64 + (dy * dy) as f64)
    };
    let mut points = vec![];
    let wd = (wd + 1.0) / 2.0;
    //eprintln!("wd = {}, ed = {}", wd, ed);
    loop {
        points.push((x0, y0));
        plot(buffer, (x0, y0));
        e2 = err;
        x2 = x0;
        if 2 * e2 >= -dx {
            /* x step */
            //eprintln!(" x step ");
            e2 += dy;
            y2 = y0;
            while e2 < ((ed as f64 * wd) as i64) && (y1 != y2 || dx > dy) {
                y2 += sy;
                plot(buffer, (x0, y2));
                points.push((x0, y2));
                e2 += dx;
            }
            if x0 == x1 {
                break;
            };
            e2 = err;
            err -= dy;
            x0 += sx;
        }
        if 2 * e2 <= dy {
            /* y step */
            //eprintln!(" y step ");
            e2 = dx - e2;
            while e2 < ((ed as f64 * wd) as i64) && (x1 != x2 || dx < dy) {
                x2 += sx;
                plot(buffer, (x2, y0));
                points.push((x2, y0));
                e2 += dy;
            }
            if y0 == y1 {
                break;
            };
            err += dx;
            y0 += sy;
        }
    }
}

pub fn plot_ellipse(
    buffer: &'_ mut Buffer<'_>,
    (xm, ym): (i64, i64),
    (a, b): (i64, i64),
    quadrants: [bool; 4],
    _wd: f64,
) {
    let mut x = -a;
    let mut y = 0;
    let mut e2 = b;
    let mut dx = (1 + 2 * x) * e2 * e2;
    let mut dy = x * x;
    let mut err = dx + dy;
    loop {
        if quadrants[0] {
            plot(buffer, (xm - x, ym + y)); /*   I. Quadrant */
        }
        if quadrants[1] {
            plot(buffer, (xm + x, ym + y)); /*  II. Quadrant */
        }
        if quadrants[2] {
            plot(buffer, (xm + x, ym - y)); /* III. Quadrant */
        }
        if quadrants[3] {
            plot(buffer, (xm - x, ym - y)); /*  IV. Quadrant */
        }
        e2 = 2 * err;
        if e2 >= dx {
            x += 1;
            dx += 2 * b * b;
            err += dx;
            //err += dx += 2*(long)b*b; }    /* x step */
        }
        if e2 <= dy {
            y += 1;
            dy += 2 * a * a;
            err += dy;
            //err += dy += 2*(long)a*a; }    /* y step */
        }
        if x > 0 {
            break;
        }
    }
    while y < b {
        /* to early stop for flat ellipses with a=1, */
        y += 1;
        plot(buffer, (xm, ym + y)); /* -> finish tip of ellipse */
        plot(buffer, (xm, ym - y));
    }
}