1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use crate::point::{Vec2D, Unit};
use crate::geom::{
segment_intersects_circle, bezier_intersects_circle,
};
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct CubicBezierCurve<T: Unit> {
pub pt1: Vec2D<T>,
pub pt2: Vec2D<T>,
pub to: Vec2D<T>,
}
impl<T: Unit> CubicBezierCurve<T> {
pub fn is_nan(&self) -> bool {
self.pt1.is_nan() || self.pt2.is_nan() || self.to.is_nan()
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum PathCommand<T: Unit> {
MoveTo(Vec2D<T>),
LineTo(Vec2D<T>),
CurveTo(CubicBezierCurve<T>),
}
impl<T: Unit + 'static> PathCommand<T> {
pub fn is_nan(&self) -> bool {
match self {
PathCommand::MoveTo(p) => p.is_nan(),
PathCommand::LineTo(p) => p.is_nan(),
PathCommand::CurveTo(c) => c.is_nan(),
}
}
pub fn to(&self) -> Vec2D<T> {
match *self {
PathCommand::MoveTo(p) => p,
PathCommand::LineTo(p) => p,
PathCommand::CurveTo(c) => c.to,
}
}
pub fn intersects_circle(&self, center: Vec2D<T>, radius: T, prev: Option<Vec2D<T>>) -> bool {
match *self {
PathCommand::MoveTo(p) => p.distance(center) < radius,
PathCommand::LineTo(p) => {
p.distance(center) < radius || segment_intersects_circle(prev, p, center, radius)
}
PathCommand::CurveTo(p) => {
p.to.distance(center) < radius || bezier_intersects_circle(prev, p.pt1, p.pt2, p.to, center, radius)
}
}
}
pub fn points(&self) -> Box<dyn Iterator<Item=Vec2D<T>>> {
match *self {
PathCommand::MoveTo(p) => Box::new(IntoIterator::into_iter([p])),
PathCommand::LineTo(p) => Box::new(IntoIterator::into_iter([p])),
PathCommand::CurveTo(CubicBezierCurve { pt1, pt2, to }) => Box::new(IntoIterator::into_iter([pt1, pt2, to])),
}
}
}