Passed
Push — master ( 90f1a9...1f2e81 )
by Andrii
01:30
created

NearestSearch::reset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace KDTree\Search;
6
7
use KDTree\Interfaces\{KDTreeInterface, NearestSearchInterface, NodeInterface, PointInterface};
8
9
class NearestSearch implements NearestSearchInterface
10
{
11
    /**
12
     * @var KDTreeInterface
13
     */
14
    private $tree;
15
16
    /**
17
     * @var int
18
     */
19
    private $visited = 0;
20
21
    /**
22
     * @var PointInterface|null
23
     */
24
    private $closestPoint;
25
26
    /**
27
     * @var float
28
     */
29
    private $bestDistance;
30
31
    /**
32
     * @param KDTreeInterface $tree
33
     */
34
    public function __construct(KDTreeInterface $tree)
35
    {
36
        $this->tree = $tree;
37
        $this->reset();
38
    }
39
40
    /**
41
     * @param PointInterface $point
42
     *
43
     * @return PointInterface|null
44
     */
45
    public function nearest(PointInterface $point): ?PointInterface
46
    {
47
        $this->reset();
48
        $this->findNearest($this->tree->getRoot(), $point);
49
50
        return $this->closestPoint;
51
    }
52
53
    /**
54
     * @return float
55
     */
56
    public function getNearestDistance(): float
57
    {
58
        return $this->bestDistance;
59
    }
60
61
    /**
62
     * @param NodeInterface|null $node
63
     * @param PointInterface $searchingPoint
64
     * @param int $cuttingDimension
65
     */
66
    private function findNearest(?NodeInterface $node, PointInterface $searchingPoint, int $cuttingDimension = 0): void
67
    {
68
        if (null === $node) {
69
            return;
70
        }
71
72
        ++$this->visited;
73
        $distance = $node->getPoint()->distance($searchingPoint);
74
75
        if (null === $this->closestPoint || $distance < $this->bestDistance) {
76
            $this->bestDistance = $distance;
77
            $this->closestPoint = $node->getPoint();
78
        }
79
80
        if (0.0 === $this->bestDistance) {
1 ignored issue
show
introduced by
The condition 0.0 === $this->bestDistance is always false.
Loading history...
81
            return;
82
        }
83
84
        $dx = $node->getPoint()->getDAxis($cuttingDimension) - $searchingPoint->getDAxis($cuttingDimension);
85
        $cuttingDimension = ($cuttingDimension + 1) % $this->tree->getDimensions();
86
87
        $this->findNearest($dx > 0 ? $node->getLeft() : $node->getRight(), $searchingPoint, $cuttingDimension);
88
        if ($dx * $dx >= $this->bestDistance) {
89
            return;
90
        }
91
92
        $this->findNearest($dx > 0 ? $node->getRight() : $node->getLeft(), $searchingPoint, $cuttingDimension);
93
    }
94
95
    private function reset(): void
96
    {
97
        $this->bestDistance = (float)PHP_INT_MAX;
98
        $this->closestPoint = null;
99
        $this->visited = 0;
100
    }
101
}
102