#![cfg_attr(feature = "strict", deny(warnings))]
#![deny(missing_docs)]
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate clapme;
use std::fmt::Alignment;
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, ClapMe, Default)]
pub struct Vector3d<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T> Vector3d<T> {
pub fn new(x: T, y: T, z: T) -> Vector3d<T> {
Vector3d { x: x, y: y, z: z }
}
pub fn dot<U: Mul<T, Output=X>, X: Add<Output=X>>(self, rhs: Vector3d<U>) -> X {
rhs.x*self.x + rhs.y*self.y + rhs.z*self.z
}
}
use std::ops::Add;
impl<T: Add<T, Output = T>> Add<Vector3d<T>> for Vector3d<T> {
type Output = Vector3d<T>;
fn add(self, rhs: Vector3d<T>) -> Self::Output {
Vector3d::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
}
}
use std::ops::Sub;
impl<T: Sub<T, Output = T>> Sub<Vector3d<T>> for Vector3d<T> {
type Output = Vector3d<T>;
fn sub(self, rhs: Vector3d<T>) -> Self::Output {
Vector3d::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
}
}
use std::ops::Neg;
impl<T: Neg<Output = T>> Neg for Vector3d<T> {
type Output = Vector3d<T>;
fn neg(self) -> Self::Output {
Vector3d::new(-self.x, -self.y, -self.z)
}
}
use std::ops::Mul;
impl<S: Clone, X, T: Mul<S, Output=X>> Mul<S> for Vector3d<T> {
type Output = Vector3d<X>;
fn mul(self, rhs: S) -> Self::Output {
Vector3d::new(self.x * rhs.clone(), self.y * rhs.clone(), self.z * rhs)
}
}
use std::ops::Div;
impl<S: Clone, X, T: Div<S, Output=X>> Div<S> for Vector3d<T> {
type Output = Vector3d<X>;
fn div(self, rhs: S) -> Self::Output {
Vector3d::new(self.x / rhs.clone(), self.y / rhs.clone(), self.z / rhs)
}
}
impl<T: Clone> Vector3d<T> {
pub fn cross<U: Clone + Mul<T, Output=X>,
X: Add<Output=X> + Sub<Output=X>>(self, rhs: Vector3d<U>) -> Vector3d<X> {
Vector3d::new(rhs.z.clone()*self.y.clone() - rhs.y.clone()*self.z.clone(),
rhs.x.clone()*self.z.clone() - rhs.z*self.x.clone(),
rhs.y*self.x - rhs.x.clone()*self.y.clone())
}
}
impl<T: Clone + Mul<T, Output=X>, X: Add<Output=X>> Vector3d<T> {
pub fn norm2(self) -> X {
self.x.clone()*self.x + self.y.clone()*self.y + self.z.clone()*self.z
}
}
use std::ops::Index;
impl<T> Index<usize> for Vector3d<T> {
type Output = T;
fn index<'a>(&'a self, index: usize) -> &'a T {
match index {
0 => &self.x,
1 => &self.y,
2 => &self.z,
_ => panic!("Invalid index"),
}
}
}
use std::ops::IndexMut;
impl<T> IndexMut<usize> for Vector3d<T> {
fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut T {
match index {
0 => &mut self.x,
1 => &mut self.y,
2 => &mut self.z,
_ => panic!("Invalid index"),
}
}
}
use std::fmt;
impl<T: fmt::Display> fmt::Display for Vector3d<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(decimals) = f.precision() {
let s = format!("({:.decimals$}, {:.decimals$}, {:.decimals$})",
self.x, self.y, self.z, decimals=decimals);
if let Some(width) = f.width() {
match f.align().unwrap_or(Alignment::Left) {
Alignment::Left =>
write!(f, "{:<width$}", s, width=width),
Alignment::Right =>
write!(f, "{:>width$}", s, width=width),
Alignment::Center =>
write!(f, "{:^width$}", s, width=width),
}
} else {
f.write_str(&s)
}
} else {
let string = format!("({}, {}, {})", self.x, self.y, self.z);
f.pad(&string)
}
}
}
#[test]
fn padding_works() {
let v = Vector3d::new(0,0,0);
assert_eq!(&format!("{}", v), "(0, 0, 0)");
assert_eq!(&format!("{:10}", v), "(0, 0, 0) ");
assert_eq!(&format!("{:<10}", v), "(0, 0, 0) ");
assert_eq!(&format!("{:>10}", v), " (0, 0, 0)");
assert_eq!(&format!("{:^11}", v), " (0, 0, 0) ");
assert_eq!(&format!("{:>11}", v), " (0, 0, 0)");
let v = Vector3d::new(0.,0.,0.);
assert_eq!(&format!("{}", v), "(0, 0, 0)");
assert_eq!(&format!("{:.2}", v), "(0.00, 0.00, 0.00)");
assert_eq!(&format!("{:19.2}", v), "(0.00, 0.00, 0.00) ");
assert_eq!(&format!("{:<19.2}", v), "(0.00, 0.00, 0.00) ");
assert_eq!(&format!("{:>19.2}", v), " (0.00, 0.00, 0.00)");
assert_eq!(&format!("{:^20.2}", v), " (0.00, 0.00, 0.00) ");
}