agg_rust/
vpgen_segmentator.rs1use crate::basics::{PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO, PATH_CMD_STOP};
8use crate::conv_adaptor_vpgen::VpgenProcessor;
9
10pub struct VpgenSegmentator {
16 approximation_scale: f64,
17 x1: f64,
18 y1: f64,
19 dx: f64,
20 dy: f64,
21 dl: f64,
22 ddl: f64,
23 cmd: u32,
24}
25
26impl VpgenSegmentator {
27 pub fn new() -> Self {
28 Self {
29 approximation_scale: 1.0,
30 x1: 0.0,
31 y1: 0.0,
32 dx: 0.0,
33 dy: 0.0,
34 dl: 2.0,
35 ddl: 2.0,
36 cmd: PATH_CMD_STOP,
37 }
38 }
39
40 pub fn approximation_scale(&self) -> f64 {
41 self.approximation_scale
42 }
43
44 pub fn set_approximation_scale(&mut self, s: f64) {
45 self.approximation_scale = s;
46 }
47
48 pub fn auto_close() -> bool {
49 false
50 }
51
52 pub fn auto_unclose() -> bool {
53 false
54 }
55
56 pub fn reset(&mut self) {
57 self.cmd = PATH_CMD_STOP;
58 }
59
60 pub fn move_to(&mut self, x: f64, y: f64) {
61 self.x1 = x;
62 self.y1 = y;
63 self.dx = 0.0;
64 self.dy = 0.0;
65 self.dl = 2.0;
66 self.ddl = 2.0;
67 self.cmd = PATH_CMD_MOVE_TO;
68 }
69
70 pub fn line_to(&mut self, x: f64, y: f64) {
71 self.x1 += self.dx;
72 self.y1 += self.dy;
73 self.dx = x - self.x1;
74 self.dy = y - self.y1;
75 let mut len = (self.dx * self.dx + self.dy * self.dy).sqrt() * self.approximation_scale;
76 if len < 1e-30 {
77 len = 1e-30;
78 }
79 self.ddl = 1.0 / len;
80 self.dl = if self.cmd == PATH_CMD_MOVE_TO {
81 0.0
82 } else {
83 self.ddl
84 };
85 if self.cmd == PATH_CMD_STOP {
86 self.cmd = PATH_CMD_LINE_TO;
87 }
88 }
89
90 pub fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
91 if self.cmd == PATH_CMD_STOP {
92 return PATH_CMD_STOP;
93 }
94
95 let cmd = self.cmd;
96 self.cmd = PATH_CMD_LINE_TO;
97 if self.dl >= 1.0 - self.ddl {
98 self.dl = 1.0;
99 self.cmd = PATH_CMD_STOP;
100 *x = self.x1 + self.dx;
101 *y = self.y1 + self.dy;
102 return cmd;
103 }
104 *x = self.x1 + self.dx * self.dl;
105 *y = self.y1 + self.dy * self.dl;
106 self.dl += self.ddl;
107 cmd
108 }
109}
110
111impl VpgenProcessor for VpgenSegmentator {
112 fn reset(&mut self) {
113 self.reset();
114 }
115
116 fn move_to(&mut self, x: f64, y: f64) {
117 self.move_to(x, y);
118 }
119
120 fn line_to(&mut self, x: f64, y: f64) {
121 self.line_to(x, y);
122 }
123
124 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
125 self.vertex(x, y)
126 }
127
128 fn auto_close() -> bool {
129 VpgenSegmentator::auto_close()
130 }
131
132 fn auto_unclose() -> bool {
133 VpgenSegmentator::auto_unclose()
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_short_segment_no_subdivision() {
143 let mut vpgen = VpgenSegmentator::new();
144 vpgen.set_approximation_scale(1.0);
145 vpgen.move_to(0.0, 0.0);
146 vpgen.line_to(0.5, 0.0);
147
148 let (mut x, mut y) = (0.0, 0.0);
149 let cmd1 = vpgen.vertex(&mut x, &mut y);
150 assert_eq!(cmd1, PATH_CMD_MOVE_TO);
151 assert!((x - 0.5).abs() < 1e-10);
153 assert!((y - 0.0).abs() < 1e-10);
154
155 let cmd2 = vpgen.vertex(&mut x, &mut y);
157 assert_eq!(cmd2, PATH_CMD_STOP);
158 }
159
160 #[test]
161 fn test_long_segment_subdivision() {
162 let mut vpgen = VpgenSegmentator::new();
163 vpgen.set_approximation_scale(10.0); vpgen.move_to(0.0, 0.0);
165 vpgen.line_to(100.0, 0.0);
166
167 let (mut x, mut y) = (0.0, 0.0);
168 let mut count = 0;
169 loop {
170 let cmd = vpgen.vertex(&mut x, &mut y);
171 if cmd == PATH_CMD_STOP {
172 break;
173 }
174 count += 1;
175 }
176 assert!(count > 2, "Long segment should be subdivided: count={count}");
177 }
178}