use crate::delaunator::Coord;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Polygon<C: Coord> {
pub(crate) points: Vec<C>,
}
impl<C: Coord> Polygon<C> {
pub fn new() -> Self {
Polygon { points: Vec::new() }
}
pub fn from_points(points: Vec<C>) -> Self {
Polygon { points }
}
pub fn points(&self) -> &[C] {
&self.points
}
}
fn inside<C: Coord>(p: &C, p1: &C, p2: &C) -> bool {
(p2.y() - p1.y()) * p.x() + (p1.x() - p2.x()) * p.y() + (p2.x() * p1.y() - p1.x() * p2.y()) < 0.0
}
fn intersection<C: Coord>(cp1: &C, cp2: &C, s: &C, e: &C) -> C {
let dc = C::from_xy(
cp1.x() - cp2.x(),
cp1.y() - cp2.y(),
);
let dp = C::from_xy(
s.x() - e.x(),
s.y() - e.y(),
);
let n1 = cp1.x() * cp2.y() - cp1.y() * cp2.x();
let n2 = s.x() * e.y() - s.y() * e.x();
let n3 = 1.0 / (dc.x() * dp.y() - dc.y() * dp.x());
C::from_xy(
(n1 * dp.x() - n2 * dc.x()) * n3,
(n1 * dp.y() - n2 * dc.y()) * n3,
)
}
pub fn sutherland_hodgman<C: Coord + Clone>(subject: &Polygon<C>, clip: &Polygon<C>) -> Polygon<C> {
let mut output_polygon = Polygon::new();
let mut input_polygon = Polygon::new();
output_polygon.points.clone_from(&subject.points);
let mut new_polygon_size = subject.points.len();
for j in 0..clip.points.len() {
input_polygon.points.clear();
input_polygon.points.clone_from(&output_polygon.points);
let mut counter = 0;
output_polygon.points.clear();
let cp1 = &clip.points[j];
let cp2 = &clip.points[(j + 1) % clip.points.len()];
for i in 0..new_polygon_size {
let s = &input_polygon.points[i];
let e = &input_polygon.points[(i + 1) % new_polygon_size];
if inside(s, cp1, cp2) && inside(e, cp1, cp2) {
output_polygon.points.push(e.clone());
counter += 1;
} else if !inside(s, cp1, cp2) && inside(e, cp1, cp2) {
output_polygon.points.push(intersection(cp1, cp2, s, e));
output_polygon.points.push(e.clone());
counter += 1;
counter += 1;
} else if inside(s, cp1, cp2) && !inside(e, cp1, cp2) {
output_polygon.points.push(intersection(cp1, cp2, s, e));
counter += 1;
}
}
new_polygon_size = counter;
}
output_polygon
}