Moved \pocketmine\math to a separate library

This commit is contained in:
Dylan K. Taylor 2018-03-17 12:45:55 +00:00
parent 313b224bec
commit 7f6b8ad7c2
10 changed files with 42 additions and 1424 deletions

View File

@ -24,7 +24,8 @@
"pocketmine/raklib": "dev-master#31d6522de71a9c404aff5c23c49c6ea0526793fb",
"pocketmine/spl": "dev-master#ee32424c100fd11ae7f7b8df7604623fd475f0ec",
"pocketmine/binaryutils": "dev-master#03e6851f814aba96487ec64181a6ae948edd9f7a",
"pocketmine/nbt": "dev-master#e8fb4c11b291e96c2b44220a5d00f97c1692556e"
"pocketmine/nbt": "dev-master#e8fb4c11b291e96c2b44220a5d00f97c1692556e",
"pocketmine/math": "dev-master#e0fe8ab70bcacead007cf11dd5b74adc91d94388"
},
"autoload": {
"psr-4": {
@ -47,6 +48,10 @@
{
"type": "vcs",
"url": "https://github.com/pmmp/NBT"
},
{
"type": "vcs",
"url": "https://github.com/pmmp/Math"
}
]
}

38
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "3426771a9526fe9ecb4c66b2ec87a3dd",
"content-hash": "e04780cd000c97da7b356dfdf858bf47",
"packages": [
{
"name": "pocketmine/binaryutils",
@ -39,6 +39,39 @@
},
"time": "2018-03-17T11:57:06+00:00"
},
{
"name": "pocketmine/math",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "e0fe8ab70bcacead007cf11dd5b74adc91d94388"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/e0fe8ab70bcacead007cf11dd5b74adc91d94388",
"reference": "e0fe8ab70bcacead007cf11dd5b74adc91d94388",
"shasum": ""
},
"require": {
"php": ">=7.2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"pocketmine\\math\\": "src/"
}
},
"license": [
"LGPL-3.0"
],
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"source": "https://github.com/pmmp/Math/tree/master",
"issues": "https://github.com/pmmp/Math/issues"
},
"time": "2018-03-17T12:35:50+00:00"
},
{
"name": "pocketmine/nbt",
"version": "dev-master",
@ -158,7 +191,8 @@
"pocketmine/raklib": 20,
"pocketmine/spl": 20,
"pocketmine/binaryutils": 20,
"pocketmine/nbt": 20
"pocketmine/nbt": 20,
"pocketmine/math": 20
},
"prefer-stable": false,
"prefer-lowest": false,

View File

