#![allow(dead_code)]
use std::cmp::Ordering;
use crate::compare_events::compare_events;
use crate::equals::equals;
use crate::signed_area::signed_area;
use crate::sweep_event::SweepEvent;
pub(crate) fn compare_segments(arena: &[SweepEvent], i1: usize, i2: usize) -> Ordering {
if i1 == i2 {
return Ordering::Equal;
}
let e1 = &arena[i1];
let e2 = &arena[i2];
let o1 = arena[e1.other_event.expect("compare_segments: e1 has no peer")].point;
let o2 = arena[e2.other_event.expect("compare_segments: e2 has no peer")].point;
let not_collinear =
signed_area(e1.point, o1, e2.point) != 0 || signed_area(e1.point, o1, o2) != 0;
if not_collinear {
if equals(e1.point, e2.point) {
return if e1.is_below(o1, o2) {
Ordering::Less
} else {
Ordering::Greater
};
}
if e1.point[0] == e2.point[0] {
return if e1.point[1] < e2.point[1] {
Ordering::Less
} else {
Ordering::Greater
};
}
if compare_events(arena, i1, i2) == Ordering::Greater {
return if e2.is_above(o2, e1.point) {
Ordering::Less
} else {
Ordering::Greater
};
}
return if e1.is_below(o1, e2.point) {
Ordering::Less
} else {
Ordering::Greater
};
}
if e1.is_subject() == e2.is_subject() {
if e1.point == e2.point {
if o1 == o2 {
return Ordering::Equal;
}
let c1 = e1.contour_id.unwrap_or(0);
let c2 = e2.contour_id.unwrap_or(0);
return if c1 > c2 {
Ordering::Greater
} else {
Ordering::Less
};
}
} else {
return if e1.is_subject() {
Ordering::Less
} else {
Ordering::Greater
};
}
if compare_events(arena, i1, i2) == Ordering::Greater {
Ordering::Greater
} else {
Ordering::Less
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edge_type::EdgeType;
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 not_collinear_shared_left_point_orders_by_right_point() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [0.0, 0.0], [1.0, 1.0], PolygonType::Subject);
let e2 = add_segment(&mut arena, [0.0, 0.0], [2.0, 3.0], PolygonType::Subject);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Less);
assert_eq!(compare_segments(&arena, e2, e1), Ordering::Greater);
}
#[test]
fn not_collinear_same_x_different_y_orders_by_left_y() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [0.0, 1.0], [1.0, 1.0], PolygonType::Subject);
let e2 = add_segment(&mut arena, [0.0, 2.0], [2.0, 3.0], PolygonType::Subject);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Less);
assert_eq!(compare_segments(&arena, e2, e1), Ordering::Greater);
}
#[test]
fn maintains_events_order_in_sweep_line() {
let mut arena = Vec::new();
let se1 = add_segment(&mut arena, [0.0, 1.0], [2.0, 1.0], PolygonType::Subject);
let se2 = add_segment(&mut arena, [-1.0, 0.0], [2.0, 3.0], PolygonType::Subject);
assert_eq!(compare_events(&arena, se1, se2), Ordering::Greater);
let o2 = arena[arena[se2].other_event.unwrap()].point;
assert!(!arena[se2].is_below(o2, arena[se1].point));
assert!(arena[se2].is_above(o2, arena[se1].point));
assert_eq!(compare_segments(&arena, se1, se2), Ordering::Less);
assert_eq!(compare_segments(&arena, se2, se1), Ordering::Greater);
}
#[test]
fn handles_when_first_point_is_below() {
let mut arena = Vec::new();
let se2 = add_segment(&mut arena, [0.0, 1.0], [2.0, 1.0], PolygonType::Subject);
let se1 = add_segment(&mut arena, [-1.0, 0.0], [2.0, 3.0], PolygonType::Subject);
let o1 = arena[arena[se1].other_event.unwrap()].point;
assert!(!arena[se1].is_below(o1, arena[se2].point));
assert_eq!(compare_segments(&arena, se1, se2), Ordering::Greater);
}
#[test]
fn collinear_subject_below_clipping() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [1.0, 1.0], [5.0, 1.0], PolygonType::Subject);
let e2 = add_segment(&mut arena, [2.0, 1.0], [3.0, 1.0], PolygonType::Clipping);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Less);
assert_eq!(compare_segments(&arena, e2, e1), Ordering::Greater);
}
#[test]
fn collinear_shared_left_point_tiebreaks_by_contour_id() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [0.0, 1.0], [5.0, 1.0], PolygonType::Clipping);
let e2 = add_segment(&mut arena, [0.0, 1.0], [3.0, 1.0], PolygonType::Clipping);
arena[e1].contour_id = Some(1);
arena[e2].contour_id = Some(2);
assert_eq!(arena[e1].is_subject(), arena[e2].is_subject());
assert_eq!(arena[e1].point, arena[e2].point);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Less);
arena[e1].contour_id = Some(2);
arena[e2].contour_id = Some(1);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Greater);
}
#[test]
fn collinear_same_polygon_different_left_points() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [1.0, 1.0], [5.0, 1.0], PolygonType::Subject);
let e2 = add_segment(&mut arena, [2.0, 1.0], [3.0, 1.0], PolygonType::Subject);
assert_eq!(arena[e1].is_subject(), arena[e2].is_subject());
assert_ne!(arena[e1].point, arena[e2].point);
assert_eq!(compare_segments(&arena, e1, e2), Ordering::Less);
assert_eq!(compare_segments(&arena, e2, e1), Ordering::Greater);
}
#[test]
fn same_index_compares_equal() {
let mut arena = Vec::new();
let e1 = add_segment(&mut arena, [0.0, 0.0], [1.0, 1.0], PolygonType::Subject);
assert_eq!(compare_segments(&arena, e1, e1), Ordering::Equal);
}
}