mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-10 17:28:40 +00:00
211 lines
4.3 KiB
PHP
Executable File
211 lines
4.3 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Jingga
|
|
*
|
|
* PHP Version 8.2
|
|
*
|
|
* @package phpOMS\Algorithm\PathFinding
|
|
* @copyright Dennis Eichhorn
|
|
* @license OMS License 2.0
|
|
* @version 1.0.0
|
|
* @link https://jingga.app
|
|
*
|
|
* Extended based on:
|
|
* MIT License
|
|
* (c) 2011-2012 Xueqiao Xu <xueqiaoxu@gmail.com>
|
|
* (c) PathFinding.js
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace phpOMS\Algorithm\PathFinding;
|
|
|
|
/**
|
|
* Path in grids.
|
|
*
|
|
* @package phpOMS\Algorithm\PathFinding
|
|
* @license OMS License 2.0
|
|
* @link https://jingga.app
|
|
* @since 1.0.0
|
|
*/
|
|
class Path
|
|
{
|
|
/**
|
|
* Nodes in the path
|
|
*
|
|
* @var Node[]
|
|
* @since 1.0.0
|
|
*/
|
|
public array $nodes = [];
|
|
|
|
/**
|
|
* Grid this path belongs to
|
|
*
|
|
* @var Grid
|
|
* @since 1.0.0
|
|
*/
|
|
private Grid $grid;
|
|
|
|
/**
|
|
* Nodes in the path
|
|
*
|
|
* @var Node[]
|
|
* @since 1.0.0
|
|
*/
|
|
private array $expandedNodes = [];
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param Grid $grid Grid this path belongs to
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function __construct(Grid $grid)
|
|
{
|
|
$this->grid = $grid;
|
|
}
|
|
|
|
/**
|
|
* Add node to the path
|
|
*
|
|
* @param Node $node Node
|
|
*
|
|
* @return void
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function addNode(Node $node) : void
|
|
{
|
|
$this->nodes[] = $node;
|
|
}
|
|
|
|
/**
|
|
* Get the path length (euclidean)
|
|
*
|
|
* @return float
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function getLength() : float
|
|
{
|
|
$n = \count($this->nodes);
|
|
|
|
$dist = 0.0;
|
|
|
|
for ($i = 1; $i < $n; ++$i) {
|
|
$dx = $this->nodes[$i - 1]->getX() - $this->nodes[$i]->getX();
|
|
$dy = $this->nodes[$i - 1]->getY() - $this->nodes[$i]->getY();
|
|
|
|
$dist += \sqrt($dx * $dx + $dy * $dy);
|
|
}
|
|
|
|
return $dist;
|
|
}
|
|
|
|
/**
|
|
* Get the incomplete node path
|
|
*
|
|
* @return Node[]
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function getPath() : array
|
|
{
|
|
return $this->nodes;
|
|
}
|
|
|
|
/**
|
|
* Get the complete node path
|
|
*
|
|
* The path may only contain the jump points or pivot points.
|
|
* In order to get every node it needs to be expanded.
|
|
*
|
|
* @return Node[]
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function expandPath() : array
|
|
{
|
|
if (empty($this->expandedNodes)) {
|
|
//$reverse = \array_reverse($this->nodes);
|
|
$reverse = $this->nodes;
|
|
$length = \count($reverse);
|
|
|
|
if ($length < 2) {
|
|
return $reverse;
|
|
}
|
|
|
|
$expanded = [];
|
|
for ($i = 0; $i < $length - 1; ++$i) {
|
|
$coord0 = $reverse[$i];
|
|
$coord1 = $reverse[$i + 1];
|
|
|
|
$interpolated = $this->interpolate($coord0, $coord1);
|
|
$expanded = \array_merge($expanded, $interpolated);
|
|
}
|
|
|
|
$expanded[] = $reverse[$length - 1];
|
|
$this->expandedNodes = $expanded;
|
|
}
|
|
|
|
return $this->expandedNodes;
|
|
}
|
|
|
|
/**
|
|
* Find nodes in between two nodes.
|
|
*
|
|
* The path may only contain the jump points or pivot points.
|
|
* In order to get every node it needs to be expanded.
|
|
*
|
|
* @param Node $node1 Node
|
|
* @param Node $node2 Node
|
|
*
|
|
* @return Node[]
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
private function interpolate(Node $node1, Node $node2) : array
|
|
{
|
|
$dx = \abs($node2->getX() - $node1->getX());
|
|
$dy = \abs($node2->getY() - $node1->getY());
|
|
|
|
$sx = ($node1->getX() < $node2->getX()) ? 1 : -1;
|
|
$sy = ($node1->getY() < $node2->getY()) ? 1 : -1;
|
|
|
|
$node = $node1;
|
|
$err = $dx - $dy;
|
|
|
|
$x0 = $node->getX();
|
|
$y0 = $node->getY();
|
|
|
|
$line = [];
|
|
while (true) {
|
|
if ($node->getX() === $node2->getX() && $node->getY() === $node2->getY()) {
|
|
break;
|
|
}
|
|
|
|
$line[] = $node;
|
|
|
|
$e2 = 2 * $err;
|
|
|
|
if ($e2 > -$dy) {
|
|
$err -= $dy;
|
|
$x0 += $sx;
|
|
}
|
|
|
|
if ($e2 < $dx) {
|
|
$err += $dx;
|
|
$y0 += $sy;
|
|
}
|
|
|
|
$node = $this->grid->getNode($x0, $y0);
|
|
|
|
if ($node === null) {
|
|
break; // @codeCoverageIgnore
|
|
}
|
|
}
|
|
|
|
return $line;
|
|
}
|
|
}
|