Completed
Push — master ( 87ff99...698648 )
by Doug
06:11
created

TransverseMercator::distance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 13
Ratio 100 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 13
loc 13
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 2.0185
1
<?php
2
/**
3
 * PHPCoord
4
 * @package PHPCoord
5
 * @author Jonathan Stott
6
 * @author Doug Wright
7
 */
8
namespace PHPCoord;
9
10
/**
11
 * Abstract class representing a Tranverse Mercator Projection
12
 * @author Doug Wright
13
 * @package PHPCoord
14
 */
15
abstract class TransverseMercator
16
{
17
18
    /**
19
     * X
20
     * @var float
21
     */
22
    protected $x;
23
24
    /**
25
     * Y
26
     * @var float
27
     */
28
    protected $y;
29
30
    /**
31
     * h
32
     * @var float
33
     */
34
    protected $h;
35
36
    /**
37
     * Reference ellipsoid used in this datum
38
     * @var RefEll
39
     */
40
    protected $refEll;
41
42
    /**
43
     * Cartesian constructor.
44
     * @param float $x
45
     * @param float $y
46
     * @param float $h
47
     * @param RefEll $refEll
48
     */
49 30
    public function __construct($x, $y, $h, RefEll $refEll)
50
    {
51 30
        $this->setX($x);
52 30
        $this->setY($y);
53 30
        $this->setH($h);
54 30
        $this->setRefEll($refEll);
55 30
    }
56
57
    /**
58
     * String version of coordinate.
59
     * @return string
60
     */
61
    public function __toString()
62
    {
63
        return "({$this->x}, {$this->y}, {$this->h})";
64
    }
65
66
    /**
67
     * @return float
68
     */
69 2
    public function getX()
70
    {
71 2
        return $this->x;
72
    }
73
74
    /**
75
     * @param float $x
76
     */
77 30
    public function setX($x)
78
    {
79 30
        $this->x = $x;
80 30
    }
81
82
    /**
83
     * @return float
84
     */
85 2
    public function getY()
86
    {
87 2
        return $this->y;
88
    }
89
90
    /**
91
     * @param float $y
92
     */
93 30
    public function setY($y)
94
    {
95 30
        $this->y = $y;
96 30
    }
97
98
    /**
99
     * @return float
100
     */
101 1
    public function getH()
102
    {
103 1
        return $this->h;
104
    }
105
106
    /**
107
     * @param float $h
108
     */
109 30
    public function setH($h)
110
    {
111 30
        $this->h = $h;
112 30
    }
113
114
    /**
115
     * @return RefEll
116
     */
117 1
    public function getRefEll()
118
    {
119 1
        return $this->refEll;
120
    }
121
122
    /**
123
     * @param RefEll $refEll
124
     */
125 30
    public function setRefEll(RefEll $refEll)
126
    {
127 30
        $this->refEll = $refEll;
128 30
    }
129
130
131
    /**
132
     * Reference ellipsoid used by this projection
133
     * @return RefEll
134
     */
135
    abstract public function getReferenceEllipsoid();
136
137
    /**
138
     * Scale factor at central meridian
139
     * @return float
140
     */
141
    abstract public function getScaleFactor();
142
143
    /**
144
     * Northing of true origin
145
     * @return float
146
     */
147
    abstract public function getOriginNorthing();
148
149
    /**
150
     * Easting of true origin
151
     * @return float
152
     */
153
    abstract public function getOriginEasting();
154
155
    /**
156
     * Latitude of true origin
157
     * @return float
158
     */
159
    abstract public function getOriginLatitude();
160
161
    /**
162
     * Longitude of true origin
163
     * @return float
164
     */
165
    abstract public function getOriginLongitude();
166
167
    /**
168
     * Convert this grid reference into a latitude and longitude
169
     * Formula for transformation is taken from OS document
170
     * "A Guide to Coordinate Systems in Great Britain"
171
     *
172
     * @param float $N map coordinate (northing) of point to convert
173
     * @param float $E map coordinate (easting) of point to convert
174
     * @param float $N0 map coordinate (northing) of true origin
175
     * @param float $E0 map coordinate (easting) of true origin
176
     * @param float $phi0 map coordinate (latitude) of true origin
177
     * @param float $lambda0 map coordinate (longitude) of true origin and central meridian
178
     * @return LatLng
179
     */
180 7
    public function convertToLatitudeLongitude($N, $E, $N0, $E0, $phi0, $lambda0)
181
    {
182
183 7
        $phi0 = deg2rad($phi0);
184 7
        $lambda0 = deg2rad($lambda0);
185
186 7
        $refEll = $this->getReferenceEllipsoid();
187 7
        $F0 = $this->getScaleFactor();
188
189 7
        $a = $refEll->getMaj();
190 7
        $b = $refEll->getMin();
191 7
        $eSquared = $refEll->getEcc();
192 7
        $n = ($a - $b) / ($a + $b);
193 7
        $phiPrime = (($N - $N0) / ($a * $F0)) + $phi0;
194
195
        do {
196
            $M =
197 7
                ($b * $F0)
198 7
                * (((1 + $n + ((5 / 4) * $n * $n) + ((5 / 4) * $n * $n * $n))
199 7
                        * ($phiPrime - $phi0))
200 7
                    - (((3 * $n) + (3 * $n * $n) + ((21 / 8) * $n * $n * $n))
201 7
                        * sin($phiPrime - $phi0)
202 7
                        * cos($phiPrime + $phi0))
203 7
                    + ((((15 / 8) * $n * $n) + ((15 / 8) * $n * $n * $n))
204 7
                        * sin(2 * ($phiPrime - $phi0))
205 7
                        * cos(2 * ($phiPrime + $phi0)))
206 7
                    - (((35 / 24) * $n * $n * $n)
207 7
                        * sin(3 * ($phiPrime - $phi0))
208 7
                        * cos(3 * ($phiPrime + $phi0))));
209 7
            $phiPrime += ($N - $N0 - $M) / ($a * $F0);
210 7
        } while (($N - $N0 - $M) >= 0.00001);
211 7
        $v = $a * $F0 * pow(1 - $eSquared * pow(sin($phiPrime), 2), -0.5);
212
        $rho =
213
            $a
214
            * $F0
215 7
            * (1 - $eSquared)
216 7
            * pow(1 - $eSquared * pow(sin($phiPrime), 2), -1.5);
217 7
        $etaSquared = ($v / $rho) - 1;
218 7
        $VII = tan($phiPrime) / (2 * $rho * $v);
219
        $VIII =
220 7
            (tan($phiPrime) / (24 * $rho * pow($v, 3)))
221
            * (5
222 7
                + (3 * pow(tan($phiPrime), 2))
223 7
                + $etaSquared
224 7
                - (9 * pow(tan($phiPrime), 2) * $etaSquared));
225
        $IX =
226 7
            (tan($phiPrime) / (720 * $rho * pow($v, 5)))
227
            * (61
228 7
                + (90 * pow(tan($phiPrime), 2))
229 7
                + (45 * pow(tan($phiPrime), 2) * pow(tan($phiPrime), 2)));
230 7
        $X = (1 / cos($phiPrime)) / $v;
231
        $XI =
232 7
            ((1 / cos($phiPrime)) / (6 * $v * $v * $v))
233 7
            * (($v / $rho) + (2 * pow(tan($phiPrime), 2)));
234
        $XII =
235 7
            ((1 / cos($phiPrime)) / (120 * pow($v, 5)))
236
            * (5
237 7
                + (28 * pow(tan($phiPrime), 2))
238 7
                + (24 * pow(tan($phiPrime), 4)));
239
        $XIIA =
240 7
            ((1 / cos($phiPrime)) / (5040 * pow($v, 7)))
241
            * (61
242 7
                + (662 * pow(tan($phiPrime), 2))
243 7
                + (1320 * pow(tan($phiPrime), 4))
244 7
                + (720
245 7
                    * pow(tan($phiPrime), 6)));
246
        $phi =
247
            $phiPrime
248 7
            - ($VII * pow($E - $E0, 2))
249 7
            + ($VIII * pow($E - $E0, 4))
250 7
            - ($IX * pow($E - $E0, 6));
251
        $lambda =
252
            $lambda0
253 7
            + ($X * ($E - $E0))
254 7
            - ($XI * pow($E - $E0, 3))
255 7
            + ($XII * pow($E - $E0, 5))
256 7
            - ($XIIA * pow($E - $E0, 7));
257
258 7
        return new LatLng(rad2deg($phi), rad2deg($lambda), 0, $refEll);
259
    }
260
261
    /**
262
     * Calculate the surface distance between this object and the one
263
     * passed in as a parameter.
264
     *
265
     * @param self $to object to measure the distance to
0 ignored issues
show
Documentation introduced by
Should the type for parameter $to not be \self?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
266
     * @return float
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|double?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
267
     */
268 1 View Code Duplication
    public function distance(self $to) {
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...
269
270 1
        if ($this->refEll != $to->refEll) {
271
            throw new \RuntimeException('Source and destination co-ordinates are not using the same ellipsoid');
272
        }
273
274
        //Because this is a 2D grid, we can use simple Pythagoras
275 1
        $distanceX = $to->getX()-$this->getX();
276 1
        $distanceY = $to->getY()-$this->getY();
277
278 1
        return pow(pow($distanceX, 2) + pow($distanceY, 2), 0.5);
279
280
    }
281
}
282