#![allow(clippy::question_mark)]
use crate::geo::*;
use smallvec::*;
use std::cmp::{Ordering};
pub fn sweep_self<'a, TItem, BoundsIter>(ordered_items: BoundsIter) -> impl 'a+Iterator<Item=(&'a TItem, &'a TItem)>
where
BoundsIter: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D,
{
SweepSelfIterator {
bounds_iterator: ordered_items,
pending: smallvec![],
by_max_x: Vec::new()
}
}
pub fn sweep_against<'a, TItem, SrcBoundsIter, TgtBoundsIter>(src: SrcBoundsIter, tgt: TgtBoundsIter) -> impl 'a+Iterator<Item=(&'a TItem, &'a TItem)>
where
SrcBoundsIter: 'a+Iterator<Item=&'a TItem>,
TgtBoundsIter: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D,
{
SweepAgainstIterator {
src_iterator: Some(src),
tgt_iterator: tgt,
pending: smallvec![],
src_by_max_x: Vec::new(),
src_last_min_x: f64::MIN
}
}
struct SweepSelfIterator<'a, TItem, BoundsIter>
where
BoundsIter: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D {
bounds_iterator: BoundsIter,
pending: SmallVec<[(&'a TItem, &'a TItem); 16]>,
by_max_x: Vec<(Bounds<TItem::Point>, &'a TItem)>
}
impl<'a, TItem, BoundsIter> Iterator for SweepSelfIterator<'a, TItem, BoundsIter>
where
BoundsIter: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D,
{
type Item = (&'a TItem, &'a TItem);
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.pending.pop() {
return Some(next);
}
loop {
let next_item = if let Some(next_item) = self.bounds_iterator.next() {
next_item
} else {
return None;
};
let next_bounds = next_item.get_bounding_box::<Bounds<_>>();
let min_x = next_bounds.min().x();
while let Some((earliest_x, _item)) = self.by_max_x.last() {
if earliest_x.max().x() >= min_x {
break;
}
self.by_max_x.pop();
}
for (item_bounds, item) in self.by_max_x.iter() {
if item_bounds.overlaps(&next_bounds) {
self.pending.push((item, next_item));
}
}
let max_x = next_bounds.max().x();
let index = self.by_max_x.binary_search_by(|(bounds, _item)| {
let item_max_x = bounds.max().x();
if item_max_x > max_x {
Ordering::Less
} else if item_max_x == max_x {
Ordering::Equal
} else {
Ordering::Greater
}
}).unwrap_or_else(|idx| idx);
self.by_max_x.insert(index, (next_bounds, next_item));
if let Some(next) = self.pending.pop() {
return Some(next);
}
}
}
}
struct SweepAgainstIterator<'a, TItem, SrcIterator, TgtIterator>
where
SrcIterator: 'a+Iterator<Item=&'a TItem>,
TgtIterator: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D,
{
src_iterator: Option<SrcIterator>,
tgt_iterator: TgtIterator,
src_last_min_x: f64,
pending: SmallVec<[(&'a TItem, &'a TItem); 16]>,
src_by_max_x: Vec<(Bounds<TItem::Point>, &'a TItem)>,
}
impl<'a, TItem, SrcIterator, TgtIterator> Iterator for SweepAgainstIterator<'a, TItem, SrcIterator, TgtIterator>
where
SrcIterator: 'a+Iterator<Item=&'a TItem>,
TgtIterator: 'a+Iterator<Item=&'a TItem>,
TItem: 'a+HasBoundingBox,
TItem::Point: Coordinate2D,
{
type Item = (&'a TItem, &'a TItem);
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(pending) = self.pending.pop() {
return Some(pending);
}
let next_tgt = self.tgt_iterator.next();
let next_tgt = if let Some(next_tgt) = next_tgt {
next_tgt
} else {
return None;
};
let next_tgt_bounds = next_tgt.get_bounding_box::<Bounds<_>>();
let tgt_min_x = next_tgt_bounds.min().x();
let tgt_max_x = next_tgt_bounds.max().x();
while let Some((earliest_x, _item)) = self.src_by_max_x.last() {
if earliest_x.max().x() >= tgt_min_x {
break;
}
self.src_by_max_x.pop();
}
loop {
if self.src_last_min_x > tgt_max_x { break; }
let next_src = if let Some(next_src) = self.src_iterator.as_mut().and_then(|iter| iter.next()) {
next_src
} else {
self.src_iterator = None;
break;
};
let src_bounds = next_src.get_bounding_box::<Bounds<_>>();
let src_min_x = src_bounds.min().x();
let src_max_x = src_bounds.max().x();
let index = self.src_by_max_x.binary_search_by(|(bounds, _item)| {
let item_max_x = bounds.max().x();
if item_max_x > src_max_x {
Ordering::Less
} else if item_max_x == src_max_x {
Ordering::Equal
} else {
Ordering::Greater
}
}).unwrap_or_else(|idx| idx);
self.src_by_max_x.insert(index, (src_bounds, next_src));
self.src_last_min_x = src_min_x;
}
for (src_item_bounds, src_item) in self.src_by_max_x.iter() {
if src_item_bounds.overlaps(&next_tgt_bounds) {
self.pending.push((src_item, next_tgt));
}
}
}
}
}