use self::PathVertex::{AllControlPoints, MirroredControlPoint, Vertex};
use crate::diag::bail;
use crate::foundations::{Array, Reflect, Smart, array, cast, elem};
use crate::layout::{Axes, Length, Rel};
use crate::visualize::{FillRule, Paint, Stroke};
#[elem]
pub struct PathElem {
pub fill: Option<Paint>,
#[default]
pub fill_rule: FillRule,
#[fold]
pub stroke: Smart<Option<Stroke>>,
#[default(false)]
pub closed: bool,
#[variadic]
pub vertices: Vec<PathVertex>,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum PathVertex {
Vertex(Axes<Rel<Length>>),
MirroredControlPoint(Axes<Rel<Length>>, Axes<Rel<Length>>),
AllControlPoints(Axes<Rel<Length>>, Axes<Rel<Length>>, Axes<Rel<Length>>),
}
impl PathVertex {
pub fn vertex(&self) -> Axes<Rel<Length>> {
match self {
Vertex(x) => *x,
MirroredControlPoint(x, _) => *x,
AllControlPoints(x, _, _) => *x,
}
}
pub fn control_point_from(&self) -> Axes<Rel<Length>> {
match self {
Vertex(_) => Axes::new(Rel::zero(), Rel::zero()),
MirroredControlPoint(_, a) => a.map(|x| -x),
AllControlPoints(_, _, b) => *b,
}
}
pub fn control_point_to(&self) -> Axes<Rel<Length>> {
match self {
Vertex(_) => Axes::new(Rel::zero(), Rel::zero()),
MirroredControlPoint(_, a) => *a,
AllControlPoints(_, a, _) => *a,
}
}
}
cast! {
PathVertex,
self => match self {
Vertex(x) => x.into_value(),
MirroredControlPoint(x, c) => array![x, c].into_value(),
AllControlPoints(x, c1, c2) => array![x, c1, c2].into_value(),
},
array: Array => {
let mut iter = array.into_iter();
match (iter.next(), iter.next(), iter.next(), iter.next()) {
(Some(a), None, None, None) => {
Vertex(a.cast()?)
},
(Some(a), Some(b), None, None) => {
if Axes::<Rel<Length>>::castable(&a) {
MirroredControlPoint(a.cast()?, b.cast()?)
} else {
Vertex(Axes::new(a.cast()?, b.cast()?))
}
},
(Some(a), Some(b), Some(c), None) => {
AllControlPoints(a.cast()?, b.cast()?, c.cast()?)
},
_ => bail!("path vertex must have 1, 2, or 3 points"),
}
},
}