streamline heuristic by using metrics implementation

This commit is contained in:
Dennis Eichhorn 2019-09-04 21:39:29 +02:00
parent c9e439c0f4
commit 2c4155b674
5 changed files with 28 additions and 41 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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];
}
}