| 1001 |
delphine |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
/**
|
|
|
4 |
* Author : Julien Moquet
|
|
|
5 |
*
|
|
|
6 |
* Inspired by Proj4js from Mike Adair madairATdmsolutions.ca
|
|
|
7 |
* and Richard Greenwood rich@greenwoodmap.com
|
|
|
8 |
* License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
|
|
9 |
*/
|
|
|
10 |
class Proj4phpCommon {
|
|
|
11 |
|
|
|
12 |
public $PI = M_PI; #3.141592653589793238; //Math.PI,
|
|
|
13 |
public $HALF_PI = M_PI_2; #1.570796326794896619; //Math.PI*0.5,
|
|
|
14 |
public $TWO_PI = 6.283185307179586477; //Math.PI*2,
|
|
|
15 |
public $FORTPI = 0.78539816339744833;
|
|
|
16 |
public $R2D = 57.29577951308232088;
|
|
|
17 |
public $D2R = 0.01745329251994329577;
|
|
|
18 |
public $SEC_TO_RAD = 4.84813681109535993589914102357e-6; /* SEC_TO_RAD = Pi/180/3600 */
|
|
|
19 |
public $EPSLN = 1.0e-10;
|
|
|
20 |
public $MAX_ITER = 20;
|
|
|
21 |
// following constants from geocent.c
|
|
|
22 |
public $COS_67P5 = 0.38268343236508977; /* cosine of 67.5 degrees */
|
|
|
23 |
public $AD_C = 1.0026000; /* Toms region 1 constant */
|
|
|
24 |
|
|
|
25 |
/* datum_type values */
|
|
|
26 |
public $PJD_UNKNOWN = 0;
|
|
|
27 |
public $PJD_3PARAM = 1;
|
|
|
28 |
public $PJD_7PARAM = 2;
|
|
|
29 |
public $PJD_GRIDSHIFT = 3;
|
|
|
30 |
public $PJD_WGS84 = 4; // WGS84 or equivalent
|
|
|
31 |
public $PJD_NODATUM = 5; // WGS84 or equivalent
|
|
|
32 |
|
|
|
33 |
const SRS_WGS84_SEMIMAJOR = 6378137.0; // only used in grid shift transforms
|
|
|
34 |
|
|
|
35 |
// ellipoid pj_set_ell.c
|
|
|
36 |
|
|
|
37 |
public $SIXTH = .1666666666666666667; /* 1/6 */
|
|
|
38 |
public $RA4 = .04722222222222222222; /* 17/360 */
|
|
|
39 |
public $RA6 = .02215608465608465608; /* 67/3024 */
|
|
|
40 |
public $RV4 = .06944444444444444444; /* 5/72 */
|
|
|
41 |
public $RV6 = .04243827160493827160; /* 55/1296 */
|
|
|
42 |
|
|
|
43 |
|
|
|
44 |
/* meridinal distance for ellipsoid and inverse
|
|
|
45 |
* * 8th degree - accurate to < 1e-5 meters when used in conjuction
|
|
|
46 |
* * with typical major axis values.
|
|
|
47 |
* * Inverse determines phi to EPS (1e-11) radians, about 1e-6 seconds.
|
|
|
48 |
*/
|
|
|
49 |
protected $C00 = 1.0;
|
|
|
50 |
protected $C02 = .25;
|
|
|
51 |
protected $C04 = .046875;
|
|
|
52 |
protected $C06 = .01953125;
|
|
|
53 |
protected $C08 = .01068115234375;
|
|
|
54 |
protected $C22 = .75;
|
|
|
55 |
protected $C44 = .46875;
|
|
|
56 |
protected $C46 = .01302083333333333333;
|
|
|
57 |
protected $C48 = .00712076822916666666;
|
|
|
58 |
protected $C66 = .36458333333333333333;
|
|
|
59 |
protected $C68 = .00569661458333333333;
|
|
|
60 |
protected $C88 = .3076171875;
|
|
|
61 |
|
|
|
62 |
/**
|
|
|
63 |
* Function to compute the constant small m which is the radius of
|
|
|
64 |
* a parallel of latitude, phi, divided by the semimajor axis.
|
|
|
65 |
*
|
|
|
66 |
* @param type $eccent
|
|
|
67 |
* @param type $sinphi
|
|
|
68 |
* @param type $cosphi
|
|
|
69 |
* @return type
|
|
|
70 |
*/
|
|
|
71 |
public function msfnz( $eccent, $sinphi, $cosphi ) {
|
|
|
72 |
|
|
|
73 |
$con = $eccent * $sinphi;
|
|
|
74 |
|
|
|
75 |
return $cosphi / (sqrt( 1.0 - $con * $con ));
|
|
|
76 |
}
|
|
|
77 |
|
|
|
78 |
/**
|
|
|
79 |
* Function to compute the constant small t for use in the forward
|
|
|
80 |
* computations in the Lambert Conformal Conic and the Polar
|
|
|
81 |
* Stereographic projections.
|
|
|
82 |
*
|
|
|
83 |
* @param type $eccent
|
|
|
84 |
* @param type $phi
|
|
|
85 |
* @param type $sinphi
|
|
|
86 |
* @return type
|
|
|
87 |
*/
|
|
|
88 |
public function tsfnz( $eccent, $phi, $sinphi ) {
|
|
|
89 |
|
|
|
90 |
$con = $eccent * $sinphi;
|
|
|
91 |
$com = 0.5 * $eccent;
|
|
|
92 |
$con = pow( ((1.0 - $con) / (1.0 + $con) ), $com );
|
|
|
93 |
|
|
|
94 |
return (tan( .5 * (M_PI_2 - $phi) ) / $con);
|
|
|
95 |
}
|
|
|
96 |
|
|
|
97 |
/**
|
|
|
98 |
* Function to compute the latitude angle, phi2, for the inverse of the
|
|
|
99 |
* Lambert Conformal Conic and Polar Stereographic projections.
|
|
|
100 |
*
|
|
|
101 |
* rise up an assertion if there is no convergence.
|
|
|
102 |
*
|
|
|
103 |
* @param type $eccent
|
|
|
104 |
* @param type $ts
|
|
|
105 |
* @return type
|
|
|
106 |
*/
|
|
|
107 |
public function phi2z( $eccent, $ts ) {
|
|
|
108 |
|
|
|
109 |
$eccnth = .5 * $eccent;
|
|
|
110 |
$phi = M_PI_2 - 2 * atan( $ts );
|
|
|
111 |
|
|
|
112 |
for( $i = 0; $i <= 15; $i++ ) {
|
|
|
113 |
$con = $eccent * sin( $phi );
|
|
|
114 |
$dphi = M_PI_2 - 2 * atan( $ts * (pow( ((1.0 - $con) / (1.0 + $con) ), $eccnth )) ) - $phi;
|
|
|
115 |
$phi += $dphi;
|
|
|
116 |
if( abs( $dphi ) <= .0000000001 )
|
|
|
117 |
return $phi;
|
|
|
118 |
}
|
|
|
119 |
assert( "false; /* phi2z has NoConvergence */" );
|
|
|
120 |
|
|
|
121 |
return (-9999);
|
|
|
122 |
}
|
|
|
123 |
|
|
|
124 |
/**
|
|
|
125 |
* Function to compute constant small q which is the radius of a
|
|
|
126 |
* parallel of latitude, phi, divided by the semimajor axis.
|
|
|
127 |
*
|
|
|
128 |
* @param type $eccent
|
|
|
129 |
* @param type $sinphi
|
|
|
130 |
* @return type
|
|
|
131 |
*/
|
|
|
132 |
public function qsfnz( $eccent, $sinphi ) {
|
|
|
133 |
|
|
|
134 |
if( $eccent > 1.0e-7 ) {
|
|
|
135 |
|
|
|
136 |
$con = $eccent * $sinphi;
|
|
|
137 |
|
|
|
138 |
return (( 1.0 - $eccent * $eccent) * ($sinphi / (1.0 - $con * $con) - (.5 / $eccent) * log( (1.0 - $con) / (1.0 + $con) )));
|
|
|
139 |
}
|
|
|
140 |
|
|
|
141 |
return (2.0 * $sinphi);
|
|
|
142 |
}
|
|
|
143 |
|
|
|
144 |
/**
|
|
|
145 |
* Function to eliminate roundoff errors in asin
|
|
|
146 |
*
|
|
|
147 |
* @param type $x
|
|
|
148 |
* @return type
|
|
|
149 |
*/
|
|
|
150 |
public function asinz( $x ) {
|
|
|
151 |
|
|
|
152 |
return asin(
|
|
|
153 |
abs( $x ) > 1.0 ? ($x > 1.0 ? 1.0 : -1.0) : $x
|
|
|
154 |
);
|
|
|
155 |
|
|
|
156 |
#if( abs( $x ) > 1.0 ) {
|
|
|
157 |
# $x = ($x > 1.0) ? 1.0 : -1.0;
|
|
|
158 |
#}
|
|
|
159 |
#return asin( $x );
|
|
|
160 |
}
|
|
|
161 |
|
|
|
162 |
/**
|
|
|
163 |
* following functions from gctpc cproj.c for transverse mercator projections
|
|
|
164 |
*
|
|
|
165 |
* @param type $x
|
|
|
166 |
* @return type
|
|
|
167 |
*/
|
|
|
168 |
public function e0fn( $x ) {
|
|
|
169 |
return (1.0 - 0.25 * $x * (1.0 + $x / 16.0 * (3.0 + 1.25 * $x)));
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
/**
|
|
|
173 |
*
|
|
|
174 |
* @param type $x
|
|
|
175 |
* @return type
|
|
|
176 |
*/
|
|
|
177 |
public function e1fn( $x ) {
|
|
|
178 |
return (0.375 * $x * (1.0 + 0.25 * $x * (1.0 + 0.46875 * $x)));
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
/**
|
|
|
182 |
*
|
|
|
183 |
* @param type $x
|
|
|
184 |
* @return type
|
|
|
185 |
*/
|
|
|
186 |
public function e2fn( $x ) {
|
|
|
187 |
return (0.05859375 * $x * $x * (1.0 + 0.75 * $x));
|
|
|
188 |
}
|
|
|
189 |
|
|
|
190 |
/**
|
|
|
191 |
*
|
|
|
192 |
* @param type $x
|
|
|
193 |
* @return type
|
|
|
194 |
*/
|
|
|
195 |
public function e3fn( $x ) {
|
|
|
196 |
return ($x * $x * $x * (35.0 / 3072.0));
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
/**
|
|
|
200 |
*
|
|
|
201 |
* @param type $e0
|
|
|
202 |
* @param type $e1
|
|
|
203 |
* @param type $e2
|
|
|
204 |
* @param type $e3
|
|
|
205 |
* @param type $phi
|
|
|
206 |
* @return type
|
|
|
207 |
*/
|
|
|
208 |
public function mlfn( $e0, $e1, $e2, $e3, $phi ) {
|
|
|
209 |
return ($e0 * $phi - $e1 * sin( 2.0 * $phi ) + $e2 * sin( 4.0 * $phi ) - $e3 * sin( 6.0 * $phi ));
|
|
|
210 |
}
|
|
|
211 |
|
|
|
212 |
/**
|
|
|
213 |
*
|
|
|
214 |
* @param type $esinp
|
|
|
215 |
* @param type $exp
|
|
|
216 |
* @return type
|
|
|
217 |
*/
|
|
|
218 |
public function srat( $esinp, $exp ) {
|
|
|
219 |
return (pow( (1.0 - $esinp) / (1.0 + $esinp), $exp ));
|
|
|
220 |
}
|
|
|
221 |
|
|
|
222 |
/**
|
|
|
223 |
* Function to return the sign of an argument
|
|
|
224 |
*
|
|
|
225 |
* @param type $x
|
|
|
226 |
* @return type
|
|
|
227 |
*/
|
|
|
228 |
public function sign( $x ) {
|
|
|
229 |
|
|
|
230 |
return $x < 0.0 ? -1 : 1;
|
|
|
231 |
}
|
|
|
232 |
|
|
|
233 |
/**
|
|
|
234 |
* Function to adjust longitude to -180 to 180; input in radians
|
|
|
235 |
*
|
|
|
236 |
* @param type $x
|
|
|
237 |
* @return type
|
|
|
238 |
*/
|
|
|
239 |
public function adjust_lon( $x ) {
|
|
|
240 |
|
|
|
241 |
return (abs( $x ) < M_PI) ? $x : ($x - ($this->sign( $x ) * $this->TWO_PI) );
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
/**
|
|
|
245 |
* IGNF - DGR : algorithms used by IGN France
|
|
|
246 |
* Function to adjust latitude to -90 to 90; input in radians
|
|
|
247 |
*
|
|
|
248 |
* @param type $x
|
|
|
249 |
* @return type
|
|
|
250 |
*/
|
|
|
251 |
public function adjust_lat( $x ) {
|
|
|
252 |
|
|
|
253 |
$x = (abs( $x ) < M_PI_2) ? $x : ($x - ($this->sign( $x ) * M_PI) );
|
|
|
254 |
|
|
|
255 |
return $x;
|
|
|
256 |
}
|
|
|
257 |
|
|
|
258 |
/**
|
|
|
259 |
* Latitude Isometrique - close to tsfnz ...
|
|
|
260 |
*
|
|
|
261 |
* @param type $eccent
|
|
|
262 |
* @param float $phi
|
|
|
263 |
* @param type $sinphi
|
|
|
264 |
* @return string
|
|
|
265 |
*/
|
|
|
266 |
public function latiso( $eccent, $phi, $sinphi ) {
|
|
|
267 |
|
|
|
268 |
if( abs( $phi ) > M_PI_2 )
|
|
|
269 |
return +NaN;
|
|
|
270 |
if( $phi == M_PI_2 )
|
|
|
271 |
return INF;
|
|
|
272 |
if( $phi == -1.0 * M_PI_2 )
|
|
|
273 |
return -1.0 * INF;
|
|
|
274 |
|
|
|
275 |
$con = $eccent * $sinphi;
|
|
|
276 |
|
|
|
277 |
return log( tan( (M_PI_2 + $phi) / 2.0 ) ) + $eccent * log( (1.0 - $con) / (1.0 + $con) ) / 2.0;
|
|
|
278 |
}
|
|
|
279 |
|
|
|
280 |
/**
|
|
|
281 |
*
|
|
|
282 |
* @param type $x
|
|
|
283 |
* @param type $L
|
|
|
284 |
* @return type
|
|
|
285 |
*/
|
|
|
286 |
public function fL( $x, $L ) {
|
|
|
287 |
return 2.0 * atan( $x * exp( $L ) ) - M_PI_2;
|
|
|
288 |
}
|
|
|
289 |
|
|
|
290 |
/**
|
|
|
291 |
* Inverse Latitude Isometrique - close to ph2z
|
|
|
292 |
*
|
|
|
293 |
* @param type $eccent
|
|
|
294 |
* @param type $ts
|
|
|
295 |
* @return type
|
|
|
296 |
*/
|
|
|
297 |
public function invlatiso( $eccent, $ts ) {
|
|
|
298 |
|
|
|
299 |
$phi = $this->fL( 1.0, $ts );
|
|
|
300 |
$Iphi = 0.0;
|
|
|
301 |
$con = 0.0;
|
|
|
302 |
|
|
|
303 |
do {
|
|
|
304 |
$Iphi = $phi;
|
|
|
305 |
$con = $eccent * sin( $Iphi );
|
|
|
306 |
$phi = $this->fL( exp( $eccent * log( (1.0 + $con) / (1.0 - $con) ) / 2.0 ), $ts );
|
|
|
307 |
} while( abs( $phi - $Iphi ) > 1.0e-12 );
|
|
|
308 |
|
|
|
309 |
return $phi;
|
|
|
310 |
}
|
|
|
311 |
|
|
|
312 |
/**
|
|
|
313 |
* Grande Normale
|
|
|
314 |
*
|
|
|
315 |
* @param type $a
|
|
|
316 |
* @param type $e
|
|
|
317 |
* @param type $sinphi
|
|
|
318 |
* @return type
|
|
|
319 |
*/
|
|
|
320 |
public function gN( $a, $e, $sinphi ) {
|
|
|
321 |
$temp = $e * $sinphi;
|
|
|
322 |
return $a / sqrt( 1.0 - $temp * $temp );
|
|
|
323 |
}
|
|
|
324 |
|
|
|
325 |
/**
|
|
|
326 |
* code from the PROJ.4 pj_mlfn.c file; this may be useful for other projections
|
|
|
327 |
*
|
|
|
328 |
* @param type $es
|
|
|
329 |
* @return type
|
|
|
330 |
*/
|
|
|
331 |
public function pj_enfn( $es ) {
|
|
|
332 |
|
|
|
333 |
$en = array( );
|
|
|
334 |
$en[0] = $this->C00 - $es * ($this->C02 + $es * ($this->C04 + $es * ($this->C06 + $es * $this->C08)));
|
|
|
335 |
$en[1] = es * ($this->C22 - $es * ($this->C04 + $es * ($this->C06 + $es * $this->C08)));
|
|
|
336 |
$t = $es * $es;
|
|
|
337 |
$en[2] = $t * ($this->C44 - $es * ($this->C46 + $es * $this->C48));
|
|
|
338 |
$t *= $es;
|
|
|
339 |
$en[3] = $t * ($this->C66 - $es * $this->C68);
|
|
|
340 |
$en[4] = $t * $es * $this->C88;
|
|
|
341 |
|
|
|
342 |
return $en;
|
|
|
343 |
}
|
|
|
344 |
|
|
|
345 |
/**
|
|
|
346 |
*
|
|
|
347 |
* @param type $phi
|
|
|
348 |
* @param type $sphi
|
|
|
349 |
* @param type $cphi
|
|
|
350 |
* @param type $en
|
|
|
351 |
* @return type
|
|
|
352 |
*/
|
|
|
353 |
public function pj_mlfn( $phi, $sphi, $cphi, $en ) {
|
|
|
354 |
|
|
|
355 |
$cphi *= $sphi;
|
|
|
356 |
$sphi *= $sphi;
|
|
|
357 |
|
|
|
358 |
return ($en[0] * $phi - $cphi * ($en[1] + $sphi * ($en[2] + $sphi * ($en[3] + $sphi * $en[4]))));
|
|
|
359 |
}
|
|
|
360 |
|
|
|
361 |
/**
|
|
|
362 |
*
|
|
|
363 |
* @param type $arg
|
|
|
364 |
* @param type $es
|
|
|
365 |
* @param type $en
|
|
|
366 |
* @return type
|
|
|
367 |
*/
|
|
|
368 |
public function pj_inv_mlfn( $arg, $es, $en ) {
|
|
|
369 |
|
|
|
370 |
$k = (float) 1 / (1 - $es);
|
|
|
371 |
$phi = $arg;
|
|
|
372 |
|
|
|
373 |
for( $i = Proj4php::$common->MAX_ITER; $i; --$i ) { /* rarely goes over 2 iterations */
|
|
|
374 |
$s = sin( $phi );
|
|
|
375 |
$t = 1. - $es * $s * $s;
|
|
|
376 |
//$t = $this->pj_mlfn($phi, $s, cos($phi), $en) - $arg;
|
|
|
377 |
//$phi -= $t * ($t * sqrt($t)) * $k;
|
|
|
378 |
$t = ($this->pj_mlfn( $phi, $s, cos( $phi ), $en ) - $arg) * ($t * sqrt( $t )) * $k;
|
|
|
379 |
$phi -= $t;
|
|
|
380 |
if( abs( $t ) < Proj4php::$common->EPSLN )
|
|
|
381 |
return $phi;
|
|
|
382 |
}
|
|
|
383 |
|
|
|
384 |
Proj4php::reportError( "cass:pj_inv_mlfn: Convergence error" );
|
|
|
385 |
|
|
|
386 |
return $phi;
|
|
|
387 |
}
|
|
|
388 |
|
|
|
389 |
}
|