lyon_algorithms/
length.rs

1//! Approximate path length.
2
3use crate::geom::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};
4use crate::path::PathEvent;
5
6use core::iter::IntoIterator;
7
8pub fn approximate_length<Iter>(path: Iter, tolerance: f32) -> f32
9where
10    Iter: IntoIterator<Item = PathEvent>,
11{
12    let tolerance = tolerance.max(1e-4);
13
14    let mut length = 0.0;
15
16    for evt in path.into_iter() {
17        match evt {
18            PathEvent::Line { from, to } => length += LineSegment { from, to }.length(),
19            PathEvent::Quadratic { from, ctrl, to } => {
20                length += QuadraticBezierSegment { from, ctrl, to }.length()
21            }
22            PathEvent::Cubic {
23                from,
24                ctrl1,
25                ctrl2,
26                to,
27            } => {
28                length += CubicBezierSegment {
29                    from,
30                    ctrl1,
31                    ctrl2,
32                    to,
33                }
34                .approximate_length(tolerance)
35            }
36            PathEvent::End {
37                last,
38                first,
39                close: true,
40            } => {
41                length += LineSegment {
42                    from: last,
43                    to: first,
44                }
45                .length()
46            }
47            _ => {}
48        }
49    }
50
51    length
52}
53
54#[test]
55fn approx_length() {
56    use crate::geom::point;
57
58    let mut builder = crate::path::Path::builder();
59    builder.begin(point(0.0, 0.0));
60    builder.line_to(point(1.0, 0.0));
61    builder.line_to(point(1.0, 1.0));
62    builder.line_to(point(0.0, 1.0));
63    builder.end(true);
64
65    let path = builder.build();
66
67    assert!((approximate_length(&path, 0.01) - 4.0).abs() < 0.0001);
68}