use crate::{
math::{
geometry::{positioning::*, Pos2D, Shape},
ConstZero, ConvenientOps, NumberWithMonotoneOps,
},
prelude::Sqrt,
};
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[allow(missing_docs)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Circle<T, const CS: bool> {
pub radius: T,
pub half_radius: T,
}
impl<const CS: bool, T: NumberWithMonotoneOps + Copy + ConvenientOps>
Circle<T, CS>
{
#[allow(missing_docs)]
pub fn new(radius: T) -> Self {
Self {
radius,
half_radius: radius.half(),
}
}
}
impl<T, const CS: bool> Shape<T> for Circle<T, CS> {}
impl<const CS: bool, T: NumberWithMonotoneOps + Copy> Pos2D<T, Circle<T, CS>> {
pub fn does_area_contain_point(&self, point: (T, T)) -> bool {
let dx = point.0 - (self.get_x() + self.get_shape().half_radius);
let dy = point.1 - (self.get_x() + self.get_shape().half_radius);
dx * dx + dy * dy <= self.get_shape().radius * self.get_shape().radius
}
}
impl<const CS: bool, T: NumberWithMonotoneOps + Copy + ConstZero + Sqrt>
Pos2D<T, Circle<T, CS>>
{
pub fn get_closest_point_on_edge(&self, point: (T, T)) -> (T, T) {
let cx = self.get_x() + self.get_shape().half_radius;
let cy = self.get_y() + self.get_shape().half_radius;
let dx = point.0 - cx;
let dy = point.1 - cy;
let dist_sq = dx * dx + dy * dy;
if core::intrinsics::unlikely(dist_sq == T::ZERO) {
return (cx + self.get_shape().radius, cy); }
let dist = dist_sq.sqrt();
let scale = self.get_shape().radius / dist;
(cx + dx * scale, cy + dy * scale)
}
}