use num_traits::identities;
use rand::{self, RngCore};
use std::{convert, ops};
use crate::scalar::{RandFloat, Scalar, ScalarFloat};
#[derive(Clone, Copy, Debug)]
pub struct Gec<S: Scalar, const DIM: usize>(pub [S; DIM]);
impl<S: Scalar, const DIM: usize> Gec<S,DIM> {
pub fn scale(mut self, by: S) -> Self {
for i in 0..DIM {
self[i] *= by;
}
self
}
}
impl<S: Scalar, const DIM: usize> ops::Index<usize> for Gec<S, DIM> {
type Output = S;
fn index<'a>(&'a self, i: usize) -> &'a S {
&self.0[i]
}
}
impl<T: Scalar, const DIM: usize> ops::IndexMut<usize> for Gec<T, DIM> {
fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut T {
&mut self.0[i]
}
}
impl<T: Scalar + ops::AddAssign, const DIM: usize> ops::AddAssign for Gec<T, DIM> {
fn add_assign(&mut self, rhs: Self) {
for n in 0..DIM {
self.0[n] += rhs.0[n];
}
}
}
impl<S: Scalar + ops::SubAssign, const DIM: usize> ops::SubAssign for Gec<S, DIM> {
fn sub_assign(&mut self, rhs: Self) {
for n in 0..DIM {
self.0[n] -= rhs.0[n];
}
}
}
impl<T: Scalar + ops::MulAssign, const DIM: usize> ops::MulAssign for Gec<T, DIM> {
fn mul_assign(&mut self, rhs: Self) {
for n in 0..DIM {
self.0[n] *= rhs.0[n];
}
}
}
impl<S: Scalar + ops::DivAssign, const DIM: usize> ops::DivAssign for Gec<S, DIM> {
fn div_assign(&mut self, rhs: Self) {
for n in 0..DIM {
self.0[n] *= rhs.0[n];
}
}
}
impl<S: Scalar, const DIM: usize> ops::Add<&Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn add(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
self += rhs;
self
}
}
impl<S: Scalar, const DIM: usize> ops::Add<Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn add(self, rhs: Gec<S, DIM>) -> Self::Output {
self + &rhs
}
}
impl<S: Scalar, const DIM: usize> ops::Add<Gec<S, DIM>> for &Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn add(self, rhs: Gec<S, DIM>) -> Self::Output {
rhs + self
}
}
impl<S: Scalar, const DIM: usize> ops::Sub<&Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn sub(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
self -= rhs;
self
}
}
impl<S: Scalar, const DIM: usize> ops::Sub<Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn sub(self, rhs: Gec<S, DIM>) -> Self::Output {
self - &rhs
}
}
impl<S: Scalar, const DIM: usize> ops::Sub<Gec<S, DIM>> for &Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn sub(self, mut rhs: Gec<S, DIM>) -> Self::Output {
for i in 0..DIM {
rhs[i] = self[i] - rhs[i];
}
rhs
}
}
impl<S: Scalar, const DIM: usize> ops::Mul<&Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn mul(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
self *= rhs;
self
}
}
impl<S: Scalar, const DIM: usize> ops::Mul<Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn mul(self, rhs: Gec<S, DIM>) -> Self::Output {
self * &rhs
}
}
impl<S: Scalar, const DIM: usize> ops::Mul<Gec<S, DIM>> for &Gec<S, DIM> {
type Output = Gec<S, DIM>;
fn mul(self, rhs: Gec<S, DIM>) -> Self::Output {
rhs * self
}
}
impl<S: Scalar, const DIM: usize> ops::Div<&Gec<S, DIM>> for Gec<S, DIM> {
type Output = Gec<S,DIM>;
fn div(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
self /= rhs;
self
}
}
impl<S: Scalar, const DIM: usize> ops::Neg for Gec<S, DIM> {
type Output = Self;
fn neg(mut self) -> Self::Output {
for i in 0..DIM {
self[i] = <S as Scalar>::zero() - self[i];
}
self
}
}
impl<S: Scalar + ops::AddAssign, const DIM: usize> ops::AddAssign<&Gec<S, DIM>> for Gec<S, DIM> {
fn add_assign(&mut self, rhs: &Gec<S, DIM>) {
for n in 0..DIM {
self.0[n] += rhs.0[n];
}
}
}
impl<S: Scalar + ops::SubAssign, const DIM: usize> ops::SubAssign<&Gec<S, DIM>> for Gec<S, DIM> {
fn sub_assign(&mut self, rhs: &Gec<S, DIM>) {
for n in 0..DIM {
self.0[n] -= rhs.0[n];
}
}
}
impl<S: Scalar + ops::MulAssign, const DIM: usize> ops::MulAssign<&Gec<S, DIM>> for Gec<S, DIM> {
fn mul_assign(&mut self, rhs: &Gec<S, DIM>) {
for n in 0..DIM {
self.0[n] *= rhs.0[n];
}
}
}
impl<S: Scalar + ops::DivAssign, const DIM: usize> ops::DivAssign<&Gec<S, DIM>> for Gec<S, DIM> {
fn div_assign(&mut self, rhs: &Gec<S, DIM>) {
for n in 0..DIM {
self.0[n] /= rhs.0[n];
}
}
}
impl<const DIM: usize> ops::Mul<Gec<f32, DIM>> for f32 {
type Output = Gec<f32, DIM>;
fn mul(self, rhs: Gec<f32, DIM>) -> Self::Output {
rhs.scale(self)
}
}
impl<const DIM: usize> ops::Mul<Gec<f64, DIM>> for f64 {
type Output = Gec<f64, DIM>;
fn mul(self, rhs: Gec<f64, DIM>) -> Self::Output {
rhs.scale(self)
}
}
impl<S: Scalar, const DIM: usize> convert::From<[S; DIM]> for Gec<S, DIM> {
fn from(value: [S; DIM]) -> Self {
Self(value)
}
}
impl<S: Scalar, const DIM: usize> Gec<S, DIM> {
pub fn zero() -> Self {
Gec([identities::zero(); DIM])
}
pub fn ones() -> Self {
Gec([identities::one(); DIM])
}
pub fn dot(self, other: Self) -> S {
self.0
.iter()
.zip(other.0.iter())
.fold(identities::zero(), |acc, (&l, &r)| acc + l * r)
}
pub fn length_squared(self) -> S {
self.dot(self)
}
}
impl<S: ScalarFloat, const DIM: usize> Gec<S, DIM> {
pub fn length(self) -> S {
self.length_squared().sqrt()
}
pub fn to_unit(self) -> Self {
self.scale(<S as Scalar>::one() / self.length())
}
}
impl<S: RandFloat, const DIM: usize> Gec<S, DIM> {
pub fn random<R: RngCore + ?Sized>(r: &mut R) -> Self {
let mut arr: [S; DIM] = [identities::zero(); DIM];
for x in &mut arr[..] {
*x = S::sample01(r);
}
Self::from(arr)
}
pub fn random_openclosed<R: RngCore + ?Sized>(r: &mut R) -> Self {
let mut arr: [S; DIM] = [identities::zero(); DIM];
for x in &mut arr[..] {
*x = S::sample01_openclosed(r);
}
Self::from(arr)
}
pub fn random_unit<R: RngCore + ?Sized>(rng: &mut R) -> Self {
let v = Self::random(rng);
v.scale(<S as Scalar>::one() / v.length())
}
pub fn random_on_hemisphere<R: RngCore + ?Sized>(rng: &mut R, normal: Self) -> Self {
let attempt = Self::random_unit(rng);
if attempt.dot(normal) > <S as Scalar>::one() {
attempt
} else {
-attempt
}
}
pub fn random_in_unit_disk<R: RngCore + ?Sized>(rng: &mut R) -> Self {
loop {
let mut v = Self::random(rng);
v[DIM - 1] = <S as Scalar>::zero();
if v.length_squared() < <S as Scalar>::one() {
break v;
}
}
}
}
impl<S: Scalar> Gec<S, 3> {
pub fn cross(self, other: Self) -> Self {
Self::from([
self[1] * other[2] - self[2] * other[1],
self[2] * other[0] - self[0] * other[2],
self[0] * other[1] - self[1] * other[0],
])
}
pub fn to_homogeneous(&self) -> Gec<S, 4> {
Gec::from([self[0], self[1], self[2], identities::one()])
}
}