use std::ops::{Add, Sub, Mul, Div, Neg};
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign};
use std::ops::{Index, IndexMut};
use std::cmp::PartialEq;
use std::str::FromStr;
use std::fmt;
use std::num;
#[derive(Debug, Clone, Copy)]
pub struct Vec2 {
pub x: f64,
pub y: f64,
}
impl Vec2 {
pub fn new<I: Into<f64>>(x: I, y: I) -> Vec2 {
Vec2 {
x: x.into(),
y: y.into(),
}
}
pub fn from_polar<I: Into<f64>>(r: I, theta: I) -> Vec2 {
let (r, theta) = (r.into(), theta.into());
Vec2::new(r * f64::cos(theta), r * f64::sin(theta))
}
pub fn zero() -> Vec2 {
Vec2::new(0.0, 0.0)
}
pub fn dot(self, rhs: Vec2) -> f64 {
self.x * rhs.x + self.y * rhs.y
}
pub fn cross(self) -> Vec2 {
Vec2::new(self.y, -self.x)
}
pub fn area(self, rhs: Vec2) -> f64 {
self.dot(rhs.cross())
}
pub fn len(self) -> f64 {
self.dot(self).sqrt()
}
pub fn ort(self) -> Vec2 {
self / self.len()
}
pub fn sqr(self) -> Vec2 {
self * self
}
pub fn sqrt(self) -> Vec2 {
Vec2::new(self.x.sqrt(), self.y.sqrt())
}
pub fn dual_basis(basis: (Vec2, Vec2)) -> (Vec2, Vec2) {
let (a, b) = basis;
let area = a.area(b);
(b.cross() / area, -a.cross() / area)
}
fn size(&self) -> usize { 2 }
}
op_default!(add, Add, +=, Vec2);
op_default!(sub, Sub, -=, Vec2);
op_default!(mul, Mul, *=, Vec2);
op_default!(f64, mul, Mul, *=, Vec2);
op_default!(f64, div, Div, /=, Vec2);
op_assign!(add_assign, AddAssign, +=, Vec2);
op_assign!(sub_assign, SubAssign, -=, Vec2);
op_assign!(mul_assign, MulAssign, *=, Vec2);
op_assign!(f64, mul_assign, MulAssign, *=, Vec2);
op_assign!(f64, div_assign, DivAssign, /=, Vec2);
impl Neg for Vec2 {
type Output = Self;
fn neg(self) -> Self {
Self::new(-self.x, -self.y)
}
}
impl Index<usize> for Vec2 {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
i => panic!("Index {} out of [0, 1] range", i)
}
}
}
impl IndexMut<usize> for Vec2 {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
i => panic!("Index {} out of [0, 1] range", i)
}
}
}
impl PartialEq for Vec2 {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl fmt::Display for Vec2 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.x, self.y)
}
}
impl FromStr for Vec2 {
type Err = num::ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let words: Vec<&str> = s.split_whitespace().collect();
let x: f64 = words[0].parse()?;
let y: f64 = words[1].parse()?;
Ok(Self::new(x, y))
}
}
#[cfg(test)]
mod linal_test {
use super::*;
#[test]
fn vec2_mul() {
let a = Vec2::new(1, 2);
let b = Vec2::new(3, 6);
let r = a * 3;
let mut z = a;
let mut x = a;
z *= 3;
x *= b;
assert_eq!(r, b);
assert_eq!(z, b);
assert_eq!(x, Vec2::new(3, 12));
}
#[test]
fn vec2_div() {
let a = Vec2::new(10, 20);
let b = Vec2::new(1, 2);
let mut z = a;
z /= 10;
assert_eq!(a / 10, b);
assert_eq!(z, b);
}
#[test]
fn vec2_div_inf() {
let a = Vec2::new(1, 2);
let b = a / 0.0;
assert!(b.x.is_infinite() && b.y.is_infinite());
}
#[test]
fn vec2_from_polar() {
let a = Vec2::new(3, 4);
let b = Vec2::from_polar(5.0, f64::atan2(4.0, 3.0));
assert!((a - b).len() < 1e-10);
}
#[test]
fn vec2_add() {
let a = Vec2::new(1, 2);
let b = Vec2::new(-3, 6);
let c = Vec2::new(-2, 8);
assert_eq!(a + b, c);
let mut z = a;
z += b;
assert_eq!(z, c);
}
#[test]
fn vec2_sub() {
let a = Vec2::new(1, 2);
let b = Vec2::new(-3, 6);
let c = Vec2::new(4, -4);
let mut z = a;
z -= b;
assert_eq!(a - b, c);
assert_eq!(z, c);
}
#[test]
fn vec2_dot() {
let a = Vec2::new(1, 2);
let b = Vec2::new(-3, 6);
let c = 9.0;
assert_eq!(a.dot(b), c);
assert_eq!(b.dot(a), c);
}
#[test]
fn vec2_area() {
let a = Vec2::new(1, 2);
let b = Vec2::new(-3, 6);
let c = 12.0;
assert_eq!(a.area(b), c);
assert_eq!(b.area(a), -c);
}
#[test]
fn vec2_cross_z() {
let a = Vec2::new(1, 2);
let b = 2.0;
let c = Vec2::new(4, -2);
assert_eq!(a.cross() * b, c);
}
#[test]
fn vec2_neg() {
let a = Vec2::new(1, 2);
let b = Vec2::new(-1, -2);
assert_eq!(-a, b);
}
#[test]
fn vec2_index() {
let a = Vec2::new(1, 2);
assert_eq!(a[0], 1.0);
assert_eq!(a[1], 2.0);
}
#[test]
#[should_panic]
fn vec2_index_out_of_range() {
let a = Vec2::new(1, 2);
let _ = a[10];
}
#[test]
fn vec2_index_mut() {
let mut a = Vec2::zero();
for i in 0..2 {
a[i] = (i as f64 + 1.0).powi(2);
}
assert_eq!(a[0], 1.0);
assert_eq!(a[1], 4.0);
}
#[test]
#[should_panic]
fn vec2_index_mut_out_of_range() {
let mut a = Vec2::zero();
a[10] = 10.0;
}
#[test]
fn vec2_parse() {
let a: Vec2 = "1 2".parse().unwrap();
assert_eq!(a, Vec2::new(1, 2));
}
}