use super::edge_color::EdgeColor;
use super::edge_segment::EdgeSegment;
use crate::math::Vector2;
use crate::math::scalar::sign;
#[derive(Debug, Clone, Default)]
pub struct Contour {
pub segments: Vec<EdgeSegment>,
pub colors: Vec<EdgeColor>,
}
#[inline]
fn shoelace(a: Vector2, b: Vector2) -> f64 {
(b.x - a.x) * (a.y + b.y)
}
impl Contour {
pub fn new() -> Self {
Contour::default()
}
#[inline]
pub fn add_edge(&mut self, edge: EdgeSegment) {
self.segments.push(edge);
self.colors.push(EdgeColor::White);
}
#[inline]
pub fn add_edge_colored(&mut self, edge: EdgeSegment, color: EdgeColor) {
self.segments.push(edge);
self.colors.push(color);
}
#[inline]
pub fn is_empty(&self) -> bool {
self.segments.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.segments.len()
}
pub fn bound(&self, min: &mut Vector2, max: &mut Vector2) {
for e in &self.segments {
e.bound(min, max);
}
}
pub fn winding(&self) -> i32 {
let n = self.segments.len();
if n == 0 {
return 0;
}
let mut total = 0.0;
if n == 1 {
let e = &self.segments[0];
let (a, b, c) = (e.point(0.0), e.point(1.0 / 3.0), e.point(2.0 / 3.0));
total += shoelace(a, b);
total += shoelace(b, c);
total += shoelace(c, a);
} else if n == 2 {
let (e0, e1) = (&self.segments[0], &self.segments[1]);
let (a, b, c, d) = (e0.point(0.0), e0.point(0.5), e1.point(0.0), e1.point(0.5));
total += shoelace(a, b);
total += shoelace(b, c);
total += shoelace(c, d);
total += shoelace(d, a);
} else {
let mut prev = self.segments[n - 1].point(0.0);
for e in &self.segments {
let cur = e.point(0.0);
total += shoelace(prev, cur);
prev = cur;
}
}
sign(total)
}
pub fn reverse(&mut self) {
self.segments.reverse();
self.colors.reverse();
for e in &mut self.segments {
e.reverse();
}
}
}