1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
from math import cos, asin, tau # the first outer tube; the rest except for the largest; the largest pr = [x for x in range(11, 44, 2) if all (x % p for p in {2, 3, 5})] t1, *tr8, t0 = pr # given three tube radii, (a, b, c), return the angle subtended # at the centre of tube <a> between the centres of tubes <b> and <c> def ang(a, b, c): t = b * c / (a * (a + b + c) + b * c) return 2 * asin(t ** 0.5) # return the length of the third side of a triangle with sides # of length <a> and <b> and an included angle <chi> def third(a, b, chi): return (a * a + b * b - 2 * a * b * cos(chi)) ** 0.5 # place a tube in a sequence of outer tubes with # tr = tubes yet to be placed, tp = tubes placed def place(tr, tp): nr = len(tp) # have we placed all but one tube? if nr == 8: # return the sequence of the nine outer tube radii yield tp + tr else: # try to place another tube for i, tn in enumerate(tr): # form the new remaining and placed sequences trn = tr[:i] + tr[i+1:] tpn = tp + [tn] # pick the sequence in which there is a divisor # of the sum of the tube radii tf = trn if nr in {1, 5} else tpn # sum the tube radii (including the current one) sp = sum(tpn) # check that the sum is a multiple of a radius # in the appropriate sequence if any(sp % t == 0 for t in tf): # and if so, place it and continue to the next yield from place(trn, tpn) # for saving the radii of the last tubes placed sol = set() # consider possible sequences of outer tube placments for s in place(tr8, [t1]): # sum the angles subtended by the outer tubes # at the centre of the central tube asum = sum(ang(t0, a, b) for a, b in zip(s, s[1:])) # find the distance between the first and last # outer tubes placed and hence the gap ln = third(t0 + s[0], t0 + s[-1], tau - asum) gap = ln - (s[0] + s[-1]) # save the radius of the last tube placed if the # gap is less than a millimetre and the third # placed tube is not the largest outer tube if 0 <= gap < 1 and s[1] != tr8[-1]: sol.add(s[-1]) print(f"{s} gap = {1000 * gap:>4.0f}\u03bcm") v, *r = sol if not r: print(f"\nThe last tube placed has a radius of {v}mm.") |