#[cfg(feature = "random")]
use rand::{Rng, SeedableRng};
use std::{
f64::consts::PI,
ops::{Rem, RemAssign},
};
use crate::{Angle, Vecc};
pub type Fecc = Vecc<f64>;
impl Fecc {
pub fn zero() -> Self {
Self { x: 0.0, y: 0.0 }
}
pub fn from_angle<A>(angle: A) -> Self
where
A: Into<Angle>,
{
let angle = angle.into();
Self {
x: angle.cos(),
y: angle.sin(),
}
}
#[cfg(feature = "random")]
#[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(feature = "random")]
#[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(feature = "random")]
#[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() {
Fecc::zero()
} else {
self / self.mag()
}
}
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: Into<Angle>,
{
Self::from_angle(angle.into()) * self.mag()
}
pub fn rotate<A>(&self, angle: A) -> Self
where
A: Into<Angle>,
{
let angle = angle.into();
Self {
x: self.x * angle.cos() - self.y * angle.sin(),
y: self.x * angle.sin() + self.y * angle.cos(),
}
}
pub fn reflect(&self, normal: Fecc) -> Self {
if normal.is_zero() {
*self
} else {
-(self + self.project(normal) * 2.0)
}
}
pub fn project(&self, other: Self) -> Self {
if other.is_zero() {
*self
} else {
other * self.dot(other) / other.dot(other)
}
}
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 {
let angle = other.angle() - self.angle();
if angle > PI {
angle - 2.0 * PI
} else if angle < -PI {
angle + 2.0 * PI
} else {
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)
}
pub fn round(&self) -> Vecc<i64> {
Vecc {
x: self.x.round() as i64,
y: self.y.round() as i64,
}
}
pub fn floor(&self) -> Vecc<i64> {
Vecc {
x: self.x.floor() as i64,
y: self.y.floor() as i64,
}
}
pub fn ceil(&self) -> Vecc<i64> {
Vecc {
x: self.x.ceil() as i64,
y: self.y.ceil() as i64,
}
}
pub fn min(&self, other: Self) -> Self {
Self {
x: self.x.min(other.x),
y: self.y.min(other.y),
}
}
pub fn max(&self, other: Self) -> Self {
Self {
x: self.x.max(other.x),
y: self.y.max(other.y),
}
}
pub fn clamp(&self, min: Self, max: Self) -> Self {
Self {
x: self.x.clamp(min.x, max.x),
y: self.y.clamp(min.y, max.y),
}
}
}
impl Rem<Fecc> for Fecc {
type Output = Fecc;
fn rem(self, rhs: Fecc) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs.x),
y: self.y.rem_euclid(rhs.y),
}
}
}
impl Rem<&Fecc> for Fecc {
type Output = Fecc;
fn rem(self, rhs: &Fecc) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs.x),
y: self.y.rem_euclid(rhs.y),
}
}
}
impl Rem<Fecc> for &Fecc {
type Output = Fecc;
fn rem(self, rhs: Fecc) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs.x),
y: self.y.rem_euclid(rhs.y),
}
}
}
impl Rem<&Fecc> for &Fecc {
type Output = Fecc;
fn rem(self, rhs: &Fecc) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs.x),
y: self.y.rem_euclid(rhs.y),
}
}
}
impl Rem<f64> for Fecc {
type Output = Fecc;
fn rem(self, rhs: f64) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs),
y: self.y.rem_euclid(rhs),
}
}
}
impl Rem<&f64> for Fecc {
type Output = Fecc;
fn rem(self, rhs: &f64) -> Self::Output {
Vecc {
x: self.x.rem_euclid(*rhs),
y: self.y.rem_euclid(*rhs),
}
}
}
impl Rem<f64> for &Fecc {
type Output = Fecc;
fn rem(self, rhs: f64) -> Self::Output {
Vecc {
x: self.x.rem_euclid(rhs),
y: self.y.rem_euclid(rhs),
}
}
}
impl Rem<&f64> for &Fecc {
type Output = Fecc;
fn rem(self, rhs: &f64) -> Self::Output {
Vecc {
x: self.x.rem_euclid(*rhs),
y: self.y.rem_euclid(*rhs),
}
}
}
impl RemAssign<Fecc> for Fecc {
fn rem_assign(&mut self, rhs: Fecc) {
self.x = self.x.rem_euclid(rhs.x);
self.y = self.y.rem_euclid(rhs.y);
}
}
impl RemAssign<&Fecc> for Fecc {
fn rem_assign(&mut self, rhs: &Fecc) {
self.x = self.x.rem_euclid(rhs.x);
self.y = self.y.rem_euclid(rhs.y);
}
}
impl RemAssign<f64> for Fecc {
fn rem_assign(&mut self, rhs: f64) {
self.x = self.x.rem_euclid(rhs);
self.y = self.y.rem_euclid(rhs);
}
}
impl RemAssign<&f64> for Fecc {
fn rem_assign(&mut self, rhs: &f64) {
self.x = self.x.rem_euclid(*rhs);
self.y = self.y.rem_euclid(*rhs);
}
}