use std::f32::consts::PI;
use crossterm::style::Color;
use crate::{
shapes::{Orientation, Shape, triangle::Triangle},
types::{pos2::Pos2, vec2::Vec2},
};
pub struct Circle {
pub center: Pos2,
pub radius: f32,
pub orientation: Orientation,
pub color: Color,
pub z_index: i32,
triangles: Vec<Triangle>,
pub children: Vec<Box<dyn Shape>>,
}
impl Circle {
pub fn new(center: Pos2, radius: f32, n_sectors: usize, color: Color) -> Self {
let mut triangles = Vec::new();
let angle_per_triangle = (PI * 2.0) / n_sectors as f32;
let base_length = 2.0 * radius * (angle_per_triangle / 2.0).sin();
for i in 0..n_sectors {
let theta = i as f32 * (2.0 * std::f32::consts::PI) / n_sectors as f32;
let triangle = Triangle::new(
center,
Orientation::Custom(theta),
Vec2::new(radius, base_length),
color,
);
triangles.push(triangle);
}
triangles.sort_by_key(|t| t.z_index);
Self {
center,
radius,
orientation: Orientation::Custom(0.0),
color,
z_index: 0,
triangles,
children: vec![],
}
}
pub fn push(&mut self, child: Box<dyn Shape>) {
self.children.push(child);
}
pub fn z_index(&self) -> i32 {
self.z_index
}
}
impl Clone for Circle {
fn clone(&self) -> Self {
let n_sectors = self.triangles.len();
let mut c = Circle::new(self.center, self.radius, n_sectors, self.color);
c.orientation = self.orientation;
c.z_index = self.z_index;
c.children = self.children.iter().map(|c| c.clone()).collect();
c
}
}
impl Shape for Circle {
fn draw(&self) {
for triangle in &self.triangles {
triangle.draw();
}
for child in &self.children {
child.draw();
}
}
fn update(&mut self) {
for triangle in &mut self.triangles {
triangle.update();
}
self.triangles.sort_by_key(|t| t.z_index);
self.children.sort_by_key(|child| child.z_index());
let parent_pos: Vec2<f32> = self.pos().into();
for child in &mut self.children {
let relative_pos = child.pos().to_relative(parent_pos);
if let Pos2::Relative(_) = relative_pos {
child.set_pos(relative_pos);
}
child.update();
}
}
fn set_orientation(&mut self, orientation: Orientation) {
self.orientation = orientation;
}
fn orientation(&self) -> Orientation {
self.orientation
}
fn z_index(&self) -> i32 {
self.z_index
}
fn pos(&self) -> Pos2 {
self.center
}
fn set_pos(&mut self, pos: Pos2) {
self.center = pos;
}
fn box_clone(&self) -> Box<dyn Shape> {
Box::new(self.clone())
}
fn collides_with(&self, other: &dyn Shape) -> bool {
let other_pos: Vec2<f32> = other.pos().into();
let center: Vec2<f32> = self.center.into();
let dx = other_pos.x - center.x;
let dy = other_pos.y - center.y;
(dx * dx + dy * dy) <= (self.radius * self.radius)
}
}