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

parseDecimalDegreesWithCardinalLetters()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 19
Code Lines 10

Duplication

Lines 6
Ratio 31.58 %

Importance

Changes 0
Metric Value
dl 6
loc 19
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 10
nc 5
nop 2
1
<?php
2
/**
3
 * Coordinate Factory
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\Factory;
11
12
use Location\Coordinate;
13
use Location\Ellipsoid;
14
15
/**
16
 * Coordinate Factory
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 CoordinateFactory implements GeometryFactoryInterface
23
{
24
    /**
25
     * Creates a Coordinate instance from the given string.
26
     *
27
     * The string is parsed by a regular expression for a known
28
     * format of geographical coordinates.
29
     *
30
     * @param string $string formatted geographical coordinate
31
     * @param \Location\Ellipsoid $ellipsoid
32
     *
33
     * @return \Location\Coordinate
34
     */
35
    public static function fromString($string, Ellipsoid $ellipsoid = null)
36
    {
37
        $result = self::parseDecimalMinutesWithoutCardinalLetters($string, $ellipsoid);
38
39
        if ($result instanceof Coordinate) {
40
            return $result;
41
        }
42
43
        $result = self::parseDecimalMinutesWithCardinalLetters($string, $ellipsoid);
44
45
        if ($result instanceof Coordinate) {
46
            return $result;
47
        }
48
49
        $result = self::parseDecimalDegreesWithoutCardinalLetters($string, $ellipsoid);
50
51
        if ($result instanceof Coordinate) {
52
            return $result;
53
        }
54
55
        $result = self::parseDecimalDegreesWithCardinalLetters($string, $ellipsoid);
56
57
        if ($result instanceof Coordinate) {
58
            return $result;
59
        }
60
61
        throw new \InvalidArgumentException("Format of coordinates was not recognized");
62
    }
63
64
    /**
65
     * @param $string
66
     * @param $ellipsoid
67
     *
68
     * @return \Location\Coordinate|null
69
     */
70
    private static function parseDecimalMinutesWithoutCardinalLetters($string, $ellipsoid)
71
    {
72
        // Decimal minutes without cardinal letters, e. g. "52 12.345, 13 23.456",
73
        // "52° 12.345, 13° 23.456", "52° 12.345′, 13° 23.456′", "52 12.345 N, 13 23.456 E",
74
        // "N52° 12.345′ E13° 23.456′"
75
        if (preg_match('/(-?\d{1,2})°?\s+(\d{1,2}\.?\d*)[\'′]?[, ]\s*(-?\d{1,3})°?\s+(\d{1,2}\.?\d*)[\'′]?/ui', $string, $match)) {
76
            $latitude = $match[1] >= 0 ? $match[1] + $match[2] / 60 : $match[1] - $match[2] / 60;
77
            $longitude = $match[3] >= 0 ? $match[3] + $match[4] / 60 : $match[3] - $match[4] / 60;
78
79
            return new Coordinate($latitude, $longitude, $ellipsoid);
80
        }
81
82
        return null;
83
    }
84
85
    /**
86
     * @param $string
87
     * @param $ellipsoid
88
     *
89
     * @return \Location\Coordinate|null
90
     */
91
    private static function parseDecimalMinutesWithCardinalLetters($string, $ellipsoid)
92
    {
93
        // Decimal minutes with cardinal letters, e. g. "52 12.345, 13 23.456",
94
        // "52° 12.345, 13° 23.456", "52° 12.345′, 13° 23.456′", "52 12.345 N, 13 23.456 E",
95
        // "N52° 12.345′ E13° 23.456′"
96
        if (preg_match('/([NS]?\s*)(\d{1,2})°?\s+(\d{1,2}\.?\d*)[\'′]?(\s*[NS]?)[, ]\s*([EW]?\s*)(\d{1,3})°?\s+(\d{1,2}\.?\d*)[\'′]?(\s*[EW]?)/ui', $string, $match)) {
97
            $latitude = $match[2] + $match[3] / 60;
98 View Code Duplication
            if (trim(strtoupper($match[1])) === 'S' || trim(strtoupper($match[4])) === 'S') {
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...
99
                $latitude = - $latitude;
100
            }
101
            $longitude = $match[6] + $match[7] / 60;
102 View Code Duplication
            if (trim(strtoupper($match[5])) === 'W' || trim(strtoupper($match[8])) === 'W') {
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...
103
                $longitude = - $longitude;
104
            }
105
106
            return new Coordinate($latitude, $longitude, $ellipsoid);
107
        }
108
109
        return null;
110
    }
111
112
    /**
113
     * @param $string
114
     * @param $ellipsoid
115
     *
116
     * @return \Location\Coordinate|null
117
     */
118
    private static function parseDecimalDegreesWithoutCardinalLetters($string, $ellipsoid)
119
    {
120
        // The most simple format: decimal degrees without cardinal letters,
121
        // e. g. "52.5, 13.5" or "53.25732 14.24984"
122
        if (preg_match('/(-?\d{1,2}\.?\d*)°?[, ]\s*(-?\d{1,3}\.?\d*)°?/u', $string, $match)) {
123
            return new Coordinate($match[1], $match[2], $ellipsoid);
124
        }
125
126
        return null;
127
    }
128
129
    /**
130
     * @param $string
131
     * @param $ellipsoid
132
     *
133
     * @return \Location\Coordinate|null
134
     */
135
    private static function parseDecimalDegreesWithCardinalLetters($string, $ellipsoid)
136
    {
137
        // Decimal degrees with cardinal letters, e. g. "N52.5, E13.5",
138
        // "40.2S, 135.3485W", or "56.234°N, 157.245°W"
139
        if (preg_match('/([NS]?\s*)(\d{1,2}\.?\d*)°?(\s*[NS]?)[, ]\s*([EW]?\s*)(\d{1,3}\.?\d*)°?(\s*[EW]?)/ui', $string, $match)) {
140
            $latitude = $match[2];
141 View Code Duplication
            if (trim(strtoupper($match[1])) === 'S' || trim(strtoupper($match[3])) === 'S') {
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...
142
                $latitude = - $latitude;
143
            }
144
            $longitude = $match[5];
145 View Code Duplication
            if (trim(strtoupper($match[4])) === 'W' || trim(strtoupper($match[6])) === 'W') {
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...
146
                $longitude = - $longitude;
147
            }
148
149
            return new Coordinate($latitude, $longitude, $ellipsoid);
150
        }
151
152
        return null;
153
    }
154
}
155