Partition   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 26
eloc 50
c 2
b 1
f 0
dl 0
loc 163
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getDMax() 0 7 2
A equals() 0 16 5
A distanceToPoint() 0 14 4
A getDimensions() 0 3 1
A getDMin() 0 7 2
A __construct() 0 20 4
A contains() 0 9 4
A intersects() 0 12 4
1
<?php
2
3
namespace KDTree\ValueObject;
4
5
use KDTree\Exceptions\{InvalidPointsCount, UnknownDimension};
6
use KDTree\Interfaces\{PartitionInterface, PointInterface, PointsListInterface};
7
8
/**
9
 * Class Partition
10
 *
11
 * @package KDTree\ValueObject
12
 */
13
final class Partition implements PartitionInterface
14
{
15
    /**
16
     * @var PointsListInterface<PointInterface>
17
     */
18
    private $pointsList;
19
20
    /**
21
     * @var float[]
22
     */
23
    private $dMax;
24
25
    /**
26
     * @var float[]
27
     */
28
    private $dMin;
29
30
    /**
31
     * @param PointsListInterface<PointInterface> $pointsList
32
     *
33
     * @throws InvalidPointsCount
34
     */
35
    public function __construct(PointsListInterface $pointsList)
36
    {
37
        $pointCount = count($pointsList);
38
        if ($pointCount !== 2 ** $pointsList->getDimensions()) {
39
            throw new InvalidPointsCount();
40
        }
41
42
        $this->pointsList = $pointsList;
43
44
        $dMax = array_fill(0, $pointsList->getDimensions(), PHP_INT_MIN);
45
        $dMin = array_fill(0, $pointsList->getDimensions(), PHP_INT_MAX);
46
        foreach ($pointsList as $point) {
47
            foreach ($point->getAxises() as $d => $axis) {
48
                $dMax[$d] = max($dMax[$d], $axis);
49
                $dMin[$d] = min($dMin[$d], $axis);
50
            }
51
        }
52
53
        $this->dMax = $dMax;
54
        $this->dMin = $dMin;
55
    }
56
57
    /**
58
     * @param PointInterface $point
59
     *
60
     * @return bool
61
     * @throws UnknownDimension
62
     */
63
    public function contains(PointInterface $point): bool
64
    {
65
        foreach ($point->getAxises() as $dimension => $axis) {
66
            if ($axis < $this->getDMin($dimension) || $axis > $this->getDMax($dimension)) {
67
                return false;
68
            }
69
        }
70
71
        return true;
72
    }
73
74
    /**
75
     * @param int $dimension
76
     *
77
     * @return float
78
     * @throws UnknownDimension
79
     */
80
    public function getDMin(int $dimension): float
81
    {
82
        if (isset($this->dMin[$dimension])) {
83
            return $this->dMin[$dimension];
84
        }
85
86
        throw new UnknownDimension();
87
    }
88
89
    /**
90
     * @param int $dimension
91
     *
92
     * @return float
93
     * @throws UnknownDimension
94
     */
95
    public function getDMax(int $dimension): float
96
    {
97
        if (isset($this->dMax[$dimension])) {
98
            return $this->dMax[$dimension];
99
        }
100
101
        throw new UnknownDimension();
102
    }
103
104
    /**
105
     * @param PartitionInterface $partition
106
     *
107
     * @return bool
108
     * @throws UnknownDimension
109
     */
110
    public function intersects(PartitionInterface $partition): bool
111
    {
112
        foreach (range(0, $this->getDimensions() - 1) as $dimension) {
113
            $isIntersects = $this->getDMax($dimension) >= $partition->getDMin($dimension)
114
                && $partition->getDMax($dimension) >= $this->getDMin($dimension);
115
116
            if (false === $isIntersects) {
117
                return false;
118
            }
119
        }
120
121
        return true;
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function getDimensions(): int
128
    {
129
        return $this->pointsList->getDimensions();
130
    }
131
132
    /**
133
     * @param PointInterface $point
134
     *
135
     * @return float
136
     * @throws UnknownDimension
137
     */
138
    public function distanceToPoint(PointInterface $point): float
139
    {
140
        $result = 0.0;
141
        foreach ($point->getAxises() as $dimension => $axis) {
142
            $len = 0.0;
143
            if ($axis < $this->getDMin($dimension)) {
144
                $len = $axis - $this->getDMin($dimension);
145
            } elseif ($axis > $this->getDMax($dimension)) {
146
                $len = $axis - $this->getDMax($dimension);
147
            }
148
            $result += $len ** 2;
149
        }
150
151
        return sqrt($result);
152
    }
153
154
    /**
155
     * @param PartitionInterface $partition
156
     *
157
     * @return bool
158
     * @throws UnknownDimension
159
     */
160
    public function equals(PartitionInterface $partition): bool
161
    {
162
        if ($partition->getDimensions() !== $this->getDimensions()) {
163
            return false;
164
        }
165
166
        foreach (range(0, $this->getDimensions() - 1) as $dimension) {
167
            if (
168
                $this->getDMin($dimension) !== $partition->getDMin($dimension)
169
                || $this->getDMax($dimension) !== $partition->getDMax($dimension)
170
            ) {
171
                return false;
172
            }
173
        }
174
175
        return true;
176
    }
177
}
178