#![warn(missing_docs)]
#![feature(doc_cfg)]
use std::{f64::consts::PI, ops};
use overload::overload;
#[cfg(any(feature = "random", doc))]
use rand::{Rng, SeedableRng};
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Vecctor {
#[allow(missing_docs)]
pub x: f64,
#[allow(missing_docs)]
pub y: f64,
}
impl Vecctor {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
pub fn zero() -> Self {
Self { x: 0.0, y: 0.0 }
}
pub fn from_angle<A>(angle: A) -> Self
where
A: Angle,
{
let angle = angle.to_rad();
Self {
x: angle.cos(),
y: angle.sin(),
}
}
#[cfg(any(feature = "random", doc))]
#[doc(cfg(feature = "random"))]
pub fn from_rng<R>(mut rng: R) -> Self
where
R: Rng,
{
let angle = rng.gen::<f64>();
Self {
x: angle.cos(),
y: angle.sin(),
}
}
#[cfg(any(feature = "random", doc))]
#[doc(cfg(feature = "random"))]
pub fn from_seed<R>(seed: R::Seed) -> Self
where
R: Rng + SeedableRng,
{
let mut rng = R::from_seed(seed);
let angle = rng.gen::<f64>();
Self {
x: angle.cos(),
y: angle.sin(),
}
}
#[cfg(any(feature = "random", doc))]
#[doc(cfg(feature = "random"))]
pub fn from_entropy<R>() -> Self
where
R: Rng + SeedableRng,
{
let mut rng = R::from_entropy();
let angle = rng.gen::<f64>();
Self {
x: angle.cos(),
y: angle.sin(),
}
}
pub fn normalize(&self) -> Self {
if self.is_zero() {
Vecctor::zero()
} else {
self / self.mag()
}
}
pub fn dot(&self, other: Self) -> f64 {
self.x * other.x + self.y * other.y
}
pub fn cross(&self, other: &Self) -> f64 {
self.x * other.y - self.y * other.x
}
pub fn limit(&self, limit: f64) -> Self {
let mag = self.mag();
if mag > limit {
*self * (limit / mag)
} else {
*self
}
}
pub fn resize(&self, mag: f64) -> Self {
*self * mag / self.mag()
}
pub fn turn<A>(&self, angle: A) -> Self
where
A: Angle,
{
Self::from_angle(angle.to_rad()) * self.mag()
}
pub fn rotate<A>(&self, angle: A) -> Self
where
A: Angle,
{
let angle = angle.to_rad();
Self {
x: self.x * angle.cos() - self.y * angle.sin(),
y: self.x * angle.sin() + self.y * angle.cos(),
}
}
pub fn dist(&self, other: Self) -> f64 {
(*self - other).mag()
}
pub fn dist_squared(&self, other: Self) -> f64 {
(*self - other).mag_squared()
}
pub fn is_zero(&self) -> bool {
(self.x == 0.0) && (self.y == 0.0)
}
pub fn angle_to(&self, other: Self) -> f64 {
other.angle() - self.angle()
}
pub fn angle(&self) -> f64 {
self.y.atan2(self.x)
}
pub fn mag(&self) -> f64 {
self.mag_squared().sqrt()
}
pub fn mag_squared(&self) -> f64 {
self.x.powf(2.0) + self.y.powf(2.0)
}
}
overload!((a: ?Vecctor) + (b: ?Vecctor) -> Vecctor { Vecctor { x: a.x + b.x, y: a.y + b.y } });
overload!((a: ?Vecctor) - (b: ?Vecctor) -> Vecctor { Vecctor { x: a.x - b.x, y: a.y - b.y } });
overload!((a: ?Vecctor) % (m: f64) -> Vecctor { Vecctor { x: ((a.x % m) + m) % m, y: ((a.y % m) + m) % m } });
overload!((a: ?Vecctor) % (b: ?Vecctor) -> Vecctor { Vecctor { x: ((a.x % b.x) + b.x) % b.x, y: ((a.y % b.y) + b.y) % b.y } });
overload!((a: ?Vecctor) * (m: f64) -> Vecctor { Vecctor { x: a.x * m, y: a.y * m } });
overload!((a: ?Vecctor) * (b: ?Vecctor) -> Vecctor { Vecctor { x: a.x * b.x, y: a.y * b.y } });
overload!((a: ?Vecctor) / (m: f64) -> Vecctor { Vecctor { x: a.x / m, y: a.y / m } });
overload!((a: ?Vecctor) / (b: ?Vecctor) -> Vecctor { Vecctor { x: a.x / b.x, y: a.y / b.y } });
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Rad(pub f64);
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Deg(pub f64);
pub trait Angle {
fn to_rad(&self) -> f64;
}
impl Angle for Rad {
fn to_rad(&self) -> f64 {
self.0
}
}
impl Angle for Deg {
fn to_rad(&self) -> f64 {
self.0 * PI / 180.0
}
}
impl Angle for f64 {
fn to_rad(&self) -> f64 {
*self
}
}
pub trait Angular {
fn rad(&self) -> Rad;
fn deg(&self) -> Deg;
}
impl<T> Angular for T
where
f64: From<T>,
T: Copy,
{
fn rad(&self) -> Rad {
Rad(f64::from(*self))
}
fn deg(&self) -> Deg {
Deg(f64::from(*self))
}
}