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 )
@@ -81,6 +82,11 @@ ZEND_BEGIN_ARG_INFO_EX(decimal_to_dms_args, 0, 0, 2)
81
82
ZEND_ARG_INFO (0 , coordinate )
82
83
ZEND_END_ARG_INFO ()
83
84
85
+ ZEND_BEGIN_ARG_INFO_EX (rdp_simplify_args , 0 , 0 , 2 )
86
+ ZEND_ARG_INFO (0 , pointsArray )
87
+ ZEND_ARG_INFO (0 , epsilon )
88
+ ZEND_END_ARG_INFO ()
89
+
84
90
/* {{{ geospatial_functions[]
85
91
*
86
92
* Every user visible function must have an entry in geospatial_functions[].
@@ -94,6 +100,7 @@ const zend_function_entry geospatial_functions[] = {
94
100
PHP_FE (transform_datum , transform_datum_args )
95
101
PHP_FE (dms_to_decimal , dms_to_decimal_args )
96
102
PHP_FE (decimal_to_dms , decimal_to_dms_args )
103
+ PHP_FE (rdp_simplify , rdp_simplify_args )
97
104
/* End of functions */
98
105
{ NULL , NULL , NULL }
99
106
};
@@ -449,6 +456,7 @@ PHP_FUNCTION(transform_datum)
449
456
long from_reference_ellipsoid , to_reference_ellipsoid ;
450
457
geo_cartesian point , converted_point ;
451
458
geo_lat_long polar ;
459
+
452
460
if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "ddll" , & latitude , & longitude , & from_reference_ellipsoid , & to_reference_ellipsoid ) == FAILURE ) {
453
461
return ;
454
462
}
@@ -529,6 +537,142 @@ PHP_FUNCTION(fraction_along_gc_line)
529
537
}
530
538
/* }}} */
531
539
540
+ geo_array * geo_hashtable_to_array (zval * array )
541
+ {
542
+ geo_array * tmp ;
543
+ int element_count ;
544
+ HashPosition pos ;
545
+ zval * * entry ;
546
+ zval * * z_lon , * * z_lat ;
547
+ int i = 0 ;
548
+
549
+ element_count = zend_hash_num_elements (Z_ARRVAL_P (array ));
550
+ tmp = geo_array_ctor (element_count );
551
+
552
+ zend_hash_internal_pointer_reset_ex (Z_ARRVAL_P (array ), & pos );
553
+ while (zend_hash_get_current_data_ex (Z_ARRVAL_P (array ), (void * * )& entry , & pos ) == SUCCESS ) {
554
+
555
+ if (Z_TYPE_PP (entry ) != IS_ARRAY ) {
556
+ goto failure ;
557
+ }
558
+ if (zend_hash_num_elements (Z_ARRVAL_PP (entry )) != 2 )
559
+ {
560
+ goto failure ;
561
+ }
562
+ if (zend_hash_index_find (HASH_OF (* entry ), 0 , (void * * ) & z_lon ) != SUCCESS ) {
563
+ return 0 ;
564
+ }
565
+ if (zend_hash_index_find (HASH_OF (* entry ), 1 , (void * * ) & z_lat ) != SUCCESS ) {
566
+ return 0 ;
567
+ }
568
+ convert_to_double_ex (z_lon );
569
+ convert_to_double_ex (z_lat );
570
+
571
+ tmp -> x [i ] = Z_DVAL_PP (z_lon );
572
+ tmp -> y [i ] = Z_DVAL_PP (z_lat );
573
+ tmp -> status [i ] = 1 ;
574
+
575
+ zend_hash_move_forward_ex (Z_ARRVAL_P (array ), & pos );
576
+ i ++ ;
577
+ }
578
+
579
+ return tmp ;
580
+
581
+ failure :
582
+ geo_array_dtor (tmp );
583
+ return NULL ;
584
+ }
585
+
586
+ double rdp_find_perpendicular_distable (double pX , double pY , double p1X , double p1Y , double p2X , double p2Y )
587
+ {
588
+ double slope , intercept , result ;
589
+
590
+ if (p1X == p2X ) {
591
+ return fabs (pX - p1X );
592
+ } else {
593
+ slope = (p2Y - p1Y ) / (p2X - p1X );
594
+ intercept = p1Y - (slope * p1X );
595
+ result = fabs (slope * pX - pY + intercept ) / sqrt (pow (slope , 2 ) + 1 );
596
+ return result ;
597
+ }
598
+ }
599
+
600
+ void rdp_simplify (geo_array * points , double epsilon , int start , int end )
601
+ {
602
+ double firstX = points -> x [start ];
603
+ double firstY = points -> y [start ];
604
+ double lastX = points -> x [end ];
605
+ double lastY = points -> y [end ];
606
+ int index = -1 ;
607
+ double dist = 0.0 , current_dist ;
608
+ int i ;
609
+
610
+ if (end - start < 2 ) {
611
+ return ;
612
+ }
613
+
614
+ for (i = start + 1 ; i < end ; i ++ ) {
615
+ if (!points -> status [i ]) {
616
+ continue ;
617
+ }
618
+
619
+ current_dist = rdp_find_perpendicular_distable (points -> x [i ], points -> y [i ], firstX , firstY , lastX , lastY );
620
+
621
+ if (current_dist > dist ) {
622
+ dist = current_dist ;
623
+ index = i ;
624
+ }
625
+ }
626
+
627
+ if (dist > epsilon ) {
628
+ rdp_simplify (points , epsilon , start , index );
629
+ rdp_simplify (points , epsilon , index , end );
630
+
631
+ return ;
632
+ } else {
633
+ for (i = start + 1 ; i < end ; i ++ ) {
634
+ points -> status [i ] = 0 ;
635
+ }
636
+ return ;
637
+ }
638
+ }
639
+
640
+ /* {{{ proto array rdp_simplify(array points, float epsilon)
641
+ Simplifies a 2D dimensional line according to the Ramer-Douglas-Peucker algorithm */
642
+ PHP_FUNCTION (rdp_simplify )
643
+ {
644
+ zval * points_array ;
645
+ double epsilon ;
646
+ geo_array * points ;
647
+ int i ;
648
+ zval * pair ;
649
+
650
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "zd" , & points_array , & epsilon ) == FAILURE ) {
651
+ return ;
652
+ }
653
+
654
+ if (!Z_TYPE_P (points_array ) == IS_ARRAY ) {
655
+ return ;
656
+ }
657
+
658
+ array_init (return_value );
659
+
660
+ points = geo_hashtable_to_array (points_array );
661
+ rdp_simplify (points , epsilon , 0 , points -> count - 1 );
662
+ for (i = 0 ; i < points -> count ; i ++ ) {
663
+ if (points -> status [i ]) {
664
+ MAKE_STD_ZVAL (pair );
665
+ array_init (pair );
666
+ add_next_index_double (pair , points -> x [i ]);
667
+ add_next_index_double (pair , points -> y [i ]);
668
+ add_next_index_zval (return_value , pair );
669
+ }
670
+ }
671
+
672
+ geo_array_dtor (points );
673
+ }
674
+ /* }}} */
675
+
532
676
/*
533
677
* Local variables:
534
678
* tab-width: 4
0 commit comments