use super::*;
use crate::elements::polygons::Polyline;
use num_traits::FromPrimitive;
#[allow(unused_variables)]
impl<T> Ellipse<T>
where
T: Clone + Real + FloatConst,
{
pub fn new<P>(center: P, radius: (T, T), angle: T) -> Self
where
P: Into<Point<T>>,
{
Self { center: center.into(), radius, rotate: angle }
}
pub fn from_coefficient(a: T, b: T, c: T, d: T, e: T, f: T) -> Self {
let b = half(b);
let d = half(d);
let e = half(e);
let delta_s = minor_delta(&a, &b, &c);
let delta_m = major_delta(&a, &b, &c, &d, &e, &f);
let eta = eta_invariant(&a, &b, &c);
Self {
center: Point { x: center_x(&a, &b, &c, &d, &e, &delta_s), y: center_y(&a, &b, &c, &d, &e, &delta_s) },
radius: (major_axis(&a, &c, &delta_m, &delta_s, &eta), minor_axis(&a, &c, &delta_m, &delta_s, &eta)),
rotate: angle(&a, &b, &c),
}
}
pub fn from_5_points(p1: Point<T>, p2: Point<T>, p3: Point<T>, p4: Point<T>, p5: Point<T>) -> Self {
let (a, b, c, d, e, f) = null_space(&[
null_space_line(p1),
null_space_line(p2),
null_space_line(p3),
null_space_line(p4),
null_space_line(p5),
]);
Self::from_coefficient(a, b, c, d, e, f)
}
}
impl<T> Ellipse<T>
where
T: Zero + PartialEq,
{
pub fn is_horizontal(&self) -> bool {
self.rotate == T::zero()
}
}
impl<T> Ellipse<T>
where
T: Real,
{
pub fn major_axis(&self) -> &T {
&self.radius.0
}
pub fn minor_axis(&self) -> &T {
&self.radius.1
}
#[inline]
pub fn homogeneous(&self) -> (T, T, T, T, T, T) {
todo!()
}
#[inline]
pub fn coefficients(&self) -> (T, T, T, T, T, T) {
let (a, b, c, d, e, f) = self.homogeneous();
(a, half(b), c, half(d), half(e), f)
}
pub fn major_delta(&self) -> T {
let (a, b, c, d, e, f) = self.homogeneous();
major_delta(&a, &b, &c, &d, &e, &f)
}
pub fn minor_delta(&self) -> T {
let (a, b, c, _, _, _) = self.homogeneous();
minor_delta(&a, &b, &c)
}
}
impl<T> Ellipse<T>
where
T: Clone + Real + FromPrimitive + FloatConst,
{
#[track_caller]
pub fn sample_polygon(&self, n: usize) -> Polygon<T> {
debug_assert!(n >= 3, "at least 3 points");
let mut vertex = Vec::with_capacity(n);
for i in 0..n {
let angle = T::from_usize(i).unwrap() * two_pi() / T::from_usize(n).unwrap();
let x = self.sample_x(&angle);
let y = self.sample_y(&angle);
vertex.push(Point::new(x, y));
}
Polygon::new(vertex)
}
#[track_caller]
pub fn sample_polyline(&self, n: usize) -> Polyline<T> {
debug_assert!(n >= 3, "at least 3 points");
let mut vertex = Vec::with_capacity(n);
for i in 0..n {
let angle = T::from_usize(i).unwrap() * two_pi() / T::from_usize(n).unwrap();
let x = self.sample_x(&angle);
let y = self.sample_y(&angle);
vertex.push(Point::new(x, y));
}
todo!()
}
pub fn sample_x(&self, t: &T) -> T {
self.radius.0 * self.rotate.cos() * t.cos() - self.radius.1 * self.rotate.sin() * t.sin() + self.center.x
}
pub fn sample_y(&self, t: &T) -> T {
self.radius.0 * self.rotate.sin() * t.cos() + self.radius.1 * self.rotate.cos() * t.cos() + self.center.y
}
}
#[inline(always)]
fn major_delta<T>(a: &T, b: &T, c: &T, d: &T, e: &T, f: &T) -> T
where
T: Clone + Real,
{
let p1 = a.clone() + c.clone() + f.clone();
let p2 = two::<T>() * b.clone() * d.clone() + two::<T>() * e.clone() * f.clone();
let p3 = a.clone() * e.clone() * e.clone() + c.clone() * d.clone() * d.clone() + f.clone() * b.clone() * b.clone();
p1 + p2 - p3
}
#[inline(always)]
fn minor_delta<T>(a: &T, b: &T, c: &T) -> T
where
T: Clone + Real,
{
a.clone() * c.clone() - b.clone() * b.clone()
}
#[inline(always)]
fn eta_invariant<T>(a: &T, b: &T, c: &T) -> T
where
T: Clone + Real,
{
let p1 = a.clone() - c.clone();
let eta = p1.powi(2) + four::<T>() * b.powi(2);
eta.sqrt()
}
#[inline(always)]
fn center_x<T>(_: &T, b: &T, c: &T, d: &T, e: &T, delta_s: &T) -> T
where
T: Clone + Real,
{
let p1 = b.clone() * e.clone() - c.clone() * d.clone();
p1 / delta_s.clone()
}
#[inline(always)]
fn center_y<T>(a: &T, b: &T, _: &T, d: &T, e: &T, delta_s: &T) -> T
where
T: Clone + Real,
{
let p1 = b.clone() * d.clone() - a.clone() * e.clone();
p1 / delta_s.clone()
}
#[inline(always)]
fn major_axis<T>(a: &T, c: &T, delta_m: &T, delta_s: &T, eta: &T) -> T
where
T: Clone + Real,
{
let p1 = (a.clone() + c.clone() + eta.clone()) * delta_s.clone();
let axis = -double(delta_m) / p1;
axis.sqrt()
}
#[inline(always)]
fn minor_axis<T>(a: &T, c: &T, delta_m: &T, delta_s: &T, eta: &T) -> T
where
T: Clone + Real,
{
let p1 = (a.clone() + c.clone() - eta.clone()) * delta_s.clone();
let axis = -double(delta_m) / p1;
axis.sqrt()
}
fn angle<T>(a: &T, b: &T, c: &T) -> T
where
T: Clone + Real + FloatConst,
{
match b.is_zero() {
true if a < c => zero(),
true => half(pi()),
false if a < c => double(b).atan2(a.clone() - c.clone()),
false => half::<T>(pi()) - double(b).atan2(a.clone() - c.clone()),
}
}
fn null_space_line<T>(p: Point<T>) -> [T; 6]
where
T: Clone + Real,
{
[p.x.clone().powi(2), p.x.clone() * p.y.clone(), p.y.clone().powi(2), p.x.clone(), p.y.clone(), T::one()]
}
fn null_space<T: Clone + Real>(_matrix: &[[T; 6]; 5]) -> (T, T, T, T, T, T) {
todo!()
}