github.com/df-mc/dragonfly@v0.9.13/server/block/cube/trace/bbox.go (about)

     1  package trace
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/go-gl/mathgl/mgl64"
     6  	"math"
     7  )
     8  
     9  // BBoxResult is the result of a basic ray trace collision with a bounding box.
    10  type BBoxResult struct {
    11  	bb   cube.BBox
    12  	pos  mgl64.Vec3
    13  	face cube.Face
    14  }
    15  
    16  // BBox ...
    17  func (r BBoxResult) BBox() cube.BBox {
    18  	return r.bb
    19  }
    20  
    21  // Position ...
    22  func (r BBoxResult) Position() mgl64.Vec3 {
    23  	return r.pos
    24  }
    25  
    26  // Face ...
    27  func (r BBoxResult) Face() cube.Face {
    28  	return r.face
    29  }
    30  
    31  // BBoxIntercept performs a ray trace and calculates the point on the BBox's edge nearest to the start position that the ray trace
    32  // collided with.
    33  // BBoxIntercept returns a BBoxResult with the colliding vector closest to the start position, if no colliding point was found,
    34  // a zero BBoxResult is returned and ok is false.
    35  func BBoxIntercept(bb cube.BBox, start, end mgl64.Vec3) (result BBoxResult, ok bool) {
    36  	min, max := bb.Min(), bb.Max()
    37  	v1 := vec3OnLineWithX(start, end, min[0])
    38  	v2 := vec3OnLineWithX(start, end, max[0])
    39  	v3 := vec3OnLineWithY(start, end, min[1])
    40  	v4 := vec3OnLineWithY(start, end, max[1])
    41  	v5 := vec3OnLineWithZ(start, end, min[2])
    42  	v6 := vec3OnLineWithZ(start, end, max[2])
    43  
    44  	if v1 != nil && !bb.Vec3WithinYZ(*v1) {
    45  		v1 = nil
    46  	}
    47  	if v2 != nil && !bb.Vec3WithinYZ(*v2) {
    48  		v2 = nil
    49  	}
    50  	if v3 != nil && !bb.Vec3WithinXZ(*v3) {
    51  		v3 = nil
    52  	}
    53  	if v4 != nil && !bb.Vec3WithinXZ(*v4) {
    54  		v4 = nil
    55  	}
    56  	if v5 != nil && !bb.Vec3WithinXY(*v5) {
    57  		v5 = nil
    58  	}
    59  	if v6 != nil && !bb.Vec3WithinXY(*v6) {
    60  		v6 = nil
    61  	}
    62  
    63  	var (
    64  		vec  *mgl64.Vec3
    65  		dist = math.MaxFloat64
    66  	)
    67  
    68  	for _, v := range [...]*mgl64.Vec3{v1, v2, v3, v4, v5, v6} {
    69  		if v == nil {
    70  			continue
    71  		}
    72  
    73  		if d := start.Sub(*v).LenSqr(); d < dist {
    74  			vec = v
    75  			dist = d
    76  		}
    77  	}
    78  
    79  	if vec == nil {
    80  		return
    81  	}
    82  
    83  	var f cube.Face
    84  	switch vec {
    85  	case v1:
    86  		f = cube.FaceWest
    87  	case v2:
    88  		f = cube.FaceEast
    89  	case v3:
    90  		f = cube.FaceDown
    91  	case v4:
    92  		f = cube.FaceUp
    93  	case v5:
    94  		f = cube.FaceNorth
    95  	case v6:
    96  		f = cube.FaceSouth
    97  	}
    98  
    99  	return BBoxResult{bb: bb, pos: *vec, face: f}, true
   100  }
   101  
   102  // vec3OnLineWithX returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with an X value passed. If no such vec3
   103  // could be found, the bool returned is false.
   104  func vec3OnLineWithX(a, b mgl64.Vec3, x float64) *mgl64.Vec3 {
   105  	if mgl64.FloatEqual(b[0], a[0]) {
   106  		return nil
   107  	}
   108  
   109  	f := (x - a[0]) / (b[0] - a[0])
   110  	if f < 0 || f > 1 {
   111  		return nil
   112  	}
   113  
   114  	return &mgl64.Vec3{x, a[1] + (b[1]-a[1])*f, a[2] + (b[2]-a[2])*f}
   115  }
   116  
   117  // vec3OnLineWithY returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with a Y value passed. If no such vec3
   118  // could be found, the bool returned is false.
   119  func vec3OnLineWithY(a, b mgl64.Vec3, y float64) *mgl64.Vec3 {
   120  	if mgl64.FloatEqual(a[1], b[1]) {
   121  		return nil
   122  	}
   123  
   124  	f := (y - a[1]) / (b[1] - a[1])
   125  	if f < 0 || f > 1 {
   126  		return nil
   127  	}
   128  
   129  	return &mgl64.Vec3{a[0] + (b[0]-a[0])*f, y, a[2] + (b[2]-a[2])*f}
   130  }
   131  
   132  // vec3OnLineWithZ returns an mgl64.Vec3 on the line between mgl64.Vec3 a and b with a Z value passed. If no such vec3
   133  // could be found, the bool returned is false.
   134  func vec3OnLineWithZ(a, b mgl64.Vec3, z float64) *mgl64.Vec3 {
   135  	if mgl64.FloatEqual(a[2], b[2]) {
   136  		return nil
   137  	}
   138  
   139  	f := (z - a[2]) / (b[2] - a[2])
   140  	if f < 0 || f > 1 {
   141  		return nil
   142  	}
   143  
   144  	return &mgl64.Vec3{a[0] + (b[0]-a[0])*f, a[1] + (b[1]-a[1])*f, z}
   145  }