use crate::{
geometry::{Dimensions, Point, Size},
primitives::{
ellipse::{self, EllipseContains},
rectangle::Rectangle,
ContainsPoint,
},
};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
pub enum Quadrant {
TopLeft,
TopRight,
BottomRight,
BottomLeft,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
pub(in crate::primitives) struct EllipseQuadrant {
bounding_box: Rectangle,
center_2x: Point,
ellipse: EllipseContains,
}
impl EllipseQuadrant {
pub fn new(top_left: Point, radius: Size, quadrant: Quadrant) -> Self {
let ellipse_top_left = match quadrant {
Quadrant::TopLeft => top_left,
Quadrant::TopRight => top_left - radius.x_axis(),
Quadrant::BottomRight => top_left - radius,
Quadrant::BottomLeft => top_left - radius.y_axis(),
};
Self {
bounding_box: Rectangle::new(top_left, radius),
center_2x: ellipse::center_2x(ellipse_top_left, radius * 2),
ellipse: EllipseContains::new(radius * 2),
}
}
}
impl Dimensions for EllipseQuadrant {
fn bounding_box(&self) -> Rectangle {
self.bounding_box
}
}
impl ContainsPoint for EllipseQuadrant {
fn contains(&self, point: Point) -> bool {
self.ellipse.contains(point * 2 - self.center_2x)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
draw_target::DrawTarget,
geometry::{Point, Size},
iterator::PixelIteratorExt,
mock_display::MockDisplay,
pixelcolor::BinaryColor,
primitives::PointsIter,
Pixel,
};
fn draw_quadrant<D: DrawTarget<Color = BinaryColor>>(
quadrant: &EllipseQuadrant,
target: &mut D,
) -> Result<(), D::Error> {
quadrant
.bounding_box
.points()
.filter(|p| quadrant.contains(*p))
.map(|p| Pixel(p, BinaryColor::On))
.draw(target)
}
#[test]
fn quadrants_even_size() {
let cases = [
(
Quadrant::TopLeft,
&[
" ####",
" #######",
" #########",
"##########",
"##########",
],
),
(
Quadrant::TopRight,
&[
"#### ",
"####### ",
"######### ",
"##########",
"##########",
],
),
(
Quadrant::BottomRight,
&[
"##########",
"##########",
"######### ",
"####### ",
"#### ",
],
),
(
Quadrant::BottomLeft,
&[
"##########",
"##########",
" #########",
" #######",
" ####",
],
),
];
for (quadrant, expected) in cases.iter() {
let ellipse_quadrant =
EllipseQuadrant::new(Point::new(0, 0), Size::new(10, 5), *quadrant);
let mut display = MockDisplay::new();
draw_quadrant(&ellipse_quadrant, &mut display).unwrap();
display.assert_pattern(*expected);
}
}
#[test]
fn quadrants_equal_even_ellipse() {
let mut display = MockDisplay::new();
let radius = Size::new(10, 5);
let top_left = Point::new(0, 0);
draw_quadrant(
&EllipseQuadrant::new(top_left, radius, Quadrant::TopLeft),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius.x_axis(), radius, Quadrant::TopRight),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius, radius, Quadrant::BottomRight),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius.y_axis(), radius, Quadrant::BottomLeft),
&mut display,
)
.unwrap();
display.assert_pattern(&[
" ######## ",
" ############## ",
" ################## ",
"####################",
"####################",
"####################",
"####################",
" ################## ",
" ############## ",
" ######## ",
]);
}
#[test]
fn quadrants_equal_odd_ellipse() {
let mut display = MockDisplay::new();
let radius = Size::new(7, 9);
let top_left = Point::new(0, 0);
draw_quadrant(
&EllipseQuadrant::new(top_left, radius, Quadrant::TopLeft),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius.x_axis(), radius, Quadrant::TopRight),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius, radius, Quadrant::BottomRight),
&mut display,
)
.unwrap();
draw_quadrant(
&EllipseQuadrant::new(top_left + radius.y_axis(), radius, Quadrant::BottomLeft),
&mut display,
)
.unwrap();
display.assert_pattern(&[
" #### ",
" ######## ",
" ########## ",
" ############ ",
" ############ ",
" ############ ",
"##############",
"##############",
"##############",
"##############",
"##############",
"##############",
" ############ ",
" ############ ",
" ############ ",
" ########## ",
" ######## ",
" #### ",
]);
}
}