From 2c4155b674d93c0075df8936f86f526923310e86 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Wed, 4 Sep 2019 21:39:29 +0200 Subject: [PATCH] streamline heuristic by using metrics implementation --- Algorithm/PathFinding/AStar.php | 2 +- Algorithm/PathFinding/Heuristic.php | 47 +++++++---------------- Algorithm/PathFinding/HeuristicType.php | 11 ++++-- Algorithm/PathFinding/JumpPointSearch.php | 4 +- Algorithm/PathFinding/Node.php | 5 +++ 5 files changed, 28 insertions(+), 41 deletions(-) diff --git a/Algorithm/PathFinding/AStar.php b/Algorithm/PathFinding/AStar.php index 52f8f9fe7..59be87f08 100644 --- a/Algorithm/PathFinding/AStar.php +++ b/Algorithm/PathFinding/AStar.php @@ -66,7 +66,7 @@ class JumpPointSearch implements PathFinderInterface if (!$neighbor->isOpened() || $ng < $neighbor->getG()) { $neighbor->setG($ng); - $neighbor->setH($neighbor->getG() ?? $neighbor->getWeight() * Heuristic::heuristic($neighbor, $endNode, $heuristic)); + $neighbor->setH($neighbor->getG() ?? $neighbor->getWeight() * Heuristic::heuristic($neighbor->getCoordinates(), $endNode->getCoordinates(), $heuristic)); $neighbor->setF($neighbor->getG() + $neighbor->getH()); $neighbor->setParent($node); diff --git a/Algorithm/PathFinding/Heuristic.php b/Algorithm/PathFinding/Heuristic.php index 0e8f259c5..8e5ae5b8e 100644 --- a/Algorithm/PathFinding/Heuristic.php +++ b/Algorithm/PathFinding/Heuristic.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace phpOMS\Algorithm\PathFinding; +use phpOMS\Math\Topology\Metrics2D; + /** * Node on grid. * @@ -24,45 +26,22 @@ namespace phpOMS\Algorithm\PathFinding; */ class Heuristic { - public static function heuristic(Node $node1, Node $node2, int $heuristic) : float + public static function heuristic(array $node1, array $node2, int $heuristic) : float { if ($heuristic === HeuristicType::MANHATTAN) { - return self::manhattan($node1, $node2); + return Metrics2D::manhattan($node1, $node2); } elseif ($heuristic === HeuristicType::EUCLIDEAN) { - return self::euclidean($node1, $node2); + return Metrics2D::euclidean($node1, $node2); } elseif ($heuristic === HeuristicType::OCTILE) { - return self::octile($node1, $node2); + return Metrics2D::octile($node1, $node2); + } elseif ($heuristic === HeuristicType::MINKOWSKI) { + return Metrics2D::minkowski($node1, $node2, 1); + } elseif ($heuristic === HeuristicType::CANBERRA) { + return Metrics2D::canberra($node1, $node2); + } elseif ($heuristic === HeuristicType::BRAY_CURTIS) { + return Metrics2D::brayCurtis($node1, $node2); } - return self::chebyshev($node1, $node2); - } - - public static function manhattan(Node $node1, Node $node2) : float - { - return \abs($node1->getX() - $node2->getX()) + \abs($node1->getY() - $node2->getY()); - } - - public static function euclidean(Node $node1, Node $node2) : float - { - $dx = \abs($node1->getX() - $node2->getX()); - $dy = \abs($node1->getY() - $node2->getY()); - - return \sqrt($dx * $dx + $dy * $dy); - } - - public static function octile(Node $node1, Node $node2) : float - { - $dx = \abs($node1->getX() - $node2->getX()); - $dy = \abs($node1->getY() - $node2->getY()); - - return $dx < $dy ? (\sqrt(2) - 1) * $dx + $dy : (\sqrt(2) - 1) * $dy + $dx; - } - - public static function chebyshev(Node $node1, Node $node2) : float - { - return \max( - \abs($node1->getX() - $node2->getX()), - \abs($node1->getY() - $node2->getY()) - ); + return Metrics2D::chebyshev($node1, $node2); } } diff --git a/Algorithm/PathFinding/HeuristicType.php b/Algorithm/PathFinding/HeuristicType.php index 73aaf483a..2d51434ad 100644 --- a/Algorithm/PathFinding/HeuristicType.php +++ b/Algorithm/PathFinding/HeuristicType.php @@ -26,8 +26,11 @@ use phpOMS\Stdlib\Base\Enum; */ abstract class HeuristicType extends Enum { - public const MANHATTAN = 1; - public const EUCLIDEAN = 2; - public const OCTILE = 4; - public const CHEBYSHEV = 8; + public const MANHATTAN = 1; + public const EUCLIDEAN = 2; + public const OCTILE = 4; + public const CHEBYSHEV = 8; + public const MINKOWSKI = 16; + public const CANBERRA = 32; + public const BRAY_CURTIS = 64; } diff --git a/Algorithm/PathFinding/JumpPointSearch.php b/Algorithm/PathFinding/JumpPointSearch.php index 0b7cdc28c..11958494c 100644 --- a/Algorithm/PathFinding/JumpPointSearch.php +++ b/Algorithm/PathFinding/JumpPointSearch.php @@ -79,12 +79,12 @@ class JumpPointSearch implements PathFinderInterface continue; } - $d = Heuristic::octile($node, $jumpPoint); + $d = Heuristic::heuristic($node->getCoordinates(), $jumpPoint->getCoordinates(), HeuristicType::OCTILE); $ng = $node->getG() + $d; if (!$jumpPoint->isOpened() || $ng < $jumpPoint->getG()) { $jumpPoint->setG($ng); - $jumpPoint->setH($jumpPoint->getH() ?? Heuristic::heuristic($jumpPoint, $endNode, $heuristic)); + $jumpPoint->setH($jumpPoint->getH() ?? Heuristic::heuristic($jumpPoint->getCoordinates(), $endNode->getCoordinates(), $heuristic)); $jumpPoint->setF($jumpPoint->getG() + $jumpPoint->getH()); $jumpPoint->setParent($node); diff --git a/Algorithm/PathFinding/Node.php b/Algorithm/PathFinding/Node.php index 916612701..7c8867dff 100644 --- a/Algorithm/PathFinding/Node.php +++ b/Algorithm/PathFinding/Node.php @@ -72,4 +72,9 @@ class Node { return $this->x === $node->getX() && $this->y === $node->getY(); } + + public function getCoordinates() : array + { + return ['x' => $this->x, 'y' => $this->y]; + } }