1use crate::geom::traits::Transformation;
82use crate::geom::{cubic_bezier, quadratic_bezier, CubicBezierSegment, QuadraticBezierSegment};
83use crate::math::*;
84use crate::{Attributes, Event, PathEvent};
85
86pub trait PathIterator: Iterator<Item = PathEvent> + Sized {
90 fn flattened(self, tolerance: f32) -> Flattened<Self> {
92 Flattened::new(tolerance, self)
93 }
94
95 fn transformed<T: Transformation<f32>>(self, mat: &T) -> Transformed<Self, T> {
97 Transformed::new(mat, self)
98 }
99}
100
101impl<Iter> PathIterator for Iter where Iter: Iterator<Item = PathEvent> {}
102
103pub struct NoAttributes<Iter>(pub(crate) Iter);
104
105impl<'l, Iter> NoAttributes<Iter>
106where
107 Iter: Iterator<Item = Event<(Point, Attributes<'l>), Point>>,
108{
109 pub fn with_attributes(self) -> Iter {
110 self.0
111 }
112}
113
114impl<'l, Iter> Iterator for NoAttributes<Iter>
115where
116 Iter: Iterator<Item = Event<(Point, Attributes<'l>), Point>>,
117{
118 type Item = PathEvent;
119 fn next(&mut self) -> Option<PathEvent> {
120 self.0.next().map(|event| event.with_points())
121 }
122}
123
124pub struct Flattened<Iter> {
126 it: Iter,
127 current_position: Point,
128 current_curve: TmpFlatteningIter,
129 tolerance: f32,
130}
131
132enum TmpFlatteningIter {
133 Quadratic(quadratic_bezier::Flattened<f32>),
134 Cubic(cubic_bezier::Flattened<f32>),
135 None,
136}
137
138impl<Iter: Iterator<Item = PathEvent>> Flattened<Iter> {
139 pub fn new(tolerance: f32, it: Iter) -> Self {
141 Flattened {
142 it,
143 current_position: point(0.0, 0.0),
144 current_curve: TmpFlatteningIter::None,
145 tolerance,
146 }
147 }
148}
149
150impl<Iter> Iterator for Flattened<Iter>
151where
152 Iter: Iterator<Item = PathEvent>,
153{
154 type Item = PathEvent;
155 fn next(&mut self) -> Option<PathEvent> {
156 match self.current_curve {
157 TmpFlatteningIter::Quadratic(ref mut it) => {
158 if let Some(to) = it.next() {
159 let from = self.current_position;
160 self.current_position = to;
161 return Some(PathEvent::Line { from, to });
162 }
163 }
164 TmpFlatteningIter::Cubic(ref mut it) => {
165 if let Some(to) = it.next() {
166 let from = self.current_position;
167 self.current_position = to;
168 return Some(PathEvent::Line { from, to });
169 }
170 }
171 _ => {}
172 }
173 self.current_curve = TmpFlatteningIter::None;
174 match self.it.next() {
175 Some(PathEvent::Begin { at }) => Some(PathEvent::Begin { at }),
176 Some(PathEvent::Line { from, to }) => Some(PathEvent::Line { from, to }),
177 Some(PathEvent::End { last, first, close }) => {
178 Some(PathEvent::End { last, first, close })
179 }
180 Some(PathEvent::Quadratic { from, ctrl, to }) => {
181 self.current_position = from;
182 self.current_curve = TmpFlatteningIter::Quadratic(
183 QuadraticBezierSegment { from, ctrl, to }.flattened(self.tolerance),
184 );
185 self.next()
186 }
187 Some(PathEvent::Cubic {
188 from,
189 ctrl1,
190 ctrl2,
191 to,
192 }) => {
193 self.current_position = from;
194 self.current_curve = TmpFlatteningIter::Cubic(
195 CubicBezierSegment {
196 from,
197 ctrl1,
198 ctrl2,
199 to,
200 }
201 .flattened(self.tolerance),
202 );
203 self.next()
204 }
205 None => None,
206 }
207 }
208
209 fn size_hint(&self) -> (usize, Option<usize>) {
210 let mut lo = self.it.size_hint().0;
214 match &self.current_curve {
215 TmpFlatteningIter::Quadratic(t) => {
216 lo += t.size_hint().0;
217 }
218 TmpFlatteningIter::Cubic(t) => {
219 lo += t.size_hint().0;
220 }
221 _ => {}
222 }
223 (lo, None)
224 }
225}
226
227pub struct Transformed<'l, I, T> {
229 it: I,
230 transform: &'l T,
231}
232
233impl<'l, I, T: Transformation<f32>> Transformed<'l, I, T>
234where
235 I: Iterator<Item = PathEvent>,
236{
237 #[inline]
239 pub fn new(transform: &'l T, it: I) -> Transformed<'l, I, T> {
240 Transformed { it, transform }
241 }
242}
243
244impl<'l, I, T> Iterator for Transformed<'l, I, T>
245where
246 I: Iterator<Item = PathEvent>,
247 T: Transformation<f32>,
248{
249 type Item = PathEvent;
250 fn next(&mut self) -> Option<PathEvent> {
251 match self.it.next() {
252 None => None,
253 Some(ref evt) => Some(evt.transformed(self.transform)),
254 }
255 }
256}
257
258pub struct FromPolyline<Iter> {
276 iter: Iter,
277 current: Point,
278 first: Point,
279 is_first: bool,
280 done: bool,
281 close: bool,
282}
283
284impl<Iter: Iterator<Item = Point>> FromPolyline<Iter> {
285 pub fn new(close: bool, iter: Iter) -> Self {
286 FromPolyline {
287 iter,
288 current: point(0.0, 0.0),
289 first: point(0.0, 0.0),
290 is_first: true,
291 done: false,
292 close,
293 }
294 }
295
296 pub fn closed(iter: Iter) -> Self {
297 FromPolyline::new(true, iter)
298 }
299
300 pub fn open(iter: Iter) -> Self {
301 FromPolyline::new(false, iter)
302 }
303}
304
305impl<Iter> Iterator for FromPolyline<Iter>
306where
307 Iter: Iterator<Item = Point>,
308{
309 type Item = PathEvent;
310
311 fn next(&mut self) -> Option<PathEvent> {
312 if self.done {
313 return None;
314 }
315
316 if let Some(next) = self.iter.next() {
317 debug_assert!(next.x.is_finite());
318 debug_assert!(next.y.is_finite());
319 let from = self.current;
320 self.current = next;
321 return if self.is_first {
322 self.is_first = false;
323 self.first = next;
324 Some(PathEvent::Begin { at: next })
325 } else {
326 Some(PathEvent::Line { from, to: next })
327 };
328 }
329
330 self.done = true;
331
332 Some(PathEvent::End {
333 last: self.current,
334 first: self.first,
335 close: self.close,
336 })
337 }
338}
339
340#[test]
341fn test_from_polyline_open() {
342 let points = &[
343 point(1.0, 1.0),
344 point(3.0, 1.0),
345 point(4.0, 5.0),
346 point(5.0, 2.0),
347 ];
348
349 let mut evts = FromPolyline::open(points.iter().cloned());
350
351 assert_eq!(
352 evts.next(),
353 Some(PathEvent::Begin {
354 at: point(1.0, 1.0)
355 })
356 );
357 assert_eq!(
358 evts.next(),
359 Some(PathEvent::Line {
360 from: point(1.0, 1.0),
361 to: point(3.0, 1.0)
362 })
363 );
364 assert_eq!(
365 evts.next(),
366 Some(PathEvent::Line {
367 from: point(3.0, 1.0),
368 to: point(4.0, 5.0)
369 })
370 );
371 assert_eq!(
372 evts.next(),
373 Some(PathEvent::Line {
374 from: point(4.0, 5.0),
375 to: point(5.0, 2.0)
376 })
377 );
378 assert_eq!(
379 evts.next(),
380 Some(PathEvent::End {
381 last: point(5.0, 2.0),
382 first: point(1.0, 1.0),
383 close: false
384 })
385 );
386 assert_eq!(evts.next(), None);
387}
388
389#[test]
390fn test_from_polyline_closed() {
391 let points = &[
392 point(1.0, 1.0),
393 point(3.0, 1.0),
394 point(4.0, 5.0),
395 point(5.0, 2.0),
396 ];
397
398 let mut evts = FromPolyline::closed(points.iter().cloned());
399
400 assert_eq!(
401 evts.next(),
402 Some(PathEvent::Begin {
403 at: point(1.0, 1.0)
404 })
405 );
406 assert_eq!(
407 evts.next(),
408 Some(PathEvent::Line {
409 from: point(1.0, 1.0),
410 to: point(3.0, 1.0)
411 })
412 );
413 assert_eq!(
414 evts.next(),
415 Some(PathEvent::Line {
416 from: point(3.0, 1.0),
417 to: point(4.0, 5.0)
418 })
419 );
420 assert_eq!(
421 evts.next(),
422 Some(PathEvent::Line {
423 from: point(4.0, 5.0),
424 to: point(5.0, 2.0)
425 })
426 );
427 assert_eq!(
428 evts.next(),
429 Some(PathEvent::End {
430 last: point(5.0, 2.0),
431 first: point(1.0, 1.0),
432 close: true
433 })
434 );
435 assert_eq!(evts.next(), None);
436}