# I wrote this on Beatrice's birthday, but didn't get around to posting # it until now.
#!/usr/bin/python # 5-dimensional hypercube with 32 vertices for Bea's 32nd birthday # Written in Python with list-comprehensions and "sum"; works in # Python 2.3, might work in 2.2 import random, math def vecmag(vec): return math.sqrt(sum([x*x for x in vec])) def vec_norm(vec): size = vecmag(vec) return [x / size for x in vec] # generate randomish vectors to project things onto # These vectors are insufficiently random --- they're more likely to # point toward the corners of the unit cube rather than the faces. oh # well. def randvec(): return vec_norm([random.random() * 2 - 1 for ii in range(5)]) def fourdcubepoints(): rv = [] for a in (0, 1): for b in (0, 1): for c in (0, 1): for d in (0, 1): rv.append((a, b, c, d)) return rv def cubelines(): points = fourdcubepoints() rv = [] for dimension in range(5): for point in points: rv.append(( point[:dimension] + (0,) + point[dimension:], point[:dimension] + (1,) + point[dimension:])) return rv def dotprod(a, b): assert len(a) == len(b) return sum([a[ii] * b[ii] for ii in range(len(a))]) def twodlines(veca, vecb): lines = cubelines() return [((dotprod(line[0], veca), dotprod(line[0], vecb)), (dotprod(line[1], veca), dotprod(line[1], vecb))) for line in lines] def pslines(lines, scale): rv = [] for line in lines: rv.append("%d %d moveto\n" % (line[0][0] * scale, line[0][1] * scale)) rv.append("%d %d lineto\n" % (line[1][0] * scale, line[1][1] * scale)) rv.append("stroke showpage\n") return ''.join(rv) def bbox(lines): minx, miny, maxx, maxy = 10000, 10000, -10000, -10000 for line in lines: for x, y in line: if x < minx: minx = x if x > maxx: maxx = x if y < miny: miny = y if y > maxy: maxy = y return minx, miny, maxx, maxy def getscale(box, width, height): minx, miny, maxx, maxy = box yscale = height / (maxy - miny) xscale = width / (maxx - minx) return min(xscale, yscale) def orthvec(basevec, othervec): amount = sum([othervec[ii] * basevec[ii] for ii in range(len(basevec))]) return vec_norm([othervec[ii] - basevec[ii] * amount for ii in range(len(basevec))]) pagewidth = 8 * 72 pageheight = 10.5 * 72 offset = 72 / 4 def goodpic(): veca, vecb = randvec(), randvec() vecb = orthvec(veca, vecb) lines = twodlines(veca, vecb) box = bbox(lines) scale = getscale(box, pagewidth, pageheight) minx, miny, _, _ = box offsetx, offsety = offset - minx * scale, offset - miny * scale return "%%!\n%d %d translate\n" % (offsetx, offsety) + pslines(lines, scale)