@ -1,432 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
class AxisAlignedBB{
/** @var float */
public $minX;
/** @var float */
public $minY;
/** @var float */
public $minZ;
/** @var float */
public $maxX;
/** @var float */
public $maxY;
/** @var float */
public $maxZ;
public function __construct(float $minX, float $minY, float $minZ, float $maxX, float $maxY, float $maxZ){
$this->minX = $minX;
$this->minY = $minY;
$this->minZ = $minZ;
$this->maxX = $maxX;
$this->maxY = $maxY;
$this->maxZ = $maxZ;
}
public function setBounds(float $minX, float $minY, float $minZ, float $maxX, float $maxY, float $maxZ){
$this->minX = $minX;
$this->minY = $minY;
$this->minZ = $minZ;
$this->maxX = $maxX;
$this->maxY = $maxY;
$this->maxZ = $maxZ;
return $this;
}
/**
* Returns a new AxisAlignedBB extended by the specified X, Y and Z.
* If each of X, Y and Z are positive, the relevant max bound will be increased. If negative, the relevant min
* bound will be decreased.
*
* @param float $x
* @param float $y
* @param float $z
*
* @return AxisAlignedBB
*/
public function addCoord(float $x, float $y, float $z) : AxisAlignedBB{
$minX = $this->minX;
$minY = $this->minY;
$minZ = $this->minZ;
$maxX = $this->maxX;
$maxY = $this->maxY;
$maxZ = $this->maxZ;
if($x < 0){
$minX += $x;
}elseif($x > 0){
$maxX += $x;
}
if($y < 0){
$minY += $y;
}elseif($y > 0){
$maxY += $y;
}
if($z < 0){
$minZ += $z;
}elseif($z > 0){
$maxZ += $z;
}
return new AxisAlignedBB($minX, $minY, $minZ, $maxX, $maxY, $maxZ);
}
/**
* Returns a new AxisAlignedBB with bounds outset by the specified X, Y and Z.
*
* @param float $x
* @param float $y
* @param float $z
*
* @return AxisAlignedBB
*/
public function grow(float $x, float $y, float $z) : AxisAlignedBB{
return new AxisAlignedBB($this->minX - $x, $this->minY - $y, $this->minZ - $z, $this->maxX + $x, $this->maxY + $y, $this->maxZ + $z);
}
/**
* Performs the same operation as grow() but operates on itself instead of returning a new object.
* @param float $x
* @param float $y
* @param float $z
*
* @return $this
*/
public function expand(float $x, float $y, float $z){
$this->minX -= $x;
$this->minY -= $y;
$this->minZ -= $z;
$this->maxX += $x;
$this->maxY += $y;
$this->maxZ += $z;
return $this;
}
/**
* Performs the same operation as getOffsetBoundingBox(), but operates on itself instead of returning a new object.
*
* @param float $x
* @param float $y
* @param float $z
*
* @return $this
*/
public function offset(float $x, float $y, float $z){
$this->minX += $x;
$this->minY += $y;
$this->minZ += $z;
$this->maxX += $x;
$this->maxY += $y;
$this->maxZ += $z;
return $this;
}
/**
* Returns a new AxisAlignedBB with bounds inset by the specified X, Y and Z.
*
* @param float $x
* @param float $y
* @param float $z
*
* @return AxisAlignedBB
*/
public function shrink(float $x, float $y, float $z) : AxisAlignedBB{
return new AxisAlignedBB($this->minX + $x, $this->minY + $y, $this->minZ + $z, $this->maxX - $x, $this->maxY - $y, $this->maxZ - $z);
}
/**
* Performs the same operation as shrink(), but operates on itself instead of returning a new object.
*
* @param float $x
* @param float $y
* @param float $z
*
* @return $this
*/
public function contract(float $x, float $y, float $z){
$this->minX += $x;
$this->minY += $y;
$this->minZ += $z;
$this->maxX -= $x;
$this->maxY -= $y;
$this->maxZ -= $z;
return $this;
}
/**
* Sets the bounding box's bounds from another AxisAlignedBB, and returns itself
*
* @param AxisAlignedBB $bb
* @return $this
*/
public function setBB(AxisAlignedBB $bb){
$this->minX = $bb->minX;
$this->minY = $bb->minY;
$this->minZ = $bb->minZ;
$this->maxX = $bb->maxX;
$this->maxY = $bb->maxY;
$this->maxZ = $bb->maxZ;
return $this;
}
/**
* Returns a new AxisAlignedBB shifted by the specified X, Y and Z
*
* @param float $x
* @param float $y
* @param float $z
*
* @return AxisAlignedBB
*/
public function getOffsetBoundingBox(float $x, float $y, float $z) : AxisAlignedBB{
return new AxisAlignedBB($this->minX + $x, $this->minY + $y, $this->minZ + $z, $this->maxX + $x, $this->maxY + $y, $this->maxZ + $z);
}
public function calculateXOffset(AxisAlignedBB $bb, float $x) : float{
if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
return $x;
}
if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
return $x;
}
if($x > 0 and $bb->maxX <= $this->minX){
$x1 = $this->minX - $bb->maxX;
if($x1 < $x){
$x = $x1;
}
}elseif($x < 0 and $bb->minX >= $this->maxX){
$x2 = $this->maxX - $bb->minX;
if($x2 > $x){
$x = $x2;
}
}
return $x;
}
public function calculateYOffset(AxisAlignedBB $bb, float $y) : float{
if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
return $y;
}
if($bb->maxZ <= $this->minZ or $bb->minZ >= $this->maxZ){
return $y;
}
if($y > 0 and $bb->maxY <= $this->minY){
$y1 = $this->minY - $bb->maxY;
if($y1 < $y){
$y = $y1;
}
}elseif($y < 0 and $bb->minY >= $this->maxY){
$y2 = $this->maxY - $bb->minY;
if($y2 > $y){
$y = $y2;
}
}
return $y;
}
public function calculateZOffset(AxisAlignedBB $bb, float $z) : float{
if($bb->maxX <= $this->minX or $bb->minX >= $this->maxX){
return $z;
}
if($bb->maxY <= $this->minY or $bb->minY >= $this->maxY){
return $z;
}
if($z > 0 and $bb->maxZ <= $this->minZ){
$z1 = $this->minZ - $bb->maxZ;
if($z1 < $z){
$z = $z1;
}
}elseif($z < 0 and $bb->minZ >= $this->maxZ){
$z2 = $this->maxZ - $bb->minZ;
if($z2 > $z){
$z = $z2;
}
}
return $z;
}
/**
* Returns whether any part of the specified AABB is inside (intersects with) this one.
*
* @param AxisAlignedBB $bb
* @param float $epsilon
*
* @return bool
*/
public function intersectsWith(AxisAlignedBB $bb, float $epsilon = 0.00001) : bool{
if($bb->maxX - $this->minX > $epsilon and $this->maxX - $bb->minX > $epsilon){
if($bb->maxY - $this->minY > $epsilon and $this->maxY - $bb->minY > $epsilon){
return $bb->maxZ - $this->minZ > $epsilon and $this->maxZ - $bb->minZ > $epsilon;
}
}
return false;
}
/**
* Returns whether the specified vector is within the bounds of this AABB on all axes.
*
* @param Vector3 $vector
* @return bool
*/
public function isVectorInside(Vector3 $vector) : bool{
if($vector->x <= $this->minX or $vector->x >= $this->maxX){
return false;
}
if($vector->y <= $this->minY or $vector->y >= $this->maxY){
return false;
}
return $vector->z > $this->minZ and $vector->z < $this->maxZ;
}
/**
* Returns the mean average of the AABB's X, Y and Z lengths.
* @return float
*/
public function getAverageEdgeLength() : float{
return ($this->maxX - $this->minX + $this->maxY - $this->minY + $this->maxZ - $this->minZ) / 3;
}
/**
* Returns whether the specified vector is within the Y and Z bounds of this AABB.
*
* @param Vector3 $vector
* @return bool
*/
public function isVectorInYZ(Vector3 $vector) : bool{
return $vector->y >= $this->minY and $vector->y <= $this->maxY and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
}
/**
* Returns whether the specified vector is within the X and Z bounds of this AABB.
*
* @param Vector3 $vector
* @return bool
*/
public function isVectorInXZ(Vector3 $vector) : bool{
return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->z >= $this->minZ and $vector->z <= $this->maxZ;
}
/**
* Returns whether the specified vector is within the X and Y bounds of this AABB.
*
* @param Vector3 $vector
* @return bool
*/
public function isVectorInXY(Vector3 $vector) : bool{
return $vector->x >= $this->minX and $vector->x <= $this->maxX and $vector->y >= $this->minY and $vector->y <= $this->maxY;
}
/**
* Performs a ray-trace and calculates the point on the AABB's edge nearest the start position that the ray-trace
* collided with. Returns a RayTraceResult with colliding vector closest to the start position.
* Returns null if no colliding point was found.
*
* @param Vector3 $pos1
* @param Vector3 $pos2
*
* @return RayTraceResult|null
*/
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
$v1 = $pos1->getIntermediateWithXValue($pos2, $this->minX);
$v2 = $pos1->getIntermediateWithXValue($pos2, $this->maxX);
$v3 = $pos1->getIntermediateWithYValue($pos2, $this->minY);
$v4 = $pos1->getIntermediateWithYValue($pos2, $this->maxY);
$v5 = $pos1->getIntermediateWithZValue($pos2, $this->minZ);
$v6 = $pos1->getIntermediateWithZValue($pos2, $this->maxZ);
if($v1 !== null and !$this->isVectorInYZ($v1)){
$v1 = null;
}
if($v2 !== null and !$this->isVectorInYZ($v2)){
$v2 = null;
}
if($v3 !== null and !$this->isVectorInXZ($v3)){
$v3 = null;
}
if($v4 !== null and !$this->isVectorInXZ($v4)){
$v4 = null;
}
if($v5 !== null and !$this->isVectorInXY($v5)){
$v5 = null;
}
if($v6 !== null and !$this->isVectorInXY($v6)){
$v6 = null;
}
$vector = null;
$distance = PHP_INT_MAX;
foreach([$v1, $v2, $v3, $v4, $v5, $v6] as $v){
if($v !== null and ($d = $pos1->distanceSquared($v)) < $distance){
$vector = $v;
$distance = $d;
}
}
if($vector === null){
return null;
}
$f = -1;
if($vector === $v1){
$f = Vector3::SIDE_WEST;
}elseif($vector === $v2){
$f = Vector3::SIDE_EAST;
}elseif($vector === $v3){
$f = Vector3::SIDE_DOWN;
}elseif($vector === $v4){
$f = Vector3::SIDE_UP;
}elseif($vector === $v5){
$f = Vector3::SIDE_NORTH;
}elseif($vector === $v6){
$f = Vector3::SIDE_SOUTH;
}
return new RayTraceResult($this, $f, $vector);
}
public function __toString(){
return "AxisAlignedBB({$this->minX}, {$this->minY}, {$this->minZ}, {$this->maxX}, {$this->maxY}, {$this->maxZ})";
}
}

