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}