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 }