1use crate::basics::{
8 is_curve, is_drawing, is_end_poly, is_equal_eps, is_move_to, is_next_poly, is_stop, is_vertex,
9 set_orientation, VertexD, VertexSource, PATH_CMD_CURVE3, PATH_CMD_CURVE4, PATH_CMD_END_POLY,
10 PATH_CMD_LINE_TO, PATH_CMD_MOVE_TO, PATH_CMD_STOP, PATH_FLAGS_CCW, PATH_FLAGS_CLOSE,
11 PATH_FLAGS_CW, PATH_FLAGS_NONE,
12};
13use crate::bezier_arc::BezierArcSvg;
14use crate::math::{calc_distance, VERTEX_DIST_EPSILON};
15
16#[derive(Clone)]
24pub struct PathStorage {
25 vertices: Vec<VertexD>,
26 iterator: usize,
27}
28
29impl PathStorage {
30 pub fn new() -> Self {
32 Self {
33 vertices: Vec::new(),
34 iterator: 0,
35 }
36 }
37
38 pub fn remove_all(&mut self) {
40 self.vertices.clear();
41 self.iterator = 0;
42 }
43
44 pub fn free_all(&mut self) {
46 self.vertices = Vec::new();
47 self.iterator = 0;
48 }
49
50 pub fn start_new_path(&mut self) -> usize {
58 if !is_stop(self.last_command()) {
59 self.vertices.push(VertexD::new(0.0, 0.0, PATH_CMD_STOP));
60 }
61 self.vertices.len()
62 }
63
64 pub fn add_vertex(&mut self, x: f64, y: f64, cmd: u32) {
68 self.vertices.push(VertexD::new(x, y, cmd));
69 }
70
71 pub fn move_to(&mut self, x: f64, y: f64) {
73 self.vertices.push(VertexD::new(x, y, PATH_CMD_MOVE_TO));
74 }
75
76 pub fn move_rel(&mut self, dx: f64, dy: f64) {
78 let (mut x, mut y) = (dx, dy);
79 self.rel_to_abs(&mut x, &mut y);
80 self.vertices.push(VertexD::new(x, y, PATH_CMD_MOVE_TO));
81 }
82
83 pub fn line_to(&mut self, x: f64, y: f64) {
85 self.vertices.push(VertexD::new(x, y, PATH_CMD_LINE_TO));
86 }
87
88 pub fn line_rel(&mut self, dx: f64, dy: f64) {
90 let (mut x, mut y) = (dx, dy);
91 self.rel_to_abs(&mut x, &mut y);
92 self.vertices.push(VertexD::new(x, y, PATH_CMD_LINE_TO));
93 }
94
95 pub fn hline_to(&mut self, x: f64) {
97 self.vertices
98 .push(VertexD::new(x, self.last_y(), PATH_CMD_LINE_TO));
99 }
100
101 pub fn hline_rel(&mut self, dx: f64) {
103 let (mut x, mut y) = (dx, 0.0);
104 self.rel_to_abs(&mut x, &mut y);
105 self.vertices.push(VertexD::new(x, y, PATH_CMD_LINE_TO));
106 }
107
108 pub fn vline_to(&mut self, y: f64) {
110 self.vertices
111 .push(VertexD::new(self.last_x(), y, PATH_CMD_LINE_TO));
112 }
113
114 pub fn vline_rel(&mut self, dy: f64) {
116 let (mut x, mut y) = (0.0, dy);
117 self.rel_to_abs(&mut x, &mut y);
118 self.vertices.push(VertexD::new(x, y, PATH_CMD_LINE_TO));
119 }
120
121 #[allow(clippy::too_many_arguments)]
123 pub fn arc_to(
124 &mut self,
125 rx: f64,
126 ry: f64,
127 angle: f64,
128 large_arc_flag: bool,
129 sweep_flag: bool,
130 x: f64,
131 y: f64,
132 ) {
133 if self.total_vertices() > 0 && is_vertex(self.last_command()) {
134 let epsilon = 1e-30;
135 let mut x0 = 0.0;
136 let mut y0 = 0.0;
137 self.last_vertex_xy(&mut x0, &mut y0);
138
139 let rx = rx.abs();
140 let ry = ry.abs();
141
142 if rx < epsilon || ry < epsilon {
143 self.line_to(x, y);
144 return;
145 }
146
147 if calc_distance(x0, y0, x, y) < epsilon {
148 return;
149 }
150
151 let mut a = BezierArcSvg::new_with_params(
152 x0,
153 y0,
154 rx,
155 ry,
156 angle,
157 large_arc_flag,
158 sweep_flag,
159 x,
160 y,
161 );
162 if a.radii_ok() {
163 self.join_path(&mut a, 0);
164 } else {
165 self.line_to(x, y);
166 }
167 } else {
168 self.move_to(x, y);
169 }
170 }
171
172 #[allow(clippy::too_many_arguments)]
174 pub fn arc_rel(
175 &mut self,
176 rx: f64,
177 ry: f64,
178 angle: f64,
179 large_arc_flag: bool,
180 sweep_flag: bool,
181 dx: f64,
182 dy: f64,
183 ) {
184 let (mut x, mut y) = (dx, dy);
185 self.rel_to_abs(&mut x, &mut y);
186 self.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
187 }
188
189 pub fn curve3(&mut self, x_ctrl: f64, y_ctrl: f64, x_to: f64, y_to: f64) {
191 self.vertices
192 .push(VertexD::new(x_ctrl, y_ctrl, PATH_CMD_CURVE3));
193 self.vertices
194 .push(VertexD::new(x_to, y_to, PATH_CMD_CURVE3));
195 }
196
197 pub fn curve3_rel(&mut self, dx_ctrl: f64, dy_ctrl: f64, dx_to: f64, dy_to: f64) {
199 let (mut x_ctrl, mut y_ctrl) = (dx_ctrl, dy_ctrl);
200 self.rel_to_abs(&mut x_ctrl, &mut y_ctrl);
201 let (mut x_to, mut y_to) = (dx_to, dy_to);
202 self.rel_to_abs(&mut x_to, &mut y_to);
203 self.vertices
204 .push(VertexD::new(x_ctrl, y_ctrl, PATH_CMD_CURVE3));
205 self.vertices
206 .push(VertexD::new(x_to, y_to, PATH_CMD_CURVE3));
207 }
208
209 pub fn curve3_smooth(&mut self, x_to: f64, y_to: f64) {
211 let mut x0 = 0.0;
212 let mut y0 = 0.0;
213 if is_vertex(self.last_vertex_xy(&mut x0, &mut y0)) {
214 let mut x_ctrl = 0.0;
215 let mut y_ctrl = 0.0;
216 let cmd = self.prev_vertex_xy(&mut x_ctrl, &mut y_ctrl);
217 if is_curve(cmd) {
218 x_ctrl = x0 + x0 - x_ctrl;
219 y_ctrl = y0 + y0 - y_ctrl;
220 } else {
221 x_ctrl = x0;
222 y_ctrl = y0;
223 }
224 self.curve3(x_ctrl, y_ctrl, x_to, y_to);
225 }
226 }
227
228 pub fn curve3_smooth_rel(&mut self, dx_to: f64, dy_to: f64) {
230 let (mut x_to, mut y_to) = (dx_to, dy_to);
231 self.rel_to_abs(&mut x_to, &mut y_to);
232 self.curve3_smooth(x_to, y_to);
233 }
234
235 #[allow(clippy::too_many_arguments)]
237 pub fn curve4(
238 &mut self,
239 x_ctrl1: f64,
240 y_ctrl1: f64,
241 x_ctrl2: f64,
242 y_ctrl2: f64,
243 x_to: f64,
244 y_to: f64,
245 ) {
246 self.vertices
247 .push(VertexD::new(x_ctrl1, y_ctrl1, PATH_CMD_CURVE4));
248 self.vertices
249 .push(VertexD::new(x_ctrl2, y_ctrl2, PATH_CMD_CURVE4));
250 self.vertices
251 .push(VertexD::new(x_to, y_to, PATH_CMD_CURVE4));
252 }
253
254 #[allow(clippy::too_many_arguments)]
256 pub fn curve4_rel(
257 &mut self,
258 dx_ctrl1: f64,
259 dy_ctrl1: f64,
260 dx_ctrl2: f64,
261 dy_ctrl2: f64,
262 dx_to: f64,
263 dy_to: f64,
264 ) {
265 let (mut x_ctrl1, mut y_ctrl1) = (dx_ctrl1, dy_ctrl1);
266 self.rel_to_abs(&mut x_ctrl1, &mut y_ctrl1);
267 let (mut x_ctrl2, mut y_ctrl2) = (dx_ctrl2, dy_ctrl2);
268 self.rel_to_abs(&mut x_ctrl2, &mut y_ctrl2);
269 let (mut x_to, mut y_to) = (dx_to, dy_to);
270 self.rel_to_abs(&mut x_to, &mut y_to);
271 self.vertices
272 .push(VertexD::new(x_ctrl1, y_ctrl1, PATH_CMD_CURVE4));
273 self.vertices
274 .push(VertexD::new(x_ctrl2, y_ctrl2, PATH_CMD_CURVE4));
275 self.vertices
276 .push(VertexD::new(x_to, y_to, PATH_CMD_CURVE4));
277 }
278
279 pub fn curve4_smooth(&mut self, x_ctrl2: f64, y_ctrl2: f64, x_to: f64, y_to: f64) {
281 let mut x0 = 0.0;
282 let mut y0 = 0.0;
283 if is_vertex(self.last_vertex_xy(&mut x0, &mut y0)) {
284 let mut x_ctrl1 = 0.0;
285 let mut y_ctrl1 = 0.0;
286 let cmd = self.prev_vertex_xy(&mut x_ctrl1, &mut y_ctrl1);
287 if is_curve(cmd) {
288 x_ctrl1 = x0 + x0 - x_ctrl1;
289 y_ctrl1 = y0 + y0 - y_ctrl1;
290 } else {
291 x_ctrl1 = x0;
292 y_ctrl1 = y0;
293 }
294 self.curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
295 }
296 }
297
298 pub fn curve4_smooth_rel(&mut self, dx_ctrl2: f64, dy_ctrl2: f64, dx_to: f64, dy_to: f64) {
300 let (mut x_ctrl2, mut y_ctrl2) = (dx_ctrl2, dy_ctrl2);
301 self.rel_to_abs(&mut x_ctrl2, &mut y_ctrl2);
302 let (mut x_to, mut y_to) = (dx_to, dy_to);
303 self.rel_to_abs(&mut x_to, &mut y_to);
304 self.curve4_smooth(x_ctrl2, y_ctrl2, x_to, y_to);
305 }
306
307 pub fn end_poly(&mut self, flags: u32) {
309 if is_vertex(self.last_command()) {
310 self.vertices
311 .push(VertexD::new(0.0, 0.0, PATH_CMD_END_POLY | flags));
312 }
313 }
314
315 pub fn close_polygon(&mut self, flags: u32) {
317 self.end_poly(PATH_FLAGS_CLOSE | flags);
318 }
319
320 pub fn total_vertices(&self) -> usize {
326 self.vertices.len()
327 }
328
329 pub fn vertices(&self) -> &[VertexD] {
332 &self.vertices
333 }
334
335 pub fn rel_to_abs(&self, x: &mut f64, y: &mut f64) {
337 if !self.vertices.is_empty() {
338 let last = &self.vertices[self.vertices.len() - 1];
339 if is_vertex(last.cmd) {
340 *x += last.x;
341 *y += last.y;
342 }
343 }
344 }
345
346 pub fn last_vertex_xy(&self, x: &mut f64, y: &mut f64) -> u32 {
348 if self.vertices.is_empty() {
349 *x = 0.0;
350 *y = 0.0;
351 return PATH_CMD_STOP;
352 }
353 let v = &self.vertices[self.vertices.len() - 1];
354 *x = v.x;
355 *y = v.y;
356 v.cmd
357 }
358
359 pub fn prev_vertex_xy(&self, x: &mut f64, y: &mut f64) -> u32 {
361 if self.vertices.len() < 2 {
362 *x = 0.0;
363 *y = 0.0;
364 return PATH_CMD_STOP;
365 }
366 let v = &self.vertices[self.vertices.len() - 2];
367 *x = v.x;
368 *y = v.y;
369 v.cmd
370 }
371
372 pub fn last_command(&self) -> u32 {
374 if self.vertices.is_empty() {
375 PATH_CMD_STOP
376 } else {
377 self.vertices[self.vertices.len() - 1].cmd
378 }
379 }
380
381 pub fn last_x(&self) -> f64 {
383 if self.vertices.is_empty() {
384 0.0
385 } else {
386 self.vertices[self.vertices.len() - 1].x
387 }
388 }
389
390 pub fn last_y(&self) -> f64 {
392 if self.vertices.is_empty() {
393 0.0
394 } else {
395 self.vertices[self.vertices.len() - 1].y
396 }
397 }
398
399 pub fn vertex_idx(&self, idx: usize, x: &mut f64, y: &mut f64) -> u32 {
401 let v = &self.vertices[idx];
402 *x = v.x;
403 *y = v.y;
404 v.cmd
405 }
406
407 pub fn command(&self, idx: usize) -> u32 {
409 self.vertices[idx].cmd
410 }
411
412 pub fn modify_vertex(&mut self, idx: usize, x: f64, y: f64) {
414 self.vertices[idx].x = x;
415 self.vertices[idx].y = y;
416 }
417
418 pub fn modify_vertex_cmd(&mut self, idx: usize, x: f64, y: f64, cmd: u32) {
420 self.vertices[idx].x = x;
421 self.vertices[idx].y = y;
422 self.vertices[idx].cmd = cmd;
423 }
424
425 pub fn modify_command(&mut self, idx: usize, cmd: u32) {
427 self.vertices[idx].cmd = cmd;
428 }
429
430 pub fn swap_vertices(&mut self, v1: usize, v2: usize) {
432 self.vertices.swap(v1, v2);
433 }
434
435 pub fn concat_path(&mut self, vs: &mut dyn VertexSource, path_id: u32) {
441 let mut x = 0.0;
442 let mut y = 0.0;
443 vs.rewind(path_id);
444 loop {
445 let cmd = vs.vertex(&mut x, &mut y);
446 if is_stop(cmd) {
447 break;
448 }
449 self.vertices.push(VertexD::new(x, y, cmd));
450 }
451 }
452
453 pub fn join_path(&mut self, vs: &mut dyn VertexSource, path_id: u32) {
458 let mut x = 0.0;
459 let mut y = 0.0;
460 vs.rewind(path_id);
461 let mut cmd = vs.vertex(&mut x, &mut y);
462 if !is_stop(cmd) {
463 if is_vertex(cmd) {
464 let mut x0 = 0.0;
465 let mut y0 = 0.0;
466 let cmd0 = self.last_vertex_xy(&mut x0, &mut y0);
467 if is_vertex(cmd0) {
468 if calc_distance(x, y, x0, y0) > VERTEX_DIST_EPSILON {
469 if is_move_to(cmd) {
470 cmd = PATH_CMD_LINE_TO;
471 }
472 self.vertices.push(VertexD::new(x, y, cmd));
473 }
474 } else {
475 if is_stop(cmd0) {
476 cmd = PATH_CMD_MOVE_TO;
477 } else if is_move_to(cmd) {
478 cmd = PATH_CMD_LINE_TO;
479 }
480 self.vertices.push(VertexD::new(x, y, cmd));
481 }
482 }
483 loop {
484 cmd = vs.vertex(&mut x, &mut y);
485 if is_stop(cmd) {
486 break;
487 }
488 let actual_cmd = if is_move_to(cmd) {
489 PATH_CMD_LINE_TO
490 } else {
491 cmd
492 };
493 self.vertices.push(VertexD::new(x, y, actual_cmd));
494 }
495 }
496 }
497
498 pub fn concat_poly(&mut self, data: &[f64], closed: bool) {
500 let mut adaptor = PolyPlainAdaptor::new(data, closed);
501 self.concat_path(&mut adaptor, 0);
502 }
503
504 pub fn join_poly(&mut self, data: &[f64], closed: bool) {
506 let mut adaptor = PolyPlainAdaptor::new(data, closed);
507 self.join_path(&mut adaptor, 0);
508 }
509
510 fn perceive_polygon_orientation(&self, start: usize, end: usize) -> u32 {
516 let np = end - start;
517 let mut area = 0.0;
518 for i in 0..np {
519 let v1 = &self.vertices[start + i];
520 let v2 = &self.vertices[start + (i + 1) % np];
521 area += v1.x * v2.y - v1.y * v2.x;
522 }
523 if area < 0.0 {
524 PATH_FLAGS_CW
525 } else {
526 PATH_FLAGS_CCW
527 }
528 }
529
530 fn invert_polygon_range(&mut self, start: usize, end: usize) {
532 let tmp_cmd = self.vertices[start].cmd;
533 let end = end - 1; for i in start..end {
537 let next_cmd = self.vertices[i + 1].cmd;
538 self.vertices[i].cmd = next_cmd;
539 }
540
541 self.vertices[end].cmd = tmp_cmd;
543
544 let (mut lo, mut hi) = (start, end);
546 while hi > lo {
547 self.vertices.swap(lo, hi);
548 lo += 1;
549 hi -= 1;
550 }
551 }
552
553 pub fn invert_polygon(&mut self, start: usize) {
555 let mut start = start;
556 let total = self.vertices.len();
557
558 while start < total && !is_vertex(self.vertices[start].cmd) {
560 start += 1;
561 }
562
563 while start + 1 < total
565 && is_move_to(self.vertices[start].cmd)
566 && is_move_to(self.vertices[start + 1].cmd)
567 {
568 start += 1;
569 }
570
571 let mut end = start + 1;
573 while end < total && !is_next_poly(self.vertices[end].cmd) {
574 end += 1;
575 }
576
577 self.invert_polygon_range(start, end);
578 }
579
580 pub fn arrange_polygon_orientation(&mut self, start: usize, orientation: u32) -> usize {
583 if orientation == PATH_FLAGS_NONE {
584 return start;
585 }
586
587 let mut start = start;
588 let total = self.vertices.len();
589
590 while start < total && !is_vertex(self.vertices[start].cmd) {
592 start += 1;
593 }
594
595 while start + 1 < total
597 && is_move_to(self.vertices[start].cmd)
598 && is_move_to(self.vertices[start + 1].cmd)
599 {
600 start += 1;
601 }
602
603 let mut end = start + 1;
605 while end < total && !is_next_poly(self.vertices[end].cmd) {
606 end += 1;
607 }
608
609 if end - start > 2 && self.perceive_polygon_orientation(start, end) != orientation {
610 self.invert_polygon_range(start, end);
611 let mut idx = end;
612 while idx < total && is_end_poly(self.vertices[idx].cmd) {
613 let cmd = self.vertices[idx].cmd;
614 self.vertices[idx].cmd = set_orientation(cmd, orientation);
615 idx += 1;
616 }
617 return idx;
618 }
619 end
620 }
621
622 pub fn arrange_orientations(&mut self, start: usize, orientation: u32) -> usize {
624 let mut start = start;
625 if orientation != PATH_FLAGS_NONE {
626 while start < self.vertices.len() {
627 start = self.arrange_polygon_orientation(start, orientation);
628 if is_stop(self.vertices.get(start).map_or(PATH_CMD_STOP, |v| v.cmd)) {
629 start += 1;
630 break;
631 }
632 }
633 }
634 start
635 }
636
637 pub fn arrange_orientations_all_paths(&mut self, orientation: u32) {
639 if orientation != PATH_FLAGS_NONE {
640 let mut start = 0;
641 while start < self.vertices.len() {
642 start = self.arrange_orientations(start, orientation);
643 }
644 }
645 }
646
647 pub fn flip_x(&mut self, x1: f64, x2: f64) {
649 for v in &mut self.vertices {
650 if is_vertex(v.cmd) {
651 v.x = x2 - v.x + x1;
652 }
653 }
654 }
655
656 pub fn flip_y(&mut self, y1: f64, y2: f64) {
658 for v in &mut self.vertices {
659 if is_vertex(v.cmd) {
660 v.y = y2 - v.y + y1;
661 }
662 }
663 }
664
665 pub fn translate(&mut self, dx: f64, dy: f64, path_id: usize) {
667 let total = self.vertices.len();
668 let mut idx = path_id;
669 while idx < total {
670 let cmd = self.vertices[idx].cmd;
671 if is_stop(cmd) {
672 break;
673 }
674 if is_vertex(cmd) {
675 self.vertices[idx].x += dx;
676 self.vertices[idx].y += dy;
677 }
678 idx += 1;
679 }
680 }
681
682 pub fn translate_all_paths(&mut self, dx: f64, dy: f64) {
684 for v in &mut self.vertices {
685 if is_vertex(v.cmd) {
686 v.x += dx;
687 v.y += dy;
688 }
689 }
690 }
691
692 pub fn transform<F: Fn(f64, f64) -> (f64, f64)>(&mut self, trans: &F, path_id: usize) {
694 let total = self.vertices.len();
695 let mut idx = path_id;
696 while idx < total {
697 let cmd = self.vertices[idx].cmd;
698 if is_stop(cmd) {
699 break;
700 }
701 if is_vertex(cmd) {
702 let (nx, ny) = trans(self.vertices[idx].x, self.vertices[idx].y);
703 self.vertices[idx].x = nx;
704 self.vertices[idx].y = ny;
705 }
706 idx += 1;
707 }
708 }
709
710 pub fn transform_all_paths<F: Fn(f64, f64) -> (f64, f64)>(&mut self, trans: &F) {
712 for v in &mut self.vertices {
713 if is_vertex(v.cmd) {
714 let (nx, ny) = trans(v.x, v.y);
715 v.x = nx;
716 v.y = ny;
717 }
718 }
719 }
720
721 pub fn align_path(&mut self, idx: usize) -> usize {
724 let total = self.total_vertices();
725 let mut idx = idx;
726
727 if idx >= total || !is_move_to(self.command(idx)) {
728 return total;
729 }
730
731 let mut start_x = 0.0;
732 let mut start_y = 0.0;
733 while idx < total && is_move_to(self.command(idx)) {
734 self.vertex_idx(idx, &mut start_x, &mut start_y);
735 idx += 1;
736 }
737 while idx < total && is_drawing(self.command(idx)) {
738 idx += 1;
739 }
740
741 let mut x = 0.0;
742 let mut y = 0.0;
743 if is_drawing(self.vertex_idx(idx - 1, &mut x, &mut y))
744 && is_equal_eps(x, start_x, 1e-8)
745 && is_equal_eps(y, start_y, 1e-8)
746 {
747 self.modify_vertex(idx - 1, start_x, start_y);
748 }
749
750 while idx < total && !is_move_to(self.command(idx)) {
751 idx += 1;
752 }
753 idx
754 }
755
756 pub fn align_all_paths(&mut self) {
758 let mut i = 0;
759 while i < self.total_vertices() {
760 i = self.align_path(i);
761 }
762 }
763}
764
765impl Default for PathStorage {
766 fn default() -> Self {
767 Self::new()
768 }
769}
770
771impl VertexSource for PathStorage {
772 fn rewind(&mut self, path_id: u32) {
773 self.iterator = path_id as usize;
774 }
775
776 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
777 if self.iterator >= self.vertices.len() {
778 return PATH_CMD_STOP;
779 }
780 let v = &self.vertices[self.iterator];
781 *x = v.x;
782 *y = v.y;
783 self.iterator += 1;
784 v.cmd
785 }
786}
787
788pub struct PolyPlainAdaptor<'a> {
797 data: &'a [f64],
798 index: usize,
799 closed: bool,
800 stop: bool,
801}
802
803impl<'a> PolyPlainAdaptor<'a> {
804 pub fn new(data: &'a [f64], closed: bool) -> Self {
806 Self {
807 data,
808 index: 0,
809 closed,
810 stop: false,
811 }
812 }
813}
814
815impl VertexSource for PolyPlainAdaptor<'_> {
816 fn rewind(&mut self, _path_id: u32) {
817 self.index = 0;
818 self.stop = false;
819 }
820
821 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
822 if self.index + 1 < self.data.len() {
823 let first = self.index == 0;
824 *x = self.data[self.index];
825 *y = self.data[self.index + 1];
826 self.index += 2;
827 return if first {
828 PATH_CMD_MOVE_TO
829 } else {
830 PATH_CMD_LINE_TO
831 };
832 }
833 *x = 0.0;
834 *y = 0.0;
835 if self.closed && !self.stop {
836 self.stop = true;
837 return PATH_CMD_END_POLY | PATH_FLAGS_CLOSE;
838 }
839 PATH_CMD_STOP
840 }
841}
842
843pub struct LineAdaptor {
847 coords: [f64; 4],
848 index: usize,
849}
850
851impl LineAdaptor {
852 pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
854 Self {
855 coords: [x1, y1, x2, y2],
856 index: 0,
857 }
858 }
859
860 pub fn init(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
862 self.coords = [x1, y1, x2, y2];
863 self.index = 0;
864 }
865}
866
867impl VertexSource for LineAdaptor {
868 fn rewind(&mut self, _path_id: u32) {
869 self.index = 0;
870 }
871
872 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
873 if self.index < 4 {
874 let first = self.index == 0;
875 *x = self.coords[self.index];
876 *y = self.coords[self.index + 1];
877 self.index += 2;
878 return if first {
879 PATH_CMD_MOVE_TO
880 } else {
881 PATH_CMD_LINE_TO
882 };
883 }
884 *x = 0.0;
885 *y = 0.0;
886 PATH_CMD_STOP
887 }
888}
889
890#[cfg(test)]
891mod tests {
892 use super::*;
893 use crate::basics::is_close;
894
895 #[test]
896 fn test_new_empty() {
897 let ps = PathStorage::new();
898 assert_eq!(ps.total_vertices(), 0);
899 assert_eq!(ps.last_command(), PATH_CMD_STOP);
900 assert_eq!(ps.last_x(), 0.0);
901 assert_eq!(ps.last_y(), 0.0);
902 }
903
904 #[test]
905 fn test_move_to_line_to() {
906 let mut ps = PathStorage::new();
907 ps.move_to(10.0, 20.0);
908 ps.line_to(30.0, 40.0);
909 ps.line_to(50.0, 60.0);
910
911 assert_eq!(ps.total_vertices(), 3);
912 assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
913 assert_eq!(ps.command(1), PATH_CMD_LINE_TO);
914 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
915
916 let (mut x, mut y) = (0.0, 0.0);
917 ps.vertex_idx(1, &mut x, &mut y);
918 assert!((x - 30.0).abs() < 1e-10);
919 assert!((y - 40.0).abs() < 1e-10);
920 }
921
922 #[test]
923 fn test_relative_commands() {
924 let mut ps = PathStorage::new();
925 ps.move_to(10.0, 20.0);
926 ps.line_rel(5.0, 5.0);
927
928 let (mut x, mut y) = (0.0, 0.0);
929 ps.vertex_idx(1, &mut x, &mut y);
930 assert!((x - 15.0).abs() < 1e-10);
931 assert!((y - 25.0).abs() < 1e-10);
932 }
933
934 #[test]
935 fn test_hline_vline() {
936 let mut ps = PathStorage::new();
937 ps.move_to(10.0, 20.0);
938 ps.hline_to(50.0);
939 ps.vline_to(80.0);
940
941 let (mut x, mut y) = (0.0, 0.0);
942 ps.vertex_idx(1, &mut x, &mut y);
943 assert!((x - 50.0).abs() < 1e-10);
944 assert!((y - 20.0).abs() < 1e-10);
945
946 ps.vertex_idx(2, &mut x, &mut y);
947 assert!((x - 50.0).abs() < 1e-10);
948 assert!((y - 80.0).abs() < 1e-10);
949 }
950
951 #[test]
952 fn test_hline_rel_vline_rel() {
953 let mut ps = PathStorage::new();
954 ps.move_to(10.0, 20.0);
955 ps.hline_rel(5.0);
956 ps.vline_rel(10.0);
957
958 let (mut x, mut y) = (0.0, 0.0);
959 ps.vertex_idx(1, &mut x, &mut y);
960 assert!((x - 15.0).abs() < 1e-10);
961 assert!((y - 20.0).abs() < 1e-10);
962
963 ps.vertex_idx(2, &mut x, &mut y);
964 assert!((x - 15.0).abs() < 1e-10);
965 assert!((y - 30.0).abs() < 1e-10);
966 }
967
968 #[test]
969 fn test_curve3() {
970 let mut ps = PathStorage::new();
971 ps.move_to(0.0, 0.0);
972 ps.curve3(50.0, 100.0, 100.0, 0.0);
973
974 assert_eq!(ps.total_vertices(), 3);
975 assert_eq!(ps.command(1), PATH_CMD_CURVE3);
976 assert_eq!(ps.command(2), PATH_CMD_CURVE3);
977 }
978
979 #[test]
980 fn test_curve4() {
981 let mut ps = PathStorage::new();
982 ps.move_to(0.0, 0.0);
983 ps.curve4(25.0, 100.0, 75.0, 100.0, 100.0, 0.0);
984
985 assert_eq!(ps.total_vertices(), 4);
986 assert_eq!(ps.command(1), PATH_CMD_CURVE4);
987 assert_eq!(ps.command(2), PATH_CMD_CURVE4);
988 assert_eq!(ps.command(3), PATH_CMD_CURVE4);
989 }
990
991 #[test]
992 fn test_close_polygon() {
993 let mut ps = PathStorage::new();
994 ps.move_to(0.0, 0.0);
995 ps.line_to(100.0, 0.0);
996 ps.line_to(100.0, 100.0);
997 ps.close_polygon(PATH_FLAGS_NONE);
998
999 assert_eq!(ps.total_vertices(), 4);
1000 assert!(is_end_poly(ps.command(3)));
1001 assert!(is_close(ps.command(3)));
1002 }
1003
1004 #[test]
1005 fn test_vertex_source_iteration() {
1006 let mut ps = PathStorage::new();
1007 ps.move_to(10.0, 20.0);
1008 ps.line_to(30.0, 40.0);
1009
1010 ps.rewind(0);
1011 let (mut x, mut y) = (0.0, 0.0);
1012
1013 let cmd = ps.vertex(&mut x, &mut y);
1014 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1015 assert!((x - 10.0).abs() < 1e-10);
1016
1017 let cmd = ps.vertex(&mut x, &mut y);
1018 assert_eq!(cmd, PATH_CMD_LINE_TO);
1019 assert!((x - 30.0).abs() < 1e-10);
1020
1021 let cmd = ps.vertex(&mut x, &mut y);
1022 assert_eq!(cmd, PATH_CMD_STOP);
1023 }
1024
1025 #[test]
1026 fn test_start_new_path() {
1027 let mut ps = PathStorage::new();
1028 ps.move_to(0.0, 0.0);
1029 ps.line_to(10.0, 10.0);
1030
1031 let id = ps.start_new_path();
1032 assert_eq!(id, 3); ps.move_to(50.0, 50.0);
1035 ps.line_to(60.0, 60.0);
1036
1037 ps.rewind(id as u32);
1039 let (mut x, mut y) = (0.0, 0.0);
1040 let cmd = ps.vertex(&mut x, &mut y);
1041 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1042 assert!((x - 50.0).abs() < 1e-10);
1043 }
1044
1045 #[test]
1046 fn test_modify_vertex() {
1047 let mut ps = PathStorage::new();
1048 ps.move_to(10.0, 20.0);
1049 ps.modify_vertex(0, 30.0, 40.0);
1050
1051 let (mut x, mut y) = (0.0, 0.0);
1052 ps.vertex_idx(0, &mut x, &mut y);
1053 assert!((x - 30.0).abs() < 1e-10);
1054 assert!((y - 40.0).abs() < 1e-10);
1055 }
1056
1057 #[test]
1058 fn test_swap_vertices() {
1059 let mut ps = PathStorage::new();
1060 ps.move_to(10.0, 20.0);
1061 ps.line_to(30.0, 40.0);
1062
1063 ps.swap_vertices(0, 1);
1064
1065 let (mut x, mut y) = (0.0, 0.0);
1066 ps.vertex_idx(0, &mut x, &mut y);
1067 assert!((x - 30.0).abs() < 1e-10);
1068 assert_eq!(ps.command(0), PATH_CMD_LINE_TO);
1069
1070 ps.vertex_idx(1, &mut x, &mut y);
1071 assert!((x - 10.0).abs() < 1e-10);
1072 assert_eq!(ps.command(1), PATH_CMD_MOVE_TO);
1073 }
1074
1075 #[test]
1076 fn test_flip_x() {
1077 let mut ps = PathStorage::new();
1078 ps.move_to(10.0, 20.0);
1079 ps.line_to(30.0, 40.0);
1080 ps.flip_x(0.0, 100.0);
1081
1082 let (mut x, mut y) = (0.0, 0.0);
1083 ps.vertex_idx(0, &mut x, &mut y);
1084 assert!((x - 90.0).abs() < 1e-10);
1085 assert!((y - 20.0).abs() < 1e-10);
1086
1087 ps.vertex_idx(1, &mut x, &mut y);
1088 assert!((x - 70.0).abs() < 1e-10);
1089 }
1090
1091 #[test]
1092 fn test_flip_y() {
1093 let mut ps = PathStorage::new();
1094 ps.move_to(10.0, 20.0);
1095 ps.line_to(30.0, 40.0);
1096 ps.flip_y(0.0, 100.0);
1097
1098 let (mut x, mut y) = (0.0, 0.0);
1099 ps.vertex_idx(0, &mut x, &mut y);
1100 assert!((x - 10.0).abs() < 1e-10);
1101 assert!((y - 80.0).abs() < 1e-10);
1102 }
1103
1104 #[test]
1105 fn test_translate() {
1106 let mut ps = PathStorage::new();
1107 ps.move_to(10.0, 20.0);
1108 ps.line_to(30.0, 40.0);
1109 ps.translate(5.0, 10.0, 0);
1110
1111 let (mut x, mut y) = (0.0, 0.0);
1112 ps.vertex_idx(0, &mut x, &mut y);
1113 assert!((x - 15.0).abs() < 1e-10);
1114 assert!((y - 30.0).abs() < 1e-10);
1115 }
1116
1117 #[test]
1118 fn test_translate_all_paths() {
1119 let mut ps = PathStorage::new();
1120 ps.move_to(10.0, 20.0);
1121 ps.line_to(30.0, 40.0);
1122 ps.translate_all_paths(100.0, 200.0);
1123
1124 let (mut x, mut y) = (0.0, 0.0);
1125 ps.vertex_idx(0, &mut x, &mut y);
1126 assert!((x - 110.0).abs() < 1e-10);
1127 assert!((y - 220.0).abs() < 1e-10);
1128 }
1129
1130 #[test]
1131 fn test_concat_path() {
1132 let mut ps = PathStorage::new();
1133 ps.move_to(0.0, 0.0);
1134
1135 let mut ps2 = PathStorage::new();
1136 ps2.move_to(10.0, 20.0);
1137 ps2.line_to(30.0, 40.0);
1138
1139 ps.concat_path(&mut ps2, 0);
1140
1141 assert_eq!(ps.total_vertices(), 3);
1142 assert_eq!(ps.command(1), PATH_CMD_MOVE_TO);
1143 }
1144
1145 #[test]
1146 fn test_join_path() {
1147 let mut ps = PathStorage::new();
1148 ps.move_to(0.0, 0.0);
1149 ps.line_to(10.0, 10.0);
1150
1151 let mut ps2 = PathStorage::new();
1152 ps2.move_to(20.0, 20.0);
1153 ps2.line_to(30.0, 30.0);
1154
1155 ps.join_path(&mut ps2, 0);
1156
1157 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
1159 let (mut x, mut y) = (0.0, 0.0);
1160 ps.vertex_idx(2, &mut x, &mut y);
1161 assert!((x - 20.0).abs() < 1e-10);
1162 }
1163
1164 #[test]
1165 fn test_remove_all() {
1166 let mut ps = PathStorage::new();
1167 ps.move_to(10.0, 20.0);
1168 ps.line_to(30.0, 40.0);
1169 ps.remove_all();
1170
1171 assert_eq!(ps.total_vertices(), 0);
1172 }
1173
1174 #[test]
1175 fn test_poly_plain_adaptor() {
1176 let data = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0];
1177 let mut adaptor = PolyPlainAdaptor::new(&data, true);
1178
1179 let (mut x, mut y) = (0.0, 0.0);
1180 let cmd = adaptor.vertex(&mut x, &mut y);
1181 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1182 assert!((x - 10.0).abs() < 1e-10);
1183
1184 let cmd = adaptor.vertex(&mut x, &mut y);
1185 assert_eq!(cmd, PATH_CMD_LINE_TO);
1186 assert!((x - 30.0).abs() < 1e-10);
1187
1188 let cmd = adaptor.vertex(&mut x, &mut y);
1189 assert_eq!(cmd, PATH_CMD_LINE_TO);
1190 assert!((x - 50.0).abs() < 1e-10);
1191
1192 let cmd = adaptor.vertex(&mut x, &mut y);
1193 assert!(is_end_poly(cmd));
1194 assert!(is_close(cmd));
1195
1196 let cmd = adaptor.vertex(&mut x, &mut y);
1197 assert_eq!(cmd, PATH_CMD_STOP);
1198 }
1199
1200 #[test]
1201 fn test_poly_plain_adaptor_open() {
1202 let data = [10.0, 20.0, 30.0, 40.0];
1203 let mut adaptor = PolyPlainAdaptor::new(&data, false);
1204
1205 let (mut x, mut y) = (0.0, 0.0);
1206 adaptor.vertex(&mut x, &mut y); adaptor.vertex(&mut x, &mut y); let cmd = adaptor.vertex(&mut x, &mut y);
1210 assert_eq!(cmd, PATH_CMD_STOP); }
1212
1213 #[test]
1214 fn test_line_adaptor() {
1215 let mut la = LineAdaptor::new(10.0, 20.0, 30.0, 40.0);
1216 let (mut x, mut y) = (0.0, 0.0);
1217
1218 let cmd = la.vertex(&mut x, &mut y);
1219 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1220 assert!((x - 10.0).abs() < 1e-10);
1221 assert!((y - 20.0).abs() < 1e-10);
1222
1223 let cmd = la.vertex(&mut x, &mut y);
1224 assert_eq!(cmd, PATH_CMD_LINE_TO);
1225 assert!((x - 30.0).abs() < 1e-10);
1226 assert!((y - 40.0).abs() < 1e-10);
1227
1228 let cmd = la.vertex(&mut x, &mut y);
1229 assert_eq!(cmd, PATH_CMD_STOP);
1230 }
1231
1232 #[test]
1233 fn test_line_adaptor_rewind() {
1234 let mut la = LineAdaptor::new(10.0, 20.0, 30.0, 40.0);
1235 let (mut x, mut y) = (0.0, 0.0);
1236
1237 la.vertex(&mut x, &mut y);
1238 la.vertex(&mut x, &mut y);
1239 la.rewind(0);
1240
1241 let cmd = la.vertex(&mut x, &mut y);
1242 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1243 }
1244
1245 #[test]
1246 fn test_curve3_smooth() {
1247 let mut ps = PathStorage::new();
1248 ps.move_to(0.0, 0.0);
1249 ps.curve3(50.0, 100.0, 100.0, 0.0);
1250 ps.curve3_smooth(200.0, 0.0);
1251
1252 assert_eq!(ps.total_vertices(), 5);
1254 let (mut x, mut y) = (0.0, 0.0);
1255 ps.vertex_idx(3, &mut x, &mut y);
1256 assert!((x - 150.0).abs() < 1e-10);
1257 assert!((y - (-100.0)).abs() < 1e-10);
1258 }
1259
1260 #[test]
1261 fn test_curve4_smooth() {
1262 let mut ps = PathStorage::new();
1263 ps.move_to(0.0, 0.0);
1264 ps.curve4(25.0, 100.0, 75.0, 100.0, 100.0, 0.0);
1265 ps.curve4_smooth(175.0, 100.0, 200.0, 0.0);
1266
1267 assert_eq!(ps.total_vertices(), 7);
1269 let (mut x, mut y) = (0.0, 0.0);
1270 ps.vertex_idx(4, &mut x, &mut y);
1271 assert!((x - 125.0).abs() < 1e-10);
1272 assert!((y - (-100.0)).abs() < 1e-10);
1273 }
1274
1275 #[test]
1276 fn test_invert_polygon() {
1277 let mut ps = PathStorage::new();
1278 ps.move_to(0.0, 0.0);
1279 ps.line_to(100.0, 0.0);
1280 ps.line_to(100.0, 100.0);
1281
1282 ps.invert_polygon(0);
1283
1284 let (mut x, mut y) = (0.0, 0.0);
1286 ps.vertex_idx(0, &mut x, &mut y);
1287 assert!((x - 100.0).abs() < 1e-10);
1288 assert!((y - 100.0).abs() < 1e-10);
1289 }
1290
1291 #[test]
1292 fn test_perceive_orientation_ccw() {
1293 let mut ps = PathStorage::new();
1294 ps.move_to(0.0, 0.0);
1296 ps.line_to(100.0, 0.0);
1297 ps.line_to(100.0, 100.0);
1298
1299 let ori = ps.perceive_polygon_orientation(0, 3);
1300 assert_eq!(ori, PATH_FLAGS_CCW);
1301 }
1302
1303 #[test]
1304 fn test_perceive_orientation_cw() {
1305 let mut ps = PathStorage::new();
1306 ps.move_to(0.0, 0.0);
1308 ps.line_to(100.0, 100.0);
1309 ps.line_to(100.0, 0.0);
1310
1311 let ori = ps.perceive_polygon_orientation(0, 3);
1312 assert_eq!(ori, PATH_FLAGS_CW);
1313 }
1314
1315 #[test]
1316 fn test_arrange_polygon_orientation() {
1317 let mut ps = PathStorage::new();
1318 ps.move_to(0.0, 0.0);
1320 ps.line_to(100.0, 100.0);
1321 ps.line_to(100.0, 0.0);
1322
1323 ps.arrange_polygon_orientation(0, PATH_FLAGS_CCW);
1325
1326 let ori = ps.perceive_polygon_orientation(0, 3);
1327 assert_eq!(ori, PATH_FLAGS_CCW);
1328 }
1329
1330 #[test]
1331 fn test_concat_poly() {
1332 let mut ps = PathStorage::new();
1333 let coords = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0];
1334 ps.concat_poly(&coords, true);
1335
1336 assert_eq!(ps.total_vertices(), 4); assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
1338 assert_eq!(ps.command(1), PATH_CMD_LINE_TO);
1339 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
1340 assert!(is_end_poly(ps.command(3)));
1341 }
1342
1343 #[test]
1344 fn test_transform_all_paths() {
1345 let mut ps = PathStorage::new();
1346 ps.move_to(10.0, 20.0);
1347 ps.line_to(30.0, 40.0);
1348
1349 ps.transform_all_paths(&|x, y| (x * 2.0, y * 3.0));
1350
1351 let (mut x, mut y) = (0.0, 0.0);
1352 ps.vertex_idx(0, &mut x, &mut y);
1353 assert!((x - 20.0).abs() < 1e-10);
1354 assert!((y - 60.0).abs() < 1e-10);
1355
1356 ps.vertex_idx(1, &mut x, &mut y);
1357 assert!((x - 60.0).abs() < 1e-10);
1358 assert!((y - 120.0).abs() < 1e-10);
1359 }
1360
1361 #[test]
1362 fn test_default() {
1363 let ps = PathStorage::default();
1364 assert_eq!(ps.total_vertices(), 0);
1365 }
1366
1367 #[test]
1368 fn test_move_rel_from_empty() {
1369 let mut ps = PathStorage::new();
1370 ps.move_rel(10.0, 20.0);
1372 let (mut x, mut y) = (0.0, 0.0);
1373 ps.vertex_idx(0, &mut x, &mut y);
1374 assert!((x - 10.0).abs() < 1e-10);
1375 assert!((y - 20.0).abs() < 1e-10);
1376 }
1377
1378 #[test]
1379 fn test_end_poly_only_after_vertex() {
1380 let mut ps = PathStorage::new();
1381 ps.end_poly(PATH_FLAGS_CLOSE);
1383 assert_eq!(ps.total_vertices(), 0);
1384
1385 ps.move_to(0.0, 0.0);
1386 ps.end_poly(PATH_FLAGS_CLOSE);
1387 assert_eq!(ps.total_vertices(), 2);
1388 }
1389
1390 #[test]
1391 fn test_arc_to() {
1392 let mut ps = PathStorage::new();
1393 ps.move_to(0.0, 0.0);
1394 ps.arc_to(50.0, 50.0, 0.0, false, true, 100.0, 0.0);
1396
1397 assert!(ps.total_vertices() > 2);
1398 }
1399
1400 #[test]
1401 fn test_arc_to_no_prior_vertex() {
1402 let mut ps = PathStorage::new();
1403 ps.arc_to(50.0, 50.0, 0.0, false, true, 100.0, 0.0);
1405 assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
1406 }
1407
1408 #[test]
1409 fn test_last_prev_vertex() {
1410 let mut ps = PathStorage::new();
1411 let (mut x, mut y) = (0.0, 0.0);
1412 assert_eq!(ps.last_vertex_xy(&mut x, &mut y), PATH_CMD_STOP);
1413 assert_eq!(ps.prev_vertex_xy(&mut x, &mut y), PATH_CMD_STOP);
1414
1415 ps.move_to(10.0, 20.0);
1416 ps.line_to(30.0, 40.0);
1417
1418 let cmd = ps.last_vertex_xy(&mut x, &mut y);
1419 assert_eq!(cmd, PATH_CMD_LINE_TO);
1420 assert!((x - 30.0).abs() < 1e-10);
1421
1422 let cmd = ps.prev_vertex_xy(&mut x, &mut y);
1423 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1424 assert!((x - 10.0).abs() < 1e-10);
1425 }
1426}