View File

@ -1,67 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
/**
* Math related classes, like matrices, bounding boxes and vector
*/
namespace pocketmine\math;
abstract class Math{
public static function floorFloat($n) : int{
$i = (int) $n;
return $n >= $i ? $i : $i - 1;
}
public static function ceilFloat($n) : int{
$i = (int) ($n + 1);
return $n >= $i ? $i : $i - 1;
}
/**
* Solves a quadratic equation with the given coefficients and returns an array of up to two solutions.
*
* @param float $a
* @param float $b
* @param float $c
*
* @return float[]
*/
public static function solveQuadratic(float $a, float $b, float $c) : array{
$discriminant = $b ** 2 - 4 * $a * $c;
if($discriminant > 0){ //2 real roots
$sqrtDiscriminant = sqrt($discriminant);
return [
(-$b + $sqrtDiscriminant) / (2 * $a),
(-$b - $sqrtDiscriminant) / (2 * $a)
];
}elseif($discriminant == 0){ //1 real root
return [
-$b / (2 * $a)
];
}else{ //No real roots
return [];
}
}
}

View File

@ -1,202 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
class Matrix implements \ArrayAccess{
private $matrix = [];
private $rows = 0;
private $columns = 0;
public function offsetExists($offset){
return isset($this->matrix[(int) $offset]);
}
public function offsetGet($offset){
return $this->matrix[(int) $offset];
}
public function offsetSet($offset, $value){
$this->matrix[(int) $offset] = $value;
}
public function offsetUnset($offset){
unset($this->matrix[(int) $offset]);
}
public function __construct($rows, $columns, array $set = []){
$this->rows = max(1, (int) $rows);
$this->columns = max(1, (int) $columns);
$this->set($set);
}
public function set(array $m){
for($r = 0; $r < $this->rows; ++$r){
$this->matrix[$r] = [];
for($c = 0; $c < $this->columns; ++$c){
$this->matrix[$r][$c] = $m[$r][$c] ?? 0;
}
}
}
public function getRows(){
return $this->rows;
}
public function getColumns(){
return $this->columns;
}
public function setElement($row, $column, $value){
if($row > $this->rows or $row < 0 or $column > $this->columns or $column < 0){
return false;
}
$this->matrix[(int) $row][(int) $column] = $value;
return true;
}
public function getElement($row, $column){
if($row > $this->rows or $row < 0 or $column > $this->columns or $column < 0){
return false;
}
return $this->matrix[(int) $row][(int) $column];
}
public function isSquare(){
return $this->rows === $this->columns;
}
public function add(Matrix $matrix){
if($this->rows !== $matrix->getRows() or $this->columns !== $matrix->getColumns()){
return false;
}
$result = new Matrix($this->rows, $this->columns);
for($r = 0; $r < $this->rows; ++$r){
for($c = 0; $c < $this->columns; ++$c){
$result->setElement($r, $c, $this->matrix[$r][$c] + $matrix->getElement($r, $c));
}
}
return $result;
}
public function subtract(Matrix $matrix){
if($this->rows !== $matrix->getRows() or $this->columns !== $matrix->getColumns()){
return false;
}
$result = clone $this;
for($r = 0; $r < $this->rows; ++$r){
for($c = 0; $c < $this->columns; ++$c){
$result->setElement($r, $c, $this->matrix[$r][$c] - $matrix->getElement($r, $c));
}
}
return $result;
}
public function multiplyScalar($number){
$result = clone $this;
for($r = 0; $r < $this->rows; ++$r){
for($c = 0; $c < $this->columns; ++$c){
$result->setElement($r, $c, $this->matrix[$r][$c] * $number);
}
}
return $result;
}
public function divideScalar($number){
$result = clone $this;
for($r = 0; $r < $this->rows; ++$r){
for($c = 0; $c < $this->columns; ++$c){
$result->setElement($r, $c, $this->matrix[$r][$c] / $number);
}
}
return $result;
}
public function transpose(){
$result = new Matrix($this->columns, $this->rows);
for($r = 0; $r < $this->rows; ++$r){
for($c = 0; $c < $this->columns; ++$c){
$result->setElement($c, $r, $this->matrix[$r][$c]);
}
}
return $result;
}
//Naive Matrix product, O(n^3)
public function product(Matrix $matrix){
if($this->columns !== $matrix->getRows()){
return false;
}
$c = $matrix->getColumns();
$result = new Matrix($this->rows, $c);
for($i = 0; $i < $this->rows; ++$i){
for($j = 0; $j < $c; ++$j){
$sum = 0;
for($k = 0; $k < $this->columns; ++$k){
$sum += $this->matrix[$i][$k] * $matrix->getElement($k, $j);
}
$result->setElement($i, $j, $sum);
}
}
return $result;
}
//Computation of the determinant of 2x2 and 3x3 matrices
public function determinant(){
if($this->isSquare() !== true){
return false;
}
switch($this->rows){
case 1:
return 0;
case 2:
return $this->matrix[0][0] * $this->matrix[1][1] - $this->matrix[0][1] * $this->matrix[1][0];
case 3:
return $this->matrix[0][0] * $this->matrix[1][1] * $this->matrix[2][2] + $this->matrix[0][1] * $this->matrix[1][2] * $this->matrix[2][0] + $this->matrix[0][2] * $this->matrix[1][0] * $this->matrix[2][1] - $this->matrix[2][0] * $this->matrix[1][1] * $this->matrix[0][2] - $this->matrix[2][1] * $this->matrix[1][2] * $this->matrix[0][0] - $this->matrix[2][2] * $this->matrix[1][0] * $this->matrix[0][1];
}
return false;
}
public function __toString(){
$s = "";
for($r = 0; $r < $this->rows; ++$r){
$s .= implode(",", $this->matrix[$r]) . ";";
}
return "Matrix({$this->rows}x{$this->columns};" . substr($s, 0, -1) . ")";
}
}

