use std::{collections::BTreeSet, fmt::Debug};
use crate::{
clipper::{Clipper, Operator},
graph::Graph,
Geometry, IsClose, Shape,
};
#[derive(Debug, Clone, Copy)]
pub(super) enum Role {
Subject(usize),
Clip(usize),
}
impl Role {
pub(super) fn is_subject(&self) -> bool {
matches!(self, Role::Subject(_))
}
}
#[derive(Debug)]
pub(super) struct Node<T>
where
T: Geometry,
{
pub(super) vertex: T::Vertex,
pub(super) role: Role,
pub(super) next: usize,
pub(super) siblings: BTreeSet<usize>,
}
impl<T> Node<T>
where
T: Geometry,
{
pub(super) fn is_intersection(&self) -> bool {
!self.siblings.is_empty()
}
}
pub(super) struct NodeIterator<'a, Op, T>
where
T: Geometry,
{
pub(super) clipper: &'a Clipper<Op, Shape<T>, Shape<T>, <T::Vertex as IsClose>::Tolerance>,
pub(super) graph: &'a mut Graph<T>,
pub(super) next: Option<usize>,
}
impl<Op, T> Iterator for NodeIterator<'_, Op, T>
where
T: Geometry,
T::Vertex: Copy + PartialEq,
Op: Operator<T>,
{
type Item = Node<T>;
fn next(&mut self) -> Option<Self::Item> {
let node = self.graph.nodes[self.next?].take()?;
self.next = self.clipper.successor(self.graph, &node);
Some(node)
}
}
pub(super) struct BoundaryCollector<'a, Op, T>
where
T: Geometry,
{
iterator: NodeIterator<'a, Op, T>,
terminal: Vec<usize>,
closed: bool,
}
impl<'a, Op, T> From<NodeIterator<'a, Op, T>> for BoundaryCollector<'a, Op, T>
where
T: Geometry,
{
fn from(iterator: NodeIterator<'a, Op, T>) -> Self {
Self {
iterator,
terminal: Vec::new(),
closed: false,
}
}
}
impl<Op, T> Iterator for &mut BoundaryCollector<'_, Op, T>
where
T: Geometry,
T::Vertex: Copy + PartialEq,
Op: Operator<T>,
{
type Item = Node<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.closed {
return None;
}
let current = self.iterator.next?;
let node = self.iterator.next()?;
if self.terminal.is_empty() {
self.terminal
.extend(node.siblings.iter().copied().chain([current]));
} else if let Some(next) = self.iterator.next {
self.closed = self.terminal.contains(&next);
} else {
self.closed = node
.siblings
.iter()
.filter_map(|&sibling| self.iterator.graph.nodes[sibling].as_ref())
.map(|sibling| sibling.next)
.chain([node.next])
.any(|node| self.terminal.contains(&node));
};
Some(node)
}
}
impl<Op, T> BoundaryCollector<'_, Op, T>
where
T: Geometry,
T::Vertex: Copy + PartialEq,
Op: Operator<T>,
{
pub(super) fn collect(mut self) -> Option<Vec<T::Vertex>> {
let vertices = self.map(|node| node.vertex).collect();
self.closed.then_some(vertices)
}
}