diff --git a/src/Axis.php b/src/Axis.php index 68f3198..f656929 100644 --- a/src/Axis.php +++ b/src/Axis.php @@ -23,24 +23,8 @@ namespace pocketmine\math; -final class Axis{ - private function __construct(){ - //NOOP - } - - public const Y = 0; - public const Z = 1; - public const X = 2; - - /** - * Returns a human-readable string representation of the given axis. - */ - public static function toString(int $axis) : string{ - return match($axis){ - Axis::Y => "y", - Axis::Z => "z", - Axis::X => "x", - default => throw new \InvalidArgumentException("Invalid axis $axis") - }; - } +enum Axis{ + case Y; + case Z; + case X; } diff --git a/src/AxisAlignedBB.php b/src/AxisAlignedBB.php index cf4a3e2..c9c69e6 100644 --- a/src/AxisAlignedBB.php +++ b/src/AxisAlignedBB.php @@ -136,12 +136,10 @@ public function offsetCopy(float $x, float $y, float $z) : AxisAlignedBB{ /** * Offsets this AxisAlignedBB in the given direction by the specified distance. * - * @param int $face one of the Facing::* constants - * * @return $this */ - public function offsetTowards(int $face, float $distance) : AxisAlignedBB{ - [$offsetX, $offsetY, $offsetZ] = Facing::OFFSET[$face] ?? throw new \InvalidArgumentException("Invalid Facing $face"); + public function offsetTowards(Facing $face, float $distance) : AxisAlignedBB{ + [$offsetX, $offsetY, $offsetZ] = $face->offset(); return $this->offset($offsetX * $distance, $offsetY * $distance, $offsetZ * $distance); } @@ -149,7 +147,7 @@ public function offsetTowards(int $face, float $distance) : AxisAlignedBB{ /** * Returns an offset clone of this AxisAlignedBB. */ - public function offsetTowardsCopy(int $face, float $distance) : AxisAlignedBB{ + public function offsetTowardsCopy(Facing $face, float $distance) : AxisAlignedBB{ return (clone $this)->offsetTowards($face, $distance); } @@ -184,7 +182,7 @@ public function contractedCopy(float $x, float $y, float $z) : AxisAlignedBB{ * @return $this * @throws \InvalidArgumentException */ - public function extend(int $face, float $distance) : AxisAlignedBB{ + public function extend(Facing $face, float $distance) : AxisAlignedBB{ match($face){ Facing::DOWN => $this->minY -= $distance, Facing::UP => $this->maxY += $distance, @@ -192,7 +190,6 @@ public function extend(int $face, float $distance) : AxisAlignedBB{ Facing::SOUTH => $this->maxZ += $distance, Facing::WEST => $this->minX -= $distance, Facing::EAST => $this->maxX += $distance, - default => throw new \InvalidArgumentException("Invalid face $face"), }; return $this; @@ -204,7 +201,7 @@ public function extend(int $face, float $distance) : AxisAlignedBB{ * * @throws \InvalidArgumentException */ - public function extendedCopy(int $face, float $distance) : AxisAlignedBB{ + public function extendedCopy(Facing $face, float $distance) : AxisAlignedBB{ return (clone $this)->extend($face, $distance); } @@ -217,7 +214,7 @@ public function extendedCopy(int $face, float $distance) : AxisAlignedBB{ * @return $this * @throws \InvalidArgumentException */ - public function trim(int $face, float $distance) : AxisAlignedBB{ + public function trim(Facing $face, float $distance) : AxisAlignedBB{ return $this->extend($face, -$distance); } @@ -227,20 +224,18 @@ public function trim(int $face, float $distance) : AxisAlignedBB{ * * @throws \InvalidArgumentException */ - public function trimmedCopy(int $face, float $distance) : AxisAlignedBB{ + public function trimmedCopy(Facing $face, float $distance) : AxisAlignedBB{ return $this->extendedCopy($face, -$distance); } /** * Increases the dimension of the AABB along the given axis. * - * @param int $axis one of the Axis::* constants * @param float $distance Negative values reduce width, positive values increase width. * * @return $this - * @throws \InvalidArgumentException */ - public function stretch(int $axis, float $distance) : AxisAlignedBB{ + public function stretch(Axis $axis, float $distance) : AxisAlignedBB{ if($axis === Axis::Y){ $this->minY -= $distance; $this->maxY += $distance; @@ -250,19 +245,16 @@ public function stretch(int $axis, float $distance) : AxisAlignedBB{ }elseif($axis === Axis::X){ $this->minX -= $distance; $this->maxX += $distance; - }else{ - throw new \InvalidArgumentException("Invalid axis $axis"); } + return $this; } /** * Returns a stretched copy of this bounding box. * @see AxisAlignedBB::stretch() - * - * @throws \InvalidArgumentException */ - public function stretchedCopy(int $axis, float $distance) : AxisAlignedBB{ + public function stretchedCopy(Axis $axis, float $distance) : AxisAlignedBB{ return (clone $this)->stretch($axis, $distance); } @@ -271,19 +263,16 @@ public function stretchedCopy(int $axis, float $distance) : AxisAlignedBB{ * @see AxisAlignedBB::stretch() * * @return $this - * @throws \InvalidArgumentException */ - public function squash(int $axis, float $distance) : AxisAlignedBB{ + public function squash(Axis $axis, float $distance) : AxisAlignedBB{ return $this->stretch($axis, -$distance); } /** * Returns a squashed copy of this bounding box. * @see AxisAlignedBB::squash() - * - * @throws \InvalidArgumentException */ - public function squashedCopy(int $axis, float $distance) : AxisAlignedBB{ + public function squashedCopy(Axis $axis, float $distance) : AxisAlignedBB{ return $this->stretchedCopy($axis, -$distance); } @@ -465,20 +454,23 @@ public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResu $vector = null; $distance = PHP_INT_MAX; - $face = -1; + /** @var Facing $face */ + $face = null; foreach([ - Facing::WEST => $v1, - Facing::EAST => $v2, - Facing::DOWN => $v3, - Facing::UP => $v4, - Facing::NORTH => $v5, - Facing::SOUTH => $v6 - ] as $f => $v){ + [Facing::WEST, $v1], + [Facing::EAST, $v2], + [Facing::DOWN, $v3], + [Facing::UP, $v4], + [Facing::NORTH, $v5], + [Facing::SOUTH, $v6] + ] as $value){ + $v = $value[1]; if($v !== null and ($d = $pos1->distanceSquared($v)) < $distance){ $vector = $v; $distance = $d; - $face = $f; + /** @var Facing $face */ + $face = $value[0]; } } diff --git a/src/Facing.php b/src/Facing.php index 134a29b..3b08952 100644 --- a/src/Facing.php +++ b/src/Facing.php @@ -23,31 +23,13 @@ namespace pocketmine\math; -use function in_array; - -final class Facing{ - private function __construct(){ - //NOOP - } - - public const FLAG_AXIS_POSITIVE = 1; - - /* most significant 2 bits = axis, least significant bit = is positive direction */ - public const DOWN = Axis::Y << 1; - public const UP = (Axis::Y << 1) | self::FLAG_AXIS_POSITIVE; - public const NORTH = Axis::Z << 1; - public const SOUTH = (Axis::Z << 1) | self::FLAG_AXIS_POSITIVE; - public const WEST = Axis::X << 1; - public const EAST = (Axis::X << 1) | self::FLAG_AXIS_POSITIVE; - - public const ALL = [ - self::DOWN, - self::UP, - self::NORTH, - self::SOUTH, - self::WEST, - self::EAST - ]; +enum Facing{ + case DOWN; + case UP; + case NORTH; + case SOUTH; + case WEST; + case EAST; public const HORIZONTAL = [ self::NORTH, @@ -56,120 +38,92 @@ private function __construct(){ self::EAST ]; - public const OFFSET = [ - self::DOWN => [ 0, -1, 0], - self::UP => [ 0, +1, 0], - self::NORTH => [ 0, 0, -1], - self::SOUTH => [ 0, 0, +1], - self::WEST => [-1, 0, 0], - self::EAST => [+1, 0, 0] - ]; - - private const CLOCKWISE = [ - Axis::Y => [ - self::NORTH => self::EAST, - self::EAST => self::SOUTH, - self::SOUTH => self::WEST, - self::WEST => self::NORTH - ], - Axis::Z => [ - self::UP => self::EAST, - self::EAST => self::DOWN, - self::DOWN => self::WEST, - self::WEST => self::UP - ], - Axis::X => [ - self::UP => self::NORTH, - self::NORTH => self::DOWN, - self::DOWN => self::SOUTH, - self::SOUTH => self::UP - ] - ]; - /** * Returns the axis of the given direction. */ - public static function axis(int $direction) : int{ - return $direction >> 1; //shift off positive/negative bit + public static function axis(Facing $direction) : Axis{ + return match ($direction) { + self::DOWN, self::UP => Axis::Y, + self::NORTH, self::SOUTH => Axis::Z, + self::WEST, self::EAST => Axis::X, + }; + } + + /** + * @return non-empty-array + */ + public function offset() : array{ + return match ($this) { + self::DOWN => [ 0, -1, 0], + self::UP => [ 0, +1, 0], + self::NORTH => [ 0, 0, -1], + self::SOUTH => [ 0, 0, +1], + self::WEST => [-1, 0, 0], + self::EAST => [+1, 0, 0] + }; } /** * Returns whether the direction is facing the positive of its axis. */ - public static function isPositive(int $direction) : bool{ - return ($direction & self::FLAG_AXIS_POSITIVE) === self::FLAG_AXIS_POSITIVE; + public static function isPositive(Facing $direction) : bool{ + return $direction === self::UP || $direction === self::SOUTH || $direction === self::EAST; } /** * Returns the opposite Facing of the specified one. - * - * @param int $direction 0-5 one of the Facing::* constants */ - public static function opposite(int $direction) : int{ - return $direction ^ self::FLAG_AXIS_POSITIVE; + public static function opposite(Facing $direction) : Facing{ + return match ($direction) { + self::DOWN => self::UP, + self::UP => self::DOWN, + self::NORTH => self::SOUTH, + self::SOUTH => self::NORTH, + self::WEST => self::EAST, + self::EAST => self::WEST, + }; } /** * Rotates the given direction around the axis. - * - * @throws \InvalidArgumentException if not possible to rotate $direction around $axis */ - public static function rotate(int $direction, int $axis, bool $clockwise) : int{ - if(!isset(self::CLOCKWISE[$axis])){ - throw new \InvalidArgumentException("Invalid axis $axis"); - } - if(!isset(self::CLOCKWISE[$axis][$direction])){ - throw new \InvalidArgumentException("Cannot rotate facing \"" . self::toString($direction) . "\" around axis \"" . Axis::toString($axis) . "\""); - } + public static function rotate(Facing $direction, Axis $axis, bool $clockwise) : Facing{ + $rotated = match ($axis) { + Axis::Y => match ($direction) { + self::NORTH => self::EAST, + self::EAST => self::SOUTH, + self::SOUTH => self::WEST, + self::WEST => self::NORTH, + default => throw new \InvalidArgumentException("Face " . strtolower($direction->name) . " not match with Axis " . strtolower($axis->name)) + }, + Axis::Z => match ($direction) { + self::UP => self::EAST, + self::EAST => self::DOWN, + self::DOWN => self::WEST, + self::WEST => self::UP, + default => throw new \InvalidArgumentException("Face " . strtolower($direction->name) . " not match with Axis " . strtolower($axis->name)) + }, + Axis::X => match ($direction) { + self::UP => self::NORTH, + self::NORTH => self::DOWN, + self::DOWN => self::SOUTH, + self::SOUTH => self::UP, + default => throw new \InvalidArgumentException("Face " . strtolower($direction->name) . " not match with Axis " . strtolower($axis->name)) + } + }; - $rotated = self::CLOCKWISE[$axis][$direction]; return $clockwise ? $rotated : self::opposite($rotated); } - /** - * @throws \InvalidArgumentException - */ - public static function rotateY(int $direction, bool $clockwise) : int{ + public static function rotateY(Facing $direction, bool $clockwise) : Facing{ return self::rotate($direction, Axis::Y, $clockwise); } - /** - * @throws \InvalidArgumentException - */ - public static function rotateZ(int $direction, bool $clockwise) : int{ + public static function rotateZ(Facing $direction, bool $clockwise) : Facing{ return self::rotate($direction, Axis::Z, $clockwise); } - /** - * @throws \InvalidArgumentException - */ - public static function rotateX(int $direction, bool $clockwise) : int{ + public static function rotateX(Facing $direction, bool $clockwise) : Facing{ return self::rotate($direction, Axis::X, $clockwise); } - - /** - * Validates the given integer as a Facing direction. - * - * @throws \InvalidArgumentException if the argument is not a valid Facing constant - */ - public static function validate(int $facing) : void{ - if(!in_array($facing, self::ALL, true)){ - throw new \InvalidArgumentException("Invalid direction $facing"); - } - } - - /** - * Returns a human-readable string representation of the given Facing direction. - */ - public static function toString(int $facing) : string{ - return match($facing){ - self::DOWN => "down", - self::UP => "up", - self::NORTH => "north", - self::SOUTH => "south", - self::WEST => "west", - self::EAST => "east", - default => throw new \InvalidArgumentException("Invalid facing $facing") - }; - } -} +} \ No newline at end of file diff --git a/src/RayTraceResult.php b/src/RayTraceResult.php index 4d0928a..156c7b1 100644 --- a/src/RayTraceResult.php +++ b/src/RayTraceResult.php @@ -28,12 +28,9 @@ */ class RayTraceResult{ - /** - * @param int $hitFace one of the Facing::* constants - */ public function __construct( public AxisAlignedBB $bb, - public int $hitFace, + public Facing $hitFace, public Vector3 $hitVector ){} @@ -41,7 +38,7 @@ public function getBoundingBox() : AxisAlignedBB{ return $this->bb; } - public function getHitFace() : int{ + public function getHitFace() : Facing{ return $this->hitFace; } diff --git a/src/Vector3.php b/src/Vector3.php index ca8701d..cc1760f 100644 --- a/src/Vector3.php +++ b/src/Vector3.php @@ -117,8 +117,8 @@ public function abs() : Vector3{ /** * @return Vector3 */ - public function getSide(int $side, int $step = 1){ - [$offsetX, $offsetY, $offsetZ] = Facing::OFFSET[$side] ?? [0, 0, 0]; + public function getSide(Facing $side, int $step = 1){ + [$offsetX, $offsetY, $offsetZ] = $side->offset(); return $this->add($offsetX * $step, $offsetY * $step, $offsetZ * $step); } @@ -170,19 +170,19 @@ public function east(int $step = 1){ * * @param int $step Distance in each direction to shift the vector * - * @return \Generator|Vector3[] - * @phpstan-return \Generator + * @return \Generator|mixed[] [Facing $facing, Vector3 $vector] + * @phpstan-return \Generator */ public function sides(int $step = 1) : \Generator{ - foreach(Facing::ALL as $facing){ - yield $facing => $this->getSide($facing, $step); + foreach(Facing::cases() as $facing){ + yield [$facing, $this->getSide($facing, $step)]; } } /** * Same as sides() but returns a pre-populated array instead of Generator. * - * @return Vector3[] + * @return array */ public function sidesArray(bool $keys = false, int $step = 1) : array{ return iterator_to_array($this->sides($step), $keys); @@ -191,15 +191,13 @@ public function sidesArray(bool $keys = false, int $step = 1) : array{ /** * Yields vectors stepped out from this one in directions except those on the given axis. * - * @param int $axis Facing directions on this axis will be excluded - * - * @return \Generator|Vector3[] - * @phpstan-return \Generator + * @return \Generator|mixed[] [Facing $facing, Vector3 $vector] + * @phpstan-return \Generator */ - public function sidesAroundAxis(int $axis, int $step = 1) : \Generator{ - foreach(Facing::ALL as $facing){ + public function sidesAroundAxis(Axis $axis, int $step = 1) : \Generator{ + foreach(Facing::cases() as $facing){ if(Facing::axis($facing) !== $axis){ - yield $facing => $this->getSide($facing, $step); + yield [$facing, $this->getSide($facing, $step)]; } } } diff --git a/tests/phpunit/FacingTest.php b/tests/phpunit/FacingTest.php index 51e3df0..81b3755 100644 --- a/tests/phpunit/FacingTest.php +++ b/tests/phpunit/FacingTest.php @@ -35,8 +35,8 @@ public static function axisProvider() : \Generator{ yield [Facing::EAST, Axis::X]; } - #[DataProvider("axisProvider")] - public function testAxis(int $direction, int $axis) : void{ + #[DataProvider("axisProvider")] + public function testAxis(Facing $direction, Axis $axis) : void{ self::assertEquals($axis, Facing::axis($direction)); } @@ -47,7 +47,7 @@ public static function oppositeProvider() : \Generator{ } #[DataProvider("oppositeProvider")] - public function testOpposite(int $dir1, int $dir2) : void{ + public function testOpposite(Facing $dir1, Facing $dir2) : void{ self::assertEquals($dir2, Facing::opposite($dir1)); self::assertEquals($dir1, Facing::opposite($dir2)); } @@ -62,7 +62,7 @@ public static function positiveProvider() : \Generator{ } #[DataProvider("positiveProvider")] - public function testIsPositive(int $facing, bool $positive) : void{ + public function testIsPositive(Facing $facing, bool $positive) : void{ self::assertEquals($positive, Facing::isPositive($facing)); } @@ -101,7 +101,7 @@ public static function rotateProvider() : \Generator{ } #[DataProvider("rotateProvider")] - public function testRotate(int $direction, int $axis, bool $clockwise, int $expected) : void{ + public function testRotate(Facing $direction, Axis $axis, bool $clockwise, Facing $expected) : void{ self::assertEquals($expected, Facing::rotate($direction, $axis, $clockwise)); } }