0

I am searching for a concept to distribute circles in a square randomly, so that they dont overlap. All circles are of the same size. The area covered by the circles can be high, up to the theoretical maximum of ca. 90 % of the square (in which they are completely ordered). About 200 circles should be placed and I want to specify the number of circles exactly. (The distribution is needed as input for a model generation of a FE-analysis, btw). Can you help me for generate the maximum with script
Example for the distribution: https://zoada.com/html5/brute.html

saded
  • 793
  • 11
  • 22

1 Answers1

4

This simple script to place a number of num_circles circles with radius radiusin a refined rectangle (aligned to global axes) speficied by xmin, xmax, ymin and ymax by trying random locations until it not colliding with an existing circle. This is certainly not the most efficient way of doing it, but it should be fine for smaller problems and if the relative area covered is not too high.

enter image description here enter image description here

At some point the script will not find a free spot anymore and throw an error. If you increase max_tries, the algorithm is more likely to find free spots at the cost of additional computation time, but the needed time raises extremely fast if you need a higher covered area. It is hard to get much higher than 50%.

enter image description here

from mathutils import Vector
from mathutils.noise import random, seed_set
import bpy

# Specify parameters
seed = 0
xmin = -1
xmax = 1
ymin = -1
ymax = 1
radius = 0.1
num_circles = 68
max_tries = 10000

# Init
seed_set(seed)
sx = xmax-xmin-2*radius
sy = ymax-ymin-2*radius
xminm = xmin+radius 
yminm = ymin+radius 
existing_locations = []
sce = bpy.context.scene
bpy.ops.mesh.primitive_circle_add(location=(0,0,0), radius=radius)
ref_circle = bpy.context.object

# Loop
for i in range(num_circles):
    j = 0
    searchOn = True
    while searchOn:
        if j > max_tries:
            bpy.ops.object.select_all(action='DESELECT')
            ref_circle.select = True
            bpy.ops.object.delete() 
            raise ValueError('Found no more room for another circle')
            break
        j += 1
        new_location = (xminm + random()*sx,
                        yminm + random()*sy,
                        0)
        for existing_location in existing_locations:
            if (Vector(existing_location)-Vector(new_location)).length < 2*radius:
                break
        else:
            new_circle = ref_circle.copy()
            new_circle.location = new_location
            sce.objects.link(new_circle)
            existing_locations.append(new_location)
            searchOn = False

ref_circle.select = True
bpy.ops.object.delete() 
sce.update()
Dimali
  • 1,675
  • 1
  • 8
  • 15
  • 2
    Nice one. Some suggestions: make one circle with the operator, then add a copy circle.copy() set to new loc and link to scene. The random location could be s * Vector((random(), random())) where s (cos it's a square) is w - 2 * r , w is the height/width of square,. s need be calculated once. (akin to local coords) Lastly 8^) have a look at python any for your collide method. – batFINGER Sep 06 '17 at 07:00
  • Thanks, good suggestions. It is not optimized code for sure. I will change these points. – Dimali Sep 06 '17 at 07:01
  • 1
    Nice one. Notice link in my comment on question. Interested how close you can get to optima using unit square and radii from tables, using random placement. – batFINGER Sep 06 '17 at 07:20
  • Nice method, I tried an example with radius 0.078, I can get 100 circles with the fraction 49%. Is there an algorithm that increase this fraction? – saded Sep 06 '17 at 10:07
  • The algorithm can be imporved slightly, because it does not find all free spots unless you calculate for an infinitely long time. However using random locations it is impossible to come much higher, unless your are very lucky with how the locations come out. – Dimali Sep 06 '17 at 10:13
  • when I increased max_tries = 100000, I can get 50% In research work, which used algorithms random sequential addition (RSA) and Dynamic Molecular (DM), it got about 54 %!. For this script, In the case of periodic (regular arrangement) or hexagonal distribution, how can I modify this script – saded Sep 06 '17 at 10:39
  • 2
    @saded surely this answer worth a UV from you? Given all the talk of research et al there is a distinct lack of code / research etc in your question. For instance the 0.9 limit is for infinitely small (approaching 0) optimally hexagonally packed circles. Is Dmali doing your homework for you? – batFINGER Sep 06 '17 at 11:25
  • My work is based on the numerical simulation of the cells of different distributions, and I found this way (blender) that helped me to make this problem especially for the 3D case. for me, I am a little weak in programming, the generation of these forms demands a programmer qualify as you. In addition, we have tried another case which represents the first square cell that is in another square cell! which I found a little bit complicated especially when working with the dimensions of the 2 cells. – saded Sep 06 '17 at 11:54
  • 2
    This is all well, but please ask a specific question and don't change it after it has been answered. I clarified in the beginning that you want random distribution and you agreed. If this answer helped you please accept it (or vote up if it helped anyway) or make clear what you expect instead. Remember that this is a QA forum and not professional support. – Dimali Sep 06 '17 at 12:22
  • Yes Dimali, it's good. For my second question, it is a case of comparison between the three distributions – saded Sep 06 '17 at 12:42
  • I have added the suggestions by bafFINGER (Thanks). It should run faster now, but the algorithm is the same. – Dimali Sep 06 '17 at 17:42
  • Thank you Dimali, it went fast that the first, if I have to generate several images with different distribution of circles, how can I add the seed – saded Sep 07 '17 at 08:43
  • I have added a value seed. 0 means the current time defines the seed, if you use any other value the result will always be the same. – Dimali Sep 07 '17 at 09:32
  • Thank you, it works well. concerning my second question which depends on the other 2 distributions, if it is possible to add the loop of choice between these 3 distributions, otherwise I can create a new topic, once again thank you for you and batFINGER. – saded Sep 07 '17 at 12:01
  • 1
    Have used this here https://blender.stackexchange.com/a/135811/15543 – batFINGER Mar 31 '19 at 14:16
  • For 2D yes, my problem now is to generate random cylinders, I have a problem waiting for a fraction of 30 – saded Apr 22 '19 at 12:53