use super::Drawable;
use super::line::segment;
use crate::CoordinateI32;
use crate::image::ImageViewMut;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Polyline<P> {
pub points: Vec<CoordinateI32>,
pub color: P,
pub closed: bool,
}
impl<P: Copy> Drawable<P> for Polyline<P> {
fn draw_into(&self, image: &mut impl ImageViewMut<Pixel = P>) {
draw_path(image, &self.points, self.color, self.closed);
}
}
pub fn draw_polyline<P: Copy, C: Into<CoordinateI32> + Copy>(
image: &mut impl ImageViewMut<Pixel = P>,
points: &[C],
color: P,
closed: bool,
) {
draw_path(image, points, color, closed);
}
fn draw_path<P: Copy, C: Into<CoordinateI32> + Copy>(
image: &mut impl ImageViewMut<Pixel = P>,
points: &[C],
color: P,
closed: bool,
) {
for pair in points.windows(2) {
segment(image, pair[0].into(), pair[1].into(), color);
}
if closed && points.len() >= 3 {
segment(
image,
points[points.len() - 1].into(),
points[0].into(),
color,
);
}
}
#[cfg(test)]
mod tests {
use super::super::tests::inked;
use super::*;
use crate::image::Image;
use crate::pixel::Mono8;
fn ink() -> Mono8 {
Mono8::new(255)
}
#[test]
fn open_chain_connects_consecutive_points() {
let mut image: Image<Mono8> = Image::zero(7, 7);
draw_polyline(&mut image, &[(0, 0), (4, 0), (4, 4)], ink(), false);
let drawn = inked(&image);
assert_eq!(drawn.len(), 9); for x in 0..=4 {
assert!(drawn.contains(&(x, 0)));
}
for y in 0..=4 {
assert!(drawn.contains(&(4, y)));
}
assert!(!drawn.contains(&(2, 2)));
}
#[test]
fn closed_chain_adds_the_return_edge() {
let mut image: Image<Mono8> = Image::zero(7, 7);
draw_polyline(&mut image, &[(0, 0), (4, 0), (4, 4)], ink(), true);
let drawn = inked(&image);
assert!(drawn.contains(&(2, 2)), "closing diagonal missing");
}
#[test]
fn degenerate_inputs_are_no_ops() {
let mut image: Image<Mono8> = Image::zero(5, 5);
let empty: &[(i32, i32)] = &[];
draw_polyline(&mut image, empty, ink(), false);
draw_polyline(&mut image, empty, ink(), true);
draw_polyline(&mut image, &[(2, 2)], ink(), true);
assert!(inked(&image).is_empty());
}
#[test]
fn two_points_closed_draws_the_segment_once_not_thrice() {
let mut image: Image<Mono8> = Image::zero(6, 6);
draw_polyline(&mut image, &[(1, 1), (4, 1)], ink(), true);
assert_eq!(inked(&image), vec![(1, 1), (2, 1), (3, 1), (4, 1)]);
}
#[test]
fn struct_and_free_function_agree() {
let points: Vec<CoordinateI32> = [(0, 5), (3, 0), (6, 5), (0, 5)].map(Into::into).to_vec();
let mut via_struct: Image<Mono8> = Image::zero(7, 7);
Polyline {
points: points.clone(),
color: ink(),
closed: false,
}
.draw_into(&mut via_struct);
let mut via_fn: Image<Mono8> = Image::zero(7, 7);
draw_polyline(&mut via_fn, &points, ink(), false);
assert_eq!(inked(&via_struct), inked(&via_fn));
}
}