Completed
Push — develop ( aece91...c301b1 )
by Marcus
02:18 queued 36s
created

SimplifyBearing::simplify()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 42
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 8.439
c 0
b 0
f 0
cc 5
eloc 23
nc 4
nop 1
1
<?php
2
/**
3
 * Simplify Polyline
4
 *
5
 * @author   Marcus Jaschen <[email protected]>
6
 * @license  https://opensource.org/licenses/GPL-3.0 GPL
7
 * @link     https://github.com/mjaschen/phpgeo
8
 */
9
10
namespace Location\Processor\Polyline;
11
12
use Location\Bearing\BearingEllipsoidal;
13
use Location\Polyline;
14
15
/**
16
 * Simplify Polyline
17
 *
18
 * @author   Marcus Jaschen <[email protected]>
19
 * @license  https://opensource.org/licenses/GPL-3.0 GPL
20
 * @link     https://github.com/mjaschen/phpgeo
21
 */
22
class SimplifyBearing implements SimplifyInterface
23
{
24
    /**
25
     * @var float
26
     */
27
    private $bearingAngle;
28
29
    /**
30
     * SimplifyBearing constructor.
31
     *
32
     * @param float $bearingAngle
33
     */
34
    public function __construct($bearingAngle)
35
    {
36
        $this->bearingAngle = $bearingAngle;
37
    }
38
39
    /**
40
     * Simplifies the given polyline
41
     *
42
     * 1. calculate the bearing angle between the first two points p1 and p2: b1
43
     * 2. calculate the bearing angle between the next two points p2 and p3: b2
44
     * 3. calculate the difference between b1 and b2: deltaB; if deltaB is
45
     *    smaller than the threshold angle, remove the middle point p2
46
     * 4. start again at (1.) as long as the polyline contains more points
47
     *
48
     * @param Polyline $polyline
49
     *
50
     * @return Polyline
51
     */
52
    public function simplify(Polyline $polyline)
53
    {
54
        $counterPoints = $polyline->getNumberOfPoints();
55
56
        if ($counterPoints < 3) {
57
            return clone $polyline;
58
        }
59
60
        $result      = new Polyline();
61
        $bearingCalc = new BearingEllipsoidal();
62
63
        $points = $polyline->getPoints();
64
65
        $index = 0;
66
67
        // add the first point to the resulting polyline
68
        $result->addPoint($points[$index]);
69
70
        do {
71
            $index++;
72
73
            // preserve the last point of the original polyline
74
            if ($index === ($counterPoints - 1)) {
75
                $result->addPoint($points[$index]);
76
                break;
77
            }
78
79
            $bearing1 = $bearingCalc->calculateBearing($points[$index - 1], $points[$index]);
80
            $bearing2 = $bearingCalc->calculateBearing($points[$index], $points[$index + 1]);
81
82
            $bearingDifference = min(
83
                fmod($bearing1 - $bearing2 + 360, 360),
84
                fmod($bearing2 - $bearing1 + 360, 360)
85
            );
86
87
            if ($bearingDifference > $this->bearingAngle) {
88
                $result->addPoint($points[$index]);
89
            }
90
        } while ($index < $counterPoints);
91
92
        return $result;
93
    }
94
}
95