PocketMine-MP 5.15.1 git-fb9a74e8799c71ed8292cfa53abe7a4c9204629d
Vector3.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 function ceil;
28use function floor;
29use function iterator_to_array;
30use function max;
31use function min;
32use function round;
33use function sqrt;
34use const PHP_ROUND_HALF_UP;
35
36class Vector3{
37 public function __construct(
38 public float|int $x,
39 public float|int $y,
40 public float|int $z
41 ){}
42
43 public static function zero() : Vector3{
44 //TODO: make this reuse a single object, once Vector3 becomes immutable
45 return new self(0, 0, 0);
46 }
47
48 public function getX() : float|int{
49 return $this->x;
50 }
51
52 public function getY() : float|int{
53 return $this->y;
54 }
55
56 public function getZ() : float|int{
57 return $this->z;
58 }
59
60 public function getFloorX() : int{
61 return (int) floor($this->x);
62 }
63
64 public function getFloorY() : int{
65 return (int) floor($this->y);
66 }
67
68 public function getFloorZ() : int{
69 return (int) floor($this->z);
70 }
71
72 public function add(float|int $x, float|int $y, float|int $z) : Vector3{
73 return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
74 }
75
76 public function addVector(Vector3 $v) : Vector3{
77 return $this->add($v->x, $v->y, $v->z);
78 }
79
80 public function subtract(float|int $x, float|int $y, float|int $z) : Vector3{
81 return $this->add(-$x, -$y, -$z);
82 }
83
84 public function subtractVector(Vector3 $v) : Vector3{
85 return $this->add(-$v->x, -$v->y, -$v->z);
86 }
87
88 public function multiply(float $number) : Vector3{
89 return new Vector3($this->x * $number, $this->y * $number, $this->z * $number);
90 }
91
92 public function divide(float $number) : Vector3{
93 return new Vector3($this->x / $number, $this->y / $number, $this->z / $number);
94 }
95
96 public function ceil() : Vector3{
97 return new Vector3((int) ceil($this->x), (int) ceil($this->y), (int) ceil($this->z));
98 }
99
100 public function floor() : Vector3{
101 return new Vector3((int) floor($this->x), (int) floor($this->y), (int) floor($this->z));
102 }
103
107 public function round(int $precision = 0, int $mode = PHP_ROUND_HALF_UP) : Vector3{
108 return $precision > 0 ?
109 new Vector3(round($this->x, $precision, $mode), round($this->y, $precision, $mode), round($this->z, $precision, $mode)) :
110 new Vector3((int) round($this->x, $precision, $mode), (int) round($this->y, $precision, $mode), (int) round($this->z, $precision, $mode));
111 }
112
113 public function abs() : Vector3{
114 return new Vector3(abs($this->x), abs($this->y), abs($this->z));
115 }
116
120 public function getSide(int $side, int $step = 1){
121 [$offsetX, $offsetY, $offsetZ] = Facing::OFFSET[$side] ?? [0, 0, 0];
122
123 return $this->add($offsetX * $step, $offsetY * $step, $offsetZ * $step);
124 }
125
129 public function down(int $step = 1){
130 return $this->getSide(Facing::DOWN, $step);
131 }
132
136 public function up(int $step = 1){
137 return $this->getSide(Facing::UP, $step);
138 }
139
143 public function north(int $step = 1){
144 return $this->getSide(Facing::NORTH, $step);
145 }
146
150 public function south(int $step = 1){
151 return $this->getSide(Facing::SOUTH, $step);
152 }
153
157 public function west(int $step = 1){
158 return $this->getSide(Facing::WEST, $step);
159 }
160
164 public function east(int $step = 1){
165 return $this->getSide(Facing::EAST, $step);
166 }
167
176 public function sides(int $step = 1) : \Generator{
177 foreach(Facing::ALL as $facing){
178 yield $facing => $this->getSide($facing, $step);
179 }
180 }
181
187 public function sidesArray(bool $keys = false, int $step = 1) : array{
188 return iterator_to_array($this->sides($step), $keys);
189 }
190
199 public function sidesAroundAxis(int $axis, int $step = 1) : \Generator{
200 foreach(Facing::ALL as $facing){
201 if(Facing::axis($facing) !== $axis){
202 yield $facing => $this->getSide($facing, $step);
203 }
204 }
205 }
206
210 public function asVector3() : Vector3{
211 return new Vector3($this->x, $this->y, $this->z);
212 }
213
214 public function distance(Vector3 $pos) : float{
215 return sqrt($this->distanceSquared($pos));
216 }
217
218 public function distanceSquared(Vector3 $pos) : float{
219 return (($this->x - $pos->x) ** 2) + (($this->y - $pos->y) ** 2) + (($this->z - $pos->z) ** 2);
220 }
221
222 public function maxPlainDistance(Vector3|Vector2|float $x, float $z = 0) : float{
223 if($x instanceof Vector3){
224 return $this->maxPlainDistance($x->x, $x->z);
225 }elseif($x instanceof Vector2){
226 return $this->maxPlainDistance($x->x, $x->y);
227 }else{
228 return max(abs($this->x - $x), abs($this->z - $z));
229 }
230 }
231
232 public function length() : float{
233 return sqrt($this->lengthSquared());
234 }
235
236 public function lengthSquared() : float{
237 return $this->x * $this->x + $this->y * $this->y + $this->z * $this->z;
238 }
239
240 public function normalize() : Vector3{
241 $len = $this->lengthSquared();
242 if($len > 0){
243 return $this->divide(sqrt($len));
244 }
245
246 return new Vector3(0, 0, 0);
247 }
248
249 public function dot(Vector3 $v) : float{
250 return $this->x * $v->x + $this->y * $v->y + $this->z * $v->z;
251 }
252
253 public function cross(Vector3 $v) : Vector3{
254 return new Vector3(
255 $this->y * $v->z - $this->z * $v->y,
256 $this->z * $v->x - $this->x * $v->z,
257 $this->x * $v->y - $this->y * $v->x
258 );
259 }
260
261 public function equals(Vector3 $v) : bool{
262 return $this->x == $v->x and $this->y == $v->y and $this->z == $v->z;
263 }
264
269 public function getIntermediateWithXValue(Vector3 $v, float $x) : ?Vector3{
270 $xDiff = $v->x - $this->x;
271 if(($xDiff * $xDiff) < 0.0000001){
272 return null;
273 }
274
275 $f = ($x - $this->x) / $xDiff;
276
277 if($f < 0 or $f > 1){
278 return null;
279 }else{
280 return new Vector3($x, $this->y + ($v->y - $this->y) * $f, $this->z + ($v->z - $this->z) * $f);
281 }
282 }
283
288 public function getIntermediateWithYValue(Vector3 $v, float $y) : ?Vector3{
289 $yDiff = $v->y - $this->y;
290 if(($yDiff * $yDiff) < 0.0000001){
291 return null;
292 }
293
294 $f = ($y - $this->y) / $yDiff;
295
296 if($f < 0 or $f > 1){
297 return null;
298 }else{
299 return new Vector3($this->x + ($v->x - $this->x) * $f, $y, $this->z + ($v->z - $this->z) * $f);
300 }
301 }
302
307 public function getIntermediateWithZValue(Vector3 $v, float $z) : ?Vector3{
308 $zDiff = $v->z - $this->z;
309 if(($zDiff * $zDiff) < 0.0000001){
310 return null;
311 }
312
313 $f = ($z - $this->z) / $zDiff;
314
315 if($f < 0 or $f > 1){
316 return null;
317 }else{
318 return new Vector3($this->x + ($v->x - $this->x) * $f, $this->y + ($v->y - $this->y) * $f, $z);
319 }
320 }
321
322 public function __toString(){
323 return "Vector3(x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")";
324 }
325
331 public function withComponents(float|int|null $x, float|int|null $y, float|int|null $z) : Vector3{
332 if($x !== null || $y !== null || $z !== null){
333 return new self($x ?? $this->x, $y ?? $this->y, $z ?? $this->z);
334 }
335 return $this;
336 }
337
343 public static function maxComponents(Vector3 $vector, Vector3 ...$vectors) : Vector3{
344 $x = $vector->x;
345 $y = $vector->y;
346 $z = $vector->z;
347 foreach($vectors as $position){
348 $x = max($x, $position->x);
349 $y = max($y, $position->y);
350 $z = max($z, $position->z);
351 }
352 return new Vector3($x, $y, $z);
353 }
354
360 public static function minComponents(Vector3 $vector, Vector3 ...$vectors) : Vector3{
361 $x = $vector->x;
362 $y = $vector->y;
363 $z = $vector->z;
364 foreach($vectors as $position){
365 $x = min($x, $position->x);
366 $y = min($y, $position->y);
367 $z = min($z, $position->z);
368 }
369 return new Vector3($x, $y, $z);
370 }
371
372 public static function sum(Vector3 ...$vector3s) : Vector3{
373 $x = $y = $z = 0;
374 foreach($vector3s as $vector3){
375 $x += $vector3->x;
376 $y += $vector3->y;
377 $z += $vector3->z;
378 }
379 return new Vector3($x, $y, $z);
380 }
381}
getIntermediateWithZValue(Vector3 $v, float $z)
Definition: Vector3.php:307
sidesAroundAxis(int $axis, int $step=1)
Definition: Vector3.php:199
getIntermediateWithXValue(Vector3 $v, float $x)
Definition: Vector3.php:269
getIntermediateWithYValue(Vector3 $v, float $y)
Definition: Vector3.php:288
sidesArray(bool $keys=false, int $step=1)
Definition: Vector3.php:187
sides(int $step=1)
Definition: Vector3.php:176
round(int $precision=0, int $mode=PHP_ROUND_HALF_UP)
Definition: Vector3.php:107
withComponents(float|int|null $x, float|int|null $y, float|int|null $z)
Definition: Vector3.php:331
static maxComponents(Vector3 $vector, Vector3 ... $vectors)
Definition: Vector3.php:343
north(int $step=1)
Definition: Vector3.php:143
east(int $step=1)
Definition: Vector3.php:164
south(int $step=1)
Definition: Vector3.php:150
static minComponents(Vector3 $vector, Vector3 ... $vectors)
Definition: Vector3.php:360
west(int $step=1)
Definition: Vector3.php:157
getSide(int $side, int $step=1)
Definition: Vector3.php:120
down(int $step=1)
Definition: Vector3.php:129
equals(self $other)
Definition: EnumTrait.php:106