blob: c15df783a33f4bdd9177b169b8f5bc3b166e738e [file] [log] [blame]
/*
* Copyright (c) 2013-2014, yinqiwen <yinqiwen@gmail.com>
* Copyright (c) 2014, Matt Stancliff <matt@genges.com>.
* Copyright (c) 2015, Salvatore Sanfilippo <antirez@gmail.com>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This is a C to C++ conversion from the redis project.
* This file started out as:
* https://github.com/antirez/redis/blob/504ccad/src/geohash_helper.h
* + https://github.com/antirez/redis/blob/356a630/src/geohash.h
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
constexpr uint8_t GEO_STEP_MAX = 26; /* 26*2 = 52 bits. */
/* Limits from EPSG:900913 / EPSG:3785 / OSGEO:41001 */
constexpr double GEO_LAT_MIN = -85.05112878;
constexpr double GEO_LAT_MAX = 85.05112878;
constexpr double GEO_LONG_MIN = -180;
constexpr double GEO_LONG_MAX = 180;
enum GeoDirection {
GEOHASH_NORTH = 0,
GEOHASH_EAST,
GEOHASH_WEST,
GEOHASH_SOUTH,
GEOHASH_SOUTH_WEST,
GEOHASH_SOUTH_EAST,
GEOHASH_NORT_WEST,
GEOHASH_NORT_EAST
};
enum GeoShapeType { kGeoShapeTypeNone = 0, kGeoShapeTypeCircular, kGeoShapeTypeRectangular };
struct GeoHashBits {
uint64_t bits = 0;
uint8_t step = 0;
};
struct GeoHashRange {
double min = 0;
double max = 0;
};
struct GeoHashArea {
GeoHashBits hash;
GeoHashRange longitude;
GeoHashRange latitude;
};
struct GeoHashNeighbors {
GeoHashBits north;
GeoHashBits east;
GeoHashBits west;
GeoHashBits south;
GeoHashBits north_east;
GeoHashBits south_east;
GeoHashBits north_west;
GeoHashBits south_west;
};
using GeoHashFix52Bits = uint64_t;
struct GeoHashRadius {
GeoHashBits hash;
GeoHashArea area;
GeoHashNeighbors neighbors;
};
struct GeoShape {
GeoShapeType type;
double xy[2];
double conversion;
double bounds[4];
double radius;
double height;
double width;
};
inline constexpr bool HASHISZERO(const GeoHashBits &r) { return !r.bits && !r.step; }
inline constexpr bool RANGEISZERO(const GeoHashRange &r) { return !bool(r.max) && !bool(r.min); }
inline constexpr bool RANGEPISZERO(const GeoHashRange *r) { return !r || RANGEISZERO(*r); }
inline constexpr void GZERO(GeoHashBits &s) { s.bits = s.step = 0; }
inline constexpr bool GISZERO(const GeoHashBits &s) { return (!s.bits && !s.step); }
inline constexpr bool GISNOTZERO(const GeoHashBits &s) { return (s.bits || s.step); }
/*
* 0:success
* -1:failed
*/
void GeohashGetCoordRange(GeoHashRange *long_range, GeoHashRange *lat_range);
int GeohashEncode(const GeoHashRange *long_range, const GeoHashRange *lat_range, double longitude, double latitude,
uint8_t step, GeoHashBits *hash);
int GeohashEncodeType(double longitude, double latitude, uint8_t step, GeoHashBits *hash);
int GeohashEncodeWGS84(double longitude, double latitude, uint8_t step, GeoHashBits *hash);
int GeohashDecode(const GeoHashRange &long_range, const GeoHashRange &lat_range, const GeoHashBits &hash,
GeoHashArea *area);
int GeohashDecodeType(const GeoHashBits &hash, GeoHashArea *area);
int GeohashDecodeAreaToLongLat(const GeoHashArea *area, double *xy);
int GeohashDecodeToLongLatType(const GeoHashBits &hash, double *xy);
int GeohashDecodeToLongLatWGS84(const GeoHashBits &hash, double *xy);
void GeohashNeighbors(const GeoHashBits *hash, GeoHashNeighbors *neighbors);
class GeoHashHelper {
public:
static uint8_t EstimateStepsByRadius(double range_meters, double lat);
static int BoundingBox(GeoShape *geo_shape);
static GeoHashRadius GetAreasByShapeWGS84(GeoShape &geo_shape);
static GeoHashFix52Bits Align52Bits(const GeoHashBits &hash);
static double GetDistance(double lon1d, double lat1d, double lon2d, double lat2d);
static int GetDistanceIfInRadius(double x1, double y1, double x2, double y2, double radius, double *distance);
static int GetDistanceIfInBox(const double *bounds, double x1, double y1, double x2, double y2, double *distance);
static int GetDistanceIfInRadiusWGS84(double x1, double y1, double x2, double y2, double radius, double *distance);
static int GetDistanceIfInBoxWGS84(const double *bounds, double x1, double y1, double x2, double y2,
double *distance);
};