Geometrable::reverse()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 10
1
<?php
2
3
namespace Bavix\Geo\Geometry;
4
5
use Bavix\Geo\Coordinate;
6
7
abstract class Geometrable implements \Countable, \JsonSerializable
8
{
9
10
    /**
11
     * @var int
12
     */
13
    protected $numberPoints;
14
15
    /**
16
     * @var array
17
     */
18
    protected $points = [];
19
20
    /**
21
     * @param Coordinate $point
22
     * @return static
23
     */
24
    public function push(Coordinate $point): self
25
    {
26
        if ($this->numberPoints && $this->count() >= $this->numberPoints) {
27
            throw new \InvalidArgumentException('This geometric shape can\'t have ' .
28
                ($this->numberPoints + 1) .
29
                ' and more points');
30
        }
31
32
        $this->points[] = $point;
33
        return $this;
34
    }
35
36
    /**
37
     * @return Coordinate
38
     */
39
    public function pop(): Coordinate
40
    {
41
        return \array_pop($this->points);
42
    }
43
44
    /**
45
     * @param int $index
46
     *
47
     * @return Coordinate
48
     */
49
    public function at(int $index): Coordinate
50
    {
51
        if (empty($this->points[$index])) {
52
            throw new \InvalidArgumentException('Point not found');
53
        }
54
55
        return $this->points[$index];
56
    }
57
58
    /**
59
     * @return Coordinate[]
60
     */
61
    public function points(): array
62
    {
63
        return $this->points;
64
    }
65
66
    /**
67
     * @return int
68
     */
69
    public function count(): int
70
    {
71
        return \count($this->points);
72
    }
73
74
    /**
75
     * @return float[]
76
     */
77
    public function latitudes(): array
78
    {
79
        $data = [];
80
        foreach ($this->points as $point) {
81
            $data[] = $point->latitude->degrees;
82
        }
83
        return $data;
84
    }
85
86
    /**
87
     * @return float[]
88
     */
89
    public function longitudes(): array
90
    {
91
        $data = [];
92
        foreach ($this->points as $point) {
93
            $data[] = $point->longitude->degrees;
94
        }
95
        return $data;
96
    }
97
98
    /**
99
     * @see https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
100
     *
101
     * @param Coordinate $point
102
     * @return bool
103
     */
104
    public function contains(Coordinate $point): bool
105
    {
106
        $count = \count($this);
107
108
        if ($this->numberPoints && $count !== $this->numberPoints) {
109
            throw new \InvalidArgumentException('It\'s not a geometric shape');
110
        }
111
112
        $result = false;
113
        $latitudes = $this->latitudes();
114
        $longitudes = $this->longitudes();
115
116
        for ($curr = 0, $prev = $count - 1; $curr < $count; $prev = $curr++) {
117
            if (($longitudes[$curr] > $point->longitude->degrees) ^
118
                ($longitudes[$prev] > $point->longitude->degrees) &&
119
120
                $point->latitude->degrees < ($latitudes[$prev] - $latitudes[$curr])
121
                * ($point->longitude->degrees - $longitudes[$curr])
122
                / ($longitudes[$prev] - $longitudes[$curr])
123
                + $latitudes[$curr]) {
124
                $result = !$result;
0 ignored issues
show
introduced by
The condition $result is always false.
Loading history...
125
            }
126
        }
127
128
        return $result;
129
    }
130
131
    /**
132
     * @param self $geometry
133
     * @return bool
134
     */
135
    public function containsGeometry(Geometrable $geometry): bool
136
    {
137
        foreach ($geometry->points() as $point) {
138
            if (!$this->contains($point)) {
139
                return false;
140
            }
141
        }
142
143
        return true;
144
    }
145
146
    /**
147
     * @return static
148
     */
149
    public function reverse(): self
150
    {
151
        $self = clone $this;
152
        $self->points = \array_reverse($this->points);
153
        return $self;
154
    }
155
156
    /**
157
     * @return array
158
     */
159
    public function jsonSerialize(): array
160
    {
161
        return $this->points();
162
    }
163
164
}
165