<commit_before>use std::ops::{Add, Sub, Mul, Neg};

use math::Matrix4;

macro_rules! define_struct {
    ($T: ident) => (
        #[derive(Debug, Copy, Clone)]
        pub struct $T {
            pub x: f64,
            pub y: f64,
            pub z: f64,
        }
    )
}

define_struct!(Vector3);
define_struct!(Point3);

macro_rules! define_impl {
    ($T: ident) => (
        impl $T {
            pub fn new(x: f64, y: f64, z: f64) -> $T {
                $T { x: x, y: y, z: z }
            }

        }

    )
}

define_impl!(Vector3);
define_impl!(Point3);

// Vector 3 specific
impl Vector3 {
    pub fn dot(&self, other: &Self) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }

    pub fn cross(&self, other: &Self) -> Self {
        let x0 = self.y * other.z - self.z * other.y;
        let y0 = self.z * other.x - self.x * other.z;
        let z0 = self.x * other.y - self.y * other.x;

        Vector3 {
            x: x0,
            y: y0,
            z: z0,
        }
    }

    pub fn reflect(&self, normal: &Self) -> Self {
        *self - *normal * (2.0 * self.dot(&normal))
    }

    pub fn length(&self) -> f64 {
        self.dot(&self).sqrt()
    }

    pub fn normalize(&self) -> Self {
        let l = self.length();

        if l == 0.0 {
            return Vector3 {
                       x: 0.0,
                       y: 0.0,
                       z: 0.0,
                   };
        }

        Vector3 {
            x: self.x / l,
            y: self.y / l,
            z: self.z / l,
        }
    }

    pub fn as_point(&self) -> Point3 {
        Point3::new(self.x, self.y, self.z)
    }
}

// Point3 specific
impl Point3 {
    pub fn at_origin() -> Point3 {
        Point3::new(0.0, 0.0, 0.0)
    }

    pub fn as_vector(&self) -> Vector3 {
        Vector3::new(self.x, self.y, self.z)
    }
}


// Operators

macro_rules! define_scalar_add {
    ($T: ty) => (
        impl Add<$T> for Vector3 {
            type Output = Vector3;

            fn add(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x + (other as f64),
                    y: self.y + (other as f64),
                    z: self.z + (other as f64),
                }
            }
        }
    )
}

macro_rules! define_add {
    ($T: ident, $V: ident, $U: ident) => (
        impl Add<$V> for $T {
            type Output = $U;

            fn add(self, other: $V) -> $U {
                $U {
                    x: self.x + other.x,
                    y: self.y + other.y,
                    z: self.z + other.z,
                }
            }
        }
    )
}

define_add!(Vector3, Vector3, Vector3);
define_add!(Point3, Vector3, Vector3);


define_scalar_add!(f64);
define_scalar_add!(f32);
define_scalar_add!(i8);
define_scalar_add!(i16);
define_scalar_add!(i32);
define_scalar_add!(i64);
define_scalar_add!(u8);
define_scalar_add!(u16);
define_scalar_add!(u32);
define_scalar_add!(u64);

macro_rules! define_scalar_sub {
    ($T: ty) => (
        impl Sub<$T> for Vector3 {
            type Output = Vector3;

            fn sub(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x - (other as f64),
                    y: self.y - (other as f64),
                    z: self.z - (other as f64),
                }
            }
        }
    )
}

macro_rules! define_sub {
    ($T: ident, $V: ident, $U: ident) => (
        impl Sub<$V> for $T {
            type Output = $U;

            fn sub(self, other: $V) -> $U {
                $U {
                    x: self.x - other.x,
                    y: self.y - other.y,
                    z: self.z - other.z,
                }
            }
        }
    )
}

define_sub!(Point3, Point3, Vector3);
define_sub!(Vector3, Vector3, Vector3);

define_scalar_sub!(f64);
define_scalar_sub!(f32);
define_scalar_sub!(i8);
define_scalar_sub!(i16);
define_scalar_sub!(i32);
define_scalar_sub!(i64);
define_scalar_sub!(u8);
define_scalar_sub!(u16);
define_scalar_sub!(u32);
define_scalar_sub!(u64);

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}


macro_rules! define_scalar_mul {
    ($T: ty) => (
        impl Mul<$T> for Vector3 {
            type Output = Vector3;

            fn mul(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x * (other as f64),
                    y: self.y * (other as f64),
                    z: self.z * (other as f64),
                }
            }
        }
    )
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
        }
    }
}

