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

     1  package cube
     2  
     3  import (
     4  	"github.com/go-gl/mathgl/mgl64"
     5  )
     6  
     7  // BBox represents an Axis Aligned Bounding Box in a 3D space. It is defined as two Vec3s, of which one is the
     8  // minimum and one is the maximum.
     9  type BBox struct {
    10  	min, max mgl64.Vec3
    11  }
    12  
    13  // Box creates a new axis aligned bounding box with the minimum and maximum coordinates provided. The returned
    14  // box has minimum and maximum coordinates swapped if necessary so that it is well-formed.
    15  func Box(x0, y0, z0, x1, y1, z1 float64) BBox {
    16  	if x0 > x1 {
    17  		x0, x1 = x1, x0
    18  	}
    19  	if y0 > y1 {
    20  		y0, y1 = y1, y0
    21  	}
    22  	if z0 > z1 {
    23  		z0, z1 = z1, z0
    24  	}
    25  	return BBox{min: mgl64.Vec3{x0, y0, z0}, max: mgl64.Vec3{x1, y1, z1}}
    26  }
    27  
    28  // Grow grows the bounding box in all directions by x and returns the new bounding box.
    29  func (box BBox) Grow(x float64) BBox {
    30  	add := mgl64.Vec3{x, x, x}
    31  	return BBox{min: box.min.Sub(add), max: box.max.Add(add)}
    32  }
    33  
    34  // GrowVec3 grows the BBox on all axes as represented by the Vec3 passed. The vec values are subtracted from
    35  // the minimum values of the BBox and added to the maximum values of the BBox.
    36  func (box BBox) GrowVec3(vec mgl64.Vec3) BBox {
    37  	return BBox{min: box.min.Sub(vec), max: box.max.Add(vec)}
    38  }
    39  
    40  // Min returns the minimum coordinate of the bounding box.
    41  func (box BBox) Min() mgl64.Vec3 {
    42  	return box.min
    43  }
    44  
    45  // Max returns the maximum coordinate of the bounding box.
    46  func (box BBox) Max() mgl64.Vec3 {
    47  	return box.max
    48  }
    49  
    50  // Width returns the width of the BBox.
    51  func (box BBox) Width() float64 {
    52  	return box.max[0] - box.min[0]
    53  }
    54  
    55  // Length returns the length of the BBox.
    56  func (box BBox) Length() float64 {
    57  	return box.max[2] - box.min[2]
    58  }
    59  
    60  // Height returns the height of the BBox.
    61  func (box BBox) Height() float64 {
    62  	return box.max[1] - box.min[1]
    63  }
    64  
    65  // Extend expands the BBox on all axes as represented by the Vec3 passed. Negative coordinates result in an
    66  // expansion towards the negative axis, and vice versa for positive coordinates.
    67  func (box BBox) Extend(vec mgl64.Vec3) BBox {
    68  	if vec[0] < 0 {
    69  		box.min[0] += vec[0]
    70  	} else if vec[0] > 0 {
    71  		box.max[0] += vec[0]
    72  	}
    73  	if vec[1] < 0 {
    74  		box.min[1] += vec[1]
    75  	} else if vec[1] > 0 {
    76  		box.max[1] += vec[1]
    77  	}
    78  	if vec[2] < 0 {
    79  		box.min[2] += vec[2]
    80  	} else if vec[2] > 0 {
    81  		box.max[2] += vec[2]
    82  	}
    83  	return box
    84  }
    85  
    86  // ExtendTowards extends the bounding box by x in a given direction.
    87  func (box BBox) ExtendTowards(f Face, x float64) BBox {
    88  	switch f {
    89  	case FaceDown:
    90  		box.max[1] -= x
    91  	case FaceUp:
    92  		box.min[1] += x
    93  	case FaceNorth:
    94  		box.min[2] -= x
    95  	case FaceSouth:
    96  		box.max[2] += x
    97  	case FaceWest:
    98  		box.min[0] -= x
    99  	case FaceEast:
   100  		box.max[0] += x
   101  	}
   102  	return box
   103  }
   104  
   105  // Stretch stretches the bounding box by x in a given axis.
   106  func (box BBox) Stretch(a Axis, x float64) BBox {
   107  	switch a {
   108  	case Y:
   109  		box.min[1] -= x
   110  		box.max[1] += x
   111  	case Z:
   112  		box.min[2] -= x
   113  		box.max[2] += x
   114  	case X:
   115  		box.min[0] -= x
   116  		box.max[0] += x
   117  	}
   118  	return box
   119  }
   120  
   121  // Translate moves the entire BBox with the Vec3 given. The (minimum and maximum) x, y and z coordinates are
   122  // moved by those in the Vec3 passed.
   123  func (box BBox) Translate(vec mgl64.Vec3) BBox {
   124  	return BBox{min: box.min.Add(vec), max: box.max.Add(vec)}
   125  }
   126  
   127  // TranslateTowards moves the entire AABB by x in the direction of a Face passed.
   128  func (box BBox) TranslateTowards(f Face, x float64) BBox {
   129  	switch f {
   130  	case FaceDown:
   131  		return box.Translate(mgl64.Vec3{0, -x, 0})
   132  	case FaceUp:
   133  		return box.Translate(mgl64.Vec3{0, x, 0})
   134  	case FaceNorth:
   135  		return box.Translate(mgl64.Vec3{0, 0, -x})
   136  	case FaceSouth:
   137  		return box.Translate(mgl64.Vec3{0, 0, x})
   138  	case FaceWest:
   139  		return box.Translate(mgl64.Vec3{-x, 0, 0})
   140  	case FaceEast:
   141  		return box.Translate(mgl64.Vec3{x, 0, 0})
   142  	}
   143  	return box
   144  }
   145  
   146  // IntersectsWith checks if the BBox intersects with another BBox, returning true if this is the case.
   147  func (box BBox) IntersectsWith(other BBox) bool {
   148  	return box.intersectsWith(other, 1e-5)
   149  }
   150  
   151  // intersectsWith checks if the BBox intersects with another BBox, using a specific epsilon. It returns true if this is
   152  // the case.
   153  func (box BBox) intersectsWith(other BBox, epsilon float64) bool {
   154  	if other.max[0]-box.min[0] > epsilon && box.max[0]-other.min[0] > epsilon {
   155  		if other.max[1]-box.min[1] > epsilon && box.max[1]-other.min[1] > epsilon {
   156  			return other.max[2]-box.min[2] > epsilon && box.max[2]-other.min[2] > epsilon
   157  		}
   158  	}
   159  	return false
   160  }
   161  
   162  // AnyIntersections checks if any of boxes1 have intersections with any of boxes2 and returns true if this
   163  // happens to be the case.
   164  func AnyIntersections(boxes []BBox, search BBox) bool {
   165  	for _, box := range boxes {
   166  		if box.intersectsWith(search, 0) {
   167  			return true
   168  		}
   169  	}
   170  	return false
   171  }
   172  
   173  // Vec3Within checks if the BBox has a Vec3 within it, returning true if it does.
   174  func (box BBox) Vec3Within(vec mgl64.Vec3) bool {
   175  	if vec[0] <= box.min[0] || vec[0] >= box.max[0] {
   176  		return false
   177  	}
   178  	if vec[2] <= box.min[2] || vec[2] >= box.max[2] {
   179  		return false
   180  	}
   181  	return vec[1] > box.min[1] && vec[1] < box.max[1]
   182  }
   183  
   184  // Vec3WithinYZ checks if the BBox has a Vec3 within its Y and Z bounds, returning true if it does.
   185  func (box BBox) Vec3WithinYZ(vec mgl64.Vec3) bool {
   186  	if vec[2] < box.min[2] || vec[2] > box.max[2] {
   187  		return false
   188  	}
   189  	return vec[1] >= box.min[1] && vec[1] <= box.max[1]
   190  }
   191  
   192  // Vec3WithinXZ checks if the BBox has a Vec3 within its X and Z bounds, returning true if it does.
   193  func (box BBox) Vec3WithinXZ(vec mgl64.Vec3) bool {
   194  	if vec[0] < box.min[0] || vec[0] > box.max[0] {
   195  		return false
   196  	}
   197  	return vec[2] >= box.min[2] && vec[2] <= box.max[2]
   198  }
   199  
   200  // Vec3WithinXY checks if the BBox has a Vec3 within its X and Y bounds, returning true if it does.
   201  func (box BBox) Vec3WithinXY(vec mgl64.Vec3) bool {
   202  	if vec[0] < box.min[0] || vec[0] > box.max[0] {
   203  		return false
   204  	}
   205  	return vec[1] >= box.min[1] && vec[1] <= box.max[1]
   206  }
   207  
   208  // XOffset calculates the offset on the X axis between two bounding boxes, returning a delta always
   209  // smaller than or equal to deltaX if deltaX is bigger than 0, or always bigger than or equal to deltaX if it
   210  // is smaller than 0.
   211  func (box BBox) XOffset(nearby BBox, deltaX float64) float64 {
   212  	// Bail out if not within the same Y/Z plane.
   213  	if box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] {
   214  		return deltaX
   215  	} else if box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
   216  		return deltaX
   217  	}
   218  	if deltaX > 0 && box.max[0] <= nearby.min[0] {
   219  		difference := nearby.min[0] - box.max[0]
   220  		if difference < deltaX {
   221  			deltaX = difference
   222  		}
   223  	}
   224  	if deltaX < 0 && box.min[0] >= nearby.max[0] {
   225  		difference := nearby.max[0] - box.min[0]
   226  
   227  		if difference > deltaX {
   228  			deltaX = difference
   229  		}
   230  	}
   231  	return deltaX
   232  }
   233  
   234  // YOffset calculates the offset on the Y axis between two bounding boxes, returning a delta always
   235  // smaller than or equal to deltaY if deltaY is bigger than 0, or always bigger than or equal to deltaY if it
   236  // is smaller than 0.
   237  func (box BBox) YOffset(nearby BBox, deltaY float64) float64 {
   238  	// Bail out if not within the same X/Z plane.
   239  	if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] {
   240  		return deltaY
   241  	} else if box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
   242  		return deltaY
   243  	}
   244  	if deltaY > 0 && box.max[1] <= nearby.min[1] {
   245  		difference := nearby.min[1] - box.max[1]
   246  		if difference < deltaY {
   247  			deltaY = difference
   248  		}
   249  	}
   250  	if deltaY < 0 && box.min[1] >= nearby.max[1] {
   251  		difference := nearby.max[1] - box.min[1]
   252  
   253  		if difference > deltaY {
   254  			deltaY = difference
   255  		}
   256  	}
   257  	return deltaY
   258  }
   259  
   260  // ZOffset calculates the offset on the Z axis between two bounding boxes, returning a delta always
   261  // smaller than or equal to deltaZ if deltaZ is bigger than 0, or always bigger than or equal to deltaZ if it
   262  // is smaller than 0.
   263  func (box BBox) ZOffset(nearby BBox, deltaZ float64) float64 {
   264  	// Bail out if not within the same X/Y plane.
   265  	if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] {
   266  		return deltaZ
   267  	} else if box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] {
   268  		return deltaZ
   269  	}
   270  	if deltaZ > 0 && box.max[2] <= nearby.min[2] {
   271  		difference := nearby.min[2] - box.max[2]
   272  		if difference < deltaZ {
   273  			deltaZ = difference
   274  		}
   275  	}
   276  	if deltaZ < 0 && box.min[2] >= nearby.max[2] {
   277  		difference := nearby.max[2] - box.min[2]
   278  
   279  		if difference > deltaZ {
   280  			deltaZ = difference
   281  		}
   282  	}
   283  	return deltaZ
   284  }