use std::iter;
use math::*;
use {PathEvent, SvgEvent, FlattenedEvent, QuadraticEvent, PathState};
use geom::{QuadraticBezierSegment, CubicBezierSegment, quadratic_bezier, cubic_bezier};
use geom::arc;
pub trait PathIterator: Iterator<Item = PathEvent> + Sized {
fn get_state(&self) -> &PathState;
fn flattened(self, tolerance: f32) -> Flattened<Self> {
Flattened::new(tolerance, self)
}
fn transformed(self, mat: &Transform2D) -> Transformed<Self> {
Transformed::new(mat, self)
}
}
pub trait SvgIterator: Iterator<Item = SvgEvent> + Sized {
fn get_state(&self) -> &PathState;
fn flattened(self, tolerance: f32) -> Flattened<PathEvents<Self>> {
self.path_events().flattened(tolerance)
}
fn path_events(self) -> PathEvents<Self> { PathEvents::new(self) }
}
pub trait FlattenedIterator: Iterator<Item = FlattenedEvent> + Sized {
fn get_state(&self) -> &PathState;
fn path_events(self) -> iter::Map<Self, fn(FlattenedEvent) -> PathEvent> {
self.map(flattened_to_path_event)
}
fn svg_events(self) -> iter::Map<Self, fn(FlattenedEvent) -> SvgEvent> {
self.map(flattened_to_svg_event)
}
fn transformed(self, mat: &Transform2D) -> Transformed<Self> {
Transformed::new(mat, self)
}
}
pub trait QuadraticPathIterator: Iterator<Item = QuadraticEvent> + Sized {
fn get_state(&self) -> &PathState;
fn path_events(self) -> iter::Map<Self, fn(QuadraticEvent) -> PathEvent> {
self.map(quadratic_to_path_event)
}
fn svg_events(self) -> iter::Map<Self, fn(QuadraticEvent) -> SvgEvent> {
self.map(quadratic_to_svg_event)
}
fn transformed(self, mat: &Transform2D) -> Transformed<Self> {
Transformed::new(mat, self)
}
}
pub struct PathEvents<SvgIter> {
it: SvgIter,
}
impl<SvgIter> PathEvents<SvgIter> {
pub fn new(it: SvgIter) -> Self { PathEvents { it } }
}
impl<SvgIter> PathIterator for PathEvents<SvgIter>
where
SvgIter: SvgIterator,
{
fn get_state(&self) -> &PathState { self.it.get_state() }
}
impl<SvgIter> Iterator for PathEvents<SvgIter>
where
SvgIter: SvgIterator,
{
type Item = PathEvent;
fn next(&mut self) -> Option<PathEvent> {
match self.it.next() {
Some(svg_evt) => Some(self.get_state().svg_to_path_event(svg_evt)),
None => None,
}
}
}
pub struct Flattened<Iter> {
it: Iter,
current_curve: TmpFlatteningIter,
tolerance: f32,
}
enum TmpFlatteningIter {
Quadratic(quadratic_bezier::Flattened<f32>),
Cubic(cubic_bezier::Flattened<f32>),
Arc(arc::Flattened<f32>),
None,
}
impl<Iter: PathIterator> Flattened<Iter> {
pub fn new(tolerance: f32, it: Iter) -> Self {
Flattened {
it,
current_curve: TmpFlatteningIter::None,
tolerance,
}
}
}
impl<Iter> FlattenedIterator for Flattened<Iter>
where
Iter: PathIterator,
{
fn get_state(&self) -> &PathState { self.it.get_state() }
}
impl<Iter> Iterator for Flattened<Iter>
where
Iter: PathIterator,
{
type Item = FlattenedEvent;
fn next(&mut self) -> Option<FlattenedEvent> {
match self.current_curve {
TmpFlatteningIter::Quadratic(ref mut it) => {
if let Some(point) = it.next() {
return Some(FlattenedEvent::LineTo(point));
}
}
TmpFlatteningIter::Cubic(ref mut it) => {
if let Some(point) = it.next() {
return Some(FlattenedEvent::LineTo(point));
}
}
TmpFlatteningIter::Arc(ref mut it) => {
if let Some(point) = it.next() {
return Some(FlattenedEvent::LineTo(point));
}
}
_ => {}
}
self.current_curve = TmpFlatteningIter::None;
let current = self.get_state().current;
match self.it.next() {
Some(PathEvent::MoveTo(to)) => Some(FlattenedEvent::MoveTo(to)),
Some(PathEvent::LineTo(to)) => Some(FlattenedEvent::LineTo(to)),
Some(PathEvent::Close) => Some(FlattenedEvent::Close),
Some(PathEvent::QuadraticTo(ctrl, to)) => {
self.current_curve = TmpFlatteningIter::Quadratic(
QuadraticBezierSegment {
from: current,
ctrl,
to,
}.flattened(self.tolerance)
);
self.next()
}
Some(PathEvent::CubicTo(ctrl1, ctrl2, to)) => {
self.current_curve = TmpFlatteningIter::Cubic(
CubicBezierSegment {
from: current,
ctrl1,
ctrl2,
to,
}.flattened(self.tolerance)
);
self.next()
}
Some(PathEvent::Arc(center, radii, sweep_angle, x_rotation)) => {
let start_angle = (current - center).angle_from_x_axis() - x_rotation;
self.current_curve = TmpFlatteningIter::Arc(
arc::Arc {
center, radii,
start_angle, sweep_angle,
x_rotation
}.flattened(self.tolerance)
);
self.next()
}
None => None,
}
}
}
pub struct SvgPathIter<Iter> {
it: Iter,
state: PathState,
}
impl<E, Iter> SvgPathIter<Iter>
where
E: Into<SvgEvent>,
Iter: Iterator<Item = E>
{
pub fn new(it: Iter) -> Self {
SvgPathIter {
it,
state: PathState::new(),
}
}
}
impl<E, Iter> SvgIterator for SvgPathIter<Iter>
where
E: Into<SvgEvent>,
Iter: Iterator<Item = E>
{
fn get_state(&self) -> &PathState { &self.state }
}
impl<E, Iter> Iterator for SvgPathIter<Iter>
where
E: Into<SvgEvent>,
Iter: Iterator<Item = E>
{
type Item = SvgEvent;
fn next(&mut self) -> Option<SvgEvent> {
if let Some(evt) = self.it.next() {
let svg_evt = evt.into();
self.state.svg_event(svg_evt);
return Some(svg_evt);
}
None
}
}
pub struct PathIter<Iter> {
it: Iter,
state: PathState,
}
impl<E, Iter> PathIter<Iter>
where
E: Into<PathEvent>,
Iter: Iterator<Item = E>
{
pub fn new(it: Iter) -> Self {
PathIter {
it,
state: PathState::new(),
}
}
}
impl<E, Iter> PathIterator for PathIter<Iter>
where
E: Into<PathEvent>,
Iter: Iterator<Item = E>
{
fn get_state(&self) -> &PathState { &self.state }
}
impl<E, Iter> Iterator for PathIter<Iter>
where
E: Into<PathEvent>,
Iter: Iterator<Item = E>
{
type Item = PathEvent;
fn next(&mut self) -> Option<PathEvent> {
if let Some(evt) = self.it.next() {
let path_evt = evt.into();
self.state.path_event(path_evt);
return Some(path_evt);
}
None
}
}
#[inline]
fn quadratic_to_path_event(evt: QuadraticEvent) -> PathEvent { evt.to_path_event() }
#[inline]
fn quadratic_to_svg_event(evt: QuadraticEvent) -> SvgEvent { evt.to_svg_event() }
#[inline]
fn flattened_to_path_event(evt: FlattenedEvent) -> PathEvent { evt.to_path_event() }
#[inline]
fn flattened_to_svg_event(evt: FlattenedEvent) -> SvgEvent { evt.to_svg_event() }
pub struct Transformed<I> {
it: I,
transform: Transform2D,
}
impl<I, Event> Transformed<I>
where
I: Iterator<Item = Event>,
Event: Transform
{
#[inline]
pub fn new(transform: &Transform2D, it: I) -> Transformed<I> {
Transformed {
it,
transform: *transform,
}
}
}
impl<I, Event> Iterator for Transformed<I>
where
I: Iterator<Item = Event>,
Event: Transform
{
type Item = Event;
fn next(&mut self) -> Option<Event> {
match self.it.next() {
None => None,
Some(ref evt) => Some(evt.transform(&self.transform)),
}
}
}
pub struct FromPolyline<Iter> {
iter: Iter,
first: bool,
done: bool,
close: bool,
}
impl<Iter: Iterator<Item = Point>> FromPolyline<Iter> {
pub fn new(close: bool, iter: Iter) -> Self {
FromPolyline {
iter,
first: true,
done: false,
close,
}
}
pub fn closed(iter: Iter) -> Self { FromPolyline::new(true, iter) }
pub fn open(iter: Iter) -> Self { FromPolyline::new(false, iter) }
pub fn path_iter(self) -> PathIter<Self> { PathIter::new(self) }
}
impl<Iter> Iterator for FromPolyline<Iter>
where
Iter: Iterator<Item = Point>,
{
type Item = FlattenedEvent;
fn next(&mut self) -> Option<FlattenedEvent> {
if self.done {
return None;
}
if let Some(next) = self.iter.next() {
return Some(
if self.first {
self.first = false;
FlattenedEvent::MoveTo(next)
} else {
FlattenedEvent::LineTo(next)
}
);
}
self.done = true;
if self.close {
return Some(FlattenedEvent::Close);
}
None
}
}
#[test]
fn test_from_polyline_open() {
let points = &[
point(1.0, 1.0),
point(3.0, 1.0),
point(4.0, 5.0),
point(5.0, 2.0),
];
let mut evts = FromPolyline::open(points.iter().cloned());
assert_eq!(evts.next(), Some(FlattenedEvent::MoveTo(point(1.0, 1.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(3.0, 1.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(4.0, 5.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(5.0, 2.0))));
assert_eq!(evts.next(), None);
}
#[test]
fn test_from_polyline_closed() {
let points = &[
point(1.0, 1.0),
point(3.0, 1.0),
point(4.0, 5.0),
point(5.0, 2.0),
];
let mut evts = FromPolyline::closed(points.iter().cloned());
assert_eq!(evts.next(), Some(FlattenedEvent::MoveTo(point(1.0, 1.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(3.0, 1.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(4.0, 5.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::LineTo(point(5.0, 2.0))));
assert_eq!(evts.next(), Some(FlattenedEvent::Close));
}