""" Version 2.2 March 15, 2005 Creates a network of VPython animations connected through key frames, with a random selection at each frame. Like a network of subway tunnels, and a choice of where to go next at each station (tunnel = scenario, nodelist = options of where to go next i.e. any scenario starting with current key frame. The theme of this hypertoon is Buckminster Fuller's concentric hierarchy of polyhedra, complete with jitterbug transformation and allusions to the CCP. Depends on / compatible with rbf.py Version 1.4 (March 15, 2005) =============================================================== History Last modified: March 15, 2005 got rid of silly eval and Vset class -- a plain dictionary works incorporated changes by John Zelle (more startup options, 2.3 compat) rewrote all the jitterbug and cube transformations to redraw existing cylinders and vertices, instead of using delete/draw double buffering -- makes for much smoother motions March 14 2005 29 scenarios, 8 key frames Fixed bugs in jitterbug Put rbf canonical points inside a class, use copies of Sped it up, other aesthetic improvements Added more five-fold shapes place balls growing/shrinking Removed dependencies on colors.py coords.py Implemented threading (2 hypertoons run together) Added stereo option First posted: March 11 2005 16 scenarios, 6 key frames Original proof of concept Background posted to Python/edu-sig http://mail.python.org/pipermail/edu-sig/2005-March/004499.html John Zelle gets it in stereo! http://mail.python.org/pipermail/edu-sig/2005-March/004503.html Kirby Urner 4D Solutions """ from random import randint import threading import rbf import sys keyframes = ['A','B','C','D','E','F','G','H'] def trans0(thing): print "trans0: rh -> octa" rh = rbf.Rhdodeca() # A: rh dodeca all alone rh.draw() if thing is not None: thing.delete() oc = rbf.Octa() oc.draw(trace=True) rh.delete() # B: octahedron all alone return oc def trans1(thing): print "trans1: rh -> cube" rh = rbf.Rhdodeca() # A: rh dodeca all alone rh.draw() if thing is not None: thing.delete() cb = rbf.Cube() cb.draw(trace=True) rh.delete() # C: cube all alone return cb def trans2(thing): print "trans2: rh -> tetra" rh = rbf.Rhdodeca() # A: rh dodeca all alone rh.draw() if thing is not None: thing.delete() cb = rbf.Cube() cb.draw(trace=True) tet = rbf.Tetra() tet.draw(trace=True) rh.delete() cb.delete() # D: tetra all alone return tet def trans3(thing): print "trans3: octa -> cube" oc = rbf.Octa() # B: octahedron all alone oc.draw() if thing is not None: thing.delete() cb = rbf.Cube() cb.draw(trace=True) oc.delete() # C: cube all alone return cb def trans4(thing): print "trans4: cube -> tetra" cb = rbf.Cube() # C: cube all alone cb.draw() if thing is not None: thing.delete() tet = rbf.Tetra() tet.draw(trace=True) cb.delete() # D: tetra all alone return tet def trans5(thing): print "trans5: tetra -> octa" tet = rbf.Tetra() # D: tetra all alone tet.draw() if thing is not None: thing.delete() oc = rbf.Octa() oc.draw(trace=True) tet.delete() # B: octahedron all alone return oc def trans6(thing): print "trans6: octa -> rh dodeca" oc = rbf.Octa() # B: octahedron all alone oc.draw() if thing is not None: thing.delete() rh = rbf.Rhdodeca() rh.draw(trace=True) oc.delete() # A: rh dodeca all alone return rh def trans7(thing): print "trans7: cube -> rh dodeca" cu = rbf.Cube() # C: cube all alone cu.draw() if thing is not None: thing.delete() rh = rbf.Rhdodeca() rh.draw(trace=True) cu.delete() # A: rh dodeca all alone return rh def trans8(thing): print "trans8: tetra -> rh dodeca" tet = rbf.Tetra() # D: tetra all alone tet.draw() if thing is not None: thing.delete() cb = rbf.Cube() cb.draw(trace=True) rh = rbf.Rhdodeca() rh.draw(trace=True) tet.delete() cb.delete() # A: rh dodeca all alone return rh def trans9(thing): print "trans9: cube -> octa" cb = rbf.Cube() # C: cube all alone cb.draw() if thing is not None: thing.delete() oc = rbf.Octa() oc.draw(trace=True) cb.delete() # B: octahedron all alone return oc def trans10(thing): print "trans10: tetra -> cube" tet = rbf.Tetra() # D: tetra all alone tet.draw() if thing is not None: thing.delete() invtet = rbf.Invtetra() invtet.draw(trace=True) cb = rbf.Cube() cb.draw(trace=True) tet.delete() invtet.delete() # C: cube all alone return cb def trans11(thing): print "trans11: octa -> tetra" oc = rbf.Octa() # B: octahedron all alone oc.draw() if thing is not None: thing.delete() cb = rbf.Cube() cb.draw(trace=True) tet = rbf.Tetra() tet.draw(trace=True) cb.delete() oc.delete() # D: tetra all alone return tet def trans12(thing): print "trans12: rh -> cubocta" rh = rbf.Rhdodeca() # A: rh dodeca all alone rh.draw() if thing is not None: thing.delete() sp = rbf.VEspokes() sp.draw(trace=True) cu = rbf.Cubocta() cu.draw(trace=True) sp.delete() rh.delete() # E: cubocta all alone return cu def trans13(thing): print "trans13: cubocta -> rh" cu = rbf.Cubocta() # E: Cubocta all alone cu.draw() if thing is not None: thing.delete() sp = rbf.VEspokes() sp.draw(trace=True) rh = rbf.Rhdodeca() rh.draw(trace=True) sp.delete() cu.delete() # A: rh dodeca all alone return rh def trans14(thing): print "trans14: cubocta -> icosa" cu = rbf.Cubocta() # E: Cubocta all alone cu.draw() if thing is not None: thing.delete() ic = rbf.Icosa() tracks = [] for let in ['O','P','Q','R','S','T','U','V','W','X','Y','Z']: tracks.append([ cu.vertices[let], ic.vertices[let+'1'] - cu.vertices[let] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) cu.redraw() ic.draw() cu.delete() # F: Icosa all alone return ic def trans15(thing): print "trans15: icosa -> cubocta" ic = rbf.Icosa() # F: Icosa all alone ic.draw() if thing is not None: thing.delete() cu = rbf.Cubocta() tracks = [] for let in ['O','P','Q','R','S','T','U','V','W','X','Y','Z']: tracks.append( [ ic.vertices[let+'1'], cu.vertices[let] - ic.vertices[let+'1'] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) ic.redraw() cu.draw() ic.delete() return cu def trans16(thing): print "trans16: cubocta -> cubocta" cu = rbf.Cubocta() # E: Cubocta all alone cu.draw() if thing is not None: thing.delete() vs = cu.vertices.values() vs.append(rbf.vector(0,0,0)) wow(vs, 500) return cu def trans17(thing): print "trans17: icosa -> icosa" ic = rbf.Icosa() # E: Icosa all alone ic.draw() if thing is not None: thing.delete() vs = ic.vertices.values() wow(vs, 500) return ic def trans18(thing): print "trans18: rh -> rh" rh = rbf.Rhdodeca() # A: rh dodeca all alone rh.draw() if thing is not None: thing.delete() vs = [] vs.append(rbf.vector(0,0,0)) wow(vs, 100) return rh def trans19(thing): print "trans19: icosa -> octa" ic = rbf.Jiticosa() # F: Icosa all alone ic.draw() if thing is not None: thing.delete() oc = rbf.Octa() tracks = [] for iclet, oclet in zip(['O','P','Q','R','S','T','U','V','W','X','Y','Z'], ['I','K','L','I','N','K','L','N','J','M','M','J']): tracks.append( [ ic.vertices[iclet+'1'], oc.vertices[oclet] - ic.vertices[iclet+'1'] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) ic.redraw() oc.draw() ic.delete() # E: Octa all alone return oc def trans20(thing): print "trans20: octa -> icosa" ic = rbf.Jiticosa() oc = rbf.Octa() for iclet, oclet in zip(['O1','P1','Q1','R1','S1','T1','U1','V1','W1','X1','Y1','Z1'], ['I','K','L','I','N','K','L','N','J','M','M','J']): v = oc.vertices[oclet] ic.vertices[iclet] = rbf.vector(v.x, v.y, v.z) # B: Octa all alone ic.draw() if thing is not None: thing.delete() ic3 = rbf.Icosa() tracks = [] for iclet in ['O1','P1','Q1','R1','S1','T1','U1','V1','W1','X1','Y1','Z1']: tracks.append( [ ic.vertices[iclet], ic3.vertices[iclet] - ic.vertices[iclet] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) ic.redraw() ic3.draw() ic.delete() # rbf.init() # F: Icosa all alone return ic3 def trans21(thing): print "trans21: icosa -> pentdodeca" ic = rbf.Icosa() # F: Icosa all alone ic.draw() if thing is not None: thing.delete() pd = rbf.Pentdodeca() pd.draw(trace=True) ic.delete() # G: Pdodeca all alone return pd def trans22(thing): print "trans22: pentdodeca -> icosa" pd = rbf.Pentdodeca() # G: Pdodeca all alone pd.draw() if thing is not None: thing.delete() ic = rbf.Icosa() ic.draw(trace=True) pd.delete() # F: Icosa all alone return ic def trans23(thing): print "trans23: pentdodeca -> cube" pd = rbf.Pentdodeca() # G: Pdodeca pd.draw() if thing is not None: thing.delete() cu1 = rbf.Pentcube() cu1.draw(trace=True) cu = rbf.Cube() tracks = [] for let1, let2 in zip(['B','G','D','E','C','A','F','H'], ['j','b','p','q','f','l','s','m']): tracks.append( [ cu1.vertices[let2], cu.vertices[let1] - cu1.vertices[let2] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) cu1.redraw() cu.draw() cu1.delete(1000) pd.delete() # C: Cube all alone return cu def trans24(thing): print "trans24: cube -> pentdodeca" cu1 = rbf.Cube() cu1.draw() # C: cube all alone if thing is not None: thing.delete() cu = rbf.Pentcube() tracks = [] for let1, let2 in zip(['B','G','D','E','C','A','F','H'], ['j','b','p','q','f','l','s','m']): tracks.append( [ cu1.vertices[let1], cu.vertices[let2] - cu1.vertices[let1] ]) for i in range(30): for v in tracks: v[0] += 1/30.0 * v[1] rbf.rate(100) cu1.redraw() cu.draw() cu1.delete(1000) pd = rbf.Pentdodeca() pd.draw(trace=True) cu.delete() # G: Pdodeca all alone return pd def trans25(thing): print "trans25: pentdodeca -> rh triaconta" pd = rbf.Pentdodeca() # G: Pdodeca all alone pd.draw() if thing is not None: thing.delete() ic = rbf.Icosa() ic.draw(trace=True) rt = rbf.Rhtriaconta() rt.draw(trace=True) pd.delete() ic.delete() # H: Rhtriac all alone return rt def trans26(thing): print "trans26: rh triaconta -> Pentdodeca" rt = rbf.Rhtriaconta() # H: Rtriac all alone rt.draw() if thing is not None: thing.delete() pd = rbf.Pentdodeca() pd.draw(trace=True) rt.delete() # G: Pentdodeca all alone return pd def trans27(thing): print "trans27: rh triaconta -> Icosa" rt = rbf.Rhtriaconta() # H: Rtriac all alone rt.draw() if thing is not None: thing.delete() ic = rbf.Icosa() ic.draw(trace=True) rt.delete() # F: Icosa all alone return ic def trans28(thing): print "trans28: Icosa -> rh triaconta" ic = rbf.Icosa() # F: Icosa all alone ic.draw() if thing is not None: thing.delete() rt = rbf.Rhtriaconta() rt.draw(trace=True) ic.delete() # H: Rhtriac all alone return rt def trans29(thing): cu = rbf.Cubocta() cu.draw() # E: Cubocta all alone if thing is not None: thing.delete() ic = trans14(cu) oc = trans19(ic) ic = trans20(oc) cu = trans15(ic) # E: Cubocta all alone return cu def wow(vs, r=60): sphs = [] maxlen = rbf.mag(rbf.Vset['A'] - rbf.Vset['B'])/2.0 for v in vs: sphs.append(rbf.sphere(pos=v, radius=0, color = (1,0.7,0.2))) for i in range(1,101): for s in sphs: rbf.rate(r) s.radius = maxlen * i/100 for i in range(100,-1,-1): for s in sphs: rbf.rate(r) s.radius = maxlen * i/100 class Scenario(object): def __init__(self, func, start, finish): self.func = func self.start = start self.finish = finish def play(self, thing=None): print self.start,'->',self.finish, r = self.func(thing) return r def __repr__(self): return "From %s to %s" % (self.start, self.finish) scenarios = {} # could be initialized by reading in from a text file # e.g # sc0 trans0 A B # sc1 trans1 A C # etc. scenarios['sc0'] = Scenario(trans0, 'A', 'B') scenarios['sc1'] = Scenario(trans1, 'A', 'C') scenarios['sc2'] = Scenario(trans2, 'A', 'D') scenarios['sc3'] = Scenario(trans3, 'B', 'C') scenarios['sc4'] = Scenario(trans4, 'C', 'D') scenarios['sc5'] = Scenario(trans5, 'D', 'B') scenarios['sc6'] = Scenario(trans6, 'B', 'A') scenarios['sc7'] = Scenario(trans7, 'C', 'A') scenarios['sc8'] = Scenario(trans8, 'D', 'A') scenarios['sc9'] = Scenario(trans9, 'C', 'B') scenarios['sc10'] = Scenario(trans10, 'D', 'C') scenarios['sc11'] = Scenario(trans11, 'B', 'D') scenarios['sc12'] = Scenario(trans12, 'A', 'E') scenarios['sc13'] = Scenario(trans13, 'E', 'A') scenarios['sc21'] = Scenario(trans21, 'F', 'G') scenarios['sc22'] = Scenario(trans22, 'G', 'F') scenarios['sc23'] = Scenario(trans23, 'G', 'C') scenarios['sc24'] = Scenario(trans24, 'C', 'G') scenarios['sc31'] = Scenario(trans24, 'C', 'G') # dupe (weighting) scenarios['sc25'] = Scenario(trans25, 'G', 'H') scenarios['sc26'] = Scenario(trans26, 'H', 'G') scenarios['sc27'] = Scenario(trans27, 'H', 'F') scenarios['sc28'] = Scenario(trans28, 'F', 'H') # jitterbug transformations scenarios['sc14'] = Scenario(trans14, 'E', 'F') scenarios['sc32'] = Scenario(trans14, 'E', 'F') # dupe (weighting) scenarios['sc15'] = Scenario(trans15, 'F', 'E') scenarios['sc19'] = Scenario(trans19, 'F', 'B') scenarios['sc20'] = Scenario(trans20, 'B', 'F') scenarios['sc29'] = Scenario(trans29, 'E', 'E') scenarios['sc30'] = Scenario(trans29, 'E', 'E') # dupe (weighting) # ball pulsings scenarios['sc16'] = Scenario(trans16, 'E', 'E') scenarios['sc17'] = Scenario(trans17, 'F', 'F') scenarios['sc18'] = Scenario(trans18, 'A', 'A') class Hypertoon(object): def __init__(self, scenarios): self.scenarios = scenarios self.nodes = dict(zip(keyframes,[[] for i in range(len(keyframes))])) for sc in self.scenarios: node = self.scenarios[sc].start self.nodes[node].append(sc) def play(self, n=5): node = keyframes[0] lastthing = None for i in xrange(n): nodelist = self.nodes[node] print nodelist nextsc = nodelist[randint(0,len(nodelist)-1)] lastthing = self.scenarios[nextsc].play(lastthing) node = self.scenarios[nextsc].finish def setup(st, fs): global scene2 scene2 = rbf.display(title='Hypertoon!', center=(0,0,0), background=(.5, .5, .5), height=768, width=1024) scene2.ambient = .5 scene2.fullscreen = fs if st: scene2.stereo = st scene2.stereodepth = 2.0 xyz = rbf.XYZaxes() xyz = 1.5 * xyz xyz.draw() scene2.autoscale = 0 xyz.delete() class Mythread(threading.Thread): def __init__(self, hypertoon, number): super(Mythread, self).__init__(None) self.hypertoon = hypertoon self.n = number def run(self): self.hypertoon.play(self.n) def main(stereo=None, threads=True, fullscreen=False): global scene2 setup(stereo, fullscreen) if threads: ht1 = Hypertoon(scenarios) ht2 = Hypertoon(scenarios) t1 = Mythread(ht1, 20) t2 = Mythread(ht2, 20) t1.start() t2.start() t1.join() t2.join() print "Threads complete" else: ht = Hypertoon(scenarios) ht.play(50) if __name__ == '__main__': stereo = None if '-S' in sys.argv: stereo = "redblue" elif '-SP' in sys.argv: stereo = "passive" elif 'SA' in sys.argv: stereo = "active" threads = '-T' in sys.argv fullscreen = '-F' in sys.argv main(stereo, threads, fullscreen)