diff options
Diffstat (limited to 'jstests/core/index/geo/geo_center_sphere2.js')
-rw-r--r-- | jstests/core/index/geo/geo_center_sphere2.js | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/jstests/core/index/geo/geo_center_sphere2.js b/jstests/core/index/geo/geo_center_sphere2.js new file mode 100644 index 00000000000..1c59850d841 --- /dev/null +++ b/jstests/core/index/geo/geo_center_sphere2.js @@ -0,0 +1,158 @@ +// @tags: [ +// requires_getmore, +// ] + +// +// Tests the error handling of spherical queries +// along with multi-location documents. +// This is necessary since the error handling must manage +// multiple documents, and so requires simultaneous testing. +// + +load("jstests/libs/geo_math.js"); + +function computexscandist(y, maxDistDegrees) { + return maxDistDegrees / + Math.min(Math.cos(deg2rad(Math.min(89.0, y + maxDistDegrees))), + Math.cos(deg2rad(Math.max(-89.0, y - maxDistDegrees)))); +} + +function pointIsOK(startPoint, radius) { + yscandist = rad2deg(radius) + 0.01; + xscandist = computexscandist(startPoint[1], yscandist); + return (startPoint[0] + xscandist < 180) && (startPoint[0] - xscandist > -180) && + (startPoint[1] + yscandist < 90) && (startPoint[1] - yscandist > -90); +} + +var numTests = 30; + +for (var test = 0; test < numTests; test++) { + Random.srand(1337 + test); + + var radius = 5000 * Random.rand(); // km + radius = radius / 6378.1; // radians; earth radius from geoconstants.h + var numDocs = Math.floor(400 * Random.rand()); + // TODO: Wrapping uses the error value to figure out what would overlap... + var bits = Math.floor(5 + Random.rand() * 28); + var maxPointsPerDoc = 50; + + var t = db.sphere; + + var randomPoint = function() { + return [Random.rand() * 360 - 180, Random.rand() * 180 - 90]; + }; + + // Get a start point that doesn't require wrapping + // TODO: Are we a bit too aggressive with wrapping issues? + var startPoint; + var ex = null; + do { + t.drop(); + startPoint = randomPoint(); + t.createIndex({loc: "2d"}, {bits: bits}); + } while (!pointIsOK(startPoint, radius)); + + var pointsIn = 0; + var pointsOut = 0; + var docsIn = 0; + var docsOut = 0; + var totalPoints = 0; + + var bulk = t.initializeUnorderedBulkOp(); + for (var i = 0; i < numDocs; i++) { + var numPoints = Math.floor(Random.rand() * maxPointsPerDoc + 1); + var docIn = false; + var multiPoint = []; + + totalPoints += numPoints; + + for (var p = 0; p < numPoints; p++) { + var point = randomPoint(); + multiPoint.push(point); + + if (Geo.sphereDistance(startPoint, point) <= radius) { + pointsIn++; + docIn = true; + } else { + pointsOut++; + } + } + + bulk.insert({loc: multiPoint}); + + if (docIn) + docsIn++; + else + docsOut++; + } + + printjson({ + test: test, + radius: radius, + bits: bits, + numDocs: numDocs, + pointsIn: pointsIn, + docsIn: docsIn, + pointsOut: pointsOut, + docsOut: docsOut + }); + + assert.commandWorked(bulk.execute()); + assert.eq(docsIn + docsOut, numDocs); + assert.eq(pointsIn + pointsOut, totalPoints); + + // $centerSphere + assert.eq(docsIn, t.find({loc: {$within: {$centerSphere: [startPoint, radius]}}}).count()); + + // $nearSphere + var cursor = t.find({loc: {$nearSphere: startPoint, $maxDistance: radius}}); + var results = cursor.limit(2 * pointsIn).toArray(); + + assert.eq(docsIn, results.length); + + var distance = 0; + for (var i = 0; i < results.length; i++) { + var minNewDistance = radius + 1; + for (var j = 0; j < results[i].loc.length; j++) { + var newDistance = Geo.sphereDistance(startPoint, results[i].loc[j]); + if (newDistance < minNewDistance && newDistance >= distance) { + minNewDistance = newDistance; + } + } + + // print( "Dist from : " + results[i].loc[j] + " to " + startPoint + " is " + // + minNewDistance + " vs " + radius ) + + assert.lte(minNewDistance, radius); + assert.gte(minNewDistance, distance); + distance = minNewDistance; + } + + // Test $geoNear. + results = t.aggregate({ + $geoNear: { + near: startPoint, + distanceField: "dis", + maxDistance: radius, + spherical: true, + } + }).toArray(); + assert.eq(docsIn, results.length, tojson(results)); + + var distance = 0; + for (var i = 0; i < results.length; i++) { + var retDistance = results[i].dis; + + var distInObj = false; + for (var j = 0; j < results[i].loc.length && distInObj == false; j++) { + var newDistance = Geo.sphereDistance(startPoint, results[i].loc[j]); + distInObj = + (newDistance >= retDistance - 0.0001 && newDistance <= retDistance + 0.0001); + } + + assert(distInObj); + assert.lte(retDistance, radius); + assert.gte(retDistance, distance); + distance = retDistance; + } +} |