Skip to content

Add geohashing capabilities #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed

Add geohashing capabilities #20

wants to merge 21 commits into from

Conversation

emirb
Copy link
Contributor

@emirb emirb commented Oct 10, 2017

I'd like to propose two new functionalities to be added to geospatial extension:

  • geohash_encode
  • geohash_decode

Geohash is a geocoding system invented by Gustavo Niemeyer. https://en.wikipedia.org/wiki/Geohash

There is a significant performance gain from using this extension compared to user-land libraries.

Source code is available at https://github.com/emirb/php-geohash-ext
Rather than creating a standalone extension for the sole purpose of dealing with geohashes, a mutual agreement has been met concerning merging it to the existing geospatial PHP extension.

Emir Beganovic added 4 commits October 10, 2017 22:44
@codecov-io
Copy link

codecov-io commented Oct 10, 2017

Codecov Report

Merging #20 into master will increase coverage by 4.42%.
The diff coverage is 97.46%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #20      +/-   ##
==========================================
+ Coverage   63.09%   67.51%   +4.42%     
==========================================
  Files           2        3       +1     
  Lines         439      508      +69     
  Branches       67        0      -67     
==========================================
+ Hits          277      343      +66     
- Misses        162      165       +3
Impacted Files Coverage Δ
geo_array.c 56.52% <ø> (ø) ⬆️
geohash.c 100% <100%> (ø)
geospatial.c 64.2% <92.59%> (+0.74%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c03c43a...ba04711. Read the comment docs.

Copy link
Contributor

@derickr derickr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi!

Thanks for this PR, I like having this functionality. Also apologies for the large amounts of comments in this code review, but I feel these need to be addressed before I can merge this.

cheers,
Derick

geohash.h Outdated
| Authors: Derick Rethans <github@derickrethans.nl> |
| Michael Maclean <michael@no-surprises.co.uk> |
| Nathaniel McHugh <nmchugh@inviqa.com> |
| Marcus Deglos <marcus@deglos.com> |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These first four lines are not needed, as we didn't write any of this code.

geohash.h Outdated
+----------------------------------------------------------------------+
| PHP Version 5/7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2016 The PHP Group |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should only be "2017" in here.

geohash.h Outdated
| Emir Beganovic <emir@php.net> |
+----------------------------------------------------------------------+
*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header files should have a guard, such as done at:

https://github.com/php-geospatial/geospatial/blob/master/php_geospatial.h#L22

I just realized geo_array.h doesn't have that either, so created a ticket: #21

geohash.h Outdated
typedef struct IntervalStruct {
double high;
double low;
} Interval;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current coding standard would have used "interval_struct", but it looks like this is something internal to the geohash algorithm, so should probably not be in a public header.

geohash.h Outdated
typedef struct GeoCoordStruct {
double latitude;
double longitude;
} GeoCoord;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto here, these should both be geo_coord - and private.

geospatial.c Outdated

zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd|l", &lat, &lng, &precision);
char* hash;
hash = _geohash_encode(lat, lng, precision);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line between declarations and code please, and none needed among the declarations.

geospatial.c Outdated
#endif
}

