use super::{interval::SweepLineInterval, monotone::MonotoneTriangulator};
use crate::{
math::{IndexType, Scalar, Vector, Vector2D},
mesh::IndexedVertex2D,
};
use std::collections::BTreeSet;
#[derive(Clone)]
struct SLISorter<Vec2: Vector2D> {
left: usize,
from: Vec2,
to: Vec2,
}
impl<Vec2: Vector2D> PartialEq for SLISorter<Vec2> {
fn eq(&self, other: &Self) -> bool {
self.left == other.left
}
}
impl<Vec2: Vector2D> Eq for SLISorter<Vec2> {}
impl<Vec2: Vector2D> PartialOrd for SLISorter<Vec2> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
let c: Vec2::S = other.from.y().min(self.from.y());
other.x_at_y(c).partial_cmp(&self.x_at_y(c))
}
}
impl<Vec2: Vector2D> Ord for SLISorter<Vec2> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other)
.expect("Ordering failed - are there NaN or inf values in your mesh?")
}
}
impl<Vec2: Vector2D> std::fmt::Debug for SLISorter<Vec2> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"IntervalBoundary: {} ({:?} -> {:?})",
self.left, self.from, self.to
)
}
}
impl<Vec2: Vector2D> SLISorter<Vec2> {
fn x_at_y(&self, y: Vec2::S) -> Vec2::S {
let s = self.from;
let e = self.to;
let dy = e.y() - s.y();
if dy == Vec2::S::ZERO {
e.x()
} else {
let dx = e.x() - s.x();
s.x() + dx * (y - s.y()) / dy
}
}
pub fn new(left: usize, from: Vec2, to: Vec2) -> Self {
assert!(from.y() >= to.y());
SLISorter { left, from, to }
}
pub fn from_interval<V: IndexType, MT: MonotoneTriangulator<V = V, Vec2 = Vec2>>(
interval: &SweepLineInterval<MT>,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> SLISorter<Vec2> {
let from = vec2s[interval.left.start].vec;
let to = vec2s[interval.left.end].vec;
SLISorter::new(interval.left.end, from, to)
}
}
pub struct SweepLineStatus<MT: MonotoneTriangulator> {
left: Vec<Option<SweepLineInterval<MT>>>,
right: Vec<usize>,
tree: Option<BTreeSet<SLISorter<MT::Vec2>>>,
}
impl<MT: MonotoneTriangulator> SweepLineStatus<MT> {
pub fn new(capacity: usize) -> Self {
let mut r = SweepLineStatus {
left: Vec::with_capacity(capacity),
right: Vec::with_capacity(capacity),
tree: None,
};
r.left.resize_with(capacity, || None);
r.right.resize_with(capacity, || usize::MAX);
r
}
pub fn insert(
&mut self,
value: SweepLineInterval<MT>,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) {
debug_assert!(value.sanity_check());
self.tree
.as_mut()
.map(|tree| assert!(tree.insert(SLISorter::from_interval(&value, vec2s))));
self.right[value.right.end] = value.left.end;
let le = value.left.end;
self.left[le] = Some(value);
}
pub fn remove_left(
&mut self,
key: usize,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> Option<SweepLineInterval<MT>> {
if let Some(v) = self.left.get_mut(key).and_then(|opt| opt.take()) {
assert!(self.left[key].is_none());
self.tree
.as_mut()
.map(|tree| assert!(tree.remove(&SLISorter::from_interval(&v, vec2s))));
self.right[v.right.end] = usize::MAX;
Some(v)
} else {
None
}
}
pub fn peek_left(&self, key: usize) -> Option<&SweepLineInterval<MT>> {
self.left[key].as_ref()
}
pub fn remove_right(
&mut self,
key: usize,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> Option<SweepLineInterval<MT>> {
let k = self.right[key];
if k != usize::MAX {
self.right[key] = usize::MAX;
if let Some(v) = self.left.get_mut(k).and_then(|opt| opt.take()) {
assert!(self.left[k].is_none());
self.tree
.as_mut()
.map(|tree| tree.remove(&SLISorter::from_interval(&v, vec2s)));
return Some(v);
}
return None;
} else {
None
}
}
pub fn peek_right(&self, key: usize) -> Option<&SweepLineInterval<MT>> {
let k = self.right[key];
if k != usize::MAX {
return self.peek_left(k);
}
return None;
}
pub fn tree_sanity_check(&self, at: <MT::Vec2 as Vector2D>::S) -> bool {
let mut last: Option<&SLISorter<MT::Vec2>> = None;
for sorter in self.tree.as_ref().unwrap() {
if let Some(l) = last {
let last_at = SLISorter::new(l.left, MT::Vec2::new(l.x_at_y(at), at), l.to);
assert!(
last_at <= *sorter,
"Tree is not sorted correctly at {} because {:?} <= {:?} does not hold.",
at,
last_at,
*sorter
);
}
last = Some(sorter);
}
return true;
}
fn find_linearly(
&self,
pos: &MT::Vec2,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> Option<usize> {
self.left
.iter()
.enumerate()
.find(|(_, v)| {
if let Some(vv) = &v {
return vv.contains(pos, vec2s);
}
return false;
})
.map(|(k, _)| k)
}
fn find_btree(
&self,
pos: &MT::Vec2,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> Option<usize> {
let sorter = SLISorter::new(usize::MAX, *pos, *pos);
debug_assert!(
self.tree_sanity_check(pos.y()),
"Tree is not sorted correctly. The sorting invariant is broken."
);
let x = self
.tree
.as_ref()
.expect("The tree should be initialized.")
.range(sorter.clone()..)
.next()
.map(|sorter| sorter.left);
debug_assert!(
x == self.find_linearly(pos, vec2s),
"The binary search did not return the same result as the linear search. {:?} != {:?}
pos = {:?}
{:?}
",
x,
self.find_linearly(pos, vec2s),
pos,
self.tree,
);
if let Some(i) = x {
if let Some(v) = &self.left[i] {
if v.contains(pos, vec2s) {
return x;
}
}
}
None
}
fn init_btree(&mut self, vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>) {
assert!(self.tree.is_none());
let mut tree = BTreeSet::new();
for mv in &self.left {
if let Some(v) = mv {
tree.insert(SLISorter::from_interval(v, vec2s));
}
}
self.tree = Some(tree);
}
pub fn find_by_position(
&mut self,
pos: &MT::Vec2,
vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>,
) -> Option<usize> {
const MIN_INTERVALS_FOR_BTREE: usize = 8;
if self.left.len() > MIN_INTERVALS_FOR_BTREE || self.tree.is_some() {
if self.tree.is_none() {
self.init_btree(vec2s);
}
self.find_btree(pos, vec2s)
} else {
self.find_linearly(pos, vec2s)
}
}
}
impl<MT: MonotoneTriangulator> std::fmt::Debug for SweepLineStatus<MT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SweepLineStatus:\n")?;
for (k, v) in self.left.iter().enumerate() {
if let Some(v) = v {
write!(f, " {}: {:?}\n", k, v)?;
}
}
Ok(())
}
}