mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
add docs to all public functions
This commit is contained in:
parent
2fd41869ec
commit
0658895eb6
|
@ -1,4 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
//! Fixed point number implementation for representing non integers efficiently.
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
cmp::{Eq, Ord, PartialEq, PartialOrd},
|
cmp::{Eq, Ord, PartialEq, PartialOrd},
|
||||||
|
@ -12,6 +14,13 @@ use core::{
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use agb_macros::num as num_inner;
|
pub use agb_macros::num as num_inner;
|
||||||
|
|
||||||
|
/// Can be thought of having the signature `num!(float) -> Num<I, N>`.
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::Num;
|
||||||
|
/// # use agb_fixnum::num;
|
||||||
|
/// let n: Num<i32, 8> = num!(0.75);
|
||||||
|
/// assert_eq!(n, Num::new(3) / 4, "0.75 == 3/4");
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! num {
|
macro_rules! num {
|
||||||
($value:literal) => {{
|
($value:literal) => {{
|
||||||
|
@ -19,6 +28,8 @@ macro_rules! num {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for everything required to use as the internal representation of the
|
||||||
|
/// fixed point number.
|
||||||
pub trait Number:
|
pub trait Number:
|
||||||
Sized
|
Sized
|
||||||
+ Copy
|
+ Copy
|
||||||
|
@ -37,6 +48,7 @@ pub trait Number:
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> Number for Num<I, N> {}
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Number for Num<I, N> {}
|
||||||
impl<I: FixedWidthUnsignedInteger> Number for I {}
|
impl<I: FixedWidthUnsignedInteger> Number for I {}
|
||||||
|
|
||||||
|
/// A trait for integers that don't implement unary negation
|
||||||
pub trait FixedWidthUnsignedInteger:
|
pub trait FixedWidthUnsignedInteger:
|
||||||
Sized
|
Sized
|
||||||
+ Copy
|
+ Copy
|
||||||
|
@ -57,14 +69,20 @@ pub trait FixedWidthUnsignedInteger:
|
||||||
+ Debug
|
+ Debug
|
||||||
+ Display
|
+ Display
|
||||||
{
|
{
|
||||||
|
/// Returns the representation of zero
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
|
/// Returns the representation of one
|
||||||
fn one() -> Self;
|
fn one() -> Self;
|
||||||
|
/// Returns the representation of ten
|
||||||
fn ten() -> Self;
|
fn ten() -> Self;
|
||||||
|
/// Converts an i32 to it's own representation, panics on failure
|
||||||
fn from_as_i32(v: i32) -> Self;
|
fn from_as_i32(v: i32) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for an integer that includes negation
|
||||||
pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg<Output = Self> {
|
pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg<Output = Self> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Returns the absolute value of the number
|
||||||
fn fixed_abs(self) -> Self;
|
fn fixed_abs(self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,12 +129,14 @@ fixed_width_unsigned_integer_impl!(usize);
|
||||||
fixed_width_signed_integer_impl!(i16);
|
fixed_width_signed_integer_impl!(i16);
|
||||||
fixed_width_signed_integer_impl!(i32);
|
fixed_width_signed_integer_impl!(i32);
|
||||||
|
|
||||||
|
/// A fixed point number represented using `I` with `N` bits of fractional precision
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Num<I: FixedWidthUnsignedInteger, const N: usize>(I);
|
pub struct Num<I: FixedWidthUnsignedInteger, const N: usize>(I);
|
||||||
|
|
||||||
|
/// An often convenient representation for the Game Boy Advance using word sized
|
||||||
|
/// internal representation for maximum efficiency
|
||||||
pub type FixedNum<const N: usize> = Num<i32, N>;
|
pub type FixedNum<const N: usize> = Num<i32, N>;
|
||||||
pub type Integer = Num<i32, 0>;
|
|
||||||
|
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> From<I> for Num<I, N> {
|
impl<I: FixedWidthUnsignedInteger, const N: usize> From<I> for Num<I, N> {
|
||||||
fn from(value: I) -> Self {
|
fn from(value: I) -> Self {
|
||||||
|
@ -266,6 +286,7 @@ impl<I: FixedWidthSignedInteger, const N: usize> Neg for Num<I, N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
||||||
|
/// Performs the conversion between two integer types and between two different fractional precisions
|
||||||
pub fn change_base<J: FixedWidthUnsignedInteger + From<I>, const M: usize>(self) -> Num<J, M> {
|
pub fn change_base<J: FixedWidthUnsignedInteger + From<I>, const M: usize>(self) -> Num<J, M> {
|
||||||
let n: J = self.0.into();
|
let n: J = self.0.into();
|
||||||
if N < M {
|
if N < M {
|
||||||
|
@ -275,19 +296,40 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A bit for bit conversion from a number to a fixed num
|
||||||
pub fn from_raw(n: I) -> Self {
|
pub fn from_raw(n: I) -> Self {
|
||||||
Num(n)
|
Num(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The internal representation of the fixed point number
|
||||||
pub fn to_raw(self) -> I {
|
pub fn to_raw(self) -> I {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Truncates the fixed point number returning the integral part
|
||||||
|
/// ```rust
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(5.67);
|
||||||
|
/// assert_eq!(n.trunc(), 5);
|
||||||
|
/// let n: Num<i32, 8> = num!(-5.67);
|
||||||
|
/// assert_eq!(n.trunc(), -5);
|
||||||
|
/// ```
|
||||||
pub fn trunc(self) -> I {
|
pub fn trunc(self) -> I {
|
||||||
self.0 / (I::one() << N)
|
self.0 / (I::one() << N)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Performs the equivalent to the integer rem_euclid, which is modulo numbering.
|
||||||
|
/// ```rust
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(5.67);
|
||||||
|
/// let r: Num<i32, 8> = num!(4.);
|
||||||
|
/// assert_eq!(n.rem_euclid(r), num!(1.67));
|
||||||
|
///
|
||||||
|
/// let n: Num<i32, 8> = num!(-1.5);
|
||||||
|
/// let r: Num<i32, 8> = num!(4.);
|
||||||
|
/// assert_eq!(n.rem_euclid(r), num!(2.5));
|
||||||
|
/// ```
|
||||||
pub fn rem_euclid(self, rhs: Self) -> Self {
|
pub fn rem_euclid(self, rhs: Self) -> Self {
|
||||||
let r = self % rhs;
|
let r = self % rhs;
|
||||||
if r < I::zero().into() {
|
if r < I::zero().into() {
|
||||||
|
@ -301,18 +343,41 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs rounding towards negative infinity
|
||||||
|
/// ```rust
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(5.67);
|
||||||
|
/// assert_eq!(n.floor(), 5);
|
||||||
|
/// let n: Num<i32, 8> = num!(-5.67);
|
||||||
|
/// assert_eq!(n.floor(), -6);
|
||||||
|
/// ```
|
||||||
pub fn floor(self) -> I {
|
pub fn floor(self) -> I {
|
||||||
self.0 >> N
|
self.0 >> N
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the fractional component of a number as it's integer representation
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(5.5);
|
||||||
|
/// assert_eq!(n.frac(), 1 << 7);
|
||||||
|
/// ```
|
||||||
pub fn frac(self) -> I {
|
pub fn frac(self) -> I {
|
||||||
self.0 & ((I::one() << N) - I::one())
|
self.0 & ((I::one() << N) - I::one())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an integer represented by a fixed point number
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = Num::new(5);
|
||||||
|
/// assert_eq!(n.frac(), 0); // no fractional component
|
||||||
|
/// assert_eq!(n, num!(5.)); // just equals the number 5
|
||||||
|
/// ```
|
||||||
pub fn new(integral: I) -> Self {
|
pub fn new(integral: I) -> Self {
|
||||||
Self(integral << N)
|
Self(integral << N)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
/// Called by the [num!] macro in order to create a fixed point number
|
||||||
pub fn new_from_parts(num: (i32, i32)) -> Self {
|
pub fn new_from_parts(num: (i32, i32)) -> Self {
|
||||||
Self(I::from_as_i32(((num.0) << N) + (num.1 >> (30 - N))))
|
Self(I::from_as_i32(((num.0) << N) + (num.1 >> (30 - N))))
|
||||||
}
|
}
|
||||||
|
@ -320,6 +385,14 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Num<I, N> {
|
||||||
|
|
||||||
impl<const N: usize> Num<i32, N> {
|
impl<const N: usize> Num<i32, N> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Returns the square root of a number, it is calcuated a digit at a time.
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(16.);
|
||||||
|
/// assert_eq!(n.sqrt(), num!(4.));
|
||||||
|
/// let n: Num<i32, 8> = num!(2.25);
|
||||||
|
/// assert_eq!(n.sqrt(), num!(1.5));
|
||||||
|
/// ```
|
||||||
pub fn sqrt(self) -> Self {
|
pub fn sqrt(self) -> Self {
|
||||||
assert_eq!(N % 2, 0, "N must be even to be able to square root");
|
assert_eq!(N % 2, 0, "N must be even to be able to square root");
|
||||||
assert!(self.0 >= 0, "sqrt is only valid for positive numbers");
|
assert!(self.0 >= 0, "sqrt is only valid for positive numbers");
|
||||||
|
@ -346,12 +419,33 @@ impl<const N: usize> Num<i32, N> {
|
||||||
|
|
||||||
impl<I: FixedWidthSignedInteger, const N: usize> Num<I, N> {
|
impl<I: FixedWidthSignedInteger, const N: usize> Num<I, N> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Returns the absolute value of a fixed point number
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(5.5);
|
||||||
|
/// assert_eq!(n.abs(), num!(5.5));
|
||||||
|
/// let n: Num<i32, 8> = num!(-5.5);
|
||||||
|
/// assert_eq!(n.abs(), num!(5.5));
|
||||||
|
/// ```
|
||||||
pub fn abs(self) -> Self {
|
pub fn abs(self) -> Self {
|
||||||
Num(self.0.fixed_abs())
|
Num(self.0.fixed_abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// domain of [0, 1].
|
/// Calculates the cosign of a fixed point number with the domain of [0, 1].
|
||||||
/// see https://github.com/tarcieri/micromath/blob/24584465b48ff4e87cffb709c7848664db896b4f/src/float/cos.rs#L226
|
/// see <https://github.com/tarcieri/micromath/blob/24584465b48ff4e87cffb709c7848664db896b4f/src/float/cos.rs#L226>
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(0.); // 0 radians
|
||||||
|
/// assert_eq!(n.cos(), num!(1.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.25); // pi / 2 radians
|
||||||
|
/// assert_eq!(n.cos(), num!(0.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.5); // pi radians
|
||||||
|
/// assert_eq!(n.cos(), num!(-1.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.75); // 3pi/2 radians
|
||||||
|
/// assert_eq!(n.cos(), num!(0.));
|
||||||
|
/// let n: Num<i32, 8> = num!(1.); // 2 pi radians (whole rotation)
|
||||||
|
/// assert_eq!(n.cos(), num!(1.));
|
||||||
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn cos(self) -> Self {
|
pub fn cos(self) -> Self {
|
||||||
let one: Self = I::one().into();
|
let one: Self = I::one().into();
|
||||||
|
@ -368,11 +462,25 @@ impl<I: FixedWidthSignedInteger, const N: usize> Num<I, N> {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the sign of a number with domain of [0, 1].
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let n: Num<i32, 8> = num!(0.); // 0 radians
|
||||||
|
/// assert_eq!(n.sin(), num!(0.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.25); // pi / 2 radians
|
||||||
|
/// assert_eq!(n.sin(), num!(1.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.5); // pi radians
|
||||||
|
/// assert_eq!(n.sin(), num!(0.));
|
||||||
|
/// let n: Num<i32, 8> = num!(0.75); // 3pi/2 radians
|
||||||
|
/// assert_eq!(n.sin(), num!(-1.));
|
||||||
|
/// let n: Num<i32, 8> = num!(1.); // 2 pi radians (whole rotation)
|
||||||
|
/// assert_eq!(n.sin(), num!(0.));
|
||||||
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sin(self) -> Self {
|
pub fn sin(self) -> Self {
|
||||||
let one: Self = I::one().into();
|
let one: Self = I::one().into();
|
||||||
let four: I = 4.into();
|
let four: I = 4.into();
|
||||||
(self + one / four).cos()
|
(self - one / four).cos()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,9 +525,12 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Debug for Num<I, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A vector of two points: (x, y) represened by integers or fixed point numbers
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct Vector2D<T: Number> {
|
pub struct Vector2D<T: Number> {
|
||||||
|
/// The x coordinate
|
||||||
pub x: T,
|
pub x: T,
|
||||||
|
/// The y coordinate
|
||||||
pub y: T,
|
pub y: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,6 +616,13 @@ impl<T: Number> SubAssign<Self> for Vector2D<T> {
|
||||||
|
|
||||||
impl<I: FixedWidthUnsignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
impl<I: FixedWidthUnsignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Truncates the x and y coordinate, see [Num::trunc]
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(1.56), num!(-2.2)).into();
|
||||||
|
/// let v2: Vector2D<i32> = (1, -2).into();
|
||||||
|
/// assert_eq!(v1.trunc(), v2);
|
||||||
|
/// ```
|
||||||
pub fn trunc(self) -> Vector2D<I> {
|
pub fn trunc(self) -> Vector2D<I> {
|
||||||
Vector2D {
|
Vector2D {
|
||||||
x: self.x.trunc(),
|
x: self.x.trunc(),
|
||||||
|
@ -513,6 +631,13 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Floors the x and y coordnate, see [Num::floor]
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = Vector2D::new(num!(1.56), num!(-2.2));
|
||||||
|
/// let v2: Vector2D<i32> = (1, -3).into();
|
||||||
|
/// assert_eq!(v1.floor(), v2);
|
||||||
|
/// ```
|
||||||
pub fn floor(self) -> Vector2D<I> {
|
pub fn floor(self) -> Vector2D<I> {
|
||||||
Vector2D {
|
Vector2D {
|
||||||
x: self.x.floor(),
|
x: self.x.floor(),
|
||||||
|
@ -523,24 +648,47 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
|
|
||||||
impl<const N: usize> Vector2D<Num<i32, N>> {
|
impl<const N: usize> Vector2D<Num<i32, N>> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Calculates the magnitude squared, ie (x*x + y*y)
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(3.), num!(4.)).into();
|
||||||
|
/// assert_eq!(v1.magnitude_squared(), 25.into());
|
||||||
|
/// ```
|
||||||
pub fn magnitude_squared(self) -> Num<i32, N> {
|
pub fn magnitude_squared(self) -> Num<i32, N> {
|
||||||
self.x * self.x + self.y * self.y
|
self.x * self.x + self.y * self.y
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Calculates the manhattan distance, x.abs() + y.abs().
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(3.), num!(4.)).into();
|
||||||
|
/// assert_eq!(v1.manhattan_distance(), 7.into());
|
||||||
|
/// ```
|
||||||
pub fn manhattan_distance(self) -> Num<i32, N> {
|
pub fn manhattan_distance(self) -> Num<i32, N> {
|
||||||
self.x.abs() + self.y.abs()
|
self.x.abs() + self.y.abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Calculates the magnitude by square root
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(3.), num!(4.)).into();
|
||||||
|
/// assert_eq!(v1.magnitude(), 5.into());
|
||||||
|
/// ```
|
||||||
pub fn magnitude(self) -> Num<i32, N> {
|
pub fn magnitude(self) -> Num<i32, N> {
|
||||||
self.magnitude_squared().sqrt()
|
self.magnitude_squared().sqrt()
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculates the magnitude of a vector using the alpha max plus beta min
|
/// Calculates the magnitude of a vector using the alpha max plus beta min
|
||||||
// algorithm https://en.wikipedia.org/wiki/Alpha_max_plus_beta_min_algorithm
|
/// algorithm https://en.wikipedia.org/wiki/Alpha_max_plus_beta_min_algorithm
|
||||||
// this has a maximum error of less than 4% of the true magnitude, probably
|
/// this has a maximum error of less than 4% of the true magnitude, probably
|
||||||
// depending on the size of your fixed point approximation
|
/// depending on the size of your fixed point approximation
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(3.), num!(4.)).into();
|
||||||
|
/// assert!(v1.fast_magnitude() > num!(4.9) && v1.fast_magnitude() < num!(5.1));
|
||||||
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn fast_magnitude(self) -> Num<i32, N> {
|
pub fn fast_magnitude(self) -> Num<i32, N> {
|
||||||
let max = core::cmp::max(self.x, self.y);
|
let max = core::cmp::max(self.x, self.y);
|
||||||
|
@ -550,11 +698,24 @@ impl<const N: usize> Vector2D<Num<i32, N>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Normalises the vector to magnitude of one by performing a square root,
|
||||||
|
/// due to fixed point imprecision this magnitude may not be exactly one
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(4.), num!(4.)).into();
|
||||||
|
/// assert_eq!(v1.normalise().magnitude(), 1.into());
|
||||||
|
/// ```
|
||||||
pub fn normalise(self) -> Self {
|
pub fn normalise(self) -> Self {
|
||||||
self / self.magnitude()
|
self / self.magnitude()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Normalises the vector to magnitude of one using [Vector2D::fast_magnitude].
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<Num<i32, 8>> = (num!(4.), num!(4.)).into();
|
||||||
|
/// assert_eq!(v1.fast_normalise().magnitude(), 1.into());
|
||||||
|
/// ```
|
||||||
pub fn fast_normalise(self) -> Self {
|
pub fn fast_normalise(self) -> Self {
|
||||||
self / self.fast_magnitude()
|
self / self.fast_magnitude()
|
||||||
}
|
}
|
||||||
|
@ -567,12 +728,25 @@ impl<T: Number, P: Number + Into<T>> From<(P, P)> for Vector2D<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Number> Vector2D<T> {
|
impl<T: Number> Vector2D<T> {
|
||||||
|
/// Converts the representation of the vector to another type
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1: Vector2D<i16> = Vector2D::new(1, 2);
|
||||||
|
/// let v2: Vector2D<i32> = v1.change_base();
|
||||||
|
/// ```
|
||||||
pub fn change_base<U: Number + From<T>>(self) -> Vector2D<U> {
|
pub fn change_base<U: Number + From<T>>(self) -> Vector2D<U> {
|
||||||
(self.x, self.y).into()
|
(self.x, self.y).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: FixedWidthSignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
impl<I: FixedWidthSignedInteger, const N: usize> Vector2D<Num<I, N>> {
|
||||||
|
/// Creates a unit vector from an angle, noting that the domain of the angle
|
||||||
|
/// is [0, 1], see [Num::cos] and [Num::sin].
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v: Vector2D<Num<i32, 8>> = Vector2D::new_from_angle(num!(0.0));
|
||||||
|
/// assert_eq!(v, (num!(1.0), num!(0.0)).into());
|
||||||
|
/// ```
|
||||||
pub fn new_from_angle(angle: Num<I, N>) -> Self {
|
pub fn new_from_angle(angle: Num<I, N>) -> Self {
|
||||||
Vector2D {
|
Vector2D {
|
||||||
x: angle.cos(),
|
x: angle.cos(),
|
||||||
|
@ -591,24 +765,61 @@ impl<I: FixedWidthUnsignedInteger, const N: usize> From<Vector2D<I>> for Vector2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
/// A rectangle with a position in 2d space and a 2d size
|
||||||
pub struct Rect<T: Number> {
|
pub struct Rect<T: Number> {
|
||||||
|
/// The position of the rectangle
|
||||||
pub position: Vector2D<T>,
|
pub position: Vector2D<T>,
|
||||||
|
/// The size of the rectangle
|
||||||
pub size: Vector2D<T>,
|
pub size: Vector2D<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Number> Rect<T> {
|
impl<T: Number> Rect<T> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Creates a rectangle from it's position and size
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(2,3));
|
||||||
|
/// assert_eq!(r.position, Vector2D::new(1,1));
|
||||||
|
/// assert_eq!(r.size, Vector2D::new(2,3));
|
||||||
|
/// ```
|
||||||
pub fn new(position: Vector2D<T>, size: Vector2D<T>) -> Self {
|
pub fn new(position: Vector2D<T>, size: Vector2D<T>) -> Self {
|
||||||
Rect { position, size }
|
Rect { position, size }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the rectangle contains the point given, note that the boundary counts as containing the rectangle.
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(3,3));
|
||||||
|
/// assert!(r.contains_point(Vector2D::new(1,1)));
|
||||||
|
/// assert!(r.contains_point(Vector2D::new(2,2)));
|
||||||
|
/// assert!(r.contains_point(Vector2D::new(3,3)));
|
||||||
|
/// assert!(r.contains_point(Vector2D::new(4,4)));
|
||||||
|
///
|
||||||
|
/// assert!(!r.contains_point(Vector2D::new(0,2)));
|
||||||
|
/// assert!(!r.contains_point(Vector2D::new(5,2)));
|
||||||
|
/// assert!(!r.contains_point(Vector2D::new(2,0)));
|
||||||
|
/// assert!(!r.contains_point(Vector2D::new(2,5)));
|
||||||
|
/// ```
|
||||||
pub fn contains_point(&self, point: Vector2D<T>) -> bool {
|
pub fn contains_point(&self, point: Vector2D<T>) -> bool {
|
||||||
point.x > self.position.x
|
point.x >= self.position.x
|
||||||
&& point.x < self.position.x + self.size.x
|
&& point.x <= self.position.x + self.size.x
|
||||||
&& point.y > self.position.y
|
&& point.y >= self.position.y
|
||||||
&& point.y < self.position.y + self.size.y
|
&& point.y <= self.position.y + self.size.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the other rectangle touches or overlaps the first.
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(3,3));
|
||||||
|
///
|
||||||
|
/// assert!(r.touches(r.clone()));
|
||||||
|
///
|
||||||
|
/// let r1 = Rect::new(Vector2D::new(2,2), Vector2D::new(3,3));
|
||||||
|
/// assert!(r.touches(r1));
|
||||||
|
///
|
||||||
|
/// let r2 = Rect::new(Vector2D::new(-10,-10), Vector2D::new(3,3));
|
||||||
|
/// assert!(!r.touches(r2));
|
||||||
|
/// ```
|
||||||
pub fn touches(&self, other: Rect<T>) -> bool {
|
pub fn touches(&self, other: Rect<T>) -> bool {
|
||||||
self.position.x < other.position.x + other.size.x
|
self.position.x < other.position.x + other.size.x
|
||||||
&& self.position.x + self.size.x > other.position.x
|
&& self.position.x + self.size.x > other.position.x
|
||||||
|
@ -617,7 +828,28 @@ impl<T: Number> Rect<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn overlapping_rect(&self, other: Rect<T>) -> Self {
|
/// Returns the rectangle that is the region that the two rectangles have in
|
||||||
|
/// common, or [None] if they don't overlap
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(3,3));
|
||||||
|
/// let r2 = Rect::new(Vector2D::new(2,2), Vector2D::new(3,3));
|
||||||
|
///
|
||||||
|
/// assert_eq!(r.overlapping_rect(r2), Some(Rect::new(Vector2D::new(2,2), Vector2D::new(2,2))));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(3,3));
|
||||||
|
/// let r2 = Rect::new(Vector2D::new(-10,-10), Vector2D::new(3,3));
|
||||||
|
///
|
||||||
|
/// assert_eq!(r.overlapping_rect(r2), None);
|
||||||
|
/// ```
|
||||||
|
pub fn overlapping_rect(&self, other: Rect<T>) -> Option<Self> {
|
||||||
|
if !self.touches(other.clone()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
fn max<E: Number>(x: E, y: E) -> E {
|
fn max<E: Number>(x: E, y: E) -> E {
|
||||||
if x > y {
|
if x > y {
|
||||||
x
|
x
|
||||||
|
@ -650,11 +882,21 @@ impl<T: Number> Rect<T> {
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
Rect::new(top_left, bottom_right - top_left)
|
Some(Rect::new(top_left, bottom_right - top_left))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FixedWidthUnsignedInteger> Rect<T> {
|
impl<T: FixedWidthUnsignedInteger> Rect<T> {
|
||||||
|
/// Iterate over the points in a rectangle in row major order.
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let r = Rect::new(Vector2D::new(1,1), Vector2D::new(2,3));
|
||||||
|
///
|
||||||
|
/// let expected_points = vec![(1,1), (2,1), (1,2), (2,2), (1,3), (2,3)];
|
||||||
|
/// let rect_points: Vec<(i32, i32)> = r.iter().collect();
|
||||||
|
///
|
||||||
|
/// assert_eq!(rect_points, expected_points);
|
||||||
|
/// ```
|
||||||
pub fn iter(self) -> impl Iterator<Item = (T, T)> {
|
pub fn iter(self) -> impl Iterator<Item = (T, T)> {
|
||||||
let mut x = self.position.x;
|
let mut x = self.position.x;
|
||||||
let mut y = self.position.y;
|
let mut y = self.position.y;
|
||||||
|
@ -676,15 +918,37 @@ impl<T: FixedWidthUnsignedInteger> Rect<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Number> Vector2D<T> {
|
impl<T: Number> Vector2D<T> {
|
||||||
|
/// Created a vector from the given coordinates
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v = Vector2D::new(1, 2);
|
||||||
|
/// assert_eq!(v.x, 1);
|
||||||
|
/// assert_eq!(v.y, 2);
|
||||||
|
/// ```
|
||||||
pub fn new(x: T, y: T) -> Self {
|
pub fn new(x: T, y: T) -> Self {
|
||||||
Vector2D { x, y }
|
Vector2D { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the tuple of the coorinates
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v = Vector2D::new(1, 2);
|
||||||
|
/// assert_eq!(v.get(), (1, 2));
|
||||||
|
/// ```
|
||||||
pub fn get(self) -> (T, T) {
|
pub fn get(self) -> (T, T) {
|
||||||
(self.x, self.y)
|
(self.x, self.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Calculates the hadamard product of two vectors
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1 = Vector2D::new(2, 3);
|
||||||
|
/// let v2 = Vector2D::new(4, 5);
|
||||||
|
///
|
||||||
|
/// let r = v1.hadamard(v2);
|
||||||
|
/// assert_eq!(r, Vector2D::new(v1.x * v2.x, v1.y * v2.y));
|
||||||
|
/// ```
|
||||||
pub fn hadamard(self, other: Self) -> Self {
|
pub fn hadamard(self, other: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: self.x * other.x,
|
x: self.x * other.x,
|
||||||
|
@ -693,6 +957,12 @@ impl<T: Number> Vector2D<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
/// Swaps the x and y coordinate
|
||||||
|
/// ```
|
||||||
|
/// # use agb_fixnum::*;
|
||||||
|
/// let v1 = Vector2D::new(2, 3);
|
||||||
|
/// assert_eq!(v1.swap(), Vector2D::new(3, 2));
|
||||||
|
/// ```
|
||||||
pub fn swap(self) -> Self {
|
pub fn swap(self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: self.y,
|
x: self.y,
|
||||||
|
|
Loading…
Reference in a new issue