forked from vv/efemra
1
0
Fork 0
efemra/src/math/box.zig

105 lines
2.8 KiB
Zig

const std = @import("std");
const Vec4f = @import("vec.zig").Vec4f;
const Mat4f = @import("vec.zig").Mat4f;
const BoxData = packed struct {};
pub fn Box(comptime Vec: type, comptime Shift: comptime_int) type {
return packed struct {
const Self = @This();
pub const empty = Self{
.lo = Vec.s(1 << Shift),
.hi = Vec.s(-(1 << Shift)),
};
lo: Vec,
hi: Vec,
pub inline fn new(lo: Vec, hi: Vec) Self {
return Self{
.lo = lo,
.hi = hi,
};
}
pub inline fn center(self: Self) Vec {
return self.lo.lerpvs(self.hi, 0.5);
}
pub inline fn size(self: Self) Vec {
return self.hi.sub(self.lo);
}
pub inline fn extents(self: Self) Vec {
return self.size().mulvs(0.5);
}
pub inline fn contains(self: Self, pt: Vec) bool {
return pt.gteq(self.lo).all3() and pt.lteq(self.hi).all3();
}
pub inline fn area(self: Self) f32 {
const sz = self.size();
return sz.x * sz.y * if (Vec.nelem > 2) sz.z else 1;
}
pub inline fn fromPts(pts: []const Vec) Self {
var lo = Vec.s(1 << Shift);
var hi = Vec.s(-(1 << Shift));
for (pts) |pt| {
lo = lo.min(pt);
hi = hi.max(pt);
}
return Self{
.lo = lo,
.hi = hi,
};
}
pub inline fn uni(lhs: Self, rhs: Self) Self {
return Self{
.lo = lhs.lo.min(rhs.lo),
.hi = lhs.hi.max(rhs.hi),
};
}
pub inline fn intersect(lhs: Self, rhs: Self) Self {
var lo = lhs.lo.min(rhs.lo);
var hi = lhs.hi.max(rhs.hi);
const mid = lo.lerpvs(hi, 0.5);
const inverted = lo.gt(hi);
lo = lo.select(mid, inverted);
hi = hi.select(mid, inverted);
return Self{
.lo = lo,
.hi = hi,
};
}
// TODO: genericise
pub inline fn transform(matrix: Mat4f, box: Self) Self {
var ct = box.center();
var exts = box.hi.sub(ct);
ct = matrix.mulPt(ct);
exts = matrix.mulExtents(exts);
return Self{
.lo = ct.sub(exts),
.hi = ct.add(exts),
};
}
};
}
// pub const Box2d = Box(Vec2f); // need to understand the shift magic
pub const Box3d = Box(Vec4f, 20);
test "Box3d" {
const b1 = Box3d.fromPts(&.{ Vec4f.s(1), Vec4f.s(-1) });
try std.testing.expectEqual(@as(f32, 8), b1.area());
const v1 = Vec4f.s(0.5);
try std.testing.expect(b1.contains(v1));
}