diff --git a/vec3/src/vec3.zig b/vec3/src/vec3.zig index f7f7342..c1f3633 100644 --- a/vec3/src/vec3.zig +++ b/vec3/src/vec3.zig @@ -85,6 +85,32 @@ pub fn vec3MulMat3(comptime T: type, a: Vec3(T), b: Mat3(T)) Vec3(T) { }; } +// Uses the Quaternion definition of q = w + xi + yj + zk +// and with i^2 = j^2 = k^2 = ijk = -1 +// I grabbed a lot of this math from https://imadrahmoune.com/rotations-with-quaternions/ +pub fn Quat(comptime T: type) type { + return struct { + w: T, + x: T, + y: T, + z: T, + + pub fn mag(q: Quat(T)) T { + return std.math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w); + } + + pub fn normalized(q: Quat(T)) Quat(T) { + const magnitude = q.mag(); + return .{ + .x = q.x / magnitude, + .y = q.y / magnitude, + .z = q.z / magnitude, + .w = q.w / magnitude, + }; + } + }; +} + test "vec3Add adds properly" { const a: Vec3(i8) = .{ .x = 1, .y = 2, .z = 3 }; const b: Vec3(i8) = .{ .x = 3, .y = 1, .z = 0 }; @@ -209,3 +235,25 @@ test "vec3 mul mat3 works" { try std.testing.expect(c.y == 3); try std.testing.expect(c.z == 5); } + +test "quat magnitude" { + const q: Quat(f32) = .{ .x = 1.0, .y = 2.0, .z = 3.0, .w = 4.0 }; + try std.testing.expect(std.math.approxEqAbs(f32, q.mag(), std.math.sqrt(30.0), 1e-7)); +} + +test "quat normalized" { + const q: Quat(f32) = .{ .x = 1.0, .y = 2.0, .z = 3.0, .w = 4.0 }; + const expected: Quat(f32) = .{ + .x = 1.0 / std.math.sqrt(30.0), + .y = 2.0 / std.math.sqrt(30.0), + .z = 3.0 / std.math.sqrt(30.0), + .w = 4.0 / std.math.sqrt(30.0), + }; + + const normalized = q.normalized(); + + try std.testing.expect(std.math.approxEqAbs(f32, normalized.x, expected.x, 1e-7)); + try std.testing.expect(std.math.approxEqAbs(f32, normalized.y, expected.y, 1e-7)); + try std.testing.expect(std.math.approxEqAbs(f32, normalized.z, expected.z, 1e-7)); + try std.testing.expect(std.math.approxEqAbs(f32, normalized.w, expected.w, 1e-7)); +}