Skip to content

Instantly share code, notes, and snippets.

@alexmerou
Last active January 18, 2023 12:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexmerou/23167623356e58d5fd636f5332905ed2 to your computer and use it in GitHub Desktop.
Save alexmerou/23167623356e58d5fd636f5332905ed2 to your computer and use it in GitHub Desktop.
An implementation of a mathematical 2D vector type with tests.
use std::ops::{Add, Div, Mul, Neg, Sub};
#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)]
pub struct Vector2 {
pub x: f32,
pub y: f32,
}
impl Vector2 {
pub const UNIT_X: Self = Self { x: 1.0, y: 0.0 };
pub const UNIT_Y: Self = Self { x: 0.0, y: 1.0 };
#[must_use]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
#[must_use]
pub const fn splat(value: f32) -> Self {
Self { x: value, y: value }
}
#[must_use]
pub fn length(self) -> f32 {
self.x.hypot(self.y)
}
#[must_use]
pub fn normalized(self) -> Self {
let length = self.length();
Self {
x: self.x / length,
y: self.y / length,
}
}
#[must_use]
pub fn dot(self, other: &Self) -> f32 {
self.x.mul_add(other.x, self.y * other.y)
}
}
impl From<[f32; 2]> for Vector2 {
fn from(array: [f32; 2]) -> Self {
Self {
x: array[0],
y: array[1],
}
}
}
impl From<(f32, f32)> for Vector2 {
fn from(tuple: (f32, f32)) -> Self {
Self {
x: tuple.0,
y: tuple.1,
}
}
}
impl Add for Vector2 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl Sub for Vector2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl Mul<f32> for Vector2 {
type Output = Self;
fn mul(self, scalar: f32) -> Self {
Self {
x: self.x * scalar,
y: self.y * scalar,
}
}
}
impl Mul<Vector2> for f32 {
type Output = Vector2;
fn mul(self, vector: Vector2) -> Vector2 {
Vector2 {
x: self * vector.x,
y: self * vector.y,
}
}
}
impl Div<f32> for Vector2 {
type Output = Self;
fn div(self, scalar: f32) -> Self {
Self {
x: self.x / scalar,
y: self.y / scalar,
}
}
}
impl Neg for Vector2 {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vector_add() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = Vector2::new(2.0, 3.0);
let v3 = v1 + v2;
let v4 = Vector2::new(3.0, 5.0);
assert_eq!(v3, v4);
}
#[test]
fn vector_sub() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = Vector2::new(2.0, 3.0);
let v3 = v1 - v2;
let v4 = Vector2::new(-1.0, -1.0);
assert_eq!(v3, v4);
}
#[test]
fn scalar_mul() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = v1 * 2.0;
let v3 = 2.0 * v1;
let v4 = Vector2::new(2.0, 4.0);
assert_eq!(v2, v4);
assert_eq!(v3, v4);
}
#[test]
fn scalar_div() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = v1 / 2.0;
let v3 = Vector2::new(0.5, 1.0);
assert_eq!(v2, v3);
}
#[test]
fn negation() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = -v1;
let v3 = Vector2::new(-1.0, -2.0);
assert_eq!(v2, v3);
}
#[test]
fn length() {
let v1 = Vector2::new(3.0, 4.0);
let len = v1.length();
let expected_len = 5.0;
assert_eq!(len, expected_len);
}
#[test]
fn normalize() {
let v1 = Vector2::new(3.0, 4.0);
let v2 = v1.normalized();
let expected_x = 3.0 / 5.0;
let expected_y = 4.0 / 5.0;
assert_eq!(v2.x, expected_x);
assert_eq!(v2.y, expected_y);
assert_eq!(v2.length(), 1.0);
}
#[test]
fn dot_product() {
let v1 = Vector2::new(1.0, 2.0);
let v2 = Vector2::new(2.0, 3.0);
let dot = v1.dot(&v2);
let expected_dot = 8.0;
assert_eq!(dot, expected_dot);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment