1use crate::core::*;
8use crate::engine_fns::*;
9use crate::engine_public::PolyTree64;
10use std::collections::BinaryHeap;
11
12pub const NONE: usize = usize::MAX;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
24#[repr(C)]
25pub enum ClipType {
26 #[default]
27 NoClip,
28 Intersection,
29 Union,
30 Difference,
31 Xor,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37#[repr(C)]
38pub enum PathType {
39 Subject,
40 Clip,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
46#[repr(C)]
47pub enum JoinWith {
48 #[default]
49 NoJoin,
50 Left,
51 Right,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
57pub struct VertexFlags(u32);
58
59impl VertexFlags {
60 pub const EMPTY: VertexFlags = VertexFlags(0);
61 pub const OPEN_START: VertexFlags = VertexFlags(1);
62 pub const OPEN_END: VertexFlags = VertexFlags(2);
63 pub const LOCAL_MAX: VertexFlags = VertexFlags(4);
64 pub const LOCAL_MIN: VertexFlags = VertexFlags(8);
65}
66
67impl std::ops::BitAnd for VertexFlags {
68 type Output = Self;
69 fn bitand(self, rhs: Self) -> Self {
70 VertexFlags(self.0 & rhs.0)
71 }
72}
73
74impl std::ops::BitOr for VertexFlags {
75 type Output = Self;
76 fn bitor(self, rhs: Self) -> Self {
77 VertexFlags(self.0 | rhs.0)
78 }
79}
80
81impl std::ops::BitAndAssign for VertexFlags {
82 fn bitand_assign(&mut self, rhs: Self) {
83 self.0 &= rhs.0;
84 }
85}
86
87impl std::ops::BitOrAssign for VertexFlags {
88 fn bitor_assign(&mut self, rhs: Self) {
89 self.0 |= rhs.0;
90 }
91}
92
93#[derive(Debug, Clone)]
100pub struct Vertex {
101 pub pt: Point64,
102 pub next: usize, pub prev: usize, pub flags: VertexFlags,
105}
106
107impl Vertex {
108 pub fn new(pt: Point64) -> Self {
109 Self {
110 pt,
111 next: NONE,
112 prev: NONE,
113 flags: VertexFlags::EMPTY,
114 }
115 }
116}
117
118#[derive(Debug, Clone)]
121pub struct OutPt {
122 pub pt: Point64,
123 pub next: usize, pub prev: usize, pub outrec: usize, pub horz: Option<usize>, }
128
129impl OutPt {
130 pub fn new(pt: Point64, outrec_idx: usize) -> Self {
131 Self {
132 pt,
133 next: NONE,
134 prev: NONE,
135 outrec: outrec_idx,
136 horz: None,
137 }
138 }
139}
140
141#[derive(Debug, Clone)]
144pub struct OutRec {
145 pub idx: usize,
146 pub owner: Option<usize>, pub front_edge: Option<usize>, pub back_edge: Option<usize>, pub pts: Option<usize>, pub polypath: Option<usize>, pub splits: Option<Vec<usize>>, pub recursive_split: Option<usize>, pub bounds: Rect64,
154 pub path: Path64,
155 pub is_open: bool,
156}
157
158impl OutRec {
159 pub fn new(idx: usize) -> Self {
160 Self {
161 idx,
162 owner: None,
163 front_edge: None,
164 back_edge: None,
165 pts: None,
166 polypath: None,
167 splits: None,
168 recursive_split: None,
169 bounds: Rect64::new(0, 0, 0, 0),
170 path: Path64::new(),
171 is_open: false,
172 }
173 }
174}
175
176#[derive(Debug, Clone)]
179pub struct Active {
180 pub bot: Point64,
181 pub top: Point64,
182 pub curr_x: i64,
183 pub dx: f64,
184 pub wind_dx: i32, pub wind_cnt: i32,
186 pub wind_cnt2: i32, pub outrec: Option<usize>, pub prev_in_ael: Option<usize>, pub next_in_ael: Option<usize>, pub prev_in_sel: Option<usize>, pub next_in_sel: Option<usize>, pub jump: Option<usize>, pub vertex_top: usize, pub local_min: usize, pub is_left_bound: bool,
198 pub join_with: JoinWith,
199}
200
201impl Active {
202 pub fn new() -> Self {
203 Self {
204 bot: Point64::new(0, 0),
205 top: Point64::new(0, 0),
206 curr_x: 0,
207 dx: 0.0,
208 wind_dx: 1,
209 wind_cnt: 0,
210 wind_cnt2: 0,
211 outrec: None,
212 prev_in_ael: None,
213 next_in_ael: None,
214 prev_in_sel: None,
215 next_in_sel: None,
216 jump: None,
217 vertex_top: NONE,
218 local_min: NONE,
219 is_left_bound: false,
220 join_with: JoinWith::NoJoin,
221 }
222 }
223}
224
225impl Default for Active {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231#[derive(Debug, Clone)]
234pub struct LocalMinima {
235 pub vertex: usize, pub polytype: PathType,
237 pub is_open: bool,
238}
239
240impl LocalMinima {
241 pub fn new(vertex: usize, polytype: PathType, is_open: bool) -> Self {
242 Self {
243 vertex,
244 polytype,
245 is_open,
246 }
247 }
248}
249
250#[derive(Debug, Clone)]
253pub struct IntersectNode {
254 pub pt: Point64,
255 pub edge1: usize, pub edge2: usize, }
258
259impl IntersectNode {
260 pub fn new() -> Self {
261 Self {
262 pt: Point64::new(0, 0),
263 edge1: NONE,
264 edge2: NONE,
265 }
266 }
267
268 pub fn with_edges(edge1: usize, edge2: usize, pt: Point64) -> Self {
269 Self { pt, edge1, edge2 }
270 }
271}
272
273impl Default for IntersectNode {
274 fn default() -> Self {
275 Self::new()
276 }
277}
278
279#[derive(Debug, Clone)]
282pub struct HorzSegment {
283 pub left_op: Option<usize>, pub right_op: Option<usize>, pub left_to_right: bool,
286}
287
288impl HorzSegment {
289 pub fn new() -> Self {
290 Self {
291 left_op: None,
292 right_op: None,
293 left_to_right: true,
294 }
295 }
296
297 pub fn with_op(op_idx: usize) -> Self {
298 Self {
299 left_op: Some(op_idx),
300 right_op: None,
301 left_to_right: true,
302 }
303 }
304}
305
306impl Default for HorzSegment {
307 fn default() -> Self {
308 Self::new()
309 }
310}
311
312#[derive(Debug, Clone)]
315pub struct HorzJoin {
316 pub op1: Option<usize>, pub op2: Option<usize>, }
319
320impl HorzJoin {
321 pub fn new() -> Self {
322 Self {
323 op1: None,
324 op2: None,
325 }
326 }
327
328 pub fn with_ops(ltr: usize, rtl: usize) -> Self {
329 Self {
330 op1: Some(ltr),
331 op2: Some(rtl),
332 }
333 }
334}
335
336impl Default for HorzJoin {
337 fn default() -> Self {
338 Self::new()
339 }
340}
341
342pub struct ClipperBase {
350 pub cliptype: ClipType,
352 pub fillrule: FillRule,
353 pub preserve_collinear: bool,
354 pub reverse_solution: bool,
355 pub error_code: i32,
356 pub has_open_paths: bool,
357 pub succeeded: bool,
358 using_polytree: bool,
359
360 bot_y: i64,
362 minima_list_sorted: bool,
363
364 pub vertex_arena: Vec<Vertex>,
366 pub active_arena: Vec<Active>,
367 pub outpt_arena: Vec<OutPt>,
368
369 pub outrec_list: Vec<OutRec>,
371 pub minima_list: Vec<LocalMinima>,
372 current_locmin_idx: usize,
373 vertex_lists: Vec<Vec<usize>>, pub actives: Option<usize>, pub sel: Option<usize>, scanline_list: BinaryHeap<i64>,
381
382 pub intersect_nodes: Vec<IntersectNode>,
384 pub horz_seg_list: Vec<HorzSegment>,
385 pub horz_join_list: Vec<HorzJoin>,
386}
387
388impl ClipperBase {
389 pub fn new() -> Self {
390 Self {
391 cliptype: ClipType::NoClip,
392 fillrule: FillRule::EvenOdd,
393 preserve_collinear: true,
394 reverse_solution: false,
395 error_code: 0,
396 has_open_paths: false,
397 succeeded: true,
398 using_polytree: false,
399 bot_y: 0,
400 minima_list_sorted: false,
401 vertex_arena: Vec::new(),
402 active_arena: Vec::new(),
403 outpt_arena: Vec::new(),
404 outrec_list: Vec::new(),
405 minima_list: Vec::new(),
406 current_locmin_idx: 0,
407 vertex_lists: Vec::new(),
408 actives: None,
409 sel: None,
410 scanline_list: BinaryHeap::new(),
411 intersect_nodes: Vec::new(),
412 horz_seg_list: Vec::new(),
413 horz_join_list: Vec::new(),
414 }
415 }
416
417 pub fn clear(&mut self) {
420 self.vertex_arena.clear();
421 self.active_arena.clear();
422 self.outpt_arena.clear();
423 self.outrec_list.clear();
424 self.minima_list.clear();
425 self.current_locmin_idx = 0;
426 self.vertex_lists.clear();
427 self.actives = None;
428 self.sel = None;
429 self.scanline_list.clear();
430 self.intersect_nodes.clear();
431 self.horz_seg_list.clear();
432 self.horz_join_list.clear();
433 self.minima_list_sorted = false;
434 self.has_open_paths = false;
435 self.succeeded = true;
436 }
437
438 #[inline]
441 pub fn insert_scanline(&mut self, y: i64) {
442 self.scanline_list.push(y);
443 }
444
445 #[inline]
448 pub fn pop_scanline(&mut self) -> Option<i64> {
449 if self.scanline_list.is_empty() {
450 return None;
451 }
452 let y = self.scanline_list.pop().unwrap();
453 while !self.scanline_list.is_empty() && *self.scanline_list.peek().unwrap() == y {
455 self.scanline_list.pop();
456 }
457 Some(y)
458 }
459
460 #[inline]
463 pub fn pop_local_minima(&mut self, y: i64) -> Option<usize> {
464 if self.current_locmin_idx < self.minima_list.len() {
465 let vertex_idx = self.minima_list[self.current_locmin_idx].vertex;
466 if self.vertex_arena[vertex_idx].pt.y == y {
467 let idx = self.current_locmin_idx;
468 self.current_locmin_idx += 1;
469 return Some(idx);
470 }
471 }
472 None
473 }
474
475 pub fn new_out_rec(&mut self) -> usize {
478 let idx = self.outrec_list.len();
479 self.outrec_list.push(OutRec::new(idx));
480 idx
481 }
482
483 pub fn new_out_pt(&mut self, pt: Point64, outrec_idx: usize) -> usize {
485 let idx = self.outpt_arena.len();
486 let mut op = OutPt::new(pt, outrec_idx);
487 op.next = idx;
488 op.prev = idx;
489 self.outpt_arena.push(op);
490 idx
491 }
492
493 pub fn new_active(&mut self) -> usize {
495 let idx = self.active_arena.len();
496 self.active_arena.push(Active::new());
497 idx
498 }
499
500 pub fn add_loc_min(&mut self, vert_idx: usize, polytype: PathType, is_open: bool) {
503 self.vertex_arena[vert_idx].flags |= VertexFlags::LOCAL_MIN;
505 self.minima_list
506 .push(LocalMinima::new(vert_idx, polytype, is_open));
507 }
508
509 pub fn add_path(&mut self, path: &Path64, polytype: PathType, is_open: bool) {
512 let mut path = path.clone();
513
514 let cnt = path.len();
516 if cnt < 2 || (!is_open && cnt < 3) {
517 return;
518 }
519
520 strip_duplicates_path(&mut path, !is_open);
522
523 if path.len() < 2 || (!is_open && path.len() < 3) {
524 return;
525 }
526
527 if is_open {
528 self.has_open_paths = true;
529 }
530
531 let first_vert_idx = self.vertex_arena.len();
533 let vert_count = path.len();
534
535 for pt in &path {
536 self.vertex_arena.push(Vertex::new(*pt));
537 }
538
539 for i in 0..vert_count {
541 let abs_idx = first_vert_idx + i;
542 self.vertex_arena[abs_idx].next = first_vert_idx + (i + 1) % vert_count;
543 self.vertex_arena[abs_idx].prev = first_vert_idx + (i + vert_count - 1) % vert_count;
544 }
545
546 let vert_indices: Vec<usize> = (first_vert_idx..first_vert_idx + vert_count).collect();
548 self.vertex_lists.push(vert_indices);
549
550 if is_open {
551 self.vertex_arena[first_vert_idx].flags |= VertexFlags::OPEN_START;
553 self.vertex_arena[first_vert_idx + vert_count - 1].flags |= VertexFlags::OPEN_END;
554
555 let mut i = first_vert_idx;
557 let last = first_vert_idx + vert_count - 1;
558
559 while i < last && self.vertex_arena[i].pt.y <= self.vertex_arena[i + 1].pt.y {
561 i += 1;
562 }
563 self.find_and_add_local_minima_open(first_vert_idx, vert_count, polytype);
567 } else {
568 self.find_and_add_local_minima_closed(first_vert_idx, vert_count, polytype);
569 }
570 }
571
572 fn find_and_add_local_minima_closed(
574 &mut self,
575 first_vert_idx: usize,
576 vert_count: usize,
577 polytype: PathType,
578 ) {
579 let mut start = first_vert_idx;
586 let end = first_vert_idx + vert_count;
587
588 let mut found_start = false;
590 for i in first_vert_idx..end {
591 let prev = self.vertex_arena[i].prev;
592 if self.vertex_arena[prev].pt.y != self.vertex_arena[i].pt.y {
593 start = i;
594 found_start = true;
595 break;
596 }
597 }
598 if !found_start {
599 return; }
601
602 let prev = self.vertex_arena[start].prev;
604 let mut going_up = self.vertex_arena[prev].pt.y > self.vertex_arena[start].pt.y;
605
606 let mut curr = start;
607 loop {
608 let next = self.vertex_arena[curr].next;
609 let curr_pt = self.vertex_arena[curr].pt;
610 let next_pt = self.vertex_arena[next].pt;
611
612 if next_pt.y > curr_pt.y && going_up {
613 self.vertex_arena[curr].flags |= VertexFlags::LOCAL_MAX;
615 going_up = false;
616 } else if next_pt.y < curr_pt.y && !going_up {
617 going_up = true;
619 self.add_loc_min(curr, polytype, false);
620 }
621
622 if next_pt.y == curr_pt.y && next != start {
624 curr = next;
625 continue;
626 }
627
628 curr = next;
629 if curr == start {
630 break;
631 }
632 }
633 }
634
635 fn find_and_add_local_minima_open(
637 &mut self,
638 first_vert_idx: usize,
639 vert_count: usize,
640 polytype: PathType,
641 ) {
642 let last_vert_idx = first_vert_idx + vert_count - 1;
643
644 let first_pt = self.vertex_arena[first_vert_idx].pt;
646 let second_pt = self.vertex_arena[first_vert_idx + 1].pt;
647
648 let mut going_up;
651 if first_pt.y > second_pt.y {
652 self.add_loc_min(first_vert_idx, polytype, true);
654 going_up = true;
655 } else if first_pt.y < second_pt.y {
656 self.vertex_arena[first_vert_idx].flags |= VertexFlags::LOCAL_MAX;
658 going_up = false;
659 } else {
660 let mut i = first_vert_idx + 1;
662 while i < last_vert_idx && self.vertex_arena[i].pt.y == first_pt.y {
663 i += 1;
664 }
665 if i >= last_vert_idx {
666 return; }
668 going_up = self.vertex_arena[i].pt.y < first_pt.y;
669 if going_up {
670 self.add_loc_min(first_vert_idx, polytype, true);
671 } else {
672 self.vertex_arena[first_vert_idx].flags |= VertexFlags::LOCAL_MAX;
673 }
674 }
675
676 for i in (first_vert_idx + 1)..last_vert_idx {
678 let curr_pt = self.vertex_arena[i].pt;
679 let next_pt = self.vertex_arena[i + 1].pt;
680
681 if next_pt.y > curr_pt.y && going_up {
682 self.vertex_arena[i].flags |= VertexFlags::LOCAL_MAX;
683 going_up = false;
684 } else if next_pt.y < curr_pt.y && !going_up {
685 going_up = true;
686 self.add_loc_min(i, polytype, true);
687 }
688 }
689
690 let last_pt = self.vertex_arena[last_vert_idx].pt;
692 let prev_pt = self.vertex_arena[last_vert_idx - 1].pt;
693 if !going_up {
694 self.add_loc_min(last_vert_idx, polytype, true);
696 } else if last_pt.y < prev_pt.y || (last_pt.y == prev_pt.y && going_up) {
697 self.vertex_arena[last_vert_idx].flags |= VertexFlags::LOCAL_MAX;
698 }
699 }
700
701 pub fn add_paths(&mut self, paths: &Paths64, polytype: PathType, is_open: bool) {
704 for path in paths {
705 self.add_path(path, polytype, is_open);
706 }
707 }
708
709 pub fn sort_minima_list(&mut self) {
711 if !self.minima_list_sorted {
712 let vertex_arena = &self.vertex_arena;
714 self.minima_list.sort_by(|a, b| {
715 let a_pt = vertex_arena[a.vertex].pt;
716 let b_pt = vertex_arena[b.vertex].pt;
717 if a_pt.y != b_pt.y {
718 b_pt.y.cmp(&a_pt.y) } else {
720 a_pt.x.cmp(&b_pt.x) }
722 });
723 self.minima_list_sorted = true;
724 }
725 }
726
727 pub fn duplicate_op(&mut self, op_idx: usize, insert_after: bool) -> usize {
730 let pt = self.outpt_arena[op_idx].pt;
731 let outrec = self.outpt_arena[op_idx].outrec;
732 let new_idx = self.outpt_arena.len();
733 let mut result = OutPt::new(pt, outrec);
734
735 if insert_after {
736 let next = self.outpt_arena[op_idx].next;
737 result.next = next;
738 result.prev = op_idx;
739 self.outpt_arena.push(result);
740 self.outpt_arena[next].prev = new_idx;
741 self.outpt_arena[op_idx].next = new_idx;
742 } else {
743 let prev = self.outpt_arena[op_idx].prev;
744 result.prev = prev;
745 result.next = op_idx;
746 self.outpt_arena.push(result);
747 self.outpt_arena[prev].next = new_idx;
748 self.outpt_arena[op_idx].prev = new_idx;
749 }
750
751 new_idx
752 }
753
754 pub fn dispose_out_pt(&mut self, op_idx: usize) -> usize {
757 let result = self.outpt_arena[op_idx].next;
758 let prev = self.outpt_arena[op_idx].prev;
759 self.outpt_arena[prev].next = result;
760 self.outpt_arena[result].prev = prev;
761 result
763 }
764
765 pub fn dispose_out_pts(&mut self, outrec_idx: usize) {
768 if let Some(pts_idx) = self.outrec_list[outrec_idx].pts {
769 let prev = self.outpt_arena[pts_idx].prev;
771 self.outpt_arena[prev].next = NONE; let mut op = Some(pts_idx);
774 while let Some(idx) = op {
775 if self.outpt_arena[idx].next == NONE {
776 break;
777 }
778 let next = self.outpt_arena[idx].next;
779 if next == NONE || next == idx {
780 break;
781 }
782 op = Some(next);
783 }
784 }
785 self.outrec_list[outrec_idx].pts = None;
786 }
787
788 #[inline]
791 pub fn set_sides(&mut self, outrec_idx: usize, start_edge: usize, end_edge: usize) {
792 self.outrec_list[outrec_idx].front_edge = Some(start_edge);
793 self.outrec_list[outrec_idx].back_edge = Some(end_edge);
794 }
795
796 pub fn swap_outrecs(&mut self, e1_idx: usize, e2_idx: usize) {
799 let or1 = self.active_arena[e1_idx].outrec;
800 let or2 = self.active_arena[e2_idx].outrec;
801
802 if or1 == or2 {
803 if let Some(or_idx) = or1 {
804 let fe = self.outrec_list[or_idx].front_edge;
805 let be = self.outrec_list[or_idx].back_edge;
806 self.outrec_list[or_idx].front_edge = be;
807 self.outrec_list[or_idx].back_edge = fe;
808 }
809 return;
810 }
811
812 if let Some(or1_idx) = or1 {
813 if self.outrec_list[or1_idx].front_edge == Some(e1_idx) {
814 self.outrec_list[or1_idx].front_edge = Some(e2_idx);
815 } else {
816 self.outrec_list[or1_idx].back_edge = Some(e2_idx);
817 }
818 }
819
820 if let Some(or2_idx) = or2 {
821 if self.outrec_list[or2_idx].front_edge == Some(e2_idx) {
822 self.outrec_list[or2_idx].front_edge = Some(e1_idx);
823 } else {
824 self.outrec_list[or2_idx].back_edge = Some(e1_idx);
825 }
826 }
827
828 self.active_arena[e1_idx].outrec = or2;
829 self.active_arena[e2_idx].outrec = or1;
830 }
831
832 #[inline]
835 pub fn is_front(&self, e_idx: usize) -> bool {
836 if let Some(or_idx) = self.active_arena[e_idx].outrec {
837 self.outrec_list[or_idx].front_edge == Some(e_idx)
838 } else {
839 false
840 }
841 }
842
843 pub fn get_prev_hot_edge(&self, e_idx: usize) -> Option<usize> {
846 let mut prev = self.active_arena[e_idx].prev_in_ael;
847 while let Some(p_idx) = prev {
848 if is_open_active(&self.active_arena[p_idx], &self.minima_list)
849 || !is_hot_edge(&self.active_arena[p_idx])
850 {
851 prev = self.active_arena[p_idx].prev_in_ael;
852 } else {
853 return Some(p_idx);
854 }
855 }
856 None
857 }
858
859 #[inline]
862 pub fn add_trial_horz_join(&mut self, op_idx: usize) {
863 let or_idx = self.outpt_arena[op_idx].outrec;
867 if self.outrec_list[or_idx].is_open {
868 return;
869 }
870 self.horz_seg_list.push(HorzSegment::with_op(op_idx));
871 }
872
873 #[inline]
876 pub fn push_horz(&mut self, e_idx: usize) {
877 self.active_arena[e_idx].next_in_sel = self.sel;
878 self.sel = Some(e_idx);
879 }
880
881 #[inline]
884 pub fn pop_horz(&mut self) -> Option<usize> {
885 let e = self.sel;
886 if let Some(e_idx) = e {
887 self.sel = self.active_arena[e_idx].next_in_sel;
888 }
889 e
890 }
891
892 pub fn build_path64(&self, outrec: &OutRec) -> Option<Path64> {
895 let op_start = outrec.pts?;
896 let cnt = point_count(op_start, &self.outpt_arena);
897 if cnt < 2 {
898 return None;
899 }
900
901 let reverse = if outrec.is_open {
902 false
903 } else {
904 let area = area_outpt(op_start, &self.outpt_arena);
905 if area == 0.0 {
906 return None;
907 }
908 (area < 0.0) != self.reverse_solution
909 };
910
911 let mut result = Path64::with_capacity(cnt as usize);
912 if reverse {
913 let mut op = op_start;
914 loop {
915 result.push(self.outpt_arena[op].pt);
916 op = self.outpt_arena[op].prev;
917 if op == op_start {
918 break;
919 }
920 }
921 } else {
922 let op_next = self.outpt_arena[op_start].next;
923 let mut op = op_next;
924 loop {
925 result.push(self.outpt_arena[op].pt);
926 op = self.outpt_arena[op].next;
927 if op == op_next {
928 break;
929 }
930 }
931 }
932
933 if !self.preserve_collinear {
935 let mut i = 0;
937 while i < result.len() && result.len() > 2 {
938 let prev = if i == 0 { result.len() - 1 } else { i - 1 };
939 let next = (i + 1) % result.len();
940 if is_collinear(result[prev], result[i], result[next]) {
941 result.remove(i);
942 i = i.saturating_sub(1);
943 } else {
944 i += 1;
945 }
946 }
947 }
948
949 if result.len() < 2 {
950 None
951 } else {
952 Some(result)
953 }
954 }
955}
956
957impl Default for ClipperBase {
958 fn default() -> Self {
959 Self::new()
960 }
961}
962
963impl ClipperBase {
969 #[inline]
973 fn is_open_idx(&self, e_idx: usize) -> bool {
974 self.minima_list[self.active_arena[e_idx].local_min].is_open
975 }
976
977 #[inline]
979 fn is_maxima_idx(&self, e_idx: usize) -> bool {
980 is_maxima_vertex(&self.vertex_arena[self.active_arena[e_idx].vertex_top])
981 }
982
983 #[inline]
985 fn is_horizontal_idx(&self, e_idx: usize) -> bool {
986 self.active_arena[e_idx].top.y == self.active_arena[e_idx].bot.y
987 }
988
989 #[inline]
991 fn is_open_end_idx(&self, e_idx: usize) -> bool {
992 is_open_end_vertex(&self.vertex_arena[self.active_arena[e_idx].vertex_top])
993 }
994
995 #[inline]
997 fn get_poly_type_idx(&self, e_idx: usize) -> PathType {
998 self.minima_list[self.active_arena[e_idx].local_min].polytype
999 }
1000
1001 #[inline]
1003 fn is_same_poly_type_idx(&self, e1: usize, e2: usize) -> bool {
1004 self.minima_list[self.active_arena[e1].local_min].polytype
1005 == self.minima_list[self.active_arena[e2].local_min].polytype
1006 }
1007
1008 #[inline]
1010 fn next_vertex_idx(&self, e_idx: usize) -> usize {
1011 if self.active_arena[e_idx].wind_dx > 0 {
1012 self.vertex_arena[self.active_arena[e_idx].vertex_top].next
1013 } else {
1014 self.vertex_arena[self.active_arena[e_idx].vertex_top].prev
1015 }
1016 }
1017
1018 pub fn reset(&mut self) {
1023 self.sort_minima_list();
1024 for i in (0..self.minima_list.len()).rev() {
1026 let y = self.vertex_arena[self.minima_list[i].vertex].pt.y;
1027 self.insert_scanline(y);
1028 }
1029 self.current_locmin_idx = 0;
1030 self.actives = None;
1031 self.sel = None;
1032 self.succeeded = true;
1033 }
1034
1035 pub fn clean_up(&mut self) {
1037 self.active_arena.clear();
1039 self.scanline_list.clear();
1040 self.intersect_nodes.clear();
1041 for i in 0..self.outrec_list.len() {
1043 self.outrec_list[i].pts = None;
1044 }
1045 self.outpt_arena.clear();
1046 self.outrec_list.clear();
1047 self.horz_seg_list.clear();
1048 self.horz_join_list.clear();
1049 self.actives = None;
1050 self.sel = None;
1051 }
1052
1053 fn is_contributing_closed(&self, e_idx: usize) -> bool {
1058 let e = &self.active_arena[e_idx];
1059 match self.fillrule {
1060 FillRule::EvenOdd => {}
1061 FillRule::NonZero => {
1062 if e.wind_cnt.abs() != 1 {
1063 return false;
1064 }
1065 }
1066 FillRule::Positive => {
1067 if e.wind_cnt != 1 {
1068 return false;
1069 }
1070 }
1071 FillRule::Negative => {
1072 if e.wind_cnt != -1 {
1073 return false;
1074 }
1075 }
1076 }
1077
1078 match self.cliptype {
1079 ClipType::NoClip => false,
1080 ClipType::Intersection => match self.fillrule {
1081 FillRule::Positive => e.wind_cnt2 > 0,
1082 FillRule::Negative => e.wind_cnt2 < 0,
1083 _ => e.wind_cnt2 != 0,
1084 },
1085 ClipType::Union => match self.fillrule {
1086 FillRule::Positive => e.wind_cnt2 <= 0,
1087 FillRule::Negative => e.wind_cnt2 >= 0,
1088 _ => e.wind_cnt2 == 0,
1089 },
1090 ClipType::Difference => {
1091 let result = match self.fillrule {
1092 FillRule::Positive => e.wind_cnt2 <= 0,
1093 FillRule::Negative => e.wind_cnt2 >= 0,
1094 _ => e.wind_cnt2 == 0,
1095 };
1096 if self.get_poly_type_idx(e_idx) == PathType::Subject {
1097 result
1098 } else {
1099 !result
1100 }
1101 }
1102 ClipType::Xor => true,
1103 }
1104 }
1105
1106 fn is_contributing_open(&self, e_idx: usize) -> bool {
1109 let e = &self.active_arena[e_idx];
1110 let (is_in_clip, is_in_subj) = match self.fillrule {
1111 FillRule::Positive => (e.wind_cnt2 > 0, e.wind_cnt > 0),
1112 FillRule::Negative => (e.wind_cnt2 < 0, e.wind_cnt < 0),
1113 _ => (e.wind_cnt2 != 0, e.wind_cnt != 0),
1114 };
1115
1116 match self.cliptype {
1117 ClipType::Intersection => is_in_clip,
1118 ClipType::Union => !is_in_subj && !is_in_clip,
1119 _ => !is_in_clip,
1120 }
1121 }
1122
1123 fn set_wind_count_for_closed_path_edge(&mut self, e_idx: usize) {
1126 let pt = self.get_poly_type_idx(e_idx);
1127 let e_wind_dx = self.active_arena[e_idx].wind_dx;
1128
1129 let mut e2_opt = self.active_arena[e_idx].prev_in_ael;
1131 while let Some(e2_idx) = e2_opt {
1132 if self.get_poly_type_idx(e2_idx) == pt && !self.is_open_idx(e2_idx) {
1133 break;
1134 }
1135 e2_opt = self.active_arena[e2_idx].prev_in_ael;
1136 }
1137
1138 let e2_start; if let Some(e2_idx) = e2_opt {
1140 if self.fillrule == FillRule::EvenOdd {
1141 self.active_arena[e_idx].wind_cnt = e_wind_dx;
1142 self.active_arena[e_idx].wind_cnt2 = self.active_arena[e2_idx].wind_cnt2;
1143 e2_start = self.active_arena[e2_idx].next_in_ael;
1144 } else {
1145 let e2_wind_cnt = self.active_arena[e2_idx].wind_cnt;
1146 let e2_wind_dx = self.active_arena[e2_idx].wind_dx;
1147 if e2_wind_cnt * e2_wind_dx < 0 {
1149 if e2_wind_cnt.abs() > 1 {
1151 if e2_wind_dx * e_wind_dx < 0 {
1152 self.active_arena[e_idx].wind_cnt = e2_wind_cnt;
1153 } else {
1154 self.active_arena[e_idx].wind_cnt = e2_wind_cnt + e_wind_dx;
1155 }
1156 } else {
1157 self.active_arena[e_idx].wind_cnt = if self.is_open_idx(e_idx) {
1158 1
1159 } else {
1160 e_wind_dx
1161 };
1162 }
1163 } else {
1164 if e2_wind_dx * e_wind_dx < 0 {
1166 self.active_arena[e_idx].wind_cnt = e2_wind_cnt;
1167 } else {
1168 self.active_arena[e_idx].wind_cnt = e2_wind_cnt + e_wind_dx;
1169 }
1170 }
1171 self.active_arena[e_idx].wind_cnt2 = self.active_arena[e2_idx].wind_cnt2;
1172 e2_start = self.active_arena[e2_idx].next_in_ael;
1173 }
1174 } else {
1175 self.active_arena[e_idx].wind_cnt = e_wind_dx;
1176 e2_start = self.actives;
1177 }
1178
1179 let mut e2_cur = e2_start;
1181 if self.fillrule == FillRule::EvenOdd {
1182 while e2_cur != Some(e_idx) {
1183 if let Some(e2i) = e2_cur {
1184 if self.get_poly_type_idx(e2i) != pt && !self.is_open_idx(e2i) {
1185 let wc2 = self.active_arena[e_idx].wind_cnt2;
1186 self.active_arena[e_idx].wind_cnt2 = if wc2 == 0 { 1 } else { 0 };
1187 }
1188 e2_cur = self.active_arena[e2i].next_in_ael;
1189 } else {
1190 break;
1191 }
1192 }
1193 } else {
1194 while e2_cur != Some(e_idx) {
1195 if let Some(e2i) = e2_cur {
1196 if self.get_poly_type_idx(e2i) != pt && !self.is_open_idx(e2i) {
1197 let e2_wd = self.active_arena[e2i].wind_dx;
1198 self.active_arena[e_idx].wind_cnt2 += e2_wd;
1199 }
1200 e2_cur = self.active_arena[e2i].next_in_ael;
1201 } else {
1202 break;
1203 }
1204 }
1205 }
1206 }
1207
1208 fn set_wind_count_for_open_path_edge(&mut self, e_idx: usize) {
1211 let mut e2_opt = self.actives;
1212 if self.fillrule == FillRule::EvenOdd {
1213 let mut cnt1 = 0i32;
1214 let mut cnt2 = 0i32;
1215 while e2_opt != Some(e_idx) {
1216 if let Some(e2i) = e2_opt {
1217 if self.get_poly_type_idx(e2i) == PathType::Clip {
1218 cnt2 += 1;
1219 } else if !self.is_open_idx(e2i) {
1220 cnt1 += 1;
1221 }
1222 e2_opt = self.active_arena[e2i].next_in_ael;
1223 } else {
1224 break;
1225 }
1226 }
1227 self.active_arena[e_idx].wind_cnt = if is_odd(cnt1) { 1 } else { 0 };
1228 self.active_arena[e_idx].wind_cnt2 = if is_odd(cnt2) { 1 } else { 0 };
1229 } else {
1230 while e2_opt != Some(e_idx) {
1231 if let Some(e2i) = e2_opt {
1232 if self.get_poly_type_idx(e2i) == PathType::Clip {
1233 self.active_arena[e_idx].wind_cnt2 += self.active_arena[e2i].wind_dx;
1234 } else if !self.is_open_idx(e2i) {
1235 self.active_arena[e_idx].wind_cnt += self.active_arena[e2i].wind_dx;
1236 }
1237 e2_opt = self.active_arena[e2i].next_in_ael;
1238 } else {
1239 break;
1240 }
1241 }
1242 }
1243 }
1244
1245 fn insert_left_edge(&mut self, e_idx: usize) {
1250 if self.actives.is_none() {
1251 self.active_arena[e_idx].prev_in_ael = None;
1252 self.active_arena[e_idx].next_in_ael = None;
1253 self.actives = Some(e_idx);
1254 } else {
1255 let actives_idx = self.actives.unwrap();
1256 if !is_valid_ael_order(
1257 &self.active_arena[actives_idx],
1258 &self.active_arena[e_idx],
1259 &self.vertex_arena,
1260 &self.minima_list,
1261 ) {
1262 self.active_arena[e_idx].prev_in_ael = None;
1263 self.active_arena[e_idx].next_in_ael = self.actives;
1264 self.active_arena[actives_idx].prev_in_ael = Some(e_idx);
1265 self.actives = Some(e_idx);
1266 } else {
1267 let mut e2 = actives_idx;
1268 while let Some(next) = self.active_arena[e2].next_in_ael {
1269 if !is_valid_ael_order(
1270 &self.active_arena[next],
1271 &self.active_arena[e_idx],
1272 &self.vertex_arena,
1273 &self.minima_list,
1274 ) {
1275 break;
1276 }
1277 e2 = next;
1278 }
1279 if self.active_arena[e2].join_with == JoinWith::Right {
1280 if let Some(next) = self.active_arena[e2].next_in_ael {
1281 e2 = next;
1282 } else {
1283 return;
1284 }
1285 }
1286 let next = self.active_arena[e2].next_in_ael;
1287 self.active_arena[e_idx].next_in_ael = next;
1288 if let Some(next_idx) = next {
1289 self.active_arena[next_idx].prev_in_ael = Some(e_idx);
1290 }
1291 self.active_arena[e_idx].prev_in_ael = Some(e2);
1292 self.active_arena[e2].next_in_ael = Some(e_idx);
1293 }
1294 }
1295 }
1296
1297 fn insert_right_edge(&mut self, e_idx: usize, e2_idx: usize) {
1300 let next = self.active_arena[e_idx].next_in_ael;
1301 self.active_arena[e2_idx].next_in_ael = next;
1302 if let Some(next_idx) = next {
1303 self.active_arena[next_idx].prev_in_ael = Some(e2_idx);
1304 }
1305 self.active_arena[e2_idx].prev_in_ael = Some(e_idx);
1306 self.active_arena[e_idx].next_in_ael = Some(e2_idx);
1307 }
1308
1309 fn add_out_pt(&mut self, e_idx: usize, pt: Point64) -> usize {
1314 let or_idx = self.active_arena[e_idx].outrec.unwrap();
1315 let to_front = self.is_front(e_idx);
1316 let op_front = self.outrec_list[or_idx].pts.unwrap();
1317 let op_back = self.outpt_arena[op_front].next;
1318
1319 if to_front {
1320 if pt == self.outpt_arena[op_front].pt {
1321 return op_front;
1322 }
1323 } else if pt == self.outpt_arena[op_back].pt {
1324 return op_back;
1325 }
1326
1327 let new_idx = self.outpt_arena.len();
1328 let mut new_op = OutPt::new(pt, or_idx);
1329 new_op.prev = op_front;
1330 new_op.next = op_back;
1331 self.outpt_arena.push(new_op);
1332 self.outpt_arena[op_back].prev = new_idx;
1333 self.outpt_arena[op_front].next = new_idx;
1334
1335 if to_front {
1336 self.outrec_list[or_idx].pts = Some(new_idx);
1337 }
1338 new_idx
1339 }
1340
1341 fn start_open_path(&mut self, e_idx: usize, pt: Point64) -> usize {
1344 let outrec_idx = self.new_out_rec();
1345 self.outrec_list[outrec_idx].is_open = true;
1346
1347 if self.active_arena[e_idx].wind_dx > 0 {
1348 self.outrec_list[outrec_idx].front_edge = Some(e_idx);
1349 self.outrec_list[outrec_idx].back_edge = None;
1350 } else {
1351 self.outrec_list[outrec_idx].front_edge = None;
1352 self.outrec_list[outrec_idx].back_edge = Some(e_idx);
1353 }
1354
1355 self.active_arena[e_idx].outrec = Some(outrec_idx);
1356
1357 let op_idx = self.new_out_pt(pt, outrec_idx);
1358 self.outrec_list[outrec_idx].pts = Some(op_idx);
1359 op_idx
1360 }
1361
1362 fn add_local_min_poly(
1365 &mut self,
1366 e1_idx: usize,
1367 e2_idx: usize,
1368 pt: Point64,
1369 is_new: bool,
1370 ) -> usize {
1371 let outrec_idx = self.new_out_rec();
1372 self.active_arena[e1_idx].outrec = Some(outrec_idx);
1373 self.active_arena[e2_idx].outrec = Some(outrec_idx);
1374
1375 if self.is_open_idx(e1_idx) {
1376 self.outrec_list[outrec_idx].owner = None;
1377 self.outrec_list[outrec_idx].is_open = true;
1378 if self.active_arena[e1_idx].wind_dx > 0 {
1379 self.set_sides(outrec_idx, e1_idx, e2_idx);
1380 } else {
1381 self.set_sides(outrec_idx, e2_idx, e1_idx);
1382 }
1383 } else {
1384 let prev_hot = self.get_prev_hot_edge(e1_idx);
1385 if let Some(prev_hot_idx) = prev_hot {
1386 if self.using_polytree {
1387 if let Some(prev_or) = self.active_arena[prev_hot_idx].outrec {
1388 set_owner(&mut self.outrec_list, outrec_idx, prev_or);
1389 }
1390 }
1391 if outrec_is_ascending(prev_hot_idx, &self.outrec_list, &self.active_arena)
1392 == is_new
1393 {
1394 self.set_sides(outrec_idx, e2_idx, e1_idx);
1395 } else {
1396 self.set_sides(outrec_idx, e1_idx, e2_idx);
1397 }
1398 } else {
1399 self.outrec_list[outrec_idx].owner = None;
1400 if is_new {
1401 self.set_sides(outrec_idx, e1_idx, e2_idx);
1402 } else {
1403 self.set_sides(outrec_idx, e2_idx, e1_idx);
1404 }
1405 }
1406 }
1407
1408 let op_idx = self.new_out_pt(pt, outrec_idx);
1409 self.outrec_list[outrec_idx].pts = Some(op_idx);
1410 op_idx
1411 }
1412
1413 fn add_local_max_poly(&mut self, e1_idx: usize, e2_idx: usize, pt: Point64) -> Option<usize> {
1416 if is_joined(&self.active_arena[e1_idx]) {
1417 self.split(e1_idx, pt);
1418 }
1419 if is_joined(&self.active_arena[e2_idx]) {
1420 self.split(e2_idx, pt);
1421 }
1422
1423 if self.is_front(e1_idx) == self.is_front(e2_idx) {
1424 if self.is_open_end_idx(e1_idx) {
1425 let or_idx = self.active_arena[e1_idx].outrec.unwrap();
1426 swap_front_back_sides(or_idx, &mut self.outrec_list, &self.outpt_arena);
1427 } else if self.is_open_end_idx(e2_idx) {
1428 let or_idx = self.active_arena[e2_idx].outrec.unwrap();
1429 swap_front_back_sides(or_idx, &mut self.outrec_list, &self.outpt_arena);
1430 } else {
1431 self.succeeded = false;
1432 return None;
1433 }
1434 }
1435
1436 let result = self.add_out_pt(e1_idx, pt);
1437 let or1 = self.active_arena[e1_idx].outrec;
1438 let or2 = self.active_arena[e2_idx].outrec;
1439
1440 if or1 == or2 {
1441 let or_idx = or1.unwrap();
1442 self.outrec_list[or_idx].pts = Some(result);
1443
1444 if self.using_polytree {
1445 let prev_hot = self.get_prev_hot_edge(e1_idx);
1446 if prev_hot.is_none() {
1447 self.outrec_list[or_idx].owner = None;
1448 } else if let Some(prev_hot_idx) = prev_hot {
1449 if let Some(prev_or) = self.active_arena[prev_hot_idx].outrec {
1450 set_owner(&mut self.outrec_list, or_idx, prev_or);
1451 }
1452 }
1453 }
1454
1455 uncouple_outrec(e1_idx, &mut self.active_arena, &mut self.outrec_list);
1456 let final_result = self.outrec_list[or_idx].pts;
1457 if let Some(owner) = self.outrec_list[or_idx].owner {
1458 if self.outrec_list[owner].front_edge.is_none() {
1459 self.outrec_list[or_idx].owner = get_real_outrec(&self.outrec_list, owner);
1460 }
1461 }
1462 return final_result;
1463 } else if self.is_open_idx(e1_idx) {
1464 if self.active_arena[e1_idx].wind_dx < 0 {
1465 self.join_outrec_paths(e1_idx, e2_idx);
1466 } else {
1467 self.join_outrec_paths(e2_idx, e1_idx);
1468 }
1469 } else {
1470 let or1_idx = or1.unwrap();
1471 let or2_idx = or2.unwrap();
1472 if self.outrec_list[or1_idx].idx < self.outrec_list[or2_idx].idx {
1473 self.join_outrec_paths(e1_idx, e2_idx);
1474 } else {
1475 self.join_outrec_paths(e2_idx, e1_idx);
1476 }
1477 }
1478 Some(result)
1479 }
1480
1481 fn join_outrec_paths(&mut self, e1_idx: usize, e2_idx: usize) {
1484 let or1 = self.active_arena[e1_idx].outrec.unwrap();
1485 let or2 = self.active_arena[e2_idx].outrec.unwrap();
1486
1487 let p1_st = self.outrec_list[or1].pts.unwrap();
1488 let p2_st = self.outrec_list[or2].pts.unwrap();
1489 let p1_end = self.outpt_arena[p1_st].next;
1490 let p2_end = self.outpt_arena[p2_st].next;
1491
1492 if self.is_front(e1_idx) {
1493 self.outpt_arena[p2_end].prev = p1_st;
1494 self.outpt_arena[p1_st].next = p2_end;
1495 self.outpt_arena[p2_st].next = p1_end;
1496 self.outpt_arena[p1_end].prev = p2_st;
1497 self.outrec_list[or1].pts = Some(p2_st);
1498 self.outrec_list[or1].front_edge = self.outrec_list[or2].front_edge;
1499 if let Some(fe) = self.outrec_list[or1].front_edge {
1500 self.active_arena[fe].outrec = Some(or1);
1501 }
1502 } else {
1503 self.outpt_arena[p1_end].prev = p2_st;
1504 self.outpt_arena[p2_st].next = p1_end;
1505 self.outpt_arena[p1_st].next = p2_end;
1506 self.outpt_arena[p2_end].prev = p1_st;
1507 self.outrec_list[or1].back_edge = self.outrec_list[or2].back_edge;
1508 if let Some(be) = self.outrec_list[or1].back_edge {
1509 self.active_arena[be].outrec = Some(or1);
1510 }
1511 }
1512
1513 self.outrec_list[or2].front_edge = None;
1514 self.outrec_list[or2].back_edge = None;
1515 self.outrec_list[or2].pts = None;
1516
1517 if self.is_open_end_idx(e1_idx) {
1518 self.outrec_list[or2].pts = self.outrec_list[or1].pts;
1519 self.outrec_list[or1].pts = None;
1520 } else {
1521 set_owner(&mut self.outrec_list, or2, or1);
1522 }
1523
1524 self.active_arena[e1_idx].outrec = None;
1525 self.active_arena[e2_idx].outrec = None;
1526 }
1527
1528 fn split(&mut self, e_idx: usize, pt: Point64) {
1531 if self.active_arena[e_idx].join_with == JoinWith::Right {
1532 self.active_arena[e_idx].join_with = JoinWith::NoJoin;
1533 let next = self.active_arena[e_idx].next_in_ael.unwrap();
1534 self.active_arena[next].join_with = JoinWith::NoJoin;
1535 self.add_local_min_poly(e_idx, next, pt, true);
1536 } else {
1537 self.active_arena[e_idx].join_with = JoinWith::NoJoin;
1538 let prev = self.active_arena[e_idx].prev_in_ael.unwrap();
1539 self.active_arena[prev].join_with = JoinWith::NoJoin;
1540 self.add_local_min_poly(prev, e_idx, pt, true);
1541 }
1542 }
1543
1544 fn delete_from_ael(&mut self, e_idx: usize) {
1549 let prev = self.active_arena[e_idx].prev_in_ael;
1550 let next = self.active_arena[e_idx].next_in_ael;
1551 if prev.is_none() && next.is_none() && self.actives != Some(e_idx) {
1552 return; }
1554 if let Some(prev_idx) = prev {
1555 self.active_arena[prev_idx].next_in_ael = next;
1556 } else {
1557 self.actives = next;
1558 }
1559 if let Some(next_idx) = next {
1560 self.active_arena[next_idx].prev_in_ael = prev;
1561 }
1562 self.active_arena[e_idx].prev_in_ael = None;
1564 self.active_arena[e_idx].next_in_ael = None;
1565 }
1566
1567 fn swap_positions_in_ael(&mut self, e1_idx: usize, e2_idx: usize) {
1570 let next = self.active_arena[e2_idx].next_in_ael;
1572 if let Some(next_idx) = next {
1573 self.active_arena[next_idx].prev_in_ael = Some(e1_idx);
1574 }
1575 let prev = self.active_arena[e1_idx].prev_in_ael;
1576 if let Some(prev_idx) = prev {
1577 self.active_arena[prev_idx].next_in_ael = Some(e2_idx);
1578 }
1579 self.active_arena[e2_idx].prev_in_ael = prev;
1580 self.active_arena[e2_idx].next_in_ael = Some(e1_idx);
1581 self.active_arena[e1_idx].prev_in_ael = Some(e2_idx);
1582 self.active_arena[e1_idx].next_in_ael = next;
1583 if self.active_arena[e2_idx].prev_in_ael.is_none() {
1584 self.actives = Some(e2_idx);
1585 }
1586 }
1587
1588 fn adjust_curr_x_and_copy_to_sel(&mut self, top_y: i64) {
1591 let mut e_opt = self.actives;
1592 self.sel = e_opt;
1593 while let Some(e_idx) = e_opt {
1594 self.active_arena[e_idx].prev_in_sel = self.active_arena[e_idx].prev_in_ael;
1595 self.active_arena[e_idx].next_in_sel = self.active_arena[e_idx].next_in_ael;
1596 self.active_arena[e_idx].jump = self.active_arena[e_idx].next_in_sel;
1597 self.active_arena[e_idx].curr_x = top_x(&self.active_arena[e_idx], top_y);
1598 e_opt = self.active_arena[e_idx].next_in_ael;
1599 }
1600 }
1601
1602 fn trim_horz(&mut self, e_idx: usize) {
1607 let mut was_trimmed = false;
1608 let nv = self.next_vertex_idx(e_idx);
1609 let mut pt = self.vertex_arena[nv].pt;
1610
1611 while pt.y == self.active_arena[e_idx].top.y {
1612 if self.preserve_collinear
1613 && (pt.x < self.active_arena[e_idx].top.x)
1614 != (self.active_arena[e_idx].bot.x < self.active_arena[e_idx].top.x)
1615 {
1616 break;
1617 }
1618
1619 self.active_arena[e_idx].vertex_top = self.next_vertex_idx(e_idx);
1620 self.active_arena[e_idx].top = pt;
1621 was_trimmed = true;
1622 if self.is_maxima_idx(e_idx) {
1623 break;
1624 }
1625 let nv2 = self.next_vertex_idx(e_idx);
1626 pt = self.vertex_arena[nv2].pt;
1627 }
1628
1629 if was_trimmed {
1630 set_dx(&mut self.active_arena[e_idx]);
1631 }
1632 }
1633
1634 fn update_edge_into_ael(&mut self, e_idx: usize) {
1637 self.active_arena[e_idx].bot = self.active_arena[e_idx].top;
1638 self.active_arena[e_idx].vertex_top = self.next_vertex_idx(e_idx);
1639 self.active_arena[e_idx].top = self.vertex_arena[self.active_arena[e_idx].vertex_top].pt;
1640 self.active_arena[e_idx].curr_x = self.active_arena[e_idx].bot.x;
1641 set_dx(&mut self.active_arena[e_idx]);
1642
1643 if is_joined(&self.active_arena[e_idx]) {
1644 let bot = self.active_arena[e_idx].bot;
1645 self.split(e_idx, bot);
1646 }
1647
1648 if self.is_horizontal_idx(e_idx) {
1649 if !self.is_open_idx(e_idx) {
1650 self.trim_horz(e_idx);
1651 }
1652 return;
1653 }
1654
1655 let top_y = self.active_arena[e_idx].top.y;
1656 self.insert_scanline(top_y);
1657 let bot = self.active_arena[e_idx].bot;
1658 self.check_join_left(e_idx, bot, false);
1659 self.check_join_right(e_idx, bot, true);
1660 }
1661
1662 fn find_edge_with_matching_loc_min(&self, e_idx: usize) -> Option<usize> {
1665 let local_min = self.active_arena[e_idx].local_min;
1666
1667 let mut result = self.active_arena[e_idx].next_in_ael;
1669 while let Some(r_idx) = result {
1670 if self.active_arena[r_idx].local_min == local_min {
1671 return Some(r_idx);
1672 }
1673 if !self.is_horizontal_idx(r_idx)
1674 && self.active_arena[e_idx].bot != self.active_arena[r_idx].bot
1675 {
1676 result = None;
1677 break;
1678 }
1679 result = self.active_arena[r_idx].next_in_ael;
1680 }
1681
1682 if result.is_none() {
1684 result = self.active_arena[e_idx].prev_in_ael;
1685 while let Some(r_idx) = result {
1686 if self.active_arena[r_idx].local_min == local_min {
1687 return Some(r_idx);
1688 }
1689 if !self.is_horizontal_idx(r_idx)
1690 && self.active_arena[e_idx].bot != self.active_arena[r_idx].bot
1691 {
1692 return None;
1693 }
1694 result = self.active_arena[r_idx].prev_in_ael;
1695 }
1696 }
1697 result
1698 }
1699
1700 fn check_join_left(&mut self, e_idx: usize, pt: Point64, check_curr_x: bool) {
1705 let prev = self.active_arena[e_idx].prev_in_ael;
1706 let prev_idx = match prev {
1707 Some(p) => p,
1708 None => return,
1709 };
1710
1711 if !is_hot_edge(&self.active_arena[e_idx])
1712 || !is_hot_edge(&self.active_arena[prev_idx])
1713 || self.is_horizontal_idx(e_idx)
1714 || self.is_horizontal_idx(prev_idx)
1715 || self.is_open_idx(e_idx)
1716 || self.is_open_idx(prev_idx)
1717 {
1718 return;
1719 }
1720
1721 let e_top = self.active_arena[e_idx].top;
1722 let p_top = self.active_arena[prev_idx].top;
1723 if (pt.y < e_top.y + 2 || pt.y < p_top.y + 2)
1724 && (self.active_arena[e_idx].bot.y > pt.y || self.active_arena[prev_idx].bot.y > pt.y)
1725 {
1726 return;
1727 }
1728
1729 if check_curr_x {
1730 if perpendic_dist_from_line_sqrd(
1731 pt,
1732 self.active_arena[prev_idx].bot,
1733 self.active_arena[prev_idx].top,
1734 ) > 0.25
1735 {
1736 return;
1737 }
1738 } else if self.active_arena[e_idx].curr_x != self.active_arena[prev_idx].curr_x {
1739 return;
1740 }
1741
1742 if !is_collinear(e_top, pt, p_top) {
1743 return;
1744 }
1745
1746 let e_or = self.active_arena[e_idx].outrec.unwrap();
1747 let p_or = self.active_arena[prev_idx].outrec.unwrap();
1748
1749 if self.outrec_list[e_or].idx == self.outrec_list[p_or].idx {
1750 self.add_local_max_poly(prev_idx, e_idx, pt);
1751 } else if self.outrec_list[e_or].idx < self.outrec_list[p_or].idx {
1752 self.join_outrec_paths(e_idx, prev_idx);
1753 } else {
1754 self.join_outrec_paths(prev_idx, e_idx);
1755 }
1756 self.active_arena[prev_idx].join_with = JoinWith::Right;
1757 self.active_arena[e_idx].join_with = JoinWith::Left;
1758 }
1759
1760 fn check_join_right(&mut self, e_idx: usize, pt: Point64, check_curr_x: bool) {
1763 let next = self.active_arena[e_idx].next_in_ael;
1764 let next_idx = match next {
1765 Some(n) => n,
1766 None => return,
1767 };
1768
1769 if !is_hot_edge(&self.active_arena[e_idx])
1770 || !is_hot_edge(&self.active_arena[next_idx])
1771 || self.is_horizontal_idx(e_idx)
1772 || self.is_horizontal_idx(next_idx)
1773 || self.is_open_idx(e_idx)
1774 || self.is_open_idx(next_idx)
1775 {
1776 return;
1777 }
1778
1779 let e_top = self.active_arena[e_idx].top;
1780 let n_top = self.active_arena[next_idx].top;
1781 if (pt.y < e_top.y + 2 || pt.y < n_top.y + 2)
1782 && (self.active_arena[e_idx].bot.y > pt.y || self.active_arena[next_idx].bot.y > pt.y)
1783 {
1784 return;
1785 }
1786
1787 if check_curr_x {
1788 if perpendic_dist_from_line_sqrd(
1789 pt,
1790 self.active_arena[next_idx].bot,
1791 self.active_arena[next_idx].top,
1792 ) > 0.35
1793 {
1794 return;
1795 }
1796 } else if self.active_arena[e_idx].curr_x != self.active_arena[next_idx].curr_x {
1797 return;
1798 }
1799
1800 if !is_collinear(e_top, pt, n_top) {
1801 return;
1802 }
1803
1804 let e_or = self.active_arena[e_idx].outrec.unwrap();
1805 let n_or = self.active_arena[next_idx].outrec.unwrap();
1806
1807 if self.outrec_list[e_or].idx == self.outrec_list[n_or].idx {
1808 self.add_local_max_poly(e_idx, next_idx, pt);
1809 } else if self.outrec_list[e_or].idx < self.outrec_list[n_or].idx {
1810 self.join_outrec_paths(e_idx, next_idx);
1811 } else {
1812 self.join_outrec_paths(next_idx, e_idx);
1813 }
1814
1815 self.active_arena[e_idx].join_with = JoinWith::Right;
1816 self.active_arena[next_idx].join_with = JoinWith::Left;
1817 }
1818
1819 fn intersect_edges(&mut self, e1_idx: usize, e2_idx: usize, pt: Point64) {
1824 if self.has_open_paths && (self.is_open_idx(e1_idx) || self.is_open_idx(e2_idx)) {
1826 if self.is_open_idx(e1_idx) && self.is_open_idx(e2_idx) {
1827 return;
1828 }
1829 let (edge_o, edge_c) = if self.is_open_idx(e1_idx) {
1830 (e1_idx, e2_idx)
1831 } else {
1832 (e2_idx, e1_idx)
1833 };
1834
1835 if is_joined(&self.active_arena[edge_c]) {
1836 self.split(edge_c, pt);
1837 }
1838
1839 if self.active_arena[edge_c].wind_cnt.abs() != 1 {
1840 return;
1841 }
1842
1843 match self.cliptype {
1844 ClipType::Union => {
1845 if !is_hot_edge(&self.active_arena[edge_c]) {
1846 return;
1847 }
1848 }
1849 _ => {
1850 if self.minima_list[self.active_arena[edge_c].local_min].polytype
1851 == PathType::Subject
1852 {
1853 return;
1854 }
1855 }
1856 }
1857
1858 match self.fillrule {
1859 FillRule::Positive => {
1860 if self.active_arena[edge_c].wind_cnt != 1 {
1861 return;
1862 }
1863 }
1864 FillRule::Negative => {
1865 if self.active_arena[edge_c].wind_cnt != -1 {
1866 return;
1867 }
1868 }
1869 _ => {
1870 if self.active_arena[edge_c].wind_cnt.abs() != 1 {
1871 return;
1872 }
1873 }
1874 }
1875
1876 if is_hot_edge(&self.active_arena[edge_o]) {
1878 self.add_out_pt(edge_o, pt);
1879 if self.is_front(edge_o) {
1880 let or = self.active_arena[edge_o].outrec.unwrap();
1881 self.outrec_list[or].front_edge = None;
1882 } else {
1883 let or = self.active_arena[edge_o].outrec.unwrap();
1884 self.outrec_list[or].back_edge = None;
1885 }
1886 self.active_arena[edge_o].outrec = None;
1887 } else if pt == self.active_arena[edge_o].bot
1888 && pt
1889 == self.vertex_arena
1890 [self.minima_list[self.active_arena[edge_o].local_min].vertex]
1891 .pt
1892 && !is_open_end_vertex(
1893 &self.vertex_arena
1894 [self.minima_list[self.active_arena[edge_o].local_min].vertex],
1895 )
1896 {
1897 let e3 = self.find_edge_with_matching_loc_min(edge_o);
1898 if let Some(e3_idx) = e3 {
1899 if is_hot_edge(&self.active_arena[e3_idx]) {
1900 let e3_or = self.active_arena[e3_idx].outrec.unwrap();
1901 self.active_arena[edge_o].outrec = Some(e3_or);
1902 if self.active_arena[edge_o].wind_dx > 0 {
1903 self.set_sides(e3_or, edge_o, e3_idx);
1904 } else {
1905 self.set_sides(e3_or, e3_idx, edge_o);
1906 }
1907 return;
1908 }
1909 }
1910 self.start_open_path(edge_o, pt);
1911 } else {
1912 self.start_open_path(edge_o, pt);
1913 }
1914 return;
1915 }
1916
1917 if is_joined(&self.active_arena[e1_idx]) {
1919 self.split(e1_idx, pt);
1920 }
1921 if is_joined(&self.active_arena[e2_idx]) {
1922 self.split(e2_idx, pt);
1923 }
1924
1925 let old_e1_windcnt;
1927 let old_e2_windcnt;
1928
1929 if self.is_same_poly_type_idx(e1_idx, e2_idx) {
1930 if self.fillrule == FillRule::EvenOdd {
1931 let tmp = self.active_arena[e1_idx].wind_cnt;
1932 self.active_arena[e1_idx].wind_cnt = self.active_arena[e2_idx].wind_cnt;
1933 self.active_arena[e2_idx].wind_cnt = tmp;
1934 } else {
1935 let e1_wc = self.active_arena[e1_idx].wind_cnt;
1936 let e2_wd = self.active_arena[e2_idx].wind_dx;
1937 let e1_wd = self.active_arena[e1_idx].wind_dx;
1938 if e1_wc + e2_wd == 0 {
1939 self.active_arena[e1_idx].wind_cnt = -e1_wc;
1940 } else {
1941 self.active_arena[e1_idx].wind_cnt = e1_wc + e2_wd;
1942 }
1943 let e2_wc = self.active_arena[e2_idx].wind_cnt;
1944 if e2_wc - e1_wd == 0 {
1945 self.active_arena[e2_idx].wind_cnt = -e2_wc;
1946 } else {
1947 self.active_arena[e2_idx].wind_cnt = e2_wc - e1_wd;
1948 }
1949 }
1950 } else if self.fillrule != FillRule::EvenOdd {
1951 self.active_arena[e1_idx].wind_cnt2 += self.active_arena[e2_idx].wind_dx;
1952 self.active_arena[e2_idx].wind_cnt2 -= self.active_arena[e1_idx].wind_dx;
1953 } else {
1954 let wc2_1 = self.active_arena[e1_idx].wind_cnt2;
1955 self.active_arena[e1_idx].wind_cnt2 = if wc2_1 == 0 { 1 } else { 0 };
1956 let wc2_2 = self.active_arena[e2_idx].wind_cnt2;
1957 self.active_arena[e2_idx].wind_cnt2 = if wc2_2 == 0 { 1 } else { 0 };
1958 }
1959
1960 let fillpos = FillRule::Positive;
1961 match self.fillrule {
1962 FillRule::EvenOdd | FillRule::NonZero => {
1963 old_e1_windcnt = self.active_arena[e1_idx].wind_cnt.abs();
1964 old_e2_windcnt = self.active_arena[e2_idx].wind_cnt.abs();
1965 }
1966 _ => {
1967 if self.fillrule == fillpos {
1968 old_e1_windcnt = self.active_arena[e1_idx].wind_cnt;
1969 old_e2_windcnt = self.active_arena[e2_idx].wind_cnt;
1970 } else {
1971 old_e1_windcnt = -self.active_arena[e1_idx].wind_cnt;
1972 old_e2_windcnt = -self.active_arena[e2_idx].wind_cnt;
1973 }
1974 }
1975 }
1976
1977 let e1_wc_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
1978 let e2_wc_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
1979
1980 if (!is_hot_edge(&self.active_arena[e1_idx]) && !e1_wc_in_01)
1981 || (!is_hot_edge(&self.active_arena[e2_idx]) && !e2_wc_in_01)
1982 {
1983 return;
1984 }
1985
1986 if is_hot_edge(&self.active_arena[e1_idx]) && is_hot_edge(&self.active_arena[e2_idx]) {
1988 if (old_e1_windcnt != 0 && old_e1_windcnt != 1)
1989 || (old_e2_windcnt != 0 && old_e2_windcnt != 1)
1990 || (!self.is_same_poly_type_idx(e1_idx, e2_idx) && self.cliptype != ClipType::Xor)
1991 {
1992 self.add_local_max_poly(e1_idx, e2_idx, pt);
1993 } else if self.is_front(e1_idx)
1994 || self.active_arena[e1_idx].outrec == self.active_arena[e2_idx].outrec
1995 {
1996 self.add_local_max_poly(e1_idx, e2_idx, pt);
1997 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
1998 } else {
1999 self.add_out_pt(e1_idx, pt);
2000 self.add_out_pt(e2_idx, pt);
2001 self.swap_outrecs(e1_idx, e2_idx);
2002 }
2003 } else if is_hot_edge(&self.active_arena[e1_idx]) {
2004 self.add_out_pt(e1_idx, pt);
2005 self.swap_outrecs(e1_idx, e2_idx);
2006 } else if is_hot_edge(&self.active_arena[e2_idx]) {
2007 self.add_out_pt(e2_idx, pt);
2008 self.swap_outrecs(e1_idx, e2_idx);
2009 } else {
2010 let e1wc2;
2012 let e2wc2;
2013 match self.fillrule {
2014 FillRule::EvenOdd | FillRule::NonZero => {
2015 e1wc2 = self.active_arena[e1_idx].wind_cnt2.abs() as i64;
2016 e2wc2 = self.active_arena[e2_idx].wind_cnt2.abs() as i64;
2017 }
2018 _ => {
2019 if self.fillrule == fillpos {
2020 e1wc2 = self.active_arena[e1_idx].wind_cnt2 as i64;
2021 e2wc2 = self.active_arena[e2_idx].wind_cnt2 as i64;
2022 } else {
2023 e1wc2 = -(self.active_arena[e1_idx].wind_cnt2 as i64);
2024 e2wc2 = -(self.active_arena[e2_idx].wind_cnt2 as i64);
2025 }
2026 }
2027 }
2028
2029 if !self.is_same_poly_type_idx(e1_idx, e2_idx) {
2030 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2031 } else if old_e1_windcnt == 1 && old_e2_windcnt == 1 {
2032 match self.cliptype {
2033 ClipType::Union => {
2034 if e1wc2 <= 0 && e2wc2 <= 0 {
2035 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2036 }
2037 }
2038 ClipType::Difference => {
2039 if (self.get_poly_type_idx(e1_idx) == PathType::Clip
2040 && e1wc2 > 0
2041 && e2wc2 > 0)
2042 || (self.get_poly_type_idx(e1_idx) == PathType::Subject
2043 && e1wc2 <= 0
2044 && e2wc2 <= 0)
2045 {
2046 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2047 }
2048 }
2049 ClipType::Xor => {
2050 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2051 }
2052 _ => {
2053 if e1wc2 > 0 && e2wc2 > 0 {
2055 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2056 }
2057 }
2058 }
2059 }
2060 }
2061 }
2062
2063 fn insert_local_minima_into_ael(&mut self, bot_y: i64) {
2068 while let Some(loc_min_idx) = self.pop_local_minima(bot_y) {
2069 let vert_idx = self.minima_list[loc_min_idx].vertex;
2070 let vert_flags = self.vertex_arena[vert_idx].flags;
2071 let vert_pt = self.vertex_arena[vert_idx].pt;
2072
2073 let left_bound_opt = if (vert_flags & VertexFlags::OPEN_START) != VertexFlags::EMPTY {
2075 None
2076 } else {
2077 let lb_idx = self.active_arena.len();
2078 let mut lb = Active::new();
2079 lb.bot = vert_pt;
2080 lb.curr_x = vert_pt.x;
2081 lb.wind_dx = -1;
2082 lb.vertex_top = self.vertex_arena[vert_idx].prev; lb.top = self.vertex_arena[lb.vertex_top].pt;
2084 lb.local_min = loc_min_idx;
2085 set_dx(&mut lb);
2086 self.active_arena.push(lb);
2087 Some(lb_idx)
2088 };
2089
2090 let right_bound_opt = if (vert_flags & VertexFlags::OPEN_END) != VertexFlags::EMPTY {
2092 None
2093 } else {
2094 let rb_idx = self.active_arena.len();
2095 let mut rb = Active::new();
2096 rb.bot = vert_pt;
2097 rb.curr_x = vert_pt.x;
2098 rb.wind_dx = 1;
2099 rb.vertex_top = self.vertex_arena[vert_idx].next; rb.top = self.vertex_arena[rb.vertex_top].pt;
2101 rb.local_min = loc_min_idx;
2102 set_dx(&mut rb);
2103 self.active_arena.push(rb);
2104 Some(rb_idx)
2105 };
2106
2107 let (mut left_bound, mut right_bound) = (left_bound_opt, right_bound_opt);
2109
2110 if let (Some(lb), Some(rb)) = (left_bound, right_bound) {
2111 if self.is_horizontal_idx(lb) {
2112 if is_heading_right_horz(&self.active_arena[lb]) {
2113 std::mem::swap(&mut left_bound, &mut right_bound);
2114 }
2115 } else if self.is_horizontal_idx(rb) {
2116 if is_heading_left_horz(&self.active_arena[rb]) {
2117 std::mem::swap(&mut left_bound, &mut right_bound);
2118 }
2119 } else if self.active_arena[lb].dx < self.active_arena[rb].dx {
2120 std::mem::swap(&mut left_bound, &mut right_bound);
2121 }
2122 } else if left_bound.is_none() {
2123 left_bound = right_bound;
2124 right_bound = None;
2125 }
2126
2127 let lb_idx = left_bound.unwrap();
2128 self.active_arena[lb_idx].is_left_bound = true;
2129 self.insert_left_edge(lb_idx);
2130
2131 let contributing = if self.is_open_idx(lb_idx) {
2132 self.set_wind_count_for_open_path_edge(lb_idx);
2133 self.is_contributing_open(lb_idx)
2134 } else {
2135 self.set_wind_count_for_closed_path_edge(lb_idx);
2136 self.is_contributing_closed(lb_idx)
2137 };
2138
2139 if let Some(rb_idx) = right_bound {
2140 self.active_arena[rb_idx].is_left_bound = false;
2141 self.active_arena[rb_idx].wind_cnt = self.active_arena[lb_idx].wind_cnt;
2142 self.active_arena[rb_idx].wind_cnt2 = self.active_arena[lb_idx].wind_cnt2;
2143 self.insert_right_edge(lb_idx, rb_idx);
2144
2145 if contributing {
2146 let bot = self.active_arena[lb_idx].bot;
2147 self.add_local_min_poly(lb_idx, rb_idx, bot, true);
2148 if !self.is_horizontal_idx(lb_idx) {
2149 let bot = self.active_arena[lb_idx].bot;
2150 self.check_join_left(lb_idx, bot, false);
2151 }
2152 }
2153
2154 while let Some(next) = self.active_arena[rb_idx].next_in_ael {
2156 if !is_valid_ael_order(
2157 &self.active_arena[next],
2158 &self.active_arena[rb_idx],
2159 &self.vertex_arena,
2160 &self.minima_list,
2161 ) {
2162 break;
2163 }
2164 let bot = self.active_arena[rb_idx].bot;
2165 self.intersect_edges(rb_idx, next, bot);
2166 self.swap_positions_in_ael(rb_idx, next);
2167 }
2168
2169 if self.is_horizontal_idx(rb_idx) {
2170 self.push_horz(rb_idx);
2171 } else {
2172 let bot = self.active_arena[rb_idx].bot;
2173 self.check_join_right(rb_idx, bot, false);
2174 let top_y = self.active_arena[rb_idx].top.y;
2175 self.insert_scanline(top_y);
2176 }
2177 } else if contributing {
2178 let bot = self.active_arena[lb_idx].bot;
2179 self.start_open_path(lb_idx, bot);
2180 }
2181
2182 if self.is_horizontal_idx(lb_idx) {
2183 self.push_horz(lb_idx);
2184 } else {
2185 let top_y = self.active_arena[lb_idx].top.y;
2186 self.insert_scanline(top_y);
2187 }
2188 }
2189 }
2190
2191 fn reset_horz_direction(&self, horz_idx: usize, max_vertex: Option<usize>) -> (i64, i64, bool) {
2196 let horz = &self.active_arena[horz_idx];
2197 if horz.bot.x == horz.top.x {
2198 let horz_left = horz.curr_x;
2199 let horz_right = horz.curr_x;
2200 let mut e = horz.next_in_ael;
2201 while let Some(e_idx) = e {
2202 if Some(self.active_arena[e_idx].vertex_top) == max_vertex {
2203 return (horz_left, horz_right, true);
2204 }
2205 e = self.active_arena[e_idx].next_in_ael;
2206 }
2207 (horz_left, horz_right, false)
2208 } else if horz.curr_x < horz.top.x {
2209 (horz.curr_x, horz.top.x, true)
2210 } else {
2211 (horz.top.x, horz.curr_x, false)
2212 }
2213 }
2214
2215 fn do_horizontal(&mut self, horz_idx: usize) {
2218 let horz_is_open = self.is_open_idx(horz_idx);
2219 let y = self.active_arena[horz_idx].bot.y;
2220
2221 let vertex_max = if horz_is_open {
2222 get_curr_y_maxima_vertex_open(&self.active_arena[horz_idx], &self.vertex_arena)
2223 } else {
2224 get_curr_y_maxima_vertex(&self.active_arena[horz_idx], &self.vertex_arena)
2225 };
2226
2227 let (mut horz_left, mut horz_right, mut is_left_to_right) =
2228 self.reset_horz_direction(horz_idx, vertex_max);
2229
2230 if is_hot_edge(&self.active_arena[horz_idx]) {
2231 let curr_x = self.active_arena[horz_idx].curr_x;
2232 let op = self.add_out_pt(horz_idx, Point64::new(curr_x, y));
2233 let or = self.outpt_arena[op].outrec;
2234 if !self.outrec_list[or].is_open {
2235 self.add_trial_horz_join(op);
2236 }
2237 }
2238
2239 loop {
2240 let e_start = if is_left_to_right {
2241 self.active_arena[horz_idx].next_in_ael
2242 } else {
2243 self.active_arena[horz_idx].prev_in_ael
2244 };
2245
2246 let mut e_opt = e_start;
2247 while let Some(e_idx) = e_opt {
2248 if Some(self.active_arena[e_idx].vertex_top) == vertex_max {
2250 if is_hot_edge(&self.active_arena[horz_idx])
2251 && is_joined(&self.active_arena[e_idx])
2252 {
2253 let top = self.active_arena[e_idx].top;
2254 self.split(e_idx, top);
2255 }
2256
2257 if is_hot_edge(&self.active_arena[horz_idx]) {
2258 while Some(self.active_arena[horz_idx].vertex_top) != vertex_max {
2259 let top = self.active_arena[horz_idx].top;
2260 self.add_out_pt(horz_idx, top);
2261 self.update_edge_into_ael(horz_idx);
2262 }
2263 if is_left_to_right {
2264 let top = self.active_arena[horz_idx].top;
2265 self.add_local_max_poly(horz_idx, e_idx, top);
2266 } else {
2267 let top = self.active_arena[horz_idx].top;
2268 self.add_local_max_poly(e_idx, horz_idx, top);
2269 }
2270 }
2271 self.delete_from_ael(e_idx);
2272 self.delete_from_ael(horz_idx);
2273 return;
2274 }
2275
2276 if vertex_max != Some(self.active_arena[horz_idx].vertex_top)
2278 || self.is_open_end_idx(horz_idx)
2279 {
2280 if (is_left_to_right && self.active_arena[e_idx].curr_x > horz_right)
2281 || (!is_left_to_right && self.active_arena[e_idx].curr_x < horz_left)
2282 {
2283 break;
2284 }
2285
2286 if self.active_arena[e_idx].curr_x == self.active_arena[horz_idx].top.x
2287 && !self.is_horizontal_idx(e_idx)
2288 {
2289 let nv_idx = self.next_vertex_idx(horz_idx);
2290 let nv_pt = self.vertex_arena[nv_idx].pt;
2291
2292 if is_left_to_right {
2293 if self.is_open_idx(e_idx)
2294 && !self.is_same_poly_type_idx(e_idx, horz_idx)
2295 && !is_hot_edge(&self.active_arena[e_idx])
2296 {
2297 if top_x(&self.active_arena[e_idx], nv_pt.y) > nv_pt.x {
2298 break;
2299 }
2300 } else if top_x(&self.active_arena[e_idx], nv_pt.y) >= nv_pt.x {
2301 break;
2302 }
2303 } else if self.is_open_idx(e_idx)
2304 && !self.is_same_poly_type_idx(e_idx, horz_idx)
2305 && !is_hot_edge(&self.active_arena[e_idx])
2306 {
2307 if top_x(&self.active_arena[e_idx], nv_pt.y) < nv_pt.x {
2308 break;
2309 }
2310 } else if top_x(&self.active_arena[e_idx], nv_pt.y) <= nv_pt.x {
2311 break;
2312 }
2313 }
2314 }
2315
2316 let pt = Point64::new(
2317 self.active_arena[e_idx].curr_x,
2318 self.active_arena[horz_idx].bot.y,
2319 );
2320 if is_left_to_right {
2321 self.intersect_edges(horz_idx, e_idx, pt);
2322 self.swap_positions_in_ael(horz_idx, e_idx);
2323 let pt2 = pt;
2324 self.check_join_left(e_idx, pt2, false);
2325 self.active_arena[horz_idx].curr_x = self.active_arena[e_idx].curr_x;
2326 e_opt = self.active_arena[horz_idx].next_in_ael;
2327 } else {
2328 self.intersect_edges(e_idx, horz_idx, pt);
2329 self.swap_positions_in_ael(e_idx, horz_idx);
2330 let pt2 = pt;
2331 self.check_join_right(e_idx, pt2, false);
2332 self.active_arena[horz_idx].curr_x = self.active_arena[e_idx].curr_x;
2333 e_opt = self.active_arena[horz_idx].prev_in_ael;
2334 }
2335
2336 if self.active_arena[horz_idx].outrec.is_some() {
2337 if let Some(last_op) = get_last_op(
2338 horz_idx,
2339 &self.active_arena,
2340 &self.outrec_list,
2341 &self.outpt_arena,
2342 ) {
2343 self.add_trial_horz_join(last_op);
2344 }
2345 }
2346 }
2347
2348 if horz_is_open && self.is_open_end_idx(horz_idx) {
2350 if is_hot_edge(&self.active_arena[horz_idx]) {
2351 let top = self.active_arena[horz_idx].top;
2352 self.add_out_pt(horz_idx, top);
2353 if self.is_front(horz_idx) {
2354 let or = self.active_arena[horz_idx].outrec.unwrap();
2355 self.outrec_list[or].front_edge = None;
2356 } else {
2357 let or = self.active_arena[horz_idx].outrec.unwrap();
2358 self.outrec_list[or].back_edge = None;
2359 }
2360 self.active_arena[horz_idx].outrec = None;
2361 }
2362 self.delete_from_ael(horz_idx);
2363 return;
2364 }
2365
2366 let nv_idx = self.next_vertex_idx(horz_idx);
2367 if self.vertex_arena[nv_idx].pt.y != self.active_arena[horz_idx].top.y {
2368 break;
2369 }
2370
2371 if is_hot_edge(&self.active_arena[horz_idx]) {
2373 let top = self.active_arena[horz_idx].top;
2374 self.add_out_pt(horz_idx, top);
2375 }
2376 self.update_edge_into_ael(horz_idx);
2377
2378 let result = self.reset_horz_direction(horz_idx, vertex_max);
2379 horz_left = result.0;
2380 horz_right = result.1;
2381 is_left_to_right = result.2;
2382 }
2383
2384 if is_hot_edge(&self.active_arena[horz_idx]) {
2385 let top = self.active_arena[horz_idx].top;
2386 let op = self.add_out_pt(horz_idx, top);
2387 self.add_trial_horz_join(op);
2388 }
2389
2390 self.update_edge_into_ael(horz_idx);
2391 }
2392
2393 fn add_new_intersect_node(&mut self, e1_idx: usize, e2_idx: usize, top_y: i64) {
2398 let e1 = &self.active_arena[e1_idx];
2399 let e2 = &self.active_arena[e2_idx];
2400 let mut ip = Point64::new(e1.curr_x, top_y);
2401 get_segment_intersect_pt(e1.bot, e1.top, e2.bot, e2.top, &mut ip);
2402
2403 if ip.y > self.bot_y || ip.y < top_y {
2404 let abs_dx1 = e1.dx.abs();
2405 let abs_dx2 = e2.dx.abs();
2406 if abs_dx1 > 100.0 && abs_dx2 > 100.0 {
2407 if abs_dx1 > abs_dx2 {
2408 ip = get_closest_point_on_segment(ip, e1.bot, e1.top);
2409 } else {
2410 ip = get_closest_point_on_segment(ip, e2.bot, e2.top);
2411 }
2412 } else if abs_dx1 > 100.0 {
2413 ip = get_closest_point_on_segment(ip, e1.bot, e1.top);
2414 } else if abs_dx2 > 100.0 {
2415 ip = get_closest_point_on_segment(ip, e2.bot, e2.top);
2416 } else {
2417 if ip.y < top_y {
2418 ip.y = top_y;
2419 } else {
2420 ip.y = self.bot_y;
2421 }
2422 if abs_dx1 < abs_dx2 {
2423 ip.x = top_x(&self.active_arena[e1_idx], ip.y);
2424 } else {
2425 ip.x = top_x(&self.active_arena[e2_idx], ip.y);
2426 }
2427 }
2428 }
2429 self.intersect_nodes
2430 .push(IntersectNode::with_edges(e1_idx, e2_idx, ip));
2431 }
2432
2433 fn build_intersect_list(&mut self, top_y: i64) -> bool {
2436 if self.actives.is_none() {
2437 return false;
2438 }
2439 let actives_idx = self.actives.unwrap();
2440 if self.active_arena[actives_idx].next_in_ael.is_none() {
2441 return false;
2442 }
2443
2444 self.adjust_curr_x_and_copy_to_sel(top_y);
2445
2446 let mut left_opt = self.sel;
2447 if left_opt.is_none() || self.active_arena[left_opt.unwrap()].jump.is_none() {
2449 return !self.intersect_nodes.is_empty();
2450 }
2451
2452 while let Some(left_idx) = left_opt {
2453 if self.active_arena[left_idx].jump.is_none() {
2454 break;
2455 }
2456
2457 let mut prev_base: Option<usize> = None;
2458 let mut left_inner = left_opt;
2459
2460 while let Some(li) = left_inner {
2461 if self.active_arena[li].jump.is_none() {
2462 break;
2463 }
2464
2465 let mut curr_base = li;
2466 let right_idx = self.active_arena[li].jump.unwrap();
2467 let mut l_end = right_idx;
2468 let r_end = self.active_arena[right_idx].jump;
2469 self.active_arena[li].jump = r_end;
2470
2471 let mut left_scan = li;
2472 let mut right_scan = right_idx;
2473
2474 while left_scan != l_end && right_scan != r_end.unwrap_or(NONE) {
2475 if self.active_arena[right_scan].curr_x < self.active_arena[left_scan].curr_x {
2476 let mut tmp = self.active_arena[right_scan].prev_in_sel;
2477 while let Some(tmp_idx) = tmp {
2478 self.add_new_intersect_node(tmp_idx, right_scan, top_y);
2479 if tmp_idx == left_scan {
2480 break;
2481 }
2482 tmp = self.active_arena[tmp_idx].prev_in_sel;
2483 }
2484
2485 let tmp_idx = right_scan;
2486 right_scan =
2487 extract_from_sel(tmp_idx, &mut self.active_arena).unwrap_or(NONE);
2488 l_end = right_scan;
2489
2490 insert1_before2_in_sel(tmp_idx, left_scan, &mut self.active_arena);
2491 if left_scan == curr_base {
2492 curr_base = tmp_idx;
2493 self.active_arena[curr_base].jump = r_end;
2494 if let Some(pb) = prev_base {
2495 self.active_arena[pb].jump = Some(curr_base);
2496 } else {
2497 self.sel = Some(curr_base);
2498 }
2499 }
2500 } else {
2501 left_scan = self.active_arena[left_scan].next_in_sel.unwrap_or(NONE);
2502 }
2503 }
2504
2505 prev_base = Some(curr_base);
2506 left_inner = r_end;
2507 }
2508
2509 left_opt = self.sel;
2510 }
2511
2512 !self.intersect_nodes.is_empty()
2513 }
2514
2515 fn do_intersections(&mut self, top_y: i64) {
2518 if self.build_intersect_list(top_y) {
2519 self.process_intersect_list();
2520 self.intersect_nodes.clear();
2521 }
2522 }
2523
2524 fn process_intersect_list(&mut self) {
2527 self.intersect_nodes.sort_by(intersect_list_sort);
2529
2530 let len = self.intersect_nodes.len();
2531 for i in 0..len {
2532 if !edges_adjacent_in_ael(&self.intersect_nodes[i], &self.active_arena) {
2534 let mut j = i + 1;
2535 while j < len
2536 && !edges_adjacent_in_ael(&self.intersect_nodes[j], &self.active_arena)
2537 {
2538 j += 1;
2539 }
2540 if j < len {
2541 self.intersect_nodes.swap(i, j);
2542 }
2543 }
2544
2545 let e1 = self.intersect_nodes[i].edge1;
2546 let e2 = self.intersect_nodes[i].edge2;
2547 let pt = self.intersect_nodes[i].pt;
2548
2549 self.intersect_edges(e1, e2, pt);
2550 self.swap_positions_in_ael(e1, e2);
2551
2552 self.active_arena[e1].curr_x = pt.x;
2553 self.active_arena[e2].curr_x = pt.x;
2554 self.check_join_left(e2, pt, true);
2555 self.check_join_right(e1, pt, true);
2556 }
2557 }
2558
2559 fn do_top_of_scanbeam(&mut self, y: i64) {
2564 self.sel = None;
2565 let mut e_opt = self.actives;
2566 while let Some(e_idx) = e_opt {
2567 if self.active_arena[e_idx].top.y == y {
2568 self.active_arena[e_idx].curr_x = self.active_arena[e_idx].top.x;
2569 if self.is_maxima_idx(e_idx) {
2570 e_opt = self.do_maxima(e_idx);
2571 continue;
2572 } else {
2573 if is_hot_edge(&self.active_arena[e_idx]) {
2574 let top = self.active_arena[e_idx].top;
2575 self.add_out_pt(e_idx, top);
2576 }
2577 self.update_edge_into_ael(e_idx);
2578 if self.is_horizontal_idx(e_idx) {
2579 self.push_horz(e_idx);
2580 }
2581 }
2582 } else {
2583 self.active_arena[e_idx].curr_x = top_x(&self.active_arena[e_idx], y);
2584 }
2585 e_opt = self.active_arena[e_idx].next_in_ael;
2586 }
2587 }
2588
2589 fn do_maxima(&mut self, e_idx: usize) -> Option<usize> {
2592 let prev_e = self.active_arena[e_idx].prev_in_ael;
2593 let mut next_e = self.active_arena[e_idx].next_in_ael;
2594
2595 if self.is_open_end_idx(e_idx) {
2596 if is_hot_edge(&self.active_arena[e_idx]) {
2597 let top = self.active_arena[e_idx].top;
2598 self.add_out_pt(e_idx, top);
2599 }
2600 if !self.is_horizontal_idx(e_idx) {
2601 if is_hot_edge(&self.active_arena[e_idx]) {
2602 if self.is_front(e_idx) {
2603 let or = self.active_arena[e_idx].outrec.unwrap();
2604 self.outrec_list[or].front_edge = None;
2605 } else {
2606 let or = self.active_arena[e_idx].outrec.unwrap();
2607 self.outrec_list[or].back_edge = None;
2608 }
2609 self.active_arena[e_idx].outrec = None;
2610 }
2611 self.delete_from_ael(e_idx);
2612 }
2613 return next_e;
2614 }
2615
2616 let max_pair = get_maxima_pair(&self.active_arena[e_idx], &self.active_arena);
2617 if max_pair.is_none() {
2618 return next_e;
2619 }
2620 let max_pair_idx = max_pair.unwrap();
2621
2622 if is_joined(&self.active_arena[e_idx]) {
2623 let top = self.active_arena[e_idx].top;
2624 self.split(e_idx, top);
2625 }
2626 if is_joined(&self.active_arena[max_pair_idx]) {
2627 let top = self.active_arena[max_pair_idx].top;
2628 self.split(max_pair_idx, top);
2629 }
2630
2631 while next_e != Some(max_pair_idx) {
2633 if let Some(ne_idx) = next_e {
2634 let top = self.active_arena[e_idx].top;
2635 self.intersect_edges(e_idx, ne_idx, top);
2636 self.swap_positions_in_ael(e_idx, ne_idx);
2637 next_e = self.active_arena[e_idx].next_in_ael;
2638 } else {
2639 break;
2640 }
2641 }
2642
2643 if self.is_open_idx(e_idx) {
2644 if is_hot_edge(&self.active_arena[e_idx]) {
2645 let top = self.active_arena[e_idx].top;
2646 self.add_local_max_poly(e_idx, max_pair_idx, top);
2647 }
2648 self.delete_from_ael(max_pair_idx);
2649 self.delete_from_ael(e_idx);
2650 return if let Some(pe) = prev_e {
2651 self.active_arena[pe].next_in_ael
2652 } else {
2653 self.actives
2654 };
2655 }
2656
2657 if is_hot_edge(&self.active_arena[e_idx]) {
2659 let top = self.active_arena[e_idx].top;
2660 self.add_local_max_poly(e_idx, max_pair_idx, top);
2661 }
2662
2663 self.delete_from_ael(e_idx);
2664 self.delete_from_ael(max_pair_idx);
2665 if let Some(pe) = prev_e {
2666 self.active_arena[pe].next_in_ael
2667 } else {
2668 self.actives
2669 }
2670 }
2671
2672 #[allow(dead_code)]
2676 fn set_horz_seg_heading_forward(&mut self, hs_idx: usize, op_p: usize, op_n: usize) -> bool {
2677 if self.outpt_arena[op_p].pt.x == self.outpt_arena[op_n].pt.x {
2678 return false;
2679 }
2680 if self.outpt_arena[op_p].pt.x < self.outpt_arena[op_n].pt.x {
2681 self.horz_seg_list[hs_idx].left_op = Some(op_p);
2682 self.horz_seg_list[hs_idx].right_op = Some(op_n);
2683 self.horz_seg_list[hs_idx].left_to_right = true;
2684 } else {
2685 self.horz_seg_list[hs_idx].left_op = Some(op_n);
2686 self.horz_seg_list[hs_idx].right_op = Some(op_p);
2687 self.horz_seg_list[hs_idx].left_to_right = false;
2688 }
2689 true
2690 }
2691
2692 fn convert_horz_segs_to_joins(&mut self) {
2695 let mut valid_count = 0;
2697 for i in 0..self.horz_seg_list.len() {
2698 let op = match self.horz_seg_list[i].left_op {
2699 Some(op) => op,
2700 None => {
2701 continue;
2702 }
2703 };
2704 let or_idx = self.outpt_arena[op].outrec;
2705 let real_or = get_real_outrec(&self.outrec_list, or_idx);
2706 if real_or.is_none() {
2707 continue;
2708 }
2709 let real_or_idx = real_or.unwrap();
2710 let has_edges = self.outrec_list[real_or_idx].front_edge.is_some();
2711 let curr_y = self.outpt_arena[op].pt.y;
2712
2713 let mut op_p = op;
2714 let mut op_n = op;
2715
2716 if has_edges {
2717 let op_a = self.outrec_list[real_or_idx].pts.unwrap();
2718 let op_z = self.outpt_arena[op_a].next;
2719 while op_p != op_z && self.outpt_arena[self.outpt_arena[op_p].prev].pt.y == curr_y {
2720 op_p = self.outpt_arena[op_p].prev;
2721 }
2722 while op_n != op_a && self.outpt_arena[self.outpt_arena[op_n].next].pt.y == curr_y {
2723 op_n = self.outpt_arena[op_n].next;
2724 }
2725 } else {
2726 while self.outpt_arena[op_p].prev != op_n
2727 && self.outpt_arena[self.outpt_arena[op_p].prev].pt.y == curr_y
2728 {
2729 op_p = self.outpt_arena[op_p].prev;
2730 }
2731 while self.outpt_arena[op_n].next != op_p
2732 && self.outpt_arena[self.outpt_arena[op_n].next].pt.y == curr_y
2733 {
2734 op_n = self.outpt_arena[op_n].next;
2735 }
2736 }
2737
2738 if self.outpt_arena[op_p].pt.x == self.outpt_arena[op_n].pt.x {
2739 self.horz_seg_list[i].right_op = None;
2740 continue;
2741 }
2742
2743 if self.outpt_arena[op_p].pt.x < self.outpt_arena[op_n].pt.x {
2745 self.horz_seg_list[i].left_op = Some(op_p);
2746 self.horz_seg_list[i].right_op = Some(op_n);
2747 self.horz_seg_list[i].left_to_right = true;
2748 } else {
2749 self.horz_seg_list[i].left_op = Some(op_n);
2750 self.horz_seg_list[i].right_op = Some(op_p);
2751 self.horz_seg_list[i].left_to_right = false;
2752 }
2753
2754 let left_op = self.horz_seg_list[i].left_op.unwrap();
2756 if self.outpt_arena[left_op].horz.is_some() {
2757 self.horz_seg_list[i].right_op = None;
2758 continue;
2759 }
2760
2761 self.outpt_arena[left_op].horz = Some(i);
2762 valid_count += 1;
2763 }
2764
2765 if valid_count < 2 {
2766 return;
2767 }
2768
2769 self.horz_seg_list.sort_by(|a, b| {
2771 let a_valid = a.right_op.is_some();
2772 let b_valid = b.right_op.is_some();
2773 if a_valid != b_valid {
2774 return if a_valid {
2775 std::cmp::Ordering::Less
2776 } else {
2777 std::cmp::Ordering::Greater
2778 };
2779 }
2780 if !a_valid {
2781 return std::cmp::Ordering::Equal;
2782 }
2783 let a_x = self.outpt_arena[a.left_op.unwrap()].pt.x;
2784 let b_x = self.outpt_arena[b.left_op.unwrap()].pt.x;
2785 a_x.cmp(&b_x)
2786 });
2787
2788 for i in 0..self.horz_seg_list.len() {
2790 if self.horz_seg_list[i].right_op.is_none() {
2791 break;
2792 }
2793 for j in (i + 1)..self.horz_seg_list.len() {
2794 if self.horz_seg_list[j].right_op.is_none() {
2795 break;
2796 }
2797
2798 let hs1_left_x = self.outpt_arena[self.horz_seg_list[i].left_op.unwrap()]
2799 .pt
2800 .x;
2801 let hs1_right_x = self.outpt_arena[self.horz_seg_list[i].right_op.unwrap()]
2802 .pt
2803 .x;
2804 let hs2_left_x = self.outpt_arena[self.horz_seg_list[j].left_op.unwrap()]
2805 .pt
2806 .x;
2807 let hs2_right_x = self.outpt_arena[self.horz_seg_list[j].right_op.unwrap()]
2808 .pt
2809 .x;
2810
2811 if hs2_left_x >= hs1_right_x
2812 || self.horz_seg_list[j].left_to_right == self.horz_seg_list[i].left_to_right
2813 || hs2_right_x <= hs1_left_x
2814 {
2815 continue;
2816 }
2817
2818 let curr_y = self.outpt_arena[self.horz_seg_list[i].left_op.unwrap()]
2819 .pt
2820 .y;
2821 let hs1_ltr = self.horz_seg_list[i].left_to_right;
2822
2823 if hs1_ltr {
2824 let mut lo1 = self.horz_seg_list[i].left_op.unwrap();
2826 while self.outpt_arena[self.outpt_arena[lo1].next].pt.y == curr_y
2827 && self.outpt_arena[self.outpt_arena[lo1].next].pt.x <= hs2_left_x
2828 {
2829 lo1 = self.outpt_arena[lo1].next;
2830 }
2831 self.horz_seg_list[i].left_op = Some(lo1);
2832 let mut lo2 = self.horz_seg_list[j].left_op.unwrap();
2833 while self.outpt_arena[self.outpt_arena[lo2].prev].pt.y == curr_y
2834 && self.outpt_arena[self.outpt_arena[lo2].prev].pt.x
2835 <= self.outpt_arena[lo1].pt.x
2836 {
2837 lo2 = self.outpt_arena[lo2].prev;
2838 }
2839 self.horz_seg_list[j].left_op = Some(lo2);
2840 let dup1 = self.duplicate_op(lo1, true);
2841 let dup2 = self.duplicate_op(lo2, false);
2842 self.horz_join_list.push(HorzJoin::with_ops(dup1, dup2));
2843 } else {
2844 let mut lo1 = self.horz_seg_list[i].left_op.unwrap();
2846 while self.outpt_arena[self.outpt_arena[lo1].prev].pt.y == curr_y
2847 && self.outpt_arena[self.outpt_arena[lo1].prev].pt.x <= hs2_left_x
2848 {
2849 lo1 = self.outpt_arena[lo1].prev;
2850 }
2851 self.horz_seg_list[i].left_op = Some(lo1);
2852 let mut lo2 = self.horz_seg_list[j].left_op.unwrap();
2853 while self.outpt_arena[self.outpt_arena[lo2].next].pt.y == curr_y
2854 && self.outpt_arena[self.outpt_arena[lo2].next].pt.x
2855 <= self.outpt_arena[lo1].pt.x
2856 {
2857 lo2 = self.outpt_arena[lo2].next;
2858 }
2859 self.horz_seg_list[j].left_op = Some(lo2);
2860 let dup1 = self.duplicate_op(lo2, true);
2861 let dup2 = self.duplicate_op(lo1, false);
2862 self.horz_join_list.push(HorzJoin::with_ops(dup1, dup2));
2863 }
2864 }
2865 }
2866 }
2867
2868 fn process_horz_joins(&mut self) {
2871 for idx in 0..self.horz_join_list.len() {
2872 let op1 = match self.horz_join_list[idx].op1 {
2873 Some(op) => op,
2874 None => continue,
2875 };
2876 let op2 = match self.horz_join_list[idx].op2 {
2877 Some(op) => op,
2878 None => continue,
2879 };
2880
2881 let or1 = get_real_outrec(&self.outrec_list, self.outpt_arena[op1].outrec);
2882 let or2 = get_real_outrec(&self.outrec_list, self.outpt_arena[op2].outrec);
2883 if or1.is_none() || or2.is_none() {
2884 continue;
2885 }
2886 let or1 = or1.unwrap();
2887 let or2_orig = or2.unwrap();
2888
2889 let op1b = self.outpt_arena[op1].next;
2890 let op2b = self.outpt_arena[op2].prev;
2891 self.outpt_arena[op1].next = op2;
2892 self.outpt_arena[op2].prev = op1;
2893 self.outpt_arena[op1b].prev = op2b;
2894 self.outpt_arena[op2b].next = op1b;
2895
2896 if or1 == or2_orig {
2897 let or2_new = self.new_out_rec();
2899 self.outrec_list[or2_new].pts = Some(op1b);
2900 fix_outrec_pts(or2_new, &self.outrec_list, &mut self.outpt_arena);
2901
2902 if self.outrec_list[or1]
2903 .pts
2904 .map(|p| self.outpt_arena[p].outrec)
2905 == Some(or2_new)
2906 {
2907 self.outrec_list[or1].pts = Some(op1);
2908 self.outpt_arena[op1].outrec = or1;
2909 }
2910
2911 if self.using_polytree {
2912 if path2_contains_path1_outpt(
2913 self.outrec_list[or1].pts.unwrap(),
2914 self.outrec_list[or2_new].pts.unwrap(),
2915 &self.outpt_arena,
2916 ) {
2917 let or1_pts = self.outrec_list[or1].pts;
2918 let or2_pts = self.outrec_list[or2_new].pts;
2919 self.outrec_list[or1].pts = or2_pts;
2920 self.outrec_list[or2_new].pts = or1_pts;
2921 fix_outrec_pts(or1, &self.outrec_list, &mut self.outpt_arena);
2922 fix_outrec_pts(or2_new, &self.outrec_list, &mut self.outpt_arena);
2923 self.outrec_list[or2_new].owner = Some(or1);
2924 } else if path2_contains_path1_outpt(
2925 self.outrec_list[or2_new].pts.unwrap(),
2926 self.outrec_list[or1].pts.unwrap(),
2927 &self.outpt_arena,
2928 ) {
2929 self.outrec_list[or2_new].owner = Some(or1);
2930 } else {
2931 self.outrec_list[or2_new].owner = self.outrec_list[or1].owner;
2932 }
2933
2934 if self.outrec_list[or1].splits.is_none() {
2935 self.outrec_list[or1].splits = Some(Vec::new());
2936 }
2937 self.outrec_list[or1].splits.as_mut().unwrap().push(or2_new);
2938 } else {
2939 self.outrec_list[or2_new].owner = Some(or1);
2940 }
2941 } else {
2942 self.outrec_list[or2_orig].pts = None;
2944 if self.using_polytree {
2945 set_owner(&mut self.outrec_list, or2_orig, or1);
2946 if self.outrec_list[or2_orig].splits.is_some() {
2947 move_splits(&mut self.outrec_list, or2_orig, or1);
2948 }
2949 } else {
2950 self.outrec_list[or2_orig].owner = Some(or1);
2951 }
2952 }
2953 }
2954 }
2955
2956 pub fn clean_collinear(&mut self, outrec_idx: usize) {
2961 let real_or = get_real_outrec(&self.outrec_list, outrec_idx);
2962 let or_idx = match real_or {
2963 Some(idx) => idx,
2964 None => return,
2965 };
2966 if self.outrec_list[or_idx].is_open {
2967 return;
2968 }
2969 if !is_valid_closed_path(self.outrec_list[or_idx].pts, &self.outpt_arena) {
2970 self.dispose_out_pts(or_idx);
2971 return;
2972 }
2973
2974 let start_op = self.outrec_list[or_idx].pts.unwrap();
2975 let mut op2 = start_op;
2976 loop {
2977 let prev = self.outpt_arena[op2].prev;
2978 let next = self.outpt_arena[op2].next;
2979 let prev_pt = self.outpt_arena[prev].pt;
2980 let op2_pt = self.outpt_arena[op2].pt;
2981 let next_pt = self.outpt_arena[next].pt;
2982
2983 if is_collinear(prev_pt, op2_pt, next_pt)
2984 && (op2_pt == prev_pt
2985 || op2_pt == next_pt
2986 || !self.preserve_collinear
2987 || dot_product_three_points(prev_pt, op2_pt, next_pt) < 0.0)
2988 {
2989 if Some(op2) == self.outrec_list[or_idx].pts {
2990 self.outrec_list[or_idx].pts = Some(prev);
2991 }
2992 op2 = self.dispose_out_pt(op2);
2993 if !is_valid_closed_path(Some(op2), &self.outpt_arena) {
2994 self.dispose_out_pts(or_idx);
2995 return;
2996 }
2997 continue;
2999 }
3000 op2 = next;
3001 if op2 == start_op
3002 || (self.outrec_list[or_idx].pts.is_some()
3003 && op2 == self.outrec_list[or_idx].pts.unwrap())
3004 {
3005 break;
3006 }
3007 }
3008 self.fix_self_intersects(or_idx);
3009 }
3010
3011 fn fix_self_intersects(&mut self, outrec_idx: usize) {
3014 let start_op = match self.outrec_list[outrec_idx].pts {
3015 Some(op) => op,
3016 None => return,
3017 };
3018
3019 let prev = self.outpt_arena[start_op].prev;
3020 let next = self.outpt_arena[start_op].next;
3021 if prev == self.outpt_arena[next].next {
3022 return; }
3024
3025 let mut op2 = start_op;
3026 loop {
3027 let prev = self.outpt_arena[op2].prev;
3028 let next = self.outpt_arena[op2].next;
3029 let next_next = self.outpt_arena[next].next;
3030
3031 if segments_intersect(
3032 self.outpt_arena[prev].pt,
3033 self.outpt_arena[op2].pt,
3034 self.outpt_arena[next].pt,
3035 self.outpt_arena[next_next].pt,
3036 false,
3037 ) {
3038 let next_next_next = self.outpt_arena[next_next].next;
3039 if segments_intersect(
3040 self.outpt_arena[prev].pt,
3041 self.outpt_arena[op2].pt,
3042 self.outpt_arena[next_next].pt,
3043 self.outpt_arena[next_next_next].pt,
3044 false,
3045 ) {
3046 op2 = self.duplicate_op(op2, false);
3048 let nnext = self.outpt_arena[self.outpt_arena[op2].next].next;
3049 let nnn = self.outpt_arena[nnext].next;
3050 self.outpt_arena[op2].pt = self.outpt_arena[nnn].pt;
3051 op2 = self.outpt_arena[op2].next;
3052 } else {
3053 if Some(op2) == self.outrec_list[outrec_idx].pts
3054 || Some(next) == self.outrec_list[outrec_idx].pts
3055 {
3056 let pts = self.outrec_list[outrec_idx].pts.unwrap();
3057 self.outrec_list[outrec_idx].pts = Some(self.outpt_arena[pts].prev);
3058 }
3059 self.do_split_op(outrec_idx, op2);
3060 if self.outrec_list[outrec_idx].pts.is_none() {
3061 break;
3062 }
3063 op2 = self.outrec_list[outrec_idx].pts.unwrap();
3064 let prev = self.outpt_arena[op2].prev;
3065 let next = self.outpt_arena[op2].next;
3066 if prev == self.outpt_arena[next].next {
3067 break;
3068 }
3069 continue;
3070 }
3071 } else {
3072 op2 = self.outpt_arena[op2].next;
3073 }
3074 if op2 == start_op
3075 || (self.outrec_list[outrec_idx].pts.is_some()
3076 && op2 == self.outrec_list[outrec_idx].pts.unwrap())
3077 {
3078 break;
3079 }
3080 }
3081 }
3082
3083 fn do_split_op(&mut self, outrec_idx: usize, split_op: usize) {
3086 let prev_op = self.outpt_arena[split_op].prev;
3087 let next_op = self.outpt_arena[split_op].next;
3088 let next_next_op = self.outpt_arena[next_op].next;
3089 self.outrec_list[outrec_idx].pts = Some(prev_op);
3090
3091 let mut ip = self.outpt_arena[prev_op].pt;
3092 get_segment_intersect_pt(
3093 self.outpt_arena[prev_op].pt,
3094 self.outpt_arena[split_op].pt,
3095 self.outpt_arena[next_op].pt,
3096 self.outpt_arena[next_next_op].pt,
3097 &mut ip,
3098 );
3099
3100 let area1 = area_outpt(self.outrec_list[outrec_idx].pts.unwrap(), &self.outpt_arena);
3101 let abs_area1 = area1.abs();
3102 if abs_area1 < 2.0 {
3103 self.dispose_out_pts(outrec_idx);
3104 return;
3105 }
3106
3107 let area2 = area_triangle(
3108 ip,
3109 self.outpt_arena[split_op].pt,
3110 self.outpt_arena[next_op].pt,
3111 );
3112 let abs_area2 = area2.abs();
3113
3114 if ip == self.outpt_arena[prev_op].pt || ip == self.outpt_arena[next_next_op].pt {
3116 self.outpt_arena[next_next_op].prev = prev_op;
3117 self.outpt_arena[prev_op].next = next_next_op;
3118 } else {
3119 let new_op2 = self.new_out_pt(ip, self.outpt_arena[prev_op].outrec);
3120 self.outpt_arena[new_op2].prev = prev_op;
3121 self.outpt_arena[new_op2].next = next_next_op;
3122 self.outpt_arena[next_next_op].prev = new_op2;
3123 self.outpt_arena[prev_op].next = new_op2;
3124 }
3125
3126 if abs_area2 >= 1.0 && (abs_area2 > abs_area1 || (area2 > 0.0) == (area1 > 0.0)) {
3127 let new_or = self.new_out_rec();
3128 self.outrec_list[new_or].owner = self.outrec_list[outrec_idx].owner;
3129
3130 self.outpt_arena[split_op].outrec = new_or;
3131 self.outpt_arena[next_op].outrec = new_or;
3132
3133 let new_op = self.new_out_pt(ip, new_or);
3134 self.outpt_arena[new_op].prev = next_op;
3135 self.outpt_arena[new_op].next = split_op;
3136 self.outrec_list[new_or].pts = Some(new_op);
3137 self.outpt_arena[split_op].prev = new_op;
3138 self.outpt_arena[next_op].next = new_op;
3139
3140 if self.using_polytree {
3141 if path2_contains_path1_outpt(prev_op, new_op, &self.outpt_arena) {
3142 self.outrec_list[new_or].splits = Some(vec![outrec_idx]);
3143 } else {
3144 if self.outrec_list[outrec_idx].splits.is_none() {
3145 self.outrec_list[outrec_idx].splits = Some(Vec::new());
3146 }
3147 self.outrec_list[outrec_idx]
3148 .splits
3149 .as_mut()
3150 .unwrap()
3151 .push(new_or);
3152 }
3153 }
3154 }
3155 }
3157
3158 pub fn check_bounds(&mut self, outrec_idx: usize) -> bool {
3163 if self.outrec_list[outrec_idx].pts.is_none() {
3164 return false;
3165 }
3166 if !self.outrec_list[outrec_idx].bounds.is_empty() {
3167 return true;
3168 }
3169 self.clean_collinear(outrec_idx);
3170 if self.outrec_list[outrec_idx].pts.is_none() {
3171 return false;
3172 }
3173
3174 let op_start = self.outrec_list[outrec_idx].pts.unwrap();
3175 let path =
3176 build_path64_from_outpt(op_start, self.reverse_solution, false, &self.outpt_arena);
3177 match path {
3178 None => {
3179 self.outrec_list[outrec_idx].path = Path64::new();
3180 false
3181 }
3182 Some(p) => {
3183 self.outrec_list[outrec_idx].bounds = get_bounds(&p);
3184 self.outrec_list[outrec_idx].path = p;
3185 true
3186 }
3187 }
3188 }
3189
3190 fn check_split_owner(&mut self, outrec_idx: usize, splits: &[usize]) -> bool {
3193 for &split_idx in splits {
3194 if self.outrec_list[split_idx].pts.is_none() {
3195 if let Some(ref sub_splits) = self.outrec_list[split_idx].splits.clone() {
3196 if self.check_split_owner(outrec_idx, sub_splits) {
3197 return true;
3198 }
3199 }
3200 }
3201 let real_split = get_real_outrec(&self.outrec_list, split_idx);
3202 let split = match real_split {
3203 Some(s) if s != outrec_idx => s,
3204 _ => continue,
3205 };
3206
3207 if self.outrec_list[split].recursive_split == Some(outrec_idx) {
3208 continue;
3209 }
3210 self.outrec_list[split].recursive_split = Some(outrec_idx);
3211
3212 if let Some(ref sub_splits) = self.outrec_list[split].splits.clone() {
3213 if self.check_split_owner(outrec_idx, sub_splits) {
3214 return true;
3215 }
3216 }
3217
3218 if !self.check_bounds(split) {
3219 continue;
3220 }
3221 let or_bounds = self.outrec_list[outrec_idx].bounds;
3222 if !self.outrec_list[split].bounds.contains_rect(&or_bounds) {
3223 continue;
3224 }
3225
3226 let or_pts = self.outrec_list[outrec_idx].pts.unwrap();
3227 let split_pts = self.outrec_list[split].pts.unwrap();
3228 if !path2_contains_path1_outpt(or_pts, split_pts, &self.outpt_arena) {
3229 continue;
3230 }
3231
3232 if !is_valid_owner(&self.outrec_list, outrec_idx, split) {
3233 self.outrec_list[split].owner = self.outrec_list[outrec_idx].owner;
3234 }
3235
3236 self.outrec_list[outrec_idx].owner = Some(split);
3237 return true;
3238 }
3239 false
3240 }
3241
3242 pub fn recursive_check_owners(&mut self, outrec_idx: usize, polytree: &mut PolyTree64) {
3245 if self.outrec_list[outrec_idx].polypath.is_some()
3246 || self.outrec_list[outrec_idx].bounds.is_empty()
3247 {
3248 return;
3249 }
3250
3251 while let Some(owner) = self.outrec_list[outrec_idx].owner {
3252 if let Some(ref splits) = self.outrec_list[owner].splits.clone() {
3253 if self.check_split_owner(outrec_idx, splits) {
3254 break;
3255 }
3256 }
3257 if self.outrec_list[owner].pts.is_some() && self.check_bounds(owner) {
3258 let or_bounds = self.outrec_list[outrec_idx].bounds;
3259 let owner_bounds = self.outrec_list[owner].bounds;
3260 let contains = owner_bounds.contains_rect(&or_bounds);
3261 if contains {
3262 let or_pts = self.outrec_list[outrec_idx].pts.unwrap();
3263 let owner_pts = self.outrec_list[owner].pts.unwrap();
3264 let p2cp1 = path2_contains_path1_outpt(or_pts, owner_pts, &self.outpt_arena);
3265 if p2cp1 {
3266 break;
3267 }
3268 }
3269 }
3270 self.outrec_list[outrec_idx].owner = self.outrec_list[owner].owner;
3271 }
3272
3273 let path = self.outrec_list[outrec_idx].path.clone();
3274 if let Some(owner) = self.outrec_list[outrec_idx].owner {
3275 if self.outrec_list[owner].polypath.is_none() {
3276 self.recursive_check_owners(owner, polytree);
3277 }
3278 let parent_pp = self.outrec_list[owner].polypath.unwrap_or(0);
3279 let pp = polytree.add_child(parent_pp, path);
3280 self.outrec_list[outrec_idx].polypath = Some(pp);
3281 } else {
3282 let pp = polytree.add_child(0, path);
3283 self.outrec_list[outrec_idx].polypath = Some(pp);
3284 }
3285 }
3286
3287 pub fn execute_internal(
3292 &mut self,
3293 ct: ClipType,
3294 fillrule: FillRule,
3295 use_polytrees: bool,
3296 ) -> bool {
3297 self.cliptype = ct;
3298 self.fillrule = fillrule;
3299 self.using_polytree = use_polytrees;
3300 self.reset();
3301
3302 if ct == ClipType::NoClip {
3303 return true;
3304 }
3305
3306 let y = match self.pop_scanline() {
3307 Some(y) => y,
3308 None => return true,
3309 };
3310
3311 let mut y = y;
3312 while self.succeeded {
3313 self.insert_local_minima_into_ael(y);
3314
3315 while let Some(e) = self.pop_horz() {
3316 self.do_horizontal(e);
3317 }
3318
3319 if !self.horz_seg_list.is_empty() {
3320 self.convert_horz_segs_to_joins();
3321 self.horz_seg_list.clear();
3322 }
3323
3324 self.bot_y = y;
3325
3326 match self.pop_scanline() {
3327 Some(new_y) => y = new_y,
3328 None => break,
3329 }
3330
3331 self.do_intersections(y);
3332 self.do_top_of_scanbeam(y);
3333
3334 while let Some(e) = self.pop_horz() {
3335 self.do_horizontal(e);
3336 }
3337 }
3338
3339 if self.succeeded {
3340 self.process_horz_joins();
3341 }
3342
3343 self.succeeded
3344 }
3345}
3346
3347#[cfg(test)]
3352#[path = "engine_tests.rs"]
3353mod tests;