1 //! Move at a defined speed along a path.
2 //!
3 //! # Path walking
4 //!
5 //! ## Overview
6 //!
7 //! In principle, walking a path is similar to iterating over it,
8 //! but instead of going from receiving path segments (of varying
9 //! sizes), the path walker makes it possible to advance by a certain
10 //! distance along the path.
11 //!
12 //! ## Example
13 //!
14 //! ```
15 //! use lyon_algorithms::walk::{RegularPattern, walk_along_path};
16 //! use lyon_algorithms::path::PathSlice;
17 //! use lyon_algorithms::path::iterator::*;
18 //! use lyon_algorithms::path::math::Point;
19 //!
20 //! fn dots_along_path(path: PathSlice, dots: &mut Vec<Point>) {
21 //!     let mut pattern = RegularPattern {
22 //!         callback: &mut |position, _tangent, _distance| {
23 //!             dots.push(position);
24 //!             true // Return true to continue walking the path.
25 //!         },
26 //!         // Invoke the callback above at a regular interval of 3 units.
27 //!         interval: 3.0,
28 //!     };
29 //!
30 //!     let tolerance = 0.01; // The path flattening tolerance.
31 //!     let start_offset = 0.0; // Start walking at the beginning of the path.
32 //!     walk_along_path(
33 //!         path.iter().flattened(tolerance),
34 //!         start_offset,
35 //!         &mut pattern
36 //!     );
37 //! }
38 //!
39 //! ```
40 //!
41 
42 use crate::math::*;
43 use crate::geom::{QuadraticBezierSegment, CubicBezierSegment, Arc};
44 use crate::path::builder::*;
45 use crate::path::PathEvent;
46 
47 use std::f32;
48 
49 /// Walks along the path staring at offset `start` and applies a `Pattern`.
walk_along_path<Iter>(path: Iter, start: f32, pattern: &mut dyn Pattern) where Iter: Iterator<Item=PathEvent>50 pub fn walk_along_path<Iter>(path: Iter, start: f32, pattern: &mut dyn Pattern)
51 where Iter: Iterator<Item=PathEvent> {
52     let mut walker = PathWalker::new(start, pattern);
53     for evt in path {
54         walker.path_event(evt);
55         if walker.done {
56             return;
57         }
58     }
59 }
60 
61 /// Types implementing the `Pattern` can be used to walk along a path
62 /// at constant speed.
63 ///
64 /// At each step, the pattern receives the position, tangent and already
65 /// traversed distance along the path and returns the distance until the
66 /// next step.
67 ///
68 /// See the `RegularPattern` and `RepeatedPattern` implementations.
69 /// This trait is also implemented for all functions/closures with signature
70 /// `FnMut(Point, Vector, f32) -> Option<f32>`.
71 pub trait Pattern {
72     /// This method is invoked at each step along the path.
73     ///
74     /// If this method returns None, path walking stops. Otherwise the returned
75     /// value is the distance along the path to the next element in the pattern.
next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32>76     fn next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32>;
77 
78     /// Invoked at the start each sub-path.
79     ///
80     /// Takes the leftover requested distance from the previous sub-path path,
81     /// if any.
82     ///
83     /// If this method returns None, path walking stops. Otherwise the returned
84     /// value is the distance along the path to the next element in the pattern.
begin(&mut self, distance: f32) -> Option<f32>85     fn begin(&mut self, distance: f32) -> Option<f32> { Some(distance) }
86 }
87 
88 /// A helper struct to walk along a flattened path using a builder API.
89 pub struct PathWalker<'l> {
90     prev: Point,
91     advancement: f32,
92     leftover: f32,
93     next_distance: f32,
94     first: Point,
95     need_moveto: bool,
96     done: bool,
97 
98     pattern: &'l mut dyn Pattern,
99 }
100 
101 impl<'l> PathWalker<'l> {
new(start: f32, pattern: &'l mut dyn Pattern) -> PathWalker<'l>102     pub fn new(start: f32, pattern: &'l mut dyn Pattern) -> PathWalker<'l> {
103         let start = f32::max(start, 0.0);
104         PathWalker {
105             prev: point(0.0, 0.0),
106             first: point(0.0, 0.0),
107             advancement: 0.0,
108             leftover: 0.0,
109             next_distance: start,
110             need_moveto: true,
111             done: false,
112             pattern,
113         }
114     }
115 }
116 
117 impl<'l> FlatPathBuilder for PathWalker<'l> {
move_to(&mut self, to: Point)118     fn move_to(&mut self, to: Point) {
119         self.need_moveto = false;
120         self.first = to;
121         self.prev = to;
122 
123         if let Some(distance) = self.pattern.begin(self.next_distance) {
124             self.next_distance = distance;
125         } else {
126             self.done = true;
127         }
128     }
129 
line_to(&mut self, to: Point)130     fn line_to(&mut self, to: Point) {
131         if self.need_moveto {
132             self.move_to(self.first);
133             if self.done {
134                 return;
135             }
136         }
137 
138         let v = to - self.prev;
139         let d = v.length();
140 
141         if d < 1e-5 {
142             return;
143         }
144 
145         let tangent = v / d;
146 
147         let mut distance = self.leftover + d;
148         while distance >= self.next_distance {
149             let position = self.prev + tangent * (self.next_distance - self.leftover);
150             self.prev = position;
151             self.leftover = 0.0;
152             self.advancement += self.next_distance;
153             distance -= self.next_distance;
154 
155             if let Some(distance) = self.pattern.next(position, tangent, self.advancement) {
156                 self.next_distance = distance;
157             } else {
158                 self.done = true;
159             }
160         }
161 
162         self.prev = to;
163         self.leftover = distance;
164     }
165 
close(&mut self)166     fn close(&mut self) {
167         let first = self.first;
168         self.line_to(first);
169         self.need_moveto = true;
170     }
171 
current_position(&self) -> Point172     fn current_position(&self) -> Point { self.prev }
173 }
174 
175 impl<'l> PathBuilder for PathWalker<'l> {
quadratic_bezier_to(&mut self, ctrl: Point, to: Point)176     fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
177         let curve = QuadraticBezierSegment {
178             from: self.prev,
179             ctrl,
180             to,
181         };
182         curve.for_each_flattened(0.01, &mut |p| {
183             self.line_to(p);
184         });
185     }
186 
cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point)187     fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
188         let curve = CubicBezierSegment {
189             from: self.prev,
190             ctrl1,
191             ctrl2,
192             to,
193         };
194         curve.for_each_flattened(0.01, &mut |p| {
195             self.line_to(p);
196         });
197     }
198 
arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle)199     fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) {
200         let start_angle = (self.current_position() - center).angle_from_x_axis() - x_rotation;
201         Arc {
202             center,
203             radii,
204             start_angle,
205             sweep_angle,
206             x_rotation,
207         }.for_each_flattened(0.01, &mut |p| {
208             self.line_to(p);
209         });
210     }
211 }
212 
213 impl<'l> PolygonBuilder for PathWalker<'l> {
214     /// Add a closed polygon.
polygon(&mut self, points: &[Point])215     fn polygon(&mut self, points: &[Point]) {
216         build_polygon(self, points);
217     }
218 }
219 
220 /// A simple pattern that invokes a callback at regular intervals.
221 ///
222 /// If the callback returns false, path walking stops.
223 pub struct RegularPattern<Cb> {
224     /// The function to call at each step.
225     pub callback: Cb,
226     /// A constant interval between each step.
227     pub interval: f32,
228 }
229 
230 impl<Cb> Pattern for RegularPattern<Cb>
231 where Cb: FnMut(Point, Vector, f32) -> bool {
232     #[inline]
next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32>233     fn next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32> {
234         if !(self.callback)(position, tangent, distance) {
235             return None;
236         }
237         Some(self.interval)
238     }
239 }
240 
241 /// A pattern that invokes a callback at a repeated sequence of
242 /// constant intervals.
243 ///
244 /// If the callback returns false, path walking stops.
245 pub struct RepeatedPattern<'l, Cb> {
246     /// The function to call at each step.
247     pub callback: Cb,
248     /// The repeated interval sequence.
249     pub intervals: &'l[f32],
250     /// The index of the next interval in the sequence.
251     pub index: usize,
252 }
253 
254 impl<'l, Cb> Pattern for RepeatedPattern<'l, Cb>
255 where Cb: FnMut(Point, Vector, f32) -> bool {
256     #[inline]
next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32>257     fn next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32> {
258         if !(self.callback)(position, tangent, distance) {
259             return None;
260         }
261         let idx = self.index % self.intervals.len();
262         self.index += 1;
263         Some(self.intervals[idx])
264     }
265 }
266 
267 impl<Cb> Pattern for Cb
268 where Cb: FnMut(Point, Vector, f32) -> Option<f32> {
269     #[inline]
next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32>270     fn next(&mut self, position: Point, tangent: Vector, distance: f32) -> Option<f32> {
271         (self)(position, tangent, distance)
272     }
273 }
274 
275 #[test]
walk_square()276 fn walk_square() {
277     let expected = [
278         (point(0.0, 0.0), vector(1.0, 0.0), 0.0),
279         (point(2.0, 0.0), vector(1.0, 0.0), 2.0),
280         (point(4.0, 0.0), vector(1.0, 0.0), 4.0),
281         (point(6.0, 0.0), vector(1.0, 0.0), 6.0),
282         (point(6.0, 2.0), vector(0.0, 1.0), 8.0),
283         (point(6.0, 4.0), vector(0.0, 1.0), 10.0),
284         (point(6.0, 6.0), vector(0.0, 1.0), 12.0),
285         (point(4.0, 6.0), vector(-1.0, 0.0), 14.0),
286         (point(2.0, 6.0), vector(-1.0, 0.0), 16.0),
287         (point(0.0, 6.0), vector(-1.0, 0.0), 18.0),
288         (point(0.0, 4.0), vector(0.0, -1.0), 20.0),
289         (point(0.0, 2.0), vector(0.0, -1.0), 22.0),
290         (point(0.0, 0.0), vector(0.0, -1.0), 24.0),
291     ];
292 
293     let mut i = 0;
294     let mut pattern = RegularPattern {
295         interval: 2.0,
296         callback: |pos, n, d| {
297             println!("p:{:?} n:{:?} d:{:?}", pos, n, d);
298             assert_eq!(pos, expected[i].0);
299             assert_eq!(n, expected[i].1);
300             assert_eq!(d, expected[i].2);
301             i += 1;
302             true
303         },
304     };
305 
306     let mut walker = PathWalker::new(0.0, &mut pattern);
307 
308     walker.move_to(point(0.0, 0.0));
309     walker.line_to(point(6.0, 0.0));
310     walker.line_to(point(6.0, 6.0));
311     walker.line_to(point(0.0, 6.0));
312     walker.close();
313 }
314 
315 #[test]
walk_with_leftover()316 fn walk_with_leftover() {
317     let expected = [
318         (point(1.0, 0.0), vector(1.0, 0.0), 1.0),
319         (point(4.0, 0.0), vector(1.0, 0.0), 4.0),
320         (point(5.0, 2.0), vector(0.0, 1.0), 7.0),
321         (point(5.0, 5.0), vector(0.0, 1.0), 10.0),
322         (point(2.0, 5.0), vector(-1.0, 0.0), 13.0),
323         (point(0.0, 4.0), vector(0.0, -1.0), 16.0),
324         (point(0.0, 1.0), vector(0.0, -1.0), 19.0),
325     ];
326 
327     let mut i = 0;
328     let mut pattern = RegularPattern {
329         interval: 3.0,
330         callback: |pos, n, d| {
331             println!("p:{:?} n:{:?} d:{:?}", pos, n, d);
332             assert_eq!(pos, expected[i].0);
333             assert_eq!(n, expected[i].1);
334             assert_eq!(d, expected[i].2);
335             i += 1;
336             true
337         }
338     };
339 
340     let mut walker = PathWalker::new(1.0, &mut pattern);
341 
342     walker.move_to(point(0.0, 0.0));
343     walker.line_to(point(5.0, 0.0));
344     walker.line_to(point(5.0, 5.0));
345     walker.line_to(point(0.0, 5.0));
346     walker.close();
347 }
348 
349 #[test]
walk_starting_after()350 fn walk_starting_after() {
351     // With a starting distance that is greater than the path, the
352     // callback should never be called.
353     let cb = &mut |_, _, _| -> Option<f32> { panic!() };
354     let mut walker = PathWalker::new(10.0, cb);
355 
356     walker.move_to(point(0.0, 0.0));
357     walker.line_to(point(5.0, 0.0));
358 }
359