use crate::elements::view::{utils, ColChar, Pixel, Vec2D, ViewElement};
use super::Line;
pub struct Triangle {
pub corners: [Vec2D; 3],
pub fill_char: ColChar,
}
impl Triangle {
#[must_use]
pub const fn new(pos0: Vec2D, pos1: Vec2D, pos2: Vec2D, fill_char: ColChar) -> Self {
Self::with_array([pos0, pos1, pos2], fill_char)
}
#[must_use]
pub const fn with_array(corners: [Vec2D; 3], fill_char: ColChar) -> Self {
Self { corners, fill_char }
}
#[deprecated = "Triangle has been restructured, just use `Triangle.corners` now"]
#[must_use]
pub const fn corners(&self) -> [Vec2D; 3] {
self.corners
}
#[must_use]
pub fn interpolate(i0: isize, d0: isize, i1: isize, d1: isize) -> Vec<isize> {
Self::interpolate_floating(i0, d0 as f64, i1, d1 as f64)
.iter()
.map(|n| n.round() as isize)
.collect()
}
#[must_use]
pub fn interpolate_floating(i0: isize, d0: f64, i1: isize, d1: f64) -> Vec<f64> {
if i0 == i1 {
return vec![d0];
}
let mut values = vec![];
let a = (d1 - d0) / (i1 - i0) as f64;
let mut d = d0;
for _i in i0..=i1 {
values.push(d);
d += a;
}
values
}
#[must_use]
pub fn draw(corners: [Vec2D; 3]) -> Vec<Vec2D> {
let mut points = vec![];
let mut corners = corners;
corners.sort_unstable_by_key(|k| k.y);
let (x0, y0) = corners[0].as_tuple();
let (x1, y1) = corners[1].as_tuple();
let (x2, y2) = corners[2].as_tuple();
let mut x01 = Self::interpolate(y0, x0, y1, x1);
let x12 = Self::interpolate(y1, x1, y2, x2);
let x02 = Self::interpolate(y0, x0, y2, x2);
x01.pop();
let x01_12 = [x01, x12].concat();
let m = (x01_12.len() as f64 / 2.0).floor() as usize;
let (x_left, x_right) = if x02[m] < x01_12[m] {
(x02, x01_12)
} else {
(x01_12, x02)
};
for (i, y) in (y0..y2).enumerate() {
for x in x_left[i]..x_right[i] {
points.push(Vec2D::new(x, y));
}
}
points.append(&mut Line::draw(corners[0], corners[1]));
points.append(&mut Line::draw(corners[1], corners[2]));
points.append(&mut Line::draw(corners[2], corners[0]));
points
}
}
impl ViewElement for Triangle {
fn active_pixels(&self) -> Vec<Pixel> {
utils::points_to_pixels(&self.active_points(), self.fill_char)
}
fn active_points(&self) -> Vec<Vec2D> {
Self::draw(self.corners)
}
}