use crate::algorithms::convex_hull::graham_scan::convex_hull;
use crate::data::{Point, PointLocation, Polygon};
use crate::{Error, PolygonScalar, TotalOrd};
pub fn new_star_polygon<T>(
mut vertices: Vec<Point<T>>,
point: &Point<T>,
) -> Result<Polygon<T>, Error>
where
T: PolygonScalar + TotalOrd,
{
let hull = convex_hull(vertices.clone())?;
if hull.locate(point) == PointLocation::Outside {
return Err(Error::ConvexViolation);
}
vertices.sort_by(|a, b| point.ccw_cmp_around(a, b));
Polygon::new(vertices)
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
use test_strategy::proptest;
#[proptest]
fn star_polygon_is_valid(
#[strategy(proptest::collection::vec(any::<Point<i8, 2>>(), 3..20))] pts: Vec<Point<i8, 2>>,
) {
let sum_x: i32 = pts.iter().map(|p| *p.x_coord() as i32).sum();
let sum_y: i32 = pts.iter().map(|p| *p.y_coord() as i32).sum();
let n = pts.len() as i32;
let center = Point::new([(sum_x / n) as i8, (sum_y / n) as i8]);
if let Ok(p) = new_star_polygon(pts, ¢er) {
prop_assert!(p.validate().is_ok());
}
}
#[test]
fn center_outside_convex_hull_fails() {
let vertices = vec![
Point::new([0, 0]),
Point::new([4, 0]),
Point::new([4, 4]),
Point::new([0, 4]),
];
let center = Point::new([10, 10]); let result = new_star_polygon(vertices, ¢er);
assert!(matches!(result, Err(Error::ConvexViolation)));
}
#[test]
fn center_inside_convex_hull_succeeds() {
let vertices = vec![
Point::new([0, 0]),
Point::new([4, 0]),
Point::new([4, 4]),
Point::new([0, 4]),
];
let center = Point::new([2, 2]); let result = new_star_polygon(vertices, ¢er);
assert!(result.is_ok());
}
}