@@ -36,6 +36,13 @@ ZEND_BEGIN_ARG_INFO_EX(haversine_args, 0, 0, 4)
36
36
ZEND_ARG_INFO (0 , radius )
37
37
ZEND_END_ARG_INFO ()
38
38
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
+
39
46
ZEND_BEGIN_ARG_INFO_EX (fraction_along_gc_line_args , 0 , 0 , 3 )
40
47
ZEND_ARG_INFO (0 , geoJsonPoint1 )
41
48
ZEND_ARG_INFO (0 , geoJsonPoint2 )
@@ -94,6 +101,7 @@ const zend_function_entry geospatial_functions[] = {
94
101
PHP_FE (transform_datum , transform_datum_args )
95
102
PHP_FE (dms_to_decimal , dms_to_decimal_args )
96
103
PHP_FE (decimal_to_dms , decimal_to_dms_args )
104
+ PHP_FE (vincenty , vincenty_args )
97
105
/* End of functions */
98
106
{ NULL , NULL , NULL }
99
107
};
@@ -222,6 +230,7 @@ double php_geo_haversine(double from_lat, double from_long, double to_lat, doubl
222
230
return result ;
223
231
}
224
232
233
+
225
234
geo_ellipsoid get_ellipsoid (long ellipsoid_const )
226
235
{
227
236
switch (ellipsoid_const ) {
@@ -233,6 +242,50 @@ geo_ellipsoid get_ellipsoid(long ellipsoid_const)
233
242
}
234
243
}
235
244
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
+
236
289
geo_helmert_constants get_helmert_constants (long from , long to )
237
290
{
238
291
switch (from - to ) {
@@ -478,6 +531,19 @@ PHP_FUNCTION(haversine)
478
531
}
479
532
/* }}} */
480
533
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
+
481
547
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 )
482
548
{
483
549
double distance ;
0 commit comments