Random point within a circle

Hi all.  Once again my lack of maths skills are letting me down :frowning:

What I would like to do is generate random x/y coords for an object that are within the given circumference of a circle, so passing the x,y and radius of a circle to a function would return a random position within said circle.
Any help is, as always, much appreciated.

local randomAngle = math.random(1000)

local circleRadius = 100

object.x = math.cos(randomAngle)*circleRadius

object.y = math.sin(randomAngle)*circleRadius

Not too difficult if you use the “easy way”:

local function randomPointInCircle(x, y, radius) local randX, randY repeat randX, randY = math.random(-radius, radius), math.random(-radius, radius) until (((-randX) ^ 2) + ((-randY) ^ 2)) ^ 0.5 \<= radius return x + randX, y + randY end

All it does is repeatedly get a random point within a rectangle, then check if the point is under the needed distance from the center of the rectangle.

This is off the top of my head, so if it doesn’t work perfectly, let me know.

EDIT: Whoops, took so long to post that @thomas6 got there before me.

Might want to try both and see which is faster; don’t know if the cosine/sine calls would be slower than a few extra random calls.

  • Caleb

Hehe, Caleb - and now we can battle out which method is more elegant or optimised!

Well, yours is definitely more elegant, but I don’t know about optimized :). Just a second, let me see…

(Also, you need to set circleRadius to random - otherwise, you’ll just get a random point on a circle.)

  • Caleb

Indeed! We’re getting there together :wink:

After extensive tests (50000 iterations of each), I can officially say…

Faster - @thomas6’s (about 1.15 times faster)

Eleganter - @thomas6’s

Slower - mine

Uglier - mine

So, if you want the slow, ugly version, use mine by all means. Otherwise, use @thomas6’s :).

Funny about my algorithm - the history is that it comes from CBEffects, the initial version of which I wrote several years ago, when I was 12, before I’d learned trigonometry. Now I’ve learned trig, but it never occurred to me to use it for that :D.

  • Caleb

Yeehaaaaa!

Thanks Caleb - did you localize the math.random() function as well for maximum speed gain?

I’m a huge trigonometry freak - probably a third of my code is making cool animations with trig.

Yep. All localized. Don’t rub it in :D.

I adore trigonometry as well. I adore geometry. I adore algebra. I adore matrices. I adore anything math-y. Heh.

  • Caleb

tho points generated in that manner won’t be evenly distributed within the circle, if it matters

to compensate:  take sqrt of a unit random, then mult by r * cos/sin(theta)

hth

How so? And which “manner” are you referring to?

  • Caleb

hi Dave,

Good point, although I’m wondering if there shouldn’t be a more elegant way to bias the circleRadius more towards the outer edge of the circle…

And in this respect, Caleb’s method does work nicely!

Oh yes now I see what you mean. What about distribute the random radius along a sine curve towards the full radius somehow? That might make things a bit better.

Good to hear mine’s better in some way!

  • Caleb

Hey Caleb,

A random radius between 1 and 36000 divided by 100 doesn’t help - and don’t you mean random angle? I think Dave is referring to the fact that using a linear distribution from center of the circle to outer edge, will mean that the points will be more densely populated near the center.

By the way, my math.random(1000) is, of course, just a crude and simple method. For perfect solutions I would need to get one full revolution in there, but I just went for something that probably works for the needs here.

Yep. Duh. I realized that right when I posted it. And yes, I meant angle. I was thinking of the angle as being better distributed that way, because it wouldn’t skip as many points nearer the edge of the circle. But that wouldn’t solve the problem anyhow.

I need to back out of this conversation before I say something really stupid :).

  • Caleb

Whew! On testing, you do actually get a little better distribution with that, so it wasn’t all that dumb after all. But it doesn’t solve the problem.

At least I’m justified in my thinking :).

EDIT: https://www.dropbox.com/s/118ql8o7m8iiol6/distribution.gif?dl=0

  • Caleb

I’m thinking - but it’s just a intuitive guess - that I can fix my method by biasing the circleRadius like this:

local circleRadius = 100

local rooted = math.random(math.sqrt(circleRadius))

local correctedDistance = rooted * rooted

object.x = math.cos(randomAngle)correctedDistance

object.y = math.sin(randomAngle)*correctedDistance

Then again, this will introduces a loss of precision in defining the radius. Oh well. Close enough!

almost, but squaring a square root just gives you back the original number (and its distribution) minus a “quantizing” effect from loss of precision (from calling math.random(N) instead of math.random()*N).  this is the sort of form you’d want for an even distribution (assuming that’s what you want):

local function pointInCircle(x,y,r) &nbsp; r = math.sqrt(math.random())\*r &nbsp; local theta = math.random()\*2\*math.pi &nbsp; return { x=x+r\*math.cos(theta), y=y+r\*math.sin(theta) } end

hth

Awesome response as usual.  I was expecting one maybe two replies at most.
Will have a play around with the different suggestions and work out which works best for what I need.
Many many thanks!