Skip to content

Commit b156736

Browse files
author
Nathaniel McHugh
committed
* trasform polar to cartesian co-ords
* transform caresian to polar co-ords * clean up code of helmert a lot * by combining output can transform between datums * -1 error with height * next step is to move these php functuons to C functions and create convert datum PHP function and wrappers
1 parent 2b54166 commit b156736

File tree

6 files changed

+103
-56
lines changed

6 files changed

+103
-56
lines changed

geospatial.c

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ 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)
44+
ZEND_BEGIN_ARG_INFO_EX(polar_to_cartesian_args, 0, 0, 3)
4545
ZEND_ARG_INFO(0, latitude)
4646
ZEND_ARG_INFO(0, longitude)
47+
ZEND_ARG_INFO(0, reference_ellipsoid)
4748
ZEND_END_ARG_INFO()
4849

49-
ZEND_BEGIN_ARG_INFO_EX(cartesian_to_polar_args, 0, 0, 3)
50+
ZEND_BEGIN_ARG_INFO_EX(cartesian_to_polar_args, 0, 0, 4)
5051
ZEND_ARG_INFO(0, x)
5152
ZEND_ARG_INFO(0, y)
5253
ZEND_ARG_INFO(0, z)
54+
ZEND_ARG_INFO(0, reference_ellipsoid)
5355
ZEND_END_ARG_INFO()
5456

5557
/* {{{ geospatial_functions[]
@@ -95,7 +97,9 @@ ZEND_GET_MODULE(geospatial)
9597
PHP_MINIT_FUNCTION(geospatial)
9698
{
9799
REGISTER_DOUBLE_CONSTANT("GEO_DEG_TO_RAD", GEO_DEG_TO_RAD, CONST_CS | CONST_PERSISTENT);
98-
REGISTER_DOUBLE_CONSTANT("GEO_EARTH_RADIUS", GEO_EARTH_RADIUS, CONST_CS | CONST_PERSISTENT);
100+
REGISTER_DOUBLE_CONSTANT("GEO_EARTH_RADIUS", GEO_EARTH_RADIUS, CONST_CS | CONST_PERSISTENT);
101+
REGISTER_LONG_CONSTANT("GEO_AIRY_1830", GEO_AIRY_1830, CONST_CS | CONST_PERSISTENT);
102+
REGISTER_LONG_CONSTANT("GEO_WGS84", GEO_WGS84, CONST_CS | CONST_PERSISTENT);
99103
return SUCCESS;
100104
}
101105
/* }}} */
@@ -129,73 +133,71 @@ PHP_FUNCTION(helmert)
129133
}
130134

131135
array_init(return_value);
132-
rX = ROTATION_X;
133-
rX /= 3600;
134-
rX *= GEO_DEG_TO_RAD;
136+
rX = ROTATION_X / GEO_SEC_IN_DEG * GEO_DEG_TO_RAD;
137+
rY = ROTATION_Y / GEO_SEC_IN_DEG * GEO_DEG_TO_RAD;
138+
rZ = ROTATION_Z / GEO_SEC_IN_DEG * GEO_DEG_TO_RAD;
135139

136-
rY = ROTATION_Y;
137-
rY /= 3600;
138-
rY *= GEO_DEG_TO_RAD;
140+
xOut = WGS84_OSGB36_X;
141+
xOut += (x - (rZ * y) + (rY * z)) * SCALE_CHANGE;
139142

140-
rZ = ROTATION_Z;
141-
rZ /= 3600;
142-
rZ *= GEO_DEG_TO_RAD;
143+
yOut = WGS84_OSGB36_Y;
144+
yOut += ((rZ * x) + y - (rX * z)) * SCALE_CHANGE;
143145

144-
xOut = x - (rZ * y) + (rY * z);
145-
xOut *= SCALE_CHANGE;
146-
xOut += WGS84_OSGB36_X;
146+
zOut = WGS84_OSGB36_Z;
147+
zOut += ((-1 * rY * x) + (rX * y) + z) * SCALE_CHANGE;
147148

