Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to uniformly spread points in circle shaped form

I've searched through a dozen questions similar to this one, but none with the same problem I've came upon. I have a map with units, 1000x1000 units, think of it as pixels. The problem is that I have to uniformly spread circle-shaped into the 1000x1000 map and all I could come up with till now is this:

$quadrant = array_search(min($quadrants), $quadrants); // the quadrant with less points
$radius = (current_points_number / sqrt(pi() / $points_density);
$angle = pi() * mt_rand() / 2 / mt_getrandmax();
$x = round((($quadrant == 2 || $quadrant == 3) ? -1 : 1) * cos($angle) * $radius + 500);
$y = round((($quadrant == 3 || $quadrant == 4) ? -1 : 1) * sin($angle) * $radius + 500);

The result of this actual algorithm is, as you can see in the next image, a problem, since it tends to make points denser to the center of the circle and widely scattered on at it's margins.

enter image description here

Any suggestion would be highly appreciated.

like image 451
Eduard Avatar asked Jan 13 '14 17:01

Eduard


2 Answers

simple solution

you can simply iterate through all map's pixels, and for each pixel inside of the given circle - create unit with probability P``, so the code is something like

for x=1 to max_x
  for y=1 to max_y
    if (x-circle_x)^2 + (y-circle_y)^2 <= circle_r^2
      if random() < P
        map[x][y] = new unit()     

Obviously it is not optimal, as you do not really need iteration through non-circle points, but this should give you the general idea. It is easy to prove, that it generates the uniform distribution, as it is simply generation of the uniform distribution on the whole map and "removing" units from outside of the circle.

more mathematical solution

You can also do it in more strict way, by applying iteratively the uniformly distributed points generator:

for i in 1...numer_of_units_to_generate:
  t = 2*pi*random()
  u = random()+random()
  if u>1 then 
    r=2-u 
  else 
    r=u
  map[r*cos(t)][r*sin(t)]=new unit()

result:

uniformly distributed points on the circle

like image 106
lejlot Avatar answered Oct 19 '22 03:10

lejlot


You could take a random x,y value, then determine if it falls within the circle. If it doesn't, then reject it and try again. When it falls within the circle, then increment your matched hits by one up until you get n random pixels within the circle.

Less math, more calls to random.

like image 37
Kieveli Avatar answered Oct 19 '22 03:10

Kieveli