#![allow(dead_code)]
use std::cmp::Ordering;
use crate::compare_events::compare_events;
use crate::divide_segment::divide_segment;
use crate::edge_type::EdgeType;
use crate::equals::equals;
use crate::event_queue::EventQueue;
use crate::segment_intersection::{intersection, SegmentIntersection};
use crate::sweep_event::SweepEvent;
pub(crate) fn possible_intersection(
arena: &mut Vec<SweepEvent>,
queue: &mut EventQueue,
se1_idx: usize,
se2_idx: usize,
) -> i32 {
let se1_pt = arena[se1_idx].point;
let se2_pt = arena[se2_idx].point;
let se1_other_idx = arena[se1_idx]
.other_event
.expect("possible_intersection: se1 has no peer");
let se2_other_idx = arena[se2_idx]
.other_event
.expect("possible_intersection: se2 has no peer");
let se1_other_pt = arena[se1_other_idx].point;
let se2_other_pt = arena[se2_other_idx].point;
let inter = intersection(se1_pt, se1_other_pt, se2_pt, se2_other_pt, false);
match inter {
SegmentIntersection::None => 0,
SegmentIntersection::Point(p) => {
if equals(se1_pt, se2_pt) || equals(se1_other_pt, se2_other_pt) {
return 0;
}
if !equals(se1_pt, p) && !equals(se1_other_pt, p) {
let (l, r) = divide_segment(arena, se1_idx, p);
queue.push(arena, l);
queue.push(arena, r);
}
if !equals(se2_pt, p) && !equals(se2_other_pt, p) {
let (l, r) = divide_segment(arena, se2_idx, p);
queue.push(arena, l);
queue.push(arena, r);
}
1
}
SegmentIntersection::Overlap(_, _) => {
if arena[se1_idx].is_subject() == arena[se2_idx].is_subject() {
return 0;
}
handle_overlap(arena, queue, se1_idx, se2_idx)
}
}
}
fn handle_overlap(
arena: &mut Vec<SweepEvent>,
queue: &mut EventQueue,
se1_idx: usize,
se2_idx: usize,
) -> i32 {
let se1_other_idx = arena[se1_idx].other_event.unwrap();
let se2_other_idx = arena[se2_idx].other_event.unwrap();
let mut events: Vec<usize> = Vec::with_capacity(4);
let mut left_coincide = false;
let mut right_coincide = false;
if equals(arena[se1_idx].point, arena[se2_idx].point) {
left_coincide = true;
} else if compare_events(arena, se1_idx, se2_idx) == Ordering::Greater {
events.push(se2_idx);
events.push(se1_idx);
} else {
events.push(se1_idx);
events.push(se2_idx);
}
if equals(arena[se1_other_idx].point, arena[se2_other_idx].point) {
right_coincide = true;
} else if compare_events(arena, se1_other_idx, se2_other_idx) == Ordering::Greater {
events.push(se2_other_idx);
events.push(se1_other_idx);
} else {
events.push(se1_other_idx);
events.push(se2_other_idx);
}
if left_coincide {
arena[se2_idx].edge_type = EdgeType::NonContributing;
let se1_in_out = arena[se1_idx].in_out;
let se2_in_out = arena[se2_idx].in_out;
arena[se1_idx].edge_type = if se1_in_out == se2_in_out {
EdgeType::SameTransition
} else {
EdgeType::DifferentTransition
};
if !right_coincide {
let target_other = arena[events[1]].other_event.unwrap();
let split_at = arena[events[0]].point;
let (l, r) = divide_segment(arena, target_other, split_at);
queue.push(arena, l);
queue.push(arena, r);
}
return 2;
}
if right_coincide {
let split_at = arena[events[1]].point;
let (l, r) = divide_segment(arena, events[0], split_at);
queue.push(arena, l);
queue.push(arena, r);
return 3;
}
let events3_other = arena[events[3]].other_event.unwrap();
if events[0] != events3_other {
let p1 = arena[events[1]].point;
let (l, r) = divide_segment(arena, events[0], p1);
queue.push(arena, l);
queue.push(arena, r);
let p2 = arena[events[2]].point;
let (l, r) = divide_segment(arena, events[1], p2);
queue.push(arena, l);
queue.push(arena, r);
return 3;
}
let p1 = arena[events[1]].point;
let (l, r) = divide_segment(arena, events[0], p1);
queue.push(arena, l);
queue.push(arena, r);
let events3_other_after = arena[events[3]].other_event.unwrap();
let p2 = arena[events[2]].point;
let (l, r) = divide_segment(arena, events3_other_after, p2);
queue.push(arena, l);
queue.push(arena, r);
3
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sweep_event::PolygonType;
fn add_segment(
arena: &mut Vec<SweepEvent>,
left_pt: [f64; 2],
right_pt: [f64; 2],
polygon_type: PolygonType,
) -> usize {
let left_idx = arena.len();
arena.push(SweepEvent::new(
left_pt,
true,
polygon_type,
EdgeType::Normal,
));
let right_idx = arena.len();
arena.push(SweepEvent::new(
right_pt,
false,
polygon_type,
EdgeType::Normal,
));
arena[left_idx].other_event = Some(right_idx);
arena[right_idx].other_event = Some(left_idx);
left_idx
}
#[test]
fn non_intersecting_segments_return_zero() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [1.0, 0.0], PolygonType::Subject);
let b = add_segment(&mut arena, [0.0, 1.0], [1.0, 1.0], PolygonType::Clipping);
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 0);
assert!(q.is_empty());
}
#[test]
fn interior_crossing_returns_one_and_creates_four_new_events() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [4.0, 4.0], PolygonType::Subject);
let b = add_segment(&mut arena, [0.0, 4.0], [4.0, 0.0], PolygonType::Clipping);
let before = arena.len();
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 1);
assert_eq!(arena.len(), before + 4);
assert_eq!(q.len(), 4);
}
#[test]
fn shared_left_endpoint_only_returns_zero() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [4.0, 4.0], PolygonType::Subject);
let b = add_segment(&mut arena, [0.0, 0.0], [4.0, -4.0], PolygonType::Clipping);
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 0);
assert!(q.is_empty());
}
#[test]
fn same_polygon_overlap_returns_zero() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [5.0, 0.0], PolygonType::Subject);
let b = add_segment(&mut arena, [2.0, 0.0], [7.0, 0.0], PolygonType::Subject);
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 0);
assert!(q.is_empty());
}
#[test]
fn collinear_overlap_different_polygons_marks_edge_types_and_splits() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [5.0, 0.0], PolygonType::Subject);
let b = add_segment(&mut arena, [2.0, 0.0], [7.0, 0.0], PolygonType::Clipping);
let ret = possible_intersection(&mut arena, &mut q, a, b);
assert_eq!(ret, 3);
assert!(!q.is_empty());
}
#[test]
fn collinear_left_coincident_marks_non_contributing() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [5.0, 0.0], PolygonType::Subject);
let b = add_segment(&mut arena, [0.0, 0.0], [3.0, 0.0], PolygonType::Clipping);
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 2);
assert_eq!(arena[b].edge_type, EdgeType::NonContributing);
assert!(matches!(
arena[a].edge_type,
EdgeType::SameTransition | EdgeType::DifferentTransition
));
}
#[test]
fn collinear_right_coincident_only_splits_once() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let a = add_segment(&mut arena, [0.0, 0.0], [5.0, 0.0], PolygonType::Subject);
let b = add_segment(&mut arena, [2.0, 0.0], [5.0, 0.0], PolygonType::Clipping);
let before = arena.len();
assert_eq!(possible_intersection(&mut arena, &mut q, a, b), 3);
assert_eq!(arena.len(), before + 2);
}
}