//! Frontiers on which to place pixels. pub mod image; pub mod mean; pub mod min; use crate::color::{ColorSpace, Rgb8}; use crate::soft::SoftDelete; use acap::coords::{Coordinates, CoordinateMetric, CoordinateProximity}; use acap::distance::{Proximity, Metric}; use std::cell::Cell; use std::ops::Deref; use std::rc::Rc; /// A frontier of pixels. pub trait Frontier { /// The width of the image. fn width(&self) -> u32; /// The height of the image. fn height(&self) -> u32; /// The number of pixels currently on the frontier. fn len(&self) -> usize; /// Whether the frontier is empty. fn is_empty(&self) -> bool; /// Place the given color on the frontier, and return its position. fn place(&mut self, rgb8: Rgb8) -> Option<(u32, u32)>; } /// A pixel on a frontier. #[derive(Debug)] struct Pixel { pos: (u32, u32), color: C, deleted: Cell, } impl Pixel { fn new(x: u32, y: u32, color: C) -> Self { Self { pos: (x, y), color, deleted: Cell::new(false), } } fn delete(&self) { self.deleted.set(true); } } /// A reference-counted pixel, to work around the coherence rules. #[derive(Clone, Debug)] struct RcPixel(Rc>); impl RcPixel { fn new(x: u32, y: u32, color: C) -> Self { Self(Rc::new(Pixel::new(x, y, color))) } } impl Deref for RcPixel { type Target = Pixel; fn deref(&self) -> &Self::Target { self.0.deref() } } /// A search target, to work around the coherence rules. #[derive(Debug)] struct Target(C); impl Proximity> for Target { type Distance = C::Distance; fn distance(&self, other: &Pixel) -> Self::Distance { self.0.distance(&other.color) } } impl Metric> for Target {} impl Proximity for Pixel { type Distance = C::Distance; fn distance(&self, other: &Pixel) -> Self::Distance { self.color.distance(&other.color) } } impl Metric for Pixel {} impl Coordinates for Pixel { type Value = C::Value; fn dims(&self) -> usize { self.color.dims() } fn coord(&self, i: usize) -> Self::Value { self.color.coord(i) } } impl SoftDelete for Pixel { fn is_deleted(&self) -> bool { self.deleted.get() } } impl Proximity> for Target { type Distance = C::Distance; fn distance(&self, other: &RcPixel) -> Self::Distance { self.0.distance(&other.0.color) } } impl Metric> for Target {} impl Coordinates for Target { type Value = C::Value; fn dims(&self) -> usize { self.0.dims() } fn coord(&self, i: usize) -> Self::Value { self.0.coord(i) } } impl> CoordinateProximity for Target { type Distance = C::Distance; fn distance_to_coords(&self, coords: &[T]) -> Self::Distance { self.0.distance_to_coords(coords) } } impl> CoordinateMetric for Target {} impl Proximity for RcPixel { type Distance = C::Distance; fn distance(&self, other: &Self) -> Self::Distance { (*self.0).distance(&*other.0) } } impl Metric for RcPixel {} impl Coordinates for RcPixel { type Value = C::Value; fn dims(&self) -> usize { (*self.0).dims() } fn coord(&self, i: usize) -> Self::Value { (*self.0).coord(i) } } impl SoftDelete for RcPixel { fn is_deleted(&self) -> bool { (*self.0).is_deleted() } } /// Return all the neighbors of a pixel location. fn neighbors(x: u32, y: u32) -> [(u32, u32); 8] { let xm1 = x.wrapping_sub(1); let ym1 = y.wrapping_sub(1); let xp1 = x + 1; let yp1 = y + 1; [ (xm1, ym1), (xm1, y), (xm1, yp1), (x, ym1), (x, yp1), (xp1, ym1), (xp1, y), (xp1, yp1), ] }