View File

@ -1,75 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
/**
* Class representing a ray trace collision with an AxisAlignedBB
*/
class RayTraceResult{
/**
* @var AxisAlignedBB
*/
public $bb;
/**
* @var int
*/
public $hitFace;
/**
* @var Vector3
*/
public $hitVector;
/**
* @param AxisAlignedBB $bb
* @param int $hitFace one of the Vector3::SIDE_* constants
* @param Vector3 $hitVector
*/
public function __construct(AxisAlignedBB $bb, int $hitFace, Vector3 $hitVector){
$this->bb = $bb;
$this->hitFace = $hitFace;
$this->hitVector = $hitVector;
}
/**
* @return AxisAlignedBB
*/
public function getBoundingBox() : AxisAlignedBB{
return $this->bb;
}
/**
* @return int
*/
public function getHitFace() : int{
return $this->hitFace;
}
/**
* @return Vector3
*/
public function getHitVector() : Vector3{
return $this->hitVector;
}
}

View File

@ -1,132 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
class Vector2{
public $x;
public $y;
public function __construct($x = 0, $y = 0){
$this->x = $x;
$this->y = $y;
}
public function getX(){
return $this->x;
}
public function getY(){
return $this->y;
}
public function getFloorX(){
return (int) floor($this->x);
}
public function getFloorY(){
return (int) floor($this->y);
}
public function add($x, $y = 0){
if($x instanceof Vector2){
return $this->add($x->x, $x->y);
}else{
return new Vector2($this->x + $x, $this->y + $y);
}
}
public function subtract($x, $y = 0){
if($x instanceof Vector2){
return $this->add(-$x->x, -$x->y);
}else{
return $this->add(-$x, -$y);
}
}
public function ceil(){
return new Vector2((int) ceil($this->x), (int) ceil($this->y));
}
public function floor(){
return new Vector2((int) floor($this->x), (int) floor($this->y));
}
public function round(){
return new Vector2(round($this->x), round($this->y));
}
public function abs(){
return new Vector2(abs($this->x), abs($this->y));
}
public function multiply($number){
return new Vector2($this->x * $number, $this->y * $number);
}
public function divide($number){
return new Vector2($this->x / $number, $this->y / $number);
}
public function distance($x, $y = 0){
if($x instanceof Vector2){
return sqrt($this->distanceSquared($x->x, $x->y));
}else{
return sqrt($this->distanceSquared($x, $y));
}
}
public function distanceSquared($x, $y = 0){
if($x instanceof Vector2){
return $this->distanceSquared($x->x, $x->y);
}else{
return (($this->x - $x) ** 2) + (($this->y - $y) ** 2);
}
}
public function length(){
return sqrt($this->lengthSquared());
}
public function lengthSquared(){
return $this->x * $this->x + $this->y * $this->y;
}
public function normalize(){
$len = $this->lengthSquared();
if($len != 0){
return $this->divide(sqrt($len));
}
return new Vector2(0, 0);
}
public function dot(Vector2 $v){
return $this->x * $v->x + $this->y * $v->y;
}
public function __toString(){
return "Vector2(x=" . $this->x . ",y=" . $this->y . ")";
}
}

