// // More tests for N-dimensional polygon querying // // Create a polygon of some shape (no holes) // using turtle graphics. Basically, will look like a very contorted octopus (quad-pus?) shape. // There are no holes, but some edges will probably touch. var numTests = 4; for (var test = 0; test < numTests; test++) { Random.srand(1337 + test); var numTurtles = 4; var gridSize = [20, 20]; var turtleSteps = 500; var bounds = [Random.rand() * -1000000 + 0.00001, Random.rand() * 1000000 + 0.00001]; var rotation = Math.PI * Random.rand(); var bits = Math.floor(Random.rand() * 32); printjson({test: test, rotation: rotation, bits: bits}); var rotatePoint = function(x, y) { if (y == undefined) { y = x[1]; x = x[0]; } xp = x * Math.cos(rotation) - y * Math.sin(rotation); yp = y * Math.cos(rotation) + x * Math.sin(rotation); var scaleX = (bounds[1] - bounds[0]) / 360; var scaleY = (bounds[1] - bounds[0]) / 360; x *= scaleX; y *= scaleY; return [xp, yp]; }; var grid = []; for (var i = 0; i < gridSize[0]; i++) { grid.push(new Array(gridSize[1])); } grid.toString = function() { var gridStr = ""; for (var j = grid[0].length - 1; j >= -1; j--) { for (var i = 0; i < grid.length; i++) { if (i == 0) gridStr += (j == -1 ? " " : (j % 10)) + ": "; if (j != -1) gridStr += "[" + (grid[i][j] != undefined ? grid[i][j] : " ") + "]"; else gridStr += " " + (i % 10) + " "; } gridStr += "\n"; } return gridStr; }; var turtles = []; for (var i = 0; i < numTurtles; i++) { var up = (i % 2 == 0) ? i - 1 : 0; var left = (i % 2 == 1) ? (i - 1) - 1 : 0; turtles[i] = [ [Math.floor(gridSize[0] / 2), Math.floor(gridSize[1] / 2)], [Math.floor(gridSize[0] / 2) + left, Math.floor(gridSize[1] / 2) + up] ]; grid[turtles[i][1][0]][turtles[i][1][1]] = i; } grid[Math.floor(gridSize[0] / 2)][Math.floor(gridSize[1] / 2)] = "S"; // print( grid.toString() ) var pickDirections = function() { var up = Math.floor(Random.rand() * 3); if (up == 2) up = -1; if (up == 0) { var left = Math.floor(Random.rand() * 3); if (left == 2) left = -1; } else left = 0; if (Random.rand() < 0.5) { var swap = left; left = up; up = swap; } return [left, up]; }; for (var s = 0; s < turtleSteps; s++) { for (var t = 0; t < numTurtles; t++) { var dirs = pickDirections(); var up = dirs[0]; var left = dirs[1]; var lastTurtle = turtles[t][turtles[t].length - 1]; var nextTurtle = [lastTurtle[0] + left, lastTurtle[1] + up]; if (nextTurtle[0] >= gridSize[0] || nextTurtle[1] >= gridSize[1] || nextTurtle[0] < 0 || nextTurtle[1] < 0) continue; if (grid[nextTurtle[0]][nextTurtle[1]] == undefined) { turtles[t].push(nextTurtle); grid[nextTurtle[0]][nextTurtle[1]] = t; } } } turtlePaths = []; for (var t = 0; t < numTurtles; t++) { turtlePath = []; var nextSeg = function(currTurtle, prevTurtle) { var pathX = currTurtle[0]; if (currTurtle[1] < prevTurtle[1]) { pathX = currTurtle[0] + 1; pathY = prevTurtle[1]; } else if (currTurtle[1] > prevTurtle[1]) { pathX = currTurtle[0]; pathY = currTurtle[1]; } else if (currTurtle[0] < prevTurtle[0]) { pathX = prevTurtle[0]; pathY = currTurtle[1]; } else if (currTurtle[0] > prevTurtle[0]) { pathX = currTurtle[0]; pathY = currTurtle[1] + 1; } // print( " Prev : " + prevTurtle + " Curr : " + currTurtle + " path // : " // + [pathX, pathY]); return [pathX, pathY]; }; for (var s = 1; s < turtles[t].length; s++) { currTurtle = turtles[t][s]; prevTurtle = turtles[t][s - 1]; turtlePath.push(nextSeg(currTurtle, prevTurtle)); } for (var s = turtles[t].length - 2; s >= 0; s--) { currTurtle = turtles[t][s]; prevTurtle = turtles[t][s + 1]; turtlePath.push(nextSeg(currTurtle, prevTurtle)); } // printjson( turtlePath ) // End of the line is not inside our polygon. var lastTurtle = turtles[t][turtles[t].length - 1]; grid[lastTurtle[0]][lastTurtle[1]] = undefined; fixedTurtlePath = []; for (var s = 1; s < turtlePath.length; s++) { if (turtlePath[s - 1][0] == turtlePath[s][0] && turtlePath[s - 1][1] == turtlePath[s][1]) { continue; } var up = turtlePath[s][1] - turtlePath[s - 1][1]; var right = turtlePath[s][0] - turtlePath[s - 1][0]; var addPoint = (up != 0 && right != 0); if (addPoint && up != right) { fixedTurtlePath.push([turtlePath[s][0], turtlePath[s - 1][1]]); } else if (addPoint) { fixedTurtlePath.push([turtlePath[s - 1][0], turtlePath[s][1]]); } fixedTurtlePath.push(turtlePath[s]); } // printjson( fixedTurtlePath ) turtlePaths.push(fixedTurtlePath); } // Uncomment to print polygon shape // print( grid.toString() ) var polygon = []; for (var t = 0; t < turtlePaths.length; t++) { for (var s = 0; s < turtlePaths[t].length; s++) { polygon.push(rotatePoint(turtlePaths[t][s])); } } // Uncomment to print out polygon // printjson( polygon ) t = db.polytest2; t.drop(); // Test single and multi-location documents var pointsIn = 0; var pointsOut = 0; var allPointsIn = []; var allPointsOut = []; for (var j = grid[0].length - 1; j >= 0; j--) { for (var i = 0; i < grid.length; i++) { var point = rotatePoint([i + 0.5, j + 0.5]); t.insert({loc: point}); if (grid[i][j] != undefined) { allPointsIn.push(point); pointsIn++; } else { allPointsOut.push(point); pointsOut++; } } } var res = t.ensureIndex({loc: "2d"}, {bits: 1 + bits, max: bounds[1], min: bounds[0]}); assert.commandWorked(res); t.insert({loc: allPointsIn}); t.insert({loc: allPointsOut}); allPoints = allPointsIn.concat(allPointsOut); t.insert({loc: allPoints}); print("Points : "); printjson({pointsIn: pointsIn, pointsOut: pointsOut}); // print( t.find( { loc : { "$within" : { "$polygon" : polygon } } } ).count() ) assert.eq(gridSize[0] * gridSize[1] + 3, t.find().count()); assert.eq(2 + pointsIn, t.find({loc: {"$within": {"$polygon": polygon}}}).count()); }