use super::monotone::MonotoneTriangulator;
use crate::{
math::{IndexType, Scalar, Vector, Vector2D},
mesh::IndexedVertex2D,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IntervalBoundaryEdge {
pub start: usize,
pub end: usize,
}
impl IntervalBoundaryEdge {
pub fn x_at_y<V: IndexType, Vec2: Vector2D>(
&self,
y: Vec2::S,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
) -> Vec2::S {
let e = vec2s[self.end].vec;
let s = vec2s[self.start].vec;
let dx = e.x() - s.x();
let dy = e.y() - s.y();
if dy == Vec2::S::ZERO {
e.x()
} else {
s.x() + dx * (y - s.y()) / dy
}
}
pub fn beam<V: IndexType, Vec2: Vector2D>(
&self,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
) -> Option<(Vec2::S, Vec2::S, Vec2::S)> {
let e = vec2s[self.end].vec;
let s = vec2s[self.start].vec;
let dx = e.x() - s.x();
let dy = e.y() - s.y();
if dy == Vec2::S::ZERO {
return None;
}
let a = dx / dy;
let b = s.x() - a * s.y();
let c = s.y();
Some((a, b, c))
}
}
impl IntervalBoundaryEdge {
pub fn new(start: usize, end: usize) -> Self {
IntervalBoundaryEdge { start, end }
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct SweepLineInterval<MT: MonotoneTriangulator> {
pub helper: usize,
pub left: IntervalBoundaryEdge,
pub right: IntervalBoundaryEdge,
pub chain: MT,
pub fixup: Option<MT>,
}
impl<MT: MonotoneTriangulator> SweepLineInterval<MT> {
pub fn contains(&self, pos: &MT::Vec2, vec2s: &Vec<IndexedVertex2D<MT::V, MT::Vec2>>) -> bool {
let p1 = self.left.x_at_y::<MT::V, MT::Vec2>(pos.y(), vec2s);
if p1 > pos.x() {
return false;
}
let p2 = self.right.x_at_y::<MT::V, MT::Vec2>(pos.y(), vec2s);
assert!(p1 <= p2);
return pos.x() <= p2;
}
fn is_circular(&self) -> bool {
(self.left.start == self.right.end && self.right.start == self.left.end)
|| (self.left.start == self.right.start && self.left.end == self.right.end)
}
pub fn is_end(&self) -> bool {
self.left.end == self.right.end
}
pub fn sanity_check(&self) -> bool {
assert!(!self.is_circular());
self.chain
.sanity_check(self.left.start, self.right.start, &self.fixup);
return true;
}
}
impl<MT: MonotoneTriangulator> std::fmt::Debug for SweepLineInterval<MT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "lowest: {} ", self.helper)?;
write!(f, "left: {}->{} ", self.left.start, self.left.end)?;
write!(f, "right: {}->{} ", self.right.start, self.right.end)?;
write!(f, "stacks: {:?} ", self.chain)?;
if let Some(fixup) = &self.fixup {
write!(f, "fixup: {:?}", fixup)?;
}
Ok(())
}
}