View File

@ -1,342 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
class Vector3{
public const SIDE_DOWN = 0;
public const SIDE_UP = 1;
public const SIDE_NORTH = 2;
public const SIDE_SOUTH = 3;
public const SIDE_WEST = 4;
public const SIDE_EAST = 5;
public $x;
public $y;
public $z;
public function __construct($x = 0, $y = 0, $z = 0){
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
public function getX(){
return $this->x;
}
public function getY(){
return $this->y;
}
public function getZ(){
return $this->z;
}
public function getFloorX(){
return (int) floor($this->x);
}
public function getFloorY(){
return (int) floor($this->y);
}
public function getFloorZ(){
return (int) floor($this->z);
}
public function getRight(){
return $this->x;
}
public function getUp(){
return $this->y;
}
public function getForward(){
return $this->z;
}
public function getSouth(){
return $this->x;
}
public function getWest(){
return $this->z;
}
/**
* @param Vector3|int $x
* @param int $y
* @param int $z
*
* @return Vector3
*/
public function add($x, $y = 0, $z = 0){
if($x instanceof Vector3){
return new Vector3($this->x + $x->x, $this->y + $x->y, $this->z + $x->z);
}else{
return new Vector3($this->x + $x, $this->y + $y, $this->z + $z);
}
}
/**
* @param Vector3|int $x
* @param int $y
* @param int $z
*
* @return Vector3
*/
public function subtract($x = 0, $y = 0, $z = 0){
if($x instanceof Vector3){
return $this->add(-$x->x, -$x->y, -$x->z);
}else{
return $this->add(-$x, -$y, -$z);
}
}
public function multiply($number){
return new Vector3($this->x * $number, $this->y * $number, $this->z * $number);
}
public function divide($number){
return new Vector3($this->x / $number, $this->y / $number, $this->z / $number);
}
public function ceil(){
return new Vector3((int) ceil($this->x), (int) ceil($this->y), (int) ceil($this->z));
}
public function floor(){
return new Vector3((int) floor($this->x), (int) floor($this->y), (int) floor($this->z));
}
public function round(int $precision = 0, int $mode = PHP_ROUND_HALF_UP){
return $precision > 0 ?
new Vector3(round($this->x, $precision, $mode), round($this->y, $precision, $mode), round($this->z, $precision, $mode)) :
new Vector3((int) round($this->x, $precision, $mode), (int) round($this->y, $precision, $mode), (int) round($this->z, $precision, $mode));
}
public function abs(){
return new Vector3(abs($this->x), abs($this->y), abs($this->z));
}
public function getSide($side, $step = 1){
switch((int) $side){
case Vector3::SIDE_DOWN:
return new Vector3($this->x, $this->y - $step, $this->z);
case Vector3::SIDE_UP:
return new Vector3($this->x, $this->y + $step, $this->z);
case Vector3::SIDE_NORTH:
return new Vector3($this->x, $this->y, $this->z - $step);
case Vector3::SIDE_SOUTH:
return new Vector3($this->x, $this->y, $this->z + $step);
case Vector3::SIDE_WEST:
return new Vector3($this->x - $step, $this->y, $this->z);
case Vector3::SIDE_EAST:
return new Vector3($this->x + $step, $this->y, $this->z);
default:
return $this;
}
}
/**
* Return a Vector3 instance
*
* @return Vector3
*/
public function asVector3() : Vector3{
return new Vector3($this->x, $this->y, $this->z);
}
/**
* Returns the Vector3 side number opposite the specified one
*
* @param int $side 0-5 one of the Vector3::SIDE_* constants
* @return int
*
* @throws \InvalidArgumentException if an invalid side is supplied
*/
public static function getOppositeSide(int $side) : int{
if($side >= 0 and $side <= 5){
return $side ^ 0x01;
}
throw new \InvalidArgumentException("Invalid side $side given to getOppositeSide");
}
public function distance(Vector3 $pos){
return sqrt($this->distanceSquared($pos));
}
public function distanceSquared(Vector3 $pos){
return (($this->x - $pos->x) ** 2) + (($this->y - $pos->y) ** 2) + (($this->z - $pos->z) ** 2);
}
public function maxPlainDistance($x = 0, $z = 0){
if($x instanceof Vector3){
return $this->maxPlainDistance($x->x, $x->z);
}elseif($x instanceof Vector2){
return $this->maxPlainDistance($x->x, $x->y);
}else{
return max(abs($this->x - $x), abs($this->z - $z));
}
}
public function length(){
return sqrt($this->lengthSquared());
}
public function lengthSquared(){
return $this->x * $this->x + $this->y * $this->y + $this->z * $this->z;
}
/**
* @return Vector3
*/
public function normalize(){
$len = $this->lengthSquared();
if($len > 0){
return $this->divide(sqrt($len));
}
return new Vector3(0, 0, 0);
}
public function dot(Vector3 $v){
return $this->x * $v->x + $this->y * $v->y + $this->z * $v->z;
}
public function cross(Vector3 $v){
return new Vector3(
$this->y * $v->z - $this->z * $v->y,
$this->z * $v->x - $this->x * $v->z,
$this->x * $v->y - $this->y * $v->x
);
}
public function equals(Vector3 $v) : bool{
return $this->x == $v->x and $this->y == $v->y and $this->z == $v->z;
}
/**
* Returns a new vector with x value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*
* @param Vector3 $v
* @param float $x
*
* @return Vector3|null
*/
public function getIntermediateWithXValue(Vector3 $v, $x){
$xDiff = $v->x - $this->x;
$yDiff = $v->y - $this->y;
$zDiff = $v->z - $this->z;
if(($xDiff * $xDiff) < 0.0000001){
return null;
}
$f = ($x - $this->x) / $xDiff;
if($f < 0 or $f > 1){
return null;
}else{
return new Vector3($x, $this->y + $yDiff * $f, $this->z + $zDiff * $f);
}
}
/**
* Returns a new vector with y value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*
* @param Vector3 $v
* @param float $y
*
* @return Vector3|null
*/
public function getIntermediateWithYValue(Vector3 $v, $y){
$xDiff = $v->x - $this->x;
$yDiff = $v->y - $this->y;
$zDiff = $v->z - $this->z;
if(($yDiff * $yDiff) < 0.0000001){
return null;
}
$f = ($y - $this->y) / $yDiff;
if($f < 0 or $f > 1){
return null;
}else{
return new Vector3($this->x + $xDiff * $f, $y, $this->z + $zDiff * $f);
}
}
/**
* Returns a new vector with z value equal to the second parameter, along the line between this vector and the
* passed in vector, or null if not possible.
*
* @param Vector3 $v
* @param float $z
*
* @return Vector3|null
*/
public function getIntermediateWithZValue(Vector3 $v, $z){
$xDiff = $v->x - $this->x;
$yDiff = $v->y - $this->y;
$zDiff = $v->z - $this->z;
if(($zDiff * $zDiff) < 0.0000001){
return null;
}
$f = ($z - $this->z) / $zDiff;
if($f < 0 or $f > 1){
return null;
}else{
return new Vector3($this->x + $xDiff * $f, $this->y + $yDiff * $f, $z);
}
}
/**
* @param $x
* @param $y
* @param $z
*
* @return $this
*/
public function setComponents($x, $y, $z){
$this->x = $x;
$this->y = $y;
$this->z = $z;
return $this;
}
public function __toString(){
return "Vector3(x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")";
}
}

