use crate::scalar::{Scalar, One};
use crate::generic_math::{Point, Vector, Rect};
use crate::{LineSegment, QuadraticBezierSegment, CubicBezierSegment};
use std::ops::Range;
pub trait Segment: Copy + Sized {
type Scalar: Scalar;
fn from(&self) -> Point<Self::Scalar>;
fn to(&self) -> Point<Self::Scalar>;
fn sample(&self, t: Self::Scalar) -> Point<Self::Scalar>;
fn x(&self, t: Self::Scalar) -> Self::Scalar { self.sample(t).x }
fn y(&self, t: Self::Scalar) -> Self::Scalar { self.sample(t).y }
fn derivative(&self, t: Self::Scalar) -> Vector<Self::Scalar>;
fn dx(&self, t: Self::Scalar) -> Self::Scalar { self.derivative(t).x }
fn dy(&self, t: Self::Scalar) -> Self::Scalar { self.derivative(t).y }
fn split(&self, t: Self::Scalar) -> (Self, Self);
fn before_split(&self, t: Self::Scalar) -> Self;
fn after_split(&self, t: Self::Scalar) -> Self;
fn split_range(&self, t_range: Range<Self::Scalar>) -> Self;
fn flip(&self) -> Self;
fn approximate_length(&self, tolerance: Self::Scalar) -> Self::Scalar;
}
pub trait BoundingRect {
type Scalar: Scalar;
fn bounding_rect(&self) -> Rect<Self::Scalar>;
fn fast_bounding_rect(&self) -> Rect<Self::Scalar> { self.bounding_rect() }
fn bounding_range_x(&self) -> (Self::Scalar, Self::Scalar);
fn bounding_range_y(&self) -> (Self::Scalar, Self::Scalar);
fn fast_bounding_range_x(&self) -> (Self::Scalar, Self::Scalar);
fn fast_bounding_range_y(&self) -> (Self::Scalar, Self::Scalar);
}
pub trait FlattenedForEach: Segment {
fn for_each_flattened<F: FnMut(Point<Self::Scalar>)>(&self, tolerance: Self::Scalar, call_back: &mut F);
}
pub trait FlatteningStep: FlattenedForEach {
fn flattening_step(&self, tolerance: Self::Scalar) -> Self::Scalar;
fn flattened(self, tolerance: Self::Scalar) -> Flattened<Self::Scalar, Self> {
Flattened::new(self, tolerance)
}
}
impl<T> FlattenedForEach for T
where T: FlatteningStep
{
fn for_each_flattened<F: FnMut(Point<Self::Scalar>)>(&self, tolerance: Self::Scalar, call_back: &mut F) {
let mut iter = *self;
loop {
let t = iter.flattening_step(tolerance);
if t >= Self::Scalar::one() {
call_back(iter.to());
break;
}
iter = iter.after_split(t);
call_back(iter.from());
}
}
}
pub struct Flattened<S, T> {
curve: T,
tolerance: S,
done: bool,
}
impl<S: Scalar, T: FlatteningStep> Flattened<S, T> {
pub fn new(curve: T, tolerance: S) -> Self {
assert!(tolerance > S::ZERO);
Flattened {
curve: curve,
tolerance: tolerance,
done: false,
}
}
}
impl<S: Scalar, T: FlatteningStep<Scalar=S>> Iterator for Flattened<S, T>
{
type Item = Point<S>;
fn next(&mut self) -> Option<Point<S>> {
if self.done {
return None;
}
let t = self.curve.flattening_step(self.tolerance);
if t >= S::ONE {
self.done = true;
return Some(self.curve.to());
}
self.curve = self.curve.after_split(t);
return Some(self.curve.from());
}
}
pub(crate) fn approximate_length_from_flattening<S: Scalar, T>(curve: &T, tolerance: S) -> S
where T: FlattenedForEach<Scalar=S>
{
let mut start = curve.from();
let mut len = S::ZERO;
curve.for_each_flattened(tolerance, &mut|p| {
len = len + (p - start).length();
start = p;
});
return len;
}
macro_rules! impl_segment {
($S:ty) => (
type Scalar = $S;
fn from(&self) -> Point<$S> { self.from() }
fn to(&self) -> Point<$S> { self.to() }
fn sample(&self, t: $S) -> Point<$S> { self.sample(t) }
fn x(&self, t: $S) -> $S { self.x(t) }
fn y(&self, t: $S) -> $S { self.y(t) }
fn derivative(&self, t: $S) -> Vector<$S> { self.derivative(t) }
fn dx(&self, t: $S) -> $S { self.dx(t) }
fn dy(&self, t: $S) -> $S { self.dy(t) }
fn split(&self, t: $S) -> (Self, Self) { self.split(t) }
fn before_split(&self, t: $S) -> Self { self.before_split(t) }
fn after_split(&self, t: $S) -> Self { self.after_split(t) }
fn split_range(&self, t_range: Range<$S>) -> Self { self.split_range(t_range) }
fn flip(&self) -> Self { self.flip() }
fn approximate_length(&self, tolerance: $S) -> $S {
self.approximate_length(tolerance)
}
)
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BezierSegment<S> {
Linear(LineSegment<S>),
Quadratic(QuadraticBezierSegment<S>),
Cubic(CubicBezierSegment<S>),
}
impl<S: Scalar> BezierSegment<S> {
#[inline]
pub fn sample(&self, t: S) -> Point<S> {
match self {
BezierSegment::Linear(segment) => segment.sample(t),
BezierSegment::Quadratic(segment) => segment.sample(t),
BezierSegment::Cubic(segment) => segment.sample(t),
}
}
#[inline]
pub fn from(&self) -> Point<S> {
match self {
BezierSegment::Linear(segment) => segment.from,
BezierSegment::Quadratic(segment) => segment.from,
BezierSegment::Cubic(segment) => segment.from,
}
}
#[inline]
pub fn to(&self) -> Point<S> {
match self {
BezierSegment::Linear(segment) => segment.to,
BezierSegment::Quadratic(segment) => segment.to,
BezierSegment::Cubic(segment) => segment.to,
}
}
#[inline]
pub fn is_linear(&self, tolerance: S) -> bool {
match self {
BezierSegment::Linear(..) => true,
BezierSegment::Quadratic(segment) => segment.is_linear(tolerance),
BezierSegment::Cubic(segment) => segment.is_linear(tolerance),
}
}
#[inline]
pub fn baseline(&self) -> LineSegment<S> {
match self {
BezierSegment::Linear(segment) => *segment,
BezierSegment::Quadratic(segment) => segment.baseline(),
BezierSegment::Cubic(segment) => segment.baseline(),
}
}
pub fn split(&self, t: S) -> (BezierSegment<S>, BezierSegment<S>) {
match self {
BezierSegment::Linear(segment) => {
let (a, b) = segment.split(t);
(BezierSegment::Linear(a), BezierSegment::Linear(b))
}
BezierSegment::Quadratic(segment) => {
let (a, b) = segment.split(t);
(BezierSegment::Quadratic(a), BezierSegment::Quadratic(b))
}
BezierSegment::Cubic(segment) => {
let (a, b) = segment.split(t);
(BezierSegment::Cubic(a), BezierSegment::Cubic(b))
}
}
}
}
impl<S> From<LineSegment<S>> for BezierSegment<S> {
fn from(s: LineSegment<S>) -> Self {
BezierSegment::Linear(s)
}
}
impl<S> From<QuadraticBezierSegment<S>> for BezierSegment<S> {
fn from(s: QuadraticBezierSegment<S>) -> Self {
BezierSegment::Quadratic(s)
}
}
impl<S> From<CubicBezierSegment<S>> for BezierSegment<S> {
fn from(s: CubicBezierSegment<S>) -> Self {
BezierSegment::Cubic(s)
}
}