use ascii_assets::TerminalChar;
use common_stdx::{Point, Rect};
use crate::BasicDraw;
#[derive(Debug, Default)]
pub struct BasicDrawCreator {
pub draws: Vec<BasicDraw>,
}
impl BasicDrawCreator {
pub fn new() -> Self {
BasicDrawCreator::default()
}
pub fn new_with_capacity(cap: usize) -> Self {
BasicDrawCreator {
draws: Vec::with_capacity(cap),
}
}
pub fn draw_char(&mut self, pos: impl Into<Point<i32>>, chr: TerminalChar) {
self.draws.push(BasicDraw {
pos: pos.into(),
chr,
});
}
pub fn draw_line(
&mut self,
p1: impl Into<Point<i32>>,
p2: impl Into<Point<i32>>,
chr: TerminalChar,
) {
let p1 = p1.into();
let p2 = p2.into();
let mut x0 = p1.x;
let mut y0 = p1.y;
let x1 = p2.x;
let y1 = p2.y;
let dx = (x1 - x0).abs();
let dy = (y1 - y0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx - dy;
loop {
self.draws.push(BasicDraw {
pos: Point { x: x0, y: y0 },
chr,
});
if x0 == x1 && y0 == y1 {
break;
}
let e2 = 2 * err;
if e2 > -dy {
err -= dy;
x0 += sx;
}
if e2 < dx {
err += dx;
y0 += sy;
}
}
}
pub fn get_bounding_box(&self) -> Option<Rect<i32>> {
if self.draws.is_empty() {
return None;
}
let mut min_x = i32::MAX;
let mut min_y = i32::MAX;
let mut max_x = i32::MIN;
let mut max_y = i32::MIN;
for d in &self.draws {
min_x = min_x.min(d.pos.x);
min_y = min_y.min(d.pos.y);
max_x = max_x.max(d.pos.x);
max_y = max_y.max(d.pos.y);
}
Some(Rect::from_coords(min_x, min_y, max_x, max_y))
}
pub fn dump_draws(&mut self) -> Vec<BasicDraw> {
std::mem::take(&mut self.draws)
}
}