use crate::renderer::CornerRadii;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Corners {
pub radii: CornerRadii,
pub curvature: f32,
}
impl Corners {
pub fn rounded(radii: impl Into<CornerRadii>) -> Self {
Self::superellipse(radii, 1.0)
}
pub fn squircle(radii: impl Into<CornerRadii>) -> Self {
Self::superellipse(radii, 2.0)
}
pub fn bevel(radii: impl Into<CornerRadii>) -> Self {
Self::superellipse(radii, 0.0)
}
pub fn scoop(radii: impl Into<CornerRadii>) -> Self {
Self::superellipse(radii, -1.0)
}
pub fn superellipse(radii: impl Into<CornerRadii>, curvature: f32) -> Self {
Self {
radii: radii.into(),
curvature,
}
}
pub const SQUARE: Self = Self {
radii: CornerRadii {
top_left: 0.0,
top_right: 0.0,
bottom_right: 0.0,
bottom_left: 0.0,
},
curvature: 1.0,
};
}
impl Default for Corners {
fn default() -> Self {
Self::SQUARE
}
}
impl<T: Into<CornerRadii>> From<T> for Corners {
fn from(radii: T) -> Self {
Self::rounded(radii)
}
}
impl crate::animation::Animatable for Corners {
fn lerp(from: &Self, to: &Self, t: f32) -> Self {
Self {
radii: crate::animation::Animatable::lerp(&from.radii, &to.radii, t),
curvature: from.curvature + (to.curvature - from.curvature) * t,
}
}
fn is_reverse(from: &Self, to: &Self) -> bool {
let total = |c: &Self| {
c.radii.top_left
+ c.radii.top_right
+ c.radii.bottom_right
+ c.radii.bottom_left
+ c.curvature
};
total(to) < total(from)
}
fn channels(&self) -> crate::animation::Channels {
crate::animation::Channels::from_slice(&[
self.radii.top_left,
self.radii.top_right,
self.radii.bottom_right,
self.radii.bottom_left,
self.curvature,
])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_constructor_names_the_shape_and_takes_the_size() {
assert_eq!(Corners::squircle(12.0).curvature, 2.0);
assert_eq!(Corners::bevel(12.0).curvature, 0.0);
assert_eq!(Corners::scoop(12.0).curvature, -1.0);
assert_eq!(Corners::rounded(12.0).curvature, 1.0);
assert_eq!(Corners::squircle(12.0).radii, CornerRadii::uniform(12.0));
}
#[test]
fn the_radii_take_one_two_or_four_values() {
assert_eq!(Corners::from(8.0).radii, CornerRadii::uniform(8.0));
let pairs = Corners::squircle([16.0, 0.0]).radii;
assert_eq!((pairs.top_left, pairs.top_right), (16.0, 16.0));
assert_eq!((pairs.bottom_right, pairs.bottom_left), (0.0, 0.0));
let four = Corners::rounded([1.0, 2.0, 3.0, 4.0]).radii;
assert_eq!(four.top_left, 1.0);
assert_eq!(four.top_right, 2.0);
assert_eq!(four.bottom_right, 3.0);
assert_eq!(four.bottom_left, 4.0);
}
}