use crate::geom::{line, Line, Point2, Quad};
use crate::math::BaseFloat;
#[derive(Clone, Debug)]
pub struct VertexPairs<I, S> {
half_thickness: S,
points: I,
point_a: Option<Point2<S>>,
point_b: Option<Point2<S>>,
}
#[derive(Clone, Debug)]
pub struct Vertices<I, S> {
pairs: VertexPairs<I, S>,
next: Option<Point2<S>>,
}
#[derive(Clone, Debug)]
pub struct TriangleIndices {
i: usize,
n_tris: usize,
second: bool,
}
impl<I, S> VertexPairs<I, S> {
pub fn new<P>(points: P, half_thickness: S) -> Self
where
I: Iterator<Item = Point2<S>>,
P: IntoIterator<IntoIter = I, Item = Point2<S>>,
S: BaseFloat,
{
let mut points = points.into_iter();
let point_a = None;
let point_b = points.next();
VertexPairs {
half_thickness,
points,
point_a,
point_b,
}
}
pub fn flatten(self) -> Vertices<I, S> {
Vertices {
pairs: self,
next: None,
}
}
}
impl TriangleIndices {
pub fn new(n_points: usize) -> Self {
let n_normals = n_points * 2;
let n_tris = n_normals - 2;
TriangleIndices {
i: 0,
n_tris,
second: false,
}
}
}
impl<I, S> Iterator for VertexPairs<I, S>
where
I: Iterator<Item = Point2<S>>,
S: BaseFloat,
{
type Item = [Point2<S>; 2];
fn next(&mut self) -> Option<Self::Item> {
let VertexPairs {
half_thickness,
ref mut points,
ref mut point_a,
ref mut point_b,
} = *self;
next_pair(half_thickness, point_a, point_b, points.next())
}
}
pub fn next_pair<S>(
half_thickness: S,
point_a: &mut Option<Point2<S>>,
point_b: &mut Option<Point2<S>>,
next_point: Option<Point2<S>>,
) -> Option<[Point2<S>; 2]>
where
S: BaseFloat,
{
let a = point_a.take();
let b = point_b.take();
match (a, b) {
(None, None) | (Some(_), None) => None,
(None, Some(b)) => {
let c = match next_point {
Some(c) => c,
None => return None,
};
let line = Line {
start: b,
end: c,
half_thickness,
};
let Quad([r, l, _, _]) = line.quad_corners();
*point_a = Some(b);
*point_b = Some(c);
Some([l, r])
}
(Some(a), Some(b)) => {
let c = match next_point {
Some(c) => c,
None => {
let line = Line {
start: a,
end: b,
half_thickness,
};
let Quad([_, _, l, r]) = line.quad_corners();
*point_a = Some(b);
return Some([l, r]);
}
};
let ab = Line {
start: a,
end: b,
half_thickness,
};
let bc = Line {
start: b,
end: c,
half_thickness,
};
let Quad([ar, al, bl_ab, br_ab]) = ab.quad_corners();
let Quad([br_bc, bl_bc, cl, cr]) = bc.quad_corners();
let il = match line::join::intersect((al, bl_ab), (cl, bl_bc)) {
Some(il) => il,
None => bl_ab,
};
let ir = match line::join::intersect((ar, br_ab), (cr, br_bc)) {
Some(ir) => ir,
None => br_ab,
};
*point_a = Some(b);
*point_b = Some(c);
Some([il, ir])
}
}
}
impl<I, S> ExactSizeIterator for VertexPairs<I, S>
where
I: Iterator<Item = Point2<S>> + ExactSizeIterator,
S: BaseFloat,
{
fn len(&self) -> usize {
let remaining_points = self.points.len();
let a = self.point_a.is_some();
let b = self.point_b.is_some();
match (a, b) {
(false, true) => {
if remaining_points <= 1 {
0
} else {
remaining_points
}
}
(true, true) => remaining_points + 1,
_ => 0,
}
}
}
impl<I, S> Iterator for Vertices<I, S>
where
I: Iterator<Item = Point2<S>>,
S: BaseFloat,
{
type Item = Point2<S>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.next.take() {
return Some(next);
}
if let Some([this, next]) = self.pairs.next() {
self.next = Some(next);
return Some(this);
}
None
}
}
impl<I, S> ExactSizeIterator for Vertices<I, S>
where
I: Iterator<Item = Point2<S>> + ExactSizeIterator,
S: BaseFloat,
{
fn len(&self) -> usize {
self.pairs.len() * 2 + if self.next.is_some() { 1 } else { 0 }
}
}
impl Iterator for TriangleIndices {
type Item = [usize; 3];
fn next(&mut self) -> Option<Self::Item> {
if self.i >= self.n_tris {
return None;
}
let trio = if self.second {
[self.i, self.i + 2, self.i + 1]
} else {
[self.i, self.i + 1, self.i + 2]
};
self.second = !self.second;
self.i += 1;
Some(trio)
}
}
impl ExactSizeIterator for TriangleIndices {
fn len(&self) -> usize {
self.n_tris - self.i
}
}
pub fn vertices<I, S>(points: I, half_thickness: S) -> VertexPairs<I::IntoIter, S>
where
I: IntoIterator<Item = Point2<S>>,
S: BaseFloat,
{
VertexPairs::new(points, half_thickness)
}
pub fn triangle_indices(n_points: usize) -> TriangleIndices {
TriangleIndices::new(n_points)
}