26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
285 lines
8.1 KiB
Go
285 lines
8.1 KiB
Go
package cube
|
|
|
|
import (
|
|
"github.com/go-gl/mathgl/mgl64"
|
|
)
|
|
|
|
// BBox represents an Axis Aligned Bounding Box in a 3D space. It is defined as
|
|
// two Vec3s, of which one is the minimum and one is the maximum.
|
|
type BBox struct {
|
|
min, max mgl64.Vec3
|
|
}
|
|
|
|
// Box creates a new axis aligned bounding box with the minimum and maximum
|
|
// coordinates provided. The returned box has minimum and maximum coordinates
|
|
// swapped if necessary so that it is well-formed.
|
|
func Box(x0, y0, z0, x1, y1, z1 float64) BBox {
|
|
if x0 > x1 {
|
|
x0, x1 = x1, x0
|
|
}
|
|
if y0 > y1 {
|
|
y0, y1 = y1, y0
|
|
}
|
|
if z0 > z1 {
|
|
z0, z1 = z1, z0
|
|
}
|
|
return BBox{min: mgl64.Vec3{x0, y0, z0}, max: mgl64.Vec3{x1, y1, z1}}
|
|
}
|
|
|
|
// Grow grows the bounding box in all directions by x and returns the new
|
|
// bounding box.
|
|
func (box BBox) Grow(x float64) BBox {
|
|
add := mgl64.Vec3{x, x, x}
|
|
return BBox{min: box.min.Sub(add), max: box.max.Add(add)}
|
|
}
|
|
|
|
// GrowVec3 grows the BBox on all axes as represented by the Vec3 passed. The
|
|
// vec values are subtracted from the minimum values of the BBox and added to
|
|
// the maximum values of the BBox.
|
|
func (box BBox) GrowVec3(vec mgl64.Vec3) BBox {
|
|
return BBox{min: box.min.Sub(vec), max: box.max.Add(vec)}
|
|
}
|
|
|
|
// Min returns the minimum coordinate of the bounding box.
|
|
func (box BBox) Min() mgl64.Vec3 {
|
|
return box.min
|
|
}
|
|
|
|
// Max returns the maximum coordinate of the bounding box.
|
|
func (box BBox) Max() mgl64.Vec3 {
|
|
return box.max
|
|
}
|
|
|
|
// Width returns the width of the BBox.
|
|
func (box BBox) Width() float64 {
|
|
return box.max[0] - box.min[0]
|
|
}
|
|
|
|
// Length returns the length of the BBox.
|
|
func (box BBox) Length() float64 {
|
|
return box.max[2] - box.min[2]
|
|
}
|
|
|
|
// Height returns the height of the BBox.
|
|
func (box BBox) Height() float64 {
|
|
return box.max[1] - box.min[1]
|
|
}
|
|
|
|
// Extend expands the BBox on all axes as represented by the Vec3 passed.
|
|
// Negative coordinates result in an expansion towards the negative axis, and
|
|
// vice versa for positive coordinates.
|
|
func (box BBox) Extend(vec mgl64.Vec3) BBox {
|
|
if vec[0] < 0 {
|
|
box.min[0] += vec[0]
|
|
} else if vec[0] > 0 {
|
|
box.max[0] += vec[0]
|
|
}
|
|
if vec[1] < 0 {
|
|
box.min[1] += vec[1]
|
|
} else if vec[1] > 0 {
|
|
box.max[1] += vec[1]
|
|
}
|
|
if vec[2] < 0 {
|
|
box.min[2] += vec[2]
|
|
} else if vec[2] > 0 {
|
|
box.max[2] += vec[2]
|
|
}
|
|
return box
|
|
}
|
|
|
|
// ExtendTowards extends the bounding box by x in a given direction.
|
|
func (box BBox) ExtendTowards(f Face, x float64) BBox {
|
|
switch f {
|
|
case FaceDown:
|
|
box.min[1] -= x
|
|
case FaceUp:
|
|
box.max[1] += x
|
|
case FaceNorth:
|
|
box.min[2] -= x
|
|
case FaceSouth:
|
|
box.max[2] += x
|
|
case FaceWest:
|
|
box.min[0] -= x
|
|
case FaceEast:
|
|
box.max[0] += x
|
|
}
|
|
return box
|
|
}
|
|
|
|
// Stretch stretches the bounding box by x in a given axis.
|
|
func (box BBox) Stretch(a Axis, x float64) BBox {
|
|
switch a {
|
|
case Y:
|
|
box.min[1] -= x
|
|
box.max[1] += x
|
|
case Z:
|
|
box.min[2] -= x
|
|
box.max[2] += x
|
|
case X:
|
|
box.min[0] -= x
|
|
box.max[0] += x
|
|
}
|
|
return box
|
|
}
|
|
|
|
// Translate moves the entire BBox with the Vec3 given. The (minimum and
|
|
// maximum) x, y and z coordinates are moved by those in the Vec3 passed.
|
|
func (box BBox) Translate(vec mgl64.Vec3) BBox {
|
|
return BBox{min: box.min.Add(vec), max: box.max.Add(vec)}
|
|
}
|
|
|
|
// TranslateTowards moves the entire BBox by x in the direction of a Face f.
|
|
func (box BBox) TranslateTowards(f Face, x float64) BBox {
|
|
switch f {
|
|
case FaceDown:
|
|
return box.Translate(mgl64.Vec3{0, -x, 0})
|
|
case FaceUp:
|
|
return box.Translate(mgl64.Vec3{0, x, 0})
|
|
case FaceNorth:
|
|
return box.Translate(mgl64.Vec3{0, 0, -x})
|
|
case FaceSouth:
|
|
return box.Translate(mgl64.Vec3{0, 0, x})
|
|
case FaceWest:
|
|
return box.Translate(mgl64.Vec3{-x, 0, 0})
|
|
case FaceEast:
|
|
return box.Translate(mgl64.Vec3{x, 0, 0})
|
|
}
|
|
return box
|
|
}
|
|
|
|
// IntersectsWith checks if the BBox intersects with another BBox.
|
|
func (box BBox) IntersectsWith(other BBox) bool {
|
|
return box.intersectsWith(other, 1e-5)
|
|
}
|
|
|
|
// intersectsWith checks if the BBox intersects with another BBox using a
|
|
// specific epsilon.
|
|
func (box BBox) intersectsWith(other BBox, epsilon float64) bool {
|
|
if other.max[0]-box.min[0] > epsilon && box.max[0]-other.min[0] > epsilon {
|
|
if other.max[1]-box.min[1] > epsilon && box.max[1]-other.min[1] > epsilon {
|
|
return other.max[2]-box.min[2] > epsilon && box.max[2]-other.min[2] > epsilon
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// AnyIntersections checks if any of boxes intersect with search.
|
|
func AnyIntersections(boxes []BBox, search BBox) bool {
|
|
for _, box := range boxes {
|
|
if box.intersectsWith(search, 0) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Vec3Within checks if a BBox has vec within it.
|
|
func (box BBox) Vec3Within(vec mgl64.Vec3) bool {
|
|
if vec[0] <= box.min[0] || vec[0] >= box.max[0] {
|
|
return false
|
|
}
|
|
if vec[2] <= box.min[2] || vec[2] >= box.max[2] {
|
|
return false
|
|
}
|
|
return vec[1] > box.min[1] && vec[1] < box.max[1]
|
|
}
|
|
|
|
// Vec3WithinYZ checks if a BBox has vec within its Y and Z bounds.
|
|
func (box BBox) Vec3WithinYZ(vec mgl64.Vec3) bool {
|
|
if vec[2] < box.min[2] || vec[2] > box.max[2] {
|
|
return false
|
|
}
|
|
return vec[1] >= box.min[1] && vec[1] <= box.max[1]
|
|
}
|
|
|
|
// Vec3WithinXZ checks if a BBox has vec within its X and Z bounds.
|
|
func (box BBox) Vec3WithinXZ(vec mgl64.Vec3) bool {
|
|
if vec[0] < box.min[0] || vec[0] > box.max[0] {
|
|
return false
|
|
}
|
|
return vec[2] >= box.min[2] && vec[2] <= box.max[2]
|
|
}
|
|
|
|
// Vec3WithinXY checks if a BBox has vec within its X and Y bounds.
|
|
func (box BBox) Vec3WithinXY(vec mgl64.Vec3) bool {
|
|
if vec[0] < box.min[0] || vec[0] > box.max[0] {
|
|
return false
|
|
}
|
|
return vec[1] >= box.min[1] && vec[1] <= box.max[1]
|
|
}
|
|
|
|
// XOffset calculates the offset on the X axis between two bounding boxes,
|
|
// returning a delta always smaller than or equal to deltaX if deltaX is bigger
|
|
// than 0, or always bigger than or equal to deltaX if it is smaller than 0.
|
|
func (box BBox) XOffset(nearby BBox, deltaX float64) float64 {
|
|
if box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] || box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
|
|
// Not in the same Y/Z plane.
|
|
return deltaX
|
|
}
|
|
if deltaX > 0 && box.max[0] <= nearby.min[0] {
|
|
deltaX = min(deltaX, nearby.min[0]-box.max[0])
|
|
} else if deltaX < 0 && box.min[0] >= nearby.max[0] {
|
|
deltaX = max(deltaX, nearby.max[0]-box.min[0])
|
|
}
|
|
return deltaX
|
|
}
|
|
|
|
// YOffset calculates the offset on the Y axis between two bounding boxes,
|
|
// returning a delta always smaller than or equal to deltaY if deltaY is bigger
|
|
// than 0, or always bigger than or equal to deltaY if it is smaller than 0.
|
|
func (box BBox) YOffset(nearby BBox, deltaY float64) float64 {
|
|
if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] || box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
|
|
// Not the same X/Z plane.
|
|
return deltaY
|
|
}
|
|
if deltaY > 0 && box.max[1] <= nearby.min[1] {
|
|
deltaY = min(deltaY, nearby.min[1]-box.max[1])
|
|
}
|
|
if deltaY < 0 && box.min[1] >= nearby.max[1] {
|
|
deltaY = max(deltaY, nearby.max[1]-box.min[1])
|
|
}
|
|
return deltaY
|
|
}
|
|
|
|
// ZOffset calculates the offset on the Z axis between two bounding boxes,
|
|
// returning a delta always smaller than or equal to deltaZ if deltaZ is bigger
|
|
// than 0, or always bigger than or equal to deltaZ if it is smaller than 0.
|
|
func (box BBox) ZOffset(nearby BBox, deltaZ float64) float64 {
|
|
if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] || box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] {
|
|
// Not the same X/Y plane.
|
|
return deltaZ
|
|
}
|
|
if deltaZ > 0 && box.max[2] <= nearby.min[2] {
|
|
deltaZ = min(deltaZ, nearby.min[2]-box.max[2])
|
|
}
|
|
if deltaZ < 0 && box.min[2] >= nearby.max[2] {
|
|
deltaZ = max(deltaZ, nearby.max[2]-box.min[2])
|
|
}
|
|
return deltaZ
|
|
}
|
|
|
|
// Corners returns the positions of all corners of a BBox.
|
|
func (box BBox) Corners() []mgl64.Vec3 {
|
|
bbmin, bbmax := box.min, box.max
|
|
return []mgl64.Vec3{
|
|
box.min,
|
|
box.max,
|
|
{bbmin[0], bbmin[1], bbmax[2]},
|
|
{bbmin[0], bbmax[1], bbmin[2]},
|
|
{bbmin[0], bbmax[1], bbmax[2]},
|
|
{bbmax[0], bbmax[1], bbmin[2]},
|
|
{bbmax[0], bbmin[1], bbmax[2]},
|
|
{bbmax[0], bbmin[1], bbmin[2]},
|
|
}
|
|
}
|
|
|
|
// Mul performs a scalar multiplication of the min and max points of a BBox.
|
|
func (box BBox) Mul(val float64) BBox {
|
|
return BBox{min: box.min.Mul(val), max: box.max.Mul(val)}
|
|
}
|
|
|
|
// Volume calculates the volume of a BBox.
|
|
func (box BBox) Volume() float64 {
|
|
return box.Height() * box.Length() * box.Width()
|
|
}
|