use std::f32;
use std::ops;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2w {
pub v: Vec2,
pub w: f32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
e: [f32; 9],
}
impl ops::Add for Vec2 {
type Output = Self;
fn add(self, other: Self) -> Self {
Vec2::new(self.x + other.x, self.y + other.y)
}
}
impl ops::Sub for Vec2 {
type Output = Self;
fn sub(self, other: Self) -> Self{
Vec2::new(self.x - other.x, self.y - other.y)
}
}
impl ops::Mul<f32> for Vec2 {
type Output = Self;
fn mul(self, s: f32) -> Self {
Vec2::new(self.x * s, self.y * s)
}
}
impl ops::Mul for Vec2 {
type Output = f32;
fn mul(self, other: Self) -> f32 {
self.x * other.y - self.y * other.x
}
}
impl ops::Div<f32> for Vec2 {
type Output = Self;
fn div(self, s: f32) -> Self {
Vec2::new(self.x / s, self.y / s)
}
}
impl ops::Neg for Vec2 {
type Output = Self;
fn neg(self) -> Self {
Vec2::new(-self.x, -self.y)
}
}
impl Vec2 {
pub fn new(x: f32, y: f32) -> Self {
Vec2 { x: x, y: y }
}
pub fn zero() -> Self {
Vec2::new(0.0, 0.0)
}
pub fn mag(self) -> f32 {
self.x.hypot(self.y)
}
pub fn normalize(self) -> Self {
let m = self.mag();
if m > 0.0 {
self / m
} else {
Vec2::zero()
}
}
pub fn dist_sq(self, other: Self) -> f32 {
let dx = self.x - other.x;
let dy = self.y - other.y;
dx * dx + dy * dy
}
#[allow(dead_code)]
pub fn dist(self, other: Self) -> f32 {
self.dist_sq(other).sqrt()
}
pub fn midpoint(self, other: Self) -> Self {
let x = (self.x + other.x) / 2.0;
let y = (self.y + other.y) / 2.0;
Vec2::new(x, y)
}
pub fn left(self) -> Self {
Vec2::new(-self.y, self.x)
}
#[allow(dead_code)]
pub fn right(self) -> Self {
Vec2::new(self.y, -self.x)
}
pub fn widdershins(self, other: Self) -> bool {
(self.x * other.y) > (other.x * self.y)
}
#[allow(dead_code)]
pub fn lerp(self, other: Self, t: f32) -> Self {
let x = float_lerp(self.x, other.x, t);
let y = float_lerp(self.y, other.y, t);
Vec2::new(x, y)
}
pub fn angle_rel(self, other: Self) -> f32 {
const PI: f32 = f32::consts::PI;
let th = self.y.atan2(self.x) - other.y.atan2(other.x);
if th < -PI {
th + 2.0 * PI
} else if th > PI {
th - 2.0 * PI
} else {
th
}
}
}
pub fn float_lerp(a: f32, b: f32, t: f32) -> f32 {
b + (a - b) * t
}
pub fn intersection(a0: Vec2,
a1: Vec2,
b0: Vec2,
b1: Vec2) -> Option<Vec2>
{
let av = a0 - a1;
let bv = b0 - b1;
let den = av * bv;
if den != 0.0 {
let ca = a0 * a1;
let cb = b0 * b1;
let xn = bv.x * ca - av.x * cb;
let yn = bv.y * ca - av.y * cb;
Some(Vec2::new(xn / den, yn / den))
} else {
None
}
}
impl Vec2w {
pub fn new(x: f32, y: f32, w: f32) -> Self {
Vec2w {
v: Vec2::new(x, y),
w: w,
}
}
pub fn midpoint(self, other: Self) -> Self {
Vec2w {
v: self.v.midpoint(other.v),
w: (self.w + other.w) / 2.0,
}
}
}
impl ops::MulAssign for Transform {
fn mul_assign(&mut self, other: Self) {
for c in 0..3 {
let mut m = [0.0; 3];
for r in 0..3 {
m[r] = self.get(0, c) * other.get(r, 0) +
self.get(1, c) * other.get(r, 1) +
self.get(2, c) * other.get(r, 2);
}
for r in 0..3 {
self.set(r, c, m[r]);
}
}
}
}
impl ops::Mul for Transform {
type Output = Self;
fn mul(self, other: Self) -> Self {
let mut m = Transform::new();
for c in 0..3 {
for r in 0..3 {
let e = self.get(0, c) * other.get(r, 0) +
self.get(1, c) * other.get(r, 1) +
self.get(2, c) * other.get(r, 2);
m.set(r, c, e);
}
}
m
}
}
impl ops::Mul<Vec2> for Transform {
type Output = Vec2;
fn mul(self, s: Vec2) -> Vec2 {
let x = self.get(0, 0) * s.x + self.get(0, 1) * s.y + self.get(0, 2);
let y = self.get(1, 0) * s.x + self.get(1, 1) * s.y + self.get(1, 2);
Vec2::new(x, y)
}
}
impl Transform {
pub fn new() -> Self {
Transform {
e: [1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0]
}
}
pub fn new_translate(tx: f32, ty: f32) -> Self {
Transform {
e: [1.0, 0.0, tx,
0.0, 1.0, ty,
0.0, 0.0, 1.0]
}
}
pub fn new_scale(sx: f32, sy: f32) -> Self {
Transform {
e: [ sx, 0.0, 0.0,
0.0, sy, 0.0,
0.0, 0.0, 1.0]
}
}
pub fn new_rotate(th: f32) -> Self {
let sn = th.sin();
let cs = th.cos();
Transform {
e: [ cs, -sn, 0.0,
sn, cs, 0.0,
0.0, 0.0, 1.0]
}
}
pub fn new_skew(ax: f32, ay: f32) -> Self {
let tnx = ax.tan();
let tny = ay.tan();
Transform {
e: [1.0, tnx, 0.0,
tny, 1.0, 0.0,
0.0, 0.0, 1.0]
}
}
fn get(&self, row: usize, col: usize) -> f32 {
self.e[row * 3 + col]
}
fn set(&mut self, row: usize, col: usize, e: f32) {
self.e[row * 3 + col] = e;
}
pub fn translate(mut self, tx: f32, ty: f32) -> Self {
self *= Transform::new_translate(tx, ty);
self
}
pub fn scale(mut self, sx: f32, sy: f32) -> Self {
self *= Transform::new_scale(sx, sy);
self
}
pub fn rotate(mut self, th: f32) -> Self {
self *= Transform::new_rotate(th);
self
}
pub fn skew(mut self, ax: f32, ay: f32) -> Self {
self *= Transform::new_skew(ax, ay);
self
}
}
#[cfg(test)]
mod test {
use super::Vec2;
#[test]
fn test_vec2() {
let a = Vec2::new(2.0, 1.0);
let b = Vec2::new(3.0, 4.0);
let c = Vec2::new(-1.0, 1.0);
assert!(a + b == Vec2::new(5.0, 5.0));
assert!(b - a == Vec2::new(1.0, 3.0));
assert!(a * 2.0 == Vec2::new(4.0, 2.0));
assert!(a / 2.0 == Vec2::new(1.0, 0.5));
assert!(-a == Vec2::new(-2.0, -1.0));
assert!(b.mag() == 5.0);
assert!(a.normalize() == Vec2::new(0.8944272, 0.4472136));
assert!(a.dist_sq(b) == 10.0);
assert!(b.dist(Vec2::new(0.0, 0.0)) == 5.0);
assert!(a.midpoint(b) == Vec2::new(2.5, 2.5));
assert!(a.left() == Vec2::new(-1.0, 2.0));
assert!(a.right() == Vec2::new(1.0, -2.0));
assert!(a.widdershins(b));
assert!(!b.widdershins(a));
assert!(b.widdershins(c));
assert!(a.angle_rel(b) == -0.4636476);
assert!(c.angle_rel(Vec2::new(1.0, 1.0)) == 1.5707963);
assert!(Vec2::new(-1.0, -1.0).angle_rel(c) == 1.5707965);
}
}