1use crate::core::*;
7use crate::engine::*;
8
9#[inline]
16pub fn is_odd(val: i32) -> bool {
17 val & 1 != 0
18}
19
20#[inline]
23pub fn is_hot_edge(e: &Active) -> bool {
24 e.outrec.is_some()
25}
26
27#[inline]
30pub fn is_open_active(e: &Active, minima_list: &[LocalMinima]) -> bool {
31 minima_list[e.local_min].is_open
32}
33
34#[inline]
37pub fn is_open_end_vertex(v: &Vertex) -> bool {
38 (v.flags & (VertexFlags::OPEN_START | VertexFlags::OPEN_END)) != VertexFlags::EMPTY
39}
40
41#[inline]
44pub fn is_open_end_active(e: &Active, vertex_arena: &[Vertex]) -> bool {
45 is_open_end_vertex(&vertex_arena[e.vertex_top])
46}
47
48#[inline]
51pub fn get_dx(pt1: Point64, pt2: Point64) -> f64 {
52 let dy = (pt2.y - pt1.y) as f64;
53 if dy != 0.0 {
54 (pt2.x - pt1.x) as f64 / dy
55 } else if pt2.x > pt1.x {
56 -f64::MAX
57 } else {
58 f64::MAX
59 }
60}
61
62#[inline]
65pub fn top_x(ae: &Active, current_y: i64) -> i64 {
66 if current_y == ae.top.y || ae.top.x == ae.bot.x {
67 ae.top.x
68 } else if current_y == ae.bot.y {
69 ae.bot.x
70 } else {
71 ae.bot.x + (ae.dx * (current_y - ae.bot.y) as f64).round() as i64
72 }
73}
74
75#[inline]
78pub fn is_horizontal_active(e: &Active) -> bool {
79 e.top.y == e.bot.y
80}
81
82#[inline]
85pub fn is_heading_right_horz(e: &Active) -> bool {
86 e.dx == -f64::MAX
87}
88
89#[inline]
92pub fn is_heading_left_horz(e: &Active) -> bool {
93 e.dx == f64::MAX
94}
95
96#[inline]
99pub fn get_poly_type(e: &Active, minima_list: &[LocalMinima]) -> PathType {
100 minima_list[e.local_min].polytype
101}
102
103#[inline]
106pub fn is_same_poly_type(e1: &Active, e2: &Active, minima_list: &[LocalMinima]) -> bool {
107 minima_list[e1.local_min].polytype == minima_list[e2.local_min].polytype
108}
109
110#[inline]
113pub fn set_dx(e: &mut Active) {
114 e.dx = get_dx(e.bot, e.top);
115}
116
117#[inline]
120pub fn next_vertex(e: &Active, vertex_arena: &[Vertex]) -> usize {
121 if e.wind_dx > 0 {
122 vertex_arena[e.vertex_top].next
123 } else {
124 vertex_arena[e.vertex_top].prev
125 }
126}
127
128#[inline]
131pub fn prev_prev_vertex(ae: &Active, vertex_arena: &[Vertex]) -> usize {
132 if ae.wind_dx > 0 {
133 let prev = vertex_arena[ae.vertex_top].prev;
134 vertex_arena[prev].prev
135 } else {
136 let next = vertex_arena[ae.vertex_top].next;
137 vertex_arena[next].next
138 }
139}
140
141#[inline]
144pub fn is_maxima_vertex(v: &Vertex) -> bool {
145 (v.flags & VertexFlags::LOCAL_MAX) != VertexFlags::EMPTY
146}
147
148#[inline]
151pub fn is_maxima_active(e: &Active, vertex_arena: &[Vertex]) -> bool {
152 is_maxima_vertex(&vertex_arena[e.vertex_top])
153}
154
155pub fn point_count(op_start: usize, outpt_arena: &[OutPt]) -> i32 {
158 let mut op2 = op_start;
159 let mut cnt = 0;
160 loop {
161 op2 = outpt_arena[op2].next;
162 cnt += 1;
163 if op2 == op_start {
164 break;
165 }
166 }
167 cnt
168}
169
170#[inline]
173pub fn is_invalid_path(op: Option<usize>, outpt_arena: &[OutPt]) -> bool {
174 match op {
175 None => true,
176 Some(idx) => outpt_arena[idx].next == idx,
177 }
178}
179
180pub fn area_outpt(op_start: usize, outpt_arena: &[OutPt]) -> f64 {
183 let mut result = 0.0;
184 let mut op2 = op_start;
185 loop {
186 let prev_idx = outpt_arena[op2].prev;
187 result += (outpt_arena[prev_idx].pt.y + outpt_arena[op2].pt.y) as f64
188 * (outpt_arena[prev_idx].pt.x - outpt_arena[op2].pt.x) as f64;
189 op2 = outpt_arena[op2].next;
190 if op2 == op_start {
191 break;
192 }
193 }
194 result * 0.5
195}
196
197#[inline]
200pub fn area_triangle(pt1: Point64, pt2: Point64, pt3: Point64) -> f64 {
201 (pt3.y + pt1.y) as f64 * (pt3.x - pt1.x) as f64
202 + (pt1.y + pt2.y) as f64 * (pt1.x - pt2.x) as f64
203 + (pt2.y + pt3.y) as f64 * (pt2.x - pt3.x) as f64
204}
205
206pub fn reverse_out_pts(op_start: usize, outpt_arena: &mut [OutPt]) {
209 let mut op1 = op_start;
210 loop {
211 std::mem::swap(&mut outpt_arena[op1].next, &mut outpt_arena[op1].prev);
212 op1 = outpt_arena[op1].prev; if op1 == op_start {
214 break;
215 }
216 }
217}
218
219pub fn intersect_list_sort(a: &IntersectNode, b: &IntersectNode) -> std::cmp::Ordering {
222 if a.pt.y == b.pt.y {
223 a.pt.x.cmp(&b.pt.x)
224 } else {
225 b.pt.y.cmp(&a.pt.y)
226 }
227}
228
229pub fn get_maxima_pair(e: &Active, active_arena: &[Active]) -> Option<usize> {
232 let mut e2_idx = e.next_in_ael;
233 while let Some(idx) = e2_idx {
234 if active_arena[idx].vertex_top == e.vertex_top {
235 return Some(idx);
236 }
237 e2_idx = active_arena[idx].next_in_ael;
238 }
239 None
240}
241
242pub fn get_curr_y_maxima_vertex_open(e: &Active, vertex_arena: &[Vertex]) -> Option<usize> {
245 let mut result = e.vertex_top;
246 if e.wind_dx > 0 {
247 while vertex_arena[vertex_arena[result].next].pt.y == vertex_arena[result].pt.y
248 && (vertex_arena[result].flags & (VertexFlags::OPEN_END | VertexFlags::LOCAL_MAX))
249 == VertexFlags::EMPTY
250 {
251 result = vertex_arena[result].next;
252 }
253 } else {
254 while vertex_arena[vertex_arena[result].prev].pt.y == vertex_arena[result].pt.y
255 && (vertex_arena[result].flags & (VertexFlags::OPEN_END | VertexFlags::LOCAL_MAX))
256 == VertexFlags::EMPTY
257 {
258 result = vertex_arena[result].prev;
259 }
260 }
261 if is_maxima_vertex(&vertex_arena[result]) {
262 Some(result)
263 } else {
264 None
265 }
266}
267
268pub fn get_curr_y_maxima_vertex(e: &Active, vertex_arena: &[Vertex]) -> Option<usize> {
271 let mut result = e.vertex_top;
272 if e.wind_dx > 0 {
273 while vertex_arena[vertex_arena[result].next].pt.y == vertex_arena[result].pt.y {
274 result = vertex_arena[result].next;
275 }
276 } else {
277 while vertex_arena[vertex_arena[result].prev].pt.y == vertex_arena[result].pt.y {
278 result = vertex_arena[result].prev;
279 }
280 }
281 if is_maxima_vertex(&vertex_arena[result]) {
282 Some(result)
283 } else {
284 None
285 }
286}
287
288pub fn is_valid_ael_order(
291 resident: &Active,
292 newcomer: &Active,
293 vertex_arena: &[Vertex],
294 minima_list: &[LocalMinima],
295) -> bool {
296 if newcomer.curr_x != resident.curr_x {
297 return newcomer.curr_x > resident.curr_x;
298 }
299
300 let i = cross_product_sign(
302 vertex_arena[resident.vertex_top].pt,
303 newcomer.bot,
304 vertex_arena[newcomer.vertex_top].pt,
305 );
306 if i != 0 {
307 return i < 0;
308 }
309
310 if !is_maxima_active(resident, vertex_arena)
314 && vertex_arena[resident.vertex_top].pt.y > vertex_arena[newcomer.vertex_top].pt.y
315 {
316 let nv = next_vertex(resident, vertex_arena);
317 return cross_product_sign(
318 newcomer.bot,
319 vertex_arena[resident.vertex_top].pt,
320 vertex_arena[nv].pt,
321 ) <= 0;
322 } else if !is_maxima_active(newcomer, vertex_arena)
323 && vertex_arena[newcomer.vertex_top].pt.y > vertex_arena[resident.vertex_top].pt.y
324 {
325 let nv = next_vertex(newcomer, vertex_arena);
326 return cross_product_sign(
327 newcomer.bot,
328 vertex_arena[newcomer.vertex_top].pt,
329 vertex_arena[nv].pt,
330 ) >= 0;
331 }
332
333 let y = newcomer.bot.y;
334 let newcomer_is_left = newcomer.is_left_bound;
335
336 if resident.bot.y != y || vertex_arena[minima_list[resident.local_min].vertex].pt.y != y {
337 newcomer.is_left_bound
338 } else if resident.is_left_bound != newcomer_is_left {
339 newcomer_is_left
340 } else if is_collinear(
341 vertex_arena[prev_prev_vertex(resident, vertex_arena)].pt,
342 resident.bot,
343 vertex_arena[resident.vertex_top].pt,
344 ) {
345 true
346 } else {
347 let ppv_r = prev_prev_vertex(resident, vertex_arena);
349 let ppv_n = prev_prev_vertex(newcomer, vertex_arena);
350 (cross_product_sign(vertex_arena[ppv_r].pt, newcomer.bot, vertex_arena[ppv_n].pt) > 0)
351 == newcomer_is_left
352 }
353}
354
355pub fn get_clean_path(op_start: usize, outpt_arena: &[OutPt]) -> Path64 {
362 let mut result = Path64::new();
363 let mut op = op_start;
364 loop {
365 let prev = outpt_arena[op].prev;
366 let next = outpt_arena[op].next;
367 if outpt_arena[op].pt == outpt_arena[prev].pt
368 || is_collinear(
369 outpt_arena[prev].pt,
370 outpt_arena[op].pt,
371 outpt_arena[next].pt,
372 )
373 {
374 op = next;
375 if op == op_start {
376 break;
377 }
378 continue;
379 }
380 result.push(outpt_arena[op].pt);
381 op = next;
382 if op == op_start {
383 break;
384 }
385 }
386 result
387}
388
389pub fn get_real_outrec(outrec_list: &[OutRec], idx: usize) -> Option<usize> {
397 let mut i = Some(idx);
398 while let Some(cur) = i {
399 if outrec_list[cur].pts.is_some() {
400 return Some(cur);
401 }
402 i = outrec_list[cur].owner;
403 }
404 None
405}
406
407pub fn is_valid_owner(outrec_list: &[OutRec], outrec_idx: usize, test_owner_idx: usize) -> bool {
410 let mut tmp = Some(test_owner_idx);
411 while let Some(idx) = tmp {
412 if idx == outrec_idx {
413 return false;
414 }
415 tmp = outrec_list[idx].owner;
416 }
417 true
418}
419
420#[inline]
423pub fn pts_really_close(pt1: Point64, pt2: Point64) -> bool {
424 (pt1.x - pt2.x).abs() < 2 && (pt1.y - pt2.y).abs() < 2
425}
426
427pub fn is_very_small_triangle(op_idx: usize, outpt_arena: &[OutPt]) -> bool {
430 let next = outpt_arena[op_idx].next;
431 let prev = outpt_arena[op_idx].prev;
432 if outpt_arena[next].next != prev {
433 return false;
434 }
435 pts_really_close(outpt_arena[prev].pt, outpt_arena[next].pt)
436 || pts_really_close(outpt_arena[op_idx].pt, outpt_arena[next].pt)
437 || pts_really_close(outpt_arena[op_idx].pt, outpt_arena[prev].pt)
438}
439
440pub fn is_valid_closed_path(op: Option<usize>, outpt_arena: &[OutPt]) -> bool {
443 match op {
444 None => false,
445 Some(idx) => {
446 let next = outpt_arena[idx].next;
447 if next == idx {
448 return false;
449 }
450 let prev = outpt_arena[idx].prev;
451 if next == prev {
452 return false;
453 }
454 !is_very_small_triangle(idx, outpt_arena)
455 }
456 }
457}
458
459#[inline]
462pub fn outrec_is_ascending(
463 hot_edge_idx: usize,
464 outrec_list: &[OutRec],
465 active_arena: &[Active],
466) -> bool {
467 if let Some(or_idx) = active_arena[hot_edge_idx].outrec {
468 outrec_list[or_idx].front_edge == Some(hot_edge_idx)
469 } else {
470 false
471 }
472}
473
474pub fn swap_front_back_sides(outrec_idx: usize, outrec_list: &mut [OutRec], outpt_arena: &[OutPt]) {
477 std::mem::swap(
478 &mut outrec_list[outrec_idx].front_edge,
479 &mut outrec_list[outrec_idx].back_edge,
480 );
481 if let Some(pts) = outrec_list[outrec_idx].pts {
482 outrec_list[outrec_idx].pts = Some(outpt_arena[pts].next);
483 }
484}
485
486#[inline]
489pub fn edges_adjacent_in_ael(inode: &IntersectNode, active_arena: &[Active]) -> bool {
490 active_arena[inode.edge1].next_in_ael == Some(inode.edge2)
491 || active_arena[inode.edge1].prev_in_ael == Some(inode.edge2)
492}
493
494#[inline]
497pub fn is_joined(e: &Active) -> bool {
498 e.join_with != JoinWith::NoJoin
499}
500
501pub fn set_owner(outrec_list: &mut [OutRec], outrec_idx: usize, new_owner_idx: usize) {
504 outrec_list[new_owner_idx].owner = match outrec_list[new_owner_idx].owner {
508 Some(owner_idx) => get_real_outrec(outrec_list, owner_idx),
509 None => None,
510 };
511 let mut tmp = Some(new_owner_idx);
512 while let Some(t) = tmp {
513 if t == outrec_idx {
514 outrec_list[new_owner_idx].owner = outrec_list[outrec_idx].owner;
515 break;
516 }
517 tmp = outrec_list[t].owner;
518 }
519 outrec_list[outrec_idx].owner = Some(new_owner_idx);
520}
521
522pub fn point_in_op_polygon(
525 pt: Point64,
526 op_start: usize,
527 outpt_arena: &[OutPt],
528) -> PointInPolygonResult {
529 let next = outpt_arena[op_start].next;
530 if next == op_start || outpt_arena[op_start].prev == next {
531 return PointInPolygonResult::IsOutside;
532 }
533
534 let mut op = op_start;
535 loop {
536 if outpt_arena[op].pt.y != pt.y {
537 break;
538 }
539 op = outpt_arena[op].next;
540 if op == op_start {
541 break;
542 }
543 }
544 if outpt_arena[op].pt.y == pt.y {
545 return PointInPolygonResult::IsOutside;
546 }
547
548 let mut is_above = outpt_arena[op].pt.y < pt.y;
549 let starting_above = is_above;
550 let mut val = 0;
551 let mut op2 = outpt_arena[op].next;
552
553 while op2 != op {
554 if is_above {
555 while op2 != op && outpt_arena[op2].pt.y < pt.y {
556 op2 = outpt_arena[op2].next;
557 }
558 } else {
559 while op2 != op && outpt_arena[op2].pt.y > pt.y {
560 op2 = outpt_arena[op2].next;
561 }
562 }
563 if op2 == op {
564 break;
565 }
566
567 if outpt_arena[op2].pt.y == pt.y {
568 let prev = outpt_arena[op2].prev;
569 if outpt_arena[op2].pt.x == pt.x
570 || (outpt_arena[op2].pt.y == outpt_arena[prev].pt.y
571 && (pt.x < outpt_arena[prev].pt.x) != (pt.x < outpt_arena[op2].pt.x))
572 {
573 return PointInPolygonResult::IsOn;
574 }
575 op2 = outpt_arena[op2].next;
576 if op2 == op {
577 break;
578 }
579 continue;
580 }
581
582 let prev = outpt_arena[op2].prev;
583 if pt.x < outpt_arena[op2].pt.x && pt.x < outpt_arena[prev].pt.x {
584 } else if pt.x > outpt_arena[prev].pt.x && pt.x > outpt_arena[op2].pt.x {
586 val = 1 - val;
587 } else {
588 let i = cross_product_sign(outpt_arena[prev].pt, outpt_arena[op2].pt, pt);
589 if i == 0 {
590 return PointInPolygonResult::IsOn;
591 }
592 if (i < 0) == is_above {
593 val = 1 - val;
594 }
595 }
596 is_above = !is_above;
597 op2 = outpt_arena[op2].next;
598 }
599
600 if is_above != starting_above {
601 let prev = outpt_arena[op2].prev;
602 let i = cross_product_sign(outpt_arena[prev].pt, outpt_arena[op2].pt, pt);
603 if i == 0 {
604 return PointInPolygonResult::IsOn;
605 }
606 if (i < 0) == is_above {
607 val = 1 - val;
608 }
609 }
610
611 if val == 0 {
612 PointInPolygonResult::IsOutside
613 } else {
614 PointInPolygonResult::IsInside
615 }
616}
617
618pub fn path2_contains_path1_outpt(
621 op1_start: usize,
622 op2_start: usize,
623 outpt_arena: &[OutPt],
624) -> bool {
625 let mut pip = PointInPolygonResult::IsOn;
626 let mut op = op1_start;
627 loop {
628 match point_in_op_polygon(outpt_arena[op].pt, op2_start, outpt_arena) {
629 PointInPolygonResult::IsOutside => {
630 if pip == PointInPolygonResult::IsOutside {
631 return false;
632 }
633 pip = PointInPolygonResult::IsOutside;
634 }
635 PointInPolygonResult::IsInside => {
636 if pip == PointInPolygonResult::IsInside {
637 return true;
638 }
639 pip = PointInPolygonResult::IsInside;
640 }
641 _ => {}
642 }
643 op = outpt_arena[op].next;
644 if op == op1_start {
645 break;
646 }
647 }
648 let clean1 = get_clean_path(op1_start, outpt_arena);
650 let clean2 = get_clean_path(op2_start, outpt_arena);
651 path2_contains_path1(&clean1, &clean2)
652}
653
654pub fn path2_contains_path1(path1: &Path64, path2: &Path64) -> bool {
658 let mut pip = PointInPolygonResult::IsOn;
659 for pt in path1 {
660 match point_in_polygon(*pt, path2) {
661 PointInPolygonResult::IsOutside => {
662 if pip == PointInPolygonResult::IsOutside {
663 return false;
664 }
665 pip = PointInPolygonResult::IsOutside;
666 }
667 PointInPolygonResult::IsInside => {
668 if pip == PointInPolygonResult::IsInside {
669 return true;
670 }
671 pip = PointInPolygonResult::IsInside;
672 }
673 _ => {}
674 }
675 }
676 if pip != PointInPolygonResult::IsInside {
677 return false;
678 }
679 let mp1 = get_bounds_path(path1).mid_point();
681 point_in_polygon(mp1, path2) == PointInPolygonResult::IsInside
682}
683
684pub fn build_path64_from_outpt(
687 op_start: usize,
688 reverse: bool,
689 is_open: bool,
690 outpt_arena: &[OutPt],
691) -> Option<Path64> {
692 let next = outpt_arena[op_start].next;
693 if next == op_start || (!is_open && next == outpt_arena[op_start].prev) {
694 return None;
695 }
696
697 let mut path = Path64::new();
698 let (mut last_pt, mut op2);
699
700 if reverse {
701 last_pt = outpt_arena[op_start].pt;
702 op2 = outpt_arena[op_start].prev;
703 } else {
704 let op_next = outpt_arena[op_start].next;
705 last_pt = outpt_arena[op_next].pt;
706 op2 = outpt_arena[op_next].next;
707 path.push(last_pt);
708 while op2 != outpt_arena[op_start].next {
709 if outpt_arena[op2].pt != last_pt {
710 last_pt = outpt_arena[op2].pt;
711 path.push(last_pt);
712 }
713 op2 = outpt_arena[op2].next;
714 }
715 if !is_open
716 && path.len() == 3
717 && is_very_small_triangle(outpt_arena[op_start].next, outpt_arena)
718 {
719 return None;
720 }
721 return if path.len() >= 2 { Some(path) } else { None };
722 }
723
724 path.push(last_pt);
726 while op2 != op_start {
727 if outpt_arena[op2].pt != last_pt {
728 last_pt = outpt_arena[op2].pt;
729 path.push(last_pt);
730 }
731 op2 = outpt_arena[op2].prev;
732 }
733
734 if !is_open && path.len() == 3 && is_very_small_triangle(op_start, outpt_arena) {
735 return None;
736 }
737
738 if path.len() >= 2 {
739 Some(path)
740 } else {
741 None
742 }
743}
744
745pub fn build_path_d_from_outpt(
748 op_start: usize,
749 reverse: bool,
750 is_open: bool,
751 outpt_arena: &[OutPt],
752 inv_scale: f64,
753) -> Option<PathD> {
754 let next = outpt_arena[op_start].next;
755 if next == op_start || (!is_open && next == outpt_arena[op_start].prev) {
756 return None;
757 }
758
759 let mut path = PathD::new();
760 let (mut last_pt, mut op2);
761
762 if reverse {
763 last_pt = outpt_arena[op_start].pt;
764 op2 = outpt_arena[op_start].prev;
765 } else {
766 let op_next = outpt_arena[op_start].next;
767 last_pt = outpt_arena[op_next].pt;
768 op2 = outpt_arena[op_next].next;
769 path.push(PointD::new(
770 last_pt.x as f64 * inv_scale,
771 last_pt.y as f64 * inv_scale,
772 ));
773 while op2 != outpt_arena[op_start].next {
774 if outpt_arena[op2].pt != last_pt {
775 last_pt = outpt_arena[op2].pt;
776 path.push(PointD::new(
777 last_pt.x as f64 * inv_scale,
778 last_pt.y as f64 * inv_scale,
779 ));
780 }
781 op2 = outpt_arena[op2].next;
782 }
783 if path.len() == 3 && is_very_small_triangle(outpt_arena[op_start].next, outpt_arena) {
784 return None;
785 }
786 return if path.len() >= 2 { Some(path) } else { None };
787 }
788
789 path.push(PointD::new(
791 last_pt.x as f64 * inv_scale,
792 last_pt.y as f64 * inv_scale,
793 ));
794 while op2 != op_start {
795 if outpt_arena[op2].pt != last_pt {
796 last_pt = outpt_arena[op2].pt;
797 path.push(PointD::new(
798 last_pt.x as f64 * inv_scale,
799 last_pt.y as f64 * inv_scale,
800 ));
801 }
802 op2 = outpt_arena[op2].prev;
803 }
804
805 if path.len() == 3 && is_very_small_triangle(op_start, outpt_arena) {
806 return None;
807 }
808
809 if path.len() >= 2 {
810 Some(path)
811 } else {
812 None
813 }
814}
815
816#[inline]
819pub fn get_last_op(
820 hot_edge_idx: usize,
821 active_arena: &[Active],
822 outrec_list: &[OutRec],
823 outpt_arena: &[OutPt],
824) -> Option<usize> {
825 if let Some(or_idx) = active_arena[hot_edge_idx].outrec {
826 let result = outrec_list[or_idx].pts?;
827 if outrec_list[or_idx].front_edge != Some(hot_edge_idx) {
828 Some(outpt_arena[result].next)
829 } else {
830 Some(result)
831 }
832 } else {
833 None
834 }
835}
836
837pub fn fix_outrec_pts(outrec_idx: usize, outrec_list: &[OutRec], outpt_arena: &mut [OutPt]) {
840 if let Some(pts) = outrec_list[outrec_idx].pts {
841 let mut op = pts;
842 loop {
843 outpt_arena[op].outrec = outrec_idx;
844 op = outpt_arena[op].next;
845 if op == pts {
846 break;
847 }
848 }
849 }
850}
851
852pub fn update_outrec_owner(outrec_idx: usize, outrec_list: &[OutRec], outpt_arena: &mut [OutPt]) {
855 fix_outrec_pts(outrec_idx, outrec_list, outpt_arena);
856}
857
858pub fn move_splits(outrec_list: &mut [OutRec], from_or: usize, to_or: usize) {
861 let from_splits = outrec_list[from_or].splits.take().unwrap_or_default();
862 if outrec_list[to_or].splits.is_none() {
863 outrec_list[to_or].splits = Some(Vec::new());
864 }
865 if let Some(ref mut to_splits) = outrec_list[to_or].splits {
866 for s in &from_splits {
867 if *s != to_or {
868 to_splits.push(*s);
869 }
870 }
871 }
872}
873
874pub fn uncouple_outrec(e_idx: usize, active_arena: &mut [Active], outrec_list: &mut [OutRec]) {
877 if let Some(or_idx) = active_arena[e_idx].outrec {
878 if let Some(fe) = outrec_list[or_idx].front_edge {
879 active_arena[fe].outrec = None;
880 }
881 if let Some(be) = outrec_list[or_idx].back_edge {
882 active_arena[be].outrec = None;
883 }
884 outrec_list[or_idx].front_edge = None;
885 outrec_list[or_idx].back_edge = None;
886 }
887}
888
889pub fn extract_from_sel(e_idx: usize, active_arena: &mut [Active]) -> Option<usize> {
892 let next = active_arena[e_idx].next_in_sel;
893 if let Some(next_idx) = next {
894 active_arena[next_idx].prev_in_sel = active_arena[e_idx].prev_in_sel;
895 }
896 if let Some(prev_idx) = active_arena[e_idx].prev_in_sel {
897 active_arena[prev_idx].next_in_sel = next;
898 }
899 active_arena[e_idx].prev_in_sel = None;
900 active_arena[e_idx].next_in_sel = None;
901 next
902}
903
904pub fn insert1_before2_in_sel(tmp_idx: usize, left_idx: usize, active_arena: &mut [Active]) {
907 let prev = active_arena[left_idx].prev_in_sel;
908 active_arena[tmp_idx].prev_in_sel = prev;
909 if let Some(prev_idx) = prev {
910 active_arena[prev_idx].next_in_sel = Some(tmp_idx);
911 }
912 active_arena[tmp_idx].next_in_sel = Some(left_idx);
913 active_arena[left_idx].prev_in_sel = Some(tmp_idx);
914}