use crate::math::*;
use crate::events::PathEvent;
use crate::geom::{CubicBezierSegment, QuadraticBezierSegment, SvgArc, Arc, ArcFlags};
use crate::path_state::PathState;
use std::marker::Sized;
pub trait Build {
type PathType;
fn build(self) -> Self::PathType;
fn build_and_reset(&mut self) -> Self::PathType;
}
pub trait FlatPathBuilder {
fn move_to(&mut self, to: Point);
fn line_to(&mut self, to: Point);
fn close(&mut self);
fn current_position(&self) -> Point;
fn flattened(self, tolerance: f32) -> FlatteningBuilder<Self> where Self: Sized {
FlatteningBuilder::new(self, tolerance)
}
}
pub trait PathBuilder: FlatPathBuilder {
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point);
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point);
fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle);
fn path_event(&mut self, event: PathEvent) {
match event {
PathEvent::Begin { at } => {
self.move_to(at);
}
PathEvent::Line { to, .. } => {
self.line_to(to);
}
PathEvent::Quadratic { ctrl, to, .. } => {
self.quadratic_bezier_to(ctrl, to);
}
PathEvent::Cubic { ctrl1, ctrl2, to, .. } => {
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
PathEvent::End { close : true, .. } => {
self.close();
}
PathEvent::End { close : false, .. } => {
}
}
}
fn with_svg(self) -> SvgPathBuilder<Self> where Self : Sized { SvgPathBuilder::new(self) }
}
pub trait SvgBuilder: PathBuilder {
fn relative_move_to(&mut self, to: Vector);
fn relative_line_to(&mut self, to: Vector);
fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector);
fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector);
fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point);
fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector);
fn smooth_quadratic_bezier_to(&mut self, to: Point);
fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector);
fn horizontal_line_to(&mut self, x: f32);
fn relative_horizontal_line_to(&mut self, dx: f32);
fn vertical_line_to(&mut self, y: f32);
fn relative_vertical_line_to(&mut self, dy: f32);
fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point);
fn relative_arc_to(
&mut self,
radii: Vector,
x_rotation: Angle,
flags: ArcFlags,
to: Vector,
);
}
pub trait PolygonBuilder {
fn polygon(&mut self, points: &[Point]);
}
#[doc(hidden)]
pub fn build_polygon<Builder: FlatPathBuilder>(builder: &mut Builder, points: &[Point]) {
if points.len() < 2 {
return;
}
builder.move_to(points[0]);
for p in &points[1..] {
builder.line_to(*p);
}
builder.close();
}
pub struct SvgPathBuilder<Builder: PathBuilder> {
builder: Builder,
state: PathState,
}
impl<Builder: PathBuilder> SvgPathBuilder<Builder> {
pub fn new(builder: Builder) -> SvgPathBuilder<Builder> {
SvgPathBuilder {
builder,
state: PathState::new(),
}
}
}
impl<Builder: PathBuilder + Build> Build for SvgPathBuilder<Builder> {
type PathType = Builder::PathType;
fn build(self) -> Builder::PathType { self.builder.build() }
fn build_and_reset(&mut self) -> Builder::PathType { self.builder.build_and_reset() }
}
impl<Builder: PathBuilder> FlatPathBuilder for SvgPathBuilder<Builder> {
fn move_to(&mut self, to: Point) {
self.state.move_to(to);
self.builder.move_to(to);
}
fn line_to(&mut self, to: Point) {
self.state.line_to(to);
self.builder.line_to(to);
}
fn close(&mut self) {
self.state.close();
self.builder.close();
}
fn current_position(&self) -> Point { self.state.current_position() }
}
impl<Builder: PathBuilder> PathBuilder for SvgPathBuilder<Builder> {
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
self.state.quadratic_bezier_to(ctrl, to);
self.builder.quadratic_bezier_to(ctrl, to);
}
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
self.state.cubic_bezier_to(ctrl1, ctrl2, to);
self.builder.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn arc(
&mut self,
center: Point,
radii: Vector,
sweep_angle: Angle,
x_rotation: Angle
) {
self.state.arc(center, radii, sweep_angle, x_rotation);
self.builder.arc(center, radii, sweep_angle, x_rotation);
}
}
impl<Builder: PathBuilder> SvgBuilder for SvgPathBuilder<Builder> {
fn relative_move_to(&mut self, to: Vector) {
self.state.relative_move_to(to);
self.builder.move_to(self.state.current_position());
}
fn relative_line_to(&mut self, to: Vector) {
self.state.relative_line_to(to);
self.builder.line_to(self.state.current_position());
}
fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) {
let offset = self.state.current_position();
self.state.relative_quadratic_bezier_to(ctrl, to);
self.builder.quadratic_bezier_to(offset + ctrl, offset + to);
}
fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector) {
let offset = self.state.current_position();
self.state.relative_cubic_bezier_to(ctrl1, ctrl2, to);
self.builder.cubic_bezier_to(offset + ctrl1, offset + ctrl2, offset + to);
}
fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) {
let ctrl1 = self.state.get_smooth_cubic_ctrl();
self.state.smooth_cubic_bezier_to(ctrl2, to);
self.builder.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) {
let ctrl1 = self.state.get_smooth_cubic_ctrl();
let offset = self.state.current_position();
self.state.smooth_relative_cubic_bezier_to(ctrl2, to);
self.builder.cubic_bezier_to(ctrl1, offset + ctrl2, offset + to);
}
fn smooth_quadratic_bezier_to(&mut self, to: Point) {
let ctrl = self.state.get_smooth_quadratic_ctrl();
self.state.smooth_quadratic_bezier_to(to);
self.builder.quadratic_bezier_to(ctrl, to);
}
fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) {
let ctrl = self.state.get_smooth_quadratic_ctrl();
let offset = self.state.current_position();
self.state.smooth_relative_quadratic_bezier_to(to);
self.builder.quadratic_bezier_to(ctrl, offset + to);
}
fn horizontal_line_to(&mut self, x: f32) {
self.state.horizontal_line_to(x);
self.builder.line_to(self.state.current_position());
}
fn relative_horizontal_line_to(&mut self, dx: f32) {
self.state.relative_horizontal_line_to(dx);
self.builder.line_to(self.state.current_position());
}
fn vertical_line_to(&mut self, y: f32) {
self.state.vertical_line_to(y);
self.builder.line_to(self.state.current_position());
}
fn relative_vertical_line_to(&mut self, dy: f32) {
self.state.relative_vertical_line_to(dy);
self.builder.line_to(self.state.current_position());
}
fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point) {
SvgArc {
from: self.state.current_position(),
to,
radii,
x_rotation,
flags: ArcFlags {
large_arc: flags.large_arc,
sweep: flags.sweep,
},
}.for_each_quadratic_bezier(&mut|curve| {
self.quadratic_bezier_to(curve.ctrl, curve.to);
});
self.state.arc_to(radii, x_rotation, flags, to);
}
fn relative_arc_to(
&mut self,
radii: Vector,
x_rotation: Angle,
flags: ArcFlags,
to: Vector,
) {
let offset = self.state.current_position();
self.arc_to(radii, x_rotation, flags, offset + to);
}
}
pub struct FlatteningBuilder<Builder> {
builder: Builder,
tolerance: f32,
}
impl<Builder: Build> Build for FlatteningBuilder<Builder> {
type PathType = Builder::PathType;
fn build(self) -> Builder::PathType { self.builder.build() }
fn build_and_reset(&mut self) -> Builder::PathType { self.builder.build_and_reset() }
}
impl<Builder: FlatPathBuilder> FlatPathBuilder for FlatteningBuilder<Builder> {
fn move_to(&mut self, to: Point) { self.builder.move_to(to); }
fn line_to(&mut self, to: Point) { self.builder.line_to(to); }
fn close(&mut self) { self.builder.close() }
fn current_position(&self) -> Point { self.builder.current_position() }
}
impl<Builder: FlatPathBuilder> PathBuilder for FlatteningBuilder<Builder> {
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
QuadraticBezierSegment {
from: self.current_position(),
ctrl,
to,
}.for_each_flattened(self.tolerance, &mut |point| { self.line_to(point); });
}
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
CubicBezierSegment {
from: self.current_position(),
ctrl1,
ctrl2,
to,
}.for_each_flattened(self.tolerance, &mut |point| { self.line_to(point); });
}
fn arc(
&mut self,
center: Point,
radii: Vector,
sweep_angle: Angle,
x_rotation: Angle
) {
let start_angle = (self.current_position() - center).angle_from_x_axis() - x_rotation;
Arc {
center,
radii,
start_angle,
sweep_angle,
x_rotation,
}.for_each_quadratic_bezier(&mut|curve| {
self.quadratic_bezier_to(curve.ctrl, curve.to);
});
}
}
impl<Builder: FlatPathBuilder> FlatteningBuilder<Builder> {
pub fn new(builder: Builder, tolerance: f32) -> FlatteningBuilder<Builder> {
FlatteningBuilder {
builder,
tolerance,
}
}
pub fn set_tolerance(&mut self, tolerance: f32) { self.tolerance = tolerance }
}