27
27
#include "php_ini.h"
28
28
#include "ext/standard/info.h"
29
29
#include "php_geospatial.h"
30
+ #include "geo_array.h"
30
31
31
32
ZEND_BEGIN_ARG_INFO_EX (haversine_args , 0 , 0 , 4 )
32
33
ZEND_ARG_INFO (0 , fromLatitude )
@@ -88,6 +89,11 @@ ZEND_BEGIN_ARG_INFO_EX(decimal_to_dms_args, 0, 0, 2)
88
89
ZEND_ARG_INFO (0 , coordinate )
89
90
ZEND_END_ARG_INFO ()
90
91
92
+ ZEND_BEGIN_ARG_INFO_EX (rdp_simplify_args , 0 , 0 , 2 )
93
+ ZEND_ARG_INFO (0 , pointsArray )
94
+ ZEND_ARG_INFO (0 , epsilon )
95
+ ZEND_END_ARG_INFO ()
96
+
91
97
/* {{{ geospatial_functions[]
92
98
*
93
99
* Every user visible function must have an entry in geospatial_functions[].
@@ -102,6 +108,7 @@ const zend_function_entry geospatial_functions[] = {
102
108
PHP_FE (dms_to_decimal , dms_to_decimal_args )
103
109
PHP_FE (decimal_to_dms , decimal_to_dms_args )
104
110
PHP_FE (vincenty , vincenty_args )
111
+ PHP_FE (rdp_simplify , rdp_simplify_args )
105
112
/* End of functions */
106
113
{ NULL , NULL , NULL }
107
114
};
@@ -498,6 +505,7 @@ PHP_FUNCTION(transform_datum)
498
505
long from_reference_ellipsoid , to_reference_ellipsoid ;
499
506
geo_cartesian point , converted_point ;
500
507
geo_lat_long polar ;
508
+
501
509
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "ddll" , & latitude , & longitude , & from_reference_ellipsoid , & to_reference_ellipsoid ) == FAILURE ) {
502
510
return ;
503
511
}
@@ -591,6 +599,142 @@ PHP_FUNCTION(fraction_along_gc_line)
591
599
}
592
600
/* }}} */
593
601
602
+ geo_array * geo_hashtable_to_array (zval * array )
603
+ {
604
+ geo_array * tmp ;
605
+ int element_count ;
606
+ HashPosition pos ;
607
+ zval * * entry ;
608
+ zval * * z_lon , * * z_lat ;
609
+ int i = 0 ;
610
+
611
+ element_count = zend_hash_num_elements (Z_ARRVAL_P (array ));
612
+ tmp = geo_array_ctor (element_count );
613
+
614
+ zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (array ), & pos );
615
+ while (zend_hash_get_current_data_ex (Z_ARRVAL_P (array ), (void * * )& entry , & pos ) == SUCCESS ) {
616
+
617
+ if (Z_TYPE_PP (entry ) != IS_ARRAY ) {
618
+ goto failure ;
619
+ }
620
+ if (zend_hash_num_elements (Z_ARRVAL_PP (entry )) != 2 )
621
+ {
622
+ goto failure ;
623
+ }
624
+ if (zend_hash_index_find (HASH_OF (* entry ), 0 , (void * * ) & z_lon ) != SUCCESS ) {
625
+ return 0 ;
626
+ }
627
+ if (zend_hash_index_find (HASH_OF (* entry ), 1 , (void * * ) & z_lat ) != SUCCESS ) {
628
+ return 0 ;
629
+ }
630
+ convert_to_double_ex (z_lon );
631
+ convert_to_double_ex (z_lat );
632
+
633
+ tmp -> x [i ] = Z_DVAL_PP (z_lon );
634
+ tmp -> y [i ] = Z_DVAL_PP (z_lat );
635
+ tmp -> status [i ] = 1 ;
636
+
637
+ zend_hash_move_forward_ex (Z_ARRVAL_P (array ), & pos );
638
+ i ++ ;
639
+ }
640
+
641
+ return tmp ;
642
+
643
+ failure :
644
+ geo_array_dtor (tmp );
645
+ return NULL ;
646
+ }
647
+
648
+ double rdp_find_perpendicular_distable (double pX , double pY , double p1X , double p1Y , double p2X , double p2Y )
649
+ {
650
+ double slope , intercept , result ;
651
+
652
+ if (p1X == p2X ) {
653
+ return fabs (pX - p1X );
654
+ } else {
655
+ slope = (p2Y - p1Y ) / (p2X - p1X );
656
+ intercept = p1Y - (slope * p1X );
657
+ result = fabs (slope * pX - pY + intercept ) / sqrt (pow (slope , 2 ) + 1 );
658
+ return result ;
659
+ }
660
+ }
661
+
662
+ void rdp_simplify (geo_array * points , double epsilon , int start , int end )
663
+ {
664
+ double firstX = points -> x [start ];
665
+ double firstY = points -> y [start ];
666
+ double lastX = points -> x [end ];
667
+ double lastY = points -> y [end ];
668
+ int index = -1 ;
669
+ double dist = 0.0 , current_dist ;
670
+ int i ;
671
+
672
+ if (end - start < 2 ) {
673
+ return ;
674
+ }
675
+
676
+ for (i = start + 1 ; i < end ; i ++ ) {
677
+ if (!points -> status [i ]) {
678
+ continue ;
679
+ }
680
+
681
+ current_dist = rdp_find_perpendicular_distable (points -> x [i ], points -> y [i ], firstX , firstY , lastX , lastY );
682
+
683
+ if (current_dist > dist ) {
684
+ dist = current_dist ;
685
+ index = i ;
686
+ }
687
+ }
688
+
689
+ if (dist > epsilon ) {
690
+ rdp_simplify (points , epsilon , start , index );
691
+ rdp_simplify (points , epsilon , index , end );
692
+
693
+ return ;
694
+ } else {
695
+ for (i = start + 1 ; i < end ; i ++ ) {
696
+ points -> status [i ] = 0 ;
697
+ }
698
+ return ;
699
+ }
700
+ }
701
+
702
+ /* {{{ proto array rdp_simplify(array points, float epsilon)
703
+ Simplifies a 2D dimensional line according to the Ramer-Douglas-Peucker algorithm */
704
+ PHP_FUNCTION (rdp_simplify )
705
+ {
706
+ zval * points_array ;
707
+ double epsilon ;
708
+ geo_array * points ;
709
+ int i ;
710
+ zval * pair ;
711
+
712
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "zd" , & points_array , & epsilon ) == FAILURE ) {
713
+ return ;
714
+ }
715
+
716
+ if (!Z_TYPE_P (points_array ) == IS_ARRAY ) {
717
+ return ;
718
+ }
719
+
720
+ array_init (return_value );
721
+
722
+ points = geo_hashtable_to_array (points_array );
723
+ rdp_simplify (points , epsilon , 0 , points -> count - 1 );
724
+ for (i = 0 ; i < points -> count ; i ++ ) {
725
+ if (points -> status [i ]) {
726
+ MAKE_STD_ZVAL (pair );
727
+ array_init (pair );
728
+ add_next_index_double (pair , points -> x [i ]);
729
+ add_next_index_double (pair , points -> y [i ]);
730
+ add_next_index_zval (return_value , pair );
731
+ }
732
+ }
733
+
734
+ geo_array_dtor (points );
735
+ }
736
+ /* }}} */
737
+
594
738
/*
595
739
* Local variables:
596
740
* tab-width: 4
0 commit comments