Completed
Push — master ( 3c4a39...ba1925 )
by Doug
02:35
created

TransverseMercator::getReferenceEllipsoid()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 1
nc 1
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
    public function __construct($x, $y, $h, RefEll $refEll)
50
    {
51
        $this->setX($x);
52
        $this->setY($y);
53
        $this->setH($h);
54
        $this->setRefEll($refEll);
55
    }
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
    public function getX()
70
    {
71
        return $this->x;
72
    }
73
74
    /**
75
     * @param float $x
76
     */
77
    public function setX($x)
78
    {
79
        $this->x = $x;
80
    }
81
82
    /**
83
     * @return float
84
     */
85
    public function getY()
86
    {
87
        return $this->y;
88
    }
89
90
    /**
91
     * @param float $y
92
     */
93
    public function setY($y)
94
    {
95
        $this->y = $y;
96
    }
97
98
    /**
99
     * @return float
100
     */
101
    public function getH()
102
    {
103
        return $this->h;
104
    }
105
106
    /**
107
     * @param float $h
108
     */
109
    public function setH($h)
110
    {
111
        $this->h = $h;
112
    }
113
114
    /**
115
     * @return RefEll
116
     */
117
    public function getRefEll()
118
    {
119
        return $this->refEll;
120
    }
121
122
    /**
123
     * @param RefEll $refEll
124
     */
125
    public function setRefEll(RefEll $refEll)
126
    {
127
        $this->refEll = $refEll;
128
    }
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
    public function convertToLatitudeLongitude($N, $E, $N0, $E0, $phi0, $lambda0)
181
    {
182
183
        $phi0 = deg2rad($phi0);
184
        $lambda0 = deg2rad($lambda0);
185
186
        $refEll = $this->getReferenceEllipsoid();
187
        $F0 = $this->getScaleFactor();
188
189
        $a = $refEll->getMaj();
190
        $b = $refEll->getMin();
191
        $eSquared = $refEll->getEcc();
192
        $n = ($a - $b) / ($a + $b);
193
        $phiPrime = (($N - $N0) / ($a * $F0)) + $phi0;
194
195
        do {
196
            $M =
197
                ($b * $F0)
198
                * (((1 + $n + ((5 / 4) * $n * $n) + ((5 / 4) * $n * $n * $n))
199
                        * ($phiPrime - $phi0))
200
                    - (((3 * $n) + (3 * $n * $n) + ((21 / 8) * $n * $n * $n))
201
                        * sin($phiPrime - $phi0)
202
                        * cos($phiPrime + $phi0))
203
                    + ((((15 / 8) * $n * $n) + ((15 / 8) * $n * $n * $n))
204
                        * sin(2 * ($phiPrime - $phi0))
205
                        * cos(2 * ($phiPrime + $phi0)))
206
                    - (((35 / 24) * $n * $n * $n)
207
                        * sin(3 * ($phiPrime - $phi0))
208
                        * cos(3 * ($phiPrime + $phi0))));
209
            $phiPrime += ($N - $N0 - $M) / ($a * $F0);
210
        } while (($N - $N0 - $M) >= 0.001);
211
        $v = $a * $F0 * pow(1 - $eSquared * pow(sin($phiPrime), 2), -0.5);
212
        $rho =
213
            $a
214
            * $F0
215
            * (1 - $eSquared)
216
            * pow(1 - $eSquared * pow(sin($phiPrime), 2), -1.5);
217
        $etaSquared = ($v / $rho) - 1;
218
        $VII = tan($phiPrime) / (2 * $rho * $v);
219
        $VIII =
220
            (tan($phiPrime) / (24 * $rho * pow($v, 3)))
221
            * (5
222
                + (3 * pow(tan($phiPrime), 2))
223
                + $etaSquared
224
                - (9 * pow(tan($phiPrime), 2) * $etaSquared));
225
        $IX =
226
            (tan($phiPrime) / (720 * $rho * pow($v, 5)))
227
            * (61
228
                + (90 * pow(tan($phiPrime), 2))
229
                + (45 * pow(tan($phiPrime), 2) * pow(tan($phiPrime), 2)));
230
        $X = (1 / cos($phiPrime)) / $v;
231
        $XI =
232
            ((1 / cos($phiPrime)) / (6 * $v * $v * $v))
233
            * (($v / $rho) + (2 * pow(tan($phiPrime), 2)));
234
        $XII =
235
            ((1 / cos($phiPrime)) / (120 * pow($v, 5)))
236
            * (5
237
                + (28 * pow(tan($phiPrime), 2))
238
                + (24 * pow(tan($phiPrime), 4)));
239
        $XIIA =
240
            ((1 / cos($phiPrime)) / (5040 * pow($v, 7)))
241
            * (61
242
                + (662 * pow(tan($phiPrime), 2))
243
                + (1320 * pow(tan($phiPrime), 4))
244
                + (720
245
                    * pow(tan($phiPrime), 6)));
246
        $phi =
247
            $phiPrime
248
            - ($VII * pow($E - $E0, 2))
249
            + ($VIII * pow($E - $E0, 4))
250
            - ($IX * pow($E - $E0, 6));
251
        $lambda =
252
            $lambda0
253
            + ($X * ($E - $E0))
254
            - ($XI * pow($E - $E0, 3))
255
            + ($XII * pow($E - $E0, 5))
256
            - ($XIIA * pow($E - $E0, 7));
257
258
        return new LatLng(rad2deg($phi), rad2deg($lambda), 0, $refEll);
259
    }
260
}
261