Skip to content

Commit 2b54166

Browse files
author
Nathaniel McHugh
committed
* converts from polar to cartesian based on Airy 1830
* converts from cartesian to polar based on Airy 1830 * need to handle different ellipsoids
1 parent 8677e05 commit 2b54166

File tree

5 files changed

+110
-3
lines changed

5 files changed

+110
-3
lines changed

geospatial.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,26 @@ ZEND_BEGIN_ARG_INFO_EX(helmert_args, 0, 0, 3)
4141
ZEND_ARG_INFO(0, z)
4242
ZEND_END_ARG_INFO()
4343

44+
ZEND_BEGIN_ARG_INFO_EX(polar_to_cartesian_args, 0, 0, 2)
45+
ZEND_ARG_INFO(0, latitude)
46+
ZEND_ARG_INFO(0, longitude)
47+
ZEND_END_ARG_INFO()
48+
49+
ZEND_BEGIN_ARG_INFO_EX(cartesian_to_polar_args, 0, 0, 3)
50+
ZEND_ARG_INFO(0, x)
51+
ZEND_ARG_INFO(0, y)
52+
ZEND_ARG_INFO(0, z)
53+
ZEND_END_ARG_INFO()
54+
4455
/* {{{ geospatial_functions[]
4556
*
4657
* Every user visible function must have an entry in geospatial_functions[].
4758
*/
4859
const zend_function_entry geospatial_functions[] = {
4960
PHP_FE(haversine, haversine_args)
5061
PHP_FE(helmert, helmert_args)
62+
PHP_FE(polar_to_cartesian, polar_to_cartesian_args)
63+
PHP_FE(cartesian_to_polar, cartesian_to_polar_args)
5164
/* End of functions */
5265
{ NULL, NULL, NULL }
5366
};
@@ -145,6 +158,61 @@ PHP_FUNCTION(helmert)
145158
add_next_index_double(return_value, zOut);
146159
}
147160

161+
PHP_FUNCTION(polar_to_cartesian)
162+
{
163+
double latitude, longitude;
164+
double x, y, z;
165+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &latitude, &longitude) == FAILURE) {
166+
return;
167+
}
168+
169+
array_init(return_value);
170+
double phi = latitude * GEO_DEG_TO_RAD;
171+
double lambda = longitude * GEO_DEG_TO_RAD;
172+
double eSq = ((AIRY_1830_A * AIRY_1830_A) - (AIRY_1830_B * AIRY_1830_B)) / (AIRY_1830_A * AIRY_1830_A);
173+
double nu = AIRY_1830_A / sqrt(1 - (eSq * sin(phi) * sin(phi)));
174+
x = nu + HEIGHT;
175+
x *= cos(phi) * cos(lambda);
176+
y = nu + HEIGHT;
177+
y *= cos(phi) * sin(lambda);
178+
z = ((1 - eSq) * nu) + HEIGHT;
179+
z*= sin(phi);
180+
add_next_index_double(return_value, x);
181+
add_next_index_double(return_value, y);
182+
add_next_index_double(return_value, z);
183+
184+
}
185+
186+
PHP_FUNCTION(cartesian_to_polar)
187+
{
188+
double latitude, longitude;
189+
double x, y, z;
190+
double nu, lambda, h;
191+
192+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ddd", &x, &y, &z) == FAILURE) {
193+
return;
194+
}
195+
//aiming for 1m accuracy
196+
double precision = 0.1 / AIRY_1830_A;
197+
array_init(return_value);
198+
double eSq = ((AIRY_1830_A * AIRY_1830_A) - (AIRY_1830_B * AIRY_1830_B)) / (AIRY_1830_A * AIRY_1830_A);
199+
double p = sqrt(x * x + y * y);
200+
double phi = atan2(z, p * (1 - eSq));
201+
double phiP = 2 * M_PI;
202+
while (abs(phi - phiP) > precision) {
203+
nu = AIRY_1830_A / sqrt(1 - eSq * sin(phi) * sin(phi));
204+
phiP = phi;
205+
phi = atan2(z + eSq * nu * sin(phi), p);
206+
}
207+
lambda = atan2(y ,x);
208+
h = p / cos(phi) - nu;
209+
210+
add_assoc_double(return_value, "lat", phi / GEO_DEG_TO_RAD);
211+
add_assoc_double(return_value, "long", lambda / GEO_DEG_TO_RAD);
212+
add_assoc_double(return_value, "height", h);
213+
214+
}
215+
148216
/* {{{ proto haversine(double fromLat, double fromLong, double toLat, double toLong [, double radius ])
149217
* Calculates the greater circle distance between the two lattitude/longitude pairs */
150218
PHP_FUNCTION(haversine)

php_geospatial.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,16 @@ extern zend_module_entry geospatial_module_entry;
5656
#define ROTATION_Y -0.2470;
5757
#define ROTATION_Z -0.8421;
5858

59+
#define HEIGHT 24.7;
60+
5961

6062
PHP_MINIT_FUNCTION(geospatial);
6163
PHP_MINFO_FUNCTION(geospatial);
6264

6365
PHP_FUNCTION(haversine);
6466
PHP_FUNCTION(helmert);
67+
PHP_FUNCTION(polar_to_cartesian);
68+
PHP_FUNCTION(cartesian_to_polar);
6569

6670
#endif /* PHP_GEOSPATIAL_H */
6771

tests/cartesian_to_polar.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test polar to cartesian
3+
--FILE--
4+
<?php
5+
$x = 3810891.6734396;
6+
$y = 97591.624686311;
7+
$z = 5095766.3939034;
8+
9+
$polar = cartesian_to_polar($x, $y, $z);
10+
echo round($polar['lat'] ,6),PHP_EOL;
11+
echo round($polar['long'] ,6),PHP_EOL;
12+
echo round($polar['height'] ,3),PHP_EOL;
13+
?>
14+
--EXPECT--
15+
53.383611
16+
1.466944
17+
24.7

tests/helmert.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ var_dump(helmert($x, $y, $z));
1111
--EXPECT--
1212
array(3) {
1313
[0]=>
14-
float(3909460.068)
14+
float(3909460.0676711)
1515
[1]=>
16-
float(-146987.30)
16+
float(-146987.30138174)
1717
[2]=>
18-
float(5019888.07)
18+
float(5019888.0705933)
1919
}

tests/polar_to_cartesian.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Test polar to cartesian
3+
--FILE--
4+
<?php
5+
$lat = 53.38361111111;
6+
$long = 1.4669444444;
7+
8+
var_dump(polar_to_cartesian($lat, $long));
9+
?>
10+
--EXPECT--
11+
array(3) {
12+
[0]=>
13+
float(3810891.6734396)
14+
[1]=>
15+
float(97591.624686311)
16+
[2]=>
17+
float(5095766.3939034)
18+
}

0 commit comments

Comments
 (0)