lyon_usvg/
lib.rs

1use lyon_path::geom::Point;
2use lyon_path::{Event, Path};
3use num_traits::ToPrimitive;
4use usvg::{PathData, PathSegment};
5
6pub trait IntoPathSegment {
7    fn into_path_segment(self) -> Option<PathSegment>;
8}
9
10impl<EndT, CtrlT> IntoPathSegment for Event<Point<EndT>, Point<CtrlT>>
11where
12    EndT: ToPrimitive,
13    CtrlT: ToPrimitive,
14{
15    fn into_path_segment(self) -> Option<PathSegment> {
16        match self {
17            Self::Begin { at } => Some(PathSegment::MoveTo {
18                x: at.x.to_f64().unwrap(),
19                y: at.y.to_f64().unwrap(),
20            }),
21            Self::Line { to, .. } => Some(PathSegment::LineTo {
22                x: to.x.to_f64().unwrap(),
23                y: to.y.to_f64().unwrap(),
24            }),
25            Self::Cubic {
26                to, ctrl1, ctrl2, ..
27            } => Some(PathSegment::CurveTo {
28                x1: ctrl1.x.to_f64().unwrap(),
29                y1: ctrl1.y.to_f64().unwrap(),
30                x2: ctrl2.x.to_f64().unwrap(),
31                y2: ctrl2.y.to_f64().unwrap(),
32                x: to.x.to_f64().unwrap(),
33                y: to.y.to_f64().unwrap(),
34            }),
35            Self::Quadratic { from, to, ctrl } => {
36                let from = Point::new(from.x.to_f64().unwrap(), from.y.to_f64().unwrap());
37                let to = Point::new(to.x.to_f64().unwrap(), to.y.to_f64().unwrap());
38                let ctrl = Point::new(ctrl.x.to_f64().unwrap(), ctrl.y.to_f64().unwrap());
39                let ctrl1 = from + (ctrl - from) * (2. / 3.);
40                let ctrl2 = to + (ctrl - to) * (2. / 3.);
41                Some(PathSegment::CurveTo {
42                    x1: ctrl1.x,
43                    y1: ctrl1.y,
44                    x2: ctrl2.x,
45                    y2: ctrl2.y,
46                    x: to.x,
47                    y: to.y,
48                })
49            }
50            Self::End { close: true, .. } => Some(PathSegment::ClosePath),
51            Self::End { close: false, .. } => None,
52        }
53    }
54}
55
56pub trait IntoPathData {
57    fn into_path_data(self) -> PathData;
58}
59
60impl<T, EndT, CtrlT> IntoPathData for T
61where
62    T: IntoIterator<Item = Event<Point<EndT>, Point<CtrlT>>>,
63    EndT: ToPrimitive,
64    CtrlT: ToPrimitive,
65{
66    fn into_path_data(self) -> PathData {
67        PathData(
68            self.into_iter()
69                .filter_map(|e| e.into_path_segment())
70                .collect(),
71        )
72    }
73}
74
75pub trait ToPath {
76    fn to_path(&self) -> Path;
77}
78
79impl ToPath for PathData {
80    fn to_path(&self) -> Path {
81        let mut builder = Path::svg_builder();
82        for segment in self.iter() {
83            match *segment {
84                usvg::PathSegment::MoveTo { x, y } => {
85                    builder.move_to(Point::new(x as f32, y as f32));
86                }
87                usvg::PathSegment::LineTo { x, y } => {
88                    builder.line_to(Point::new(x as f32, y as f32));
89                }
90                usvg::PathSegment::CurveTo {
91                    x1,
92                    y1,
93                    x2,
94                    y2,
95                    x,
96                    y,
97                } => {
98                    builder.cubic_bezier_to(
99                        Point::new(x1 as f32, y1 as f32),
100                        Point::new(x2 as f32, y2 as f32),
101                        Point::new(x as f32, y as f32),
102                    );
103                }
104                usvg::PathSegment::ClosePath => {
105                    builder.close();
106                }
107            }
108        }
109        builder.build()
110    }
111}