Skip to content

Commit c628cbe

Browse files
author
Nathaniel McHugh
committed
add vincenty function
1 parent 528eaa9 commit c628cbe

File tree

3 files changed

+86
-2
lines changed

3 files changed

+86
-2
lines changed

geospatial.c

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

39+
ZEND_BEGIN_ARG_INFO_EX(vincenty_args, 0, 0, 3)
40+
ZEND_ARG_INFO(0, fromLatitude)
41+
ZEND_ARG_INFO(0, fromLongitude)
42+
ZEND_ARG_INFO(0, toLatitude)
43+
ZEND_ARG_INFO(0, toLongitude)
44+
ZEND_END_ARG_INFO()
45+
3946
ZEND_BEGIN_ARG_INFO_EX(fraction_along_gc_line_args, 0, 0, 3)
4047
ZEND_ARG_INFO(0, geoJsonPoint1)
4148
ZEND_ARG_INFO(0, geoJsonPoint2)
@@ -94,6 +101,7 @@ const zend_function_entry geospatial_functions[] = {
94101
PHP_FE(transform_datum, transform_datum_args)
95102
PHP_FE(dms_to_decimal, dms_to_decimal_args)
96103
PHP_FE(decimal_to_dms, decimal_to_dms_args)
104+
PHP_FE(vincenty, vincenty_args)
97105
/* End of functions */
98106
{ NULL, NULL, NULL }
99107
};
@@ -222,6 +230,7 @@ double php_geo_haversine(double from_lat, double from_long, double to_lat, doubl
222230
return result;
223231
}
224232

233+
225234
geo_ellipsoid get_ellipsoid(long ellipsoid_const)
226235
{
227236
switch (ellipsoid_const) {
@@ -233,6 +242,50 @@ geo_ellipsoid get_ellipsoid(long ellipsoid_const)
233242
}
234243
}
235244

245+
double php_geo_vincenty(double from_lat, double from_long, double to_lat, double to_long, geo_ellipsoid eli)
246+
{
247+
double U1, U2, L, lambda, lambdaP;
248+
double sinSigma, cosSigma, sigma, sinLambda, cosLambda;
249+
double sinU1, sinU2, cosU1, cosU2;
250+
double sinAlpha, cos2Alpha;
251+
double cosof2sigma, A, B, C, uSq, deltaSigma, s;
252+
int loopLimit = 100;
253+
double precision = 0.000000000001;
254+
255+
U1 = atan((1.0 - eli.f) * tan(from_lat));
256+
U2 = atan((1.0 - eli.f) * tan(to_lat));
257+
L = to_long - from_long;
258+
sinU1 = sin(U1);
259+
cosU1 = cos(U1);
260+
sinU2 = sin(U2);
261+
cosU2 = cos(U2);
262+
lambda = L;
263+
do {
264+
sinLambda = sin(lambda);
265+
cosLambda = cos(lambda);
266+
sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
267+
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
268+
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
269+
sigma = atan2(sinSigma, cosSigma);
270+
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
271+
cos2Alpha = 1.0 - sinAlpha * sinAlpha;
272+
cosof2sigma = cosSigma - 2.0 * sinU1 * sinU2 / cos2Alpha;
273+
C = eli.f / 16.0 * cos2Alpha * (4.0 + eli.f * (4.0 - 3.0 * cos2Alpha));
274+
lambdaP = lambda;
275+
lambda = L + (1.0 - C) * eli.f * sinAlpha *
276+
(sigma + C*sinSigma*(cosof2sigma+C*cosSigma*(-1.0 + 2.0 *cosof2sigma*cosof2sigma)));
277+
--loopLimit;
278+
} while (fabs(lambda - lambdaP) > precision && loopLimit > 0);
279+
uSq = cos2Alpha * (eli.a * eli.a - eli.b * eli.b) / (eli.b * eli.b);
280+
A = 1.0 + uSq / 16384.0 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
281+
B = uSq / 1024.0 * ( 256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
282+
deltaSigma = B * sinSigma * (cosof2sigma+B/4.0 * (cosSigma * (-1.0 + 2.0 *cosof2sigma*cosof2sigma)-
283+
B / 6.0 * cosof2sigma * (-3.0 + 4.0 *sinSigma*sinSigma) * (-3.0 + 4.0 *cosof2sigma*cosof2sigma)));
284+
s = eli.b * A * (sigma - deltaSigma);
285+
s = floor(s * 1000) / 1000;
286+
return s;
287+
}
288+
236289
geo_helmert_constants get_helmert_constants(long from, long to)
237290
{
238291
switch (from - to) {
@@ -478,6 +531,19 @@ PHP_FUNCTION(haversine)
478531
}
479532
/* }}} */
480533

534+
PHP_FUNCTION(vincenty)
535+
{
536+
double from_lat, from_long, to_lat, to_long;
537+
double radius = GEO_EARTH_RADIUS;
538+
long reference_ellipsoid;
539+
540+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dddd|l", &from_lat, &from_long, &to_lat, &to_long, &reference_ellipsoid) == FAILURE) {
541+
return;
542+
}
543+
geo_ellipsoid eli = get_ellipsoid(reference_ellipsoid);
544+
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));
545+
}
546+
481547
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)
482548
{
483549
double distance;

php_geospatial.h

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

5051
typedef struct {
@@ -70,11 +71,15 @@ typedef struct {
7071
/**
7172
* The WGS84 elipsoid semi major axes
7273
*/
73-
const geo_ellipsoid wgs84 = {6378137.000, 6356752.3142};
74+
const geo_ellipsoid wgs84 = {6378137.000, 6356752.3142, 1.0/298.257223563};
7475
/**
7576
* The Airy 1830 elipsoid semi major axes
7677
*/
77-
const geo_ellipsoid airy_1830 = {6377563.396, 6356256.910};
78+
const geo_ellipsoid airy_1830 = {6377563.396, 6356256.910, 1.0/299.3249646};
79+
/**
80+
* The GRS 80 elipsoid semi major axes
81+
*/
82+
const geo_ellipsoid grs80 = {6378137.000, 6356752.314140, 1.0/298.257222101};
7883

7984
/**
8085
* The values of the 7 variables for performing helmert transformation between
@@ -128,6 +133,7 @@ PHP_FUNCTION(cartesian_to_polar);
128133
PHP_FUNCTION(transform_datum);
129134
PHP_FUNCTION(dms_to_decimal);
130135
PHP_FUNCTION(decimal_to_dms);
136+
PHP_FUNCTION(vincenty);
131137

132138
#endif /* PHP_GEOSPATIAL_H */
133139

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)