use math::{Point, Vec2, point, vec2};
use super::{PathEvent, SvgEvent, FlattenedEvent};
pub struct PathState {
pub current: Point,
pub first: Point,
pub last_ctrl: Point,
}
impl PathState {
pub fn new() -> Self {
PathState {
current: point(0.0, 0.0),
first: point(0.0, 0.0),
last_ctrl: point(0.0, 0.0),
}
}
}
impl PathState {
pub fn svg_event(&mut self, event: SvgEvent) {
match event {
SvgEvent::MoveTo(to) => {
self.move_to(to);
}
SvgEvent::RelativeMoveTo(to) => {
let to = self.from_relative(to);
self.move_to(to);
}
SvgEvent::LineTo(to) => self.line_to(to),
SvgEvent::QuadraticTo(ctrl, to) => {
self.curve_to(ctrl, to);
}
SvgEvent::CubicTo(_, ctrl2, to) => {
self.curve_to(ctrl2, to);
}
SvgEvent::ArcTo(_, _, _, to) => {
self.last_ctrl = self.current; self.current = to;
}
SvgEvent::RelativeLineTo(to) => {
let to = self.from_relative(to);
self.line_to(to);
}
SvgEvent::RelativeQuadraticTo(ctrl, to) => {
let to = self.from_relative(to);
let ctrl = self.from_relative(ctrl);
self.curve_to(ctrl, to);
}
SvgEvent::RelativeCubicTo(_, ctrl2, to) => {
let to = self.from_relative(to);
let ctrl2 = self.from_relative(ctrl2);
self.curve_to(ctrl2, to);
}
SvgEvent::RelativeArcTo(_, _, _, to) => {
self.last_ctrl = self.current; self.relative_next(to);
}
SvgEvent::HorizontalLineTo(x) => {
let to = point(x, self.current.y);
self.line_to(to);
}
SvgEvent::VerticalLineTo(y) => {
let to = point(self.current.x, y);
self.line_to(to);
}
SvgEvent::RelativeHorizontalLineTo(x) => {
let to = self.current + vec2(x, 0.0);
self.line_to(to);
}
SvgEvent::RelativeVerticalLineTo(y) => {
let to = self.current + vec2(0.0, y);
self.line_to(to);
}
SvgEvent::SmoothQuadraticTo(to) => {
let ctrl = self.get_smooth_ctrl();
self.curve_to(ctrl, to);
}
SvgEvent::SmoothCubicTo(ctrl2, to) => {
self.curve_to(ctrl2, to);
}
SvgEvent::SmoothRelativeQuadraticTo(to) => {
let ctrl = self.get_smooth_ctrl();
let to = self.from_relative(to);
self.curve_to(ctrl, to);
}
SvgEvent::SmoothRelativeCubicTo(ctrl2, to) => {
let ctrl2 = self.from_relative(ctrl2);
let to = self.from_relative(to);
self.curve_to(ctrl2, to);
}
SvgEvent::Close => {
self.close();
}
}
}
pub fn path_event(&mut self, event: PathEvent) {
match event {
PathEvent::MoveTo(to) => {
self.move_to(to);
}
PathEvent::LineTo(to) => {
self.line_to(to);
}
PathEvent::QuadraticTo(ctrl, to) => {
self.curve_to(ctrl, to);
}
PathEvent::CubicTo(_, ctrl2, to) => {
self.curve_to(ctrl2, to);
}
PathEvent::Close => {
self.close();
}
}
}
pub fn flattened_event(&mut self, event: FlattenedEvent) {
match event {
FlattenedEvent::MoveTo(to) => {
self.move_to(to);
}
FlattenedEvent::LineTo(to) => {
self.line_to(to);
}
FlattenedEvent::Close => {
self.close();
}
}
}
pub fn move_to(&mut self, to: Point) {
self.last_ctrl = self.current;
self.current = to;
self.first = to;
}
pub fn line_to(&mut self, to: Point) {
self.last_ctrl = self.current;
self.current = to;
}
pub fn curve_to(&mut self, ctrl: Point, to: Point) {
self.last_ctrl = ctrl;
self.current = to;
}
pub fn close(&mut self) {
self.last_ctrl = self.first;
self.current = self.first;
}
pub fn next(&mut self, to: Point) { self.current = to; }
pub fn relative_next(&mut self, to: Vec2) { self.current = self.from_relative(to); }
pub fn get_smooth_ctrl(&self) -> Point { self.current + (self.current - self.last_ctrl) }
pub fn from_relative(&self, v: Vec2) -> Point { self.current + v }
pub fn svg_to_path_event(&self, event: SvgEvent) -> PathEvent {
match event {
SvgEvent::MoveTo(to) => PathEvent::MoveTo(to),
SvgEvent::LineTo(to) => PathEvent::LineTo(to),
SvgEvent::QuadraticTo(ctrl, to) => PathEvent::QuadraticTo(ctrl, to),
SvgEvent::CubicTo(ctrl1, ctrl2, to) => PathEvent::CubicTo(ctrl1, ctrl2, to),
SvgEvent::Close => PathEvent::Close,
SvgEvent::RelativeMoveTo(to) => PathEvent::MoveTo(self.from_relative(to)),
SvgEvent::RelativeLineTo(to) => PathEvent::LineTo(self.from_relative(to)),
SvgEvent::RelativeQuadraticTo(ctrl, to) => {
PathEvent::QuadraticTo(self.from_relative(ctrl), self.from_relative(to))
}
SvgEvent::RelativeCubicTo(ctrl1, ctrl2, to) => {
PathEvent::CubicTo(
self.from_relative(ctrl1),
self.from_relative(ctrl2),
self.from_relative(to),
)
}
SvgEvent::HorizontalLineTo(x) => {
PathEvent::LineTo(point(x, self.current.y))
}
SvgEvent::VerticalLineTo(y) => PathEvent::LineTo(point(self.current.x, y)),
SvgEvent::RelativeHorizontalLineTo(x) => {
PathEvent::LineTo(point(self.current.x + x, self.current.y))
}
SvgEvent::RelativeVerticalLineTo(y) => {
PathEvent::LineTo(point(self.current.x, self.current.y + y))
}
SvgEvent::SmoothQuadraticTo(to) => {
PathEvent::QuadraticTo(self.get_smooth_ctrl(), to)
}
SvgEvent::SmoothCubicTo(ctrl2, to) => {
PathEvent::CubicTo(self.get_smooth_ctrl(), ctrl2, to)
}
SvgEvent::SmoothRelativeQuadraticTo(to) => {
PathEvent::QuadraticTo(self.get_smooth_ctrl(), self.from_relative(to))
}
SvgEvent::SmoothRelativeCubicTo(ctrl2, to) => {
PathEvent::CubicTo(
self.get_smooth_ctrl(),
self.from_relative(ctrl2),
self.from_relative(to),
)
}
_ => unimplemented!(),
}
}
}