define_scalar_mul!(f64);
define_scalar_mul!(f32);
define_scalar_mul!(i8);
define_scalar_mul!(i16);
define_scalar_mul!(i32);
define_scalar_mul!(i64);
define_scalar_mul!(u8);
define_scalar_mul!(u16);
define_scalar_mul!(u32);
define_scalar_mul!(u64);

impl Mul<Matrix4> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: Matrix4) -> Vector3 {
        Vector3::new(other[(0, 0)] * self.x + other[(1, 0)] * self.y + other[(2, 0)] * self.z,
                     other[(0, 1)] * self.x + other[(1, 1)] * self.y + other[(2, 1)] * self.z,
                     other[(0, 2)] * self.x + other[(1, 2)] * self.y + other[(2, 2)] * self.z)
    }
}

impl Mul<Matrix4> for Point3 {
    type Output = Point3;

    fn mul(self, other: Matrix4) -> Point3 {
        Point3::new(other[(0, 0)] * self.x + other[(1, 0)] * self.y + other[(2, 0)] * self.z +
                    other[(3, 0)],
                    other[(0, 1)] * self.x + other[(1, 1)] * self.y + other[(2, 1)] * self.z +
                    other[(3, 1)],
                    other[(0, 2)] * self.x + other[(1, 2)] * self.y + other[(2, 2)] * self.z +
                    other[(3, 2)])
    }
}


// TOOD: Improve tests for Point3
#[cfg(test)]
mod tests {
    use math::{EPSILON, Matrix4};
    use super::{Vector3, Point3};
    use std::f64::consts::PI;


    #[test]
    fn test_constructor() {
        let vec = Vector3 {
            x: 2.0,
            y: 1.0,
            z: 0.0,
        };

        assert_eq_within_bound!(vec.x, 2.0, EPSILON);
        assert_eq_within_bound!(vec.y, 1.0, EPSILON);
        assert_eq_within_bound!(vec.z, 0.0, EPSILON);
    }
<commit_msg>Correctly multiply points and matrices<commit_after>use std::ops::{Add, Sub, Mul, Neg};

use math::{Matrix4, EPSILON};

macro_rules! define_struct {
    ($T: ident) => (
        #[derive(Debug, Copy, Clone)]
        pub struct $T {
            pub x: f64,
            pub y: f64,
            pub z: f64,
        }
    )
}

define_struct!(Vector3);
define_struct!(Point3);

macro_rules! define_impl {
    ($T: ident) => (
        impl $T {
            pub fn new(x: f64, y: f64, z: f64) -> $T {
                $T { x: x, y: y, z: z }
            }

        }

    )
}

define_impl!(Vector3);
define_impl!(Point3);

// Vector 3 specific
impl Vector3 {
    pub fn dot(&self, other: &Self) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }

    pub fn cross(&self, other: &Self) -> Self {
        let x0 = self.y * other.z - self.z * other.y;
        let y0 = self.z * other.x - self.x * other.z;
        let z0 = self.x * other.y - self.y * other.x;

        Vector3 {
            x: x0,
            y: y0,
            z: z0,
        }
    }

    pub fn reflect(&self, normal: &Self) -> Self {
        *self - *normal * (2.0 * self.dot(&normal))
    }

    pub fn length(&self) -> f64 {
        self.dot(&self).sqrt()
    }

    pub fn normalize(&self) -> Self {
        let l = self.length();

        if l == 0.0 {
            return Vector3 {
                       x: 0.0,
                       y: 0.0,
                       z: 0.0,
                   };
        }

        Vector3 {
            x: self.x / l,
            y: self.y / l,
            z: self.z / l,
        }
    }

    pub fn as_point(&self) -> Point3 {
        Point3::new(self.x, self.y, self.z)
    }
}

// Point3 specific
impl Point3 {
    pub fn at_origin() -> Point3 {
        Point3::new(0.0, 0.0, 0.0)
    }

    pub fn as_vector(&self) -> Vector3 {
        Vector3::new(self.x, self.y, self.z)
    }
}


// Operators

macro_rules! define_scalar_add {
    ($T: ty) => (
        impl Add<$T> for Vector3 {
            type Output = Vector3;

            fn add(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x + (other as f64),
                    y: self.y + (other as f64),
                    z: self.z + (other as f64),
                }
            }
        }
    )
}

macro_rules! define_add {
    ($T: ident, $V: ident, $U: ident) => (
        impl Add<$V> for $T {
            type Output = $U;

            fn add(self, other: $V) -> $U {
                $U {
                    x: self.x + other.x,
                    y: self.y + other.y,
                    z: self.z + other.z,
                }
            }
        }
    )
}

define_add!(Vector3, Vector3, Vector3);
define_add!(Point3, Vector3, Vector3);


