Skip to content

Commit db780b4

Browse files
committed
Merge branch 'master' of github.com:php-geospatial/geospatial
Conflicts: php_geospatial.h
2 parents 23a7d69 + 976ebcc commit db780b4

File tree

3 files changed

+86
-6
lines changed

3 files changed

+86
-6
lines changed

geospatial.c

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ ZEND_BEGIN_ARG_INFO_EX(haversine_args, 0, 0, 4)
3737
ZEND_ARG_INFO(0, radius)
3838
ZEND_END_ARG_INFO()
3939

40+
ZEND_BEGIN_ARG_INFO_EX(vincenty_args, 0, 0, 3)
41+
ZEND_ARG_INFO(0, fromLatitude)
42+
ZEND_ARG_INFO(0, fromLongitude)
43+
ZEND_ARG_INFO(0, toLatitude)
44+
ZEND_ARG_INFO(0, toLongitude)
45+
ZEND_END_ARG_INFO()
46+
4047
ZEND_BEGIN_ARG_INFO_EX(fraction_along_gc_line_args, 0, 0, 3)
4148
ZEND_ARG_INFO(0, geoJsonPoint1)
4249
ZEND_ARG_INFO(0, geoJsonPoint2)
@@ -100,6 +107,7 @@ const zend_function_entry geospatial_functions[] = {
100107
PHP_FE(transform_datum, transform_datum_args)
101108
PHP_FE(dms_to_decimal, dms_to_decimal_args)
102109
PHP_FE(decimal_to_dms, decimal_to_dms_args)
110+
PHP_FE(vincenty, vincenty_args)
103111
PHP_FE(rdp_simplify, rdp_simplify_args)
104112
/* End of functions */
105113
{ NULL, NULL, NULL }
@@ -229,29 +237,70 @@ double php_geo_haversine(double from_lat, double from_long, double to_lat, doubl
229237
return result;
230238
}
231239

240+
232241
geo_ellipsoid get_ellipsoid(long ellipsoid_const)
233242
{
234243
switch (ellipsoid_const) {
235244
case GEO_AIRY_1830:
236245
return airy_1830;
237-
break;
238246
case GEO_WGS84:
239247
default:
240248
return wgs84;
241-
break;
242249
}
243250
}
244251

252+
double php_geo_vincenty(double from_lat, double from_long, double to_lat, double to_long, geo_ellipsoid eli)
253+
{
254+
double U1, U2, L, lambda, lambdaP;
255+
double sinSigma, cosSigma, sigma, sinLambda, cosLambda;
256+
double sinU1, sinU2, cosU1, cosU2;
257+
double sinAlpha, cos2Alpha;
258+
double cosof2sigma, A, B, C, uSq, deltaSigma, s;
259+
int loopLimit = 100;
260+
double precision = 0.000000000001;
261+
262+
U1 = atan((1.0 - eli.f) * tan(from_lat));
263+
U2 = atan((1.0 - eli.f) * tan(to_lat));
264+
L = to_long - from_long;
265+
sinU1 = sin(U1);
266+
cosU1 = cos(U1);
267+
sinU2 = sin(U2);
268+
cosU2 = cos(U2);
269+
lambda = L;
270+
do {
271+
sinLambda = sin(lambda);
272+
cosLambda = cos(lambda);
273+
sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
274+
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
275+
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
276+
sigma = atan2(sinSigma, cosSigma);
277+
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
278+
cos2Alpha = 1.0 - sinAlpha * sinAlpha;
279+
cosof2sigma = cosSigma - 2.0 * sinU1 * sinU2 / cos2Alpha;
280+
C = eli.f / 16.0 * cos2Alpha * (4.0 + eli.f * (4.0 - 3.0 * cos2Alpha));
281+
lambdaP = lambda;
282+
lambda = L + (1.0 - C) * eli.f * sinAlpha *
283+
(sigma + C*sinSigma*(cosof2sigma+C*cosSigma*(-1.0 + 2.0 *cosof2sigma*cosof2sigma)));
284+
--loopLimit;
285+
} while (fabs(lambda - lambdaP) > precision && loopLimit > 0);
286+
uSq = cos2Alpha * (eli.a * eli.a - eli.b * eli.b) / (eli.b * eli.b);
287+
A = 1.0 + uSq / 16384.0 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
288+
B = uSq / 1024.0 * ( 256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
289+
deltaSigma = B * sinSigma * (cosof2sigma+B/4.0 * (cosSigma * (-1.0 + 2.0 *cosof2sigma*cosof2sigma)-
290+
B / 6.0 * cosof2sigma * (-3.0 + 4.0 *sinSigma*sinSigma) * (-3.0 + 4.0 *cosof2sigma*cosof2sigma)));
291+
s = eli.b * A * (sigma - deltaSigma);
292+
s = floor(s * 1000) / 1000;
293+
return s;
294+
}
295+
245296
geo_helmert_constants get_helmert_constants(long from, long to)
246297
{
247298
switch (from - to) {
248299
case 1:
249300
return osgb36_wgs84;
250-
break;
251301
default:
252302
case -1:
253303
return wgs84_osgb36;
254-
break;
255304
}
256305
}
257306

@@ -500,6 +549,19 @@ PHP_FUNCTION(haversine)
500549
}
501550
/* }}} */
502551

552+
PHP_FUNCTION(vincenty)
553+
{
554+
double from_lat, from_long, to_lat, to_long;
555+
double radius = GEO_EARTH_RADIUS;
556+
long reference_ellipsoid;
557+
558+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dddd|l", &from_lat, &from_long, &to_lat, &to_long, &reference_ellipsoid) == FAILURE) {
559+
return;
560+
}
561+
geo_ellipsoid eli = get_ellipsoid(reference_ellipsoid);
562+
RETURN_DOUBLE(php_geo_vincenty(from_lat * GEO_DEG_TO_RAD, from_long * GEO_DEG_TO_RAD, to_lat * GEO_DEG_TO_RAD, to_long * GEO_DEG_TO_RAD, eli));
563+
}
564+
503565
void php_geo_fraction_along_gc_line(double from_lat, double from_long, double to_lat, double to_long, double fraction, double radius, double *res_lat, double *res_long)
504566
{
505567
double distance;

php_geospatial.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ typedef struct {
4646
typedef struct {
4747
double a;
4848
double b;
49+
double f;
4950
} geo_ellipsoid;
5051

5152
typedef struct {
@@ -71,12 +72,16 @@ typedef struct {
7172
/**
7273
* The WGS84 elipsoid semi major axes
7374
*/
74-
const geo_ellipsoid wgs84 = {6378137.000, 6356752.3142};
75+
const geo_ellipsoid wgs84 = {6378137.000, 6356752.3142, 1.0/298.257223563};
7576

7677
/**
7778
* The Airy 1830 elipsoid semi major axes
7879
*/
79-
const geo_ellipsoid airy_1830 = {6377563.396, 6356256.910};
80+
const geo_ellipsoid airy_1830 = {6377563.396, 6356256.910, 1.0/299.3249646};
81+
/**
82+
* The GRS 80 elipsoid semi major axes
83+
*/
84+
const geo_ellipsoid grs80 = {6378137.000, 6356752.314140, 1.0/298.257222101};
8085

8186
/**
8287
* The values of the 7 variables for performing helmert transformation between
@@ -131,6 +136,7 @@ PHP_FUNCTION(cartesian_to_polar);
131136
PHP_FUNCTION(transform_datum);
132137
PHP_FUNCTION(dms_to_decimal);
133138
PHP_FUNCTION(decimal_to_dms);
139+
PHP_FUNCTION(vincenty);
134140
PHP_FUNCTION(rdp_simplify);
135141

136142
#endif /* PHP_GEOSPATIAL_H */

tests/Vincenty.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Test for "Vincenty" distance between FlindersPeak and Buninyong
3+
--FILE--
4+
<?php
5+
$flindersPeakLat = dms_to_decimal(-37, 57, 3.72030);
6+
$flindersPeakLong = dms_to_decimal(144, 25, 29.52440);
7+
$buninyongLat = dms_to_decimal(-37, 39, 10.15610);
8+
$buninyongLong = dms_to_decimal(143, 55, 35.38390);
9+
echo vincenty($flindersPeakLat, $flindersPeakLong, $buninyongLat, $buninyongLong), 'm';
10+
?>
11+
--EXPECT--
12+
54972.271m

0 commit comments

Comments
 (0)