#![warn(missing_docs)]
#![cfg_attr(feature = "simd", feature(doc_cfg))]
#[cfg(feature = "simd")]
#[cfg_attr(feature = "simd", doc(cfg(feature = "simd")))]
pub mod simd;
pub mod circle;
pub use circle::Circle;
mod group;
pub use group::*;
pub mod rectangle;
pub use rectangle::Rectangle;
mod scalar;
pub use scalar::*;
mod transform;
pub use transform::*;
macro_rules! int_mod {
($T:ident) => {
pub mod $T {
pub type Dim = $T;
pub type Vec2 = [Dim; 2];
pub type Rect = [Dim; 4];
}
};
}
int_mod!(u8);
int_mod!(u16);
int_mod!(u32);
int_mod!(u64);
int_mod!(u128);
int_mod!(usize);
int_mod!(i8);
int_mod!(i16);
int_mod!(i32);
int_mod!(i64);
int_mod!(i128);
int_mod!(isize);
macro_rules! float_mod {
($T:ident) => {
pub mod $T {
pub type Dim = $T;
pub type Vec2 = [Dim; 2];
pub type Rect = [Dim; 4];
pub type Circ = (Vec2, Dim);
pub type Trans = [[Dim; 3]; 2];
}
};
}
float_mod!(f32);
float_mod!(f64);
use std::ops::Neg;
pub use Circle as _;
pub use Rectangle as _;
pub use Transform as _;
pub trait Vector2: Copy {
type Scalar: Scalar;
fn x(&self) -> Self::Scalar;
fn y(&self) -> Self::Scalar;
fn new(x: Self::Scalar, y: Self::Scalar) -> Self;
fn set_x(&mut self, x: Self::Scalar) {
*self = Vector2::new(x, self.y())
}
fn set_y(&mut self, y: Self::Scalar) {
*self = Vector2::new(self.x(), y)
}
fn with_x(self, x: Self::Scalar) -> Self {
Self::new(x, self.y())
}
fn with_y(self, y: Self::Scalar) -> Self {
Self::new(self.x(), y)
}
fn square(s: Self::Scalar) -> Self {
Self::new(s, s)
}
#[inline(always)]
fn map_into<V>(self) -> V
where
V: Vector2,
V::Scalar: From<Self::Scalar>,
{
V::new(V::Scalar::from(self.x()), V::Scalar::from(self.y()))
}
fn map_vec2(self) -> [Self::Scalar; 2] {
self.map_into()
}
fn map_dims<F>(self, mut f: F) -> Self
where
F: FnMut(Self::Scalar) -> Self::Scalar,
{
Self::new(f(self.x()), f(self.y()))
}
fn map_with<V, F>(self, mut f: F) -> V
where
V: Vector2,
F: FnMut(Self::Scalar) -> V::Scalar,
{
V::new(f(self.x()), f(self.y()))
}
#[inline(always)]
fn neg(self) -> Self
where
Self::Scalar: Neg<Output = Self::Scalar>,
{
Self::square(Self::Scalar::ZERO).sub(self)
}
#[inline(always)]
fn add(self, other: Self) -> Self {
Self::new(self.x() + other.x(), self.y() + other.y())
}
#[inline(always)]
fn sub(self, other: Self) -> Self {
Self::new(self.x() - other.x(), self.y() - other.y())
}
#[inline(always)]
fn mul(self, by: Self::Scalar) -> Self {
self.mul2(Self::square(by))
}
#[inline(always)]
fn mul2(self, other: Self) -> Self {
Self::new(self.x() * other.x(), self.y() * other.y())
}
#[inline(always)]
fn div(self, by: Self::Scalar) -> Self {
self.div2(Self::square(by))
}
#[inline(always)]
fn div2(self, other: Self) -> Self {
Self::new(self.x() / other.x(), self.y() / other.y())
}
#[inline(always)]
fn add_assign(&mut self, other: Self) {
*self = self.add(other);
}
#[inline(always)]
fn sub_assign(&mut self, other: Self) {
*self = self.sub(other);
}
#[inline(always)]
fn mul_assign(&mut self, by: Self::Scalar) {
*self = self.mul(by);
}
#[inline(always)]
fn mul2_assign(&mut self, other: Self) {
*self = self.mul2(other);
}
#[inline(always)]
fn div_assign(&mut self, by: Self::Scalar) {
*self = self.div(by);
}
#[inline(always)]
fn div2_assign(&mut self, other: Self) {
*self = self.div2(other);
}
fn max_dim(self) -> Self::Scalar {
if self.x().abs() > self.y().abs() {
self.x()
} else {
self.y()
}
}
fn min_dim(self) -> Self::Scalar {
if self.x().abs() < self.y().abs() {
self.x()
} else {
self.y()
}
}
fn dot(self, other: Self) -> Self::Scalar {
let sum = self.mul2(other);
sum.x() + sum.y()
}
}
impl<P> Vector2 for P
where
P: Pair + Copy,
P::Item: Scalar,
{
type Scalar = P::Item;
#[inline(always)]
fn x(&self) -> P::Item {
self.first()
}
#[inline(always)]
fn y(&self) -> P::Item {
self.second()
}
#[inline(always)]
fn new(x: P::Item, y: P::Item) -> Self {
Self::from_items(x, y)
}
}
pub trait FloatingVector2: Vector2
where
Self::Scalar: FloatingScalar,
{
fn from_angle(radians: Self::Scalar) -> Self {
Self::new(radians.cos(), radians.sin())
}
#[inline(always)]
fn dist(self, to: Self) -> Self::Scalar {
self.sub(to).mag()
}
#[inline(always)]
fn squared_dist(self, to: Self) -> Self::Scalar {
self.sub(to).squared_mag()
}
#[inline(always)]
fn mag(self) -> Self::Scalar {
self.squared_mag().sqrt()
}
#[inline(always)]
fn squared_mag(self) -> Self::Scalar {
self.x().square() + self.y().square()
}
#[inline(always)]
fn unit(self) -> Self {
let mag = self.mag();
if mag < Self::Scalar::EPSILON {
Self::new(Self::Scalar::ZERO, Self::Scalar::ZERO)
} else {
self.div(mag)
}
}
fn rotate(self, radians: Self::Scalar) -> Self {
self.rotate_about(radians, Self::square(Self::Scalar::ZERO))
}
fn rotate_about(self, radians: Self::Scalar, pivot: Self) -> Self {
let sin = radians.sin();
let cos = radians.cos();
let origin_point = self.sub(pivot);
let rotated_point = Self::new(
origin_point.x() * cos - origin_point.y() * sin,
origin_point.x() * sin + origin_point.y() * cos,
);
rotated_point.add(pivot)
}
#[inline(always)]
fn lerp(self, other: Self, t: Self::Scalar) -> Self {
Self::square(Self::Scalar::ONE - t)
.mul2(self)
.add(Self::square(t).mul2(other))
}
fn atan(self) -> Self::Scalar {
self.y().atan2(self.x())
}
fn transform<T>(self, transform: T) -> Self
where
T: Transform<Scalar = Self::Scalar>,
{
transform.apply(self)
}
fn project(self, other: Self) -> Self {
let mag = other.mag();
if mag < Self::Scalar::EPSILON {
Self::new(Self::Scalar::ZERO, Self::Scalar::ZERO)
} else {
other.unit().mul(self.dot(other) / mag)
}
}
}
impl<T> FloatingVector2 for T
where
T: Vector2,
T::Scalar: FloatingScalar,
{
}
#[cfg(test)]
#[test]
fn margins() {
let rect = [0, 0, 8, 8];
assert!(rect.contains([1, 1]));
assert!(!rect.inner_margin(2).contains([1, 1]));
}
#[cfg(test)]
#[test]
fn transforms() {
let v = [1.0, 3.0];
let rot = 1.0;
let pivot = [5.0; 2];
let transform = f32::Trans::identity().rotate_about(rot, pivot);
let v1 = v.rotate_about(rot, pivot);
let v2 = v.transform(transform);
dbg!(v1.dist(v2) / f32::EPSILON);
assert!(v1.dist(v2).is_near_zero(10.0));
}
#[cfg(test)]
#[test]
fn rect_with_bound() {
let rect = [0, 0, 5, 5];
let rt3 = rect.with_top(3);
let rb8 = rect.with_bottom(8);
let rl1 = rect.with_left(1);
let rr1 = rect.with_right(1);
assert_eq!(rt3, [0, 3, 5, 2]);
assert_eq!(rb8, [0, 0, 5, 8]);
assert_eq!(rl1, [1, 0, 4, 5]);
assert_eq!(rr1, [0, 0, 1, 5]);
}