Identical circle packing on a rectangular surface

Dear all,
i need to pack identical circles on a certain rectangular surface (e. g. figure). I know that there isn't any general solution to this problem but i wanted to ask anyway to have a starting point.

 采纳的回答

See circle packing tag on the right hand side of this screen.
Here's a start:
radius = 20;
rows = 480;
columns = 640;
xc = 1 : radius*2 : columns;
yc = 1 : radius*2 : rows;
[x, y] = meshgrid(xc, yc);
% Shift every other row by a radius
x(2:2:end, :) = x(2:2:end, :) + radius;
numCircles = length(x(:))
numCircles = 192
radii = radius * ones(numCircles, 1);
viscircles([x(:), y(:)], radii, 'Color', 'r')
ans =
Group with properties: Children: [2×1 Line] Visible: on HitTest: on Show all properties

19 个评论

Thank you so much!
I have a follow up question. Would it be possible to turn these circles into cylinders? Or should I use the "cylinder()" and start from scratch?
I don't know - try it.
And as you probably figured out, you'll need to adjust the radius. Once the circles in alternate rows have been shifted, they no longer touch. To get them to touch you'll need to have the new radius be sqrt(5)/2 times the old radius.
gridSpacing = 20;
rows = 480;
columns = 640;
scalingFactor = sqrt(5) / 2;
xc = 1 : scalingFactor * gridSpacing*2 : columns;
yc = 1 : gridSpacing*2 : rows;
[x, y] = meshgrid(xc, yc);
% Shift every other row by a radius
x(2:2:end, :) = x(2:2:end, :) + gridSpacing;
numCircles = length(x(:))
numCircles = 180
radii = scalingFactor * gridSpacing * ones(numCircles, 1);
viscircles([x(:), y(:)], radii, 'Color', 'r')
ans =
Group with properties: Children: [2×1 Line] Visible: on HitTest: on Show all properties
I have a follow up question. How can i delete the circles that fall outside of the constrainted area?
Just get their indexes and set those indexes of both arrays to null to eliminate them
% Turn into column vectors:
x = x(:);
y = y(:);
% Find out which centers are less than x1 or more than x2
% or y < y1 or y > y2
badIndexes = (x < x1) | (x > x2) | (y < y1) | (y > y2);
x(badIndexes) = [];
y(badIndexes) = [];
I have a new follow up question to this.
I need to set the first circle of first two rows to null and set the last circle of following two rows also to null. In other words two rows missing the first circles and the next two rows missing the last circles. I also need to do this for the whole plot. I tried doing it by altering your example but could not succeed. Hope you can help me.
You probably already figured it out by now, but here is how I'd do it: set the coordinates of the circles you don't want to NaN:
% Initialization Steps.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
gridSpacing = 20;
rows = 480;
columns = 640;
scalingFactor = sqrt(5) / 2;
xc = 1 : scalingFactor * gridSpacing*2 : columns;
yc = 1 : gridSpacing*2 : rows;
[x, y] = meshgrid(xc, yc);
% Shift every other row by a radius
x(2:2:end, :) = x(2:2:end, :) + gridSpacing;
numCircles = length(x(:))
radii = scalingFactor * gridSpacing * ones(numCircles, 1);
subplot(3, 1, 1);
viscircles([x(:), y(:)], radii, 'Color', 'r')
title('Original with all circles')
xlim([min(x(:) - radii(1)), max(x(:) + radii(1))])
axis square
grid on;
% Now get rid of first two circles in rows 1&2, 5&6, 9&10, etc. by setting those values to nan
% Row 1 (first row) is considered to be the bottom row (lowest y value).
x(1:4:end, 1) = nan;
x(2:4:end, 1) = nan;
y(1:4:end, 1) = nan;
y(2:4:end, 1) = nan;
% Now get rid of last circle in rows 3&4, 7&8, 11&12, etc. by setting those values to nan
x(3:4:end, end) = nan;
x(4:4:end, end) = nan;
y(3:4:end, end) = nan;
y(4:4:end, end) = nan;
subplot(3, 1, 2);
viscircles([x(:), y(:)], radii, 'Color', 'r')
grid on;
xlim([min(x(:) - radii(1)), max(x(:) + radii(1))])
axis square
title('New, with some circles missing')
% If you need it flipped vertically, subtract y from y max
yMax = max(y(:))
y = yMax - y;
subplot(3, 1, 3);
viscircles([x(:), y(:)], radii, 'Color', 'r')
title('New, flipped')
xlim([min(x(:) - radii(1)), max(x(:) + radii(1))])
axis square
grid on;
Would it be possible to change the radii of a row but keep the gap to the adjacenst rows same?
Yes, that was the way I did it first. The radii and the grid spacing can be independent.
I mean, can the rows have different radii? For example, first row has a radii of 20 and the second row has a radii of 10.
Of course. Just make radii an array. Did you try it?
I tried but couldn't figure it out
Even if i manage to set the radii of a row smaller i am not sure how to keep the gaps to adjacent rows the same.
You just have separate variables for grid spacing and radii. Like this:
xGridSpacing = 200;
yGridSpacing = 100;
rows = 480;
columns = 640;
xc = 1 : xGridSpacing : columns;
yc = 1 : yGridSpacing : rows;
[x, y] = meshgrid(xc, yc);
% Shift every other row by half a grid spacing.
x(2:2:end, :) = x(2:2:end, :) + xGridSpacing / 2;
numCircles = length(x(:))
% Set up radii alternating 20, 10, 20, 10, etc.
radii = y; % Initialize
for k = 1 : 2 : length(yc)
indexes = y == yc(k);
radii(indexes) = 20;
end
for k = 2 : 2 : length(yc)
indexes = y == yc(k);
radii(indexes) = 10;
end
viscircles([x(:), y(:)], radii(:), 'Color', 'r')
axis('on', 'image')
grid on;
I have obtained the following plot by deleting the circles in some rows. I need a way to make the bigger gaps in y-direction (deleted rows) variable so i want to be able to change these gap sizes. I think it has also to do with yGridspacing but it starts in the second row and repeats every 3 rows. Do you think that is possible?
Yes, you should have enough skills to do that. Maybe have two arrays offset vertically and horizontally by some amount.
I tried to put yc in a while loop depending on an if statement to change the increment step between two values but couldn't figure out how to properly do it. Do you think it might work that way?
% Inputs
Diameter = 18;
Height = 100;
rows = 685;
columns = 300;
GapWidth = 2;
GapToTop = 5;
GapToWall =3;
Distance = 20;
r = Diameter/2;
scalingFactor = sqrt(5) / 2;
gridSpacing = r/scalingFactor+GapWidth;
% Cuboid
P = [columns/2, rows/2, Height/2];
L = [columns, rows, Height];
O = P-L/2;
plot(L,O,.8,[1 1 1]);
hold on
plot3(P(1),P(2),P(3),'*k')
alpha(.01)
%Cylinder
[X,Y,Z] = cylinder(r);
Z = Z*Height;
for i = r : scalingFactor * gridSpacing*2 : columns
for ii = r : gridSpacing*8+Distance*2 : rows
surf(X+i,Y+r,Z)
end
end
for k = r+gridSpacing: scalingFactor * gridSpacing*2 : columns
for kk= r+gridSpacing*2+Distance : gridSpacing*8+Distance*2 : rows
surf(X+k,Y+kk,Z)
end
end
if Distance>0
b = 1;
else
b = 0;
end
for l = r+(scalingFactor * gridSpacing*2)*b:scalingFactor * gridSpacing*2:columns
for ll = r+gridSpacing*4+Distance : gridSpacing*8+Distance*2 : rows
surf(X+l,Y+ll,Z)
end
end
for j = r+gridSpacing:scalingFactor * gridSpacing*2:columns-Distance
for jj = r+gridSpacing*6+Distance*2 : gridSpacing*8+Distance*2 : rows
surf(X+j,Y+jj,Z)
end
end
for n = r : scalingFactor * gridSpacing*2 : columns-Distance
for nn = r+gridSpacing*8+Distance*2: gridSpacing*8+Distance*2 : rows
surf(X+n,Y+nn,Z)
end
end
axis image
alpha(.5)
view(3)
I have managed to adjust the distance between every other two rows and plotted them as cylinders. But since i did not use viscircles for that i no longer have the number of elements. Do you have any idea how i can obtain the number of these cylinders? And do you think it is possible to obtain the center coordinates of the cylinders as an output?

请先登录,再进行评论。

更多回答(0 个)

类别

产品

版本

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by