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