use crate::coordinate_systems::Face;
pub type Pentagon = [Face; 5];
pub type Triangle = [Face; 3];
#[derive(Debug, Clone)]
pub struct PentagonShape {
vertices: Vec<Face>,
}
impl PentagonShape {
pub fn new(vertices: Pentagon) -> Self {
let mut pentagon = Self {
vertices: vertices.to_vec(),
};
if !pentagon.is_winding_correct() {
pentagon.vertices.reverse();
}
pentagon
}
pub fn new_triangle(vertices: Triangle) -> Self {
let mut pentagon = Self {
vertices: vertices.to_vec(),
};
if !pentagon.is_winding_correct() {
pentagon.vertices.reverse();
}
pentagon
}
fn from_vertices(vertices: Vec<Face>) -> Self {
let mut pentagon = Self { vertices };
if !pentagon.is_winding_correct() {
pentagon.vertices.reverse();
}
pentagon
}
pub fn get_area(&self) -> f64 {
let mut signed_area = 0.0;
let n = self.vertices.len();
for i in 0..n {
let j = (i + 1) % n;
signed_area += (self.vertices[j].x() - self.vertices[i].x())
* (self.vertices[j].y() + self.vertices[i].y());
}
signed_area
}
fn is_winding_correct(&self) -> bool {
self.get_area() >= 0.0
}
pub fn get_vertices(&self) -> Pentagon {
let mut pentagon = [Face::new(0.0, 0.0); 5];
for (i, vertex) in self.vertices.iter().enumerate().take(5) {
pentagon[i] = *vertex;
}
pentagon
}
pub fn get_vertices_vec(&self) -> &Vec<Face> {
&self.vertices
}
pub fn scale(&mut self, scale: f64) -> &mut Self {
for vertex in &mut self.vertices {
*vertex = Face::new(vertex.x() * scale, vertex.y() * scale);
}
self
}
pub fn rotate180(&mut self) -> &mut Self {
for vertex in &mut self.vertices {
*vertex = Face::new(-vertex.x(), -vertex.y());
}
self
}
pub fn reflect_y(&mut self) -> &mut Self {
for vertex in &mut self.vertices {
*vertex = Face::new(vertex.x(), -vertex.y());
}
self.vertices.reverse();
self
}
pub fn translate(&mut self, translation: Face) -> &mut Self {
for vertex in &mut self.vertices {
*vertex = Face::new(vertex.x() + translation.x(), vertex.y() + translation.y());
}
self
}
pub fn get_center(&self) -> Face {
let n = self.vertices.len() as f64;
let (sum_x, sum_y) = self.vertices.iter().fold((0.0, 0.0), |(sum_x, sum_y), v| {
(sum_x + v.x() / n, sum_y + v.y() / n)
});
Face::new(sum_x, sum_y)
}
pub fn contains_point(&self, point: Face) -> f64 {
if !self.is_winding_correct() {
panic!("Pentagon is not counter-clockwise");
}
let n = self.vertices.len();
let mut d_max: f64 = 1.0;
for i in 0..n {
let v1 = self.vertices[i];
let v2 = self.vertices[(i + 1) % n];
let dx = v1.x() - v2.x();
let dy = v1.y() - v2.y();
let px = point.x() - v1.x();
let py = point.y() - v1.y();
let cross_product = dx * py - dy * px;
if cross_product < 0.0 {
let p_length = (px * px + py * py).sqrt();
d_max = d_max.min(cross_product / p_length);
}
}
d_max
}
pub fn split_edges(&self, segments: usize) -> PentagonShape {
if segments <= 1 {
return self.clone();
}
let mut new_vertices = Vec::new();
let n = self.vertices.len();
for i in 0..n {
let v1 = self.vertices[i];
let v2 = self.vertices[(i + 1) % n];
new_vertices.push(v1);
for j in 1..segments {
let t = j as f64 / segments as f64;
let interpolated = Face::new(
v1.x() + t * (v2.x() - v1.x()),
v1.y() + t * (v2.y() - v1.y()),
);
new_vertices.push(interpolated);
}
}
PentagonShape::from_vertices(new_vertices)
}
}