6

I am trying to use geohash to generate a grid of rectangles to cover an area. But I am not very familiar with the coding system of geohash. My question is:

If I have a specific geohash gh of 3 characters, how do I get a list of all 4,5,6-character geohashes that are contained in the ST_GeomFromGeohash of the original geohash gh?

I am using PostGIS (2.5, 3.0alpha; PostgreSQL 11), and can manage the basics of getting the geometries of a geohash etc. I am just not sure how to get all the "sub-geohashes", e.g. by string operations. If there is a built-in function in PostGIS/PostgreSQL, it is even better.

Related:

What is the precision of a Geohash

1 Answer 1

7

First of all, a geohash is easier to explain with referencee to points, but the logic can easily be extended to a grid, using two points, for opposite corners, similar to how ST_MakeBox2D works. A geohash in made up of interwoven bits, where each even bit represents increasing precision (powers of two in longitude) and each odd bit represents increasing precision in latitude, as explained very well in the wikipedia article. In other words the first bit, 0 or 1, determines that the range is either from -180 to 0 or 0 to 180, so the range for each possible bit value is 180, the mean value is +/- 90, and the maximum error is 90 degrees. The second bit determines the range as either -90 to 0 or 0 to 90, so half the range, mean value and maximum error of the corresponding longitude values. The third bit then splits the range in half, so from +/-180 to +/-90 or +/-90 to 0, depending on whether the previous odd bit was a 0 or 1.

Once you have interweaved bit values, you convert to a geohash using a modified base32 encoding, as illustrated in Wikipedia. So, a geohash of 3 letters, corresponds three 5 bit words, ie, 15 digits, which means 8 digits of precision in longitude and 7 digits in latitude, ie, the maximum error is now 0.352 in both directions.

So, for example, I am sitting at 41.48N, 2.17E. This corresponds to a geohash of sp3e3kupuxj6bggjfdc4, as you can see from:

SELECT ST_GeoHash(ST_SetSRID(ST_MakePoint(2.17, 41.38), 4326));

Doing the inverse transform, we get a polygon (box) representing the bounds of the precision -- as determined by the bit length of the base32 encoding.

So, with a precision of 20, this gives,

 SELECT ST_Astext(ST_GeomFromGeoHash(ST_GeoHash(ST_SetSRID(ST_MakePoint(2.17, 41.38), 4326), 20)));

POLYGON((2.16999999999999 41.3799999999999,2.16999999999999 41.3800000000001,2.17000000000031 41.3800000000001,2.17000000000031 41.3799999999999,2.16999999999999 41.3799999999999))

which is an extremely tight box around the original point. If we change the precision to 3, for example, then we get a bounding box of

POLYGON((1.40625 40.78125,1.40625 42.1875,2.8125 42.1875,2.8125 40.78125,1.40625 40.78125))

ie, a range of 1.406 degrees, which corresponds to +/-0.703, potential error around the exact point.

So, going back to your original question, if you have a 3 letter geohash, you can't get beyond 6 decimal places, no matter what precision you request, as there are only 15 bits in a 3 letter word.

SELECT ST_AsText(ST_PointFromGeoHash('sp3'), 7);

yields:

POINT(2.109375 41.484375)

as does

 SELECT ST_AsText(ST_PointFromGeoHash('sp3'), 10);

as you can't get any more precision that that which is contained in a 3 letter base32 encoding.

As you are interested in bounding boxes, you can use the function, ST_Box2dFromGeoHash, which will return the bounding box around a point, based on the rules outlined above.

If you run this function, you will be able to determine the width of your bounding box, and to make the grid denser, you would simply subdivide this box into smaller boxes, and increase the ST_GeoHash precision to get tighter bounds each time.

I do not believe that there is a a built in function, but this would be easy enough to do by chaining together ST_Box2dFromGeoHash, ST_XMin, ST_Ymin, ST_Xmax, ST_Ymax, ST_GeoHash and generate_series twice for the x and y direction and a final generate_series for the precision, ie, conceptually a triple for loop, and each time you increase the precision, you will get a longer hash code.

3
  • Thanks for the detailed answer. What I was looking for is a way to enumerate e.g. 4-letter geohash codes that "bleong to" the 3-letter code geographically. In your example, sp3 has sp3e obviously. But what are the others? Is it sp3[0-9,a-z]? Then, similarly what are the 5-letter codes.
    – tinlyx
    Commented Jul 21, 2019 at 12:57
  • I am uncertain because going down one level of a quad-tree should add two-bits, but adding one letter in geohash seems to add 5-bit to it. Again, this is because I don't know much about geohash, and whether its hierarchical approximated code systems maps to quad-trees.
    – tinlyx
    Commented Jul 21, 2019 at 13:00
  • Yes, because one letter of a base32 encoding is 5 bits. From the wikipedia article, the first "letter" of the base32 alphabet is 0, which corresponds to 00000 and the last letter is z, which corresponds to 11111, ie, 31. So, one level down in the quad tree, will add 10 bits, 5 for each direction. Commented Jul 21, 2019 at 13:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.