@@ -97,6 +97,16 @@ ZEND_BEGIN_ARG_INFO_EX(rdp_simplify_args, 0, 0, 2)
97
97
ZEND_ARG_INFO(0, epsilon)
98
98
ZEND_END_ARG_INFO()
99
99
100
+ ZEND_BEGIN_ARG_INFO_EX(interpolate_linestring_args, 0, 0, 2)
101
+ ZEND_ARG_INFO(0, GeoJSONLineString)
102
+ ZEND_ARG_INFO(0, epsilon)
103
+ ZEND_END_ARG_INFO()
104
+
105
+ ZEND_BEGIN_ARG_INFO_EX(interpolate_polygon_args, 0, 0, 2)
106
+ ZEND_ARG_INFO(0, GeoJSONPolygon)
107
+ ZEND_ARG_INFO(0, epsilon)
108
+ ZEND_END_ARG_INFO()
109
+
100
110
/* {{{ geospatial_functions[]
101
111
*
102
112
* Every user visible function must have an entry in geospatial_functions[].
@@ -113,6 +123,8 @@ const zend_function_entry geospatial_functions[] = {
113
123
PHP_FE(decimal_to_dms, decimal_to_dms_args)
114
124
PHP_FE(vincenty, vincenty_args)
115
125
PHP_FE(rdp_simplify, rdp_simplify_args)
126
+ PHP_FE(interpolate_linestring, interpolate_linestring_args)
127
+ PHP_FE(interpolate_polygon, interpolate_polygon_args)
116
128
/* End of functions */
117
129
{ NULL, NULL, NULL }
118
130
};
@@ -186,24 +198,12 @@ void retval_point_from_coordinates(zval *return_value, double lon, double lat)
186
198
add_assoc_zval_ex(return_value, "coordinates", sizeof("coordinates"), coordinates);
187
199
}
188
200
189
- int geojson_point_to_lon_lat (zval *point , double *lon, double *lat)
201
+ static int parse_point_pair (zval *coordinates , double *lon, double *lat)
190
202
{
191
- zval **type, **coordinates, **z_lon, **z_lat;
192
203
HashTable *coords;
204
+ zval **z_lon, **z_lat;
193
205
194
- if (zend_hash_find(HASH_OF(point), "type", sizeof("type"), (void**) &type) != SUCCESS) {
195
- return 0;
196
- }
197
- if (Z_TYPE_PP(type) != IS_STRING || strcmp(Z_STRVAL_PP(type), "Point") != 0) {
198
- return 0;
199
- }
200
- if (zend_hash_find(HASH_OF(point), "coordinates", sizeof("coordinates"), (void**) &coordinates) != SUCCESS) {
201
- return 0;
202
- }
203
- if (Z_TYPE_PP(coordinates) != IS_ARRAY) {
204
- return 0;
205
- }
206
- coords = HASH_OF(*coordinates);
206
+ coords = HASH_OF(coordinates);
207
207
if (coords->nNumOfElements != 2) {
208
208
return 0;
209
209
}
@@ -220,6 +220,26 @@ int geojson_point_to_lon_lat(zval *point, double *lon, double *lat)
220
220
return 1;
221
221
}
222
222
223
+ int geojson_point_to_lon_lat(zval *point, double *lon, double *lat)
224
+ {
225
+ zval **type, **coordinates;
226
+
227
+ if (zend_hash_find(HASH_OF(point), "type", sizeof("type"), (void**) &type) != SUCCESS) {
228
+ return 0;
229
+ }
230
+ if (Z_TYPE_PP(type) != IS_STRING || strcmp(Z_STRVAL_PP(type), "Point") != 0) {
231
+ return 0;
232
+ }
233
+ if (zend_hash_find(HASH_OF(point), "coordinates", sizeof("coordinates"), (void**) &coordinates) != SUCCESS) {
234
+ return 0;
235
+ }
236
+ if (Z_TYPE_PP(coordinates) != IS_ARRAY) {
237
+ return 0;
238
+ }
239
+
240
+ return parse_point_pair(*coordinates, lon, lat);
241
+ }
242
+
223
243
/* }}} */
224
244
225
245
double php_geo_haversine(double from_lat, double from_long, double to_lat, double to_long)
@@ -516,7 +536,9 @@ PHP_FUNCTION(transform_datum)
516
536
return;
517
537
}
518
538
519
- geojson_point_to_lon_lat(geojson, &longitude, &latitude);
539
+ if (!geojson_point_to_lon_lat(geojson, &longitude, &latitude)) {
540
+ RETURN_FALSE;
541
+ }
520
542
521
543
geo_ellipsoid eli_from = get_ellipsoid(from_reference_ellipsoid);
522
544
geo_ellipsoid eli_to = get_ellipsoid(to_reference_ellipsoid);
@@ -630,8 +652,8 @@ var brng = Math.atan2(y, x).toDeg();
630
652
*/
631
653
double x, y;
632
654
633
- y = sin(to_long - from_long) * cos(to_lat);
634
- x = cos(from_lat) * sin(to_lat) - sin(from_lat) * cos(to_lat) * cos(to_long - to_long );
655
+ y = sin(fabs( to_long - from_long) ) * cos(to_lat);
656
+ x = ( cos(from_lat) * sin(to_lat)) - ( sin(from_lat) * cos(to_lat) * cos(fabs( to_long - from_long)) );
635
657
636
658
return atan2(y, x);
637
659
}
@@ -667,7 +689,7 @@ geo_array *geo_hashtable_to_array(zval *array)
667
689
int element_count;
668
690
HashPosition pos;
669
691
zval **entry;
670
- zval **z_lon, **z_lat ;
692
+ double lon, lat ;
671
693
int i = 0;
672
694
673
695
element_count = zend_hash_num_elements(Z_ARRVAL_P(array));
@@ -676,24 +698,12 @@ geo_array *geo_hashtable_to_array(zval *array)
676
698
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
677
699
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
678
700
679
- if (Z_TYPE_PP(entry) != IS_ARRAY) {
680
- goto failure;
681
- }
682
- if (zend_hash_num_elements(Z_ARRVAL_PP(entry)) != 2)
683
- {
701
+ if (!parse_point_pair(*entry, &lon, &lat)) {
684
702
goto failure;
685
703
}
686
- if (zend_hash_index_find(HASH_OF(*entry), 0, (void**) &z_lon) != SUCCESS) {
687
- return 0;
688
- }
689
- if (zend_hash_index_find(HASH_OF(*entry), 1, (void**) &z_lat) != SUCCESS) {
690
- return 0;
691
- }
692
- convert_to_double_ex(z_lon);
693
- convert_to_double_ex(z_lat);
694
704
695
- tmp->x[i] = Z_DVAL_PP(z_lon) ;
696
- tmp->y[i] = Z_DVAL_PP(z_lat) ;
705
+ tmp->x[i] = lon ;
706
+ tmp->y[i] = lat ;
697
707
tmp->status[i] = 1;
698
708
699
709
zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
@@ -707,6 +717,37 @@ geo_array *geo_hashtable_to_array(zval *array)
707
717
return NULL;
708
718
}
709
719
720
+ int geojson_linestring_to_array(zval *line, geo_array **array)
721
+ {
722
+ geo_array *tmp;
723
+ zval **type, **coordinates;
724
+
725
+ if (Z_TYPE_P(line) != IS_ARRAY) {
726
+ return 0;
727
+ }
728
+
729
+ if (zend_hash_find(HASH_OF(line), "type", sizeof("type"), (void**) &type) != SUCCESS) {
730
+ return 0;
731
+ }
732
+ if (Z_TYPE_PP(type) != IS_STRING || strcmp(Z_STRVAL_PP(type), "Linestring") != 0) {
733
+ return 0;
734
+ }
735
+ if (zend_hash_find(HASH_OF(line), "coordinates", sizeof("coordinates"), (void**) &coordinates) != SUCCESS) {
736
+ return 0;
737
+ }
738
+ if (Z_TYPE_PP(coordinates) != IS_ARRAY) {
739
+ return 0;
740
+ }
741
+
742
+ tmp = geo_hashtable_to_array(*coordinates);
743
+ if (tmp && array) {
744
+ *array = tmp;
745
+ return 1;
746
+ }
747
+
748
+ return 0;
749
+ }
750
+
710
751
double rdp_find_perpendicular_distable(double pX, double pY, double p1X, double p1Y, double p2X, double p2Y)
711
752
{
712
753
double slope, intercept, result;
@@ -797,6 +838,118 @@ PHP_FUNCTION(rdp_simplify)
797
838
}
798
839
/* }}} */
799
840
841
+ static geo_array *interpolate_line(geo_array *points, double epsilon)
842
+ {
843
+ int i;
844
+ geo_array *new_array;
845
+ double dx, dy, distance, step_size, res_lat, res_long, fraction;
846
+
847
+ new_array = geo_array_ctor(0);
848
+
849
+ for (i = 0; i < points->count - 1; i++) {
850
+ dx = fabs(points->x[i] - points->x[i + 1]);
851
+ dy = fabs(points->y[i] - points->y[i + 1]);
852
+ distance = sqrt((dx * dx) + (dy * dy));
853
+ if (distance > epsilon) {
854
+ step_size = epsilon/distance;
855
+ for (fraction = 0; fraction < 1; fraction += step_size) {
856
+ php_geo_fraction_along_gc_line(
857
+ points->y[i] * GEO_DEG_TO_RAD,
858
+ points->x[i] * GEO_DEG_TO_RAD,
859
+ points->y[i + 1] * GEO_DEG_TO_RAD,
860
+ points->x[i + 1] * GEO_DEG_TO_RAD,
861
+ fraction, GEO_EARTH_RADIUS,
862
+ &res_lat, &res_long
863
+ );
864
+ geo_array_add(new_array, res_long / GEO_DEG_TO_RAD, res_lat / GEO_DEG_TO_RAD);
865
+ }
866
+ } else {
867
+ geo_array_add(new_array, points->x[i], points->y[i]);
868
+ }
869
+ }
870
+ geo_array_add(new_array, points->x[points->count - 1], points->y[points->count - 1]);
871
+
872
+ return new_array;
873
+ }
874
+
875
+ /* {{{ proto array interpolate_linestring(GeoJSONLineString line, float epsilon)
876
+ Interpolates lines with intermediate points to show line segments as GC lines */
877
+ PHP_FUNCTION(interpolate_linestring)
878
+ {
879
+ zval *line;
880
+ double epsilon;
881
+ geo_array *points;
882
+ int i;
883
+ zval *pair;
884
+ geo_array *new_array;
885
+
886
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zd", &line, &epsilon) == FAILURE) {
887
+ return;
888
+ }
889
+
890
+ if (!geojson_linestring_to_array(line, &points)) {
891
+ RETURN_FALSE;
892
+ }
893
+
894
+ array_init(return_value);
895
+
896
+ new_array = interpolate_line(points, epsilon);
897
+
898
+ for (i = 0; i < new_array->count; i++) {
899
+ if (new_array->status[i]) {
900
+ MAKE_STD_ZVAL(pair);
901
+ array_init(pair);
902
+ add_next_index_double(pair, new_array->x[i]);
903
+ add_next_index_double(pair, new_array->y[i]);
904
+ add_next_index_zval(return_value, pair);
905
+ }
906
+ }
907
+
908
+ geo_array_dtor(points);
909
+ geo_array_dtor(new_array);
910
+ }
911
+ /* }}} */
912
+
913
+ /* {{{ proto array interpolate_polygon(GeoJSONPolygon polygon, float epsilon)
914
+ Interpolates polygons with intermediate points to show line segments as GC lines */
915
+ PHP_FUNCTION(interpolate_polygon)
916
+ {
917
+ zval *polygon;
918
+ double epsilon;
919
+ geo_array *points;
920
+ int i;
921
+ zval *pair;
922
+
923
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zd", &polygon, &epsilon) == FAILURE) {
924
+ return;
925
+ }
926
+
927
+ if (!Z_TYPE_P(polygon) == IS_ARRAY) {
928
+ return;
929
+ }
930
+
931
+ if (!geojson_linestring_to_array(polygon, &points)) {
932
+ RETURN_FALSE;
933
+ }
934
+
935
+ array_init(return_value);
936
+
937
+ rdp_simplify(points, epsilon, 0, points->count - 1);
938
+
939
+ for (i = 0; i < points->count; i++) {
940
+ if (points->status[i]) {
941
+ MAKE_STD_ZVAL(pair);
942
+ array_init(pair);
943
+ add_next_index_double(pair, points->x[i]);
944
+ add_next_index_double(pair, points->y[i]);
945
+ add_next_index_zval(return_value, pair);
946
+ }
947
+ }
948
+
949
+ geo_array_dtor(points);
950
+ }
951
+ /* }}} */
952
+
800
953
/*
801
954
* Local variables:
802
955
* tab-width: 4
0 commit comments