8个不稳定版本 (3个破坏性更新)
0.4.1 | 2024年6月16日 |
---|---|
0.4.0 | 2024年6月5日 |
0.3.0 | 2024年6月3日 |
0.2.0 | 2024年1月22日 |
0.1.3 | 2024年1月19日 |
#227 in 数学
140KB
2.5K SLoC
SwiftVec
SwiftVec 是一个易于使用、直观的向量数学库,具有大量功能,适用于游戏开发、物理模拟和其他潜在用例。
⚠️警告⚠️
该库尚处于起步阶段!缺少4D向量和其他计划中的功能。请注意潜在的错误!
入门!
只需在指向项目目录的终端中运行 cargo add swift_vec
,或者在 cargo.toml
文件中添加 swift_vec = X.X
。
以下是一些该库允许的基本功能示例;
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...
}
我们还提供了矩形及其相关几何函数的功能;
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)));
}
特性
- ℹ️ 简单而直观的语法。没有混乱的构造函数!
- ➕ 标准向量算术和操作。
- ✨ 矩阵操作支持!
- ⛛ 三角函数和角度操作。
- ↗️ 标准向量操作,如
magnitude()
、normalize()
、dot()
、cross()
等。 - 🪞 反射和折射函数。
- 🌍 几何比较和操作,如
distance_to()
、slide()
等。 - 🐌 不同的插值方法,如
lerp()
、bezier_sample()
、cubic_interpolate()
和cubic_interpolate_in_time()
。 - 📚 常见函数的别名,例如
length()
对应于magnitude()
。
依赖项
~0.5–1.4MB
~37K SLoC