use std::convert::TryFrom;
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
use crate::color::Color;
use crate::math::Vec3;
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Point3 {
pub const ZERO: Point3 = Point3 {
x: 0.0,
y: 0.0,
z: 0.0,
};
pub fn new(x: f64, y: f64, z: f64) -> Self {
Point3 { x, y, z }
}
pub fn splat(value: f64) -> Self {
Point3 {
x: value,
y: value,
z: value,
}
}
pub fn to_vec3(&self) -> Vec3 {
(*self).into()
}
}
impl Add<Point3> for Point3 {
type Output = Point3;
fn add(self, rhs: Point3) -> Self::Output {
Point3 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl AddAssign<Point3> for Point3 {
fn add_assign(&mut self, rhs: Point3) {
*self = *self + rhs;
}
}
impl Add<Vec3> for Point3 {
type Output = Point3;
fn add(self, rhs: Vec3) -> Self::Output {
Point3 {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z,
}
}
}
impl AddAssign<Vec3> for Point3 {
fn add_assign(&mut self, rhs: Vec3) {
*self = *self + rhs;
}
}
impl Sub<Point3> for Point3 {
type Output = Vec3;
fn sub(self, rhs: Point3) -> Self::Output {
Vec3::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
impl Sub<Vec3> for Point3 {
type Output = Point3;
fn sub(self, rhs: Vec3) -> Self::Output {
Point3 {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
impl SubAssign<Vec3> for Point3 {
fn sub_assign(&mut self, rhs: Vec3) {
*self = *self - rhs;
}
}
impl Mul<f64> for Point3 {
type Output = Point3;
fn mul(self, rhs: f64) -> Self {
Point3 {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}
impl MulAssign<f64> for Point3 {
fn mul_assign(&mut self, rhs: f64) {
*self = *self * rhs;
}
}
impl Mul<Point3> for f64 {
type Output = Point3;
fn mul(self, rhs: Point3) -> Self::Output {
rhs * self
}
}
impl Div<f64> for Point3 {
type Output = Point3;
fn div(self, rhs: f64) -> Self::Output {
let rhs_inverse = 1.0 / rhs;
Point3 {
x: self.x * rhs_inverse,
y: self.y * rhs_inverse,
z: self.z * rhs_inverse,
}
}
}
impl DivAssign<f64> for Point3 {
fn div_assign(&mut self, rhs: f64) {
*self = *self / rhs;
}
}
impl Neg for Point3 {
type Output = Point3;
fn neg(self) -> Self::Output {
Point3 {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}
impl From<[f64; 3]> for Point3 {
fn from(s: [f64; 3]) -> Self {
Point3 {
x: s[0],
y: s[1],
z: s[2],
}
}
}
impl From<(f64, f64, f64)> for Point3 {
fn from(t: (f64, f64, f64)) -> Self {
Point3 {
x: t.0,
y: t.1,
z: t.2,
}
}
}
impl From<Vec3> for Point3 {
fn from(v: Vec3) -> Self {
Point3 {
x: v.x,
y: v.y,
z: v.z,
}
}
}
impl From<Color> for Point3 {
fn from(c: Color) -> Self {
Point3 {
x: c.r as f64,
y: c.g as f64,
z: c.b as f64,
}
}
}
impl TryFrom<Vec<f64>> for Point3 {
type Error = &'static str;
fn try_from(v: Vec<f64>) -> Result<Self, Self::Error> {
if v.len() != 3 {
Err("Point3 can only be build from a vector of length 3.")
} else {
Ok(Point3 {
x: v[0],
y: v[1],
z: v[2],
})
}
}
}
impl TryFrom<&[f64]> for Point3 {
type Error = &'static str;
fn try_from(s: &[f64]) -> Result<Self, Self::Error> {
if s.len() != 3 {
Err("Point3 can only be build from a slice of length 3.")
} else {
Ok(Point3 {
x: s[0],
y: s[1],
z: s[2],
})
}
}
}
impl Index<usize> for Point3 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!(
"index out of bounds: the len is 3 but the index is {}",
index
),
}
}
}
impl IndexMut<usize> for Point3 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!(
"index out of bounds: the len is 3 but the index is {}",
index
),
}
}
}