1

I have a given area (let's say 1000 x 1000), and I want to place circles in this area with the following requirements:

  • The number of circles is arbitrary, but fixed after it was chosen at the begin of the algorithm. The number should be so that most of the area is covered by the circles.
  • The circles shall have in general different radii, and the sizes of the radii shall be in a certain interval (e. g. between 20 and 80).
  • The circles shall not overlap.

I want to implement a code which does this with matlab. So far I have accomplished this code, which contains for simplicity only one value for the radius:

%% Area
perix=1000;
periy=1000;

%Number of circles
numbercircles=100;
radii(1:numbercircles)=70

%% Placing Circles

%first circle
xi=rand*perix;   % array for storing x-values of circle centers
yi=radii(1);            %array for storing y-values of circle centers
radiusarray=[radii(1)] ; %array for storing radii
plot(sin(linspace(0,2*pi,100))*radii(1)+xi,cos(linspace(0,2*pi,100))*radii(1)+yi);
hold on
axis([0 perix 0 perix])

% Idea: 
%* Step 1: Random x coordinate for each circle middle point, y-coordinate at
% the top of the area, y_init=periy, and given radius.
%* Step 2: Lower y coordinate with constant x-coordinate until the distance to
%neighbour spheres is lower than the combined radii of those spheres.
%* Step 3: Move sphere on the x-axis to decrease the distance and further
%decrease the y-value if possible.

for lauf=2:numbercircles;
    disp(numbercircles-lauf)
    deltaz=10;

    %% Step 1
    % random x coordinate of sphere
    x1=rand*100;
    % y coordinate of circle is on the edge of the area and will be
    % lower in the following
    y1=periy;
    Radnew=radii(lauf);

    %% Step 2
    %distance to other circle
    d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2-(Radnew+radiusarray)) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);

    while deltaz > 1e-4
    %lower till y1=Radnew or distance to other spheres <  2*Rad
        while ((y1>Radnew) & (d > deltaz)) 
                    %number=number+1        
            % lower y1
%             if a<2
%                deltaz
%             end
               y1=y1-deltaz;
            % recalculate distance to all other spheres
            d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
        end;
        dmaxakt=d;
        %adjust position in x direction and y direction: Increasing
        %x coordinate iteratively in small steps
        if (y1>Radnew)
            xz(1)=x1+deltaz*rand;
            if xz(1)>perix
                xz(1)=x1-perix;
            elseif xz(1)<0
                xz(1)=x1+perix;
            end;
            dz(1)=min([sqrt((xi-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-xz(1)).^2+(yi-y1).^2)-(Radnew+radiusarray)]);

            xz(2)=x1-deltaz*rand;
            if xz(2)>perix
                xz(2)=x1-perix;
            elseif xz(1)<0
                xz(2)=x1+perix;
            end;
            dz(2)=min([sqrt((xi-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-xz(2)).^2+(yi-y1).^2)-(Radnew+radiusarray)]);

            %determine which distance z is the largest
            vmax=find(max(dz)==dz);

            %set the x-value to the value which belongs to the largest
            %distance
            x1=xz(vmax(1));

        end;
            %calculate new distance
            d=min([sqrt((xi-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi+perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray) sqrt(((xi-perix)-x1).^2+(yi-y1).^2)-(Radnew+radiusarray)]);
        if ((d>dmaxakt) & (y1>Radnew))
            dmaxakt=d;
        else
            deltaz=deltaz*1e-1;
        end;

    end;
%     if (y1<1e-5) 
%         y1=rand;            
%     end;
    %last check: test if y-coordinate is still in the area
    if (y1<periy-Radnew)
        %Assembling the arrays for the circle places
        xi=[xi x1];
        yi=[yi y1];
        radiusarray=[radiusarray Radnew];
    end;

    %Plotting
    %zeit(lauf)=cputime-t;
    plot(sin(linspace(0,2*pi,20))*Radnew+x1,cos(linspace(0,2*pi,20))*Radnew+y1);
    %plot(sin(linspace(0,2*pi,20))*Rad1+x1+perix,cos(linspace(0,2*pi,20))*Rad1+y1);
    %plot(sin(linspace(0,2*pi,20))*Rad1+x1-perix,cos(linspace(0,2*pi,20))*Rad1+y1);
    hold on
    axis([0 perix 0 perix])
    pause(0.0001);
    saveas(gcf, 'circle.png')
end;

The code basically assumes an initial x-coordinate and the maximum y-coordinate and lowers the y-coordinate until overlap is detected. Then the x-coordinate and the y-coordinate are modified to achieve high density of the circles. The problem of this code is, that it is very slow, because the distance of lowering the y-coordinate is decreasing in every while-loop, which means that the time of lowering the spheres can be very long. I would appreciate if somebody could come up with an idea how to increase the speed of this code.

Tornado
  • 13
  • 3
  • Have you looked at [this](http://stackoverflow.com/questions/36177195/non-overlapping-randomly-located-circles) or [this](http://stackoverflow.com/questions/36130596/matlab-how-to-generate-non-uniform-and-non-overlap-circle-rectangle-in-a-circle)? – beaker Jun 27 '16 at 14:56
  • This is probably better suited for [Code Review](http://codereview.stackexchange.com/) TBH – sco1 Jun 27 '16 at 14:58
  • I saw these two questions, but in both, the distance between the circles is not minimized, so this does not fit to my problem. I didn't know Code Review, I will post the question also there. – Tornado Jun 27 '16 at 15:12

1 Answers1

0

Not sure if this helps, but i checked your code as you posted it with the profiler and it says 98% of the time is saving the .png file

Line Number 111 / saveas(gcf, 'circle.png') / 99 / 47.741s / 98.4%

Do you want a picture everytime a new circle is drawn or just the last one? In the ladder case just put the 'saveas(...)' behind the last end, and caluclation is down to 1% of the time

Finn
  • 2,333
  • 1
  • 10
  • 21