Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #![allow(dead_code)] | |
| use std::mem::transmute; | |
| use std::ops; | |
| use std::default::Default; | |
| use std::marker::PhantomData; | |
| use std::convert::{ From, AsMut, AsRef }; | |
| use std::fmt; | |
| use units::{ Unit, Untyped }; | |
| use constants::*; | |
| use super::fuzzy_eq; | |
| pub type Vec2 = Vector2D<Untyped>; | |
| pub fn vec2(x: f32, y: f32) -> Vec2 { Vector2D::new(x, y) } | |
| pub type Rect = Rectangle<Untyped>; | |
| pub type IntRect = IntRectangle<Untyped>; | |
| pub struct Vector2D<Unit = Untyped> { | |
| pub x: f32, | |
| pub y: f32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| pub struct Rectangle<Unit = Untyped> { | |
| pub x: f32, | |
| pub y: f32, | |
| pub width: f32, | |
| pub height: f32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| pub struct IntRectangle<Unit = Untyped> { | |
| pub x: i32, | |
| pub y: i32, | |
| pub width: i32, | |
| pub height: i32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| pub struct Size2D<Unit = Untyped> { | |
| pub width: f32, | |
| pub height: f32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| pub struct IntSize2D<Unit = Untyped> { | |
| pub width: i32, | |
| pub height: i32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| pub struct IntVector2D<Unit = Untyped> { | |
| pub x: i32, | |
| pub y: i32, | |
| _unit: PhantomData<Unit>, | |
| } | |
| impl<U> AsRef<[f32; 2]> for Vector2D<U> { | |
| fn as_ref(&self) -> &[f32; 2] { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsRef<(f32, f32)> for Vector2D<U> { | |
| fn as_ref(&self) -> &(f32, f32) { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsMut<[f32; 2]> for Vector2D<U> { | |
| fn as_mut(&mut self) -> &mut [f32; 2] { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsMut<(f32, f32)> for Vector2D<U> { | |
| fn as_mut(&mut self) -> &mut (f32, f32) { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsRef<Vector2D<U>> for [f32; 2] { | |
| fn as_ref(&self) -> &Vector2D<U> { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsRef<Vector2D<U>> for (f32, f32) { | |
| fn as_ref(&self) -> &Vector2D<U> { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsMut<Vector2D<U>> for [f32; 2] { | |
| fn as_mut(&mut self) -> &mut Vector2D<U> { unsafe { transmute(self) } } | |
| } | |
| impl<U> AsMut<Vector2D<U>> for (f32, f32) { | |
| fn as_mut(&mut self) -> &mut Vector2D<U> { unsafe { transmute(self) } } | |
| } | |
| impl<U> From<[f32; 2]> for Vector2D<U> { | |
| fn from(v: [f32; 2]) -> Vector2D<U> { Vector2D::new(v[0], v[1]) } | |
| } | |
| impl<U> From<(f32, f32)> for Vector2D<U> { | |
| fn from(v: (f32, f32)) -> Vector2D<U> { let (x, y) = v; Vector2D::new(x, y) } | |
| } | |
| impl<U> From<Vector2D<U>> for [f32; 2] { | |
| fn from(v: Vector2D<U>) -> [f32; 2] { [v.x, v.y] } | |
| } | |
| impl<U> From<Vector2D<U>> for (f32, f32) { | |
| fn from(v: Vector2D<U>) -> (f32, f32) { (v.x, v.y) } | |
| } | |
| impl<U> Default for Vector2D<U> { | |
| fn default() -> Vector2D<U> { Vector2D::new(0.0, 0.0) } | |
| } | |
| impl<U> Default for Rectangle<U> { | |
| fn default() -> Rectangle<U> { Rectangle::new(0.0, 0.0, 0.0, 0.0) } | |
| } | |
| impl<U> Vector2D<U> { | |
| pub fn new(x: f32, y: f32) -> Vector2D<U> { | |
| Vector2D { | |
| x: x, | |
| y: y, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn from_slice(from: &[f32]) -> Vector2D<U> { | |
| assert!(from.len() >= 2); | |
| return Vector2D { | |
| x: from[0], | |
| y: from[1], | |
| _unit: PhantomData | |
| }; | |
| } | |
| pub fn as_slice<'l>(&'l self) -> &'l [f32] { | |
| unsafe { | |
| return transmute((&self.x as *const f32, 2 as usize )); | |
| } | |
| } | |
| pub fn as_mut_slice<'l>(&'l mut self) -> &'l mut [f32] { | |
| unsafe { | |
| return transmute((&mut self.x as *mut f32, 2 as usize )); | |
| } | |
| } | |
| #[inline] | |
| pub fn array(&self) -> [f32; 2] { [self.x, self.y] } | |
| #[inline] | |
| pub fn tuple(&self) -> (f32, f32) { (self.x, self.y) } | |
| #[inline] | |
| pub fn from_array(array: [f32; 2]) -> Vector2D<U>{ Vector2D::new(array[0], array[1]) } | |
| #[inline] | |
| pub fn from_tuple(tuple: (f32, f32)) -> Vector2D<U> { | |
| let (x, y) = tuple; | |
| Vector2D::new(x, y) | |
| } | |
| #[inline] | |
| pub fn dot(&self, rhs: &Vector2D<U>) -> f32 { | |
| return self.x*rhs.x + self.y*rhs.y; | |
| } | |
| #[inline] | |
| pub fn cross(&self, rhs: Vector2D<U>) -> f32 { | |
| self.x * rhs.y - self.y * rhs.x | |
| } | |
| #[inline] | |
| pub fn length(&self) -> f32 { | |
| return self.square_length().sqrt(); | |
| } | |
| #[inline] | |
| pub fn square_length(&self) -> f32 { | |
| return self.x * self.x + self.y * self.y; | |
| } | |
| pub fn normalized(&self) -> Vector2D<U> { *self / self.length() } | |
| pub fn xy(&self) -> Vector2D<U> { Vector2D { x: self.x, y:self.y, _unit: PhantomData } } | |
| pub fn yx(&self) -> Vector2D<U> { Vector2D { x: self.y, y:self.x, _unit: PhantomData } } | |
| /// Angle between vectors v1 and v2 (oriented clockwise assyming y points downwards). | |
| /// The result is a number between 0 and 2*PI. | |
| /// | |
| /// ex: directed_angle([0,1], [1,0]) = 3/2 Pi rad | |
| /// x __ | |
| /// 0--> / \ | |
| /// y| | x--> v2 | |
| /// v \ |v1 | |
| /// v | |
| /// | |
| /// Or, assuming y points upwards: | |
| /// directed_angle([0,-1], [1,0]) = 1/2 Pi rad | |
| /// | |
| /// ^ v2 | |
| /// y| x--> | |
| /// 0--> v1 | / | |
| /// x v- | |
| /// | |
| pub fn directed_angle(self, other: Vector2D<U>) -> f32 { | |
| let a = (other.y).atan2(other.x) - (self.y).atan2(self.x); | |
| return if a < 0.0 { a + 2.0 * PI } else { a }; | |
| } | |
| pub fn directed_angle2(self, a: Vector2D<U>, b: Vector2D<U>) -> f32 { | |
| (a - self).directed_angle(b - self) | |
| } | |
| pub fn fuzzy_eq(self, rhs: Vector2D<U>) -> bool { | |
| return fuzzy_eq(self.x, rhs.x) && fuzzy_eq(self.y, rhs.y); | |
| } | |
| } | |
| impl<U> ops::Add<Vector2D<U>> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn add(self, rhs: Vector2D<U>) -> Vector2D<U> { | |
| return Vector2D { | |
| x: self.x + rhs.x, | |
| y: self.y + rhs.y, | |
| _unit: PhantomData | |
| }; | |
| } | |
| } | |
| impl<U> ops::Sub<Vector2D<U>> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn sub(self, rhs: Vector2D<U>) -> Vector2D<U> { | |
| return Vector2D { | |
| x: self.x - rhs.x, | |
| y: self.y - rhs.y, | |
| _unit: PhantomData | |
| }; | |
| } | |
| } | |
| impl<U> ops::Mul<Vector2D<U>> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn mul(self, rhs: Vector2D<U>) -> Vector2D<U> { | |
| return Vector2D { | |
| x: self.x * rhs.x, | |
| y: self.y * rhs.y, | |
| _unit: PhantomData | |
| }; | |
| } | |
| } | |
| impl<U> ops::Mul<f32> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn mul(self, rhs: f32) -> Vector2D<U> { | |
| return Vector2D::new(self.x * rhs, self.y * rhs); | |
| } | |
| } | |
| impl<U> ops::Div<Vector2D<U>> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn div(self, rhs: Vector2D<U>) -> Vector2D<U> { | |
| return Vector2D { | |
| x: self.x / rhs.x, | |
| y: self.y / rhs.y, | |
| _unit: PhantomData | |
| }; | |
| } | |
| } | |
| impl<U> ops::Div<f32> for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn div(self, rhs: f32) -> Vector2D<U> { | |
| return Vector2D::new(self.x / rhs, self.y / rhs); | |
| } | |
| } | |
| impl<U> ops::Neg for Vector2D<U> { | |
| type Output = Vector2D<U>; | |
| #[inline] | |
| fn neg(self) -> Vector2D<U> { | |
| return Vector2D { | |
| x: -self.x, | |
| y: -self.y, | |
| _unit: PhantomData | |
| }; | |
| } | |
| } | |
| impl<U: Unit> fmt::Debug for Vector2D<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "Vector2D<{}>[{}, {}]", U::name(), self.x, self.y) | |
| } | |
| } | |
| impl<U> Copy for Vector2D<U> {} | |
| impl<U> Clone for Vector2D<U> { | |
| fn clone(&self) -> Vector2D<U> { *self } | |
| } | |
| impl<U> PartialEq for Vector2D<U> { | |
| fn eq(&self, other: &Vector2D<U>) -> bool { self.x == other.x && self.y == other.y } | |
| } | |
| impl<U> Rectangle<U> { | |
| pub fn new(x: f32, y: f32, w: f32, h:f32) -> Rectangle<U> { | |
| let mut rect = Rectangle { x: x, y: y, width: w, height: h, _unit: PhantomData }; | |
| rect.ensure_invariant(); | |
| return rect; | |
| } | |
| pub fn origin(&self) -> Vector2D<U> { Vector2D { x: self.x, y: self.y, _unit: PhantomData } } | |
| pub fn size(&self) -> Size2D<U> { Size2D::new(self.width, self.height) } | |
| pub fn move_by(&mut self, v: Vector2D<U>) { | |
| self.x = self.x + v.x; | |
| self.y = self.y + v.y; | |
| } | |
| pub fn scale_by(&mut self, v: f32) { | |
| self.x = self.x * v; | |
| self.y = self.y * v; | |
| self.width = self.width * v; | |
| self.height = self.height * v; | |
| self.ensure_invariant(); | |
| } | |
| pub fn top_left(&self) -> Vector2D<U> { | |
| Vector2D { | |
| x: self.x, | |
| y: self.y, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn top_right(&self) -> Vector2D<U> { | |
| Vector2D { | |
| x: self.x + self.width, | |
| y: self.y, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn bottom_right(&self) -> Vector2D<U> { | |
| Vector2D { | |
| x: self.x + self.width, | |
| y: self.y + self.height, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn bottom_left(&self) -> Vector2D<U> { | |
| Vector2D { | |
| x: self.x, | |
| y: self.y + self.height, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn x_most(&self) -> f32 { self.x + self.width } | |
| pub fn y_most(&self) -> f32 { self.y + self.height } | |
| pub fn contains(&self, other: &Rectangle<U>) -> bool { | |
| return self.x <= other.x && | |
| self.y <= self.y && | |
| self.x_most() >= other.x_most() && | |
| self.y_most() >= other.y_most(); | |
| } | |
| pub fn intersects(&self, other: &Rectangle<U>) -> bool { | |
| return self.x < other.x_most() && other.x < self.x_most() && | |
| self.y < other.y_most() && other.y < self.y_most(); | |
| } | |
| pub fn inflate(&mut self, d: f32) { | |
| self.x -= d; | |
| self.y -= d; | |
| self.width += 2.0*d; | |
| self.height += 2.0*d; | |
| } | |
| pub fn deflate(&mut self, d: f32) { self.inflate(-d); } | |
| pub fn ensure_invariant(&mut self) { | |
| self.x = self.x.min(self.x + self.width); | |
| self.y = self.y.min(self.y + self.height); | |
| self.width = self.width.abs(); | |
| self.height = self.height.abs(); | |
| } | |
| } | |
| impl<U: Unit> fmt::Debug for Rectangle<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "Rectangle<{}>[x:{}, y:{} w:{} h:{}]", U::name(), self.x, self.y, self.width, self.height) | |
| } | |
| } | |
| impl<U> Copy for Rectangle<U> {} | |
| impl<U> Clone for Rectangle<U> { | |
| fn clone(&self) -> Rectangle<U> { *self } | |
| } | |
| impl<U> PartialEq for Rectangle<U> { | |
| fn eq(&self, other: &Rectangle<U>) -> bool { | |
| self.x == other.x && self.y == other.y && self.width == other.width && self.height == other.height | |
| } | |
| } | |
| impl<U> IntRectangle<U> { | |
| pub fn new(x: i32, y: i32, w: i32, h:i32) -> IntRectangle<U> { | |
| let mut rect = IntRectangle { x: x, y: y, width: w, height: h, _unit: PhantomData }; | |
| rect.ensure_invariant(); | |
| return rect; | |
| } | |
| pub fn origin(&self) -> IntVector2D<U> { IntVector2D { x: self.x, y: self.y, _unit: PhantomData } } | |
| pub fn size(&self) -> IntSize2D<U> { IntSize2D { width: self.width, height: self.height, _unit: PhantomData } } | |
| pub fn move_by(&mut self, v: IntVector2D<U>) { | |
| self.x = self.x + v.x; | |
| self.y = self.y + v.y; | |
| } | |
| pub fn top_left(&self) -> IntVector2D<U> { | |
| IntVector2D { | |
| x: self.x, | |
| y: self.y, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn top_right(&self) -> IntVector2D<U> { | |
| IntVector2D { | |
| x: self.x + self.width, | |
| y: self.y, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn bottom_right(&self) -> IntVector2D<U> { | |
| IntVector2D { | |
| x: self.x + self.width, | |
| y: self.y + self.height, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn bottom_left(&self) -> IntVector2D<U> { | |
| IntVector2D { | |
| x: self.x, | |
| y: self.y + self.height, | |
| _unit: PhantomData | |
| } | |
| } | |
| pub fn x_most(&self) -> i32 { self.x + self.width } | |
| pub fn y_most(&self) -> i32 { self.y + self.height } | |
| pub fn contains(&self, other: &IntRectangle<U>) -> bool { | |
| return self.x <= other.x && | |
| self.y <= self.y && | |
| self.x_most() >= other.x_most() && | |
| self.y_most() >= other.y_most(); | |
| } | |
| pub fn ensure_invariant(&mut self) { | |
| self.x = imin(self.x, self.x + self.width); | |
| self.y = imin(self.y, self.y + self.height); | |
| self.width = self.width.abs(); | |
| self.height = self.height.abs(); | |
| } | |
| } | |
| impl<U: Unit> fmt::Debug for IntRectangle<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "IntRectangle<{}>[x:{}, y:{} w:{} h:{}]", U::name(), self.x, self.y, self.width, self.height) | |
| } | |
| } | |
| impl<U> Copy for IntRectangle<U> {} | |
| impl<U> Clone for IntRectangle<U> { | |
| fn clone(&self) -> IntRectangle<U> { *self } | |
| } | |
| impl<U> PartialEq for IntRectangle<U> { | |
| fn eq(&self, other: &IntRectangle<U>) -> bool { | |
| self.x == other.x && self.y == other.y && self.width == other.width && self.height == other.height | |
| } | |
| } | |
| fn imin(a: i32, b: i32) -> i32 { if a >= b { a } else { b } } | |
| impl<U> Size2D<U> { | |
| pub fn new(w: f32, h: f32) -> Size2D<U> { Size2D { width: w, height: h, _unit: PhantomData } } | |
| } | |
| impl<U: Unit> fmt::Debug for Size2D<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "Size2D<{}>[{}, {}]", U::name(), self.width, self.height) | |
| } | |
| } | |
| impl<U> Copy for Size2D<U> {} | |
| impl<U> Clone for Size2D<U> { | |
| fn clone(&self) -> Size2D<U> { *self } | |
| } | |
| impl<U> PartialEq for Size2D<U> { | |
| fn eq(&self, other: &Size2D<U>) -> bool { | |
| self.width == other.width && self.height == other.height | |
| } | |
| } | |
| impl<U> IntSize2D<U> { | |
| pub fn new(w: i32, h: i32) -> IntSize2D<U> { IntSize2D { width: w, height: h, _unit: PhantomData } } | |
| } | |
| impl<U: Unit> fmt::Debug for IntSize2D<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "IntSize2D<{}>[{}, {}]", U::name(), self.width, self.height) | |
| } | |
| } | |
| impl<U> Copy for IntSize2D<U> {} | |
| impl<U> Clone for IntSize2D<U> { | |
| fn clone(&self) -> IntSize2D<U> { *self } | |
| } | |
| impl<U: Unit> fmt::Debug for IntVector2D<U> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f, "IntVector2D<{}>[{}, {}]", U::name(), self.x, self.y) | |
| } | |
| } | |
| impl<U> Copy for IntVector2D<U> {} | |
| impl<U> Clone for IntVector2D<U> { | |
| fn clone(&self) -> IntVector2D<U> { *self } | |
| } | |
| impl<U> PartialEq for IntVector2D<U> { | |
| fn eq(&self, other: &IntVector2D<U>) -> bool { | |
| self.x == other.x && self.y == other.y | |
| } | |
| } | |
| pub fn test_directed_angle() { | |
| assert!(fuzzy_eq(vec2(1.0, 1.0).directed_angle(vec2(1.0, 1.0)), 0.0)); | |
| assert!(fuzzy_eq(vec2(1.0, 0.0).directed_angle(vec2(0.0, 1.0)), PI * 0.5)); | |
| assert!(fuzzy_eq(vec2(1.0, 0.0).directed_angle(vec2(-1.0, 0.0)), PI)); | |
| assert!(fuzzy_eq(vec2(1.0, 0.0).directed_angle(vec2(0.0, -1.0)), PI * 1.5)); | |
| assert!(fuzzy_eq(vec2(1.0, -1.0).directed_angle(vec2(1.0, 0.0)), PI * 0.25)); | |
| assert!(fuzzy_eq(vec2(1.0, -1.0).directed_angle(vec2(1.0, 1.0)), PI * 0.5)); | |
| assert!(fuzzy_eq(vec2(1.0, -1.0).directed_angle(vec2(-1.0, 1.0)), PI)); | |
| assert!(fuzzy_eq(vec2(1.0, -1.0).directed_angle(vec2(-1.0, -1.0)), PI * 1.5)); | |
| assert!(fuzzy_eq(vec2(10.0, -10.0).directed_angle(vec2(3.0, 0.0)), PI * 0.25)); | |
| assert!(fuzzy_eq(vec2(10.0, -10.0).directed_angle(vec2(3.0, 3.0)), PI * 0.5)); | |
| assert!(fuzzy_eq(vec2(10.0, -10.0).directed_angle(vec2(-3.0, 3.0)), PI)); | |
| assert!(fuzzy_eq(vec2(10.0, -10.0).directed_angle(vec2(-3.0, -3.0)), PI * 1.5)); | |
| assert!(fuzzy_eq(vec2(-1.0, 0.0).directed_angle(vec2(1.0, 0.0)), PI)); | |
| assert!(fuzzy_eq(vec2(-1.0, 0.0).directed_angle(vec2(0.0, 1.0)), PI * 1.5)); | |
| assert!(fuzzy_eq(vec2(-1.0, 0.0).directed_angle(vec2(0.0, -1.0)), PI * 0.5)); | |
| } | |
| pub fn array_to_vec2_slice<U>(slice: &[[f32; 2]]) -> &[Vector2D<U>] { unsafe { transmute(slice) } } | |
| pub fn vec2_to_array_slice<U>(slice: &[Vector2D<U>]) -> &[[f32; 2]] { unsafe { transmute(slice) } } | |
| pub fn tuple_to_vec2_slice<U>(slice: &[(f32, f32)]) -> &[Vector2D<U>] { unsafe { transmute(slice) } } | |
| pub fn vec2_to_tuple_slice<U>(slice: &[Vector2D<U>]) -> &[(f32, f32)] { unsafe { transmute(slice) } } | |
| // The orphan rule forbids this: | |
| // | |
| //impl<'l, U: Unit> From<&'l [[f32; 2]]> for &'l [Vector2D<U>] { | |
| // fn from(slice: &'l[[f32; 2]]) -> &'l[Vector2D<U>] { array_to_vec2_slice(slice) } | |
| //} | |
| // | |
| //impl<'l, U: Unit> From<&'l [Vector2D<U>]> for &'l [[f32; 2]] { | |
| // fn from(slice: &'l[Vector2D<U>]) -> &'l[[f32; 2]] { vec2_to_array_slice(slice) } | |
| //} |