agg_rust/
conv_adaptor_vcgen.rs1use crate::basics::{
7 is_end_poly, is_move_to, is_stop, is_vertex, VertexSource, PATH_CMD_MOVE_TO, PATH_CMD_STOP,
8};
9
10pub trait VcgenGenerator {
18 fn remove_all(&mut self);
19 fn add_vertex(&mut self, x: f64, y: f64, cmd: u32);
20 fn rewind(&mut self, path_id: u32);
21 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32;
22}
23
24#[derive(Debug, Clone, Copy, PartialEq)]
29enum Status {
30 Initial,
31 Accumulate,
32 Generate,
33}
34
35pub struct ConvAdaptorVcgen<VS: VertexSource, Gen: VcgenGenerator> {
43 source: VS,
44 generator: Gen,
45 status: Status,
46 last_cmd: u32,
47 start_x: f64,
48 start_y: f64,
49}
50
51impl<VS: VertexSource, Gen: VcgenGenerator> ConvAdaptorVcgen<VS, Gen> {
52 pub fn new(source: VS, generator: Gen) -> Self {
53 Self {
54 source,
55 generator,
56 status: Status::Initial,
57 last_cmd: 0,
58 start_x: 0.0,
59 start_y: 0.0,
60 }
61 }
62
63 pub fn generator(&self) -> &Gen {
64 &self.generator
65 }
66
67 pub fn generator_mut(&mut self) -> &mut Gen {
68 &mut self.generator
69 }
70
71 pub fn source(&self) -> &VS {
72 &self.source
73 }
74
75 pub fn source_mut(&mut self) -> &mut VS {
76 &mut self.source
77 }
78}
79
80impl<VS: VertexSource, Gen: VcgenGenerator> VertexSource for ConvAdaptorVcgen<VS, Gen> {
81 fn rewind(&mut self, path_id: u32) {
82 self.source.rewind(path_id);
83 self.status = Status::Initial;
84 }
85
86 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
87 loop {
88 match self.status {
89 Status::Initial => {
90 self.last_cmd = self.source.vertex(&mut self.start_x, &mut self.start_y);
92 self.status = Status::Accumulate;
93 }
95 Status::Accumulate => {
96 if is_stop(self.last_cmd) {
97 return PATH_CMD_STOP;
98 }
99
100 self.generator.remove_all();
101 self.generator
102 .add_vertex(self.start_x, self.start_y, PATH_CMD_MOVE_TO);
103 loop {
106 let cmd = self.source.vertex(x, y);
107 if is_vertex(cmd) {
108 self.last_cmd = cmd;
109 if is_move_to(cmd) {
110 self.start_x = *x;
111 self.start_y = *y;
112 break;
113 }
114 self.generator.add_vertex(*x, *y, cmd);
115 } else {
117 if is_stop(cmd) {
118 self.last_cmd = PATH_CMD_STOP;
119 break;
120 }
121 if is_end_poly(cmd) {
122 self.generator.add_vertex(*x, *y, cmd);
123 break;
124 }
125 }
126 }
127 self.generator.rewind(0);
128 self.status = Status::Generate;
129 }
131 Status::Generate => {
132 let cmd = self.generator.vertex(x, y);
133 if is_stop(cmd) {
134 self.status = Status::Accumulate;
136 continue;
137 }
138 return cmd;
139 }
140 }
141 }
142 }
143}
144
145#[cfg(test)]
150mod tests {
151 use super::*;
152 use crate::basics::PATH_CMD_STOP;
153
154 struct EchoGenerator {
156 vertices: Vec<(f64, f64, u32)>,
157 idx: usize,
158 }
159
160 impl EchoGenerator {
161 fn new() -> Self {
162 Self {
163 vertices: Vec::new(),
164 idx: 0,
165 }
166 }
167 }
168
169 impl VcgenGenerator for EchoGenerator {
170 fn remove_all(&mut self) {
171 self.vertices.clear();
172 }
173 fn add_vertex(&mut self, x: f64, y: f64, cmd: u32) {
174 self.vertices.push((x, y, cmd));
175 }
176 fn rewind(&mut self, _path_id: u32) {
177 self.idx = 0;
178 }
179 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
180 if self.idx >= self.vertices.len() {
181 return PATH_CMD_STOP;
182 }
183 let (vx, vy, cmd) = self.vertices[self.idx];
184 *x = vx;
185 *y = vy;
186 self.idx += 1;
187 cmd
188 }
189 }
190
191 #[test]
192 fn test_empty_source() {
193 use crate::path_storage::PathStorage;
194 let path = PathStorage::new();
195 let mut adaptor = ConvAdaptorVcgen::new(path, EchoGenerator::new());
196 adaptor.rewind(0);
197
198 let (mut x, mut y) = (0.0, 0.0);
199 let cmd = adaptor.vertex(&mut x, &mut y);
200 assert_eq!(cmd, PATH_CMD_STOP);
201 }
202
203 #[test]
204 fn test_passthrough_with_echo() {
205 use crate::path_storage::PathStorage;
206
207 let mut path = PathStorage::new();
208 path.move_to(10.0, 20.0);
209 path.line_to(30.0, 40.0);
210
211 let mut adaptor = ConvAdaptorVcgen::new(path, EchoGenerator::new());
212 adaptor.rewind(0);
213
214 let mut verts = Vec::new();
215 loop {
216 let (mut x, mut y) = (0.0, 0.0);
217 let cmd = adaptor.vertex(&mut x, &mut y);
218 if is_stop(cmd) {
219 break;
220 }
221 verts.push((x, y, cmd));
222 }
223 assert!(
224 verts.len() >= 2,
225 "Expected >= 2 vertices, got {}",
226 verts.len()
227 );
228 }
229
230 #[test]
231 fn test_generator_access() {
232 use crate::path_storage::PathStorage;
233 let path = PathStorage::new();
234 let adaptor = ConvAdaptorVcgen::new(path, EchoGenerator::new());
235 let _ = adaptor.generator();
236 }
237}