Index: binaries/data/mods/public/maps/random/rmgen/math.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/math.js (revision 21862) +++ binaries/data/mods/public/maps/random/rmgen/math.js (working copy) @@ -173,3 +173,58 @@ return order; } + +function poissondiskSamples(width, height, r, k = 30) +{ + let cellSize = r / Math.sqrt(2); // sqrt of the dimension of the grid. + let gridWidth = Math.ceil(width / cellSize); + let gridHeight = Math.ceil(height / cellSize); + let grid = new Array(gridWidth * gridHeight); + + let point = new Vector2D(width * Math.random(), height * Math.random()); + let queue = [point]; + let gridX = Math.floor(point.x / cellSize); + let gridY = Math.floor(point.y / cellSize); + + grid[gridX + gridY * gridWidth] = point; + + let ret = []; + ret.push(point); + + while (queue.length) + { + let randPoint = pickRandom(queue); + queue.splice(0, 1); + + for (let i = 0; i < k; ++i) + { + let randAngle = randomAngle(); + let randDist = r * Math.sqrt(3 * Math.random() + 1); + + let newPoint = new Vector2D(randPoint.x + randDist * Math.cos(randAngle), randPoint.y + randDist * Math.sin(randAngle)); + if (newPoint.x < 0 || newPoint.x > width || newPoint.y < 0 || newPoint.y > height) + continue; + + let [gridx, gridy] = [Math.floor(newPoint.x / cellSize), Math.floor(newPoint.y / cellSize)]; + let gridPoints = []; + + for (let x = Math.max(gridx - 2, 0); x < Math.min(gridx + 3, gridWidth); ++x) + for (let y = Math.max(gridy - 2, 0); y < Math.min(gridy + 3, gridHeight); ++y) + { + let gridPoint = grid[x + y * gridWidth] + if (!gridPoint) + continue; + gridPoints.push(gridPoint); + } + + if (gridPoints.every(point => point.distanceTo(newPoint) > r)) + { + queue.push(newPoint); + grid[gridx + gridy * gridWidth] = newPoint; + ret.push(newPoint); + } + } + } + + return ret; +}