/* {{{ string geohash_decode( [ string $geohash ] )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$geohash is not optional here, so shouldn't have [ .. ]

geospatial.c Outdated

array_init(return_value);
add_assoc_double(return_value, "latitude", area.latitude);
add_assoc_double(return_value, "longitude", area.longitude);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return of this should be a GeoJSONPoint.

php_geospatial.h Outdated
@@ -22,7 +22,7 @@
#ifndef PHP_GEOSPATIAL_H
#define PHP_GEOSPATIAL_H

#define PHP_GEOSPATIAL_VERSION "0.1.1-dev"
#define PHP_GEOSPATIAL_VERSION "0.1.2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to bump the version, this we only do when making a release. However, you probably should change it to 0.2.0-dev, as there is new functionality with this PR.

@@ -143,6 +150,8 @@ PHP_FUNCTION(vincenty);
PHP_FUNCTION(rdp_simplify);
PHP_FUNCTION(interpolate_linestring);
PHP_FUNCTION(interpolate_polygon);
PHP_FUNCTION(geohash_encode);
PHP_FUNCTION(geohash_decode);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add documentation and an example to the README.rst file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

README.rst Outdated
[0]=>
float(16.4)
[1]=>
float(48.2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the following output:

array(2) {
  'type' =>
  string(5) "Point"
  'coordinates' =>
  array(2) {
    [0] =>
    double(171.02859674022)
    [1] =>
    double(49.674154138193)
  }
}

Perhaps make the input the same as the output from above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've adjusted it but bear in mind that the output of a 12 char geohash will be a a float with 12 decimal places because of high detail level.

README.rst Outdated

The `geohash_encode` function can be used to convert GeoJSON Point to a geohash::

$geohash = geohash_encode(array('type' => 'Point', 'coordinates' => [16.4, 48.2]), 12);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this to:

echo geohash_encode(array('type' => 'Point', 'coordinates' => [16.4, 48.2]), 12);

As that actually outputs, and perhaps explain the 12 as well - which I presume is the length of the returned string?

geo_lat_long.h Outdated
double height;
} geo_lat_long;

#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick: misses CR at end of line.

geohash.c Outdated
typedef struct IntervalStruct {
double high;
double low;
} interval_struct;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed changing "struct IntervalStruct" to "struct interval_string" here? It's not used really, so the compiler wouldn't bitch.

geohash.c Outdated
hash = (char*)safe_emalloc(precision, sizeof(char), 1);

hash[precision] = '\0';
steps = precision*5.0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit pick: add spaces around the *.

geo_lat_long.h Outdated

typedef struct {
double latitude;
double longitude;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise this was my mistake, but can you swap latitude and longitude, so that the order is x, y, and z ?

geo_lat_long.h Outdated
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2016 The PHP Group |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use "2017" here.

geospatial.c Outdated
RETURN_FALSE;
}

char* hash;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be up with the other variable declarations, as in C you can't mix code and declarations.

geospatial.c Outdated
return;
}

geo_lat_long area = php_geo_geohash_decode(hash);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the decoding altogether fail? With an invalid string for example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I've tried to break it though with utf8 chars and so on...

echo geohash_encode(array('type' => 'Point', 'coordinates' => [90, 90]), 6).PHP_EOL;
echo geohash_encode(array('type' => 'Point', 'coordinates' => [16.363, 48.21]), 32).PHP_EOL;
echo geohash_encode(array('type' => 'Point', 'coordinates' => [95, 95]), 6).PHP_EOL;
echo geohash_encode(array('type' => 'Point', 'coordinates' => [185, 185]), 12).PHP_EOL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these numbers in the last two not out of range? Shouldn't that make it return false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By definition of the geohashing algorithm there should always be a return AFAIK, and or everything out of bounds >180 it will return zzzzzzzzzzzz. This is the behaviour that I've seen in geohash libraries in other languages as well.

@derickr
Copy link
Contributor

derickr commented Nov 17, 2017

Hi!

Are you still interested in working further on this?

cheers,
Derick

@emirb
Copy link
Contributor Author

emirb commented Nov 28, 2017

Hi @derickr.

I didn't have time lately to finish final changes on this but will do so today or tomorrow.

Thanks for your patience!

Cheers

@emirb
Copy link
Contributor Author

emirb commented Dec 24, 2017

@derickr Sorry for the long delay. I hope that's it now and that you can finally merge the code additions and release new version.

Merry Christmas!

derickr added a commit that referenced this pull request Dec 29, 2017
@derickr
Copy link
Contributor

derickr commented Dec 29, 2017

Merged, after rebase, and some code standard changes. I've also released 0.2.0.

@derickr derickr closed this Dec 29, 2017
@emirb emirb deleted the feature/geohash branch December 29, 2017 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants