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] {
335 &self.vertices
336 }
337
338 pub fn rel_to_abs(&self, x: &mut f64, y: &mut f64) {
340 if !self.vertices.is_empty() {
341 let last = &self.vertices[self.vertices.len() - 1];
342 if is_vertex(last.cmd) {
343 *x += last.x;
344 *y += last.y;
345 }
346 }
347 }
348
349 pub fn last_vertex_xy(&self, x: &mut f64, y: &mut f64) -> u32 {
351 if self.vertices.is_empty() {
352 *x = 0.0;
353 *y = 0.0;
354 return PATH_CMD_STOP;
355 }
356 let v = &self.vertices[self.vertices.len() - 1];
357 *x = v.x;
358 *y = v.y;
359 v.cmd
360 }
361
362 pub fn prev_vertex_xy(&self, x: &mut f64, y: &mut f64) -> u32 {
364 if self.vertices.len() < 2 {
365 *x = 0.0;
366 *y = 0.0;
367 return PATH_CMD_STOP;
368 }
369 let v = &self.vertices[self.vertices.len() - 2];
370 *x = v.x;
371 *y = v.y;
372 v.cmd
373 }
374
375 pub fn last_command(&self) -> u32 {
377 if self.vertices.is_empty() {
378 PATH_CMD_STOP
379 } else {
380 self.vertices[self.vertices.len() - 1].cmd
381 }
382 }
383
384 pub fn last_x(&self) -> f64 {
386 if self.vertices.is_empty() {
387 0.0
388 } else {
389 self.vertices[self.vertices.len() - 1].x
390 }
391 }
392
393 pub fn last_y(&self) -> f64 {
395 if self.vertices.is_empty() {
396 0.0
397 } else {
398 self.vertices[self.vertices.len() - 1].y
399 }
400 }
401
402 pub fn vertex_idx(&self, idx: usize, x: &mut f64, y: &mut f64) -> u32 {
404 let v = &self.vertices[idx];
405 *x = v.x;
406 *y = v.y;
407 v.cmd
408 }
409
410 pub fn command(&self, idx: usize) -> u32 {
412 self.vertices[idx].cmd
413 }
414
415 pub fn modify_vertex(&mut self, idx: usize, x: f64, y: f64) {
417 self.vertices[idx].x = x;
418 self.vertices[idx].y = y;
419 }
420
421 pub fn modify_vertex_cmd(&mut self, idx: usize, x: f64, y: f64, cmd: u32) {
423 self.vertices[idx].x = x;
424 self.vertices[idx].y = y;
425 self.vertices[idx].cmd = cmd;
426 }
427
428 pub fn modify_command(&mut self, idx: usize, cmd: u32) {
430 self.vertices[idx].cmd = cmd;
431 }
432
433 pub fn swap_vertices(&mut self, v1: usize, v2: usize) {
435 self.vertices.swap(v1, v2);
436 }
437
438 pub fn concat_path(&mut self, vs: &mut dyn VertexSource, path_id: u32) {
444 let mut x = 0.0;
445 let mut y = 0.0;
446 vs.rewind(path_id);
447 loop {
448 let cmd = vs.vertex(&mut x, &mut y);
449 if is_stop(cmd) {
450 break;
451 }
452 self.vertices.push(VertexD::new(x, y, cmd));
453 }
454 }
455
456 pub fn join_path(&mut self, vs: &mut dyn VertexSource, path_id: u32) {
461 let mut x = 0.0;
462 let mut y = 0.0;
463 vs.rewind(path_id);
464 let mut cmd = vs.vertex(&mut x, &mut y);
465 if !is_stop(cmd) {
466 if is_vertex(cmd) {
467 let mut x0 = 0.0;
468 let mut y0 = 0.0;
469 let cmd0 = self.last_vertex_xy(&mut x0, &mut y0);
470 if is_vertex(cmd0) {
471 if calc_distance(x, y, x0, y0) > VERTEX_DIST_EPSILON {
472 if is_move_to(cmd) {
473 cmd = PATH_CMD_LINE_TO;
474 }
475 self.vertices.push(VertexD::new(x, y, cmd));
476 }
477 } else {
478 if is_stop(cmd0) {
479 cmd = PATH_CMD_MOVE_TO;
480 } else if is_move_to(cmd) {
481 cmd = PATH_CMD_LINE_TO;
482 }
483 self.vertices.push(VertexD::new(x, y, cmd));
484 }
485 }
486 loop {
487 cmd = vs.vertex(&mut x, &mut y);
488 if is_stop(cmd) {
489 break;
490 }
491 let actual_cmd = if is_move_to(cmd) {
492 PATH_CMD_LINE_TO
493 } else {
494 cmd
495 };
496 self.vertices.push(VertexD::new(x, y, actual_cmd));
497 }
498 }
499 }
500
501 pub fn concat_poly(&mut self, data: &[f64], closed: bool) {
503 let mut adaptor = PolyPlainAdaptor::new(data, closed);
504 self.concat_path(&mut adaptor, 0);
505 }
506
507 pub fn join_poly(&mut self, data: &[f64], closed: bool) {
509 let mut adaptor = PolyPlainAdaptor::new(data, closed);
510 self.join_path(&mut adaptor, 0);
511 }
512
513 fn perceive_polygon_orientation(&self, start: usize, end: usize) -> u32 {
519 let np = end - start;
520 let mut area = 0.0;
521 for i in 0..np {
522 let v1 = &self.vertices[start + i];
523 let v2 = &self.vertices[start + (i + 1) % np];
524 area += v1.x * v2.y - v1.y * v2.x;
525 }
526 if area < 0.0 {
527 PATH_FLAGS_CW
528 } else {
529 PATH_FLAGS_CCW
530 }
531 }
532
533 fn invert_polygon_range(&mut self, start: usize, end: usize) {
535 let tmp_cmd = self.vertices[start].cmd;
536 let end = end - 1; for i in start..end {
540 let next_cmd = self.vertices[i + 1].cmd;
541 self.vertices[i].cmd = next_cmd;
542 }
543
544 self.vertices[end].cmd = tmp_cmd;
546
547 let (mut lo, mut hi) = (start, end);
549 while hi > lo {
550 self.vertices.swap(lo, hi);
551 lo += 1;
552 hi -= 1;
553 }
554 }
555
556 pub fn invert_polygon(&mut self, start: usize) {
558 let mut start = start;
559 let total = self.vertices.len();
560
561 while start < total && !is_vertex(self.vertices[start].cmd) {
563 start += 1;
564 }
565
566 while start + 1 < total
568 && is_move_to(self.vertices[start].cmd)
569 && is_move_to(self.vertices[start + 1].cmd)
570 {
571 start += 1;
572 }
573
574 let mut end = start + 1;
576 while end < total && !is_next_poly(self.vertices[end].cmd) {
577 end += 1;
578 }
579
580 self.invert_polygon_range(start, end);
581 }
582
583 pub fn arrange_polygon_orientation(&mut self, start: usize, orientation: u32) -> usize {
586 if orientation == PATH_FLAGS_NONE {
587 return start;
588 }
589
590 let mut start = start;
591 let total = self.vertices.len();
592
593 while start < total && !is_vertex(self.vertices[start].cmd) {
595 start += 1;
596 }
597
598 while start + 1 < total
600 && is_move_to(self.vertices[start].cmd)
601 && is_move_to(self.vertices[start + 1].cmd)
602 {
603 start += 1;
604 }
605
606 let mut end = start + 1;
608 while end < total && !is_next_poly(self.vertices[end].cmd) {
609 end += 1;
610 }
611
612 if end - start > 2 && self.perceive_polygon_orientation(start, end) != orientation {
613 self.invert_polygon_range(start, end);
614 let mut idx = end;
615 while idx < total && is_end_poly(self.vertices[idx].cmd) {
616 let cmd = self.vertices[idx].cmd;
617 self.vertices[idx].cmd = set_orientation(cmd, orientation);
618 idx += 1;
619 }
620 return idx;
621 }
622 end
623 }
624
625 pub fn arrange_orientations(&mut self, start: usize, orientation: u32) -> usize {
627 let mut start = start;
628 if orientation != PATH_FLAGS_NONE {
629 while start < self.vertices.len() {
630 start = self.arrange_polygon_orientation(start, orientation);
631 if is_stop(self.vertices.get(start).map_or(PATH_CMD_STOP, |v| v.cmd)) {
632 start += 1;
633 break;
634 }
635 }
636 }
637 start
638 }
639
640 pub fn arrange_orientations_all_paths(&mut self, orientation: u32) {
642 if orientation != PATH_FLAGS_NONE {
643 let mut start = 0;
644 while start < self.vertices.len() {
645 start = self.arrange_orientations(start, orientation);
646 }
647 }
648 }
649
650 pub fn flip_x(&mut self, x1: f64, x2: f64) {
652 for v in &mut self.vertices {
653 if is_vertex(v.cmd) {
654 v.x = x2 - v.x + x1;
655 }
656 }
657 }
658
659 pub fn flip_y(&mut self, y1: f64, y2: f64) {
661 for v in &mut self.vertices {
662 if is_vertex(v.cmd) {
663 v.y = y2 - v.y + y1;
664 }
665 }
666 }
667
668 pub fn translate(&mut self, dx: f64, dy: f64, path_id: usize) {
670 let total = self.vertices.len();
671 let mut idx = path_id;
672 while idx < total {
673 let cmd = self.vertices[idx].cmd;
674 if is_stop(cmd) {
675 break;
676 }
677 if is_vertex(cmd) {
678 self.vertices[idx].x += dx;
679 self.vertices[idx].y += dy;
680 }
681 idx += 1;
682 }
683 }
684
685 pub fn translate_all_paths(&mut self, dx: f64, dy: f64) {
687 for v in &mut self.vertices {
688 if is_vertex(v.cmd) {
689 v.x += dx;
690 v.y += dy;
691 }
692 }
693 }
694
695 pub fn transform<F: Fn(f64, f64) -> (f64, f64)>(&mut self, trans: &F, path_id: usize) {
697 let total = self.vertices.len();
698 let mut idx = path_id;
699 while idx < total {
700 let cmd = self.vertices[idx].cmd;
701 if is_stop(cmd) {
702 break;
703 }
704 if is_vertex(cmd) {
705 let (nx, ny) = trans(self.vertices[idx].x, self.vertices[idx].y);
706 self.vertices[idx].x = nx;
707 self.vertices[idx].y = ny;
708 }
709 idx += 1;
710 }
711 }
712
713 pub fn transform_all_paths<F: Fn(f64, f64) -> (f64, f64)>(&mut self, trans: &F) {
715 for v in &mut self.vertices {
716 if is_vertex(v.cmd) {
717 let (nx, ny) = trans(v.x, v.y);
718 v.x = nx;
719 v.y = ny;
720 }
721 }
722 }
723
724 pub fn align_path(&mut self, idx: usize) -> usize {
727 let total = self.total_vertices();
728 let mut idx = idx;
729
730 if idx >= total || !is_move_to(self.command(idx)) {
731 return total;
732 }
733
734 let mut start_x = 0.0;
735 let mut start_y = 0.0;
736 while idx < total && is_move_to(self.command(idx)) {
737 self.vertex_idx(idx, &mut start_x, &mut start_y);
738 idx += 1;
739 }
740 while idx < total && is_drawing(self.command(idx)) {
741 idx += 1;
742 }
743
744 let mut x = 0.0;
745 let mut y = 0.0;
746 if is_drawing(self.vertex_idx(idx - 1, &mut x, &mut y))
747 && is_equal_eps(x, start_x, 1e-8)
748 && is_equal_eps(y, start_y, 1e-8)
749 {
750 self.modify_vertex(idx - 1, start_x, start_y);
751 }
752
753 while idx < total && !is_move_to(self.command(idx)) {
754 idx += 1;
755 }
756 idx
757 }
758
759 pub fn align_all_paths(&mut self) {
761 let mut i = 0;
762 while i < self.total_vertices() {
763 i = self.align_path(i);
764 }
765 }
766}
767
768impl Default for PathStorage {
769 fn default() -> Self {
770 Self::new()
771 }
772}
773
774impl VertexSource for PathStorage {
775 fn rewind(&mut self, path_id: u32) {
776 self.iterator = path_id as usize;
777 }
778
779 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
780 if self.iterator >= self.vertices.len() {
781 return PATH_CMD_STOP;
782 }
783 let v = &self.vertices[self.iterator];
784 *x = v.x;
785 *y = v.y;
786 self.iterator += 1;
787 v.cmd
788 }
789}
790
791pub struct PolyPlainAdaptor<'a> {
800 data: &'a [f64],
801 index: usize,
802 closed: bool,
803 stop: bool,
804}
805
806impl<'a> PolyPlainAdaptor<'a> {
807 pub fn new(data: &'a [f64], closed: bool) -> Self {
809 Self {
810 data,
811 index: 0,
812 closed,
813 stop: false,
814 }
815 }
816}
817
818impl VertexSource for PolyPlainAdaptor<'_> {
819 fn rewind(&mut self, _path_id: u32) {
820 self.index = 0;
821 self.stop = false;
822 }
823
824 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
825 if self.index + 1 < self.data.len() {
826 let first = self.index == 0;
827 *x = self.data[self.index];
828 *y = self.data[self.index + 1];
829 self.index += 2;
830 return if first {
831 PATH_CMD_MOVE_TO
832 } else {
833 PATH_CMD_LINE_TO
834 };
835 }
836 *x = 0.0;
837 *y = 0.0;
838 if self.closed && !self.stop {
839 self.stop = true;
840 return PATH_CMD_END_POLY | PATH_FLAGS_CLOSE;
841 }
842 PATH_CMD_STOP
843 }
844}
845
846pub struct LineAdaptor {
850 coords: [f64; 4],
851 index: usize,
852}
853
854impl LineAdaptor {
855 pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
857 Self {
858 coords: [x1, y1, x2, y2],
859 index: 0,
860 }
861 }
862
863 pub fn init(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
865 self.coords = [x1, y1, x2, y2];
866 self.index = 0;
867 }
868}
869
870impl VertexSource for LineAdaptor {
871 fn rewind(&mut self, _path_id: u32) {
872 self.index = 0;
873 }
874
875 fn vertex(&mut self, x: &mut f64, y: &mut f64) -> u32 {
876 if self.index < 4 {
877 let first = self.index == 0;
878 *x = self.coords[self.index];
879 *y = self.coords[self.index + 1];
880 self.index += 2;
881 return if first {
882 PATH_CMD_MOVE_TO
883 } else {
884 PATH_CMD_LINE_TO
885 };
886 }
887 *x = 0.0;
888 *y = 0.0;
889 PATH_CMD_STOP
890 }
891}
892
893#[cfg(test)]
894mod tests {
895 use super::*;
896 use crate::basics::is_close;
897
898 #[test]
899 fn test_new_empty() {
900 let ps = PathStorage::new();
901 assert_eq!(ps.total_vertices(), 0);
902 assert_eq!(ps.last_command(), PATH_CMD_STOP);
903 assert_eq!(ps.last_x(), 0.0);
904 assert_eq!(ps.last_y(), 0.0);
905 }
906
907 #[test]
908 fn test_move_to_line_to() {
909 let mut ps = PathStorage::new();
910 ps.move_to(10.0, 20.0);
911 ps.line_to(30.0, 40.0);
912 ps.line_to(50.0, 60.0);
913
914 assert_eq!(ps.total_vertices(), 3);
915 assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
916 assert_eq!(ps.command(1), PATH_CMD_LINE_TO);
917 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
918
919 let (mut x, mut y) = (0.0, 0.0);
920 ps.vertex_idx(1, &mut x, &mut y);
921 assert!((x - 30.0).abs() < 1e-10);
922 assert!((y - 40.0).abs() < 1e-10);
923 }
924
925 #[test]
926 fn test_relative_commands() {
927 let mut ps = PathStorage::new();
928 ps.move_to(10.0, 20.0);
929 ps.line_rel(5.0, 5.0);
930
931 let (mut x, mut y) = (0.0, 0.0);
932 ps.vertex_idx(1, &mut x, &mut y);
933 assert!((x - 15.0).abs() < 1e-10);
934 assert!((y - 25.0).abs() < 1e-10);
935 }
936
937 #[test]
938 fn test_hline_vline() {
939 let mut ps = PathStorage::new();
940 ps.move_to(10.0, 20.0);
941 ps.hline_to(50.0);
942 ps.vline_to(80.0);
943
944 let (mut x, mut y) = (0.0, 0.0);
945 ps.vertex_idx(1, &mut x, &mut y);
946 assert!((x - 50.0).abs() < 1e-10);
947 assert!((y - 20.0).abs() < 1e-10);
948
949 ps.vertex_idx(2, &mut x, &mut y);
950 assert!((x - 50.0).abs() < 1e-10);
951 assert!((y - 80.0).abs() < 1e-10);
952 }
953
954 #[test]
955 fn test_hline_rel_vline_rel() {
956 let mut ps = PathStorage::new();
957 ps.move_to(10.0, 20.0);
958 ps.hline_rel(5.0);
959 ps.vline_rel(10.0);
960
961 let (mut x, mut y) = (0.0, 0.0);
962 ps.vertex_idx(1, &mut x, &mut y);
963 assert!((x - 15.0).abs() < 1e-10);
964 assert!((y - 20.0).abs() < 1e-10);
965
966 ps.vertex_idx(2, &mut x, &mut y);
967 assert!((x - 15.0).abs() < 1e-10);
968 assert!((y - 30.0).abs() < 1e-10);
969 }
970
971 #[test]
972 fn test_curve3() {
973 let mut ps = PathStorage::new();
974 ps.move_to(0.0, 0.0);
975 ps.curve3(50.0, 100.0, 100.0, 0.0);
976
977 assert_eq!(ps.total_vertices(), 3);
978 assert_eq!(ps.command(1), PATH_CMD_CURVE3);
979 assert_eq!(ps.command(2), PATH_CMD_CURVE3);
980 }
981
982 #[test]
983 fn test_curve4() {
984 let mut ps = PathStorage::new();
985 ps.move_to(0.0, 0.0);
986 ps.curve4(25.0, 100.0, 75.0, 100.0, 100.0, 0.0);
987
988 assert_eq!(ps.total_vertices(), 4);
989 assert_eq!(ps.command(1), PATH_CMD_CURVE4);
990 assert_eq!(ps.command(2), PATH_CMD_CURVE4);
991 assert_eq!(ps.command(3), PATH_CMD_CURVE4);
992 }
993
994 #[test]
995 fn test_close_polygon() {
996 let mut ps = PathStorage::new();
997 ps.move_to(0.0, 0.0);
998 ps.line_to(100.0, 0.0);
999 ps.line_to(100.0, 100.0);
1000 ps.close_polygon(PATH_FLAGS_NONE);
1001
1002 assert_eq!(ps.total_vertices(), 4);
1003 assert!(is_end_poly(ps.command(3)));
1004 assert!(is_close(ps.command(3)));
1005 }
1006
1007 #[test]
1008 fn test_vertex_source_iteration() {
1009 let mut ps = PathStorage::new();
1010 ps.move_to(10.0, 20.0);
1011 ps.line_to(30.0, 40.0);
1012
1013 ps.rewind(0);
1014 let (mut x, mut y) = (0.0, 0.0);
1015
1016 let cmd = ps.vertex(&mut x, &mut y);
1017 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1018 assert!((x - 10.0).abs() < 1e-10);
1019
1020 let cmd = ps.vertex(&mut x, &mut y);
1021 assert_eq!(cmd, PATH_CMD_LINE_TO);
1022 assert!((x - 30.0).abs() < 1e-10);
1023
1024 let cmd = ps.vertex(&mut x, &mut y);
1025 assert_eq!(cmd, PATH_CMD_STOP);
1026 }
1027
1028 #[test]
1029 fn test_start_new_path() {
1030 let mut ps = PathStorage::new();
1031 ps.move_to(0.0, 0.0);
1032 ps.line_to(10.0, 10.0);
1033
1034 let id = ps.start_new_path();
1035 assert_eq!(id, 3); ps.move_to(50.0, 50.0);
1038 ps.line_to(60.0, 60.0);
1039
1040 ps.rewind(id as u32);
1042 let (mut x, mut y) = (0.0, 0.0);
1043 let cmd = ps.vertex(&mut x, &mut y);
1044 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1045 assert!((x - 50.0).abs() < 1e-10);
1046 }
1047
1048 #[test]
1049 fn test_modify_vertex() {
1050 let mut ps = PathStorage::new();
1051 ps.move_to(10.0, 20.0);
1052 ps.modify_vertex(0, 30.0, 40.0);
1053
1054 let (mut x, mut y) = (0.0, 0.0);
1055 ps.vertex_idx(0, &mut x, &mut y);
1056 assert!((x - 30.0).abs() < 1e-10);
1057 assert!((y - 40.0).abs() < 1e-10);
1058 }
1059
1060 #[test]
1061 fn test_swap_vertices() {
1062 let mut ps = PathStorage::new();
1063 ps.move_to(10.0, 20.0);
1064 ps.line_to(30.0, 40.0);
1065
1066 ps.swap_vertices(0, 1);
1067
1068 let (mut x, mut y) = (0.0, 0.0);
1069 ps.vertex_idx(0, &mut x, &mut y);
1070 assert!((x - 30.0).abs() < 1e-10);
1071 assert_eq!(ps.command(0), PATH_CMD_LINE_TO);
1072
1073 ps.vertex_idx(1, &mut x, &mut y);
1074 assert!((x - 10.0).abs() < 1e-10);
1075 assert_eq!(ps.command(1), PATH_CMD_MOVE_TO);
1076 }
1077
1078 #[test]
1079 fn test_flip_x() {
1080 let mut ps = PathStorage::new();
1081 ps.move_to(10.0, 20.0);
1082 ps.line_to(30.0, 40.0);
1083 ps.flip_x(0.0, 100.0);
1084
1085 let (mut x, mut y) = (0.0, 0.0);
1086 ps.vertex_idx(0, &mut x, &mut y);
1087 assert!((x - 90.0).abs() < 1e-10);
1088 assert!((y - 20.0).abs() < 1e-10);
1089
1090 ps.vertex_idx(1, &mut x, &mut y);
1091 assert!((x - 70.0).abs() < 1e-10);
1092 }
1093
1094 #[test]
1095 fn test_flip_y() {
1096 let mut ps = PathStorage::new();
1097 ps.move_to(10.0, 20.0);
1098 ps.line_to(30.0, 40.0);
1099 ps.flip_y(0.0, 100.0);
1100
1101 let (mut x, mut y) = (0.0, 0.0);
1102 ps.vertex_idx(0, &mut x, &mut y);
1103 assert!((x - 10.0).abs() < 1e-10);
1104 assert!((y - 80.0).abs() < 1e-10);
1105 }
1106
1107 #[test]
1108 fn test_translate() {
1109 let mut ps = PathStorage::new();
1110 ps.move_to(10.0, 20.0);
1111 ps.line_to(30.0, 40.0);
1112 ps.translate(5.0, 10.0, 0);
1113
1114 let (mut x, mut y) = (0.0, 0.0);
1115 ps.vertex_idx(0, &mut x, &mut y);
1116 assert!((x - 15.0).abs() < 1e-10);
1117 assert!((y - 30.0).abs() < 1e-10);
1118 }
1119
1120 #[test]
1121 fn test_translate_all_paths() {
1122 let mut ps = PathStorage::new();
1123 ps.move_to(10.0, 20.0);
1124 ps.line_to(30.0, 40.0);
1125 ps.translate_all_paths(100.0, 200.0);
1126
1127 let (mut x, mut y) = (0.0, 0.0);
1128 ps.vertex_idx(0, &mut x, &mut y);
1129 assert!((x - 110.0).abs() < 1e-10);
1130 assert!((y - 220.0).abs() < 1e-10);
1131 }
1132
1133 #[test]
1134 fn test_concat_path() {
1135 let mut ps = PathStorage::new();
1136 ps.move_to(0.0, 0.0);
1137
1138 let mut ps2 = PathStorage::new();
1139 ps2.move_to(10.0, 20.0);
1140 ps2.line_to(30.0, 40.0);
1141
1142 ps.concat_path(&mut ps2, 0);
1143
1144 assert_eq!(ps.total_vertices(), 3);
1145 assert_eq!(ps.command(1), PATH_CMD_MOVE_TO);
1146 }
1147
1148 #[test]
1149 fn test_join_path() {
1150 let mut ps = PathStorage::new();
1151 ps.move_to(0.0, 0.0);
1152 ps.line_to(10.0, 10.0);
1153
1154 let mut ps2 = PathStorage::new();
1155 ps2.move_to(20.0, 20.0);
1156 ps2.line_to(30.0, 30.0);
1157
1158 ps.join_path(&mut ps2, 0);
1159
1160 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
1162 let (mut x, mut y) = (0.0, 0.0);
1163 ps.vertex_idx(2, &mut x, &mut y);
1164 assert!((x - 20.0).abs() < 1e-10);
1165 }
1166
1167 #[test]
1168 fn test_remove_all() {
1169 let mut ps = PathStorage::new();
1170 ps.move_to(10.0, 20.0);
1171 ps.line_to(30.0, 40.0);
1172 ps.remove_all();
1173
1174 assert_eq!(ps.total_vertices(), 0);
1175 }
1176
1177 #[test]
1178 fn test_poly_plain_adaptor() {
1179 let data = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0];
1180 let mut adaptor = PolyPlainAdaptor::new(&data, true);
1181
1182 let (mut x, mut y) = (0.0, 0.0);
1183 let cmd = adaptor.vertex(&mut x, &mut y);
1184 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1185 assert!((x - 10.0).abs() < 1e-10);
1186
1187 let cmd = adaptor.vertex(&mut x, &mut y);
1188 assert_eq!(cmd, PATH_CMD_LINE_TO);
1189 assert!((x - 30.0).abs() < 1e-10);
1190
1191 let cmd = adaptor.vertex(&mut x, &mut y);
1192 assert_eq!(cmd, PATH_CMD_LINE_TO);
1193 assert!((x - 50.0).abs() < 1e-10);
1194
1195 let cmd = adaptor.vertex(&mut x, &mut y);
1196 assert!(is_end_poly(cmd));
1197 assert!(is_close(cmd));
1198
1199 let cmd = adaptor.vertex(&mut x, &mut y);
1200 assert_eq!(cmd, PATH_CMD_STOP);
1201 }
1202
1203 #[test]
1204 fn test_poly_plain_adaptor_open() {
1205 let data = [10.0, 20.0, 30.0, 40.0];
1206 let mut adaptor = PolyPlainAdaptor::new(&data, false);
1207
1208 let (mut x, mut y) = (0.0, 0.0);
1209 adaptor.vertex(&mut x, &mut y); adaptor.vertex(&mut x, &mut y); let cmd = adaptor.vertex(&mut x, &mut y);
1213 assert_eq!(cmd, PATH_CMD_STOP); }
1215
1216 #[test]
1217 fn test_line_adaptor() {
1218 let mut la = LineAdaptor::new(10.0, 20.0, 30.0, 40.0);
1219 let (mut x, mut y) = (0.0, 0.0);
1220
1221 let cmd = la.vertex(&mut x, &mut y);
1222 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1223 assert!((x - 10.0).abs() < 1e-10);
1224 assert!((y - 20.0).abs() < 1e-10);
1225
1226 let cmd = la.vertex(&mut x, &mut y);
1227 assert_eq!(cmd, PATH_CMD_LINE_TO);
1228 assert!((x - 30.0).abs() < 1e-10);
1229 assert!((y - 40.0).abs() < 1e-10);
1230
1231 let cmd = la.vertex(&mut x, &mut y);
1232 assert_eq!(cmd, PATH_CMD_STOP);
1233 }
1234
1235 #[test]
1236 fn test_line_adaptor_rewind() {
1237 let mut la = LineAdaptor::new(10.0, 20.0, 30.0, 40.0);
1238 let (mut x, mut y) = (0.0, 0.0);
1239
1240 la.vertex(&mut x, &mut y);
1241 la.vertex(&mut x, &mut y);
1242 la.rewind(0);
1243
1244 let cmd = la.vertex(&mut x, &mut y);
1245 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1246 }
1247
1248 #[test]
1249 fn test_curve3_smooth() {
1250 let mut ps = PathStorage::new();
1251 ps.move_to(0.0, 0.0);
1252 ps.curve3(50.0, 100.0, 100.0, 0.0);
1253 ps.curve3_smooth(200.0, 0.0);
1254
1255 assert_eq!(ps.total_vertices(), 5);
1257 let (mut x, mut y) = (0.0, 0.0);
1258 ps.vertex_idx(3, &mut x, &mut y);
1259 assert!((x - 150.0).abs() < 1e-10);
1260 assert!((y - (-100.0)).abs() < 1e-10);
1261 }
1262
1263 #[test]
1264 fn test_curve4_smooth() {
1265 let mut ps = PathStorage::new();
1266 ps.move_to(0.0, 0.0);
1267 ps.curve4(25.0, 100.0, 75.0, 100.0, 100.0, 0.0);
1268 ps.curve4_smooth(175.0, 100.0, 200.0, 0.0);
1269
1270 assert_eq!(ps.total_vertices(), 7);
1272 let (mut x, mut y) = (0.0, 0.0);
1273 ps.vertex_idx(4, &mut x, &mut y);
1274 assert!((x - 125.0).abs() < 1e-10);
1275 assert!((y - (-100.0)).abs() < 1e-10);
1276 }
1277
1278 #[test]
1279 fn test_invert_polygon() {
1280 let mut ps = PathStorage::new();
1281 ps.move_to(0.0, 0.0);
1282 ps.line_to(100.0, 0.0);
1283 ps.line_to(100.0, 100.0);
1284
1285 ps.invert_polygon(0);
1286
1287 let (mut x, mut y) = (0.0, 0.0);
1289 ps.vertex_idx(0, &mut x, &mut y);
1290 assert!((x - 100.0).abs() < 1e-10);
1291 assert!((y - 100.0).abs() < 1e-10);
1292 }
1293
1294 #[test]
1295 fn test_perceive_orientation_ccw() {
1296 let mut ps = PathStorage::new();
1297 ps.move_to(0.0, 0.0);
1299 ps.line_to(100.0, 0.0);
1300 ps.line_to(100.0, 100.0);
1301
1302 let ori = ps.perceive_polygon_orientation(0, 3);
1303 assert_eq!(ori, PATH_FLAGS_CCW);
1304 }
1305
1306 #[test]
1307 fn test_perceive_orientation_cw() {
1308 let mut ps = PathStorage::new();
1309 ps.move_to(0.0, 0.0);
1311 ps.line_to(100.0, 100.0);
1312 ps.line_to(100.0, 0.0);
1313
1314 let ori = ps.perceive_polygon_orientation(0, 3);
1315 assert_eq!(ori, PATH_FLAGS_CW);
1316 }
1317
1318 #[test]
1319 fn test_arrange_polygon_orientation() {
1320 let mut ps = PathStorage::new();
1321 ps.move_to(0.0, 0.0);
1323 ps.line_to(100.0, 100.0);
1324 ps.line_to(100.0, 0.0);
1325
1326 ps.arrange_polygon_orientation(0, PATH_FLAGS_CCW);
1328
1329 let ori = ps.perceive_polygon_orientation(0, 3);
1330 assert_eq!(ori, PATH_FLAGS_CCW);
1331 }
1332
1333 #[test]
1334 fn test_concat_poly() {
1335 let mut ps = PathStorage::new();
1336 let coords = [0.0, 0.0, 100.0, 0.0, 100.0, 100.0];
1337 ps.concat_poly(&coords, true);
1338
1339 assert_eq!(ps.total_vertices(), 4); assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
1341 assert_eq!(ps.command(1), PATH_CMD_LINE_TO);
1342 assert_eq!(ps.command(2), PATH_CMD_LINE_TO);
1343 assert!(is_end_poly(ps.command(3)));
1344 }
1345
1346 #[test]
1347 fn test_transform_all_paths() {
1348 let mut ps = PathStorage::new();
1349 ps.move_to(10.0, 20.0);
1350 ps.line_to(30.0, 40.0);
1351
1352 ps.transform_all_paths(&|x, y| (x * 2.0, y * 3.0));
1353
1354 let (mut x, mut y) = (0.0, 0.0);
1355 ps.vertex_idx(0, &mut x, &mut y);
1356 assert!((x - 20.0).abs() < 1e-10);
1357 assert!((y - 60.0).abs() < 1e-10);
1358
1359 ps.vertex_idx(1, &mut x, &mut y);
1360 assert!((x - 60.0).abs() < 1e-10);
1361 assert!((y - 120.0).abs() < 1e-10);
1362 }
1363
1364 #[test]
1365 fn test_default() {
1366 let ps = PathStorage::default();
1367 assert_eq!(ps.total_vertices(), 0);
1368 }
1369
1370 #[test]
1371 fn test_move_rel_from_empty() {
1372 let mut ps = PathStorage::new();
1373 ps.move_rel(10.0, 20.0);
1375 let (mut x, mut y) = (0.0, 0.0);
1376 ps.vertex_idx(0, &mut x, &mut y);
1377 assert!((x - 10.0).abs() < 1e-10);
1378 assert!((y - 20.0).abs() < 1e-10);
1379 }
1380
1381 #[test]
1382 fn test_end_poly_only_after_vertex() {
1383 let mut ps = PathStorage::new();
1384 ps.end_poly(PATH_FLAGS_CLOSE);
1386 assert_eq!(ps.total_vertices(), 0);
1387
1388 ps.move_to(0.0, 0.0);
1389 ps.end_poly(PATH_FLAGS_CLOSE);
1390 assert_eq!(ps.total_vertices(), 2);
1391 }
1392
1393 #[test]
1394 fn test_arc_to() {
1395 let mut ps = PathStorage::new();
1396 ps.move_to(0.0, 0.0);
1397 ps.arc_to(50.0, 50.0, 0.0, false, true, 100.0, 0.0);
1399
1400 assert!(ps.total_vertices() > 2);
1401 }
1402
1403 #[test]
1404 fn test_arc_to_no_prior_vertex() {
1405 let mut ps = PathStorage::new();
1406 ps.arc_to(50.0, 50.0, 0.0, false, true, 100.0, 0.0);
1408 assert_eq!(ps.command(0), PATH_CMD_MOVE_TO);
1409 }
1410
1411 #[test]
1412 fn test_last_prev_vertex() {
1413 let mut ps = PathStorage::new();
1414 let (mut x, mut y) = (0.0, 0.0);
1415 assert_eq!(ps.last_vertex_xy(&mut x, &mut y), PATH_CMD_STOP);
1416 assert_eq!(ps.prev_vertex_xy(&mut x, &mut y), PATH_CMD_STOP);
1417
1418 ps.move_to(10.0, 20.0);
1419 ps.line_to(30.0, 40.0);
1420
1421 let cmd = ps.last_vertex_xy(&mut x, &mut y);
1422 assert_eq!(cmd, PATH_CMD_LINE_TO);
1423 assert!((x - 30.0).abs() < 1e-10);
1424
1425 let cmd = ps.prev_vertex_xy(&mut x, &mut y);
1426 assert_eq!(cmd, PATH_CMD_MOVE_TO);
1427 assert!((x - 10.0).abs() < 1e-10);
1428 }
1429
1430 #[test]
1431 fn test_vertices_accessor() {
1432 let mut ps = PathStorage::new();
1433 ps.move_to(1.0, 2.0);
1434 ps.line_to(3.0, 4.0);
1435 ps.line_to(5.0, 6.0);
1436
1437 let verts = ps.vertices();
1438 assert_eq!(verts.len(), 3);
1439 assert!((verts[0].x - 1.0).abs() < 1e-10);
1440 assert!((verts[0].y - 2.0).abs() < 1e-10);
1441 assert_eq!(verts[0].cmd, PATH_CMD_MOVE_TO);
1442 assert!((verts[1].x - 3.0).abs() < 1e-10);
1443 assert!((verts[2].x - 5.0).abs() < 1e-10);
1444 assert_eq!(verts[2].cmd, PATH_CMD_LINE_TO);
1445 }
1446}