1 use crate::BackendCoord;
2 
get_dir_vector(from: BackendCoord, to: BackendCoord, flag: bool) -> ((f64, f64), (f64, f64))3 fn get_dir_vector(from: BackendCoord, to: BackendCoord, flag: bool) -> ((f64, f64), (f64, f64)) {
4     let v = (i64::from(to.0 - from.0), i64::from(to.1 - from.1));
5     let l = ((v.0 * v.0 + v.1 * v.1) as f64).sqrt();
6 
7     let v = (v.0 as f64 / l, v.1 as f64 / l);
8 
9     if flag {
10         (v, (v.1, -v.0))
11     } else {
12         (v, (-v.1, v.0))
13     }
14 }
15 
compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64) -> BackendCoord16 fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64) -> BackendCoord {
17     let (a_t, a_n) = get_dir_vector(triple[0], triple[1], false);
18     let (b_t, b_n) = get_dir_vector(triple[2], triple[1], true);
19 
20     let a_p = (
21         f64::from(triple[1].0) + d * a_n.0,
22         f64::from(triple[1].1) + d * a_n.1,
23     );
24     let b_p = (
25         f64::from(triple[1].0) + d * b_n.0,
26         f64::from(triple[1].1) + d * b_n.1,
27     );
28 
29     // u * a_t + a_p = v * b_t + b_p
30     // u * a_t.0 - v * b_t.0 = b_p.0 - a_p.0
31     // u * a_t.1 - v * b_t.1 = b_p.1 - a_p.1
32     if a_p.0 as i32 == b_p.0 as i32 && a_p.1 as i32 == b_p.1 as i32 {
33         return (a_p.0 as i32, a_p.1 as i32);
34     }
35 
36     let a0 = a_t.0;
37     let b0 = -b_t.0;
38     let c0 = b_p.0 - a_p.0;
39     let a1 = a_t.1;
40     let b1 = -b_t.1;
41     let c1 = b_p.1 - a_p.1;
42 
43     // This is the coner case that
44     if (a0 * b1 - a1 * b0).abs() < 1e-10 {
45         return (a_p.0 as i32, a_p.1 as i32);
46     }
47 
48     let u = (c0 * b1 - c1 * b0) / (a0 * b1 - a1 * b0);
49 
50     let x = a_p.0 + u * a_t.0;
51     let y = a_p.1 + u * a_t.1;
52 
53     (x.round() as i32, y.round() as i32)
54 }
55 
traverse_vertices<'a>( mut vertices: impl Iterator<Item = &'a BackendCoord>, width: u32, mut op: impl FnMut(BackendCoord), )56 fn traverse_vertices<'a>(
57     mut vertices: impl Iterator<Item = &'a BackendCoord>,
58     width: u32,
59     mut op: impl FnMut(BackendCoord),
60 ) {
61     let mut a = vertices.next().unwrap();
62     let mut b = vertices.next().unwrap();
63 
64     while a == b {
65         a = b;
66         if let Some(new_b) = vertices.next() {
67             b = new_b;
68         } else {
69             return;
70         }
71     }
72 
73     let (_, n) = get_dir_vector(*a, *b, false);
74 
75     op((
76         (f64::from(a.0) + n.0 * f64::from(width) / 2.0).round() as i32,
77         (f64::from(a.1) + n.1 * f64::from(width) / 2.0).round() as i32,
78     ));
79 
80     let mut recent = [(0, 0), *a, *b];
81 
82     for p in vertices {
83         if *p == recent[2] {
84             continue;
85         }
86         recent.swap(0, 1);
87         recent.swap(1, 2);
88         recent[2] = *p;
89         op(compute_polygon_vertex(&recent, f64::from(width) / 2.0));
90     }
91 
92     let b = recent[1];
93     let a = recent[2];
94 
95     let (_, n) = get_dir_vector(a, b, true);
96 
97     op((
98         (f64::from(a.0) + n.0 * f64::from(width) / 2.0).round() as i32,
99         (f64::from(a.1) + n.1 * f64::from(width) / 2.0).round() as i32,
100     ));
101 }
102 
103 /// Covert a path with >1px stroke width into polygon.
polygonize(vertices: &[BackendCoord], stroke_width: u32) -> Vec<BackendCoord>104 pub fn polygonize(vertices: &[BackendCoord], stroke_width: u32) -> Vec<BackendCoord> {
105     if vertices.len() < 2 {
106         return vec![];
107     }
108 
109     let mut ret = vec![];
110 
111     traverse_vertices(vertices.iter(), stroke_width, |v| ret.push(v));
112     traverse_vertices(vertices.iter().rev(), stroke_width, |v| ret.push(v));
113 
114     ret
115 }
116