This is something from years ago, I needed to get a random point within a circular radius from a different point. The brute-force way would have to be "just get a random point and check if it is within the specified distance".

Below is a circle of radius 'r' centered at origin, and a point situated at (x,y) somewhere within the circle.

An image of a circle of radius 'r' centered at origin showing a point at (x,y) inside the circle

It would be something like this:

const x = Math.random() * r; // A number between 0 (inclusive) and r (exclusive)
const y = Math.random() * r; // A number between 0 (inclusive) and r (exclusive)

// According to mathematical equation of this circle
if ((x^2) + (y^2) < (r^2)) {
	console.log(`Hurray, we can use (${x},${y}).`);
} else {
	console.error(`Sorry, (${x},${y}) doesn't fall inside the circle.`);
}

The problem with this approach is that each time we have to check and we aren't sure how many iterations it might take to land on workable coordinates. But we have another way that we can approach this problem.

Polar coordinates for the win

We can even show the same point in terms of its polar coordinates: (d, θ)

The same point represented with its polar coordinates

Now, rather than having a constraint only on the combined values of these parameters we have individual constraints on both of them:

  • 0 ≤ θ ≤ 2π
  • 0 ≤ d < r

This makes it much easier to generate both values, which can be done like this:

const d = Math.random() * r; // A value between 0 (inclusive) and r (exclusive)
const angle = Math.random() * (2 * Math.PI); // A value between 0 (inclusive) and 2π (exclusive)

// Using their projections on both the axes we get the values of x and y
const x = d * Math.cos(angle);
const y = d * Math.sin(angle);

With this, in a single execution we are guaranteed to get one of the points that we desire.

Side-bonus: How to get a random point in a disc around a point

What if we want to instead of getting the point inside a circle, want to get one inside a disc centered around origin with inner-radius being ri and outer-radius being ro (= r from before).

The only condition we need to update here is this one:

  • Before: 0 ≤ d < r
  • Now: ri ≤ d < ro

The code gets updated to:

const d = (Math.random() * (rOuter - rInner)) + rInner; // A value between rInner (inclusive) and rOuter (exclusive)
const angle = Math.random() * (2 * Math.PI); // A value between 0 (inclusive) and 2π (exclusive)

// Using their projections on both the axes we get the values of x and y
const x = d * Math.cos(angle);
const y = d * Math.sin(angle);