use num_traits::ToPrimitive;
use crate::{
geometry::util::EPS,
numeric::{
cgar_rational::CgarRational,
lazy_exact::LazyExact,
scalar::{FromRef, RefInto, Scalar},
},
operations::{Abs, One, Zero},
};
use std::{
cmp::Ordering,
hash::Hash,
ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign},
};
#[derive(Clone, Debug)]
pub struct CgarF64(pub f64);
impl Default for CgarF64 {
fn default() -> Self {
CgarF64(0.0)
}
}
impl Scalar for CgarF64 {
fn from_num_den(num: i32, den: i32) -> Self {
CgarF64(num as f64 / den as f64)
}
fn tolerance() -> Self {
return Self(EPS);
}
fn tolerance_squared() -> Self {
let tol = Self::tolerance();
CgarF64(tol.0 * tol.0)
}
fn point_merge_threshold() -> Self {
CgarF64(1e-6)
}
fn edge_degeneracy_threshold() -> Self {
CgarF64(1e-5)
}
fn area_degeneracy_threshold() -> Self {
CgarF64(EPS) }
fn query_tolerance() -> Self {
CgarF64(EPS)
}
fn query_tolerance_squared() -> Self {
let tol = Self::query_tolerance();
CgarF64(tol.0 * tol.0)
}
fn point_merge_threshold_squared() -> Self {
let tol = Self::point_merge_threshold();
CgarF64(tol.0 * tol.0)
}
fn sign(&self) -> i8 {
if self.is_positive() {
1
} else if self.is_negative() {
-1
} else {
0
}
}
fn approx_eq(&self, other: &Self) -> bool {
return (self.0 - other.0).abs() < EPS;
}
#[inline(always)]
fn cmp_ref(a: &Self, b: &Self) -> Ordering {
a.0.total_cmp(&b.0)
}
fn as_f64_fast(&self) -> Option<f64> {
Some(self.0)
}
fn double_interval(&self) -> Option<(f64, f64)> {
Some((self.0, self.0))
}
fn ball_center_f64(&self) -> f64 {
self.0
}
}
impl<'a, 'b> Add<&'b CgarF64> for &'a CgarF64 {
type Output = CgarF64;
fn add(self, rhs: &'b CgarF64) -> CgarF64 {
let mut result = self.0.clone();
result += &rhs.0;
CgarF64(result)
}
}
impl Add for CgarF64 {
type Output = CgarF64;
fn add(self, rhs: CgarF64) -> CgarF64 {
&self + &rhs }
}
impl<'a, 'b> Sub<&'b CgarF64> for &'a CgarF64 {
type Output = CgarF64;
fn sub(self, rhs: &'b CgarF64) -> CgarF64 {
let mut result = self.0.clone();
result -= &rhs.0;
CgarF64(result)
}
}
impl Sub for CgarF64 {
type Output = CgarF64;
fn sub(self, rhs: CgarF64) -> CgarF64 {
&self - &rhs }
}
impl<'a, 'b> Mul<&'b CgarF64> for &'a CgarF64 {
type Output = CgarF64;
fn mul(self, rhs: &'b CgarF64) -> CgarF64 {
let mut result = self.0.clone();
result *= &rhs.0;
CgarF64(result)
}
}
impl Mul for CgarF64 {
type Output = CgarF64;
fn mul(self, rhs: CgarF64) -> CgarF64 {
&self * &rhs }
}
impl<'a, 'b> Div<&'b CgarF64> for &'a CgarF64 {
type Output = CgarF64;
fn div(self, rhs: &'b CgarF64) -> CgarF64 {
let mut result = self.0.clone();
result /= &rhs.0;
CgarF64(result)
}
}
impl<'c> AddAssign<&'c CgarF64> for CgarF64 {
fn add_assign(&mut self, rhs: &'c CgarF64) {
self.0 += &rhs.0;
}
}
impl<'d> SubAssign<&'d CgarF64> for CgarF64 {
fn sub_assign(&mut self, rhs: &'d CgarF64) {
self.0 -= &rhs.0;
}
}
impl Div for CgarF64 {
type Output = CgarF64;
fn div(self, rhs: CgarF64) -> CgarF64 {
&self / &rhs }
}
impl From<i32> for CgarF64 {
fn from(value: i32) -> Self {
CgarF64(value as f64)
}
}
impl From<f64> for CgarF64 {
fn from(value: f64) -> Self {
CgarF64(value)
}
}
impl From<CgarF64> for f64 {
fn from(value: CgarF64) -> Self {
value.0
}
}
impl From<rug::Rational> for CgarF64 {
fn from(value: rug::Rational) -> Self {
CgarF64(value.to_f64())
}
}
impl From<CgarRational> for CgarF64 {
fn from(value: CgarRational) -> Self {
CgarF64(value.0.to_f64())
}
}
impl From<LazyExact> for CgarF64 {
fn from(value: LazyExact) -> Self {
value.approx()
}
}
impl ToPrimitive for CgarF64 {
fn to_i64(&self) -> Option<i64> {
Some(self.0 as i64)
}
fn to_u64(&self) -> Option<u64> {
Some(self.0 as u64)
}
fn to_f32(&self) -> Option<f32> {
Some(self.0 as f32)
}
fn to_f64(&self) -> Option<f64> {
Some(self.0)
}
}
impl FromRef<CgarF64> for CgarF64 {
fn from_ref(value: &CgarF64) -> Self {
value.clone()
}
}
impl FromRef<CgarRational> for CgarF64 {
fn from_ref(value: &CgarRational) -> Self {
CgarF64(value.to_f64().unwrap_or(0.0))
}
}
impl FromRef<LazyExact> for CgarF64 {
fn from_ref(value: &LazyExact) -> Self {
value.approx()
}
}
impl RefInto<CgarF64> for CgarF64 {
fn ref_into(&self) -> CgarF64 {
self.clone()
}
}
impl RefInto<CgarRational> for CgarF64 {
fn ref_into(&self) -> CgarRational {
CgarRational::from(self.0)
}
}
impl RefInto<LazyExact> for CgarF64 {
fn ref_into(&self) -> LazyExact {
LazyExact::from_cgar_f64(self.clone())
}
}
impl PartialEq for CgarF64 {
fn eq(&self, other: &CgarF64) -> bool {
self.0.to_bits() == other.0.to_bits() }
}
impl PartialOrd for CgarF64 {
fn partial_cmp(&self, other: &CgarF64) -> Option<std::cmp::Ordering> {
let diff = self.0 - other.0;
if diff.abs() < EPS {
return Some(std::cmp::Ordering::Equal);
}
if diff > EPS {
return Some(std::cmp::Ordering::Greater);
}
if diff < -EPS {
return Some(std::cmp::Ordering::Less);
}
self.0.partial_cmp(&other.0)
}
}
impl Hash for CgarF64 {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.to_bits().hash(state);
}
}
impl Eq for CgarF64 {}
impl crate::operations::Zero for CgarF64 {
fn zero() -> Self {
CgarF64(0.0)
}
fn is_zero(&self) -> bool {
self.0.abs() < EPS
}
fn is_positive(&self) -> bool {
self.0 > EPS
}
fn is_negative(&self) -> bool {
self.0 < -EPS
}
fn is_positive_or_zero(&self) -> bool {
self.0 >= -EPS
}
fn is_negative_or_zero(&self) -> bool {
self.0 <= EPS
}
}
impl One for CgarF64 {
fn one() -> Self {
CgarF64(1.0)
}
}
impl Abs for CgarF64 {
fn abs(&self) -> Self {
CgarF64(self.0.abs())
}
}
impl Neg for CgarF64 {
type Output = CgarF64;
fn neg(self) -> CgarF64 {
CgarF64(-self.0)
}
}
impl<'a> Neg for &'a CgarF64 {
type Output = CgarF64;
fn neg(self) -> CgarF64 {
CgarF64(-&self.0)
}
}