Coding standards, and a new test

This commit is contained in:
Derick Rethans
2017-12-29 12:01:35 +00:00
parent 6bd4087dfc
commit 5fbedfdc60
8 changed files with 138 additions and 141 deletions

View File

@@ -174,25 +174,28 @@ you would use::
Geohashing
----------
The `geohash_encode` function can be used to convert GeoJSON Point to a geohash of a specific lenth (in this case, 12)::
The `geohash_encode` function can be used to convert GeoJSON Point to a
geohash of a specific length (in this case, 12)::
echo geohash_encode(array('type' => 'Point', 'coordinates' => [16.4, 48.2]), 12);
$point = [ 'type' => 'Point', 'coordinates' => [ 16.4, 48.2 ] ];
echo geohash_encode( $point, 12 );
Which outputs::
u2edjnw17enr
u2edjnw17enr
Similarly, a hashed geopoint can be decoded using `geohash_decode` function::
Similarly, a hashed coordinates pair can be decoded using `geohash_decode`
function::
var_dump(geohash_decode('u2edjnw17enr'));
array(2) {
["type"]=>
string(5) "Point"
["coordinates"]=>
array(2) {
[0]=>
float(16.40000006184)
[1]=>
float(48.199999993667)
}
}
var_dump(geohash_decode('u2edjnw17enr'));
array(2) {
["type"]=>
string(5) "Point"
["coordinates"]=>
array(2) {
[0]=>
float(16.40000006184)
[1]=>
float(48.199999993667)
}
}

View File

@@ -19,8 +19,6 @@
+----------------------------------------------------------------------+
*/
#ifndef PHP_GEO_ARRAY_H
#define PHP_GEO_ARRAY_H
#include <stdlib.h>
#include "geo_array.h"
@@ -61,4 +59,3 @@ void geo_array_dtor(geo_array *points)
free(points->y);
free(points);
}
#endif /* PHP_GEO_ARRAY_H */

View File

