agg_rust/
trans_single_path.rs1use crate::array::{VertexDist, VertexSequence};
7use crate::basics::{is_move_to, is_stop, is_vertex, VertexSource};
8use crate::span_interpolator_linear::Transformer;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12enum Status {
13 Initial,
14 MakingPath,
15 Ready,
16}
17
18pub struct TransSinglePath {
24 src_vertices: VertexSequence,
25 base_length: f64,
26 kindex: f64,
27 status: Status,
28 preserve_x_scale: bool,
29}
30
31impl TransSinglePath {
32 pub fn new() -> Self {
33 Self {
34 src_vertices: VertexSequence::new(),
35 base_length: 0.0,
36 kindex: 0.0,
37 status: Status::Initial,
38 preserve_x_scale: true,
39 }
40 }
41
42 pub fn base_length(&self) -> f64 {
43 self.base_length
44 }
45
46 pub fn set_base_length(&mut self, v: f64) {
47 self.base_length = v;
48 }
49
50 pub fn preserve_x_scale(&self) -> bool {
51 self.preserve_x_scale
52 }
53
54 pub fn set_preserve_x_scale(&mut self, f: bool) {
55 self.preserve_x_scale = f;
56 }
57
58 pub fn reset(&mut self) {
59 self.src_vertices.remove_all();
60 self.kindex = 0.0;
61 self.status = Status::Initial;
62 }
63
64 pub fn move_to(&mut self, x: f64, y: f64) {
65 if self.status == Status::Initial {
66 self.src_vertices.modify_last(VertexDist::new(x, y));
67 self.status = Status::MakingPath;
68 } else {
69 self.line_to(x, y);
70 }
71 }
72
73 pub fn line_to(&mut self, x: f64, y: f64) {
74 if self.status == Status::MakingPath {
75 self.src_vertices.add(VertexDist::new(x, y));
76 }
77 }
78
79 pub fn add_path<VS: VertexSource>(&mut self, vs: &mut VS, path_id: u32) {
81 let mut x = 0.0;
82 let mut y = 0.0;
83
84 vs.rewind(path_id);
85 loop {
86 let cmd = vs.vertex(&mut x, &mut y);
87 if is_stop(cmd) {
88 break;
89 }
90 if is_move_to(cmd) {
91 self.move_to(x, y);
92 } else if is_vertex(cmd) {
93 self.line_to(x, y);
94 }
95 }
96 self.finalize_path();
97 }
98
99 pub fn finalize_path(&mut self) {
101 if self.status != Status::MakingPath || self.src_vertices.size() <= 1 {
102 return;
103 }
104
105 self.src_vertices.close(false);
106
107 if self.src_vertices.size() > 2 {
108 let n = self.src_vertices.size();
109 if self.src_vertices[n - 2].dist * 10.0 < self.src_vertices[n - 3].dist {
112 let d = self.src_vertices[n - 3].dist + self.src_vertices[n - 2].dist;
113 let last = self.src_vertices[n - 1];
114 self.src_vertices[n - 2] = last;
115 self.src_vertices.remove_last();
116 let idx = self.src_vertices.size() - 2;
117 self.src_vertices[idx].dist = d;
118 }
119 }
120
121 let mut dist = 0.0;
123 for i in 0..self.src_vertices.size() {
124 let d = self.src_vertices[i].dist;
125 self.src_vertices[i].dist = dist;
126 dist += d;
127 }
128
129 self.kindex = (self.src_vertices.size() - 1) as f64 / dist;
130 self.status = Status::Ready;
131 }
132
133 pub fn total_length(&self) -> f64 {
135 if self.base_length >= 1e-10 {
136 return self.base_length;
137 }
138 if self.status == Status::Ready {
139 self.src_vertices[self.src_vertices.size() - 1].dist
140 } else {
141 0.0
142 }
143 }
144}
145
146impl Transformer for TransSinglePath {
147 fn transform(&self, x: &mut f64, y: &mut f64) {
148 if self.status != Status::Ready {
149 return;
150 }
151
152 let n = self.src_vertices.size();
153 let total_dist = self.src_vertices[n - 1].dist;
154
155 if self.base_length > 1e-10 {
156 *x *= total_dist / self.base_length;
157 }
158
159 let x1;
160 let y1;
161 let dx;
162 let dy;
163 let d;
164 let dd;
165
166 if *x < 0.0 {
167 x1 = self.src_vertices[0].x;
169 y1 = self.src_vertices[0].y;
170 dx = self.src_vertices[1].x - x1;
171 dy = self.src_vertices[1].y - y1;
172 dd = self.src_vertices[1].dist - self.src_vertices[0].dist;
173 d = *x;
174 } else if *x > total_dist {
175 let i = n - 2;
177 let j = n - 1;
178 x1 = self.src_vertices[j].x;
179 y1 = self.src_vertices[j].y;
180 dx = x1 - self.src_vertices[i].x;
181 dy = y1 - self.src_vertices[i].y;
182 dd = self.src_vertices[j].dist - self.src_vertices[i].dist;
183 d = *x - self.src_vertices[j].dist;
184 } else {
185 let mut i = 0usize;
187 let mut j = n - 1;
188
189 if self.preserve_x_scale {
190 loop {
191 if j - i <= 1 {
192 break;
193 }
194 let k = (i + j) >> 1;
195 if *x < self.src_vertices[k].dist {
196 j = k;
197 } else {
198 i = k;
199 }
200 }
201 dd = self.src_vertices[j].dist - self.src_vertices[i].dist;
202 d = *x - self.src_vertices[i].dist;
203 } else {
204 let fi = *x * self.kindex;
205 i = fi as usize;
206 j = i + 1;
207 dd = self.src_vertices[j].dist - self.src_vertices[i].dist;
208 d = (fi - i as f64) * dd;
209 }
210
211 x1 = self.src_vertices[i].x;
212 y1 = self.src_vertices[i].y;
213 dx = self.src_vertices[j].x - x1;
214 dy = self.src_vertices[j].y - y1;
215 }
216
217 let x2 = x1 + dx * d / dd;
218 let y2 = y1 + dy * d / dd;
219 *x = x2 - *y * dy / dd;
220 *y = y2 + *y * dx / dd;
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_straight_line_path() {
230 let mut tsp = TransSinglePath::new();
231 tsp.move_to(0.0, 0.0);
232 tsp.line_to(100.0, 0.0);
233 tsp.finalize_path();
234
235 assert!((tsp.total_length() - 100.0).abs() < 1e-10);
236
237 let (mut x, mut y) = (50.0, 0.0);
239 tsp.transform(&mut x, &mut y);
240 assert!((x - 50.0).abs() < 1e-10);
241 assert!((y - 0.0).abs() < 1e-10);
242
243 let (mut x, mut y) = (50.0, 10.0);
245 tsp.transform(&mut x, &mut y);
246 assert!((x - 50.0).abs() < 1e-10);
247 assert!((y - 10.0).abs() < 1e-10);
248 }
249
250 #[test]
251 fn test_diagonal_path() {
252 let mut tsp = TransSinglePath::new();
253 tsp.move_to(0.0, 0.0);
254 tsp.line_to(100.0, 100.0);
255 tsp.finalize_path();
256
257 let expected_len = (100.0_f64 * 100.0 + 100.0 * 100.0).sqrt();
258 assert!((tsp.total_length() - expected_len).abs() < 1e-10);
259 }
260
261 #[test]
262 fn test_base_length_scaling() {
263 let mut tsp = TransSinglePath::new();
264 tsp.move_to(0.0, 0.0);
265 tsp.line_to(200.0, 0.0);
266 tsp.finalize_path();
267 tsp.set_base_length(100.0);
268
269 let (mut x, mut y) = (50.0, 0.0);
271 tsp.transform(&mut x, &mut y);
272 assert!((x - 100.0).abs() < 1e-10);
273 assert!((y - 0.0).abs() < 1e-10);
274 }
275
276 #[test]
277 fn test_extrapolation_left() {
278 let mut tsp = TransSinglePath::new();
279 tsp.move_to(10.0, 0.0);
280 tsp.line_to(110.0, 0.0);
281 tsp.finalize_path();
282
283 let (mut x, mut y) = (-10.0, 0.0);
285 tsp.transform(&mut x, &mut y);
286 assert!((x - 0.0).abs() < 1e-10);
288 assert!((y - 0.0).abs() < 1e-10);
289 }
290
291 #[test]
292 fn test_extrapolation_right() {
293 let mut tsp = TransSinglePath::new();
294 tsp.move_to(0.0, 0.0);
295 tsp.line_to(100.0, 0.0);
296 tsp.finalize_path();
297
298 let (mut x, mut y) = (110.0, 0.0);
300 tsp.transform(&mut x, &mut y);
301 assert!((x - 110.0).abs() < 1e-10);
302 assert!((y - 0.0).abs() < 1e-10);
303 }
304
305 #[test]
306 fn test_multi_segment_path() {
307 let mut tsp = TransSinglePath::new();
308 tsp.move_to(0.0, 0.0);
309 tsp.line_to(50.0, 0.0);
310 tsp.line_to(50.0, 50.0);
311 tsp.finalize_path();
312
313 assert!((tsp.total_length() - 100.0).abs() < 1e-10);
315
316 let (mut x, mut y) = (25.0, 0.0);
318 tsp.transform(&mut x, &mut y);
319 assert!((x - 25.0).abs() < 1e-10);
320 assert!((y - 0.0).abs() < 1e-10);
321
322 let (mut x, mut y) = (75.0, 0.0);
324 tsp.transform(&mut x, &mut y);
325 assert!((x - 50.0).abs() < 1e-10);
326 assert!((y - 25.0).abs() < 1e-10);
327 }
328
329 #[test]
330 fn test_no_preserve_x_scale() {
331 let mut tsp = TransSinglePath::new();
332 tsp.set_preserve_x_scale(false);
333 tsp.move_to(0.0, 0.0);
334 tsp.line_to(100.0, 0.0);
335 tsp.finalize_path();
336
337 let (mut x, mut y) = (50.0, 0.0);
338 tsp.transform(&mut x, &mut y);
339 assert!((x - 50.0).abs() < 1e-10);
340 }
341
342 #[test]
343 fn test_not_ready_is_noop() {
344 let tsp = TransSinglePath::new();
345 let (mut x, mut y) = (50.0, 25.0);
346 tsp.transform(&mut x, &mut y);
347 assert!((x - 50.0).abs() < 1e-10);
348 assert!((y - 25.0).abs() < 1e-10);
349 }
350}