Non overlapping randomly located circles

前端 未结 4 521
生来不讨喜
生来不讨喜 2020-12-21 07:02

I need to generate a fixed number of non-overlapping circles located randomly. I can display circles, in this case 20, located randomly with this piece of code,

<         


        
相关标签:
4条回答
  • 2020-12-21 07:16

    If you're happy with brute-forcing, consider this solution:

    N = 60;                        % number of circles
    r = 0.5;                       % radius
    newpt = @() rand([1,2]) * 10;  % function to generate a new candidate point
    
    xy = newpt();  % matrix to store XY coordinates
    fails = 0;     % to avoid looping forever
    while size(xy,1) < N
        % generate new point and test distance
        pt = newpt();
        if all(pdist2(xy, pt) > 2*r)
            xy = [xy; pt];  % add it
            fails = 0;      % reset failure counter
        else
            % increase failure counter,
            fails = fails + 1;
            % give up if exceeded some threshold
            if fails > 1000
                error('this is taking too long...');
            end
        end
    end
    
    % plot
    plot(xy(:,1), xy(:,2), 'x'), hold on
    for i=1:size(xy,1)
        circle3(xy(i,1), xy(i,2), r);
    end
    hold off
    

    0 讨论(0)
  • 2020-12-21 07:21

    you can save a list of all the previously drawn circles. After randomizing a new circle check that it doesn't intersects the previously drawn circles.

    code example:

    nCircles = 20;
    circles = zeros(nCircles ,2);
    r = 0.5;
    
    for i=1:nCircles
        %Flag which holds true whenever a new circle was found
        newCircleFound = false;
        
        %loop iteration which runs until finding a circle which doesnt intersect with previous ones
        while ~newCircleFound
            x = 0 + (5+5)*rand(1);
            y = 0 + (5+5)*rand(1);
            
            %calculates distances from previous drawn circles
            prevCirclesY = circles(1:i-1,1);
            prevCirclesX = circles(1:i-1,2);
            distFromPrevCircles = ((prevCirclesX-x).^2+(prevCirclesY-y).^2).^0.5;
            
            %if the distance is not to small - adds the new circle to the list
            if i==1 || sum(distFromPrevCircles<=2*r)==0
                newCircleFound = true;
                circles(i,:) = [y x];
                circle3(x,y,r)
            end
        
        end
        hold on
    end
    

    *notice that if the amount of circles is too big relatively to the range in which the x and y coordinates are drawn from, the loop may run infinitely. in order to avoid it - define this range accordingly (it can be defined as a function of nCircles).

    0 讨论(0)
  • 2020-12-21 07:28

    Although this is an old post, and because I faced the same problem before I would like to share my solution, which uses anonymous functions: https://github.com/davidnsousa/mcsd/blob/master/mcsd/cells.m . This code allows to create 1, 2 or 3-D cell environments from user-defined cell radii distributions. The purpose was to create a complex environment for monte-carlo simulations of diffusion in biological tissues: https://www.mathworks.com/matlabcentral/fileexchange/67903-davidnsousa-mcsd

    A simpler but less flexible version of this code would be the simple case of a 2-D environment. The following creates a space distribution of N randomly positioned and non-overlapping circles with radius R and with minimum distance D from other cells. All packed in a square region of length S.

    function C = cells(N, R, D, S)
      C = @(x, y, r) 0;
      for n=1:N
        o = randi(S-R,1,2);
        while C(o(1),o(2),2 * R + D) ~= 0
          o = randi(S-R,1,2);
        end
        f = @(x, y) sqrt ((x - o(1)) ^ 2 + (y - o(2)) ^ 2);
        c = @(x, y, r) f(x, y) .* (f(x, y) < r);
        C = @(x, y, r) + C(x, y, r) + c(x, y, r);
      end
      C = @(x, y) + C(x, y, R);
    end
    

    where the return C is the combined anonymous functions of all circles. Although it is a brute force solution it is fast and elegant, I believe.

    0 讨论(0)
  • 2020-12-21 07:30

    Slightly amended code @drorco to make sure exact number of circles I want are drawn

    nCircles = 20;
    circles = zeros(nCircles ,2);
    r = 0.5;
    c=0; 
    
    for i=1:nCircles
    %Flag which holds true whenever a new circle was found
    newCircleFound = false;
    
    %loop iteration which runs until finding a circle which doesnt intersect with     previous ones
    while ~newCircleFound & c<=nCircles
        x = 0 + (5+5)*rand(1);
        y = 0 + (5+5)*rand(1);
    
        %calculates distances from previous drawn circles
        prevCirclesY = circles(1:i-1,1);
        prevCirclesX = circles(1:i-1,2);
        distFromPrevCircles = ((prevCirclesX-x).^2+(prevCirclesY-y).^2).^0.5;
    
        %if the distance is not to small - adds the new circle to the list
        if i==1 || sum(distFromPrevCircles<=2*r)==0
            newCircleFound = true;
            c=c+1
            circles(i,:) = [y x];
            circle3(x,y,r)
        end
    
    end
    hold on
    

    end

    0 讨论(0)
提交回复
热议问题