diff options
Diffstat (limited to 'db/geo/core.h')
-rw-r--r-- | db/geo/core.h | 153 |
1 files changed, 81 insertions, 72 deletions
diff --git a/db/geo/core.h b/db/geo/core.h index 13f3636..602b513 100644 --- a/db/geo/core.h +++ b/db/geo/core.h @@ -31,23 +31,23 @@ namespace mongo { class GeoBitSets { public: - GeoBitSets(){ - for ( int i=0; i<32; i++ ){ + GeoBitSets() { + for ( int i=0; i<32; i++ ) { masks32[i] = ( 1 << ( 31 - i ) ); } - for ( int i=0; i<64; i++ ){ + for ( int i=0; i<64; i++ ) { masks64[i] = ( 1LL << ( 63 - i ) ); } - - for ( unsigned i=0; i<16; i++ ){ + + for ( unsigned i=0; i<16; i++ ) { unsigned fixed = 0; - for ( int j=0; j<4; j++ ){ + for ( int j=0; j<4; j++ ) { if ( i & ( 1 << j ) ) fixed |= ( 1 << ( j * 2 ) ); } hashedToNormal[fixed] = i; } - + } int masks32[32]; long long masks64[64]; @@ -56,24 +56,24 @@ namespace mongo { }; extern GeoBitSets geoBitSets; - + class GeoHash { public: GeoHash() - : _hash(0),_bits(0){ + : _hash(0),_bits(0) { } - explicit GeoHash( const char * hash ){ + explicit GeoHash( const char * hash ) { init( hash ); } - explicit GeoHash( const string& hash ){ + explicit GeoHash( const string& hash ) { init( hash ); } - explicit GeoHash( const BSONElement& e , unsigned bits=32 ){ + explicit GeoHash( const BSONElement& e , unsigned bits=32 ) { _bits = bits; - if ( e.type() == BinData ){ + if ( e.type() == BinData ) { int len = 0; _copy( (char*)&_hash , e.binData( len ) ); assert( len == 8 ); @@ -85,26 +85,26 @@ namespace mongo { } _fix(); } - - GeoHash( unsigned x , unsigned y , unsigned bits=32){ + + GeoHash( unsigned x , unsigned y , unsigned bits=32) { init( x , y , bits ); } - GeoHash( const GeoHash& old ){ + GeoHash( const GeoHash& old ) { _hash = old._hash; _bits = old._bits; } GeoHash( long long hash , unsigned bits ) - : _hash( hash ) , _bits( bits ){ + : _hash( hash ) , _bits( bits ) { _fix(); } - void init( unsigned x , unsigned y , unsigned bits ){ + void init( unsigned x , unsigned y , unsigned bits ) { assert( bits <= 32 ); _hash = 0; _bits = bits; - for ( unsigned i=0; i<bits; i++ ){ + for ( unsigned i=0; i<bits; i++ ) { if ( isBitSet( x , i ) ) _hash |= geoBitSets.masks64[i*2]; if ( isBitSet( y , i ) ) _hash |= geoBitSets.masks64[(i*2)+1]; } @@ -114,7 +114,7 @@ namespace mongo { x = 0; y = 0; char * c = (char*)(&_hash); - for ( int i=0; i<8; i++ ){ + for ( int i=0; i<8; i++ ) { unsigned t = (unsigned)(c[i]) & 0x55; y |= ( geoBitSets.hashedToNormal[t] << (4*(i)) ); @@ -126,7 +126,7 @@ namespace mongo { void unhash_slow( unsigned& x , unsigned& y ) const { x = 0; y = 0; - for ( unsigned i=0; i<_bits; i++ ){ + for ( unsigned i=0; i<_bits; i++ ) { if ( getBitX(i) ) x |= geoBitSets.masks32[i]; if ( getBitY(i) ) @@ -141,14 +141,14 @@ namespace mongo { /** * @param 0 = high */ - static bool isBitSet( unsigned val , unsigned bit ){ + static bool isBitSet( unsigned val , unsigned bit ) { return geoBitSets.masks32[bit] & val; } - + GeoHash up() const { return GeoHash( _hash , _bits - 1 ); } - + bool hasPrefix( const GeoHash& other ) const { assert( other._bits <= _bits ); if ( other._bits == 0 ) @@ -157,9 +157,9 @@ namespace mongo { x = x >> (64-(other._bits*2)); return x == 0; } - - string toString() const { + + string toString() const { StringBuilder buf( _bits * 2 ); for ( unsigned x=0; x<_bits*2; x++ ) buf.append( _hash & geoBitSets.masks64[x] ? "1" : "0" ); @@ -172,7 +172,7 @@ namespace mongo { return ss.str(); } - void init( const string& s ){ + void init( const string& s ) { _hash = 0; _bits = s.size() / 2; for ( unsigned pos=0; pos<s.size(); pos++ ) @@ -180,14 +180,14 @@ namespace mongo { setBit( pos , 1 ); } - void setBit( unsigned pos , bool one ){ + void setBit( unsigned pos , bool one ) { assert( pos < _bits * 2 ); if ( one ) _hash |= geoBitSets.masks64[pos]; else if ( _hash & geoBitSets.masks64[pos] ) _hash &= ~geoBitSets.masks64[pos]; } - + bool getBit( unsigned pos ) const { return _hash & geoBitSets.masks64[pos]; } @@ -201,7 +201,7 @@ namespace mongo { assert( pos < 32 ); return getBit( ( pos * 2 ) + 1 ); } - + BSONObj wrap() const { BSONObjBuilder b(20); append( b , "" ); @@ -213,20 +213,20 @@ namespace mongo { bool constrains() const { return _bits > 0; } - - void move( int x , int y ){ + + void move( int x , int y ) { assert( _bits ); _move( 0 , x ); _move( 1 , y ); } - void _move( unsigned offset , int d ){ + void _move( unsigned offset , int d ) { if ( d == 0 ) return; assert( d <= 1 && d>= -1 ); // TEMP - + bool from, to; - if ( d > 0 ){ + if ( d > 0 ) { from = 0; to = 1; } @@ -238,34 +238,34 @@ namespace mongo { unsigned pos = ( _bits * 2 ) - 1; if ( offset == 0 ) pos--; - while ( true ){ - if ( getBit(pos) == from ){ + while ( true ) { + if ( getBit(pos) == from ) { setBit( pos , to ); return; } - if ( pos < 2 ){ + if ( pos < 2 ) { // overflow - for ( ; pos < ( _bits * 2 ) ; pos += 2 ){ + for ( ; pos < ( _bits * 2 ) ; pos += 2 ) { setBit( pos , from ); } return; } - + setBit( pos , from ); pos -= 2; } - + assert(0); } - GeoHash& operator=(const GeoHash& h) { + GeoHash& operator=(const GeoHash& h) { _hash = h._hash; _bits = h._bits; return *this; } - - bool operator==(const GeoHash& h ){ + + bool operator==(const GeoHash& h ) { return _hash == h._hash && _bits == h._bits; } @@ -273,7 +273,7 @@ namespace mongo { unsigned pos = _bits * 2; _bits += strlen(s) / 2; assert( _bits <= 32 ); - while ( s[0] ){ + while ( s[0] ) { if ( s[0] == '1' ) setBit( pos , 1 ); pos++; @@ -288,19 +288,19 @@ namespace mongo { n+=s; return n; } - - void _fix(){ + + void _fix() { static long long FULL = 0xFFFFFFFFFFFFFFFFLL; long long mask = FULL << ( 64 - ( _bits * 2 ) ); _hash &= mask; } - + void append( BSONObjBuilder& b , const char * name ) const { char buf[8]; _copy( buf , (char*)&_hash ); b.appendBinData( name , 8 , bdtCustom , buf ); } - + long long getHash() const { return _hash; } @@ -311,9 +311,9 @@ namespace mongo { GeoHash commonPrefix( const GeoHash& other ) const { unsigned i=0; - for ( ; i<_bits && i<other._bits; i++ ){ + for ( ; i<_bits && i<other._bits; i++ ) { if ( getBitX( i ) == other.getBitX( i ) && - getBitY( i ) == other.getBitY( i ) ) + getBitY( i ) == other.getBitY( i ) ) continue; break; } @@ -323,7 +323,7 @@ namespace mongo { private: void _copy( char * dst , const char * src ) const { - for ( unsigned a=0; a<8; a++ ){ + for ( unsigned a=0; a<8; a++ ) { dst[a] = src[7-a]; } } @@ -332,14 +332,14 @@ namespace mongo { unsigned _bits; // bits per field, so 1 to 32 }; - inline ostream& operator<<( ostream &s, const GeoHash &h ){ + inline ostream& operator<<( ostream &s, const GeoHash &h ) { s << h.toString(); return s; - } + } class GeoConvert { public: - virtual ~GeoConvert(){} + virtual ~GeoConvert() {} virtual void unhash( const GeoHash& h , double& x , double& y ) const = 0; virtual GeoHash hash( double x , double y ) const = 0; @@ -347,31 +347,31 @@ namespace mongo { class Point { public: - - Point( const GeoConvert * g , const GeoHash& hash ){ + + Point( const GeoConvert * g , const GeoHash& hash ) { g->unhash( hash , _x , _y ); } - - explicit Point( const BSONElement& e ){ + + explicit Point( const BSONElement& e ) { BSONObjIterator i(e.Obj()); _x = i.next().number(); _y = i.next().number(); } - explicit Point( const BSONObj& o ){ + explicit Point( const BSONObj& o ) { BSONObjIterator i(o); _x = i.next().number(); _y = i.next().number(); } Point( double x , double y ) - : _x( x ) , _y( y ){ + : _x( x ) , _y( y ) { } - - Point() : _x(0),_y(0){ + + Point() : _x(0),_y(0) { } - GeoHash hash( const GeoConvert * g ){ + GeoHash hash( const GeoConvert * g ) { return g->hash( _x , _y ); } @@ -380,12 +380,12 @@ namespace mongo { double b = _y - p._y; return sqrt( ( a * a ) + ( b * b ) ); } - + string toString() const { StringBuilder buf(32); buf << "(" << _x << "," << _y << ")"; return buf.str(); - + } double _x; @@ -393,8 +393,11 @@ namespace mongo { }; - extern double EARTH_RADIUS_KM; - extern double EARTH_RADIUS_MILES; + extern const double EARTH_RADIUS_KM; + extern const double EARTH_RADIUS_MILES; + + inline double deg2rad(double deg) { return deg * (M_PI/180); } + inline double rad2deg(double rad) { return rad * (180/M_PI); } // WARNING: _x and _y MUST be longitude and latitude in that order // note: multiply by earth radius for distance @@ -407,20 +410,26 @@ namespace mongo { double sin_y1(sin(p1._y)), cos_y1(cos(p1._y)); double sin_x2(sin(p2._x)), cos_x2(cos(p2._x)); double sin_y2(sin(p2._y)), cos_y2(cos(p2._y)); - - double cross_prod = + + double cross_prod = (cos_y1*cos_x1 * cos_y2*cos_x2) + (cos_y1*sin_x1 * cos_y2*sin_x2) + (sin_y1 * sin_y2); + if (cross_prod >= 1 || cross_prod <= -1) { + // fun with floats + assert( fabs(cross_prod)-1 < 1e-6 ); + return cross_prod > 0 ? 0 : M_PI; + } + return acos(cross_prod); } // note: return is still in radians as that can be multiplied by radius to get arc length inline double spheredist_deg( const Point& p1, const Point& p2 ) { return spheredist_rad( - Point( p1._x * (M_PI/180), p1._y * (M_PI/180)), - Point( p2._x * (M_PI/180), p2._y * (M_PI/180)) + Point( deg2rad(p1._x), deg2rad(p1._y) ), + Point( deg2rad(p2._x), deg2rad(p2._y) ) ); } |