#![allow(dead_code)]
use crate::compute_fields::compute_fields;
use crate::event_queue::EventQueue;
use crate::operation::Operation;
use crate::possible_intersection::possible_intersection;
use crate::sweep_event::SweepEvent;
use crate::sweep_line::SweepLine;
use crate::types::BBox;
pub(crate) fn subdivide_segments(
arena: &mut Vec<SweepEvent>,
queue: &mut EventQueue,
sbbox: BBox,
cbbox: BBox,
operation: Operation,
) -> Vec<usize> {
let mut sweep_line = SweepLine::new();
let mut sorted_events: Vec<usize> = Vec::new();
let rightbound = sbbox[2].min(cbbox[2]);
while !queue.is_empty() {
let event_idx = queue.pop(arena).expect("queue.pop on non-empty queue");
sorted_events.push(event_idx);
let event_x = arena[event_idx].point[0];
if (operation == Operation::Intersection && event_x > rightbound)
|| (operation == Operation::Difference && event_x > sbbox[2])
{
break;
}
if arena[event_idx].left {
sweep_line_insert_path(arena, queue, &mut sweep_line, event_idx, operation);
} else {
sweep_line_remove_path(arena, queue, &mut sweep_line, event_idx);
}
}
sorted_events
}
fn sweep_line_insert_path(
arena: &mut Vec<SweepEvent>,
queue: &mut EventQueue,
sweep_line: &mut SweepLine,
event_idx: usize,
operation: Operation,
) {
let position = sweep_line.insert(arena, event_idx);
let prev_event = sweep_line.prev(position);
let next_event = sweep_line.next(position);
compute_fields(arena, event_idx, prev_event, operation);
if let Some(next) = next_event {
if possible_intersection(arena, queue, event_idx, next) == 2 {
compute_fields(arena, event_idx, prev_event, operation);
compute_fields(arena, next, Some(event_idx), operation);
}
}
if let Some(prev) = prev_event {
if possible_intersection(arena, queue, prev, event_idx) == 2 {
let prevprev_event = if position >= 2 {
sweep_line.at(position - 2)
} else {
None
};
compute_fields(arena, prev, prevprev_event, operation);
compute_fields(arena, event_idx, Some(prev), operation);
}
}
}
fn sweep_line_remove_path(
arena: &mut Vec<SweepEvent>,
queue: &mut EventQueue,
sweep_line: &mut SweepLine,
event_idx: usize,
) {
let left_event_idx = arena[event_idx]
.other_event
.expect("subdivide_segments: right event has no peer");
let Some(position) = sweep_line.position(arena, left_event_idx) else {
return;
};
let prev_event = sweep_line.prev(position);
let next_event = sweep_line.next(position);
sweep_line.remove_at(position);
if let (Some(prev), Some(next)) = (prev_event, next_event) {
possible_intersection(arena, queue, prev, next);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::fill_queue::fill_queue;
use crate::types::MultiPolygon;
fn empty_bbox() -> BBox {
[
f64::INFINITY,
f64::INFINITY,
f64::NEG_INFINITY,
f64::NEG_INFINITY,
]
}
fn unit_square_at(origin: [f64; 2]) -> MultiPolygon {
let [x, y] = origin;
vec![vec![vec![
[x, y],
[x + 1.0, y],
[x + 1.0, y + 1.0],
[x, y + 1.0],
[x, y],
]]]
}
#[test]
fn empty_queue_returns_empty_sorted_events() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let result = subdivide_segments(
&mut arena,
&mut q,
empty_bbox(),
empty_bbox(),
Operation::Union,
);
assert!(result.is_empty());
}
#[test]
fn single_subject_drains_the_queue() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let mut sbb = empty_bbox();
let mut cbb = empty_bbox();
fill_queue(
&mut arena,
&mut q,
&unit_square_at([0.0, 0.0]),
&vec![],
&mut sbb,
&mut cbb,
Operation::Union,
);
let event_count_before = arena.len();
let result = subdivide_segments(&mut arena, &mut q, sbb, cbb, Operation::Union);
assert_eq!(arena.len(), event_count_before);
assert_eq!(result.len(), event_count_before);
}
#[test]
fn two_overlapping_squares_produce_extra_events_from_intersection() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let mut sbb = empty_bbox();
let mut cbb = empty_bbox();
fill_queue(
&mut arena,
&mut q,
&unit_square_at([0.0, 0.0]),
&unit_square_at([0.5, 0.5]),
&mut sbb,
&mut cbb,
Operation::Union,
);
let initial_event_count = arena.len();
assert_eq!(initial_event_count, 16);
let result = subdivide_segments(&mut arena, &mut q, sbb, cbb, Operation::Union);
assert!(arena.len() > initial_event_count);
assert!(!result.is_empty());
}
#[test]
fn intersection_bbox_shortcut_stops_early() {
let mut arena = Vec::new();
let mut q = EventQueue::new();
let mut sbb = empty_bbox();
let mut cbb = empty_bbox();
fill_queue(
&mut arena,
&mut q,
&unit_square_at([0.0, 0.0]),
&unit_square_at([5.0, 0.0]),
&mut sbb,
&mut cbb,
Operation::Intersection,
);
let result = subdivide_segments(&mut arena, &mut q, sbb, cbb, Operation::Intersection);
assert!(result.len() < arena.len());
}
}