148-
yOut = (rZ * x) + y - (rX * z);
149-
yOut *= SCALE_CHANGE;
150-
yOut += WGS84_OSGB36_Y;
151-
152-
zOut = (-rY * x) + (rX * y) + z;
153-
zOut *= SCALE_CHANGE;
154-
zOut += WGS84_OSGB36_Z;
155-
156-
add_next_index_double(return_value, xOut);
157-
add_next_index_double(return_value, yOut);
158-
add_next_index_double(return_value, zOut);
149+
add_assoc_double(return_value, "x", xOut);
150+
add_assoc_double(return_value, "y", yOut);
151+
add_assoc_double(return_value, "z", zOut);
159152
}
160153

161154
PHP_FUNCTION(polar_to_cartesian)
162155
{
163156
double latitude, longitude;
164157
double x, y, z;
165-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &latitude, &longitude) == FAILURE) {
158+
long reference_ellipsoid;
159+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd|l", &latitude, &longitude, &reference_ellipsoid) == FAILURE) {
166160
return;
167161
}
168-
162+
geo_ellipsoid eli = {WGS84_A, WGS84_B};
163+
if (reference_ellipsoid == GEO_AIRY_1830) {
164+
eli.a = AIRY_1830_A;
165+
eli.b = AIRY_1830_B;
166+
}
169167
array_init(return_value);
170168
double phi = latitude * GEO_DEG_TO_RAD;
171169
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)));
170+
double eSq = ((eli.a * eli.a) - (eli.b * eli.b)) / (eli.a * eli.a);
171+
double nu = eli.a / sqrt(1 - (eSq * sin(phi) * sin(phi)));
174172
x = nu + HEIGHT;
175173
x *= cos(phi) * cos(lambda);
176174
y = nu + HEIGHT;
177175
y *= cos(phi) * sin(lambda);
178176
z = ((1 - eSq) * nu) + HEIGHT;
179177
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-
178+
add_assoc_double(return_value, "x", x);
179+
add_assoc_double(return_value, "y", y);
180+
add_assoc_double(return_value, "z", z);
184181
}
185182

186183
PHP_FUNCTION(cartesian_to_polar)
187184
{
188185
double latitude, longitude;
189186
double x, y, z;
190187
double nu, lambda, h;
191-
192-
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ddd", &x, &y, &z) == FAILURE) {
188+
long reference_ellipsoid;
189+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ddd|l", &x, &y, &z, &reference_ellipsoid) == FAILURE) {
193190
return;
194191
}
192+
geo_ellipsoid eli = {WGS84_A, WGS84_B};
193+
if (reference_ellipsoid == GEO_AIRY_1830) {
194+
eli.a = AIRY_1830_A;
195+
eli.b = AIRY_1830_B;
196+
}
195197
//aiming for 1m accuracy
196-
double precision = 0.1 / AIRY_1830_A;
198+
double precision = 0.1 / eli.a;
197199
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);
200+
double eSq = ((eli.a * eli.a) - (eli.b * eli.b)) / (eli.a * eli.a);
199201
double p = sqrt(x * x + y * y);
200202
double phi = atan2(z, p * (1 - eSq));
201203
double phiP = 2 * M_PI;
@@ -210,7 +212,6 @@ PHP_FUNCTION(cartesian_to_polar)
210212
add_assoc_double(return_value, "lat", phi / GEO_DEG_TO_RAD);
211213
add_assoc_double(return_value, "long", lambda / GEO_DEG_TO_RAD);
212214
add_assoc_double(return_value, "height", h);
213-
214215
}
215216

216217
/* {{{ proto haversine(double fromLat, double fromLong, double toLat, double toLong [, double radius ])

php_geospatial.h

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,46 @@ extern zend_module_entry geospatial_module_entry;
3636
#include "TSRM.h"
3737
#endif
3838

39+
typedef struct {
40+
double latitude;
41+
double longitude;
42+
} latLong;
43+
44+
typedef struct {
45+
double a;
46+
double b;
47+
} geo_ellipsoid;
48+
49+
3950
#define GEO_DEG_TO_RAD 0.017453292519943295769236907684886
4051
/**
4152
* Calculate the radius using WGS-84's equatorial radius of
4253
* 6,378,1370m
4354
*/
4455
#define GEO_EARTH_RADIUS 6378.137
56+
#define GEO_SEC_IN_DEG 3600
57+
58+
#define GEO_WGS84 0x0001
59+
#define GEO_AIRY_1830 0x0002
60+
4561

