alex
alex

Reputation: 81

AS3 Get random point in ring

How can I get a random point within a ring? Like, the space between two concentric circles. I make the circles in code myself so I know the radius, etc. This is for a game I am working on where I am spacing the enemies out in waves, or different rings spaced from the center of the field. I was thinking the only way is some kind of loop that checks points or something. As3

Upvotes: 0

Views: 1640

Answers (2)

Jason S
Jason S

Reputation: 189796

Another solution besides fuzzyTew's to create uniform density distribution w/o having to loop + reject (which is expensive for narrow rings), is to use knowledge of the cumulative distribution function for radius. (Rings are evenly distributed as a function of angle so you can just use a uniform distribution of angle.)

The CDF for a ring with inner radius r1 and outer radius r2 is proportional to r2 - r12 (this is the integral of a term proportional to r dr, which is the probability density of a ring of radius r and infinitesimally small thickness dr). CDF(r=r1) = 0, and CDF(r=r2) = 1, so CDF(r) = (r2 - r12)/(r22 - r12).

So what? Well, now we just need to pick a CDF value q uniformly distributed between 0 and 1, and invert the CDF to get a radius r:

q = (r^2 - r1^2)/(r2^2 - r1^2)
r = sqrt(q*(r2^2 - r1^2) + r1^2)

So for an implementation (apologies for syntax errors, I'm not that familiar w/ AS3 vs. Javascript)

var angle : Number = Math.random() * Math.PI * 2;
var q : Number = Math.random();
var radius : Number = Math.sqrt(q*(r2*r2-r1*r1) + r1*r1);
var x : Number = Math.cos( angle ) * radius;
var y : Number = Math.sin( angle ) * radius;

Upvotes: 4

fuzzyTew
fuzzyTew

Reputation: 3778

One solution is to consider the point in polar coordinates. Randomize the angle, and then randomize the distance from the centre:

var angle : Number = Math.random() * Math.PI * 2;
var radius : Number = Math.random() * (outerRadius - innerRadius) + innerRadius;
var x : Number = Math.cos( angle ) * radius;
var y : Number = Math.sin( angle ) * radius;

However, the above polar solution will give an increased density for points chosen towards the inner ring. If you need a precisely even distribution, one solution is to randomly pick points in the square surrounding the ring, discarding points not in the ring:

var x : Number;
var y : Number;
var radiusSquared : Number;
var outerRadiusSquared : Number = outerRadius * outerRadius;
var innerRadiusSquared : Number = innerRadius * innerRadius;
do {
    x = Math.random() * outerRadius * 2 - outerRadius;
    y = Math.random() * outerRadius * 2 - outerRadius;
    radiusSquared = x * x + y * y;
} while ( radiusSquared > outerRadiusSquared || radiusSquared < innerRadiusSquared );

Alternatively the polar solution can be weighted to give an even distribution. I think this is how to do it, but I'm not sure:

var angle : Number = Math.random() * Math.PI * 2;
var outerRadiusSquared : Number = outerRadius * outerRadius;
var innerRadiusSquared : Number = innerRadius * innerRadius;
var radius : Number = Math.sqrt( outerRadiusSquared + Math.random() * (innerRadiusSquared - outerRadiusSquared) )
var x : Number = Math.cos( angle ) * radius;
var y : Number = Math.sin( angle ) * radius;

Upvotes: 1

Related Questions