mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 01:21:03 +01:00
check spherical earth query bounds SERVER-2980
This commit is contained in:
parent
be124009c2
commit
aa13edaae8
@ -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) {
|
||||
|
@ -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); }
|
||||
|
||||
|
42
jstests/geo_oob_sphere.js
Normal file
42
jstests/geo_oob_sphere.js
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// Ensures spherical queries report invalid latitude values in points and center positions
|
||||
//
|
||||
|
||||
t = db.geooobsphere
|
||||
t.drop();
|
||||
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 89 } })
|
||||
t.insert({ loc : { x : 30, y : 91 } })
|
||||
|
||||
t.ensureIndex({ loc : "2d" })
|
||||
assert.isnull( db.getLastError() )
|
||||
|
||||
t.find({ loc : { $nearSphere : [ 30, 91 ], $maxDistance : 0.25 } }).count()
|
||||
var err = db.getLastError()
|
||||
assert( err != null )
|
||||
printjson( err )
|
||||
|
||||
t.find({ loc : { $nearSphere : [ 30, 89 ], $maxDistance : 0.25 } }).count()
|
||||
var err = db.getLastError()
|
||||
assert( err != null )
|
||||
printjson( err )
|
||||
|
||||
t.find({ loc : { $within : { $centerSphere : [[ -180, -91 ], 0.25] } } }).count()
|
||||
var err = db.getLastError()
|
||||
assert( err != null )
|
||||
printjson( err )
|
||||
|
||||
db.runCommand({ geoNear : "geooobsphere", near : [179, -91], maxDistance : 0.25, spherical : true })
|
||||
var err = db.getLastError()
|
||||
assert( err != null )
|
||||
printjson( err )
|
||||
|
||||
db.runCommand({ geoNear : "geooobsphere", near : [30, 89], maxDistance : 0.25, spherical : true })
|
||||
var err = db.getLastError()
|
||||
assert( err != null )
|
||||
printjson( err )
|
Loading…
Reference in New Issue
Block a user