4662
#define AIRY_1830_A 6377563.396
4763
#define AIRY_1830_B 6356256.910
4864

49-
#define WGS84_OSGB36_X -446.448;
50-
#define WGS84_OSGB36_Y 125.157;
51-
#define WGS84_OSGB36_Z -542.060;
65+
#define WGS84_A 6378137.000
66+
#define WGS84_B 6356752.3142
67+
68+
#define WGS84_OSGB36_X -446.448
69+
#define WGS84_OSGB36_Y 125.157
70+
#define WGS84_OSGB36_Z -542.060
5271

53-
#define SCALE_CHANGE 1.0000204894;
72+
#define SCALE_CHANGE 1.0000204894
5473

55-
#define ROTATION_X -0.1502;
56-
#define ROTATION_Y -0.2470;
57-
#define ROTATION_Z -0.8421;
74+
#define ROTATION_X -0.1502
75+
#define ROTATION_Y -0.2470
76+
#define ROTATION_Z -0.8421
5877

59-
#define HEIGHT 24.7;
78+
#define HEIGHT 24.7
6079

6180

6281
PHP_MINIT_FUNCTION(geospatial);

tests/WGS84_to_OSGB36.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
WGS84 to OSGB36
3+
--FILE--
4+
<?php
5+
6+
function getDecimal($d, $m, $s) {
7+
$mul = $d < 0 ? -1 : 1;
8+
return $mul * (abs($d)+ $m / 60 + $s /3600);
9+
}
10+
11+
$lat = getDecimal(53, 23, 1);
12+
$long = getDecimal(-1, 28, 1);
13+
14+
extract(polar_to_cartesian($lat, $long, GEO_WGS84));
15+
extract(helmert($x, $y, $z));
16+
17+
$polar = cartesian_to_polar($x, $y, $z, GEO_AIRY_1830);
18+
var_dump($polar);
19+
--EXPECT--
20+
array(3) {
21+
["lat"]=>
22+
float(53.38334018402)
23+
["long"]=>
24+
float(-1.4654162848544)
25+
["height"]=>
26+
float(24.780265408568)
27+
}

tests/cartesian_to_polar.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
--TEST--
2-
Test polar to cartesian
2+
Test cartesian to polar
33
--FILE--
44
<?php
55
$x = 3810891.6734396;
66
$y = 97591.624686311;
77
$z = 5095766.3939034;
88

9-
$polar = cartesian_to_polar($x, $y, $z);
9+
$polar = cartesian_to_polar($x, $y, $z, GEO_AIRY_1830);
1010
echo round($polar['lat'] ,6),PHP_EOL;
1111
echo round($polar['long'] ,6),PHP_EOL;
1212
echo round($polar['height'] ,3),PHP_EOL;

tests/helmert.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ var_dump(helmert($x, $y, $z));
1010
?>
1111
--EXPECT--
1212
array(3) {
13-
[0]=>
13+
["x"]=>
1414
float(3909460.0676711)
15-
[1]=>
15+
["y"]=>
1616
float(-146987.30138174)
17-
[2]=>
17+
["z"]=>
1818
float(5019888.0705933)
1919
}

tests/polar_to_cartesian.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ Test polar to cartesian
55
$lat = 53.38361111111;
66
$long = 1.4669444444;
77

8-
var_dump(polar_to_cartesian($lat, $long));
8+
var_dump(polar_to_cartesian($lat, $long, GEO_AIRY_1830));
99
?>
1010
--EXPECT--
1111
array(3) {
12-
[0]=>
12+
["x"]=>
1313
float(3810891.6734396)
14-
[1]=>
14+
["y"]=>
1515
float(97591.624686311)
16-
[2]=>
16+
["z"]=>
1717
float(5095766.3939034)
1818
}

0 commit comments

Comments
 (0)