use super::{ChainDirection, MonotoneTriangulator};
use crate::{
math::{IndexType, Scalar, Vector2D},
mesh::{IndexedVertex2D, Triangulation},
};
#[derive(Clone)]
pub struct LinearMonoTriangulator<V: IndexType, Vec2: Vector2D> {
stack: Vec<usize>,
d: ChainDirection,
last_left: Option<usize>,
last_right: Option<usize>,
phantom: std::marker::PhantomData<(V, Vec2)>,
}
impl<V: IndexType, Vec2: Vector2D> std::fmt::Debug for LinearMonoTriangulator<V, Vec2> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}{:?}", self.d, self.stack)
}
}
impl<V: IndexType, Vec2: Vector2D> LinearMonoTriangulator<V, Vec2> {
fn direction(&self) -> ChainDirection {
self.d
}
fn last(&self) -> usize {
self.stack.last().unwrap().clone()
}
fn first(&self) -> usize {
self.stack.first().unwrap().clone()
}
#[inline]
fn add_same_direction(
&mut self,
value: usize,
indices: &mut Triangulation<V>,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
d: ChainDirection,
) {
assert!(self.stack.len() >= 1);
loop {
let l = self.stack.len();
if l <= 1 {
break;
}
let angle = vec2s[value]
.vec
.angle_tri(vec2s[self.stack[l - 1]].vec, vec2s[self.stack[l - 2]].vec);
if d == ChainDirection::Left {
if angle > Vec2::S::ZERO {
break;
}
indices.insert_triangle_local(self.stack[l - 1], value, self.stack[l - 2], vec2s);
} else {
if angle < Vec2::S::ZERO {
break;
}
indices.insert_triangle_local(self.stack[l - 1], self.stack[l - 2], value, vec2s);
}
#[cfg(feature = "sweep_debug_print")]
println!(
"create vis: {:?}",
[self.stack[l - 1], self.stack[l - 2], value]
);
self.stack.pop();
}
self.stack.push(value);
}
#[inline]
fn add_opposite_direction(
&mut self,
value: usize,
indices: &mut Triangulation<V>,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
d: ChainDirection,
) {
assert!(self.d != d);
assert!(self.stack.len() >= 1);
if self.stack.len() == 1 {
self.stack.push(value);
self.d = d;
} else {
for i in 1..self.stack.len() {
if d == ChainDirection::Left {
indices.insert_triangle_local(self.stack[i - 1], value, self.stack[i], vec2s);
} else {
indices.insert_triangle_local(self.stack[i - 1], self.stack[i], value, vec2s);
}
#[cfg(feature = "sweep_debug_print")]
println!(
"create mul l: {:?}",
[self.stack[i - 1], self.stack[i], value]
);
}
let last = self.stack.pop().unwrap();
self.stack.clear();
self.stack.push(last);
self.stack.push(value);
self.d = d;
}
}
#[inline]
fn add(
&mut self,
value: usize,
indices: &mut Triangulation<V>,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
d: ChainDirection,
) -> &Self {
#[cfg(feature = "sweep_debug_print")]
println!("chain add: {:?} {} {:?}", self.d, value, self.stack);
if self.d == ChainDirection::None {
assert!(self.stack.len() == 1);
self.stack.push(value);
self.d = d;
} else if self.d == d {
self.add_same_direction(value, indices, vec2s, d);
} else {
self.add_opposite_direction(value, indices, vec2s, d);
}
assert!(self.d == d);
self
}
fn len(&self) -> usize {
self.stack.len()
}
fn is_done(&self) -> bool {
self.stack.len() <= 2
}
}
impl<V: IndexType, Vec2: Vector2D> MonotoneTriangulator for LinearMonoTriangulator<V, Vec2> {
type V = V;
type Vec2 = Vec2;
fn new(v: usize) -> Self {
LinearMonoTriangulator {
stack: vec![v],
d: ChainDirection::None,
phantom: std::marker::PhantomData,
last_left: Some(v),
last_right: None,
}
}
fn last_opposite(&self) -> usize {
let res = if self.d == ChainDirection::None {
assert!(self.last_right.is_none());
self.last_left.unwrap()
} else if self.d == ChainDirection::Right {
self.last_left.unwrap()
} else {
self.last_right.unwrap()
};
assert!(res == self.first());
return res;
}
fn is_right(&self) -> bool {
self.direction() == ChainDirection::Right
}
fn sanity_check(&self, left_start: usize, right_start: usize, fixup: &Option<Self>) {
match self.direction() {
ChainDirection::None => {
assert!(self.len() == 1);
assert_eq!(left_start, self.first());
assert_eq!(right_start, self.first());
}
ChainDirection::Left => {
assert!(self.len() >= 2);
if let Some(fixup) = fixup {
assert!(fixup.len() >= 2);
assert_eq!(right_start, self.first());
assert_eq!(left_start, fixup.first());
} else {
assert_eq!(right_start, self.first());
assert_eq!(left_start, self.last());
}
}
ChainDirection::Right => {
assert!(self.len() >= 2);
if let Some(fixup) = fixup {
assert!(fixup.len() >= 2);
assert_eq!(left_start, self.first());
assert_eq!(right_start, fixup.first());
} else {
assert_eq!(left_start, self.first());
assert_eq!(right_start, self.last());
}
}
};
}
#[inline]
fn right(
&mut self,
value: usize,
indices: &mut Triangulation<V>,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
) {
self.last_right = Some(value);
if self.d == ChainDirection::None {
}
self.add(value, indices, vec2s, ChainDirection::Right);
}
#[inline]
fn left(
&mut self,
value: usize,
indices: &mut Triangulation<V>,
vec2s: &Vec<IndexedVertex2D<V, Vec2>>,
) {
self.last_left = Some(value);
self.add(value, indices, vec2s, ChainDirection::Left);
}
fn finish(&mut self, _indices: &mut Triangulation<V>, _vec2s: &Vec<IndexedVertex2D<V, Vec2>>) {
assert!(self.is_done());
}
}