use std::fmt;
use std::ops::{Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign, Div, DivAssign};
use std::mem;
use consts::*;
use num;
#[repr(C)]
#[derive(Clone, Copy, Default, PartialEq, Debug)]
pub struct Vector {
pub x: f32,
pub y: f32,
}
#[repr(C)]
#[derive(Clone, Copy, Default, PartialEq, Debug)]
pub struct Point {
pub x: f32,
pub y: f32,
}
impl Vector {
#[inline]
pub fn new(x: f32, y: f32) -> Vector {
Vector { x: x, y: y }
}
#[inline]
pub fn unit_from_radians(angle: f32) -> Vector {
let (sin, cos) = angle.sin_cos();
Vector { x: cos, y: sin }
}
#[inline]
pub fn unit_from_degrees(angle: f32) -> Vector {
let (sin, cos) = angle.to_radians().sin_cos();
Vector { x: cos, y: sin }
}
#[inline]
pub fn new_polar_rad(radius: f32, angle: f32) -> Vector {
let (sin, cos) = angle.sin_cos();
Vector {
x: cos * radius,
y: sin * radius,
}
}
#[inline]
pub fn new_polar_deg(radius: f32, angle: f32) -> Vector {
Vector::new_polar_rad(radius, angle.to_radians())
}
#[inline]
pub fn magnitude(self) -> f32 {
self.x.hypot(self.y)
}
#[inline]
pub fn dot(self, other: Vector) -> f32 {
self.x.mul_add(other.x, self.y * other.y)
}
#[inline]
pub fn scale(self, other: Vector) -> Vector {
Vector {
x: self.x * other.x,
y: self.y * other.y,
}
}
#[inline]
pub fn scale_mut(&mut self, other: Vector) {
self.x *= other.x;
self.y *= other.y;
}
#[inline]
pub fn rotate(self, rotation: Rotation) -> Vector {
Vector {
x: self.x * rotation.cos - self.y * rotation.sin,
y: self.x * rotation.sin + self.y * rotation.cos,
}
}
#[inline]
pub fn rotate_mut(&mut self, rotation: Rotation) {
*self = self.rotate(rotation);
}
#[inline]
pub fn rotate_rad(self, angle: f32) -> Vector {
self.rotate(Rotation::new_rad(angle))
}
#[inline]
pub fn rotate_rad_mut(&mut self, angle: f32) {
*self = self.rotate_rad(angle);
}
#[inline]
pub fn rotate_deg(self, angle: f32) -> Vector {
self.rotate(Rotation::new_deg(angle))
}
#[inline]
pub fn rotate_deg_mut(&mut self, angle: f32) {
*self = self.rotate_deg(angle);
}
#[inline]
pub fn normalize(self) -> Vector {
if self == VEC_ZERO {
VEC_RIGHT
} else {
self * self.magnitude().recip()
}
}
#[inline]
pub fn normalize_mut(&mut self) {
if *self == VEC_ZERO {
*self = VEC_RIGHT
} else {
*self *= self.magnitude().recip()
}
}
#[inline]
pub fn dist(self, other: Vector) -> f32 {
(self - other).magnitude()
}
#[inline]
pub fn grid_dist(self, other: Vector) -> f32 {
(self.x - other.x).abs() + (self.y - other.y).abs()
}
#[inline]
pub fn angle_rad(self) -> f32 {
self.y.atan2(self.x)
}
#[inline]
pub fn angle_deg(self) -> f32 {
self.angle_rad().to_degrees()
}
#[inline]
pub fn angle_between_rad(self, other: Vector) -> f32 {
let x = self.x * other.x + self.y * other.y;
let y = self.x * other.y - self.y * other.x;
y.atan2(x)
}
#[inline]
pub fn angle_between_deg(self, other: Vector) -> f32 {
self.angle_between_rad(other).to_degrees()
}
#[inline]
pub fn map<F: Fn(f32) -> f32>(self, func: &F) -> Vector {
Vector {
x: func(self.x),
y: func(self.y),
}
}
#[inline]
pub fn map_mut<F: Fn(f32) -> f32>(&mut self, func: &F) {
self.x = func(self.x);
self.y = func(self.y);
}
#[inline]
pub fn lerp(self, other: Vector, t: f32) -> Vector {
self + (other - self) * t
}
#[inline]
pub fn is_in_rect(self, vert1: Vector, vert2: Vector) -> bool {
let min_x = vert1.x.min(vert2.x);
let max_x = vert1.x.max(vert2.x);
let min_y = vert1.y.min(vert2.y);
let max_y = vert1.y.max(vert2.y);
self.x >= min_x && self.x <= max_x &&
self.y >= min_y && self.y <= max_y
}
#[inline]
pub fn clamp_to_rect(self, vert1: Vector, vert2: Vector) -> Vector {
Vector {
x: num::clamp(self.x, vert1.x, vert2.x),
y: num::clamp(self.y, vert1.y, vert2.y),
}
}
#[inline]
pub fn as_point(self) -> Point {
Point::new(self.x, self.y)
}
#[inline]
pub fn from_vec2(vec2: [f32; 2]) -> Vector {
Vector::new(vec2[0], vec2[1])
}
#[inline]
pub fn to_vec2(self) -> [f32; 2] {
[self.x, self.y]
}
#[inline]
pub fn to_vec3(self) -> [f32; 3] {
[self.x, self.y, 0.0]
}
#[inline]
pub fn to_vec4(self) -> [f32; 4] {
[self.x, self.y, 0.0, 0.0]
}
#[inline]
pub fn arr_from_vec2s(arr: &[[f32; 2]]) -> &[Vector] {
unsafe { mem::transmute(arr) }
}
#[inline]
pub fn arr_to_vec2s(arr: &[Vector]) -> &[[f32; 2]] {
unsafe { mem::transmute(arr) }
}
}
impl Point {
#[inline]
pub fn new(x: f32, y: f32) -> Point {
Point { x: x, y: y }
}
#[inline]
pub fn new_polar_rad(radius: f32, angle: f32) -> Point {
let (sin, cos) = angle.sin_cos();
Point::new(radius * cos, radius * sin)
}
#[inline]
pub fn new_polar_deg(radius: f32, angle: f32) -> Point {
Point::new_polar_rad(radius, angle.to_radians())
}
#[inline]
pub fn dist(self, other: Point) -> f32 {
(self - other).magnitude()
}
#[inline]
pub fn rotate(self, pivot: Point, rotation: Rotation) -> Point {
(self - pivot).rotate(rotation) + pivot
}
#[inline]
pub fn rotate_rad(self, pivot: Point, angle: f32) -> Point {
self.rotate(pivot, Rotation::new_rad(angle))
}
#[inline]
pub fn rotate_deg(self, pivot: Point, angle: f32) -> Point {
self.rotate_rad(pivot, angle.to_radians())
}
#[inline]
pub fn as_vec(self) -> Vector {
Vector::new(self.x, self.y)
}
#[inline]
pub fn from_gl_vec2(vec2: [f32; 2]) -> Point {
Point::new(vec2[0], vec2[1])
}
#[inline]
pub fn to_gl_vec2(self) -> [f32; 2] {
[self.x, self.y]
}
#[inline]
pub fn from_vec2(vec2: [f32; 2]) -> Point {
Point::new(vec2[0], vec2[1])
}
#[inline]
pub fn to_vec2(self) -> [f32; 2] {
[self.x, self.y]
}
#[inline]
pub fn to_vec3(self) -> [f32; 3] {
[self.x, self.y, 0.0]
}
#[inline]
pub fn to_vec4(self) -> [f32; 4] {
[self.x, self.y, 0.0, 1.0]
}
#[inline]
pub fn arr_from_vec2s(arr: &[[f32; 2]]) -> &[Point] {
unsafe { mem::transmute(arr) }
}
#[inline]
pub fn arr_to_vec2s(arr: &[Point]) -> &[[f32; 2]] {
unsafe { mem::transmute(arr) }
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Rotation {
pub cos: f32,
pub sin: f32,
}
impl Rotation {
#[inline]
pub fn new_in_direction(dir: Vector) -> Rotation {
let normalized = dir.normalize();
Rotation {
cos: normalized.x,
sin: normalized.y,
}
}
#[inline]
pub fn new_rad(angle: f32) -> Rotation {
let (sin, cos) = angle.sin_cos();
Rotation {
cos: cos,
sin: sin,
}
}
#[inline]
pub fn new_deg(angle: f32) -> Rotation {
Rotation::new_rad(angle.to_radians())
}
#[inline]
pub fn between(from: Vector, to: Vector) -> Rotation {
Rotation::new_in_direction(Vector {
x: from.x * to.x + from.y * to.y,
y: from.x * to.y - from.y * to.x,
})
}
#[inline]
pub fn negate(self) -> Rotation {
Rotation {
cos: self.cos,
sin: -self.sin,
}
}
#[inline]
pub fn add(self, other: Rotation) -> Rotation {
Rotation {
cos: self.cos * other.cos - self.sin * other.sin,
sin: self.sin * other.cos + self.cos * other.sin,
}
}
#[inline]
pub fn sub(self, other: Rotation) -> Rotation {
Rotation {
cos: self.cos * other.cos + self.sin * other.sin,
sin: self.sin * other.cos - self.cos * other.sin,
}
}
#[inline]
pub fn angle_rad(self) -> f32 {
self.sin.atan2(self.cos)
}
#[inline]
pub fn angle_deg(self) -> f32 {
self.angle_rad().to_degrees()
}
}
impl fmt::Debug for Rotation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"Rotation(angle: {} degrees, cos: {}, sin: {})",
self.angle_deg(),
self.cos,
self.sin)
}
}
#[derive(Clone, Copy, PartialEq)]
pub struct Transform {
pub mat: [[f32; 2]; 2],
pub vec: Vector,
}
impl Transform {
#[inline]
pub fn new(translation: Vector, rotation: Rotation, scale: Vector) -> Transform {
Transform {
vec: translation,
mat: [
[scale.x * rotation.cos,
scale.x * rotation.sin],
[scale.y * -rotation.sin,
scale.y * rotation.cos],
],
}
}
#[inline]
pub fn new_rad(translation: Vector, angle: f32, scale: Vector) -> Transform {
Transform::new(translation, Rotation::new_rad(angle), scale)
}
#[inline]
pub fn new_deg(translation: Vector, angle: f32, scale: Vector) -> Transform {
Transform::new(translation, Rotation::new_deg(angle), scale)
}
#[inline]
pub fn new_matrix(mat1_1: f32, mat2_1: f32, mat1_2: f32, mat2_2: f32) -> Transform {
Transform {
vec: VEC_ZERO,
mat: [[mat1_1, mat2_1],
[mat1_2, mat2_2]],
}
}
#[inline]
pub fn new_scaling(scale: Vector) -> Transform {
Transform::new_matrix(scale.x, 0.0, 0.0, scale.y)
}
#[inline]
pub fn new_rotation(rotation: Rotation) -> Transform {
Transform::new_matrix(rotation.cos, -rotation.sin, rotation.sin, rotation.cos)
}
#[inline]
pub fn new_rotation_rad(angle: f32) -> Transform {
Transform::new_rotation(Rotation::new_rad(angle))
}
#[inline]
pub fn new_rotation_deg(angle: f32) -> Transform {
Transform::new_rotation(Rotation::new_deg(angle))
}
#[inline]
pub fn new_translation(offset: Vector) -> Transform {
Transform {
vec: offset,
mat: TRANSFORM_IDENTITY.mat,
}
}
#[inline]
pub fn translate(self, offset: Vector) -> Transform {
Transform { vec: self.vec + offset, ..self }
}
#[inline]
pub fn translate_mut(&mut self, offset: Vector) {
self.vec += offset;
}
#[inline]
pub fn translate_local(self, offset: Vector) -> Transform {
Transform { vec: self.vec + self.transform(offset), ..self }
}
#[inline]
pub fn translate_local_mut(&mut self, offset: Vector) {
self.vec += self.transform(offset);
}
#[inline]
pub fn rotate(self, rotation: Rotation) -> Transform {
Transform {
mat: [
[self.mat[0][0] * rotation.cos + self.mat[1][0] * rotation.sin,
self.mat[0][1] * rotation.cos + self.mat[1][1] * rotation.sin],
[self.mat[1][0] * rotation.cos - self.mat[0][0] * rotation.sin,
self.mat[1][1] * rotation.cos - self.mat[0][1] * rotation.sin],
],
..self
}
}
#[inline]
pub fn rotate_rad(self, angle: f32) -> Transform {
self.rotate(Rotation::new_rad(angle))
}
#[inline]
pub fn rotate_deg(self, angle: f32) -> Transform {
self.rotate(Rotation::new_deg(angle))
}
#[inline]
pub fn rotate_mut(&mut self, rotation: Rotation) {
*self = self.rotate(rotation);
}
#[inline]
pub fn rotate_rad_mut(&mut self, angle: f32) {
self.rotate_mut(Rotation::new_rad(angle));
}
#[inline]
pub fn rotate_deg_mut(&mut self, angle: f32) {
self.rotate_mut(Rotation::new_deg(angle));
}
#[inline]
pub fn scale(self, factor: Vector) -> Transform {
Transform {
mat: [
[self.mat[0][0] * factor.x, self.mat[0][1] * factor.x],
[self.mat[1][0] * factor.y, self.mat[1][1] * factor.y],
],
..self
}
}
#[inline]
pub fn scale_by_num(self, factor: f32) -> Transform {
Transform {
mat: [
[self.mat[0][0] * factor, self.mat[0][1] * factor],
[self.mat[1][0] * factor, self.mat[1][1] * factor],
],
..self
}
}
#[inline]
pub fn scale_mut(&mut self, factor: Vector) {
self.mat[0][0] *= factor.x;
self.mat[0][1] *= factor.x;
self.mat[1][0] *= factor.y;
self.mat[1][1] *= factor.y;
}
#[inline]
pub fn scale_by_num_mut(&mut self, factor: f32) {
self.mat[0][0] *= factor;
self.mat[0][1] *= factor;
self.mat[1][0] *= factor;
self.mat[1][1] *= factor;
}
#[inline]
pub fn transform_arr<T>(self, arr: &[T]) -> Vec<T> where
Self: Transformation<T>, T: Copy
{
arr.iter().map(|el| self.transform(*el)).collect()
}
#[inline]
pub fn transform_arr_mut<T>(self, arr: &mut [T]) where
Self: Transformation<T>, T: Copy
{
for el in arr {
self.transform_mut(el);
}
}
#[inline]
pub fn from_mat3x2(mat3x2: [[f32; 2]; 3]) -> Transform {
Transform {
mat: [mat3x2[0], mat3x2[1]],
vec: Vector::new(mat3x2[2][0], mat3x2[2][1]),
}
}
#[inline]
pub fn to_mat3x2(self) -> [[f32; 2]; 3] {
[
self.mat[0],
self.mat[1],
[self.vec.x, self.vec.y],
]
}
#[inline]
pub fn to_mat4x4(self) -> [[f32; 4]; 4] {
[
[self.mat[0][0], self.mat[0][1], 0.0, 0.0],
[self.mat[1][0], self.mat[1][1], 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[self.vec.x, self.vec.y, 0.0, 1.0],
]
}
#[inline]
pub fn arr_from_mat3x2s(arr: &[[[f32; 4]; 4]]) -> &[Transform] {
unsafe { mem::transmute(arr) }
}
#[inline]
pub fn arr_to_mat3x2s(arr: &[Transform]) -> &[[[f32; 4]; 4]] {
unsafe { mem::transmute(arr) }
}
}
impl fmt::Debug for Transform {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"Transform:\n[{}, {}]\n[{}, {}],\n{:?}",
self.mat[0][0], self.mat[1][0],
self.mat[0][1], self.mat[1][1],
self.vec)
}
}
pub trait MaybeInvertible: Sized + Copy {
fn is_invertible(self) -> bool;
fn invert(self) -> Self;
#[inline]
fn invert_mut(&mut self) {
*self = self.invert();
}
#[inline]
fn invert_checked(self) -> Option<Self> {
if self.is_invertible() {
Some(self.invert())
} else {
None
}
}
}
impl MaybeInvertible for Transform {
#[inline]
fn is_invertible(self) -> bool {
self.mat[0][0] * self.mat[1][1] != self.mat[0][1] * self.mat[1][0]
}
#[inline]
fn invert(self) -> Self {
let inv_det = (
self.mat[0][0] * self.mat[1][1] - self.mat[0][1] * self.mat[1][0]
).recip();
Transform {
mat: [
[self.mat[1][1] * inv_det, -self.mat[0][1] * inv_det],
[-self.mat[1][0] * inv_det, self.mat[0][0] * inv_det],
],
vec: inv_det * Vector {
x: self.mat[0][1] * self.vec.y - self.mat[1][1] * self.vec.x,
y: self.mat[1][0] * self.vec.x - self.mat[0][0] * self.vec.y,
},
}
}
}
pub trait Transformation<T>: MaybeInvertible {
fn transform(self, operand: T) -> T;
#[inline]
fn transform_mut(self, operand: &mut T) where T: Copy {
*operand = self.transform(*operand);
}
#[inline]
fn inverse_transform(self, operand: T) -> T {
self.invert().transform(operand)
}
#[inline]
fn inverse_transform_checked(self, operand: T) -> Option<T> {
if self.is_invertible() {
Some(self.inverse_transform(operand))
}
else { None }
}
}
impl Transformation<Vector> for Transform {
#[inline]
fn transform(self, vec: Vector) -> Vector {
Vector {
x: self.mat[0][0] * vec.x + self.mat[1][0] * vec.y,
y: self.mat[0][1] * vec.x + self.mat[1][1] * vec.y,
}
}
#[inline]
fn inverse_transform(self, vec: Vector) -> Vector {
let inv_det = (
self.mat[0][0] * self.mat[1][1] - self.mat[0][1] * self.mat[1][0]
).recip();
Vector {
x: inv_det * (self.mat[1][1] * vec.x - self.mat[1][0] * vec.y),
y: inv_det * (self.mat[0][0] * vec.y - self.mat[0][1] * vec.x),
}
}
}
impl Transformation<Point> for Transform {
#[inline]
fn transform(self, pt: Point) -> Point {
(self.transform(pt.as_vec()) + self.vec).as_point()
}
#[inline]
fn inverse_transform(self, pt: Point) -> Point {
self.inverse_transform(pt.as_vec() - self.vec).as_point()
}
}
impl Transformation<Transform> for Transform {
#[inline]
fn transform(self, rhs: Transform) -> Transform {
Transform {
mat: [[self.mat[0][0] * rhs.mat[0][0] + self.mat[1][0] * rhs.mat[0][1],
self.mat[0][1] * rhs.mat[0][0] + self.mat[1][1] * rhs.mat[0][1]],
[self.mat[0][0] * rhs.mat[1][0] + self.mat[1][0] * rhs.mat[1][1],
self.mat[0][1] * rhs.mat[1][0] + self.mat[1][1] * rhs.mat[1][1]]],
vec: self.vec + self.transform(rhs.vec),
}
}
}
macro_rules! impl_elementwise {
($lhs:ty, $rhs:ty, $res:ident, $trai:ident, $fun:ident) => (
impl $trai<$rhs> for $lhs {
type Output = $res;
#[inline]
fn $fun(self, other: $rhs) -> $res {
$res {
x: self.x.$fun(other.x),
y: self.y.$fun(other.y),
}
}
}
)
}
impl_elementwise!(Vector, Vector, Vector, Add, add);
impl_elementwise!(Point, Vector, Point, Add, add);
impl_elementwise!(Vector, Point, Point, Add, add);
impl_elementwise!(Vector, Vector, Vector, Sub, sub);
impl_elementwise!(Point, Vector, Point, Sub, sub);
impl_elementwise!(Point, Point, Vector, Sub, sub);
macro_rules! impl_elwise_assign {
($lhs:ty, $rhs:ty, $trai:ident, $fun:ident) => (
impl $trai<$rhs> for $lhs {
#[inline]
fn $fun(&mut self, other: $rhs) {
self.x.$fun(other.x);
self.y.$fun(other.y);
}
}
)
}
impl_elwise_assign!(Vector, Vector, AddAssign, add_assign);
impl_elwise_assign!(Point, Vector, AddAssign, add_assign);
impl_elwise_assign!(Vector, Vector, SubAssign, sub_assign);
impl_elwise_assign!(Point, Vector, SubAssign, sub_assign);
impl Mul<f32> for Vector {
type Output = Vector;
#[inline]
fn mul(self, scalar: f32) -> Vector {
Vector {
x: self.x * scalar,
y: self.y * scalar,
}
}
}
impl Mul<Vector> for f32 {
type Output = Vector;
#[inline]
fn mul(self, vec: Vector) -> Vector {
Vector {
x: vec.x * self,
y: vec.y * self,
}
}
}
impl MulAssign<f32> for Vector {
#[inline]
fn mul_assign(&mut self, scalar: f32) {
self.x *= scalar;
self.y *= scalar;
}
}
impl Div<f32> for Vector {
type Output = Vector;
#[inline]
fn div(self, scalar: f32) -> Vector {
Vector {
x: self.x / scalar,
y: self.y / scalar,
}
}
}
impl DivAssign<f32> for Vector {
#[inline]
fn div_assign(&mut self, scalar: f32) {
self.x /= scalar;
self.y /= scalar;
}
}
impl Neg for Vector {
type Output = Vector;
#[inline]
fn neg(self) -> Vector {
Vector {
x: -self.x,
y: -self.y,
}
}
}