Reputation: 412
I want to generate x
amount of points that are all spaced similairly while still maintaining randomness. The randomly generated points will be displayed on a rectangular canvas. At the moment I'm simply generating each point with Math.random()
. I've tried testing the spacing for each point in relation to the others but I don't know how to make this work with x
amount of points.
How should I go about generating these points?
Upvotes: 0
Views: 1457
Reputation: 412
Thanks to both @MBo & @Blindman67. I used the idea of dividing the canvas into a grid with one tile for each point desired. Determining the dimensions of the grid required some simple algebra based on the following equations:
rows * columns = x
rows / columns = canvasHeight / canvasWidth
Using that I was able to create a formula for both rows and columns:
rows = ((canvasHeight * x) / canvasWidth)^(1/2)
columns = x / ((canvasHeight * x) / canvasWidth)^(1/2)
Here is how I implemented the code:
var x = 100; // number of points
var points = [];
// determine increment for grid
var yIndex = canvas.height / Math.round(Math.sqrt((canvas.height * x) / canvas.width));
var xIndex = canvas.width / Math.round(x / Math.sqrt((canvas.height * x) / canvas.width));
// generate points randomly across grid
var k = 0;
for (var y = 0; y < this.canvas.height; y+=yIndex) {
for (var x = 0; x < this.canvas.width; x+=xIndex) {
points[k] = [
getRandomArbitrary(x,x+xIndex),
getRandomArbitrary(y,y+yIndex),
];
k++;
}
}
Visual demonstration
Before:
After:
Upvotes: 1
Reputation: 54026
You can use a semi random distribution by dividing the area into equal size grid and placing a point randomly in each grid. But you will need to know how many points you will be adding or it will not work.
The demo compares the result of random and weighted distribution. The reality is that the random function will produce a more even distribution as the point count increases. Click the canvas to double the point count and compare the result of random and weighted.
const ctx = canvas.getContext("2d");
const ctx1 = canvas1.getContext("2d");
const w = canvas.width;
const h = canvas.height;
canvas.addEventListener("click",drawPoints);
canvas1.addEventListener("click",drawPoints);
function randomPoint(){
const xx = Math.floor(Math.random() * w);
const yy = Math.floor(Math.random() * h);
ctx1.fillRect(xx,yy,pointSize,pointSize);
}
function randomPointOf(n, ofM){
const spread = Math.sqrt(ofM);
const xs = w / spread; // x spacing
const ys = h / spread; // y spacing
n = n % ofM;
const x = (n % spread) * xs;
const y = (Math.floor(n / spread)) * ys;
const xx = Math.floor(Math.random() * xs + x);
const yy = Math.floor(Math.random() * ys + y);
ctx.fillRect(xx,yy,pointSize,pointSize);
}
function randomPoints(pointCount, distrabutionCount){
var i;
for(i = 0; i < pointCount; i ++){
randomPointOf(i,distrabutionCount); // do distrubuted random
randomPoint(); // do random
}
}
var pointCount = 100;
var pointSize = 1
ctx.font = ctx1.font = "12px arial";
ctx1.fillStyle = ctx.fillStyle = "black";
ctx1.strokeStyle = ctx.strokeStyle = "white";
ctx1.lineWidth = ctx.lineWidth = 3;
drawPoints();
function drawPoints(){
ctx.clearRect(0,0,w,h);
ctx1.clearRect(0,0,w,h);
pointCount *= 2;
if(pointCount > w * h){
pointCount = 100;
}
pointSize = pointCount < 1600 ? 2 : 1;
randomPoints(pointCount,100);
ctx.strokeText("Weighted. "+ pointCount + " points",10,14);
ctx1.strokeText("Random. "+ pointCount + " points",10,14);
ctx.fillText("Weighted. "+ pointCount + " points",10,14);
ctx1.fillText("Random. "+ pointCount + " points",10,14);
}
canvas {
border : 2px black solid;
}
<canvas id="canvas" width = 256 height = 256></canvas>
<canvas id="canvas1" width = 256 height = 256></canvas>
<div>Click canvas to increase point count</div>
Upvotes: 1
Reputation: 80177
You can use something like the next approach (pseudocode).
Points are linked to the nodes of square grid and have some random displacement.
for iy in rowcountrange
for ix in columncountrange
points[iy, ix].X = ix * spacing + (random(0..1) - 0.5) * spacing
points[iy, ix].Y = iy * spacing + (random(0..1) - 0.5) * spacing
Upvotes: 1