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 self.add_loc_min(first_vert_idx, polytype, true);
669 going_up = true;
670 } else {
671 going_up = self.vertex_arena[i].pt.y < first_pt.y;
672 if going_up {
673 self.add_loc_min(first_vert_idx, polytype, true);
674 } else {
675 self.vertex_arena[first_vert_idx].flags |= VertexFlags::LOCAL_MAX;
676 }
677 }
678 }
679
680 for i in (first_vert_idx + 1)..last_vert_idx {
682 let curr_pt = self.vertex_arena[i].pt;
683 let next_pt = self.vertex_arena[i + 1].pt;
684
685 if next_pt.y > curr_pt.y && going_up {
686 self.vertex_arena[i].flags |= VertexFlags::LOCAL_MAX;
687 going_up = false;
688 } else if next_pt.y < curr_pt.y && !going_up {
689 going_up = true;
690 self.add_loc_min(i, polytype, true);
691 }
692 }
693
694 let last_pt = self.vertex_arena[last_vert_idx].pt;
696 let prev_pt = self.vertex_arena[last_vert_idx - 1].pt;
697 if !going_up {
698 self.add_loc_min(last_vert_idx, polytype, true);
700 } else if last_pt.y < prev_pt.y || (last_pt.y == prev_pt.y && going_up) {
701 self.vertex_arena[last_vert_idx].flags |= VertexFlags::LOCAL_MAX;
702 }
703 }
704
705 pub fn add_paths(&mut self, paths: &Paths64, polytype: PathType, is_open: bool) {
708 for path in paths {
709 self.add_path(path, polytype, is_open);
710 }
711 }
712
713 pub fn sort_minima_list(&mut self) {
715 if !self.minima_list_sorted {
716 let vertex_arena = &self.vertex_arena;
718 self.minima_list.sort_by(|a, b| {
719 let a_pt = vertex_arena[a.vertex].pt;
720 let b_pt = vertex_arena[b.vertex].pt;
721 if a_pt.y != b_pt.y {
722 b_pt.y.cmp(&a_pt.y) } else {
724 a_pt.x.cmp(&b_pt.x) }
726 });
727 self.minima_list_sorted = true;
728 }
729 }
730
731 pub fn duplicate_op(&mut self, op_idx: usize, insert_after: bool) -> usize {
734 let pt = self.outpt_arena[op_idx].pt;
735 let outrec = self.outpt_arena[op_idx].outrec;
736 let new_idx = self.outpt_arena.len();
737 let mut result = OutPt::new(pt, outrec);
738
739 if insert_after {
740 let next = self.outpt_arena[op_idx].next;
741 result.next = next;
742 result.prev = op_idx;
743 self.outpt_arena.push(result);
744 self.outpt_arena[next].prev = new_idx;
745 self.outpt_arena[op_idx].next = new_idx;
746 } else {
747 let prev = self.outpt_arena[op_idx].prev;
748 result.prev = prev;
749 result.next = op_idx;
750 self.outpt_arena.push(result);
751 self.outpt_arena[prev].next = new_idx;
752 self.outpt_arena[op_idx].prev = new_idx;
753 }
754
755 new_idx
756 }
757
758 pub fn dispose_out_pt(&mut self, op_idx: usize) -> usize {
761 let result = self.outpt_arena[op_idx].next;
762 let prev = self.outpt_arena[op_idx].prev;
763 self.outpt_arena[prev].next = result;
764 self.outpt_arena[result].prev = prev;
765 result
767 }
768
769 pub fn dispose_out_pts(&mut self, outrec_idx: usize) {
772 if let Some(pts_idx) = self.outrec_list[outrec_idx].pts {
773 let prev = self.outpt_arena[pts_idx].prev;
775 self.outpt_arena[prev].next = NONE; let mut op = Some(pts_idx);
778 while let Some(idx) = op {
779 if self.outpt_arena[idx].next == NONE {
780 break;
781 }
782 let next = self.outpt_arena[idx].next;
783 if next == NONE || next == idx {
784 break;
785 }
786 op = Some(next);
787 }
788 }
789 self.outrec_list[outrec_idx].pts = None;
790 }
791
792 #[inline]
795 pub fn set_sides(&mut self, outrec_idx: usize, start_edge: usize, end_edge: usize) {
796 self.outrec_list[outrec_idx].front_edge = Some(start_edge);
797 self.outrec_list[outrec_idx].back_edge = Some(end_edge);
798 }
799
800 pub fn swap_outrecs(&mut self, e1_idx: usize, e2_idx: usize) {
803 let or1 = self.active_arena[e1_idx].outrec;
804 let or2 = self.active_arena[e2_idx].outrec;
805
806 if or1 == or2 {
807 if let Some(or_idx) = or1 {
808 let fe = self.outrec_list[or_idx].front_edge;
809 let be = self.outrec_list[or_idx].back_edge;
810 self.outrec_list[or_idx].front_edge = be;
811 self.outrec_list[or_idx].back_edge = fe;
812 }
813 return;
814 }
815
816 if let Some(or1_idx) = or1 {
817 if self.outrec_list[or1_idx].front_edge == Some(e1_idx) {
818 self.outrec_list[or1_idx].front_edge = Some(e2_idx);
819 } else {
820 self.outrec_list[or1_idx].back_edge = Some(e2_idx);
821 }
822 }
823
824 if let Some(or2_idx) = or2 {
825 if self.outrec_list[or2_idx].front_edge == Some(e2_idx) {
826 self.outrec_list[or2_idx].front_edge = Some(e1_idx);
827 } else {
828 self.outrec_list[or2_idx].back_edge = Some(e1_idx);
829 }
830 }
831
832 self.active_arena[e1_idx].outrec = or2;
833 self.active_arena[e2_idx].outrec = or1;
834 }
835
836 #[inline]
839 pub fn is_front(&self, e_idx: usize) -> bool {
840 if let Some(or_idx) = self.active_arena[e_idx].outrec {
841 self.outrec_list[or_idx].front_edge == Some(e_idx)
842 } else {
843 false
844 }
845 }
846
847 pub fn get_prev_hot_edge(&self, e_idx: usize) -> Option<usize> {
850 let mut prev = self.active_arena[e_idx].prev_in_ael;
851 while let Some(p_idx) = prev {
852 if is_open_active(&self.active_arena[p_idx], &self.minima_list)
853 || !is_hot_edge(&self.active_arena[p_idx])
854 {
855 prev = self.active_arena[p_idx].prev_in_ael;
856 } else {
857 return Some(p_idx);
858 }
859 }
860 None
861 }
862
863 #[inline]
866 pub fn add_trial_horz_join(&mut self, op_idx: usize) {
867 let or_idx = self.outpt_arena[op_idx].outrec;
871 if self.outrec_list[or_idx].is_open {
872 return;
873 }
874 self.horz_seg_list.push(HorzSegment::with_op(op_idx));
875 }
876
877 #[inline]
880 pub fn push_horz(&mut self, e_idx: usize) {
881 self.active_arena[e_idx].next_in_sel = self.sel;
882 self.sel = Some(e_idx);
883 }
884
885 #[inline]
888 pub fn pop_horz(&mut self) -> Option<usize> {
889 let e = self.sel;
890 if let Some(e_idx) = e {
891 self.sel = self.active_arena[e_idx].next_in_sel;
892 }
893 e
894 }
895
896 pub fn build_path64(&self, outrec: &OutRec) -> Option<Path64> {
899 let op_start = outrec.pts?;
900 let cnt = point_count(op_start, &self.outpt_arena);
901 if cnt < 2 {
902 return None;
903 }
904
905 let reverse = if outrec.is_open {
906 false
907 } else {
908 let area = area_outpt(op_start, &self.outpt_arena);
909 if area == 0.0 {
910 return None;
911 }
912 (area < 0.0) != self.reverse_solution
913 };
914
915 let mut result = Path64::with_capacity(cnt as usize);
916 if reverse {
917 let mut op = op_start;
918 loop {
919 result.push(self.outpt_arena[op].pt);
920 op = self.outpt_arena[op].prev;
921 if op == op_start {
922 break;
923 }
924 }
925 } else {
926 let op_next = self.outpt_arena[op_start].next;
927 let mut op = op_next;
928 loop {
929 result.push(self.outpt_arena[op].pt);
930 op = self.outpt_arena[op].next;
931 if op == op_next {
932 break;
933 }
934 }
935 }
936
937 if !self.preserve_collinear {
939 let mut i = 0;
941 while i < result.len() && result.len() > 2 {
942 let prev = if i == 0 { result.len() - 1 } else { i - 1 };
943 let next = (i + 1) % result.len();
944 if is_collinear(result[prev], result[i], result[next]) {
945 result.remove(i);
946 i = i.saturating_sub(1);
947 } else {
948 i += 1;
949 }
950 }
951 }
952
953 if result.len() < 2 {
954 None
955 } else {
956 Some(result)
957 }
958 }
959}
960
961impl Default for ClipperBase {
962 fn default() -> Self {
963 Self::new()
964 }
965}
966
967impl ClipperBase {
973 #[inline]
977 fn is_open_idx(&self, e_idx: usize) -> bool {
978 self.minima_list[self.active_arena[e_idx].local_min].is_open
979 }
980
981 #[inline]
983 fn is_maxima_idx(&self, e_idx: usize) -> bool {
984 is_maxima_vertex(&self.vertex_arena[self.active_arena[e_idx].vertex_top])
985 }
986
987 #[inline]
989 fn is_horizontal_idx(&self, e_idx: usize) -> bool {
990 self.active_arena[e_idx].top.y == self.active_arena[e_idx].bot.y
991 }
992
993 #[inline]
995 fn is_open_end_idx(&self, e_idx: usize) -> bool {
996 is_open_end_vertex(&self.vertex_arena[self.active_arena[e_idx].vertex_top])
997 }
998
999 #[inline]
1001 fn get_poly_type_idx(&self, e_idx: usize) -> PathType {
1002 self.minima_list[self.active_arena[e_idx].local_min].polytype
1003 }
1004
1005 #[inline]
1007 fn is_same_poly_type_idx(&self, e1: usize, e2: usize) -> bool {
1008 self.minima_list[self.active_arena[e1].local_min].polytype
1009 == self.minima_list[self.active_arena[e2].local_min].polytype
1010 }
1011
1012 #[inline]
1014 fn next_vertex_idx(&self, e_idx: usize) -> usize {
1015 if self.active_arena[e_idx].wind_dx > 0 {
1016 self.vertex_arena[self.active_arena[e_idx].vertex_top].next
1017 } else {
1018 self.vertex_arena[self.active_arena[e_idx].vertex_top].prev
1019 }
1020 }
1021
1022 pub fn reset(&mut self) {
1027 self.sort_minima_list();
1028 for i in (0..self.minima_list.len()).rev() {
1030 let y = self.vertex_arena[self.minima_list[i].vertex].pt.y;
1031 self.insert_scanline(y);
1032 }
1033 self.current_locmin_idx = 0;
1034 self.actives = None;
1035 self.sel = None;
1036 self.succeeded = true;
1037 }
1038
1039 pub fn clean_up(&mut self) {
1041 self.active_arena.clear();
1043 self.scanline_list.clear();
1044 self.intersect_nodes.clear();
1045 for i in 0..self.outrec_list.len() {
1047 self.outrec_list[i].pts = None;
1048 }
1049 self.outpt_arena.clear();
1050 self.outrec_list.clear();
1051 self.horz_seg_list.clear();
1052 self.horz_join_list.clear();
1053 self.actives = None;
1054 self.sel = None;
1055 }
1056
1057 fn is_contributing_closed(&self, e_idx: usize) -> bool {
1062 let e = &self.active_arena[e_idx];
1063 match self.fillrule {
1064 FillRule::EvenOdd => {}
1065 FillRule::NonZero => {
1066 if e.wind_cnt.abs() != 1 {
1067 return false;
1068 }
1069 }
1070 FillRule::Positive => {
1071 if e.wind_cnt != 1 {
1072 return false;
1073 }
1074 }
1075 FillRule::Negative => {
1076 if e.wind_cnt != -1 {
1077 return false;
1078 }
1079 }
1080 }
1081
1082 match self.cliptype {
1083 ClipType::NoClip => false,
1084 ClipType::Intersection => match self.fillrule {
1085 FillRule::Positive => e.wind_cnt2 > 0,
1086 FillRule::Negative => e.wind_cnt2 < 0,
1087 _ => e.wind_cnt2 != 0,
1088 },
1089 ClipType::Union => match self.fillrule {
1090 FillRule::Positive => e.wind_cnt2 <= 0,
1091 FillRule::Negative => e.wind_cnt2 >= 0,
1092 _ => e.wind_cnt2 == 0,
1093 },
1094 ClipType::Difference => {
1095 let result = match self.fillrule {
1096 FillRule::Positive => e.wind_cnt2 <= 0,
1097 FillRule::Negative => e.wind_cnt2 >= 0,
1098 _ => e.wind_cnt2 == 0,
1099 };
1100 if self.get_poly_type_idx(e_idx) == PathType::Subject {
1101 result
1102 } else {
1103 !result
1104 }
1105 }
1106 ClipType::Xor => true,
1107 }
1108 }
1109
1110 fn is_contributing_open(&self, e_idx: usize) -> bool {
1113 let e = &self.active_arena[e_idx];
1114 let (is_in_clip, is_in_subj) = match self.fillrule {
1115 FillRule::Positive => (e.wind_cnt2 > 0, e.wind_cnt > 0),
1116 FillRule::Negative => (e.wind_cnt2 < 0, e.wind_cnt < 0),
1117 _ => (e.wind_cnt2 != 0, e.wind_cnt != 0),
1118 };
1119
1120 match self.cliptype {
1121 ClipType::Intersection => is_in_clip,
1122 ClipType::Union => !is_in_subj && !is_in_clip,
1123 _ => !is_in_clip,
1124 }
1125 }
1126
1127 fn set_wind_count_for_closed_path_edge(&mut self, e_idx: usize) {
1130 let pt = self.get_poly_type_idx(e_idx);
1131 let e_wind_dx = self.active_arena[e_idx].wind_dx;
1132
1133 let mut e2_opt = self.active_arena[e_idx].prev_in_ael;
1135 while let Some(e2_idx) = e2_opt {
1136 if self.get_poly_type_idx(e2_idx) == pt && !self.is_open_idx(e2_idx) {
1137 break;
1138 }
1139 e2_opt = self.active_arena[e2_idx].prev_in_ael;
1140 }
1141
1142 let e2_start; if let Some(e2_idx) = e2_opt {
1144 if self.fillrule == FillRule::EvenOdd {
1145 self.active_arena[e_idx].wind_cnt = e_wind_dx;
1146 self.active_arena[e_idx].wind_cnt2 = self.active_arena[e2_idx].wind_cnt2;
1147 e2_start = self.active_arena[e2_idx].next_in_ael;
1148 } else {
1149 let e2_wind_cnt = self.active_arena[e2_idx].wind_cnt;
1150 let e2_wind_dx = self.active_arena[e2_idx].wind_dx;
1151 if e2_wind_cnt * e2_wind_dx < 0 {
1153 if e2_wind_cnt.abs() > 1 {
1155 if e2_wind_dx * e_wind_dx < 0 {
1156 self.active_arena[e_idx].wind_cnt = e2_wind_cnt;
1157 } else {
1158 self.active_arena[e_idx].wind_cnt = e2_wind_cnt + e_wind_dx;
1159 }
1160 } else {
1161 self.active_arena[e_idx].wind_cnt = if self.is_open_idx(e_idx) {
1162 1
1163 } else {
1164 e_wind_dx
1165 };
1166 }
1167 } else {
1168 if e2_wind_dx * e_wind_dx < 0 {
1170 self.active_arena[e_idx].wind_cnt = e2_wind_cnt;
1171 } else {
1172 self.active_arena[e_idx].wind_cnt = e2_wind_cnt + e_wind_dx;
1173 }
1174 }
1175 self.active_arena[e_idx].wind_cnt2 = self.active_arena[e2_idx].wind_cnt2;
1176 e2_start = self.active_arena[e2_idx].next_in_ael;
1177 }
1178 } else {
1179 self.active_arena[e_idx].wind_cnt = e_wind_dx;
1180 e2_start = self.actives;
1181 }
1182
1183 let mut e2_cur = e2_start;
1185 if self.fillrule == FillRule::EvenOdd {
1186 while e2_cur != Some(e_idx) {
1187 if let Some(e2i) = e2_cur {
1188 if self.get_poly_type_idx(e2i) != pt && !self.is_open_idx(e2i) {
1189 let wc2 = self.active_arena[e_idx].wind_cnt2;
1190 self.active_arena[e_idx].wind_cnt2 = if wc2 == 0 { 1 } else { 0 };
1191 }
1192 e2_cur = self.active_arena[e2i].next_in_ael;
1193 } else {
1194 break;
1195 }
1196 }
1197 } else {
1198 while e2_cur != Some(e_idx) {
1199 if let Some(e2i) = e2_cur {
1200 if self.get_poly_type_idx(e2i) != pt && !self.is_open_idx(e2i) {
1201 let e2_wd = self.active_arena[e2i].wind_dx;
1202 self.active_arena[e_idx].wind_cnt2 += e2_wd;
1203 }
1204 e2_cur = self.active_arena[e2i].next_in_ael;
1205 } else {
1206 break;
1207 }
1208 }
1209 }
1210 }
1211
1212 fn set_wind_count_for_open_path_edge(&mut self, e_idx: usize) {
1215 let mut e2_opt = self.actives;
1216 if self.fillrule == FillRule::EvenOdd {
1217 let mut cnt1 = 0i32;
1218 let mut cnt2 = 0i32;
1219 while e2_opt != Some(e_idx) {
1220 if let Some(e2i) = e2_opt {
1221 if self.get_poly_type_idx(e2i) == PathType::Clip {
1222 cnt2 += 1;
1223 } else if !self.is_open_idx(e2i) {
1224 cnt1 += 1;
1225 }
1226 e2_opt = self.active_arena[e2i].next_in_ael;
1227 } else {
1228 break;
1229 }
1230 }
1231 self.active_arena[e_idx].wind_cnt = if is_odd(cnt1) { 1 } else { 0 };
1232 self.active_arena[e_idx].wind_cnt2 = if is_odd(cnt2) { 1 } else { 0 };
1233 } else {
1234 while e2_opt != Some(e_idx) {
1235 if let Some(e2i) = e2_opt {
1236 if self.get_poly_type_idx(e2i) == PathType::Clip {
1237 self.active_arena[e_idx].wind_cnt2 += self.active_arena[e2i].wind_dx;
1238 } else if !self.is_open_idx(e2i) {
1239 self.active_arena[e_idx].wind_cnt += self.active_arena[e2i].wind_dx;
1240 }
1241 e2_opt = self.active_arena[e2i].next_in_ael;
1242 } else {
1243 break;
1244 }
1245 }
1246 }
1247 }
1248
1249 fn insert_left_edge(&mut self, e_idx: usize) {
1254 if self.actives.is_none() {
1255 self.active_arena[e_idx].prev_in_ael = None;
1256 self.active_arena[e_idx].next_in_ael = None;
1257 self.actives = Some(e_idx);
1258 } else {
1259 let actives_idx = self.actives.unwrap();
1260 if !is_valid_ael_order(
1261 &self.active_arena[actives_idx],
1262 &self.active_arena[e_idx],
1263 &self.vertex_arena,
1264 &self.minima_list,
1265 ) {
1266 self.active_arena[e_idx].prev_in_ael = None;
1267 self.active_arena[e_idx].next_in_ael = self.actives;
1268 self.active_arena[actives_idx].prev_in_ael = Some(e_idx);
1269 self.actives = Some(e_idx);
1270 } else {
1271 let mut e2 = actives_idx;
1272 while let Some(next) = self.active_arena[e2].next_in_ael {
1273 if !is_valid_ael_order(
1274 &self.active_arena[next],
1275 &self.active_arena[e_idx],
1276 &self.vertex_arena,
1277 &self.minima_list,
1278 ) {
1279 break;
1280 }
1281 e2 = next;
1282 }
1283 if self.active_arena[e2].join_with == JoinWith::Right {
1284 if let Some(next) = self.active_arena[e2].next_in_ael {
1285 e2 = next;
1286 } else {
1287 return;
1288 }
1289 }
1290 let next = self.active_arena[e2].next_in_ael;
1291 self.active_arena[e_idx].next_in_ael = next;
1292 if let Some(next_idx) = next {
1293 self.active_arena[next_idx].prev_in_ael = Some(e_idx);
1294 }
1295 self.active_arena[e_idx].prev_in_ael = Some(e2);
1296 self.active_arena[e2].next_in_ael = Some(e_idx);
1297 }
1298 }
1299 }
1300
1301 fn insert_right_edge(&mut self, e_idx: usize, e2_idx: usize) {
1304 let next = self.active_arena[e_idx].next_in_ael;
1305 self.active_arena[e2_idx].next_in_ael = next;
1306 if let Some(next_idx) = next {
1307 self.active_arena[next_idx].prev_in_ael = Some(e2_idx);
1308 }
1309 self.active_arena[e2_idx].prev_in_ael = Some(e_idx);
1310 self.active_arena[e_idx].next_in_ael = Some(e2_idx);
1311 }
1312
1313 fn add_out_pt(&mut self, e_idx: usize, pt: Point64) -> usize {
1318 let or_idx = self.active_arena[e_idx].outrec.unwrap();
1319 let to_front = self.is_front(e_idx);
1320 let op_front = self.outrec_list[or_idx].pts.unwrap();
1321 let op_back = self.outpt_arena[op_front].next;
1322
1323 if to_front {
1324 if pt == self.outpt_arena[op_front].pt {
1325 return op_front;
1326 }
1327 } else if pt == self.outpt_arena[op_back].pt {
1328 return op_back;
1329 }
1330
1331 let new_idx = self.outpt_arena.len();
1332 let mut new_op = OutPt::new(pt, or_idx);
1333 new_op.prev = op_front;
1334 new_op.next = op_back;
1335 self.outpt_arena.push(new_op);
1336 self.outpt_arena[op_back].prev = new_idx;
1337 self.outpt_arena[op_front].next = new_idx;
1338
1339 if to_front {
1340 self.outrec_list[or_idx].pts = Some(new_idx);
1341 }
1342 new_idx
1343 }
1344
1345 fn start_open_path(&mut self, e_idx: usize, pt: Point64) -> usize {
1348 let outrec_idx = self.new_out_rec();
1349 self.outrec_list[outrec_idx].is_open = true;
1350
1351 if self.active_arena[e_idx].wind_dx > 0 {
1352 self.outrec_list[outrec_idx].front_edge = Some(e_idx);
1353 self.outrec_list[outrec_idx].back_edge = None;
1354 } else {
1355 self.outrec_list[outrec_idx].front_edge = None;
1356 self.outrec_list[outrec_idx].back_edge = Some(e_idx);
1357 }
1358
1359 self.active_arena[e_idx].outrec = Some(outrec_idx);
1360
1361 let op_idx = self.new_out_pt(pt, outrec_idx);
1362 self.outrec_list[outrec_idx].pts = Some(op_idx);
1363 op_idx
1364 }
1365
1366 fn add_local_min_poly(
1369 &mut self,
1370 e1_idx: usize,
1371 e2_idx: usize,
1372 pt: Point64,
1373 is_new: bool,
1374 ) -> usize {
1375 let outrec_idx = self.new_out_rec();
1376 self.active_arena[e1_idx].outrec = Some(outrec_idx);
1377 self.active_arena[e2_idx].outrec = Some(outrec_idx);
1378
1379 if self.is_open_idx(e1_idx) {
1380 self.outrec_list[outrec_idx].owner = None;
1381 self.outrec_list[outrec_idx].is_open = true;
1382 if self.active_arena[e1_idx].wind_dx > 0 {
1383 self.set_sides(outrec_idx, e1_idx, e2_idx);
1384 } else {
1385 self.set_sides(outrec_idx, e2_idx, e1_idx);
1386 }
1387 } else {
1388 let prev_hot = self.get_prev_hot_edge(e1_idx);
1389 if let Some(prev_hot_idx) = prev_hot {
1390 if self.using_polytree {
1391 if let Some(prev_or) = self.active_arena[prev_hot_idx].outrec {
1392 set_owner(&mut self.outrec_list, outrec_idx, prev_or);
1393 }
1394 }
1395 if outrec_is_ascending(prev_hot_idx, &self.outrec_list, &self.active_arena)
1396 == is_new
1397 {
1398 self.set_sides(outrec_idx, e2_idx, e1_idx);
1399 } else {
1400 self.set_sides(outrec_idx, e1_idx, e2_idx);
1401 }
1402 } else {
1403 self.outrec_list[outrec_idx].owner = None;
1404 if is_new {
1405 self.set_sides(outrec_idx, e1_idx, e2_idx);
1406 } else {
1407 self.set_sides(outrec_idx, e2_idx, e1_idx);
1408 }
1409 }
1410 }
1411
1412 let op_idx = self.new_out_pt(pt, outrec_idx);
1413 self.outrec_list[outrec_idx].pts = Some(op_idx);
1414 op_idx
1415 }
1416
1417 fn add_local_max_poly(&mut self, e1_idx: usize, e2_idx: usize, pt: Point64) -> Option<usize> {
1420 if is_joined(&self.active_arena[e1_idx]) {
1421 self.split(e1_idx, pt);
1422 }
1423 if is_joined(&self.active_arena[e2_idx]) {
1424 self.split(e2_idx, pt);
1425 }
1426
1427 if self.is_front(e1_idx) == self.is_front(e2_idx) {
1428 if self.is_open_end_idx(e1_idx) {
1429 let or_idx = self.active_arena[e1_idx].outrec.unwrap();
1430 swap_front_back_sides(or_idx, &mut self.outrec_list, &self.outpt_arena);
1431 } else if self.is_open_end_idx(e2_idx) {
1432 let or_idx = self.active_arena[e2_idx].outrec.unwrap();
1433 swap_front_back_sides(or_idx, &mut self.outrec_list, &self.outpt_arena);
1434 } else {
1435 self.succeeded = false;
1436 return None;
1437 }
1438 }
1439
1440 let result = self.add_out_pt(e1_idx, pt);
1441 let or1 = self.active_arena[e1_idx].outrec;
1442 let or2 = self.active_arena[e2_idx].outrec;
1443
1444 if or1 == or2 {
1445 let or_idx = or1.unwrap();
1446 self.outrec_list[or_idx].pts = Some(result);
1447
1448 if self.using_polytree {
1449 let prev_hot = self.get_prev_hot_edge(e1_idx);
1450 if prev_hot.is_none() {
1451 self.outrec_list[or_idx].owner = None;
1452 } else if let Some(prev_hot_idx) = prev_hot {
1453 if let Some(prev_or) = self.active_arena[prev_hot_idx].outrec {
1454 set_owner(&mut self.outrec_list, or_idx, prev_or);
1455 }
1456 }
1457 }
1458
1459 uncouple_outrec(e1_idx, &mut self.active_arena, &mut self.outrec_list);
1460 let final_result = self.outrec_list[or_idx].pts;
1461 if let Some(owner) = self.outrec_list[or_idx].owner {
1462 if self.outrec_list[owner].front_edge.is_none() {
1463 self.outrec_list[or_idx].owner = get_real_outrec(&self.outrec_list, owner);
1464 }
1465 }
1466 return final_result;
1467 } else if self.is_open_idx(e1_idx) {
1468 if self.active_arena[e1_idx].wind_dx < 0 {
1469 self.join_outrec_paths(e1_idx, e2_idx);
1470 } else {
1471 self.join_outrec_paths(e2_idx, e1_idx);
1472 }
1473 } else {
1474 let or1_idx = or1.unwrap();
1475 let or2_idx = or2.unwrap();
1476 if self.outrec_list[or1_idx].idx < self.outrec_list[or2_idx].idx {
1477 self.join_outrec_paths(e1_idx, e2_idx);
1478 } else {
1479 self.join_outrec_paths(e2_idx, e1_idx);
1480 }
1481 }
1482 Some(result)
1483 }
1484
1485 fn join_outrec_paths(&mut self, e1_idx: usize, e2_idx: usize) {
1488 let or1 = self.active_arena[e1_idx].outrec.unwrap();
1489 let or2 = self.active_arena[e2_idx].outrec.unwrap();
1490
1491 let p1_st = self.outrec_list[or1].pts.unwrap();
1492 let p2_st = self.outrec_list[or2].pts.unwrap();
1493 let p1_end = self.outpt_arena[p1_st].next;
1494 let p2_end = self.outpt_arena[p2_st].next;
1495
1496 if self.is_front(e1_idx) {
1497 self.outpt_arena[p2_end].prev = p1_st;
1498 self.outpt_arena[p1_st].next = p2_end;
1499 self.outpt_arena[p2_st].next = p1_end;
1500 self.outpt_arena[p1_end].prev = p2_st;
1501 self.outrec_list[or1].pts = Some(p2_st);
1502 self.outrec_list[or1].front_edge = self.outrec_list[or2].front_edge;
1503 if let Some(fe) = self.outrec_list[or1].front_edge {
1504 self.active_arena[fe].outrec = Some(or1);
1505 }
1506 } else {
1507 self.outpt_arena[p1_end].prev = p2_st;
1508 self.outpt_arena[p2_st].next = p1_end;
1509 self.outpt_arena[p1_st].next = p2_end;
1510 self.outpt_arena[p2_end].prev = p1_st;
1511 self.outrec_list[or1].back_edge = self.outrec_list[or2].back_edge;
1512 if let Some(be) = self.outrec_list[or1].back_edge {
1513 self.active_arena[be].outrec = Some(or1);
1514 }
1515 }
1516
1517 self.outrec_list[or2].front_edge = None;
1518 self.outrec_list[or2].back_edge = None;
1519 self.outrec_list[or2].pts = None;
1520
1521 if self.is_open_end_idx(e1_idx) {
1522 self.outrec_list[or2].pts = self.outrec_list[or1].pts;
1523 self.outrec_list[or1].pts = None;
1524 } else {
1525 set_owner(&mut self.outrec_list, or2, or1);
1526 }
1527
1528 self.active_arena[e1_idx].outrec = None;
1529 self.active_arena[e2_idx].outrec = None;
1530 }
1531
1532 fn split(&mut self, e_idx: usize, pt: Point64) {
1535 if self.active_arena[e_idx].join_with == JoinWith::Right {
1536 self.active_arena[e_idx].join_with = JoinWith::NoJoin;
1537 let next = self.active_arena[e_idx].next_in_ael.unwrap();
1538 self.active_arena[next].join_with = JoinWith::NoJoin;
1539 self.add_local_min_poly(e_idx, next, pt, true);
1540 } else {
1541 self.active_arena[e_idx].join_with = JoinWith::NoJoin;
1542 let prev = self.active_arena[e_idx].prev_in_ael.unwrap();
1543 self.active_arena[prev].join_with = JoinWith::NoJoin;
1544 self.add_local_min_poly(prev, e_idx, pt, true);
1545 }
1546 }
1547
1548 fn delete_from_ael(&mut self, e_idx: usize) {
1553 let prev = self.active_arena[e_idx].prev_in_ael;
1554 let next = self.active_arena[e_idx].next_in_ael;
1555 if prev.is_none() && next.is_none() && self.actives != Some(e_idx) {
1556 return; }
1558 if let Some(prev_idx) = prev {
1559 self.active_arena[prev_idx].next_in_ael = next;
1560 } else {
1561 self.actives = next;
1562 }
1563 if let Some(next_idx) = next {
1564 self.active_arena[next_idx].prev_in_ael = prev;
1565 }
1566 self.active_arena[e_idx].prev_in_ael = None;
1568 self.active_arena[e_idx].next_in_ael = None;
1569 }
1570
1571 fn swap_positions_in_ael(&mut self, e1_idx: usize, e2_idx: usize) {
1574 let next = self.active_arena[e2_idx].next_in_ael;
1576 if let Some(next_idx) = next {
1577 self.active_arena[next_idx].prev_in_ael = Some(e1_idx);
1578 }
1579 let prev = self.active_arena[e1_idx].prev_in_ael;
1580 if let Some(prev_idx) = prev {
1581 self.active_arena[prev_idx].next_in_ael = Some(e2_idx);
1582 }
1583 self.active_arena[e2_idx].prev_in_ael = prev;
1584 self.active_arena[e2_idx].next_in_ael = Some(e1_idx);
1585 self.active_arena[e1_idx].prev_in_ael = Some(e2_idx);
1586 self.active_arena[e1_idx].next_in_ael = next;
1587 if self.active_arena[e2_idx].prev_in_ael.is_none() {
1588 self.actives = Some(e2_idx);
1589 }
1590 }
1591
1592 fn adjust_curr_x_and_copy_to_sel(&mut self, top_y: i64) {
1595 let mut e_opt = self.actives;
1596 self.sel = e_opt;
1597 while let Some(e_idx) = e_opt {
1598 self.active_arena[e_idx].prev_in_sel = self.active_arena[e_idx].prev_in_ael;
1599 self.active_arena[e_idx].next_in_sel = self.active_arena[e_idx].next_in_ael;
1600 self.active_arena[e_idx].jump = self.active_arena[e_idx].next_in_sel;
1601 self.active_arena[e_idx].curr_x = top_x(&self.active_arena[e_idx], top_y);
1602 e_opt = self.active_arena[e_idx].next_in_ael;
1603 }
1604 }
1605
1606 fn trim_horz(&mut self, e_idx: usize) {
1611 let mut was_trimmed = false;
1612 let nv = self.next_vertex_idx(e_idx);
1613 let mut pt = self.vertex_arena[nv].pt;
1614
1615 while pt.y == self.active_arena[e_idx].top.y {
1616 if self.preserve_collinear
1617 && (pt.x < self.active_arena[e_idx].top.x)
1618 != (self.active_arena[e_idx].bot.x < self.active_arena[e_idx].top.x)
1619 {
1620 break;
1621 }
1622
1623 self.active_arena[e_idx].vertex_top = self.next_vertex_idx(e_idx);
1624 self.active_arena[e_idx].top = pt;
1625 was_trimmed = true;
1626 if self.is_maxima_idx(e_idx) {
1627 break;
1628 }
1629 let nv2 = self.next_vertex_idx(e_idx);
1630 pt = self.vertex_arena[nv2].pt;
1631 }
1632
1633 if was_trimmed {
1634 set_dx(&mut self.active_arena[e_idx]);
1635 }
1636 }
1637
1638 fn update_edge_into_ael(&mut self, e_idx: usize) {
1641 self.active_arena[e_idx].bot = self.active_arena[e_idx].top;
1642 self.active_arena[e_idx].vertex_top = self.next_vertex_idx(e_idx);
1643 self.active_arena[e_idx].top = self.vertex_arena[self.active_arena[e_idx].vertex_top].pt;
1644 self.active_arena[e_idx].curr_x = self.active_arena[e_idx].bot.x;
1645 set_dx(&mut self.active_arena[e_idx]);
1646
1647 if is_joined(&self.active_arena[e_idx]) {
1648 let bot = self.active_arena[e_idx].bot;
1649 self.split(e_idx, bot);
1650 }
1651
1652 if self.is_horizontal_idx(e_idx) {
1653 if !self.is_open_idx(e_idx) {
1654 self.trim_horz(e_idx);
1655 }
1656 return;
1657 }
1658
1659 let top_y = self.active_arena[e_idx].top.y;
1660 self.insert_scanline(top_y);
1661 let bot = self.active_arena[e_idx].bot;
1662 self.check_join_left(e_idx, bot, false);
1663 self.check_join_right(e_idx, bot, true);
1664 }
1665
1666 fn find_edge_with_matching_loc_min(&self, e_idx: usize) -> Option<usize> {
1669 let local_min = self.active_arena[e_idx].local_min;
1670
1671 let mut result = self.active_arena[e_idx].next_in_ael;
1673 while let Some(r_idx) = result {
1674 if self.active_arena[r_idx].local_min == local_min {
1675 return Some(r_idx);
1676 }
1677 if !self.is_horizontal_idx(r_idx)
1678 && self.active_arena[e_idx].bot != self.active_arena[r_idx].bot
1679 {
1680 result = None;
1681 break;
1682 }
1683 result = self.active_arena[r_idx].next_in_ael;
1684 }
1685
1686 if result.is_none() {
1688 result = self.active_arena[e_idx].prev_in_ael;
1689 while let Some(r_idx) = result {
1690 if self.active_arena[r_idx].local_min == local_min {
1691 return Some(r_idx);
1692 }
1693 if !self.is_horizontal_idx(r_idx)
1694 && self.active_arena[e_idx].bot != self.active_arena[r_idx].bot
1695 {
1696 return None;
1697 }
1698 result = self.active_arena[r_idx].prev_in_ael;
1699 }
1700 }
1701 result
1702 }
1703
1704 fn check_join_left(&mut self, e_idx: usize, pt: Point64, check_curr_x: bool) {
1709 let prev = self.active_arena[e_idx].prev_in_ael;
1710 let prev_idx = match prev {
1711 Some(p) => p,
1712 None => return,
1713 };
1714
1715 if !is_hot_edge(&self.active_arena[e_idx])
1716 || !is_hot_edge(&self.active_arena[prev_idx])
1717 || self.is_horizontal_idx(e_idx)
1718 || self.is_horizontal_idx(prev_idx)
1719 || self.is_open_idx(e_idx)
1720 || self.is_open_idx(prev_idx)
1721 {
1722 return;
1723 }
1724
1725 let e_top = self.active_arena[e_idx].top;
1726 let p_top = self.active_arena[prev_idx].top;
1727 if (pt.y < e_top.y + 2 || pt.y < p_top.y + 2)
1728 && (self.active_arena[e_idx].bot.y > pt.y || self.active_arena[prev_idx].bot.y > pt.y)
1729 {
1730 return;
1731 }
1732
1733 if check_curr_x {
1734 if perpendic_dist_from_line_sqrd(
1735 pt,
1736 self.active_arena[prev_idx].bot,
1737 self.active_arena[prev_idx].top,
1738 ) > 0.25
1739 {
1740 return;
1741 }
1742 } else if self.active_arena[e_idx].curr_x != self.active_arena[prev_idx].curr_x {
1743 return;
1744 }
1745
1746 if !is_collinear(e_top, pt, p_top) {
1747 return;
1748 }
1749
1750 let e_or = self.active_arena[e_idx].outrec.unwrap();
1751 let p_or = self.active_arena[prev_idx].outrec.unwrap();
1752
1753 if self.outrec_list[e_or].idx == self.outrec_list[p_or].idx {
1754 self.add_local_max_poly(prev_idx, e_idx, pt);
1755 } else if self.outrec_list[e_or].idx < self.outrec_list[p_or].idx {
1756 self.join_outrec_paths(e_idx, prev_idx);
1757 } else {
1758 self.join_outrec_paths(prev_idx, e_idx);
1759 }
1760 self.active_arena[prev_idx].join_with = JoinWith::Right;
1761 self.active_arena[e_idx].join_with = JoinWith::Left;
1762 }
1763
1764 fn check_join_right(&mut self, e_idx: usize, pt: Point64, check_curr_x: bool) {
1767 let next = self.active_arena[e_idx].next_in_ael;
1768 let next_idx = match next {
1769 Some(n) => n,
1770 None => return,
1771 };
1772
1773 if !is_hot_edge(&self.active_arena[e_idx])
1774 || !is_hot_edge(&self.active_arena[next_idx])
1775 || self.is_horizontal_idx(e_idx)
1776 || self.is_horizontal_idx(next_idx)
1777 || self.is_open_idx(e_idx)
1778 || self.is_open_idx(next_idx)
1779 {
1780 return;
1781 }
1782
1783 let e_top = self.active_arena[e_idx].top;
1784 let n_top = self.active_arena[next_idx].top;
1785 if (pt.y < e_top.y + 2 || pt.y < n_top.y + 2)
1786 && (self.active_arena[e_idx].bot.y > pt.y || self.active_arena[next_idx].bot.y > pt.y)
1787 {
1788 return;
1789 }
1790
1791 if check_curr_x {
1792 if perpendic_dist_from_line_sqrd(
1793 pt,
1794 self.active_arena[next_idx].bot,
1795 self.active_arena[next_idx].top,
1796 ) > 0.35
1797 {
1798 return;
1799 }
1800 } else if self.active_arena[e_idx].curr_x != self.active_arena[next_idx].curr_x {
1801 return;
1802 }
1803
1804 if !is_collinear(e_top, pt, n_top) {
1805 return;
1806 }
1807
1808 let e_or = self.active_arena[e_idx].outrec.unwrap();
1809 let n_or = self.active_arena[next_idx].outrec.unwrap();
1810
1811 if self.outrec_list[e_or].idx == self.outrec_list[n_or].idx {
1812 self.add_local_max_poly(e_idx, next_idx, pt);
1813 } else if self.outrec_list[e_or].idx < self.outrec_list[n_or].idx {
1814 self.join_outrec_paths(e_idx, next_idx);
1815 } else {
1816 self.join_outrec_paths(next_idx, e_idx);
1817 }
1818
1819 self.active_arena[e_idx].join_with = JoinWith::Right;
1820 self.active_arena[next_idx].join_with = JoinWith::Left;
1821 }
1822
1823 fn intersect_edges(&mut self, e1_idx: usize, e2_idx: usize, pt: Point64) {
1828 if self.has_open_paths && (self.is_open_idx(e1_idx) || self.is_open_idx(e2_idx)) {
1830 if self.is_open_idx(e1_idx) && self.is_open_idx(e2_idx) {
1831 return;
1832 }
1833 let (edge_o, edge_c) = if self.is_open_idx(e1_idx) {
1834 (e1_idx, e2_idx)
1835 } else {
1836 (e2_idx, e1_idx)
1837 };
1838
1839 if is_joined(&self.active_arena[edge_c]) {
1840 self.split(edge_c, pt);
1841 }
1842
1843 if self.active_arena[edge_c].wind_cnt.abs() != 1 {
1844 return;
1845 }
1846
1847 match self.cliptype {
1848 ClipType::Union => {
1849 if !is_hot_edge(&self.active_arena[edge_c]) {
1850 return;
1851 }
1852 }
1853 _ => {
1854 if self.minima_list[self.active_arena[edge_c].local_min].polytype
1855 == PathType::Subject
1856 {
1857 return;
1858 }
1859 }
1860 }
1861
1862 match self.fillrule {
1863 FillRule::Positive => {
1864 if self.active_arena[edge_c].wind_cnt != 1 {
1865 return;
1866 }
1867 }
1868 FillRule::Negative => {
1869 if self.active_arena[edge_c].wind_cnt != -1 {
1870 return;
1871 }
1872 }
1873 _ => {
1874 if self.active_arena[edge_c].wind_cnt.abs() != 1 {
1875 return;
1876 }
1877 }
1878 }
1879
1880 if is_hot_edge(&self.active_arena[edge_o]) {
1882 self.add_out_pt(edge_o, pt);
1883 if self.is_front(edge_o) {
1884 let or = self.active_arena[edge_o].outrec.unwrap();
1885 self.outrec_list[or].front_edge = None;
1886 } else {
1887 let or = self.active_arena[edge_o].outrec.unwrap();
1888 self.outrec_list[or].back_edge = None;
1889 }
1890 self.active_arena[edge_o].outrec = None;
1891 } else if pt == self.active_arena[edge_o].bot
1892 && pt
1893 == self.vertex_arena
1894 [self.minima_list[self.active_arena[edge_o].local_min].vertex]
1895 .pt
1896 && !is_open_end_vertex(
1897 &self.vertex_arena
1898 [self.minima_list[self.active_arena[edge_o].local_min].vertex],
1899 )
1900 {
1901 let e3 = self.find_edge_with_matching_loc_min(edge_o);
1902 if let Some(e3_idx) = e3 {
1903 if is_hot_edge(&self.active_arena[e3_idx]) {
1904 let e3_or = self.active_arena[e3_idx].outrec.unwrap();
1905 self.active_arena[edge_o].outrec = Some(e3_or);
1906 if self.active_arena[edge_o].wind_dx > 0 {
1907 self.set_sides(e3_or, edge_o, e3_idx);
1908 } else {
1909 self.set_sides(e3_or, e3_idx, edge_o);
1910 }
1911 return;
1912 }
1913 }
1914 self.start_open_path(edge_o, pt);
1915 } else {
1916 self.start_open_path(edge_o, pt);
1917 }
1918 return;
1919 }
1920
1921 if is_joined(&self.active_arena[e1_idx]) {
1923 self.split(e1_idx, pt);
1924 }
1925 if is_joined(&self.active_arena[e2_idx]) {
1926 self.split(e2_idx, pt);
1927 }
1928
1929 let old_e1_windcnt;
1931 let old_e2_windcnt;
1932
1933 if self.is_same_poly_type_idx(e1_idx, e2_idx) {
1934 if self.fillrule == FillRule::EvenOdd {
1935 let tmp = self.active_arena[e1_idx].wind_cnt;
1936 self.active_arena[e1_idx].wind_cnt = self.active_arena[e2_idx].wind_cnt;
1937 self.active_arena[e2_idx].wind_cnt = tmp;
1938 } else {
1939 let e1_wc = self.active_arena[e1_idx].wind_cnt;
1940 let e2_wd = self.active_arena[e2_idx].wind_dx;
1941 let e1_wd = self.active_arena[e1_idx].wind_dx;
1942 if e1_wc + e2_wd == 0 {
1943 self.active_arena[e1_idx].wind_cnt = -e1_wc;
1944 } else {
1945 self.active_arena[e1_idx].wind_cnt = e1_wc + e2_wd;
1946 }
1947 let e2_wc = self.active_arena[e2_idx].wind_cnt;
1948 if e2_wc - e1_wd == 0 {
1949 self.active_arena[e2_idx].wind_cnt = -e2_wc;
1950 } else {
1951 self.active_arena[e2_idx].wind_cnt = e2_wc - e1_wd;
1952 }
1953 }
1954 } else if self.fillrule != FillRule::EvenOdd {
1955 self.active_arena[e1_idx].wind_cnt2 += self.active_arena[e2_idx].wind_dx;
1956 self.active_arena[e2_idx].wind_cnt2 -= self.active_arena[e1_idx].wind_dx;
1957 } else {
1958 let wc2_1 = self.active_arena[e1_idx].wind_cnt2;
1959 self.active_arena[e1_idx].wind_cnt2 = if wc2_1 == 0 { 1 } else { 0 };
1960 let wc2_2 = self.active_arena[e2_idx].wind_cnt2;
1961 self.active_arena[e2_idx].wind_cnt2 = if wc2_2 == 0 { 1 } else { 0 };
1962 }
1963
1964 let fillpos = FillRule::Positive;
1965 match self.fillrule {
1966 FillRule::EvenOdd | FillRule::NonZero => {
1967 old_e1_windcnt = self.active_arena[e1_idx].wind_cnt.abs();
1968 old_e2_windcnt = self.active_arena[e2_idx].wind_cnt.abs();
1969 }
1970 _ => {
1971 if self.fillrule == fillpos {
1972 old_e1_windcnt = self.active_arena[e1_idx].wind_cnt;
1973 old_e2_windcnt = self.active_arena[e2_idx].wind_cnt;
1974 } else {
1975 old_e1_windcnt = -self.active_arena[e1_idx].wind_cnt;
1976 old_e2_windcnt = -self.active_arena[e2_idx].wind_cnt;
1977 }
1978 }
1979 }
1980
1981 let e1_wc_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
1982 let e2_wc_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
1983
1984 if (!is_hot_edge(&self.active_arena[e1_idx]) && !e1_wc_in_01)
1985 || (!is_hot_edge(&self.active_arena[e2_idx]) && !e2_wc_in_01)
1986 {
1987 return;
1988 }
1989
1990 if is_hot_edge(&self.active_arena[e1_idx]) && is_hot_edge(&self.active_arena[e2_idx]) {
1992 if (old_e1_windcnt != 0 && old_e1_windcnt != 1)
1993 || (old_e2_windcnt != 0 && old_e2_windcnt != 1)
1994 || (!self.is_same_poly_type_idx(e1_idx, e2_idx) && self.cliptype != ClipType::Xor)
1995 {
1996 self.add_local_max_poly(e1_idx, e2_idx, pt);
1997 } else if self.is_front(e1_idx)
1998 || self.active_arena[e1_idx].outrec == self.active_arena[e2_idx].outrec
1999 {
2000 self.add_local_max_poly(e1_idx, e2_idx, pt);
2001 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2002 } else {
2003 self.add_out_pt(e1_idx, pt);
2004 self.add_out_pt(e2_idx, pt);
2005 self.swap_outrecs(e1_idx, e2_idx);
2006 }
2007 } else if is_hot_edge(&self.active_arena[e1_idx]) {
2008 self.add_out_pt(e1_idx, pt);
2009 self.swap_outrecs(e1_idx, e2_idx);
2010 } else if is_hot_edge(&self.active_arena[e2_idx]) {
2011 self.add_out_pt(e2_idx, pt);
2012 self.swap_outrecs(e1_idx, e2_idx);
2013 } else {
2014 let e1wc2;
2016 let e2wc2;
2017 match self.fillrule {
2018 FillRule::EvenOdd | FillRule::NonZero => {
2019 e1wc2 = self.active_arena[e1_idx].wind_cnt2.abs() as i64;
2020 e2wc2 = self.active_arena[e2_idx].wind_cnt2.abs() as i64;
2021 }
2022 _ => {
2023 if self.fillrule == fillpos {
2024 e1wc2 = self.active_arena[e1_idx].wind_cnt2 as i64;
2025 e2wc2 = self.active_arena[e2_idx].wind_cnt2 as i64;
2026 } else {
2027 e1wc2 = -(self.active_arena[e1_idx].wind_cnt2 as i64);
2028 e2wc2 = -(self.active_arena[e2_idx].wind_cnt2 as i64);
2029 }
2030 }
2031 }
2032
2033 if !self.is_same_poly_type_idx(e1_idx, e2_idx) {
2034 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2035 } else if old_e1_windcnt == 1 && old_e2_windcnt == 1 {
2036 match self.cliptype {
2037 ClipType::Union => {
2038 if e1wc2 <= 0 && e2wc2 <= 0 {
2039 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2040 }
2041 }
2042 ClipType::Difference => {
2043 if (self.get_poly_type_idx(e1_idx) == PathType::Clip
2044 && e1wc2 > 0
2045 && e2wc2 > 0)
2046 || (self.get_poly_type_idx(e1_idx) == PathType::Subject
2047 && e1wc2 <= 0
2048 && e2wc2 <= 0)
2049 {
2050 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2051 }
2052 }
2053 ClipType::Xor => {
2054 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2055 }
2056 _ => {
2057 if e1wc2 > 0 && e2wc2 > 0 {
2059 self.add_local_min_poly(e1_idx, e2_idx, pt, false);
2060 }
2061 }
2062 }
2063 }
2064 }
2065 }
2066
2067 fn insert_local_minima_into_ael(&mut self, bot_y: i64) {
2072 while let Some(loc_min_idx) = self.pop_local_minima(bot_y) {
2073 let vert_idx = self.minima_list[loc_min_idx].vertex;
2074 let vert_flags = self.vertex_arena[vert_idx].flags;
2075 let vert_pt = self.vertex_arena[vert_idx].pt;
2076
2077 let left_bound_opt = if (vert_flags & VertexFlags::OPEN_START) != VertexFlags::EMPTY {
2079 None
2080 } else {
2081 let lb_idx = self.active_arena.len();
2082 let mut lb = Active::new();
2083 lb.bot = vert_pt;
2084 lb.curr_x = vert_pt.x;
2085 lb.wind_dx = -1;
2086 lb.vertex_top = self.vertex_arena[vert_idx].prev; lb.top = self.vertex_arena[lb.vertex_top].pt;
2088 lb.local_min = loc_min_idx;
2089 set_dx(&mut lb);
2090 self.active_arena.push(lb);
2091 Some(lb_idx)
2092 };
2093
2094 let right_bound_opt = if (vert_flags & VertexFlags::OPEN_END) != VertexFlags::EMPTY {
2096 None
2097 } else {
2098 let rb_idx = self.active_arena.len();
2099 let mut rb = Active::new();
2100 rb.bot = vert_pt;
2101 rb.curr_x = vert_pt.x;
2102 rb.wind_dx = 1;
2103 rb.vertex_top = self.vertex_arena[vert_idx].next; rb.top = self.vertex_arena[rb.vertex_top].pt;
2105 rb.local_min = loc_min_idx;
2106 set_dx(&mut rb);
2107 self.active_arena.push(rb);
2108 Some(rb_idx)
2109 };
2110
2111 let (mut left_bound, mut right_bound) = (left_bound_opt, right_bound_opt);
2113
2114 if let (Some(lb), Some(rb)) = (left_bound, right_bound) {
2115 if self.is_horizontal_idx(lb) {
2116 if is_heading_right_horz(&self.active_arena[lb]) {
2117 std::mem::swap(&mut left_bound, &mut right_bound);
2118 }
2119 } else if self.is_horizontal_idx(rb) {
2120 if is_heading_left_horz(&self.active_arena[rb]) {
2121 std::mem::swap(&mut left_bound, &mut right_bound);
2122 }
2123 } else if self.active_arena[lb].dx < self.active_arena[rb].dx {
2124 std::mem::swap(&mut left_bound, &mut right_bound);
2125 }
2126 } else if left_bound.is_none() {
2127 left_bound = right_bound;
2128 right_bound = None;
2129 }
2130
2131 let lb_idx = left_bound.unwrap();
2132 self.active_arena[lb_idx].is_left_bound = true;
2133 self.insert_left_edge(lb_idx);
2134
2135 let contributing = if self.is_open_idx(lb_idx) {
2136 self.set_wind_count_for_open_path_edge(lb_idx);
2137 self.is_contributing_open(lb_idx)
2138 } else {
2139 self.set_wind_count_for_closed_path_edge(lb_idx);
2140 self.is_contributing_closed(lb_idx)
2141 };
2142
2143 if let Some(rb_idx) = right_bound {
2144 self.active_arena[rb_idx].is_left_bound = false;
2145 self.active_arena[rb_idx].wind_cnt = self.active_arena[lb_idx].wind_cnt;
2146 self.active_arena[rb_idx].wind_cnt2 = self.active_arena[lb_idx].wind_cnt2;
2147 self.insert_right_edge(lb_idx, rb_idx);
2148
2149 if contributing {
2150 let bot = self.active_arena[lb_idx].bot;
2151 self.add_local_min_poly(lb_idx, rb_idx, bot, true);
2152 if !self.is_horizontal_idx(lb_idx) {
2153 let bot = self.active_arena[lb_idx].bot;
2154 self.check_join_left(lb_idx, bot, false);
2155 }
2156 }
2157
2158 while let Some(next) = self.active_arena[rb_idx].next_in_ael {
2160 if !is_valid_ael_order(
2161 &self.active_arena[next],
2162 &self.active_arena[rb_idx],
2163 &self.vertex_arena,
2164 &self.minima_list,
2165 ) {
2166 break;
2167 }
2168 let bot = self.active_arena[rb_idx].bot;
2169 self.intersect_edges(rb_idx, next, bot);
2170 self.swap_positions_in_ael(rb_idx, next);
2171 }
2172
2173 if self.is_horizontal_idx(rb_idx) {
2174 self.push_horz(rb_idx);
2175 } else {
2176 let bot = self.active_arena[rb_idx].bot;
2177 self.check_join_right(rb_idx, bot, false);
2178 let top_y = self.active_arena[rb_idx].top.y;
2179 self.insert_scanline(top_y);
2180 }
2181 } else if contributing {
2182 let bot = self.active_arena[lb_idx].bot;
2183 self.start_open_path(lb_idx, bot);
2184 }
2185
2186 if self.is_horizontal_idx(lb_idx) {
2187 self.push_horz(lb_idx);
2188 } else {
2189 let top_y = self.active_arena[lb_idx].top.y;
2190 self.insert_scanline(top_y);
2191 }
2192 }
2193 }
2194
2195 fn reset_horz_direction(&self, horz_idx: usize, max_vertex: Option<usize>) -> (i64, i64, bool) {
2200 let horz = &self.active_arena[horz_idx];
2201 if horz.bot.x == horz.top.x {
2202 let horz_left = horz.curr_x;
2203 let horz_right = horz.curr_x;
2204 let mut e = horz.next_in_ael;
2205 while let Some(e_idx) = e {
2206 if Some(self.active_arena[e_idx].vertex_top) == max_vertex {
2207 return (horz_left, horz_right, true);
2208 }
2209 e = self.active_arena[e_idx].next_in_ael;
2210 }
2211 (horz_left, horz_right, false)
2212 } else if horz.curr_x < horz.top.x {
2213 (horz.curr_x, horz.top.x, true)
2214 } else {
2215 (horz.top.x, horz.curr_x, false)
2216 }
2217 }
2218
2219 fn do_horizontal(&mut self, horz_idx: usize) {
2222 let horz_is_open = self.is_open_idx(horz_idx);
2223 let y = self.active_arena[horz_idx].bot.y;
2224
2225 let vertex_max = if horz_is_open {
2226 get_curr_y_maxima_vertex_open(&self.active_arena[horz_idx], &self.vertex_arena)
2227 } else {
2228 get_curr_y_maxima_vertex(&self.active_arena[horz_idx], &self.vertex_arena)
2229 };
2230
2231 let (mut horz_left, mut horz_right, mut is_left_to_right) =
2232 self.reset_horz_direction(horz_idx, vertex_max);
2233
2234 if is_hot_edge(&self.active_arena[horz_idx]) {
2235 let curr_x = self.active_arena[horz_idx].curr_x;
2236 let op = self.add_out_pt(horz_idx, Point64::new(curr_x, y));
2237 let or = self.outpt_arena[op].outrec;
2238 if !self.outrec_list[or].is_open {
2239 self.add_trial_horz_join(op);
2240 }
2241 }
2242
2243 loop {
2244 let e_start = if is_left_to_right {
2245 self.active_arena[horz_idx].next_in_ael
2246 } else {
2247 self.active_arena[horz_idx].prev_in_ael
2248 };
2249
2250 let mut e_opt = e_start;
2251 while let Some(e_idx) = e_opt {
2252 if Some(self.active_arena[e_idx].vertex_top) == vertex_max {
2254 if is_hot_edge(&self.active_arena[horz_idx])
2255 && is_joined(&self.active_arena[e_idx])
2256 {
2257 let top = self.active_arena[e_idx].top;
2258 self.split(e_idx, top);
2259 }
2260
2261 if is_hot_edge(&self.active_arena[horz_idx]) {
2262 while Some(self.active_arena[horz_idx].vertex_top) != vertex_max {
2263 let top = self.active_arena[horz_idx].top;
2264 self.add_out_pt(horz_idx, top);
2265 self.update_edge_into_ael(horz_idx);
2266 }
2267 if is_left_to_right {
2268 let top = self.active_arena[horz_idx].top;
2269 self.add_local_max_poly(horz_idx, e_idx, top);
2270 } else {
2271 let top = self.active_arena[horz_idx].top;
2272 self.add_local_max_poly(e_idx, horz_idx, top);
2273 }
2274 }
2275 self.delete_from_ael(e_idx);
2276 self.delete_from_ael(horz_idx);
2277 return;
2278 }
2279
2280 if vertex_max != Some(self.active_arena[horz_idx].vertex_top)
2282 || self.is_open_end_idx(horz_idx)
2283 {
2284 if (is_left_to_right && self.active_arena[e_idx].curr_x > horz_right)
2285 || (!is_left_to_right && self.active_arena[e_idx].curr_x < horz_left)
2286 {
2287 break;
2288 }
2289
2290 if self.active_arena[e_idx].curr_x == self.active_arena[horz_idx].top.x
2291 && !self.is_horizontal_idx(e_idx)
2292 {
2293 let nv_idx = self.next_vertex_idx(horz_idx);
2294 let nv_pt = self.vertex_arena[nv_idx].pt;
2295
2296 if is_left_to_right {
2297 if self.is_open_idx(e_idx)
2298 && !self.is_same_poly_type_idx(e_idx, horz_idx)
2299 && !is_hot_edge(&self.active_arena[e_idx])
2300 {
2301 if top_x(&self.active_arena[e_idx], nv_pt.y) > nv_pt.x {
2302 break;
2303 }
2304 } else if top_x(&self.active_arena[e_idx], nv_pt.y) >= nv_pt.x {
2305 break;
2306 }
2307 } else if self.is_open_idx(e_idx)
2308 && !self.is_same_poly_type_idx(e_idx, horz_idx)
2309 && !is_hot_edge(&self.active_arena[e_idx])
2310 {
2311 if top_x(&self.active_arena[e_idx], nv_pt.y) < nv_pt.x {
2312 break;
2313 }
2314 } else if top_x(&self.active_arena[e_idx], nv_pt.y) <= nv_pt.x {
2315 break;
2316 }
2317 }
2318 }
2319
2320 let pt = Point64::new(
2321 self.active_arena[e_idx].curr_x,
2322 self.active_arena[horz_idx].bot.y,
2323 );
2324 if is_left_to_right {
2325 self.intersect_edges(horz_idx, e_idx, pt);
2326 self.swap_positions_in_ael(horz_idx, e_idx);
2327 let pt2 = pt;
2328 self.check_join_left(e_idx, pt2, false);
2329 self.active_arena[horz_idx].curr_x = self.active_arena[e_idx].curr_x;
2330 e_opt = self.active_arena[horz_idx].next_in_ael;
2331 } else {
2332 self.intersect_edges(e_idx, horz_idx, pt);
2333 self.swap_positions_in_ael(e_idx, horz_idx);
2334 let pt2 = pt;
2335 self.check_join_right(e_idx, pt2, false);
2336 self.active_arena[horz_idx].curr_x = self.active_arena[e_idx].curr_x;
2337 e_opt = self.active_arena[horz_idx].prev_in_ael;
2338 }
2339
2340 if self.active_arena[horz_idx].outrec.is_some() {
2341 if let Some(last_op) = get_last_op(
2342 horz_idx,
2343 &self.active_arena,
2344 &self.outrec_list,
2345 &self.outpt_arena,
2346 ) {
2347 self.add_trial_horz_join(last_op);
2348 }
2349 }
2350 }
2351
2352 if horz_is_open && self.is_open_end_idx(horz_idx) {
2354 if is_hot_edge(&self.active_arena[horz_idx]) {
2355 let top = self.active_arena[horz_idx].top;
2356 self.add_out_pt(horz_idx, top);
2357 if self.is_front(horz_idx) {
2358 let or = self.active_arena[horz_idx].outrec.unwrap();
2359 self.outrec_list[or].front_edge = None;
2360 } else {
2361 let or = self.active_arena[horz_idx].outrec.unwrap();
2362 self.outrec_list[or].back_edge = None;
2363 }
2364 self.active_arena[horz_idx].outrec = None;
2365 }
2366 self.delete_from_ael(horz_idx);
2367 return;
2368 }
2369
2370 let nv_idx = self.next_vertex_idx(horz_idx);
2371 if self.vertex_arena[nv_idx].pt.y != self.active_arena[horz_idx].top.y {
2372 break;
2373 }
2374
2375 if is_hot_edge(&self.active_arena[horz_idx]) {
2377 let top = self.active_arena[horz_idx].top;
2378 self.add_out_pt(horz_idx, top);
2379 }
2380 self.update_edge_into_ael(horz_idx);
2381
2382 let result = self.reset_horz_direction(horz_idx, vertex_max);
2383 horz_left = result.0;
2384 horz_right = result.1;
2385 is_left_to_right = result.2;
2386 }
2387
2388 if is_hot_edge(&self.active_arena[horz_idx]) {
2389 let top = self.active_arena[horz_idx].top;
2390 let op = self.add_out_pt(horz_idx, top);
2391 self.add_trial_horz_join(op);
2392 }
2393
2394 self.update_edge_into_ael(horz_idx);
2395 }
2396
2397 fn add_new_intersect_node(&mut self, e1_idx: usize, e2_idx: usize, top_y: i64) {
2402 let e1 = &self.active_arena[e1_idx];
2403 let e2 = &self.active_arena[e2_idx];
2404 let mut ip = Point64::new(e1.curr_x, top_y);
2405 get_segment_intersect_pt(e1.bot, e1.top, e2.bot, e2.top, &mut ip);
2406
2407 if ip.y > self.bot_y || ip.y < top_y {
2408 let abs_dx1 = e1.dx.abs();
2409 let abs_dx2 = e2.dx.abs();
2410 if abs_dx1 > 100.0 && abs_dx2 > 100.0 {
2411 if abs_dx1 > abs_dx2 {
2412 ip = get_closest_point_on_segment(ip, e1.bot, e1.top);
2413 } else {
2414 ip = get_closest_point_on_segment(ip, e2.bot, e2.top);
2415 }
2416 } else if abs_dx1 > 100.0 {
2417 ip = get_closest_point_on_segment(ip, e1.bot, e1.top);
2418 } else if abs_dx2 > 100.0 {
2419 ip = get_closest_point_on_segment(ip, e2.bot, e2.top);
2420 } else {
2421 if ip.y < top_y {
2422 ip.y = top_y;
2423 } else {
2424 ip.y = self.bot_y;
2425 }
2426 if abs_dx1 < abs_dx2 {
2427 ip.x = top_x(&self.active_arena[e1_idx], ip.y);
2428 } else {
2429 ip.x = top_x(&self.active_arena[e2_idx], ip.y);
2430 }
2431 }
2432 }
2433 self.intersect_nodes
2434 .push(IntersectNode::with_edges(e1_idx, e2_idx, ip));
2435 }
2436
2437 fn build_intersect_list(&mut self, top_y: i64) -> bool {
2440 if self.actives.is_none() {
2441 return false;
2442 }
2443 let actives_idx = self.actives.unwrap();
2444 if self.active_arena[actives_idx].next_in_ael.is_none() {
2445 return false;
2446 }
2447
2448 self.adjust_curr_x_and_copy_to_sel(top_y);
2449
2450 let mut left_opt = self.sel;
2451 if left_opt.is_none() || self.active_arena[left_opt.unwrap()].jump.is_none() {
2453 return !self.intersect_nodes.is_empty();
2454 }
2455
2456 while let Some(left_idx) = left_opt {
2457 if self.active_arena[left_idx].jump.is_none() {
2458 break;
2459 }
2460
2461 let mut prev_base: Option<usize> = None;
2462 let mut left_inner = left_opt;
2463
2464 while let Some(li) = left_inner {
2465 if self.active_arena[li].jump.is_none() {
2466 break;
2467 }
2468
2469 let mut curr_base = li;
2470 let right_idx = self.active_arena[li].jump.unwrap();
2471 let mut l_end = right_idx;
2472 let r_end = self.active_arena[right_idx].jump;
2473 self.active_arena[li].jump = r_end;
2474
2475 let mut left_scan = li;
2476 let mut right_scan = right_idx;
2477
2478 while left_scan != l_end && right_scan != r_end.unwrap_or(NONE) {
2479 if self.active_arena[right_scan].curr_x < self.active_arena[left_scan].curr_x {
2480 let mut tmp = self.active_arena[right_scan].prev_in_sel;
2481 while let Some(tmp_idx) = tmp {
2482 self.add_new_intersect_node(tmp_idx, right_scan, top_y);
2483 if tmp_idx == left_scan {
2484 break;
2485 }
2486 tmp = self.active_arena[tmp_idx].prev_in_sel;
2487 }
2488
2489 let tmp_idx = right_scan;
2490 right_scan =
2491 extract_from_sel(tmp_idx, &mut self.active_arena).unwrap_or(NONE);
2492 l_end = right_scan;
2493
2494 insert1_before2_in_sel(tmp_idx, left_scan, &mut self.active_arena);
2495 if left_scan == curr_base {
2496 curr_base = tmp_idx;
2497 self.active_arena[curr_base].jump = r_end;
2498 if let Some(pb) = prev_base {
2499 self.active_arena[pb].jump = Some(curr_base);
2500 } else {
2501 self.sel = Some(curr_base);
2502 }
2503 }
2504 } else {
2505 left_scan = self.active_arena[left_scan].next_in_sel.unwrap_or(NONE);
2506 }
2507 }
2508
2509 prev_base = Some(curr_base);
2510 left_inner = r_end;
2511 }
2512
2513 left_opt = self.sel;
2514 }
2515
2516 !self.intersect_nodes.is_empty()
2517 }
2518
2519 fn do_intersections(&mut self, top_y: i64) {
2522 if self.build_intersect_list(top_y) {
2523 self.process_intersect_list();
2524 self.intersect_nodes.clear();
2525 }
2526 }
2527
2528 fn process_intersect_list(&mut self) {
2531 self.intersect_nodes.sort_by(intersect_list_sort);
2533
2534 let len = self.intersect_nodes.len();
2535 for i in 0..len {
2536 if !edges_adjacent_in_ael(&self.intersect_nodes[i], &self.active_arena) {
2538 let mut j = i + 1;
2539 while j < len
2540 && !edges_adjacent_in_ael(&self.intersect_nodes[j], &self.active_arena)
2541 {
2542 j += 1;
2543 }
2544 if j < len {
2545 self.intersect_nodes.swap(i, j);
2546 }
2547 }
2548
2549 let e1 = self.intersect_nodes[i].edge1;
2550 let e2 = self.intersect_nodes[i].edge2;
2551 let pt = self.intersect_nodes[i].pt;
2552
2553 self.intersect_edges(e1, e2, pt);
2554 self.swap_positions_in_ael(e1, e2);
2555
2556 self.active_arena[e1].curr_x = pt.x;
2557 self.active_arena[e2].curr_x = pt.x;
2558 self.check_join_left(e2, pt, true);
2559 self.check_join_right(e1, pt, true);
2560 }
2561 }
2562
2563 fn do_top_of_scanbeam(&mut self, y: i64) {
2568 self.sel = None;
2569 let mut e_opt = self.actives;
2570 while let Some(e_idx) = e_opt {
2571 if self.active_arena[e_idx].top.y == y {
2572 self.active_arena[e_idx].curr_x = self.active_arena[e_idx].top.x;
2573 if self.is_maxima_idx(e_idx) {
2574 e_opt = self.do_maxima(e_idx);
2575 continue;
2576 } else {
2577 if is_hot_edge(&self.active_arena[e_idx]) {
2578 let top = self.active_arena[e_idx].top;
2579 self.add_out_pt(e_idx, top);
2580 }
2581 self.update_edge_into_ael(e_idx);
2582 if self.is_horizontal_idx(e_idx) {
2583 self.push_horz(e_idx);
2584 }
2585 }
2586 } else {
2587 self.active_arena[e_idx].curr_x = top_x(&self.active_arena[e_idx], y);
2588 }
2589 e_opt = self.active_arena[e_idx].next_in_ael;
2590 }
2591 }
2592
2593 fn do_maxima(&mut self, e_idx: usize) -> Option<usize> {
2596 let prev_e = self.active_arena[e_idx].prev_in_ael;
2597 let mut next_e = self.active_arena[e_idx].next_in_ael;
2598
2599 if self.is_open_end_idx(e_idx) {
2600 if is_hot_edge(&self.active_arena[e_idx]) {
2601 let top = self.active_arena[e_idx].top;
2602 self.add_out_pt(e_idx, top);
2603 }
2604 if !self.is_horizontal_idx(e_idx) {
2605 if is_hot_edge(&self.active_arena[e_idx]) {
2606 if self.is_front(e_idx) {
2607 let or = self.active_arena[e_idx].outrec.unwrap();
2608 self.outrec_list[or].front_edge = None;
2609 } else {
2610 let or = self.active_arena[e_idx].outrec.unwrap();
2611 self.outrec_list[or].back_edge = None;
2612 }
2613 self.active_arena[e_idx].outrec = None;
2614 }
2615 self.delete_from_ael(e_idx);
2616 }
2617 return next_e;
2618 }
2619
2620 let max_pair = get_maxima_pair(&self.active_arena[e_idx], &self.active_arena);
2621 if max_pair.is_none() {
2622 return next_e;
2623 }
2624 let max_pair_idx = max_pair.unwrap();
2625
2626 if is_joined(&self.active_arena[e_idx]) {
2627 let top = self.active_arena[e_idx].top;
2628 self.split(e_idx, top);
2629 }
2630 if is_joined(&self.active_arena[max_pair_idx]) {
2631 let top = self.active_arena[max_pair_idx].top;
2632 self.split(max_pair_idx, top);
2633 }
2634
2635 while next_e != Some(max_pair_idx) {
2637 if let Some(ne_idx) = next_e {
2638 let top = self.active_arena[e_idx].top;
2639 self.intersect_edges(e_idx, ne_idx, top);
2640 self.swap_positions_in_ael(e_idx, ne_idx);
2641 next_e = self.active_arena[e_idx].next_in_ael;
2642 } else {
2643 break;
2644 }
2645 }
2646
2647 if self.is_open_idx(e_idx) {
2648 if is_hot_edge(&self.active_arena[e_idx]) {
2649 let top = self.active_arena[e_idx].top;
2650 self.add_local_max_poly(e_idx, max_pair_idx, top);
2651 }
2652 self.delete_from_ael(max_pair_idx);
2653 self.delete_from_ael(e_idx);
2654 return if let Some(pe) = prev_e {
2655 self.active_arena[pe].next_in_ael
2656 } else {
2657 self.actives
2658 };
2659 }
2660
2661 if is_hot_edge(&self.active_arena[e_idx]) {
2663 let top = self.active_arena[e_idx].top;
2664 self.add_local_max_poly(e_idx, max_pair_idx, top);
2665 }
2666
2667 self.delete_from_ael(e_idx);
2668 self.delete_from_ael(max_pair_idx);
2669 if let Some(pe) = prev_e {
2670 self.active_arena[pe].next_in_ael
2671 } else {
2672 self.actives
2673 }
2674 }
2675
2676 #[allow(dead_code)]
2680 fn set_horz_seg_heading_forward(&mut self, hs_idx: usize, op_p: usize, op_n: usize) -> bool {
2681 if self.outpt_arena[op_p].pt.x == self.outpt_arena[op_n].pt.x {
2682 return false;
2683 }
2684 if self.outpt_arena[op_p].pt.x < self.outpt_arena[op_n].pt.x {
2685 self.horz_seg_list[hs_idx].left_op = Some(op_p);
2686 self.horz_seg_list[hs_idx].right_op = Some(op_n);
2687 self.horz_seg_list[hs_idx].left_to_right = true;
2688 } else {
2689 self.horz_seg_list[hs_idx].left_op = Some(op_n);
2690 self.horz_seg_list[hs_idx].right_op = Some(op_p);
2691 self.horz_seg_list[hs_idx].left_to_right = false;
2692 }
2693 true
2694 }
2695
2696 fn convert_horz_segs_to_joins(&mut self) {
2699 let mut valid_count = 0;
2701 for i in 0..self.horz_seg_list.len() {
2702 let op = match self.horz_seg_list[i].left_op {
2703 Some(op) => op,
2704 None => {
2705 continue;
2706 }
2707 };
2708 let or_idx = self.outpt_arena[op].outrec;
2709 let real_or = get_real_outrec(&self.outrec_list, or_idx);
2710 if real_or.is_none() {
2711 continue;
2712 }
2713 let real_or_idx = real_or.unwrap();
2714 let has_edges = self.outrec_list[real_or_idx].front_edge.is_some();
2715 let curr_y = self.outpt_arena[op].pt.y;
2716
2717 let mut op_p = op;
2718 let mut op_n = op;
2719
2720 if has_edges {
2721 let op_a = self.outrec_list[real_or_idx].pts.unwrap();
2722 let op_z = self.outpt_arena[op_a].next;
2723 while op_p != op_z && self.outpt_arena[self.outpt_arena[op_p].prev].pt.y == curr_y {
2724 op_p = self.outpt_arena[op_p].prev;
2725 }
2726 while op_n != op_a && self.outpt_arena[self.outpt_arena[op_n].next].pt.y == curr_y {
2727 op_n = self.outpt_arena[op_n].next;
2728 }
2729 } else {
2730 while self.outpt_arena[op_p].prev != op_n
2731 && self.outpt_arena[self.outpt_arena[op_p].prev].pt.y == curr_y
2732 {
2733 op_p = self.outpt_arena[op_p].prev;
2734 }
2735 while self.outpt_arena[op_n].next != op_p
2736 && self.outpt_arena[self.outpt_arena[op_n].next].pt.y == curr_y
2737 {
2738 op_n = self.outpt_arena[op_n].next;
2739 }
2740 }
2741
2742 if self.outpt_arena[op_p].pt.x == self.outpt_arena[op_n].pt.x {
2743 self.horz_seg_list[i].right_op = None;
2744 continue;
2745 }
2746
2747 if self.outpt_arena[op_p].pt.x < self.outpt_arena[op_n].pt.x {
2749 self.horz_seg_list[i].left_op = Some(op_p);
2750 self.horz_seg_list[i].right_op = Some(op_n);
2751 self.horz_seg_list[i].left_to_right = true;
2752 } else {
2753 self.horz_seg_list[i].left_op = Some(op_n);
2754 self.horz_seg_list[i].right_op = Some(op_p);
2755 self.horz_seg_list[i].left_to_right = false;
2756 }
2757
2758 let left_op = self.horz_seg_list[i].left_op.unwrap();
2760 if self.outpt_arena[left_op].horz.is_some() {
2761 self.horz_seg_list[i].right_op = None;
2762 continue;
2763 }
2764
2765 self.outpt_arena[left_op].horz = Some(i);
2766 valid_count += 1;
2767 }
2768
2769 if valid_count < 2 {
2770 return;
2771 }
2772
2773 self.horz_seg_list.sort_by(|a, b| {
2775 let a_valid = a.right_op.is_some();
2776 let b_valid = b.right_op.is_some();
2777 if a_valid != b_valid {
2778 return if a_valid {
2779 std::cmp::Ordering::Less
2780 } else {
2781 std::cmp::Ordering::Greater
2782 };
2783 }
2784 if !a_valid {
2785 return std::cmp::Ordering::Equal;
2786 }
2787 let a_x = self.outpt_arena[a.left_op.unwrap()].pt.x;
2788 let b_x = self.outpt_arena[b.left_op.unwrap()].pt.x;
2789 a_x.cmp(&b_x)
2790 });
2791
2792 for i in 0..self.horz_seg_list.len() {
2794 if self.horz_seg_list[i].right_op.is_none() {
2795 break;
2796 }
2797 for j in (i + 1)..self.horz_seg_list.len() {
2798 if self.horz_seg_list[j].right_op.is_none() {
2799 break;
2800 }
2801
2802 let hs1_left_x = self.outpt_arena[self.horz_seg_list[i].left_op.unwrap()]
2803 .pt
2804 .x;
2805 let hs1_right_x = self.outpt_arena[self.horz_seg_list[i].right_op.unwrap()]
2806 .pt
2807 .x;
2808 let hs2_left_x = self.outpt_arena[self.horz_seg_list[j].left_op.unwrap()]
2809 .pt
2810 .x;
2811 let hs2_right_x = self.outpt_arena[self.horz_seg_list[j].right_op.unwrap()]
2812 .pt
2813 .x;
2814
2815 if hs2_left_x >= hs1_right_x
2816 || self.horz_seg_list[j].left_to_right == self.horz_seg_list[i].left_to_right
2817 || hs2_right_x <= hs1_left_x
2818 {
2819 continue;
2820 }
2821
2822 let curr_y = self.outpt_arena[self.horz_seg_list[i].left_op.unwrap()]
2823 .pt
2824 .y;
2825 let hs1_ltr = self.horz_seg_list[i].left_to_right;
2826
2827 if hs1_ltr {
2828 let mut lo1 = self.horz_seg_list[i].left_op.unwrap();
2830 while self.outpt_arena[self.outpt_arena[lo1].next].pt.y == curr_y
2831 && self.outpt_arena[self.outpt_arena[lo1].next].pt.x <= hs2_left_x
2832 {
2833 lo1 = self.outpt_arena[lo1].next;
2834 }
2835 self.horz_seg_list[i].left_op = Some(lo1);
2836 let mut lo2 = self.horz_seg_list[j].left_op.unwrap();
2837 while self.outpt_arena[self.outpt_arena[lo2].prev].pt.y == curr_y
2838 && self.outpt_arena[self.outpt_arena[lo2].prev].pt.x
2839 <= self.outpt_arena[lo1].pt.x
2840 {
2841 lo2 = self.outpt_arena[lo2].prev;
2842 }
2843 self.horz_seg_list[j].left_op = Some(lo2);
2844 let dup1 = self.duplicate_op(lo1, true);
2845 let dup2 = self.duplicate_op(lo2, false);
2846 self.horz_join_list.push(HorzJoin::with_ops(dup1, dup2));
2847 } else {
2848 let mut lo1 = self.horz_seg_list[i].left_op.unwrap();
2850 while self.outpt_arena[self.outpt_arena[lo1].prev].pt.y == curr_y
2851 && self.outpt_arena[self.outpt_arena[lo1].prev].pt.x <= hs2_left_x
2852 {
2853 lo1 = self.outpt_arena[lo1].prev;
2854 }
2855 self.horz_seg_list[i].left_op = Some(lo1);
2856 let mut lo2 = self.horz_seg_list[j].left_op.unwrap();
2857 while self.outpt_arena[self.outpt_arena[lo2].next].pt.y == curr_y
2858 && self.outpt_arena[self.outpt_arena[lo2].next].pt.x
2859 <= self.outpt_arena[lo1].pt.x
2860 {
2861 lo2 = self.outpt_arena[lo2].next;
2862 }
2863 self.horz_seg_list[j].left_op = Some(lo2);
2864 let dup1 = self.duplicate_op(lo2, true);
2865 let dup2 = self.duplicate_op(lo1, false);
2866 self.horz_join_list.push(HorzJoin::with_ops(dup1, dup2));
2867 }
2868 }
2869 }
2870 }
2871
2872 fn process_horz_joins(&mut self) {
2875 for idx in 0..self.horz_join_list.len() {
2876 let op1 = match self.horz_join_list[idx].op1 {
2877 Some(op) => op,
2878 None => continue,
2879 };
2880 let op2 = match self.horz_join_list[idx].op2 {
2881 Some(op) => op,
2882 None => continue,
2883 };
2884
2885 let or1 = get_real_outrec(&self.outrec_list, self.outpt_arena[op1].outrec);
2886 let or2 = get_real_outrec(&self.outrec_list, self.outpt_arena[op2].outrec);
2887 if or1.is_none() || or2.is_none() {
2888 continue;
2889 }
2890 let or1 = or1.unwrap();
2891 let or2_orig = or2.unwrap();
2892
2893 let op1b = self.outpt_arena[op1].next;
2894 let op2b = self.outpt_arena[op2].prev;
2895 self.outpt_arena[op1].next = op2;
2896 self.outpt_arena[op2].prev = op1;
2897 self.outpt_arena[op1b].prev = op2b;
2898 self.outpt_arena[op2b].next = op1b;
2899
2900 if or1 == or2_orig {
2901 let or2_new = self.new_out_rec();
2903 self.outrec_list[or2_new].pts = Some(op1b);
2904 fix_outrec_pts(or2_new, &self.outrec_list, &mut self.outpt_arena);
2905
2906 if self.outrec_list[or1]
2907 .pts
2908 .map(|p| self.outpt_arena[p].outrec)
2909 == Some(or2_new)
2910 {
2911 self.outrec_list[or1].pts = Some(op1);
2912 self.outpt_arena[op1].outrec = or1;
2913 }
2914
2915 if self.using_polytree {
2916 if path2_contains_path1_outpt(
2917 self.outrec_list[or1].pts.unwrap(),
2918 self.outrec_list[or2_new].pts.unwrap(),
2919 &self.outpt_arena,
2920 ) {
2921 let or1_pts = self.outrec_list[or1].pts;
2922 let or2_pts = self.outrec_list[or2_new].pts;
2923 self.outrec_list[or1].pts = or2_pts;
2924 self.outrec_list[or2_new].pts = or1_pts;
2925 fix_outrec_pts(or1, &self.outrec_list, &mut self.outpt_arena);
2926 fix_outrec_pts(or2_new, &self.outrec_list, &mut self.outpt_arena);
2927 self.outrec_list[or2_new].owner = Some(or1);
2928 } else if path2_contains_path1_outpt(
2929 self.outrec_list[or2_new].pts.unwrap(),
2930 self.outrec_list[or1].pts.unwrap(),
2931 &self.outpt_arena,
2932 ) {
2933 self.outrec_list[or2_new].owner = Some(or1);
2934 } else {
2935 self.outrec_list[or2_new].owner = self.outrec_list[or1].owner;
2936 }
2937
2938 if self.outrec_list[or1].splits.is_none() {
2939 self.outrec_list[or1].splits = Some(Vec::new());
2940 }
2941 self.outrec_list[or1].splits.as_mut().unwrap().push(or2_new);
2942 } else {
2943 self.outrec_list[or2_new].owner = Some(or1);
2944 }
2945 } else {
2946 self.outrec_list[or2_orig].pts = None;
2948 if self.using_polytree {
2949 set_owner(&mut self.outrec_list, or2_orig, or1);
2950 if self.outrec_list[or2_orig].splits.is_some() {
2951 move_splits(&mut self.outrec_list, or2_orig, or1);
2952 }
2953 } else {
2954 self.outrec_list[or2_orig].owner = Some(or1);
2955 }
2956 }
2957 }
2958 }
2959
2960 pub fn clean_collinear(&mut self, outrec_idx: usize) {
2965 let real_or = get_real_outrec(&self.outrec_list, outrec_idx);
2966 let or_idx = match real_or {
2967 Some(idx) => idx,
2968 None => return,
2969 };
2970 if self.outrec_list[or_idx].is_open {
2971 return;
2972 }
2973 if !is_valid_closed_path(self.outrec_list[or_idx].pts, &self.outpt_arena) {
2974 self.dispose_out_pts(or_idx);
2975 return;
2976 }
2977
2978 let start_op = self.outrec_list[or_idx].pts.unwrap();
2979 let mut op2 = start_op;
2980 loop {
2981 let prev = self.outpt_arena[op2].prev;
2982 let next = self.outpt_arena[op2].next;
2983 let prev_pt = self.outpt_arena[prev].pt;
2984 let op2_pt = self.outpt_arena[op2].pt;
2985 let next_pt = self.outpt_arena[next].pt;
2986
2987 if is_collinear(prev_pt, op2_pt, next_pt)
2988 && (op2_pt == prev_pt
2989 || op2_pt == next_pt
2990 || !self.preserve_collinear
2991 || dot_product_three_points(prev_pt, op2_pt, next_pt) < 0.0)
2992 {
2993 if Some(op2) == self.outrec_list[or_idx].pts {
2994 self.outrec_list[or_idx].pts = Some(prev);
2995 }
2996 op2 = self.dispose_out_pt(op2);
2997 if !is_valid_closed_path(Some(op2), &self.outpt_arena) {
2998 self.dispose_out_pts(or_idx);
2999 return;
3000 }
3001 continue;
3003 }
3004 op2 = next;
3005 if op2 == start_op
3006 || (self.outrec_list[or_idx].pts.is_some()
3007 && op2 == self.outrec_list[or_idx].pts.unwrap())
3008 {
3009 break;
3010 }
3011 }
3012 self.fix_self_intersects(or_idx);
3013 }
3014
3015 fn fix_self_intersects(&mut self, outrec_idx: usize) {
3018 let start_op = match self.outrec_list[outrec_idx].pts {
3019 Some(op) => op,
3020 None => return,
3021 };
3022
3023 let prev = self.outpt_arena[start_op].prev;
3024 let next = self.outpt_arena[start_op].next;
3025 if prev == self.outpt_arena[next].next {
3026 return; }
3028
3029 let mut op2 = start_op;
3030 loop {
3031 let prev = self.outpt_arena[op2].prev;
3032 let next = self.outpt_arena[op2].next;
3033 let next_next = self.outpt_arena[next].next;
3034
3035 if segments_intersect(
3036 self.outpt_arena[prev].pt,
3037 self.outpt_arena[op2].pt,
3038 self.outpt_arena[next].pt,
3039 self.outpt_arena[next_next].pt,
3040 false,
3041 ) {
3042 let next_next_next = self.outpt_arena[next_next].next;
3043 if segments_intersect(
3044 self.outpt_arena[prev].pt,
3045 self.outpt_arena[op2].pt,
3046 self.outpt_arena[next_next].pt,
3047 self.outpt_arena[next_next_next].pt,
3048 false,
3049 ) {
3050 op2 = self.duplicate_op(op2, false);
3052 let nnext = self.outpt_arena[self.outpt_arena[op2].next].next;
3053 let nnn = self.outpt_arena[nnext].next;
3054 self.outpt_arena[op2].pt = self.outpt_arena[nnn].pt;
3055 op2 = self.outpt_arena[op2].next;
3056 } else {
3057 if Some(op2) == self.outrec_list[outrec_idx].pts
3058 || Some(next) == self.outrec_list[outrec_idx].pts
3059 {
3060 let pts = self.outrec_list[outrec_idx].pts.unwrap();
3061 self.outrec_list[outrec_idx].pts = Some(self.outpt_arena[pts].prev);
3062 }
3063 self.do_split_op(outrec_idx, op2);
3064 if self.outrec_list[outrec_idx].pts.is_none() {
3065 break;
3066 }
3067 op2 = self.outrec_list[outrec_idx].pts.unwrap();
3068 let prev = self.outpt_arena[op2].prev;
3069 let next = self.outpt_arena[op2].next;
3070 if prev == self.outpt_arena[next].next {
3071 break;
3072 }
3073 continue;
3074 }
3075 } else {
3076 op2 = self.outpt_arena[op2].next;
3077 }
3078 if op2 == start_op
3079 || (self.outrec_list[outrec_idx].pts.is_some()
3080 && op2 == self.outrec_list[outrec_idx].pts.unwrap())
3081 {
3082 break;
3083 }
3084 }
3085 }
3086
3087 fn do_split_op(&mut self, outrec_idx: usize, split_op: usize) {
3090 let prev_op = self.outpt_arena[split_op].prev;
3091 let next_op = self.outpt_arena[split_op].next;
3092 let next_next_op = self.outpt_arena[next_op].next;
3093 self.outrec_list[outrec_idx].pts = Some(prev_op);
3094
3095 let mut ip = self.outpt_arena[prev_op].pt;
3096 get_segment_intersect_pt(
3097 self.outpt_arena[prev_op].pt,
3098 self.outpt_arena[split_op].pt,
3099 self.outpt_arena[next_op].pt,
3100 self.outpt_arena[next_next_op].pt,
3101 &mut ip,
3102 );
3103
3104 let area1 = area_outpt(self.outrec_list[outrec_idx].pts.unwrap(), &self.outpt_arena);
3105 let abs_area1 = area1.abs();
3106 if abs_area1 < 2.0 {
3107 self.dispose_out_pts(outrec_idx);
3108 return;
3109 }
3110
3111 let area2 = area_triangle(
3112 ip,
3113 self.outpt_arena[split_op].pt,
3114 self.outpt_arena[next_op].pt,
3115 );
3116 let abs_area2 = area2.abs();
3117
3118 if ip == self.outpt_arena[prev_op].pt || ip == self.outpt_arena[next_next_op].pt {
3120 self.outpt_arena[next_next_op].prev = prev_op;
3121 self.outpt_arena[prev_op].next = next_next_op;
3122 } else {
3123 let new_op2 = self.new_out_pt(ip, self.outpt_arena[prev_op].outrec);
3124 self.outpt_arena[new_op2].prev = prev_op;
3125 self.outpt_arena[new_op2].next = next_next_op;
3126 self.outpt_arena[next_next_op].prev = new_op2;
3127 self.outpt_arena[prev_op].next = new_op2;
3128 }
3129
3130 if abs_area2 >= 1.0 && (abs_area2 > abs_area1 || (area2 > 0.0) == (area1 > 0.0)) {
3131 let new_or = self.new_out_rec();
3132 self.outrec_list[new_or].owner = self.outrec_list[outrec_idx].owner;
3133
3134 self.outpt_arena[split_op].outrec = new_or;
3135 self.outpt_arena[next_op].outrec = new_or;
3136
3137 let new_op = self.new_out_pt(ip, new_or);
3138 self.outpt_arena[new_op].prev = next_op;
3139 self.outpt_arena[new_op].next = split_op;
3140 self.outrec_list[new_or].pts = Some(new_op);
3141 self.outpt_arena[split_op].prev = new_op;
3142 self.outpt_arena[next_op].next = new_op;
3143
3144 if self.using_polytree {
3145 if path2_contains_path1_outpt(prev_op, new_op, &self.outpt_arena) {
3146 self.outrec_list[new_or].splits = Some(vec![outrec_idx]);
3147 } else {
3148 if self.outrec_list[outrec_idx].splits.is_none() {
3149 self.outrec_list[outrec_idx].splits = Some(Vec::new());
3150 }
3151 self.outrec_list[outrec_idx]
3152 .splits
3153 .as_mut()
3154 .unwrap()
3155 .push(new_or);
3156 }
3157 }
3158 }
3159 }
3161
3162 pub fn check_bounds(&mut self, outrec_idx: usize) -> bool {
3167 if self.outrec_list[outrec_idx].pts.is_none() {
3168 return false;
3169 }
3170 if !self.outrec_list[outrec_idx].bounds.is_empty() {
3171 return true;
3172 }
3173 self.clean_collinear(outrec_idx);
3174 if self.outrec_list[outrec_idx].pts.is_none() {
3175 return false;
3176 }
3177
3178 let op_start = self.outrec_list[outrec_idx].pts.unwrap();
3179 let path =
3180 build_path64_from_outpt(op_start, self.reverse_solution, false, &self.outpt_arena);
3181 match path {
3182 None => {
3183 self.outrec_list[outrec_idx].path = Path64::new();
3184 false
3185 }
3186 Some(p) => {
3187 self.outrec_list[outrec_idx].bounds = get_bounds(&p);
3188 self.outrec_list[outrec_idx].path = p;
3189 true
3190 }
3191 }
3192 }
3193
3194 fn check_split_owner(&mut self, outrec_idx: usize, splits: &[usize]) -> bool {
3197 for &split_idx in splits {
3198 if self.outrec_list[split_idx].pts.is_none() {
3199 if let Some(ref sub_splits) = self.outrec_list[split_idx].splits.clone() {
3200 if self.check_split_owner(outrec_idx, sub_splits) {
3201 return true;
3202 }
3203 }
3204 }
3205 let real_split = get_real_outrec(&self.outrec_list, split_idx);
3206 let split = match real_split {
3207 Some(s) if s != outrec_idx => s,
3208 _ => continue,
3209 };
3210
3211 if self.outrec_list[split].recursive_split == Some(outrec_idx) {
3212 continue;
3213 }
3214 self.outrec_list[split].recursive_split = Some(outrec_idx);
3215
3216 if let Some(ref sub_splits) = self.outrec_list[split].splits.clone() {
3217 if self.check_split_owner(outrec_idx, sub_splits) {
3218 return true;
3219 }
3220 }
3221
3222 if !self.check_bounds(split) {
3223 continue;
3224 }
3225 let or_bounds = self.outrec_list[outrec_idx].bounds;
3226 if !self.outrec_list[split].bounds.contains_rect(&or_bounds) {
3227 continue;
3228 }
3229
3230 let or_pts = self.outrec_list[outrec_idx].pts.unwrap();
3231 let split_pts = self.outrec_list[split].pts.unwrap();
3232 if !path2_contains_path1_outpt(or_pts, split_pts, &self.outpt_arena) {
3233 continue;
3234 }
3235
3236 if !is_valid_owner(&self.outrec_list, outrec_idx, split) {
3237 self.outrec_list[split].owner = self.outrec_list[outrec_idx].owner;
3238 }
3239
3240 self.outrec_list[outrec_idx].owner = Some(split);
3241 return true;
3242 }
3243 false
3244 }
3245
3246 pub fn recursive_check_owners(&mut self, outrec_idx: usize, polytree: &mut PolyTree64) {
3249 if self.outrec_list[outrec_idx].polypath.is_some()
3250 || self.outrec_list[outrec_idx].bounds.is_empty()
3251 {
3252 return;
3253 }
3254
3255 while let Some(owner) = self.outrec_list[outrec_idx].owner {
3256 if let Some(ref splits) = self.outrec_list[owner].splits.clone() {
3257 if self.check_split_owner(outrec_idx, splits) {
3258 break;
3259 }
3260 }
3261 if self.outrec_list[owner].pts.is_some() && self.check_bounds(owner) {
3262 let or_bounds = self.outrec_list[outrec_idx].bounds;
3263 let owner_bounds = self.outrec_list[owner].bounds;
3264 let contains = owner_bounds.contains_rect(&or_bounds);
3265 if contains {
3266 let or_pts = self.outrec_list[outrec_idx].pts.unwrap();
3267 let owner_pts = self.outrec_list[owner].pts.unwrap();
3268 let p2cp1 = path2_contains_path1_outpt(or_pts, owner_pts, &self.outpt_arena);
3269 if p2cp1 {
3270 break;
3271 }
3272 }
3273 }
3274 self.outrec_list[outrec_idx].owner = self.outrec_list[owner].owner;
3275 }
3276
3277 let path = self.outrec_list[outrec_idx].path.clone();
3278 if let Some(owner) = self.outrec_list[outrec_idx].owner {
3279 if self.outrec_list[owner].polypath.is_none() {
3280 self.recursive_check_owners(owner, polytree);
3281 }
3282 let parent_pp = self.outrec_list[owner].polypath.unwrap_or(0);
3283 let pp = polytree.add_child(parent_pp, path);
3284 self.outrec_list[outrec_idx].polypath = Some(pp);
3285 } else {
3286 let pp = polytree.add_child(0, path);
3287 self.outrec_list[outrec_idx].polypath = Some(pp);
3288 }
3289 }
3290
3291 pub fn execute_internal(
3296 &mut self,
3297 ct: ClipType,
3298 fillrule: FillRule,
3299 use_polytrees: bool,
3300 ) -> bool {
3301 self.cliptype = ct;
3302 self.fillrule = fillrule;
3303 self.using_polytree = use_polytrees;
3304 self.reset();
3305
3306 if ct == ClipType::NoClip {
3307 return true;
3308 }
3309
3310 let y = match self.pop_scanline() {
3311 Some(y) => y,
3312 None => return true,
3313 };
3314
3315 let mut y = y;
3316 while self.succeeded {
3317 self.insert_local_minima_into_ael(y);
3318
3319 while let Some(e) = self.pop_horz() {
3320 self.do_horizontal(e);
3321 }
3322
3323 if !self.horz_seg_list.is_empty() {
3324 self.convert_horz_segs_to_joins();
3325 self.horz_seg_list.clear();
3326 }
3327
3328 self.bot_y = y;
3329
3330 match self.pop_scanline() {
3331 Some(new_y) => y = new_y,
3332 None => break,
3333 }
3334
3335 self.do_intersections(y);
3336 self.do_top_of_scanbeam(y);
3337
3338 while let Some(e) = self.pop_horz() {
3339 self.do_horizontal(e);
3340 }
3341 }
3342
3343 if self.succeeded {
3344 self.process_horz_joins();
3345 }
3346
3347 self.succeeded
3348 }
3349}
3350
3351#[cfg(test)]
3356#[path = "engine_tests.rs"]
3357mod tests;