agg_rust/
conv_adaptor_vpgen.rs1use crate::basics::{
8 is_closed, is_end_poly, is_move_to, is_stop, is_vertex, VertexSource, PATH_CMD_END_POLY,
9 PATH_CMD_STOP, PATH_FLAGS_CLOSE,
10};
11
12pub trait VpgenProcessor {
18 fn reset(&mut self);
19 fn move_to(&mut self, x: f64, y: f64);
20 fn line_to(&mut self, x: f64, y: f64);
21 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32;
22 fn auto_close() -> bool;
23 fn auto_unclose() -> bool;
24}
25
26pub struct ConvAdaptorVpgen<VS, Gen> {
31 source: VS,
32 vpgen: Gen,
33 start_x: f64,
34 start_y: f64,
35 poly_flags: u32,
36 vertices: i32,
37}
38
39impl<VS: VertexSource, Gen: VpgenProcessor> ConvAdaptorVpgen<VS, Gen> {
40 pub fn new(source: VS, vpgen: Gen) -> Self {
41 Self {
42 source,
43 vpgen,
44 start_x: 0.0,
45 start_y: 0.0,
46 poly_flags: 0,
47 vertices: 0,
48 }
49 }
50
51 pub fn source(&self) -> &VS {
52 &self.source
53 }
54
55 pub fn source_mut(&mut self) -> &mut VS {
56 &mut self.source
57 }
58
59 pub fn vpgen(&self) -> &Gen {
60 &self.vpgen
61 }
62
63 pub fn vpgen_mut(&mut self) -> &mut Gen {
64 &mut self.vpgen
65 }
66}
67
68impl<VS: VertexSource, Gen: VpgenProcessor> VertexSource for ConvAdaptorVpgen<VS, Gen> {
69 fn rewind(&mut self, path_id: u32) {
70 self.source.rewind(path_id);
71 self.vpgen.reset();
72 self.start_x = 0.0;
73 self.start_y = 0.0;
74 self.poly_flags = 0;
75 self.vertices = 0;
76 }
77
78 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
79 loop {
80 let cmd = self.vpgen.vertex(x, y);
81 if !is_stop(cmd) {
82 return cmd;
83 }
84
85 if self.poly_flags != 0 && !Gen::auto_unclose() {
86 *x = 0.0;
87 *y = 0.0;
88 let cmd = self.poly_flags;
89 self.poly_flags = 0;
90 return cmd;
91 }
92
93 if self.vertices < 0 {
94 if self.vertices < -1 {
95 self.vertices = 0;
96 return PATH_CMD_STOP;
97 }
98 self.vpgen.move_to(self.start_x, self.start_y);
99 self.vertices = 1;
100 continue;
101 }
102
103 let mut tx = 0.0;
104 let mut ty = 0.0;
105 let cmd = self.source.vertex(&mut tx, &mut ty);
106
107 if is_vertex(cmd) {
108 if is_move_to(cmd) {
109 if Gen::auto_close() && self.vertices > 2 {
110 self.vpgen.line_to(self.start_x, self.start_y);
111 self.poly_flags = PATH_CMD_END_POLY | PATH_FLAGS_CLOSE;
112 self.start_x = tx;
113 self.start_y = ty;
114 self.vertices = -1;
115 continue;
116 }
117 self.vpgen.move_to(tx, ty);
118 self.start_x = tx;
119 self.start_y = ty;
120 self.vertices = 1;
121 } else {
122 self.vpgen.line_to(tx, ty);
123 self.vertices += 1;
124 }
125 } else if is_end_poly(cmd) {
126 self.poly_flags = cmd;
127 if is_closed(cmd) || Gen::auto_close() {
128 if Gen::auto_close() {
129 self.poly_flags |= PATH_FLAGS_CLOSE;
130 }
131 if self.vertices > 2 {
132 self.vpgen.line_to(self.start_x, self.start_y);
133 }
134 self.vertices = 0;
135 }
136 } else {
137 if Gen::auto_close() && self.vertices > 2 {
139 self.vpgen.line_to(self.start_x, self.start_y);
140 self.poly_flags = PATH_CMD_END_POLY | PATH_FLAGS_CLOSE;
141 self.vertices = -2;
142 continue;
143 }
144 return PATH_CMD_STOP;
145 }
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use crate::basics::{PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO};
154 use crate::vpgen_segmentator::VpgenSegmentator;
155
156 struct SimpleLineSource {
158 idx: usize,
159 }
160
161 impl SimpleLineSource {
162 fn new() -> Self {
163 Self { idx: 0 }
164 }
165 }
166
167 impl VertexSource for SimpleLineSource {
168 fn rewind(&mut self, _path_id: u32) {
169 self.idx = 0;
170 }
171
172 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
173 self.idx += 1;
174 match self.idx {
175 1 => {
176 *x = 0.0;
177 *y = 0.0;
178 PATH_CMD_MOVE_TO
179 }
180 2 => {
181 *x = 100.0;
182 *y = 0.0;
183 PATH_CMD_LINE_TO
184 }
185 _ => PATH_CMD_STOP,
186 }
187 }
188 }
189
190 #[test]
191 fn test_adaptor_with_segmentator() {
192 let source = SimpleLineSource::new();
193 let vpgen = VpgenSegmentator::new();
194 let mut adaptor = ConvAdaptorVpgen::new(source, vpgen);
195 adaptor.vpgen_mut().set_approximation_scale(1.0);
196 adaptor.rewind(0);
197
198 let (mut x, mut y) = (0.0, 0.0);
199 let mut count = 0;
200 loop {
201 let cmd = adaptor.vertex(&mut x, &mut y);
202 if is_stop(cmd) {
203 break;
204 }
205 count += 1;
206 }
207 assert!(count >= 2, "Expected at least 2 vertices, got {count}");
209 }
210
211 #[test]
212 fn test_adaptor_subdivides_long_segment() {
213 let source = SimpleLineSource::new();
214 let vpgen = VpgenSegmentator::new();
215 let mut adaptor = ConvAdaptorVpgen::new(source, vpgen);
216 adaptor.vpgen_mut().set_approximation_scale(10.0); adaptor.rewind(0);
218
219 let (mut x, mut y) = (0.0, 0.0);
220 let mut count = 0;
221 loop {
222 let cmd = adaptor.vertex(&mut x, &mut y);
223 if is_stop(cmd) {
224 break;
225 }
226 count += 1;
227 }
228 assert!(
229 count > 2,
230 "Long segment with scale=10 should subdivide: got {count}"
231 );
232 }
233}