use std::ops::{Add, Div, Mul, Sub}; #[derive(Clone, Copy)] pub struct Vec3 { x: f64, y: f64, z: f64, } #[derive(Clone, Copy)] pub struct Point3 { x: f64, y: f64, z: f64, } #[derive(Clone, Copy)] pub struct Ray { direction: Vec3, origin: Point3, } impl Ray { pub fn new(origin: Point3, direction: Vec3) -> Ray { Ray { direction, origin } } pub fn at(self, t: f64) -> Point3 { (self.origin.to_vec() + Vec3 { x: t, y: t, z: t } * self.direction).to_point() } pub fn direction(self) -> Vec3 { self.direction } pub fn origin(self) -> Point3 { self.origin } } macro_rules! impl_op { ($trait:ident, $func:ident, $op:tt, $who:ident) => { impl $trait for $who { type Output = Self; fn $func(self, other: Self) -> Self { Self { x: self.x $op other.x, y: self.y $op other.y, z: self.z $op other.z, } } } impl $trait for $who { type Output = Self; fn $func(self, value: f64) -> Self { Self { x: self.x $op value, y: self.y $op value, z: self.z $op value, } } } }; } impl_op!(Add, add, +,Vec3); impl_op!(Sub, sub, -,Vec3); impl_op!(Mul, mul, *,Vec3); impl_op!(Div, div, /,Vec3); impl_op!(Add, add, +,Point3); impl_op!(Sub, sub, -,Point3); impl_op!(Mul, mul, *,Point3); impl_op!(Div, div, /,Point3); impl Point3 { pub fn new(x: f64, y: f64, z: f64) -> Point3 { Point3 { x, y, z } } pub fn to_vec(self) -> Vec3 { Vec3 { x: self.x, y: self.y, z: self.z, } } } impl Vec3 { pub fn new(x: f64, y: f64, z: f64) -> Vec3 { Vec3 { x, y, z } } pub fn full(v: f64) -> Vec3 { Vec3 { x: v, y: v, z: v } } pub fn to_point(self) -> Point3 { Point3 { x: self.x, y: self.y, z: self.z, } } pub fn dot(self, other: Vec3) -> f64 { self.x * other.x + self.y * other.y + self.z * other.z } pub fn x(self) -> f64 { self.x } pub fn y(self) -> f64 { self.y } pub fn z(self) -> f64 { self.z } pub fn cross(self, other: Vec3) -> Vec3 { let x = self.y * other.z - self.z * other.y; let y = self.y * other.x - self.x * other.y; let z = self.x * other.y - self.y * other.x; Vec3 { x, y, z } } pub fn length_squared(self) -> f64 { self.x * self.x + self.y * self.y + self.z * self.z } pub fn length(self) -> f64 { self.length_squared().sqrt() } pub fn unit(self) -> Vec3 { self / self.length() } }