Here's a solution treating the bottle as circles, not squares. It's a brute force algorithm since it hunts for a place to fit. And it's not an optimal solution, since the order the bottles are attempted can affect whether they fit or not. But is CAN find a solution and even seems to default to a honeycomb pattern if the bottle are all the same size (which is good).
First assume that the center of any bottle can be no closer to any wall of the cabinet than it's radius. This means we only have to test x,y positions for the center of a bottle that are smaller than the cabinet.
[tt]
0,0
+----------------------------+
| .......................... |
| . . |
| . . |
| . . |
| . . |
| .......................... |
+----------------------------+
max_x,max_y
[/tt]
That is, if the cabinet is from the vertical lines and dashes, then the center of a bottle can only be on or within the dots (from 0+radius,0+radius to max_x-radius,max_y-radius). And this changes per bottle as they each may have a different radius. Smaller bottles can have their center closer to the wall than a bigger bottle.
Then, to place each bottle, it's just a matter of testing each bottle. It can be placed if you can find an x,y in the cabinet that meets these criteria...
1) It's center is more than a radius away from any wall
2) The distance from it's center to the center of any other bottle is greater than the sum of their radiuses.
So, something like this (in bad pseudocode)...
Code:
int max_x; // width of cabinet
int max_y; // depth of cabinet
for each bottle not yet placed
for test_x = (0 + bottle_radius) to (max_x - bottle_radius)
for test_y = (0 + bottle_radius) to (max_y - bottle_radius)
for b = loop through all bottles already placed
if distance from test_x,test_y to b_x,b_y > bottle_radius+b_radius
place bottle
endif
endfor
endfor
endfor
endfor
Presorting the bottles by their radius will change their placement. From smallest to biggest, verses biggest to smallest will cause different placements. Randomizing the bottle order would give different results.
Since it is a brute force method, you could even try every permutation of bottle order which would cover any and all order advantages and disadvantages.
Do I make sense? Not sure if I described it very well, but it makes sense to me.