1use crate::array::{VertexDist, VertexSequence};
10use crate::basics::{is_move_to, is_stop, is_vertex, VertexSource};
11use crate::span_interpolator_linear::Transformer;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15enum Status {
16 Initial,
17 MakingPath,
18 Ready,
19}
20
21pub struct TransDoublePath {
28 src_vertices1: VertexSequence,
29 src_vertices2: VertexSequence,
30 base_length: f64,
31 base_height: f64,
32 kindex1: f64,
33 kindex2: f64,
34 status1: Status,
35 status2: Status,
36 preserve_x_scale: bool,
37}
38
39impl TransDoublePath {
40 pub fn new() -> Self {
41 Self {
42 src_vertices1: VertexSequence::new(),
43 src_vertices2: VertexSequence::new(),
44 base_length: 0.0,
45 base_height: 1.0,
46 kindex1: 0.0,
47 kindex2: 0.0,
48 status1: Status::Initial,
49 status2: Status::Initial,
50 preserve_x_scale: true,
51 }
52 }
53
54 pub fn set_base_length(&mut self, v: f64) {
55 self.base_length = v;
56 }
57
58 pub fn base_length(&self) -> f64 {
59 self.base_length
60 }
61
62 pub fn set_base_height(&mut self, v: f64) {
63 self.base_height = v;
64 }
65
66 pub fn base_height(&self) -> f64 {
67 self.base_height
68 }
69
70 pub fn set_preserve_x_scale(&mut self, f: bool) {
71 self.preserve_x_scale = f;
72 }
73
74 pub fn preserve_x_scale(&self) -> bool {
75 self.preserve_x_scale
76 }
77
78 pub fn reset(&mut self) {
79 self.src_vertices1.remove_all();
80 self.src_vertices2.remove_all();
81 self.kindex1 = 0.0;
82 self.kindex2 = 0.0;
83 self.status1 = Status::Initial;
84 self.status2 = Status::Initial;
85 }
86
87 pub fn move_to1(&mut self, x: f64, y: f64) {
88 if self.status1 == Status::Initial {
89 self.src_vertices1.modify_last(VertexDist::new(x, y));
90 self.status1 = Status::MakingPath;
91 } else {
92 self.line_to1(x, y);
93 }
94 }
95
96 pub fn line_to1(&mut self, x: f64, y: f64) {
97 if self.status1 == Status::MakingPath {
98 self.src_vertices1.add(VertexDist::new(x, y));
99 }
100 }
101
102 pub fn move_to2(&mut self, x: f64, y: f64) {
103 if self.status2 == Status::Initial {
104 self.src_vertices2.modify_last(VertexDist::new(x, y));
105 self.status2 = Status::MakingPath;
106 } else {
107 self.line_to2(x, y);
108 }
109 }
110
111 pub fn line_to2(&mut self, x: f64, y: f64) {
112 if self.status2 == Status::MakingPath {
113 self.src_vertices2.add(VertexDist::new(x, y));
114 }
115 }
116
117 pub fn add_paths<VS1: VertexSource, VS2: VertexSource>(
119 &mut self,
120 vs1: &mut VS1,
121 vs2: &mut VS2,
122 path1_id: u32,
123 path2_id: u32,
124 ) {
125 let (mut x, mut y) = (0.0, 0.0);
126
127 vs1.rewind(path1_id);
128 loop {
129 let cmd = vs1.vertex(&mut x, &mut y);
130 if is_stop(cmd) {
131 break;
132 }
133 if is_move_to(cmd) {
134 self.move_to1(x, y);
135 } else if is_vertex(cmd) {
136 self.line_to1(x, y);
137 }
138 }
139
140 vs2.rewind(path2_id);
141 loop {
142 let cmd = vs2.vertex(&mut x, &mut y);
143 if is_stop(cmd) {
144 break;
145 }
146 if is_move_to(cmd) {
147 self.move_to2(x, y);
148 } else if is_vertex(cmd) {
149 self.line_to2(x, y);
150 }
151 }
152
153 self.finalize_paths();
154 }
155
156 pub fn finalize_paths(&mut self) {
158 if self.status1 == Status::MakingPath
159 && self.src_vertices1.size() > 1
160 && self.status2 == Status::MakingPath
161 && self.src_vertices2.size() > 1
162 {
163 self.kindex1 = Self::finalize_path(&mut self.src_vertices1);
164 self.kindex2 = Self::finalize_path(&mut self.src_vertices2);
165 self.status1 = Status::Ready;
166 self.status2 = Status::Ready;
167 }
168 }
169
170 pub fn total_length1(&self) -> f64 {
172 if self.base_length >= 1e-10 {
173 return self.base_length;
174 }
175 if self.status1 == Status::Ready {
176 self.src_vertices1[self.src_vertices1.size() - 1].dist
177 } else {
178 0.0
179 }
180 }
181
182 pub fn total_length2(&self) -> f64 {
184 if self.base_length >= 1e-10 {
185 return self.base_length;
186 }
187 if self.status2 == Status::Ready {
188 self.src_vertices2[self.src_vertices2.size() - 1].dist
189 } else {
190 0.0
191 }
192 }
193
194 fn finalize_path(vertices: &mut VertexSequence) -> f64 {
198 vertices.close(false);
199
200 if vertices.size() > 2 {
201 let n = vertices.size();
202 if vertices[n - 2].dist * 10.0 < vertices[n - 3].dist {
203 let d = vertices[n - 3].dist + vertices[n - 2].dist;
204 let last = vertices[n - 1];
205 vertices[n - 2] = last;
206 vertices.remove_last();
207 let idx = vertices.size() - 2;
208 vertices[idx].dist = d;
209 }
210 }
211
212 let mut dist = 0.0;
213 for i in 0..vertices.size() {
214 let d = vertices[i].dist;
215 vertices[i].dist = dist;
216 dist += d;
217 }
218
219 (vertices.size() - 1) as f64 / dist
220 }
221
222 fn transform1(
225 &self,
226 vertices: &VertexSequence,
227 kindex: f64,
228 kx: f64,
229 x: &mut f64,
230 y: &mut f64,
231 ) {
232 let x1;
233 let y1;
234 let dx;
235 let dy;
236 let d;
237 let dd;
238
239 *x *= kx;
240
241 if *x < 0.0 {
242 x1 = vertices[0].x;
244 y1 = vertices[0].y;
245 dx = vertices[1].x - x1;
246 dy = vertices[1].y - y1;
247 dd = vertices[1].dist - vertices[0].dist;
248 d = *x;
249 } else if *x > vertices[vertices.size() - 1].dist {
250 let i = vertices.size() - 2;
252 let j = vertices.size() - 1;
253 x1 = vertices[j].x;
254 y1 = vertices[j].y;
255 dx = x1 - vertices[i].x;
256 dy = y1 - vertices[i].y;
257 dd = vertices[j].dist - vertices[i].dist;
258 d = *x - vertices[j].dist;
259 } else {
260 let mut i = 0usize;
262 let mut j = vertices.size() - 1;
263
264 if self.preserve_x_scale {
265 loop {
266 if j - i <= 1 {
267 break;
268 }
269 let k = (i + j) >> 1;
270 if *x < vertices[k].dist {
271 j = k;
272 } else {
273 i = k;
274 }
275 }
276 dd = vertices[j].dist - vertices[i].dist;
277 d = *x - vertices[i].dist;
278 } else {
279 let fi = *x * kindex;
280 i = fi as usize;
281 j = i + 1;
282 dd = vertices[j].dist - vertices[i].dist;
283 d = (fi - i as f64) * dd;
284 }
285
286 x1 = vertices[i].x;
287 y1 = vertices[i].y;
288 dx = vertices[j].x - x1;
289 dy = vertices[j].y - y1;
290 }
291
292 *x = x1 + dx * d / dd;
293 *y = y1 + dy * d / dd;
294 }
295}
296
297impl Default for TransDoublePath {
298 fn default() -> Self {
299 Self::new()
300 }
301}
302
303impl Transformer for TransDoublePath {
304 fn transform(&self, x: &mut f64, y: &mut f64) {
305 if self.status1 != Status::Ready || self.status2 != Status::Ready {
306 return;
307 }
308
309 if self.base_length > 1e-10 {
310 *x *= self.src_vertices1[self.src_vertices1.size() - 1].dist / self.base_length;
311 }
312
313 let mut x1 = *x;
314 let mut y1 = *y;
315 let mut x2 = *x;
316 let mut y2 = *y;
317
318 let dd = self.src_vertices2[self.src_vertices2.size() - 1].dist
319 / self.src_vertices1[self.src_vertices1.size() - 1].dist;
320
321 self.transform1(&self.src_vertices1, self.kindex1, 1.0, &mut x1, &mut y1);
322 self.transform1(&self.src_vertices2, self.kindex2, dd, &mut x2, &mut y2);
323
324 *x = x1 + *y * (x2 - x1) / self.base_height;
325 *y = y1 + *y * (y2 - y1) / self.base_height;
326 }
327}
328
329#[cfg(test)]
334mod tests {
335 use super::*;
336
337 #[test]
338 fn test_parallel_horizontal_paths() {
339 let mut tdp = TransDoublePath::new();
340 tdp.set_base_height(20.0);
341
342 tdp.move_to1(0.0, 0.0);
344 tdp.line_to1(100.0, 0.0);
345
346 tdp.move_to2(0.0, 20.0);
348 tdp.line_to2(100.0, 20.0);
349
350 tdp.finalize_paths();
351
352 assert!((tdp.total_length1() - 100.0).abs() < 1e-10);
353 assert!((tdp.total_length2() - 100.0).abs() < 1e-10);
354
355 let (mut x, mut y) = (50.0, 0.0);
357 tdp.transform(&mut x, &mut y);
358 assert!((x - 50.0).abs() < 1e-10);
359 assert!((y - 0.0).abs() < 1e-10);
360
361 let (mut x, mut y) = (50.0, 10.0);
363 tdp.transform(&mut x, &mut y);
364 assert!((x - 50.0).abs() < 1e-10);
365 assert!((y - 10.0).abs() < 1e-10);
366
367 let (mut x, mut y) = (50.0, 20.0);
369 tdp.transform(&mut x, &mut y);
370 assert!((x - 50.0).abs() < 1e-10);
371 assert!((y - 20.0).abs() < 1e-10);
372 }
373
374 #[test]
375 fn test_diverging_paths() {
376 let mut tdp = TransDoublePath::new();
377 tdp.set_base_height(10.0);
378
379 tdp.move_to1(0.0, 0.0);
381 tdp.line_to1(100.0, 0.0);
382
383 tdp.move_to2(0.0, 0.0);
385 tdp.line_to2(100.0, 50.0);
386
387 tdp.finalize_paths();
388
389 let (mut x, mut y) = (50.0, 0.0);
391 tdp.transform(&mut x, &mut y);
392 assert!((x - 50.0).abs() < 1e-6);
393 assert!((y - 0.0).abs() < 1e-6);
394 }
395
396 #[test]
397 fn test_base_length() {
398 let mut tdp = TransDoublePath::new();
399 tdp.set_base_height(10.0);
400 tdp.set_base_length(50.0);
401
402 tdp.move_to1(0.0, 0.0);
403 tdp.line_to1(100.0, 0.0);
404 tdp.move_to2(0.0, 10.0);
405 tdp.line_to2(100.0, 10.0);
406 tdp.finalize_paths();
407
408 assert!((tdp.total_length1() - 50.0).abs() < 1e-10);
409 }
410
411 #[test]
412 fn test_not_ready_is_noop() {
413 let tdp = TransDoublePath::new();
414 let (mut x, mut y) = (50.0, 25.0);
415 tdp.transform(&mut x, &mut y);
416 assert!((x - 50.0).abs() < 1e-10);
417 assert!((y - 25.0).abs() < 1e-10);
418 }
419
420 #[test]
421 fn test_add_paths_from_vertex_sources() {
422 use crate::path_storage::PathStorage;
423
424 let mut tdp = TransDoublePath::new();
425 tdp.set_base_height(20.0);
426
427 let mut p1 = PathStorage::new();
428 p1.move_to(0.0, 0.0);
429 p1.line_to(100.0, 0.0);
430
431 let mut p2 = PathStorage::new();
432 p2.move_to(0.0, 20.0);
433 p2.line_to(100.0, 20.0);
434
435 tdp.add_paths(&mut p1, &mut p2, 0, 0);
436
437 assert!((tdp.total_length1() - 100.0).abs() < 1e-10);
438 assert!((tdp.total_length2() - 100.0).abs() < 1e-10);
439 }
440}