use std::convert::{TryInto, From};
use std::ops;
use ultraviolet::{Vec3,Vec3i};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct Point3 {
pub x: i32,
pub y: i32,
pub z: i32,
}
#[cfg(feature = "specs")]
impl specs::prelude::Component for Point3 {
type Storage = specs::prelude::VecStorage<Self>;
}
impl Point3 {
pub fn new<T>(x: T, y: T, z: T) -> Self
where
T: TryInto<i32>,
{
Self {
x: x.try_into().ok().unwrap(),
y: y.try_into().ok().unwrap(),
z: z.try_into().ok().unwrap(),
}
}
pub fn from_tuple(t: (i32, i32, i32)) -> Self {
Self {
x: t.0,
y: t.1,
z: t.2
}
}
pub fn to_vec3(&self) -> Vec3 {
Vec3::new(self.x as f32, self.y as f32, self.z as f32)
}
pub fn to_vec3i(&self) -> Vec3i {
Vec3i::new(self.x, self.y, self.z)
}
}
impl From<Vec3> for Point3 {
fn from(item: Vec3) -> Self {
Self {
x: item.x as i32,
y: item.y as i32,
z: item.z as i32
}
}
}
impl From<Vec3i> for Point3 {
fn from(item: Vec3i) -> Self {
Self {
x: item.x,
y: item.y,
z: item.z
}
}
}
impl ops::Add<Point3> for Point3 {
type Output = Point3;
fn add(mut self, rhs: Point3) -> Point3 {
self.x += rhs.x;
self.y += rhs.y;
self.z += rhs.z;
self
}
}
impl ops::Add<i32> for Point3 {
type Output = Point3;
fn add(mut self, rhs: i32) -> Point3 {
self.x += rhs;
self.y += rhs;
self.z += rhs;
self
}
}
impl ops::Sub<Point3> for Point3 {
type Output = Point3;
fn sub(mut self, rhs: Point3) -> Point3 {
self.x -= rhs.x;
self.y -= rhs.y;
self.z -= rhs.z;
self
}
}
impl ops::Sub<i32> for Point3 {
type Output = Point3;
fn sub(mut self, rhs: i32) -> Point3 {
self.x -= rhs;
self.y -= rhs;
self.z -= rhs;
self
}
}
impl ops::Mul<Point3> for Point3 {
type Output = Point3;
fn mul(mut self, rhs: Point3) -> Point3 {
self.x *= rhs.x;
self.y *= rhs.y;
self.z *= rhs.z;
self
}
}
impl ops::Mul<i32> for Point3 {
type Output = Point3;
fn mul(mut self, rhs: i32) -> Point3 {
self.x *= rhs;
self.y *= rhs;
self.z *= rhs;
self
}
}
impl ops::Mul<f32> for Point3 {
type Output = Point3;
fn mul(mut self, rhs: f32) -> Point3 {
self.x = (self.x as f32 * rhs) as i32;
self.y = (self.y as f32 * rhs) as i32;
self.z = (self.z as f32 * rhs) as i32;
self
}
}
impl ops::Div<Point3> for Point3 {
type Output = Point3;
fn div(mut self, rhs: Point3) -> Point3 {
self.x /= rhs.x;
self.y /= rhs.y;
self.z /= rhs.z;
self
}
}
impl ops::Div<i32> for Point3 {
type Output = Point3;
fn div(mut self, rhs: i32) -> Point3 {
self.x /= rhs;
self.y /= rhs;
self.z /= rhs;
self
}
}
impl ops::Div<f32> for Point3 {
type Output = Point3;
fn div(mut self, rhs: f32) -> Point3 {
self.x = (self.x as f32 / rhs) as i32;
self.y = (self.y as f32 / rhs) as i32;
self.z = (self.z as f32 / rhs) as i32;
self
}
}
#[cfg(test)]
mod tests {
use super::Point3;
#[test]
fn new_point3() {
let pt = Point3::new(1, 2, 3);
assert_eq!(pt.x, 1);
assert_eq!(pt.y, 2);
assert_eq!(pt.z, 3);
}
#[test]
fn add_point_to_point3() {
let pt = Point3::new(0, 0, 0);
let p2 = pt + Point3::new(1, 2, 3);
assert_eq!(p2.x, 1);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 3);
}
#[test]
fn add_point3_to_int() {
let pt = Point3::new(0, 0, 0);
let p2 = pt + 2;
assert_eq!(p2.x, 2);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 2);
}
#[test]
fn sub_point3_to_point() {
let pt = Point3::new(0, 0, 0);
let p2 = pt - Point3::new(1, 2, 3);
assert_eq!(p2.x, -1);
assert_eq!(p2.y, -2);
assert_eq!(p2.z, -3);
}
#[test]
fn sub_point3_to_int() {
let pt = Point3::new(0, 0, 0);
let p2 = pt - 2;
assert_eq!(p2.x, -2);
assert_eq!(p2.y, -2);
assert_eq!(p2.z, -2);
}
#[test]
fn mul_point3_to_point() {
let pt = Point3::new(1, 1, 1);
let p2 = pt * Point3::new(1, 2, 4);
assert_eq!(p2.x, 1);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 4);
}
#[test]
fn mul_point3_to_int() {
let pt = Point3::new(1, 1, 1);
let p2 = pt * 2;
assert_eq!(p2.x, 2);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 2);
}
#[test]
fn mul_point3_to_float() {
let pt = Point3::new(1, 1, 1);
let p2 = pt * 4.0;
assert_eq!(p2.x, 4);
assert_eq!(p2.y, 4);
assert_eq!(p2.z, 4);
}
#[test]
fn div_point3_to_point() {
let pt = Point3::new(4, 4, 4);
let p2 = pt / Point3::new(2, 4, 1);
assert_eq!(p2.x, 2);
assert_eq!(p2.y, 1);
assert_eq!(p2.z, 4);
}
#[test]
fn div_point3_to_int() {
let pt = Point3::new(4, 4, 4);
let p2 = pt / 2;
assert_eq!(p2.x, 2);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 2);
}
#[test]
fn div_point3_to_float() {
let pt = Point3::new(4, 4, 4);
let p2 = pt / 2.0;
assert_eq!(p2.x, 2);
assert_eq!(p2.y, 2);
assert_eq!(p2.z, 2);
}
}