diff options
author | gregs <greg@10gen.com> | 2011-05-06 10:22:08 -0400 |
---|---|---|
committer | gregs <greg@10gen.com> | 2011-05-06 13:31:26 -0400 |
commit | aa13edaae8449d76d16d3931428c6bd922cbb81f (patch) | |
tree | 229178cdfa416c175f0f49196a9e1746a22ada83 /db/geo | |
parent | be124009c226d122979fb11623dc3f98aaa1c3be (diff) | |
download | mongo-aa13edaae8449d76d16d3931428c6bd922cbb81f.tar.gz |
check spherical earth query bounds SERVER-2980
Diffstat (limited to 'db/geo')
-rw-r--r-- | db/geo/2d.cpp | 31 | ||||
-rw-r--r-- | db/geo/core.h | 6 |
2 files changed, 27 insertions, 10 deletions
diff --git a/db/geo/2d.cpp b/db/geo/2d.cpp index 2404bf6df8a..a2c864aff5e 100644 --- a/db/geo/2d.cpp +++ b/db/geo/2d.cpp @@ -1599,12 +1599,14 @@ namespace mongo { double approxDistance( const GeoHash& h ) { double approxDistance = -1; + Point p( _g, h ); switch (_type) { case GEO_PLAIN: - approxDistance = _near.distance( Point( _g, h ) ); + approxDistance = _near.distance( p ); break; case GEO_SPHERE: - approxDistance = spheredist_deg( _near, Point( _g, h ) ); + checkEarthBounds( p ); + approxDistance = spheredist_deg( _near, p ); break; default: assert( false ); } @@ -1636,14 +1638,17 @@ namespace mongo { double exactDistance = -1; bool exactWithin = false; + Point p( loc ); + // Get the appropriate distance for the type switch ( _type ) { case GEO_PLAIN: - exactDistance = _near.distance( Point( loc ) ); - exactWithin = _near.distanceWithin( Point( loc ), _maxDistance ); + exactDistance = _near.distance( p ); + exactWithin = _near.distanceWithin( p, _maxDistance ); break; case GEO_SPHERE: - exactDistance = spheredist_deg( _near, Point( loc ) ); + checkEarthBounds( p ); + exactDistance = spheredist_deg( _near, p ); exactWithin = ( exactDistance <= _maxDistance ); break; default: assert( false ); @@ -1723,6 +1728,7 @@ namespace mongo { _scanDistance = maxDistance + _spec->_error; } else if (type == GEO_SPHERE) { + checkEarthBounds( startPt ); // TODO: consider splitting into x and y scan distances _scanDistance = computeXScanDistance( startPt._y, rad2deg( _maxDistance ) + _spec->_error ); } @@ -1927,6 +1933,7 @@ namespace mongo { // Same, but compute maxDistance using spherical transform uassert(13461, "Spherical MaxDistance > PI. Are you sure you are using radians?", _maxDistance < M_PI); + checkEarthBounds( _startPt ); _type = GEO_SPHERE; _yScanDistance = rad2deg( _maxDistance ) + _g->_error; @@ -1973,10 +1980,13 @@ namespace mongo { d = _g->distance( _start , h ); error = _g->_error; break; - case GEO_SPHERE: - d = spheredist_deg( _startPt, Point( _g, h ) ); + case GEO_SPHERE: { + Point p( _g, h ); + checkEarthBounds( p ); + d = spheredist_deg( _startPt, p ); error = _g->_errorSphere; break; + } default: assert( false ); } @@ -1991,17 +2001,19 @@ namespace mongo { GEODEBUG( "Inexact distance : " << d << " vs " << _maxDistance << " from " << ( *i ).toString() << " due to error " << error ); + Point p( *i ); // Exact distance checks. switch (_type) { case GEO_PLAIN: { - if( _startPt.distanceWithin( Point( *i ), _maxDistance ) ) return true; + if( _startPt.distanceWithin( p, _maxDistance ) ) return true; break; } case GEO_SPHERE: // Ignore all locations not hashed to the key's hash, since spherical calcs are // more expensive. if( _g->_hash( *i ) != h ) break; - if( spheredist_deg( _startPt , Point( *i ) ) <= _maxDistance ) return true; + checkEarthBounds( p ); + if( spheredist_deg( _startPt , p ) <= _maxDistance ) return true; break; default: assert( false ); } @@ -2373,7 +2385,6 @@ namespace mongo { if ( cmdObj["spherical"].trueValue() ) type = GEO_SPHERE; - // We're returning exact distances, so don't evaluate lazily. GeoSearch gs( g , n , numWanted , filter , maxDistance , type ); if ( cmdObj["start"].type() == String) { diff --git a/db/geo/core.h b/db/geo/core.h index 684b6e49b4a..109495066c0 100644 --- a/db/geo/core.h +++ b/db/geo/core.h @@ -454,6 +454,12 @@ namespace mongo { extern const double EARTH_RADIUS_KM; extern const double EARTH_RADIUS_MILES; + // Technically lat/long bounds, not really tied to earth radius. + inline void checkEarthBounds( Point p ) { + uassert( 14808, str::stream() << "point " << p.toString() << " must be in earth-like bounds of long : [-180, 180), lat : [-90, 90] ", + p._x >= -180 && p._x < 180 && p._y >= -90 && p._y <= 90 ); + } + inline double deg2rad(double deg) { return deg * (M_PI/180); } inline double rad2deg(double rad) { return rad * (180/M_PI); } |