use crate::{Vect, Rect, Ray, IntersectionPoints};
use crate::math::Intersection;
#[derive(Copy, Clone, Debug)]
pub struct Circ {
pub c: Vect,
pub r: f32,
}
impl Circ {
#[inline]
pub fn new(x: f32, y: f32, r:f32) -> Self {
Self { r, c: Vect { x, y } }
}
#[inline]
pub fn contains(&self, pos: Vect) -> bool {
self.c.dist(pos) <= self.r
}
#[inline]
pub fn prj_x(&self, x: f32) -> f32 {
(self.r * self.r - (x - self.c.x).powi(2)).sqrt() - self.c.y
}
#[inline]
pub fn prj_y(&self, y: f32) -> f32 {
(self.r * self.r - (y - self.c.y).powi(2)).sqrt() - self.c.y
}
#[inline]
pub fn formula_x(&self, x: f32) -> (f32, f32) {
(2.0 * self.c.y, self.c.y * self.c.y - self.r * self.r + (x - self.c.x).powi(2))
}
#[inline]
pub fn formula_y(&self, y: f32) -> (f32, f32) {
(2.0 * self.c.x, self.c.x * self.c.x - self.r * self.r + (y - self.c.y).powi(2))
}
#[inline]
pub fn precise_prj(&self, arg: f32, formula: fn(&Self, f32) -> (f32, f32)) -> [Option<f32>; 2] {
let (b, c) = formula(self, arg);
let mut dis = b * b - 4.0 * c;
if dis < 0.0 {
return [None, None];
} else if dis == 0.0 {
return [Some(-b/2.0), None]
}
dis = dis.sqrt();
[Some((-b - dis)/2.0), Some((-b + dis)/2.0)]
}
#[inline]
pub fn precise_prj_x(&self, x: f32) -> [Option<f32>; 2] {
self.precise_prj(x, Self::formula_x)
}
#[inline]
pub fn precise_prj_y(&self, y: f32) -> [Option<f32>; 2] {
self.precise_prj(y, Self::formula_y)
}
}
impl Intersection<Circ> for Circ {
#[inline]
fn intersects(&self, o: &Circ) -> bool {
self.c.dist(o.c) < self.r + o.r
}
}
impl Intersection<Rect> for Circ {
#[inline]
fn intersects(&self, o: &Rect) -> bool {
o.intersects(self)
}
}
impl Intersection<Ray> for Circ {
#[inline]
fn intersects(&self, o: &Ray) -> bool {
o.intersects(self)
}
}
impl IntersectionPoints<Ray> for Circ {
#[inline]
fn intersects_points(&self, o: &Ray) -> [Option<Vect>; 2] {
o.intersects_points(self)
}
}
#[cfg(test)]
mod tests {
use super::Circ;
use crate::Vect;
#[test]
fn prj_test() {
let base = circ!(0, 0; 10);
assert_eq!(0.0 ,base.prj_y(10.0));
assert_eq!(0.0 ,base.prj_x(10.0));
assert_eq!(10.0 ,base.prj_y(0.0));
assert_eq!(10.0 ,base.prj_x(0.0));
}
#[test]
fn precise_pre_test() {
let base = circ!(0, 0; 10);
assert_eq!([Some(0.0), None] ,base.precise_prj_y(10.0));
assert_eq!([Some(0.0), None] ,base.precise_prj_x(10.0));
assert_eq!([Some(-8.0), Some(8.0)] ,base.precise_prj_y(6.0));
assert_eq!([Some(-8.0), Some(8.0)] ,base.precise_prj_x(6.0));
}
}