# How can I pack circles of different sizes into a spiral?

Given a list of circles of different areas, I need to arrange them tangentially in order of increasing area and spiraling outward. An example of the type of packing I'm attempting is shown by the orange circles in the figure below:

Is there a concise way to calculate the centers of the circles?

• Vi Hart has a great little video on a related idea. No help with doing this problem, but it does put this kind of problem in and interesting light. youtube.com/watch?v=DK5Z709J2eo Jun 14, 2012 at 20:45
• Could you post a minimal set of radii you want to have positioned (and perhaps how that should look like)? The image is somewhat more complicated than what your request implies and breaking down the problem may be helpful. Jun 15, 2012 at 13:25

Here's my version. I don't know how fast/slow it is compared to the other solutions, but at least is shortish.

spiral[rlist_ /; Length[rlist] >= 2] := Module[{findCentre},
findCentre[zlist_] := Module[{coslst, theta, ind, k},
k = Length[zlist] + 1;
coslst = Table[
With[{dist = N@Norm[zlist[[-1]] - zlist[[l]]]},
((rlist[[k - 1]] + rlist[[k]])^2 - (rlist[[k]] + rlist[[l]])^2 + dist^2)/dist],
{l, k - 2}]/2/(rlist[[k - 1]] + rlist[[k]]) ;
ind = Flatten[Position[coslst, a_?NumericQ /; Abs[a] < 1]];
theta = Min[Mod[#, 2 Pi,
ArcTan @@ (zlist[[-2]] - zlist[[-1]])] &@(-ArcCos[
coslst[[ind]]] + (ArcTan @@ (# - zlist[[k - 1]]) & /@
zlist[[ind]]))];
zlist[[k - 1]] + (rlist[[k]] + rlist[[k - 1]]) {Cos[theta], Sin[theta]}];
Nest[Append[#, findCentre[#]] &, {{0, 0}, {Total[rlist[[;; 2]]], 0}}, Length[rlist] - 2]]

testList = Union@RandomReal[{1, 10}, 50];
result = spiral[testList];


(* Position of a circle tangential to other two circles *)
pos[{{x1_, y1_}, r1_}, {{x2_, y2_}, r2_}, r3_] :=
(k = N@( ((x1 - x3)^2 + (y1 - y3)^2 == (r1 + r3)^2) &&
(x2 - x3)^2 + (y2 - y3)^2 == (r2 + r3)^2);
({x3, y3} /. FindInstance[k, {x3, y3}, Reals, 2])
)

(*Select the correct center*)
{Last@SortBy[Select[Flatten[Table[
pos[p, Last@prevCirc, currentCircRadius], {p, Most@prevCirc}], 1],
Im[#] == {0., 0.} && prevCirc[[-1, 1, 1]] #[[2]] - prevCirc[[-1, 1, 2]] #[[1]] <=0 &],