Completed
Push — master ( defad8...41fcb8 )
by Marcus
02:50
created

src/Location/Processor/Polyline/Simplify.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Simplify Polyline with the Douglas-Peucker-Algorithm
4
 *
5
 * The Algorithm is described here:
6
 * http://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
7
 *
8
 * The formula for the Perpendicular Distance is described here:
9
 * http://biodiversityinformatics.amnh.org/open_source/pdc/documentation.php
10
 *
11
 * @author    Marcus Jaschen <[email protected]>
12
 * @license   https://opensource.org/licenses/GPL-3.0 GPL
13
 * @link      https://github.com/mjaschen/phpgeo
14
 */
15
16
namespace Location\Processor\Polyline;
17
18
use Location\Coordinate;
19
use Location\Line;
20
use Location\Polyline;
21
22
/**
23
 * Simplify Polyline with the Douglas-Peucker-Algorithm
24
 *
25
 * @deprecated This class is no longer supported. Please use
26
 * the `SimplifyDouglasPeucker` oder `SimplifyBearing` classes.
27
 *
28
 * @author   Marcus Jaschen <[email protected]>
29
 * @license  https://opensource.org/licenses/GPL-3.0 GPL
30
 * @link     https://github.com/mjaschen/phpgeo
31
 */
32
class Simplify
33
{
34
    /**
35
     * @var \Location\Polyline
36
     */
37
    protected $polyline;
38
39
    /**
40
     * @param Polyline $polyline
41
     */
42
    public function __construct(Polyline $polyline)
43
    {
44
        $this->polyline = $polyline;
45
    }
46
47
    /**
48
     * @param float $tolerance The maximum allowed deviation
49
     *
50
     * @return Polyline
51
     */
52 View Code Duplication
    public function simplify($tolerance)
53
    {
54
        $simplifiedLine = $this->douglasPeucker(
55
            $this->polyline->getPoints(),
56
            $tolerance
57
        );
58
59
        $resultPolyline = new Polyline();
60
61
        foreach ($simplifiedLine as $point) {
62
            $resultPolyline->addPoint($point);
63
        }
64
65
        return $resultPolyline;
66
    }
67
68
    /**
69
     * @param array $line
70
     * @param float $tolerance
71
     *
72
     * @return array
73
     */
74 View Code Duplication
    protected function douglasPeucker($line = [], $tolerance)
0 ignored issues
show
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...
75
    {
76
        $distanceMax = 0;
77
        $index       = 0;
78
79
        $lineSize = count($line);
80
81
        for ($i = 1; $i <= ($lineSize - 1); $i ++) {
82
            $distance = $this->getPerpendicularDistance($line[$i], new Line($line[0], $line[$lineSize - 1]));
83
84
            if ($distance > $distanceMax) {
85
                $index       = $i;
86
                $distanceMax = $distance;
87
            }
88
        }
89
90
        if ($distanceMax > $tolerance) {
91
            $lineSplitFirst  = array_slice($line, 0, $index);
92
            $lineSplitSecond = array_slice($line, $index, $lineSize);
93
94
            $recursiveResultsSplitFirst  = $this->douglasPeucker($lineSplitFirst, $tolerance);
95
            $recursiveResultsSplitSecond = $this->douglasPeucker($lineSplitSecond, $tolerance);
96
97
            array_pop($recursiveResultsSplitFirst);
98
99
            return array_merge($recursiveResultsSplitFirst, $recursiveResultsSplitSecond);
100
        }
101
102
        return [$line[0], $line[$lineSize - 1]];
103
    }
104
105
    /**
106
     * @param Coordinate $point
107
     * @param Line $line
108
     *
109
     * @return number
110
     */
111 View Code Duplication
    protected function getPerpendicularDistance(Coordinate $point, Line $line)
112
    {
113
        $ellipsoid = $point->getEllipsoid();
114
115
        $ellipsoidRadius = $ellipsoid->getArithmeticMeanRadius();
116
117
        $firstLinePointLat = $this->deg2radLatitude($line->getPoint1()->getLat());
118
        $firstLinePointLng = $this->deg2radLongitude($line->getPoint1()->getLng());
119
120
        $firstLinePointX = $ellipsoidRadius * cos($firstLinePointLng) * sin($firstLinePointLat);
121
        $firstLinePointY = $ellipsoidRadius * sin($firstLinePointLng) * sin($firstLinePointLat);
122
        $firstLinePointZ = $ellipsoidRadius * cos($firstLinePointLat);
123
124
        $secondLinePointLat = $this->deg2radLatitude($line->getPoint2()->getLat());
125
        $secondLinePointLng = $this->deg2radLongitude($line->getPoint2()->getLng());
126
127
        $secondLinePointX = $ellipsoidRadius * cos($secondLinePointLng) * sin($secondLinePointLat);
128
        $secondLinePointY = $ellipsoidRadius * sin($secondLinePointLng) * sin($secondLinePointLat);
129
        $secondLinePointZ = $ellipsoidRadius * cos($secondLinePointLat);
130
131
        $pointLat = $this->deg2radLatitude($point->getLat());
132
        $pointLng = $this->deg2radLongitude($point->getLng());
133
134
        $pointX = $ellipsoidRadius * cos($pointLng) * sin($pointLat);
135
        $pointY = $ellipsoidRadius * sin($pointLng) * sin($pointLat);
136
        $pointZ = $ellipsoidRadius * cos($pointLat);
137
138
        $normalizedX = $firstLinePointY * $secondLinePointZ - $firstLinePointZ * $secondLinePointY;
139
        $normalizedY = $firstLinePointZ * $secondLinePointX - $firstLinePointX * $secondLinePointZ;
140
        $normalizedZ = $firstLinePointX * $secondLinePointY - $firstLinePointY * $secondLinePointX;
141
142
        $length = sqrt($normalizedX * $normalizedX + $normalizedY * $normalizedY + $normalizedZ * $normalizedZ);
143
144
        $normalizedX /= $length;
145
        $normalizedY /= $length;
146
        $normalizedZ /= $length;
147
148
        $thetaPoint = $normalizedX * $pointX + $normalizedY * $pointY + $normalizedZ * $pointZ;
149
150
        $length = sqrt($pointX * $pointX + $pointY * $pointY + $pointZ * $pointZ);
151
152
        $thetaPoint /= $length;
153
154
        $distance = abs((M_PI / 2) - acos($thetaPoint));
155
156
        return $distance * $ellipsoidRadius;
157
    }
158
159
    /**
160
     * @param float $latitude
161
     *
162
     * @return float
163
     */
164
    protected function deg2radLatitude($latitude)
165
    {
166
        return deg2rad(90 - $latitude);
167
    }
168
169
    /**
170
     * @param float $longitude
171
     *
172
     * @return float
173
     */
174
    protected function deg2radLongitude($longitude)
175
    {
176
        if ($longitude > 0) {
177
            return deg2rad($longitude);
178
        }
179
180
        return deg2rad($longitude + 360);
181
    }
182
}
183