zeno/
command.rs

1//! Path commands.
2
3use super::geometry::{Point, Transform};
4use super::path_builder::PathBuilder;
5
6use core::borrow::Borrow;
7
8/// Path command.
9#[derive(Copy, Clone, PartialEq, Debug)]
10pub enum Command {
11    /// Begins a new subpath at the specified point.
12    MoveTo(Point),
13    /// A straight line from the previous point to the specified point.
14    LineTo(Point),
15    /// A cubic bezier curve from the previous point to the final point with
16    /// two intermediate control points.
17    CurveTo(Point, Point, Point),
18    /// A quadratic curve from the previous point to the final point with one
19    /// intermediate control point.
20    QuadTo(Point, Point),
21    /// Closes a subpath, connecting the final point to the initial point.
22    Close,
23}
24
25impl Command {
26    /// Returns the associated verb for the command.
27    pub fn verb(&self) -> Verb {
28        use Command::*;
29        match self {
30            MoveTo(..) => Verb::MoveTo,
31            LineTo(..) => Verb::LineTo,
32            QuadTo(..) => Verb::QuadTo,
33            CurveTo(..) => Verb::CurveTo,
34            Close => Verb::CurveTo,
35        }
36    }
37
38    /// Returns the result of a transformation matrix applied to the command.
39    #[inline]
40    pub fn transform(&self, transform: &Transform) -> Self {
41        use Command::*;
42        let t = transform;
43        match self {
44            MoveTo(p) => MoveTo(t.transform_point(*p)),
45            LineTo(p) => LineTo(t.transform_point(*p)),
46            QuadTo(c, p) => QuadTo(t.transform_point(*c), t.transform_point(*p)),
47            CurveTo(c1, c2, p) => CurveTo(
48                t.transform_point(*c1),
49                t.transform_point(*c2),
50                t.transform_point(*p),
51            ),
52            Close => Close,
53        }
54    }
55}
56
57/// Action of a path command.
58#[derive(Copy, Clone, PartialEq, Eq, Debug)]
59pub enum Verb {
60    MoveTo,
61    LineTo,
62    CurveTo,
63    QuadTo,
64    Close,
65}
66
67#[derive(Clone)]
68pub struct PointsCommands<'a> {
69    points: &'a [Point],
70    verbs: &'a [Verb],
71    point: usize,
72    verb: usize,
73}
74
75impl<'a> PointsCommands<'a> {
76    pub(super) fn new(points: &'a [Point], verbs: &'a [Verb]) -> Self {
77        Self {
78            points,
79            verbs,
80            point: 0,
81            verb: 0,
82        }
83    }
84
85    #[inline(always)]
86    pub(super) fn copy_to(&self, sink: &mut impl PathBuilder) {
87        self.copy_to_inner(sink);
88    }
89
90    #[inline(always)]
91    fn copy_to_inner(&self, sink: &mut impl PathBuilder) -> Option<()> {
92        let mut i = 0;
93        for verb in self.verbs {
94            match verb {
95                Verb::MoveTo => {
96                    let p = self.points.get(i)?;
97                    i += 1;
98                    sink.move_to(*p);
99                }
100                Verb::LineTo => {
101                    let p = self.points.get(i)?;
102                    i += 1;
103                    sink.line_to(*p);
104                }
105                Verb::QuadTo => {
106                    let p = self.points.get(i + 1)?;
107                    let c = self.points.get(i)?;
108                    i += 2;
109                    sink.quad_to(*c, *p);
110                }
111                Verb::CurveTo => {
112                    let p = self.points.get(i + 2)?;
113                    let c2 = self.points.get(i + 1)?;
114                    let c1 = self.points.get(i)?;
115                    i += 3;
116                    sink.curve_to(*c1, *c2, *p);
117                }
118                Verb::Close => {
119                    sink.close();
120                }
121            }
122        }
123        Some(())
124    }
125}
126
127impl Iterator for PointsCommands<'_> {
128    type Item = Command;
129
130    #[inline(always)]
131    fn next(&mut self) -> Option<Self::Item> {
132        use Command::*;
133        let verb = self.verbs.get(self.verb)?;
134        self.verb += 1;
135        Some(match verb {
136            Verb::MoveTo => {
137                let p = self.points.get(self.point)?;
138                self.point += 1;
139                MoveTo(*p)
140            }
141            Verb::LineTo => {
142                let p = self.points.get(self.point)?;
143                self.point += 1;
144                LineTo(*p)
145            }
146            Verb::QuadTo => {
147                let p = self.points.get(self.point..self.point + 2)?;
148                self.point += 2;
149                QuadTo(p[0], p[1])
150            }
151            Verb::CurveTo => {
152                let p = self.points.get(self.point..self.point + 3)?;
153                self.point += 3;
154                CurveTo(p[0], p[1], p[2])
155            }
156            Verb::Close => Close,
157        })
158    }
159}
160
161#[derive(Clone)]
162pub struct TransformCommands<D> {
163    pub data: D,
164    pub transform: Transform,
165}
166
167impl<D> Iterator for TransformCommands<D>
168where
169    D: Iterator + Clone,
170    D::Item: Borrow<Command>,
171{
172    type Item = Command;
173
174    fn next(&mut self) -> Option<Self::Item> {
175        Some(self.data.next()?.borrow().transform(&self.transform))
176    }
177}