Opened 8 years ago

Closed 7 years ago

#3723 closed defect (fixed)

st_geohash not correct for some multipoint

Reported by: hzhang Owned by: pramsey
Priority: high Milestone: PostGIS 2.5.0
Component: postgis Version: 2.2.x
Keywords: st_geohash Cc:

Description

Please correct me if I am wrong.

for example,

postgres=# select st_astext(st_geomfromgeohash('z'));
                   st_astext                   
-----------------------------------------------
 POLYGON((135 45,135 90,180 90,180 45,135 45))
(1 row)
 

if point/linestring/polygon exist in above bbox should be hashed to 'z', but


 
postgres=# select st_geohash(st_geomfromtext('multipoint(166.2 60.2, 175.6 67.5)'));
 st_geohash
------------
 
(1 row)

does not yield 'z' here, which that multipoint exists in that box.

My version is: POSTGIS="2.2.2 r14797" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.11.4, released 2016/01/25" LIBXML="2.9.1" LIBJSON="0.11" TOPOLOGY RASTER

Change History (5)

comment:1 by hzhang, 8 years ago

another example:

for LINESTRING (1 1, 40 40)

bbox of that linestring is:
select ST_extent('LINESTRING (1 1, 40 40)');
   st_extent    
----------------
 BOX(1 1,40 40)
(1 row)

and bbox for geohash 's' is:
select ST_Box2dFromGeoHash('s');
 st_box2dfromgeohash 
---------------------
 BOX(0 0,45 45)
(1 row)


it clearly shows that linestring is within that 's' bbox, but the st_geohash function doesn't return s:

SELECT ST_GeoHash(ST_GeographyFromText('LINESTRING (1 1, 40 40)')) geohash;
 geohash 
---------
 
(1 row)

or:

postgres=# select ST_Within(a , b) from ( select ST_extent('LINESTRING (1 1, 40 40)') as a, ST_Box2dFromGeoHash('s') as b) as foo;
 st_within 
-----------
 t
(1 row)



comment:2 by robe, 8 years ago

Milestone: PostGIS 2.3.3PostGIS 2.4.0

comment:3 by robe, 7 years ago

I think the issue here has to do with how ST_GeoHash computes it's default precision. In the examples you demonstrated, it decided the best precision is 0 which always returns nothing.

So for example:

SELECT ST_GeoHash(ST_GeomFromText('LINESTRING (1 1, 40 40)') ,2 );

yields:

s7

Which is probably closer to what you are expecting but then that is wrong too since it doesn't cover the linestring so it needs a lower precision than that. 1, would give you the right answer.

Same case here:

SELECT st_geohash(st_geomfromtext('multipoint(166.2 60.2, 175.6 67.5)'),1);

yields:

z

I wonder if it would be safe to change the precision to 1 in cases where it decides precision should be 0.

comment:4 by robe, 7 years ago

Milestone: PostGIS 2.4.0PostGIS 2.5.0

comment:5 by pramsey, 7 years ago

Resolution: fixed
Status: newclosed

Interesting. Geohash is really annoying in that each char carries 5 bits of information, so not a complete cycle of x/y adjustments of the bounds in the algorithm. The issue was that one calculation was returning only a complete cycle of info (the precision calc) while the other was returning the partial cycles (the bounds calc). It seems that adjusting the precision calc to do partials makes things better without making things worse, so I've done that.

Trunk at r15661

Note: See TracTickets for help on using tickets.