use alloc::rc::Rc;
use core::f64::consts::PI;
use i_float::float::compatible::FloatPointCompatible;
use i_float::float::number::FloatNumber;
#[derive(Debug, Clone)]
pub enum LineCap<P: FloatPointCompatible> {
Butt,
Round(P::Scalar),
Square,
Custom(Rc<[P]>),
}
#[derive(Debug, Clone)]
pub enum LineJoin<T: FloatNumber> {
Bevel,
Miter(T),
Round(T),
}
#[derive(Debug, Clone)]
pub struct StrokeStyle<P: FloatPointCompatible> {
pub width: P::Scalar,
pub start_cap: LineCap<P>,
pub end_cap: LineCap<P>,
pub join: LineJoin<P::Scalar>,
}
#[derive(Debug)]
pub struct OutlineStyle<T: FloatNumber> {
pub outer_offset: T,
pub inner_offset: T,
pub join: LineJoin<T>,
}
impl<P: FloatPointCompatible> LineCap<P> {
pub(crate) fn normalize(self) -> Self {
if let LineCap::Round(angle) = self {
let a = angle.to_f64().clamp(0.01 * PI, 0.25 * PI);
LineCap::Round(P::Scalar::from_float(a))
} else {
self
}
}
}
impl<T: FloatNumber> LineJoin<T> {
pub(crate) fn normalize(self) -> Self {
match self {
LineJoin::Miter(ratio) => {
let a = ratio.to_f64().clamp(0.01 * PI, 0.99 * PI);
LineJoin::Miter(T::from_float(a))
}
LineJoin::Round(angle) => {
let a = angle.to_f64().clamp(0.01 * PI, 0.25 * PI);
LineJoin::Round(T::from_float(a))
}
_ => self,
}
}
}
impl<P: FloatPointCompatible> StrokeStyle<P> {
pub fn new(width: P::Scalar) -> Self {
Self {
width,
..Default::default()
}
}
pub fn width(mut self, width: P::Scalar) -> Self {
self.width = P::Scalar::from_float(width.to_f64().max(0.0));
self
}
pub fn start_cap(mut self, cap: LineCap<P>) -> Self {
self.start_cap = cap.normalize();
self
}
pub fn end_cap(mut self, cap: LineCap<P>) -> Self {
self.end_cap = cap.normalize();
self
}
pub fn line_join(mut self, join: LineJoin<P::Scalar>) -> Self {
self.join = join.normalize();
self
}
}
impl<P: FloatPointCompatible> Default for StrokeStyle<P> {
fn default() -> Self {
Self {
width: P::Scalar::from_float(1.0),
start_cap: LineCap::Butt,
end_cap: LineCap::Butt,
join: LineJoin::Bevel,
}
}
}
impl<T: FloatNumber> OutlineStyle<T> {
pub fn new(offset: T) -> Self {
Self {
outer_offset: offset,
inner_offset: offset,
..Default::default()
}
}
pub fn offset(mut self, offset: T) -> Self {
self.outer_offset = offset;
self.inner_offset = offset;
self
}
pub fn outer_offset(mut self, outer_offset: T) -> Self {
self.outer_offset = outer_offset;
self
}
pub fn inner_offset(mut self, inner_offset: T) -> Self {
self.inner_offset = inner_offset;
self
}
pub fn line_join(mut self, join: LineJoin<T>) -> Self {
self.join = join;
self
}
}
impl<T: FloatNumber> Default for OutlineStyle<T> {
fn default() -> Self {
Self {
outer_offset: T::from_float(1.0),
inner_offset: T::from_float(1.0),
join: LineJoin::Bevel,
}
}
}