View File

@ -1,33 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
abstract class VectorMath{
public static function getDirection2D($azimuth){
return new Vector2(cos($azimuth), sin($azimuth));
}
}

View File

@ -1,138 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\math;
abstract class VoxelRayTrace{
/**
* Performs a ray trace from the start position in the given direction, for a distance of $maxDistance. This
* returns a Generator which yields Vector3s containing the coordinates of voxels it passes through.
*
* @param Vector3 $start
* @param Vector3 $directionVector
* @param float $maxDistance
*
* @return \Generator|Vector3[]
*/
public static function inDirection(Vector3 $start, Vector3 $directionVector, float $maxDistance) : \Generator{
return self::betweenPoints($start, $start->add($directionVector->multiply($maxDistance)));
}
/**
* Performs a ray trace between the start and end coordinates. This returns a Generator which yields Vector3s
* containing the coordinates of voxels it passes through.
*
* This is an implementation of the algorithm described in the link below.
* @link http://www.cse.yorku.ca/~amana/research/grid.pdf
*
* @param Vector3 $start
* @param Vector3 $end
*
* @return \Generator|Vector3[]
*/
public static function betweenPoints(Vector3 $start, Vector3 $end) : \Generator{
$currentBlock = $start->floor();
$directionVector = $end->subtract($start)->normalize();
if($directionVector->lengthSquared() <= 0){
throw new \InvalidArgumentException("Start and end points are the same, giving a zero direction vector");
}
$radius = $start->distance($end);
$stepX = $directionVector->x <=> 0;
$stepY = $directionVector->y <=> 0;
$stepZ = $directionVector->z <=> 0;
//Initialize the step accumulation variables depending how far into the current block the start position is. If
//the start position is on the corner of the block, these will be zero.
$tMaxX = self::rayTraceDistanceToBoundary($start->x, $directionVector->x);
$tMaxY = self::rayTraceDistanceToBoundary($start->y, $directionVector->y);
$tMaxZ = self::rayTraceDistanceToBoundary($start->z, $directionVector->z);
//The change in t on each axis when taking a step on that axis (always positive).
$tDeltaX = $directionVector->x == 0 ? 0 : $stepX / $directionVector->x;
$tDeltaY = $directionVector->y == 0 ? 0 : $stepY / $directionVector->y;
$tDeltaZ = $directionVector->z == 0 ? 0 : $stepZ / $directionVector->z;
while(true){
yield $currentBlock;
// tMaxX stores the t-value at which we cross a cube boundary along the
// X axis, and similarly for Y and Z. Therefore, choosing the least tMax
// chooses the closest cube boundary.
if($tMaxX < $tMaxY and $tMaxX < $tMaxZ){
if($tMaxX > $radius){
break;
}
$currentBlock->x += $stepX;
$tMaxX += $tDeltaX;
}elseif($tMaxY < $tMaxZ){
if($tMaxY > $radius){
break;
}
$currentBlock->y += $stepY;
$tMaxY += $tDeltaY;
}else{
if($tMaxZ > $radius){
break;
}
$currentBlock->z += $stepZ;
$tMaxZ += $tDeltaZ;
}
}
}
/**
* Returns the distance that must be travelled on an axis from the start point with the direction vector component to
* cross a block boundary.
*
* For example, given an X coordinate inside a block and the X component of a direction vector, will return the distance
* travelled by that direction component to reach a block with a different X coordinate.
*
* Find the smallest positive t such that s+t*ds is an integer.
*
* @param float $s Starting coordinate
* @param float $ds Direction vector component of the relevant axis
*
* @return float Distance along the ray trace that must be travelled to cross a boundary.
*/
private static function rayTraceDistanceToBoundary(float $s, float $ds) : float{
if($ds == 0){
return INF;
}
if($ds < 0){
$s = -$s;
$ds = -$ds;
if(floor($s) == $s){ //exactly at coordinate, will leave the coordinate immediately by moving negatively
return 0;
}
}
// problem is now s+t*ds = 1
return (1 - ($s - floor($s))) / $ds;
}
}