define_scalar_add!(f64);
define_scalar_add!(f32);
define_scalar_add!(i8);
define_scalar_add!(i16);
define_scalar_add!(i32);
define_scalar_add!(i64);
define_scalar_add!(u8);
define_scalar_add!(u16);
define_scalar_add!(u32);
define_scalar_add!(u64);

macro_rules! define_scalar_sub {
    ($T: ty) => (
        impl Sub<$T> for Vector3 {
            type Output = Vector3;

            fn sub(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x - (other as f64),
                    y: self.y - (other as f64),
                    z: self.z - (other as f64),
                }
            }
        }
    )
}

macro_rules! define_sub {
    ($T: ident, $V: ident, $U: ident) => (
        impl Sub<$V> for $T {
            type Output = $U;

            fn sub(self, other: $V) -> $U {
                $U {
                    x: self.x - other.x,
                    y: self.y - other.y,
                    z: self.z - other.z,
                }
            }
        }
    )
}

define_sub!(Point3, Point3, Vector3);
define_sub!(Vector3, Vector3, Vector3);

define_scalar_sub!(f64);
define_scalar_sub!(f32);
define_scalar_sub!(i8);
define_scalar_sub!(i16);
define_scalar_sub!(i32);
define_scalar_sub!(i64);
define_scalar_sub!(u8);
define_scalar_sub!(u16);
define_scalar_sub!(u32);
define_scalar_sub!(u64);

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}


macro_rules! define_scalar_mul {
    ($T: ty) => (
        impl Mul<$T> for Vector3 {
            type Output = Vector3;

            fn mul(self, other: $T) -> Vector3 {
                Vector3 {
                    x: self.x * (other as f64),
                    y: self.y * (other as f64),
                    z: self.z * (other as f64),
                }
            }
        }
    )
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
        }
    }
}

define_scalar_mul!(f64);
define_scalar_mul!(f32);
define_scalar_mul!(i8);
define_scalar_mul!(i16);
define_scalar_mul!(i32);
define_scalar_mul!(i64);
define_scalar_mul!(u8);
define_scalar_mul!(u16);
define_scalar_mul!(u32);
define_scalar_mul!(u64);

impl Mul<Matrix4> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: Matrix4) -> Vector3 {
        Vector3::new(other[(0, 0)] * self.x + other[(1, 0)] * self.y + other[(2, 0)] * self.z,
                     other[(0, 1)] * self.x + other[(1, 1)] * self.y + other[(2, 1)] * self.z,
                     other[(0, 2)] * self.x + other[(1, 2)] * self.y + other[(2, 2)] * self.z)
    }
}

impl Mul<Matrix4> for Point3 {
    type Output = Point3;

    fn mul(self, other: Matrix4) -> Point3 {
        let mut x = other[(0, 0)] * self.x + other[(1, 0)] * self.y + other[(2, 0)] * self.z +
                    other[(3, 0)];
        let mut y = other[(0, 1)] * self.x + other[(1, 1)] * self.y + other[(2, 1)] * self.z +
                    other[(3, 1)];
        let mut z = other[(0, 2)] * self.x + other[(1, 2)] * self.y + other[(2, 2)] * self.z +
                    other[(3, 2)];
        let w = other[(0, 3)] * self.x + other[(1, 3)] * self.y + other[(2, 3)] * self.z +
                other[(3, 3)];

        if !(w > (1.0 - EPSILON) && w < (1.0 + EPSILON)) &&
           !(w > (0.0 - EPSILON) && w < (0.0 + EPSILON)) {
            assert!(false, "Bad value for w {}", w);
            x /= w;
            y /= w;
            z /= w;
        }



        Point3::new(x, y, z)
    }
}


// TOOD: Improve tests for Point3
#[cfg(test)]
mod tests {
    use math::{EPSILON, Matrix4};
    use super::{Vector3, Point3};
    use std::f64::consts::PI;


    #[test]
    fn test_constructor() {
        let vec = Vector3 {
            x: 2.0,
            y: 1.0,
            z: 0.0,
        };

        assert_eq_within_bound!(vec.x, 2.0, EPSILON);
        assert_eq_within_bound!(vec.y, 1.0, EPSILON);
        assert_eq_within_bound!(vec.z, 0.0, EPSILON);
    }

{'fraction_non_alphanumeric': 0.157033400282675, 'fraction_numerical': 0.03600386818418508, 'mean_word_length': 1.484109386548411, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4969011', 'n_tokens_mistral': 5062, 'n_tokens_neox': 4748, 'n_words': 1109}