Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have an image that contains a circles at a specific location, and of a specific diameter. What I need to do is to be able to calculate random points within the circle, and then manipulate the pixels said points correlate to. I have the following code already:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * ( Math.PI * 2 );
    var x = _originX + ( _radius * Math.Cos( angle ) );
    var y = _originY + ( _radius * Math.Sin( angle ) );
    return new Point( ( int )x, ( int )y );
}

And that works fine for finding all the points at the circumference of the circle, but I need all points from anywhere in the circle. If this doesn't make sense let me know and I will do my best to clarify.

share|improve this question
    
Check the update. –  David Gouveia Apr 3 '12 at 20:34
2  
Good question in the sense that inadvertently creating a weighted distribution is a common error. –  Tim Holt Apr 3 '12 at 20:54

4 Answers 4

up vote 23 down vote accepted

If you want a simple solution just randomize the radius too:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var radius = _random.NextDouble() * _radius;
    var x = _originX + radius * Math.Cos(angle);
    var y = _originY + radius * Math.Sin(angle);
    return new Point((int)x,(int)y);
}

That however results in your points being more concentrated towards the center of the circle:

enter image description here

In order to get an uniform distribution make the following change to the algorithm:

var radius = Math.Sqrt(_random.NextDouble()) * _radius;

Which will give the following result:

enter image description here

For more information check the following link: MathWorld - Disk Point Picking.

And finally here's a simple JsFiddle demonstration comparing both version of the algorithm.

share|improve this answer
1  
Excellent answer. Just one thing to add: don't forget to seed the random number generator :) –  ktodisco Apr 3 '12 at 20:40
    
Oop you beat met to it - didn't see this post when I posted mine. The wolfram site is an awesome resource for this kind of thing. –  Tim Holt Apr 3 '12 at 20:54
1  
@TimHolt Happens all the time :) –  David Gouveia Apr 3 '12 at 21:05
    
Is this assuming the circle center is at 0,0 ? –  PsychoDad Sep 29 '13 at 18:06
    
@PsychoDad The center of the circle would be (_originX, _originY) –  David Gouveia Oct 1 '13 at 10:12

You’re halfway there. In addition to generating a random angle, just generate a random distance, less than or equal to the radius:

private Point CalculatePoint()
{
    var angle = _random.NextDouble() * Math.PI * 2;
    var distance = _random.NextDouble() * _radius;

    var x = _originX + (distance * Math.Cos(angle));
    var y = _originY + (distance * Math.Sin(angle));
    return new Point((int)x, (int)y);
}

Now you’re thinking with polar.

share|improve this answer
    
Okay, so we gave exactly the same answer within seconds of difference. Now what? :) –  David Gouveia Apr 3 '12 at 20:23
    
@DavidGouveia We both get upvotes for both being right. Everybody wins! :D –  Jon Purdy Apr 3 '12 at 20:24
    
Both answers very much appreciated (and the link too!). Man I am an idiot for not seeing that myself though, -1 to me :( Thanks again to you both! –  DMills Apr 3 '12 at 20:29

DO NOT just use random r and theta! This creates a weighted distribution with more points in the center. This page illustrates it well...

http://mathworld.wolfram.com/DiskPointPicking.html

Here's the method that creates a non-weighted distribution...

var r = rand(0,1)
var theta = rand(0,360)

var x = sqrt(r) * cos(theta)
var y = sqrt(r) * sin(theta)
share|improve this answer
    
Oops duplicate of selected answer :P –  Tim Holt Apr 3 '12 at 20:56

If performance is an issue then one alternative solution is to generate a random position in a box with the width/height of your circle and then throw away any points that are not in the area of the circle.

The advantage of this method is that you are doing no cos/sin/sqrt functions, which depending on your platform may be a big speed saving.

var x = _random.NextDouble();
var y = _random.NextDouble();
if (x*x + y*y < 1.0f)
{
    // we have a usable point inside a circle
    x = x * diameter - _radius + _OriginX;
    y = y * diameter - _radius + _OriginY;
    // use the point(x,y)
}
share|improve this answer
    
I'm going to try that out and see if it speeds things up. I'm not sure I have a performance problem, but I'll try this anyway, thanks! –  DMills Apr 11 '12 at 1:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.