Skip to content

Commit fa1844b

Browse files
committed
Merged pull request #20
2 parents c03c43a + 5fbedfd commit fa1844b

File tree

11 files changed

+533
-20
lines changed

11 files changed

+533
-20
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ env:
1616
before_script:
1717
- phpize
1818
- EXTRA_LDFLAGS="-precious-files-regex .libs/geospatial.gcno" LDFLAGS="-lgcov" CFLAGS="-Wall -ggdb3 -fno-strict-aliasing -coverage -O0" ./configure --enable-geospatial
19-
- make -j 5 test && if ls tests/*.diff >/dev/null 2>&1; then echo "Tests failed" && exit 1; fi
19+
- make -j 5 test && if ls tests/*.diff >/dev/null 2>&1; then echo "Tests failed" && cat tests/*.diff && exit 1; fi
2020
- gcov --object-directory .libs *.c
2121
- bash <(curl -s https://codecov.io/bash)
2222

README.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,32 @@ you would use::
170170
$point2 = [ 'type' => 'Point', 'coordinates' => [ 15, 10 ] ];
171171

172172
var_dump(fraction_along_gc_line($point1, $point2, 0.25));
173+
174+
Geohashing
175+
----------
176+
177+
The `geohash_encode` function can be used to convert GeoJSON Point to a
178+
geohash of a specific length (in this case, 12)::
179+
180+
$point = [ 'type' => 'Point', 'coordinates' => [ 16.4, 48.2 ] ];
181+
echo geohash_encode( $point, 12 );
182+
183+
Which outputs::
184+
185+
u2edjnw17enr
186+
187+
Similarly, a hashed coordinates pair can be decoded using `geohash_decode`
188+
function::
189+
190+
var_dump(geohash_decode('u2edjnw17enr'));
191+
array(2) {
192+
["type"]=>
193+
string(5) "Point"
194+
["coordinates"]=>
195+
array(2) {
196+
[0]=>
197+
float(16.40000006184)
198+
[1]=>
199+
float(48.199999993667)
200+
}
201+
}

config.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ PHP_ARG_ENABLE(geospatial, whether to enable geospatial support,
55
[ --enable-geospatial Enable geospatial support])
66

77
if test "$PHP_GEOSPATIAL" != "no"; then
8-
PHP_NEW_EXTENSION(geospatial, geospatial.c geo_array.c, $ext_shared)
8+
PHP_NEW_EXTENSION(geospatial, geospatial.c geo_array.c geohash.c, $ext_shared)
99
fi

geo_array.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
| Marcus Deglos <[email protected]> |
1919
+----------------------------------------------------------------------+
2020
*/
21+
#ifndef PHP_GEO_ARRAY_H
22+
#define PHP_GEO_ARRAY_H
2123

2224
typedef struct geo_array {
2325
double *x;
@@ -30,3 +32,4 @@ typedef struct geo_array {
3032
geo_array *geo_array_ctor(int element_count);
3133
void geo_array_add(geo_array *points, double lat, double lon);
3234
void geo_array_dtor(geo_array *points);
35+
#endif /* PHP_GEO_ARRAY_H */

geo_lat_long.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 7 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 2017 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Emir Beganovic <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
#ifndef PHP_GEO_LAT_LONG_H
19+
#define PHP_GEO_LAT_LONG_H
20+
21+
typedef struct {
22+
double x;
23+
double y;
24+
double z;
25+
} geo_lat_long;
26+
27+
#endif

geohash.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 7 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 2017 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Emir Beganovic <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#include <stdlib.h>
20+
21+
#include "php.h"
22+
#include "geo_lat_long.h"
23+
#include "geohash.h"
24+
25+
#define MAX_LAT 90.0
26+
#define MIN_LAT -90.0
27+
28+
#define MAX_LONG 180.0
29+
#define MIN_LONG -180.0
30+
31+
typedef struct interval_string {
32+
double high;
33+
double low;
34+
} interval_struct;
35+
36+
static char char_map[32] = "0123456789bcdefghjkmnpqrstuvwxyz";
37+
static size_t char_map_size = sizeof(char_map);
38+
39+
char *php_geo_geohash_encode(double latitude, double longitude, int precision)
40+
{
41+
char *hash;
42+
int steps;
43+
double coord, mid;
44+
int is_even = 1;
45+
unsigned int hash_char = 0;
46+
int i;
47+
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
48+
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
49+
interval_struct *interval;
50+
51+
hash = (char*)safe_emalloc(precision, sizeof(char), 1);
52+
53+
hash[precision] = '\0';
54+
steps = precision * 5.0;
55+
56+
for (i = 1; i <= steps; i++) {
57+
if (is_even) {
58+
interval = &lng_interval;
59+
coord = longitude;
60+
} else {
61+
interval = &lat_interval;
62+
coord = latitude;
63+
}
64+
65+
mid = (interval->low + interval->high) / 2.0;
66+
hash_char = hash_char << 1;
67+
68+
if (coord > mid) {
69+
interval->low = mid;
70+
hash_char |= 0x01;
71+
} else {
72+
interval->high = mid;
73+
}
74+
75+
if (!(i % 5)) {
76+
hash[(i - 1) / 5] = char_map[hash_char];
77+
hash_char = 0;
78+
}
79+
80+
is_even = !is_even;
81+
}
82+
83+
return hash;
84+
}
85+
86+
static unsigned int index_for_char(char c, char *string, size_t string_amount)
87+
{
88+
unsigned int index = -1;
89+
int i;
90+
91+
for (i = 0; i < string_amount; i++) {
92+
if (c == string[i]) {
93+
index = i;
94+
break;
95+
}
96+
}
97+
98+
return index;
99+
}
100+
101+
geo_lat_long php_geo_geohash_decode(char *hash, size_t char_amount)
102+
{
103+
geo_lat_long coordinate;
104+
105+
if (char_amount) {
106+
int charmap_index;
107+
double delta;
108+
int i, j;
109+
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
110+
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
111+
interval_struct *interval;
112+
113+
int is_even = 1;
114+
115+
for (i = 0; i < char_amount; i++) {
116+
charmap_index = index_for_char(hash[i], char_map, char_map_size);
117+
118+
/* Interpret the last 5 bits of the integer */
119+
for (j = 0; j < 5; j++) {
120+
interval = is_even ? &lng_interval : &lat_interval;
121+
122+
delta = (interval->high - interval->low) / 2.0;
123+
124+
if ((charmap_index << j) & 0x0010) {
125+
interval->low += delta;
126+
} else {
127+
interval->high -= delta;
128+
}
129+
130+
is_even = !is_even;
131+
}
132+
}
133+
134+
coordinate.x = lat_interval.high - ((lat_interval.high - lat_interval.low) / 2.0);
135+
coordinate.y = lng_interval.high - ((lng_interval.high - lng_interval.low) / 2.0);
136+
coordinate.z = 0;
137+
}
138+
139+
return coordinate;
140+
}

geohash.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5/7 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 2017 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Emir Beganovic <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
#ifndef PHP_GEOHASH_H
19+
#define PHP_GEOHASH_H
20+
21+
char *php_geo_geohash_encode(double lat, double lng, int precision);
22+
geo_lat_long php_geo_geohash_decode(char *hash, size_t hash_len);
23+
24+
#endif /* PHP_GEOHASH_H */

0 commit comments

Comments
 (0)