Completed
Push — master ( eedcfb...3a03fe )
by Marcus
02:26
created

Polyline::getAveragePoint()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Location;
6
7
use Location\Distance\DistanceInterface;
8
use Location\Exception\InvalidGeometryException;
9
use Location\Formatter\Polyline\FormatterInterface;
10
11
/**
12
 * Polyline Implementation
13
 *
14
 * @author Marcus Jaschen <[email protected]>
15
 */
16
class Polyline implements GeometryInterface
17
{
18
    use GetBoundsTrait;
19
20
    /**
21
     * @var Coordinate[]
22
     */
23
    protected $points = [];
24
25
    /**
26
     * @param Coordinate $point
27
     *
28
     * @return void
29
     */
30
    public function addPoint(Coordinate $point)
31
    {
32
        $this->points[] = $point;
33
    }
34
35
    /**
36
     * Adds an unique point to the polyline. A maximum allowed distance for
37
     * same point comparison can be provided. Default allowed distance
38
     * deviation is 0.001 meters (1 millimeter).
39
     *
40
     * @param Coordinate $point
41
     * @param float $allowedDistance
42
     *
43
     * @return void
44
     */
45
    public function addUniquePoint(Coordinate $point, float $allowedDistance = .001)
46
    {
47
        if ($this->containsPoint($point, $allowedDistance)) {
48
            return;
49
        }
50
51
        $this->addPoint($point);
52
    }
53
54
    /**
55
     * @return Coordinate[]
56
     */
57
    public function getPoints(): array
58
    {
59
        return $this->points;
60
    }
61
62
    /**
63
     * @return int
64
     */
65
    public function getNumberOfPoints(): int
66
    {
67
        return count($this->points);
68
    }
69
70
    /**
71
     * @param Coordinate $point
72
     * @param float $allowedDistance
73
     *
74
     * @return bool
75
     */
76
    public function containsPoint(Coordinate $point, float $allowedDistance = .001): bool
77
    {
78
        foreach ($this->points as $existingPoint) {
79
            if ($existingPoint->hasSameLocation($point, $allowedDistance)) {
80
                return true;
81
            }
82
        }
83
84
        return false;
85
    }
86
87
    /**
88
     * @param FormatterInterface $formatter
89
     *
90
     * @return string
91
     */
92
    public function format(FormatterInterface $formatter): string
93
    {
94
        return $formatter->format($this);
95
    }
96
97
    /**
98
     * @return Line[]
99
     */
100
    public function getSegments(): array
101
    {
102
        $length = count($this->points);
103
        $segments = [];
104
105
        if ($length <= 1) {
106
            return $segments;
107
        }
108
109 View Code Duplication
        for ($i = 1; $i < $length; $i++) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
            $segments[] = new Line($this->points[$i - 1], $this->points[$i]);
111
        }
112
113
        return $segments;
114
    }
115
116
    /**
117
     * Calculates the length of the polyline.
118
     *
119
     * @param DistanceInterface $calculator instance of distance calculation class
120
     *
121
     * @return float
122
     */
123 View Code Duplication
    public function getLength(DistanceInterface $calculator): float
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
    {
125
        $distance = 0.0;
126
127
        if (count($this->points) <= 1) {
128
            return $distance;
129
        }
130
131
        foreach ($this->getSegments() as $segment) {
132
            $distance += $segment->getLength($calculator);
133
        }
134
135
        return $distance;
136
    }
137
138
    /**
139
     * Create a new polyline with reversed order of points, i. e. reversed
140
     * polyline direction.
141
     *
142
     * @return Polyline
143
     */
144 View Code Duplication
    public function getReverse(): Polyline
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145
    {
146
        $reversed = new static();
147
148
        foreach (array_reverse($this->points) as $point) {
149
            $reversed->addPoint($point);
150
        }
151
152
        return $reversed;
153
    }
154
155
    /**
156
     * Returns the point which is defined by the avarages of all
157
     * latitude/longitude values.
158
     *
159
     * This currently only works for polylines which don't cross the dateline at
160
     * 180/-180 degrees longitude.
161
     *
162
     * @return Coordinate
163
     *
164
     * @throws InvalidGeometryException when the polyline doesn't contain any points.
165
     */
166
    public function getAveragePoint(): Coordinate
167
    {
168
        $latitude = 0.0;
169
        $longitude = 0.0;
170
        $numberOfPoints = count($this->points);
171
172
        if ($this->getNumberOfPoints() === 0) {
173
            throw new InvalidGeometryException('Polyline doesn\'t contain points', 9464188927);
174
        }
175
176
        foreach ($this->points as $point) {
177
            /* @var $point Coordinate */
178
            $latitude += $point->getLat();
179
            $longitude += $point->getLng();
180
        }
181
182
        $latitude /= $numberOfPoints;
183
        $longitude /= $numberOfPoints;
184
185
        return new Coordinate($latitude, $longitude);
186
    }
187
}
188