use super::command::{Command, TransformCommands};
use super::geometry::*;
use super::path_data::PathData;
use super::segment::{segments, Segment, Segments};
use core::borrow::Borrow;
use core::cell::RefCell;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Vertex {
Start(Point, Vector),
Middle(Vector, Point, Vector),
End(Vector, Point, bool),
}
#[derive(Clone)]
pub struct Vertices<D> {
segments: Segments<D>,
prev_point: Point,
prev_dir: Vector,
is_first: bool,
}
impl<D> Vertices<D>
where
D: Iterator<Item = Command> + Clone,
{
pub fn new(data: impl PathData<Commands = D>) -> Self {
Self {
segments: segments(data.commands(), false),
prev_point: Point::ZERO,
prev_dir: Vector::new(1., 0.),
is_first: true,
}
}
}
impl<D> Vertices<TransformCommands<D>>
where
D: Iterator<Item = Command> + Clone,
{
pub fn with_transform(data: impl PathData<Commands = D>, transform: Transform) -> Self {
let data = TransformCommands {
data: data.commands(),
transform,
};
Self {
segments: segments(data, false),
prev_point: Point::ZERO,
prev_dir: Vector::new(1., 0.),
is_first: true,
}
}
}
impl<D> Iterator for Vertices<D>
where
D: Iterator + Clone,
D::Item: Borrow<Command>,
{
type Item = Vertex;
fn next(&mut self) -> Option<Self::Item> {
use Segment::*;
if self.is_first {
self.is_first = false;
match self.segments.next()?.borrow() {
End(closed) => {
self.is_first = true;
return Some(Vertex::End(self.prev_dir, self.prev_point, *closed));
}
segment => {
let (start, in_dir, out_dir, end) = get_components(segment);
self.prev_dir = out_dir;
self.prev_point = end;
return Some(Vertex::Start(start, in_dir));
}
}
} else {
match self.segments.next()?.borrow() {
End(closed) => {
self.is_first = true;
return Some(Vertex::End(self.prev_dir, self.prev_point, *closed));
}
segment => {
let (start, in_dir, out_dir, end) = get_components(segment);
let prev_dir = self.prev_dir;
self.prev_dir = out_dir;
self.prev_point = end;
return Some(Vertex::Middle(prev_dir, start, in_dir));
}
}
}
}
}
fn get_components(segment: &Segment) -> (Point, Vector, Vector, Point) {
match segment {
Segment::Curve(_, curve) => {
let a = curve.evaluate(0.05);
let b = curve.evaluate(0.95);
let a_dir = (a - curve.a).normalize();
let b_dir = (curve.d - b).normalize();
(curve.a, a_dir, b_dir, curve.d)
}
Segment::Line(_, line) => {
let dir = (line.b - line.a).normalize();
(line.a, dir, dir, line.b)
}
Segment::End(..) => (Point::ZERO, Vector::ZERO, Vector::ZERO, Point::ZERO),
}
}
pub struct Walk<D> {
init: Segments<D>,
iter: Segments<D>,
segment: Segment,
segment_offset: f32,
first: bool,
length: RefCell<Option<f32>>,
walked: f32,
}
impl<D> Walk<D>
where
D: Iterator<Item = Command> + Clone,
{
pub fn new(data: impl PathData<Commands = D>) -> Self {
let data = data.commands();
Self {
init: segments(data.clone(), false),
iter: segments(data, false),
segment: Segment::default(),
segment_offset: 0.,
first: true,
length: RefCell::new(None),
walked: 0.,
}
}
}
impl<D> Walk<TransformCommands<D>>
where
D: Iterator<Item = Command> + Clone,
{
pub fn with_transform(data: impl PathData<Commands = D>, transform: Transform) -> Self {
let data = data.commands();
let data = TransformCommands { data, transform };
Self {
init: segments(data.clone(), false),
iter: segments(data, false),
segment: Segment::default(),
segment_offset: 0.,
first: true,
length: RefCell::new(None),
walked: 0.,
}
}
}
impl<D> Walk<D>
where
D: Iterator + Clone,
D::Item: Borrow<Command>,
{
pub fn step(&mut self, distance: f32) -> Option<(Point, Vector)> {
if self.first {
self.segment = self.next_segment()?;
self.segment_offset = 0.;
self.first = false;
}
let mut t;
let mut offset = self.segment_offset;
let mut segment = self.segment;
let mut remaining = distance;
loop {
let dt = segment.time(offset + remaining, 1.);
remaining -= dt.distance - offset;
t = dt.time;
offset = dt.distance;
if remaining <= 0. {
break;
}
segment = self.next_segment()?;
offset = 0.;
}
self.segment = segment;
self.segment_offset = offset;
self.walked += distance;
let (p, n) = segment.point_normal(t);
Some((p, n))
}
pub fn remaining(&self) -> f32 {
let mut l = self.length.borrow_mut();
if l.is_none() {
let iter = self.init.clone();
let mut sum = 0.;
for s in iter {
sum += s.length();
}
*l = Some(sum);
}
l.unwrap() - self.walked
}
fn next_segment(&mut self) -> Option<Segment> {
while let Some(s) = self.iter.next() {
match s {
Segment::End(..) => continue,
_ => return Some(s),
}
}
None
}
}