@@ -18,6 +18,8 @@
| Marcus Deglos <marcus@deglos.com> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_GEO_ARRAY_H
#define PHP_GEO_ARRAY_H
typedef struct geo_array {
double *x;
@@ -30,3 +32,4 @@ typedef struct geo_array {
geo_array *geo_array_ctor(int element_count);
void geo_array_add(geo_array *points, double lat, double lon);
void geo_array_dtor(geo_array *points);
#endif /* PHP_GEO_ARRAY_H */

View File

@@ -15,14 +15,13 @@
| Authors: Emir Beganovic <emir@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_GEO_LAT_LONG_H
#define PHP_GEO_LAT_LONG_H
typedef struct {
double x;
double y;
double z;
double x;
double y;
double z;
} geo_lat_long;
#endif

166
geohash.c
View File

@@ -22,125 +22,119 @@
#include "geo_lat_long.h"
#include "geohash.h"
#define MAX_LAT 90.0
#define MAX_LAT 90.0
#define MIN_LAT -90.0
#define MAX_LONG 180.0
#define MAX_LONG 180.0
#define MIN_LONG -180.0
typedef struct interval_string {
double high;
double low;
double high;
double low;
} interval_struct;
static char char_map[32] = "0123456789bcdefghjkmnpqrstuvwxyz";
static size_t char_map_size = sizeof(char_map);
char* php_geo_geohash_encode(double latitude, double longitude, int precision)
char *php_geo_geohash_encode(double latitude, double longitude, int precision)
{
char* hash;
int steps;
double coord, mid;
int is_even = 1;
unsigned int hash_char = 0;
int i;
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
interval_struct* interval;
char *hash;
int steps;
double coord, mid;
int is_even = 1;
unsigned int hash_char = 0;
int i;
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
interval_struct *interval;
hash = (char*)safe_emalloc(precision, sizeof(char), 1);
hash = (char*)safe_emalloc(precision, sizeof(char), 1);
hash[precision] = '\0';
steps = precision * 5.0;
hash[precision] = '\0';
steps = precision * 5.0;
for (i = 1; i <= steps; i++) {
if (is_even) {
interval = &lng_interval;
coord = longitude;
} else {
interval = &lat_interval;
coord = latitude;
}
for (i = 1; i <= steps; i++) {
if (is_even) {
interval = &lng_interval;
coord = longitude;
} else {
interval = &lat_interval;
coord = latitude;
}
mid = (interval->low + interval->high) / 2.0;
hash_char = hash_char << 1;
mid = (interval->low + interval->high) / 2.0;
hash_char = hash_char << 1;
if (coord > mid) {
interval->low = mid;
hash_char |= 0x01;
} else {
interval->high = mid;
}
if (coord > mid) {
interval->low = mid;
hash_char |= 0x01;
} else {
interval->high = mid;
}
if (!(i % 5)) {
hash[(i - 1) / 5] = char_map[hash_char];
hash_char = 0;
}
if (!(i % 5)) {
hash[(i - 1) / 5] = char_map[hash_char];
hash_char = 0;
}
is_even = !is_even;
}
is_even = !is_even;
}
return hash;
return hash;
}
static unsigned int index_for_char(char c, char* string)
static unsigned int index_for_char(char c, char *string, size_t string_amount)
{
unsigned int index = -1;
int string_amount = strlen(string);
int i;
unsigned int index = -1;
int i;
for (i = 0; i < string_amount; i++) {
if (c == string[i]) {
index = i;
break;
}
}
for (i = 0; i < string_amount; i++) {
if (c == string[i]) {
index = i;
break;
}
}
return index;
return index;
}
geo_lat_long php_geo_geohash_decode(char* hash)
geo_lat_long php_geo_geohash_decode(char *hash, size_t char_amount)
{
geo_lat_long coordinate;
int char_amount = strlen(hash);
geo_lat_long coordinate;
if (char_amount) {
if (char_amount) {
int charmap_index;
double delta;
int i, j;
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
interval_struct *interval;
int charmap_index;
double delta;
int i, j;
int is_even = 1;
interval_struct lat_interval = { MAX_LAT, MIN_LAT };
interval_struct lng_interval = { MAX_LONG, MIN_LONG };
interval_struct* interval;
for (i = 0; i < char_amount; i++) {
charmap_index = index_for_char(hash[i], char_map, char_map_size);
int is_even = 1;
/* Interpret the last 5 bits of the integer */
for (j = 0; j < 5; j++) {
interval = is_even ? &lng_interval : &lat_interval;
for (i = 0; i < char_amount; i++) {
delta = (interval->high - interval->low) / 2.0;
charmap_index = index_for_char(hash[i], (char*)char_map);
if ((charmap_index << j) & 0x0010) {
interval->low += delta;
} else {
interval->high -= delta;
}
/* Interpret the last 5 bits of the integer */
for (j = 0; j < 5; j++) {
interval = is_even ? &lng_interval : &lat_interval;
is_even = !is_even;
}
}
delta = (interval->high - interval->low) / 2.0;
coordinate.x = lat_interval.high - ((lat_interval.high - lat_interval.low) / 2.0);
coordinate.y = lng_interval.high - ((lng_interval.high - lng_interval.low) / 2.0);
coordinate.z = 0;
}
if ((charmap_index << j) & 0x0010) {
interval->low += delta;
} else {
interval->high -= delta;
}
is_even = !is_even;
}
}
coordinate.x = lat_interval.high - ((lat_interval.high - lat_interval.low) / 2.0);
coordinate.y = lng_interval.high - ((lng_interval.high - lng_interval.low) / 2.0);
coordinate.z = 0;
}
return coordinate;
return coordinate;
}
/* }}} */

View File

@@ -15,19 +15,10 @@
| Authors: Emir Beganovic <emir@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_GEOHASH_H
#define PHP_GEOHASH_H
char* php_geo_geohash_encode(double lat, double lng, int precision);
geo_lat_long php_geo_geohash_decode(char* hash);
#endif /* PHP_GEOHASH_H */
char *php_geo_geohash_encode(double lat, double lng, int precision);
geo_lat_long php_geo_geohash_decode(char *hash, size_t hash_len);
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
#endif /* PHP_GEOHASH_H */

View File

@@ -369,7 +369,7 @@ double php_geo_vincenty(double from_lat, double from_long, double to_lat, double
sinLambda = sin(lambda);
cosLambda = cos(lambda);
sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = atan2(sinSigma, cosSigma);
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
@@ -378,14 +378,14 @@ double php_geo_vincenty(double from_lat, double from_long, double to_lat, double
C = eli.f / 16.0 * cos2Alpha * (4.0 + eli.f * (4.0 - 3.0 * cos2Alpha));
lambdaP = lambda;
lambda = L + (1.0 - C) * eli.f * sinAlpha *
(sigma + C*sinSigma*(cosof2sigma+C*cosSigma*(-1.0 + 2.0 *cosof2sigma*cosof2sigma)));
(sigma + C*sinSigma*(cosof2sigma+C*cosSigma*(-1.0 + 2.0 *cosof2sigma*cosof2sigma)));
--loopLimit;
} while (fabs(lambda - lambdaP) > precision && loopLimit > 0);
uSq = cos2Alpha * (eli.a * eli.a - eli.b * eli.b) / (eli.b * eli.b);
A = 1.0 + uSq / 16384.0 * (4096.0 + uSq * (-768.0 + uSq * (320.0 - 175.0 * uSq)));
B = uSq / 1024.0 * ( 256.0 + uSq * (-128.0 + uSq * (74.0 - 47.0 * uSq)));
deltaSigma = B * sinSigma * (cosof2sigma+B/4.0 * (cosSigma * (-1.0 + 2.0 *cosof2sigma*cosof2sigma)-
B / 6.0 * cosof2sigma * (-3.0 + 4.0 *sinSigma*sinSigma) * (-3.0 + 4.0 *cosof2sigma*cosof2sigma)));
deltaSigma = B * sinSigma * (cosof2sigma+B/4.0 * (cosSigma * (-1.0 + 2.0 *cosof2sigma*cosof2sigma) -
B / 6.0 * cosof2sigma * (-3.0 + 4.0 *sinSigma*sinSigma) * (-3.0 + 4.0 *cosof2sigma*cosof2sigma)));
s = eli.b * A * (sigma - deltaSigma);
s = floor(s * 1000) / 1000;
return s;
@@ -729,7 +729,7 @@ double php_initial_bearing(double from_lat, double from_long, double to_lat, dou
/*
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x).toDeg();
*/
double x, y;
@@ -1087,15 +1087,14 @@ PHP_FUNCTION(interpolate_polygon)
*/
PHP_FUNCTION(geohash_encode)
{
double longitude, latitude;
double longitude, latitude;
#if PHP_VERSION_ID >= 70000
zend_long precision = 12;
zend_long precision = 12;
#else
long precision = 12;
long precision = 12;
#endif
zval *geojson;
char* hash;
zval *geojson;
char *hash;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al", &geojson, &precision) == FAILURE) {
return;
@@ -1105,13 +1104,12 @@ PHP_FUNCTION(geohash_encode)
RETURN_FALSE;
}
hash = php_geo_geohash_encode(latitude, longitude, precision);
#if PHP_VERSION_ID < 70000
RETVAL_STRING(hash, 0);
#else
#if PHP_VERSION_ID >= 70000
RETVAL_STRING(hash);
efree(hash);
#else
RETVAL_STRING(hash, 0);
#endif
}
@@ -1119,19 +1117,18 @@ PHP_FUNCTION(geohash_encode)
*/
PHP_FUNCTION(geohash_decode)
{
char* hash;
char *hash;
#if PHP_VERSION_ID >= 70000
size_t hash_len;
size_t hash_len;
#else
int hash_len;
int hash_len;
#endif
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hash, &hash_len) == FAILURE) {
return;
}
geo_lat_long area = php_geo_geohash_decode(hash);
geo_lat_long area = php_geo_geohash_decode(hash, hash_len);
retval_point_from_coordinates(return_value, area.y, area.x);
}

View File

@@ -22,6 +22,8 @@ var_dump(geohash_decode('ezs42'));
var_dump(geohash_decode('.'));
var_dump(geohash_decode('u2edjnw17enr'));
var_dump(geohash_decode('zzzzzzzzzzzz'));
?>
--EXPECT--
array(2) {
@@ -189,3 +191,14 @@ array(2) {
float(48.199999993667)
}
}
array(2) {
["type"]=>
string(5) "Point"
["coordinates"]=>
array(2) {
[0]=>
float(179.99999983236)
[1]=>
float(89.999999916181)
}
}