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