PocketMine-MP 5.33.2 git-1133d49c924b4358c79d44eeb97dcbf56cb4d1eb
Loading...
Searching...
No Matches
AxisAlignedBB.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20*/
21
22declare(strict_types=1);
23
24namespace pocketmine\math;
25
26use function abs;
27use const PHP_INT_MAX;
28
29final readonly class AxisAlignedBB{
30
31 public float $minX;
32 public float $minY;
33 public float $minZ;
34 public float $maxX;
35 public float $maxY;
36 public float $maxZ;
37
38 public function __construct(float $minX, float $minY, float $minZ, float $maxX, float $maxY, float $maxZ){
39 if($minX > $maxX){
40 throw new \InvalidArgumentException("minX $minX is larger than maxX $maxX");
41 }
42 if($minY > $maxY){
43 throw new \InvalidArgumentException("minY $minY is larger than maxY $maxY");
44 }
45 if($minZ > $maxZ){
46 throw new \InvalidArgumentException("minZ $minZ is larger than maxZ $maxZ");
47 }
48 $this->minX = $minX;
49 $this->minY = $minY;
50 $this->minZ = $minZ;
51 $this->maxX = $maxX;
52 $this->maxY = $maxY;
53 $this->maxZ = $maxZ;
54 }
55
61 public function addCoord(float $x, float $y, float $z) : AxisAlignedBB{
62 $minX = $this->minX;
63 $minY = $this->minY;
64 $minZ = $this->minZ;
65 $maxX = $this->maxX;
66 $maxY = $this->maxY;
67 $maxZ = $this->maxZ;
68
69 if($x < 0){
70 $minX += $x;
71 }elseif($x > 0){
72 $maxX += $x;
73 }
74
75 if($y < 0){
76 $minY += $y;
77 }elseif($y > 0){
78 $maxY += $y;
79 }
80
81 if($z < 0){
82 $minZ += $z;
83 }elseif($z > 0){
84 $maxZ += $z;
85 }
86
87 return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
88 }
89
93 public function expandedCopy(float $x, float $y, float $z): AxisAlignedBB{
94 return new AxisAlignedBB(
95 $this->minX - $x,
96 $this->minY - $y,
97 $this->minZ - $z,
98 $this->maxX + $x,
99 $this->maxY + $y,
100 $this->maxZ + $z
101 );
102 }
103
107 public function offsetCopy(float $x, float $y, float $z) : AxisAlignedBB{
108 return new AxisAlignedBB(
109 $this->minX + $x,
110 $this->minY + $y,
111 $this->minZ + $z,
112 $this->maxX + $x,
113 $this->maxY + $y,
114 $this->maxZ + $z
115 );
116 }
117
121 public function offsetTowardsCopy(Facing $face, float $distance) : AxisAlignedBB{
122 [$offsetX, $offsetY, $offsetZ] = Facing::OFFSET[$face->value];
123
124 return $this->offsetCopy($offsetX * $distance, $offsetY * $distance, $offsetZ * $distance);
125 }
126
130 public function contractedCopy(float $x, float $y, float $z) : AxisAlignedBB{
131 return new AxisAlignedBB(
132 $this->minX + $x,
133 $this->minY + $y,
134 $this->minZ + $z,
135 $this->maxX - $x,
136 $this->maxY - $y,
137 $this->maxZ - $z
138 );
139 }
140
146 public function extendedCopy(Facing $face, float $distance) : AxisAlignedBB{
147 $minX = $this->minX;
148 $minY = $this->minY;
149 $minZ = $this->minZ;
150 $maxX = $this->maxX;
151 $maxY = $this->maxY;
152 $maxZ = $this->maxZ;
153
154 match($face){
155 Facing::DOWN => $minY -= $distance,
156 Facing::UP => $maxY += $distance,
157 Facing::NORTH => $minZ -= $distance,
158 Facing::SOUTH => $maxZ += $distance,
159 Facing::WEST => $minX -= $distance,
160 Facing::EAST => $maxX += $distance,
161 };
162
163 return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
164 }
165
172 public function trimmedCopy(Facing $face, float $distance) : AxisAlignedBB{
173 return $this->extendedCopy($face, -$distance);
174 }
175
181 public function stretchedCopy(Axis $axis, float $distance) : AxisAlignedBB{
182 $minX = $this->minX;
183 $minY = $this->minY;
184 $minZ = $this->minZ;
185 $maxX = $this->maxX;
186 $maxY = $this->maxY;
187 $maxZ = $this->maxZ;
188
189 if($axis === Axis::Y){
190 $minY -= $distance;
191 $maxY += $distance;
192 }elseif($axis === Axis::Z){
193 $minZ -= $distance;
194 $maxZ += $distance;
195 }elseif($axis === Axis::X){
196 $minX -= $distance;
197 $maxX += $distance;
198 }
199
200 return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
201 }
202
207 public function squashedCopy(Axis $axis, float $distance) : AxisAlignedBB{
208 return $this->stretchedCopy($axis, -$distance);
209 }
210
211 public function calculateXOffset(AxisAlignedBB $bb, float $x) : float{
212 if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
213 return $x;
214 }
215 if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
216 return $x;
217 }
218 if($x > 0 and $bb->maxX <= $this->minX){
219 $x1 = $this->minX - $bb->maxX;
220 if($x1 < $x){
221 $x = $x1;
222 }
223 }elseif($x < 0 and $bb->minX >= $this->maxX){
224 $x2 = $this->maxX - $bb->minX;
225 if($x2 > $x){
226 $x = $x2;
227 }
228 }
229
230 return $x;
231 }
232
233 public function calculateYOffset(AxisAlignedBB $bb, float $y) : float{
234 if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
235 return $y;
236 }
237 if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
238 return $y;
239 }
240 if($y > 0 and $bb->maxY <= $this->minY){
241 $y1 = $this->minY - $bb->maxY;
242 if($y1 < $y){
243 $y = $y1;
244 }
245 }elseif($y < 0 and $bb->minY >= $this->maxY){
246 $y2 = $this->maxY - $bb->minY;
247 if($y2 > $y){
248 $y = $y2;
249 }
250 }
251
252 return $y;
253 }
254
255 public function calculateZOffset(AxisAlignedBB $bb, float $z) : float{
256 if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
257 return $z;
258 }
259 if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
260 return $z;
261 }
262 if($z > 0 and $bb->maxZ <= $this->minZ){
263 $z1 = $this->minZ - $bb->maxZ;
264 if($z1 < $z){
265 $z = $z1;
266 }
267 }elseif($z < 0 and $bb->minZ >= $this->maxZ){
268 $z2 = $this->maxZ - $bb->minZ;
269 if($z2 > $z){
270 $z = $z2;
271 }
272 }
273
274 return $z;
275 }
276
280 public function intersectsWith(AxisAlignedBB $bb, float $epsilon = 0.00001) : bool{
281 if($bb->maxX - $this->minX > $epsilon and $this->maxX - $bb->minX > $epsilon){
282 if($bb->maxY - $this->minY > $epsilon and $this->maxY - $bb->minY > $epsilon){
283 return $bb->maxZ - $this->minZ > $epsilon and $this->maxZ - $bb->minZ > $epsilon;
284 }
285 }
286
287 return false;
288 }
289
293 public function isVectorInside(Vector3 $vector) : bool{
294 if($vector->x <= $this->minX or $vector->x >= $this->maxX){
295 return false;
296 }
297 if($vector->y <= $this->minY or $vector->y >= $this->maxY){
298 return false;
299 }
300
301 return $vector->z > $this->minZ and $vector->z < $this->maxZ;
302 }
303
307 public function getAverageEdgeLength() : float{
308 return ($this->maxX - $this->minX + $this->maxY - $this->minY + $this->maxZ - $this->minZ) / 3;
309 }
310
311 public function getXLength() : float{ return $this->maxX - $this->minX; }
312
313 public function getYLength() : float{ return $this->maxY - $this->minY; }
314
315 public function getZLength() : float{ return $this->maxZ - $this->minZ; }
316
317 public function isCube(float $epsilon = 0.000001) : bool{
318 [$xLen, $yLen, $zLen] = [$this->getXLength(), $this->getYLength(), $this->getZLength()];
319 return abs($xLen - $yLen) < $epsilon && abs($yLen - $zLen) < $epsilon;
320 }
321
325 public function getVolume() : float{
326 return ($this->maxX - $this->minX) * ($this->maxY - $this->minY) * ($this->maxZ - $this->minZ);
327 }
328
332 public function isVectorInYZ(Vector3 $vector) : bool{
333 return $vector->y >= $this->minY and $vector->y <= $this->maxY and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
334 }
335
339 public function isVectorInXZ(Vector3 $vector) : bool{
340 return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
341 }
342
346 public function isVectorInXY(Vector3 $vector) : bool{
347 return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->y >= $this->minY and $vector->y <= $this->maxY;
348 }
349
355 public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
356 $v1 = $pos1->getIntermediateWithXValue($pos2, $this->minX);
357 $v2 = $pos1->getIntermediateWithXValue($pos2, $this->maxX);
358 $v3 = $pos1->getIntermediateWithYValue($pos2, $this->minY);
359 $v4 = $pos1->getIntermediateWithYValue($pos2, $this->maxY);
360 $v5 = $pos1->getIntermediateWithZValue($pos2, $this->minZ);
361 $v6 = $pos1->getIntermediateWithZValue($pos2, $this->maxZ);
362
363 if($v1 !== null and !$this->isVectorInYZ($v1)){
364 $v1 = null;
365 }
366
367 if($v2 !== null and !$this->isVectorInYZ($v2)){
368 $v2 = null;
369 }
370
371 if($v3 !== null and !$this->isVectorInXZ($v3)){
372 $v3 = null;
373 }
374
375 if($v4 !== null and !$this->isVectorInXZ($v4)){
376 $v4 = null;
377 }
378
379 if($v5 !== null and !$this->isVectorInXY($v5)){
380 $v5 = null;
381 }
382
383 if($v6 !== null and !$this->isVectorInXY($v6)){
384 $v6 = null;
385 }
386
387 $distance = PHP_INT_MAX;
388 $vectorAndFace = null;
389
390 foreach([
391 [Facing::WEST, $v1],
392 [Facing::EAST, $v2],
393 [Facing::DOWN, $v3],
394 [Facing::UP, $v4],
395 [Facing::NORTH, $v5],
396 [Facing::SOUTH, $v6],
397 ] as [$f, $v]){
398 if($v !== null and ($d = $pos1->distanceSquared($v)) < $distance){
399 $distance = $d;
400 $vectorAndFace = [$v, $f];
401 }
402 }
403
404 if($vectorAndFace === null){
405 return null;
406 }
407 [$vector, $face] = $vectorAndFace;
408
409 return new RayTraceResult($this, $face, $vector);
410 }
411
412 public function __toString() : string{
413 return "AxisAlignedBB({$this->minX}, {$this->minY}, {$this->minZ}, {$this->maxX}, {$this->maxY}, {$this->maxZ})";
414 }
415
419 public static function one() : AxisAlignedBB{
420 return new AxisAlignedBB(0, 0, 0, 1, 1, 1);
421 }
422}
offsetTowardsCopy(Facing $face, float $distance)
intersectsWith(AxisAlignedBB $bb, float $epsilon=0.00001)
trimmedCopy(Facing $face, float $distance)
expandedCopy(float $x, float $y, float $z)
contractedCopy(float $x, float $y, float $z)
stretchedCopy(Axis $axis, float $distance)
addCoord(float $x, float $y, float $z)
squashedCopy(Axis $axis, float $distance)
offsetCopy(float $x, float $y, float $z)
calculateIntercept(Vector3 $pos1, Vector3 $pos2)
extendedCopy(Facing $face, float $distance)
getIntermediateWithZValue(Vector3 $v, float $z)
Definition Vector3.php:302
getIntermediateWithXValue(Vector3 $v, float $x)
Definition Vector3.php:264
getIntermediateWithYValue(Vector3 $v, float $y)
Definition Vector3.php:283