AngularSweep   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 45
dl 0
loc 136
rs 10
c 0
b 0
f 0
wmc 19

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getMaxCenter() 0 7 2
A getMax() 0 3 1
A calculateDistances() 0 6 3
B getPointsInside() 0 35 9
A findMaxPoint() 0 7 3
A __construct() 0 6 1
1
<?php
2
3
namespace Hotrush\AngularSweep;
4
5
class AngularSweep
6
{
7
    /**
8
     * @var NumbersCollection
9
     */
10
    private $numbersCollection;
11
12
    /**
13
     * @var float
14
     */
15
    private $radius;
16
17
    /**
18
     * @var array
19
     */
20
    private $distances = [];
21
22
    /**
23
     * @var int
24
     */
25
    private $max = 0;
26
27
    /**
28
     * @var null|int
29
     */
30
    private $maxCenterKey;
31
32
    /**
33
     * AngularSweep constructor.
34
     *
35
     * @param NumbersCollection $numbersCollection
36
     * @param $radius
37
     * @throws \Exception
38
     */
39
    public function __construct(NumbersCollection $numbersCollection, $radius)
40
    {
41
        $this->numbersCollection = $numbersCollection;
42
        $this->radius = floatval($radius);
43
        $this->calculateDistances();
44
        $this->findMaxPoint();
45
    }
46
47
    /**
48
     * @return int
49
     */
50
    public function getMax()
51
    {
52
        return $this->max;
53
    }
54
55
    /**
56
     * @return ComplexNumber
57
     */
58
    public function getMaxCenter()
59
    {
60
        if (is_null($this->maxCenterKey)) {
61
            throw new \InvalidArgumentException('No center found.');
62
        }
63
64
        return $this->numbersCollection->get($this->maxCenterKey);
65
    }
66
67
    /**
68
     * Calculate distances between points.
69
     *
70
     * @return void
71
     */
72
    private function calculateDistances()
73
    {
74
        for ($i = 0; $i < $this->numbersCollection->total() - 1; $i++) {
75
            for ($j = $i + 1; $j < $this->numbersCollection->total(); $j++) {
76
                $this->distances[$i][$j] = $this->distances[$j][$i] =
77
                    $this->numbersCollection->get($i)->subtract($this->numbersCollection->get($j))->abs();
78
            }
79
        }
80
    }
81
82
    /**
83
     * Find the max points number inside circle and get the center.
84
     *
85
     * @return void
86
     * @throws \Exception
87
     */
88
    private function findMaxPoint()
89
    {
90
        for ($i = 0; $i < $this->numbersCollection->total(); $i++) {
91
            $max = $this->getPointsInside($i);
92
            if ($max > $this->max) {
93
                $this->max = $max;
94
                $this->maxCenterKey = $i;
95
            }
96
        }
97
    }
98
99
    /**
100
     * Get points number inside circle.
101
     *
102
     * @param $i
103
     * @return int
104
     * @throws \Exception
105
     */
106
    private function getPointsInside($i)
107
    {
108
        $angles = [];
109
110
        for ($j = 0; $j < $this->numbersCollection->total(); $j++) {
111
            if ($i !== $j && $this->distances[$i][$j] <= 2 * $this->radius) {
112
                $B = acos($this->distances[$i][$j] / (2 * $this->radius));
113
                $A = $this->numbersCollection->get($j)->subtract($this->numbersCollection->get($i))->arg();
114
                $alpha = $A - $B;
115
                $beta = $A + $B;
116
                $angles[] = [$alpha, true];
117
                $angles[] = [$beta, false];
118
            }
119
        }
120
121
        usort($angles, function ($a, $b) {
122
            if ($a === $b) {
123
                return 0;
124
            }
125
            return $a > $b ? 1 : -1;
126
        });
127
128
        $count = 1; $res = 1;
129
        foreach ($angles as $angle) {
130
            if ($angle[1]) {
131
                $count++;
132
            } else {
133
                $count--;
134
            }
135
            if ($count > $res) {
136
                $res = $count;
137
            }
138
        }
139
140
        return $res;
141
    }
142
}