SwiftVec is an easy-to-use, intuitive vector maths library with a ton of functionality for game development, physics simulations, and other potential use cases.
This crate is in its infancy! 4D vectors are missing, along with other planned functionality.
Beware of bugs!
Simply either run cargo add swift_vec
at the terminal directed towards the directory of your project,
or add swift_vec = X.X
to your cargo.toml
file.
To show off some basic functionality of what this crate allows for;
use core::f32::consts::TAU;
use swift_vec::prelude::*;
use swift_vec::vector::{ Vec2, Vec3, Mat3, Axis2, SignedAxis3 };
use Axis2::*; // It is recommended to import from the Axis enums if you're going to be
// indexing a lot.
fn main() {
/*
* Vectors!
*/
// Supports tuple destructuring and field indexing.
let Vec2(x, y): Vec2<i32> = Vec2(1, 0);
match Vec2(x, y) {
Vec2( 0, 1) => println!("Up"),
Vec2( 0, -1) => println!("Down"),
Vec2(-1, 0) => println!("Left"),
Vec2( 1, 0) => println!("Right"),
_ => println!("Other")
}
let mut test_vec: Vec2<i32> = Vec2(1, 0);
let argmax_axis: Axis2 = test_vec.argmax();
let argmax_val: i32 = test_vec[argmax_axis];
test_vec[X] = 2; // You could always use tuple fields (`test_vec.0`) but this is more readable.
test_vec[Y] = 3;
assert_eq!(argmax_axis, X);
assert_eq!(argmax_val, 1);
assert_eq!(test_vec, Vec2(2, 3));
// Vectors support all primitive numerical types and support multiple construction methods.
let vec_i32: Vec3<i32> = 1.vec3();
let vec_u32: Vec3<u32> = (1, 2, 3).vec3();
let vec_usize: Vec3<usize> = (3, Vec2(2, 3)).vec3();
let vec_f64: Vec3<f64> = (Vec2(5.0, 6.0), 4.0).vec3();
// Vectors can be cast to other types, and can be manipulated just like any other numerical data.
let avg: Vec3<f32> = (vec_i32.cast().unwrap() + vec_u32.cast().unwrap() + vec_usize.cast().unwrap() + vec_f64.cast().unwrap()) / 4.0;
assert_eq!(avg, Vec3(2.5, 2.75, 2.75));
// Several operations are implemented, such as dot/cross products, magnitude/normalization, etc.
let dot: f64 = Vec3(5.0, 4.0, 3.0).dot(Vec3(1.0, 2.0, 3.0));
let mag: f64 = Vec3(3.0, 4.0, 5.0).magnitude();
assert_eq!(dot, 22.0);
assert_eq!(mag, 5.0 * 2.0f64.sqrt());
assert!(Vec3(3.0, 4.0, 5.0).normalized().magnitude().approx_eq(1.0));
// Interpolation is added to vector types.
let a: Vec2<f32> = Vec2(1.0, 2.0);
let b: Vec2<f32> = Vec2(3.0, 3.0);
let c: Vec2<f32> = a.lerp(b, 0.5);
assert_eq!(c, Vec2(2.0, 2.5));
let a: Vec2<f32> = 1.0.vec2();
let b: Vec2<f32> = 2.0.vec2();
let pre_a: Vec2<f32> = -5.0.vec2();
let post_b: Vec2<f32> = 3.0.vec2();
let c_025: Vec2<f32> = a.cubic_interpolate(b, pre_a, post_b, 0.25);
let c_050: Vec2<f32> = a.cubic_interpolate(b, pre_a, post_b, 0.50);
let c_075: Vec2<f32> = a.cubic_interpolate(b, pre_a, post_b, 0.75);
assert!(c_025.approx_eq(Vec2(1.601563, 1.601563)));
assert!(c_050.approx_eq(Vec2(1.8125, 1.8125 )));
assert!(c_075.approx_eq(Vec2(1.867188, 1.867188)));
/*
* Matrices are also supported!
*/
// Create a matrix from a scale.
let control: Mat3<u32> = Mat3::new(
2, 0, 0,
0, 4, 0,
0, 0, 8
);
let scale: Vec3<u32> = Vec3(2, 4, 8);
let mat: Mat3<u32> = Mat3::from_scale(scale);
assert_eq!(mat, control);
// Rotate the matrix.
// You can use `rotated_free()` to specify a custom axis.
let mut mat: Mat3<f32> = mat.cast().unwrap();
mat = mat.rotated(TAU / 2.0, SignedAxis3::YPos);
mat = mat.rotated(TAU / 4.0, SignedAxis3::XPos);
assert!(mat.get_scale().approx_eq(Vec3(2.0, 4.0, 8.0)));
// Matrix inversion is suppported.
let control: Mat3<f32> = Mat3::new(
0.452055, 0.041096, -0.39726,
-0.054795, -0.09589, 0.260274,
-0.041096, 0.178082, -0.054795
);
let mat: Mat3<f32> = Mat3::new(
3.0, 5.0, 2.0,
1.0, 3.0, 7.0,
1.0, 6.0, 3.0
);
assert!(mat.inverse().approx_eq(&control));
// So is normalization.
let mut mat: Mat3<f32> = Mat3::IDENTITY.scaled(Vec3(3.0, 4.0, 6.0));
mat = mat.rotated(TAU, SignedAxis3::YPos);
mat = mat.rotated(TAU, SignedAxis3::XPos);
mat = mat.orthonormalized();
assert!(Vec3(
mat.x.length(), // You can also index Matrices by using `Axis3`.
mat.y.length(),
mat.z.length()
).approx_eq(1.0.vec3()));
// And a bunch of other stuff...
}
We also provide functionality for rectangles and their associated geometric functions;
use swift_vec::prelude::*;
use swift_vec::vector::{ Vec2, Axis2 };
use swift_vec::rect::{ Rect2, Side2 };
fn main() {
// Just like vectors, rectangles can be destructured and indexed.
let Rect2(position, dimensions): Rect2<i32> = Rect2(Vec2(1, 1), Vec2(3, 6));
let rect: Rect2<i32> = Rect2(position, dimensions);
let longest_axis: Axis2 = rect.longest_axis();
let longest_length: i32 = rect.longest_axis_length();
assert_eq!(longest_axis, Axis2::Y);
assert_eq!(longest_length, 6);
// There are checks in place for determining whether rectangles intersect, and to allow for the
// computation of their cross-section.
let rect_a: Rect2<f32> = Rect2::from_offsets(-5.0, -5.0, 5.0, 5.0);
let rect_b: Rect2<f32> = Rect2::from_components(-10.0, -10.0, 7.5, 7.5);
assert_eq!(rect_a.intersects(&rect_b, false), true); // `include_borders` is set to false - not that it matters here.
assert_eq!(rect_a.intersection(&rect_b).unwrap(), Rect2(Vec2(-5.0, -5.0), Vec2(2.5, 2.5)));
let smaller_rect: Rect2<isize> = Rect2::unit();
let bigger_rect: Rect2<i64> = Rect2(Vec2(-32, -32), Vec2(64, 64));
assert_eq!(bigger_rect.encompasses(&smaller_rect.cast()), true); // Casting is supported.
assert_eq!(smaller_rect.encompasses(&bigger_rect.cast()), false);
// Rectangles can be checked to see if they contain a point.
let platform: Rect2<i16> = Rect2(Vec2(0, 0), Vec2(100, 100));
let point: Vec2<i16> = Vec2(50, 50);
assert_eq!(platform.encompasses_point(point), true);
// Rectangles can be merged and their shape can be manipulated.
let rect_a: Rect2<i32> = Rect2::from_components(-3, -3, 3, 3);
let rect_b: Rect2<i32> = Rect2::from_components(3, 3, 3, 3);
let merged: Rect2<i32> = rect_a.merge(&rect_b);
assert_eq!(merged, Rect2(Vec2(-3, -3), Vec2(9, 9)));
let base_rect: Rect2<i32> = Rect2::unit();
let mod_rect: Rect2<i32> = base_rect.grow_side(Side2::Top, 5);
assert_eq!(mod_rect, Rect2(Vec2(0, -5), Vec2(1, 6)));
}
- ℹ️ Simple yet intuitive syntax. No messy constructors!
- ➕ Standard vector arithmetic and operations.
- ✨ Matrix operation support!
- ⛛ Trigonometric functions and angle manipulation.
↗️ Standard vector operations such asmagnitude()
,normalize()
,dot()
,cross()
, etc.- 🪞 Reflection and refraction functions.
- 🌍 Geometric comparisons and operations such as
distance_to()
,slide()
, etc. - 🐌 Different interpolation methods such as
lerp()
,bezier_sample()
,cubic_interpolate()
, andcubic_interpolate_in_time()
. - 📚 Aliases for common functions, such as
length()
formagnitude()
.