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