#![allow(clippy::needless_collect)]
use super::bounds::*;
use super::to_curves::*;
use super::super::curve::*;
use super::super::super::geo::*;
use itertools::*;
use std::vec;
use std::iter;
pub trait BezierPath : Geo+Clone+Sized {
type PointIter: Iterator<Item=(Self::Point, Self::Point, Self::Point)>;
fn start_point(&self) -> Self::Point;
fn points(&self) -> Self::PointIter;
#[inline]
fn bounding_box<Bounds: BoundingBox<Point=Self::Point>>(&self) -> Bounds {
path_bounding_box(self)
}
fn fast_bounding_box<Bounds: BoundingBox<Point=Self::Point>>(&self) -> Bounds {
path_fast_bounding_box(self)
}
#[inline]
fn to_curves<Curve: BezierCurveFactory<Point=Self::Point>>(&self) -> Vec<Curve> {
path_to_curves(self).collect()
}
fn reversed<POut>(&self) -> POut
where
POut: BezierPathFactory<Point=Self::Point>,
{
let fake_first_point = (Self::Point::origin(), Self::Point::origin(), self.start_point());
let points = self.points();
let points = iter::once(fake_first_point).chain(points);
let mut end_point = self.start_point();
let mut reversed_points = vec![];
for ((_, _, start_point), (cp1, cp2, last_point)) in points.tuple_windows() {
end_point = last_point;
reversed_points.push((cp2, cp1, start_point));
}
POut::from_points(end_point, reversed_points.into_iter().rev())
}
#[inline]
fn map_points<POut>(&self, map_fn: impl Fn(Self::Point) -> Self::Point) -> POut
where
POut: BezierPathFactory<Point=Self::Point>,
{
let start_point = map_fn(self.start_point());
POut::from_points(start_point, self.points().map(|(p1, p2, p3)|
(map_fn(p1), map_fn(p2), map_fn(p3))
))
}
#[inline]
fn with_offset<POut>(&self, offset: Self::Point) -> POut
where
POut: BezierPathFactory<Point=Self::Point>,
{
self.map_points(|p| p + offset)
}
}
pub trait BezierPathFactory : BezierPath {
fn from_points<FromIter: IntoIterator<Item=(Self::Point, Self::Point, Self::Point)>>(start_point: Self::Point, points: FromIter) -> Self;
fn from_path<FromPath: BezierPath<Point=Self::Point>>(path: &FromPath) -> Self {
Self::from_points(path.start_point(), path.points())
}
fn from_connected_curves<TCurve: BezierCurve<Point=Self::Point>>(curves: impl IntoIterator<Item=TCurve>) -> Self {
let mut curves = curves.into_iter();
let first_curve = curves.next();
let start_point = first_curve.as_ref().map(|c| c.start_point()).unwrap_or_else(|| Self::Point::origin());
let points = first_curve.into_iter().chain(curves)
.map(|curve| {
let (_, (cp1, cp2), ep) = curve.all_points();
(cp1, cp2, ep)
});
Self::from_points(start_point, points)
}
}
impl<Point: Clone+Coordinate> Geo for (Point, Vec<(Point, Point, Point)>) {
type Point = Point;
}
impl<Point: Clone+Coordinate> BezierPath for (Point, Vec<(Point, Point, Point)>) {
type PointIter = vec::IntoIter<(Point, Point, Point)>;
fn start_point(&self) -> Self::Point {
self.0
}
fn points(&self) -> Self::PointIter {
self.1.clone().into_iter()
}
}
impl<Point: Clone+Coordinate> BezierPathFactory for (Point, Vec<(Point, Point, Point)>) {
fn from_points<FromIter: IntoIterator<Item=(Self::Point, Self::Point, Self::Point)>>(start_point: Self::Point, points: FromIter) -> Self {
(start_point, points.into_iter().collect())
}
}
pub type SimpleBezierPath = (Coord2, Vec<(Coord2, Coord2, Coord2)>);
pub type SimpleBezierPath3 = (Coord3, Vec<(Coord3, Coord3, Coord3)>);