GeoHashRadius geohashGetAreasByRadius(uint8_t coord_type, double latitude, double longitude, double radius_meters) { GeoHashRange lat_range, long_range; GeoHashRadius radius = { { 0 } }; GeoHashBits hash = { 0 }; GeoHashNeighbors neighbors = { { 0 } }; GeoHashArea area = { { 0 } }; double delta_longitude, delta_latitude; double min_lat, max_lat, min_lon, max_lon; int steps; if (coord_type == GEO_WGS84_TYPE) { double bounds[4]; geohashBoundingBox(latitude, longitude, radius_meters, bounds); min_lat = bounds[0]; min_lon = bounds[1]; max_lat = bounds[2]; max_lon = bounds[3]; } else { delta_latitude = delta_longitude = radius_meters; min_lat = latitude - delta_latitude; max_lat = latitude + delta_latitude; min_lon = longitude - delta_longitude; max_lon = longitude + delta_longitude; } steps = geohashEstimateStepsByRadius(radius_meters); geohashGetCoordRange(coord_type, &lat_range, &long_range); geohashEncode(lat_range, long_range, latitude, longitude, steps, &hash); geohashNeighbors(&hash, &neighbors); geohashDecode(lat_range, long_range, hash, &area); if (area.latitude.min < min_lat) { GZERO(neighbors.south); GZERO(neighbors.south_west); GZERO(neighbors.south_east); } if (area.latitude.max > max_lat) { GZERO(neighbors.north); GZERO(neighbors.north_east); GZERO(neighbors.north_west); } if (area.longitude.min < min_lon) { GZERO(neighbors.west); GZERO(neighbors.south_west); GZERO(neighbors.north_west); } if (area.longitude.max > max_lon) { GZERO(neighbors.east); GZERO(neighbors.south_east); GZERO(neighbors.north_east); } radius.hash = hash; radius.neighbors = neighbors; radius.area = area; return radius; }
/* Return a set of areas (center + 8) that are able to cover a range query * for the specified position and radius. */ GeoHashRadius geohashGetAreasByRadius(double longitude, double latitude, double radius_meters) { GeoHashRange long_range, lat_range; GeoHashRadius radius; GeoHashBits hash; GeoHashNeighbors neighbors; GeoHashArea area; double min_lon, max_lon, min_lat, max_lat; double bounds[4]; int steps; geohashBoundingBox(longitude, latitude, radius_meters, bounds); min_lon = bounds[0]; min_lat = bounds[1]; max_lon = bounds[2]; max_lat = bounds[3]; steps = geohashEstimateStepsByRadius(radius_meters,latitude); geohashGetCoordRange(&long_range,&lat_range); geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash); geohashNeighbors(&hash,&neighbors); geohashDecode(long_range,lat_range,hash,&area); /* Check if the step is enough at the limits of the covered area. * Sometimes when the search area is near an edge of the * area, the estimated step is not small enough, since one of the * north / south / west / east square is too near to the search area * to cover everything. */ int decrease_step = 0; { GeoHashArea north, south, east, west; geohashDecode(long_range, lat_range, neighbors.north, &north); geohashDecode(long_range, lat_range, neighbors.south, &south); geohashDecode(long_range, lat_range, neighbors.east, &east); geohashDecode(long_range, lat_range, neighbors.west, &west); if (geohashGetDistance(longitude,latitude,longitude,north.latitude.max) < radius_meters) decrease_step = 1; if (geohashGetDistance(longitude,latitude,longitude,south.latitude.min) < radius_meters) decrease_step = 1; if (geohashGetDistance(longitude,latitude,east.longitude.max,latitude) < radius_meters) decrease_step = 1; if (geohashGetDistance(longitude,latitude,west.longitude.min,latitude) < radius_meters) decrease_step = 1; } if (decrease_step) { steps--; geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash); geohashNeighbors(&hash,&neighbors); geohashDecode(long_range,lat_range,hash,&area); } /* Exclude the search areas that are useless. */ if (area.latitude.min < min_lat) { GZERO(neighbors.south); GZERO(neighbors.south_west); GZERO(neighbors.south_east); } if (area.latitude.max > max_lat) { GZERO(neighbors.north); GZERO(neighbors.north_east); GZERO(neighbors.north_west); } if (area.longitude.min < min_lon) { GZERO(neighbors.west); GZERO(neighbors.south_west); GZERO(neighbors.north_west); } if (area.longitude.max > max_lon) { GZERO(neighbors.east); GZERO(neighbors.south_east); GZERO(neighbors.north_east); } radius.hash = hash; radius.neighbors = neighbors; radius.area = area; return radius; }