summaryrefslogtreecommitdiff log msg author committer range
path: root/third_party/spiro/curves/bigmat.py
diff options
 context: 12345678910152025303540 space: includeignore mode: unifiedssdiffstat only
Diffstat (limited to 'third_party/spiro/curves/bigmat.py')
-rw-r--r--third_party/spiro/curves/bigmat.py662
1 files changed, 662 insertions, 0 deletions
 diff --git a/third_party/spiro/curves/bigmat.py b/third_party/spiro/curves/bigmat.pynew file mode 100644index 0000000..c1fac0c--- /dev/null+++ b/third_party/spiro/curves/bigmat.py@@ -0,0 +1,662 @@+# Solver based on direct Newton solving of 4 parameters for each curve+# segment++import sys+from math import *++from Numeric import *+import LinearAlgebra as la++import poly3+import band++class Seg:+ def __init__(self, chord, th):+ self.ks = [0., 0., 0., 0.]+ self.chord = chord+ self.th = th+ def compute_ends(self, ks):+ chord, ch_th = poly3.integ_chord(ks)+ l = chord / self.chord+ thl = ch_th - (-.5 * ks[0] + .125 * ks[1] - 1./48 * ks[2] + 1./384 * ks[3])+ thr = (.5 * ks[0] + .125 * ks[1] + 1./48 * ks[2] + 1./384 * ks[3]) - ch_th+ k0l = l * (ks[0] - .5 * ks[1] + .125 * ks[2] - 1./48 * ks[3])+ k0r = l * (ks[0] + .5 * ks[1] + .125 * ks[2] + 1./48 * ks[3])+ l2 = l * l+ k1l = l2 * (ks[1] - .5 * ks[2] + .125 * ks[3])+ k1r = l2 * (ks[1] + .5 * ks[2] + .125 * ks[3])+ l3 = l2 * l+ k2l = l3 * (ks[2] - .5 * ks[3])+ k2r = l3 * (ks[2] + .5 * ks[3])+ return (thl, k0l, k1l, k2l), (thr, k0r, k1r, k2r), l+ def set_ends_from_ks(self):+ self.endl, self.endr, self.l = self.compute_ends(self.ks)+ def fast_pderivs(self):+ l = self.l+ l2 = l * l+ l3 = l2 * l+ return [((.5, l, 0, 0), (.5, l, 0, 0)),+ ((-1./12, -l/2, l2, 0), (1./12, l/2, l2, 0)),+ ((1./48, l/8, -l2/2, l3), (1./48, l/8, l2/2, l3)),+ ((-1./480, -l/48, l2/8, -l3/2), (1./480, l/48, l2/8, l3/2))]+ def compute_pderivs(self):+ rd = 2e6+ delta = 1./rd+ base_ks = self.ks+ base_endl, base_endr, dummy = self.compute_ends(base_ks)+ result = []+ for i in range(4):+ try_ks = base_ks[:]+ try_ks[i] += delta+ try_endl, try_endr, dummy = self.compute_ends(try_ks)+ deriv_l = (rd * (try_endl[0] - base_endl[0]),+ rd * (try_endl[1] - base_endl[1]),+ rd * (try_endl[2] - base_endl[2]),+ rd * (try_endl[3] - base_endl[3]))+ deriv_r = (rd * (try_endr[0] - base_endr[0]),+ rd * (try_endr[1] - base_endr[1]),+ rd * (try_endr[2] - base_endr[2]),+ rd * (try_endr[3] - base_endr[3]))+ result.append((deriv_l, deriv_r))+ return result++class Node:+ def __init__(self, x, y, ty, th):+ self.x = x+ self.y = y+ self.ty = ty+ self.th = th+ def continuity(self):+ if self.ty == 'o':+ return 4+ elif self.ty in ('c', '[', ']'):+ return 2+ else:+ return 0++def mod_2pi(th):+ u = th / (2 * pi)+ return 2 * pi * (u - floor(u + 0.5))++def setup_path(path):+ segs = []+ nodes = []+ nsegs = len(path)+ if path[0][2] == '{':+ nsegs -= 1+ for i in range(nsegs):+ i1 = (i + 1) % len(path)+ x0, y0, t0 = path[i]+ x1, y1, t1 = path[i1]+ s = Seg(hypot(y1 - y0, x1 - x0), atan2(y1 - y0, x1 - x0))+ segs.append(s)+ for i in range(len(path)):+ x0, y0, t0 = path[i]++ if t0 in ('{', '}', 'v'):+ th = 0+ else:+ s0 = segs[(i + len(path) - 1) % len(path)]+ s1 = segs[i]+ th = mod_2pi(s1.th - s0.th)++ n = Node(x0, y0, t0, th)+ nodes.append(n)+ return segs, nodes++def count_vec(nodes):+ jincs = []+ n = 0+ for i in range(len(nodes)):+ i1 = (i + 1) % len(nodes)+ t0 = nodes[i].ty+ t1 = nodes[i1].ty+ if t0 in ('{', '}', 'v', '[') and t1 in ('{', '}', 'v', ']'):+ jinc = 0+ elif t0 in ('{', '}', 'v', '[') and t1 == 'c':+ jinc = 1+ elif t0 == 'c' and t1 in ('{', '}', 'v', ']'):+ jinc = 1+ elif t0 == 'c' and t1 == 'c':+ jinc = 2+ else:+ jinc = 4+ jincs.append(jinc)+ n += jinc+ return n, jincs++thscale, k0scale, k1scale, k2scale = 1, 1, 1, 1++def inversedot_woodbury(m, v):+ a = zeros((n, 11), Float)+ for i in range(n):+ for j in range(max(-7, -i), min(4, n - i)):+ a[i, j + 7] = m[i, i + j]+ print a+ al, indx, d = band.bandec(a, 7, 3)+ VtZ = identity(4, Float)+ Z = zeros((n, 4), Float)+ for i in range(4):+ u = zeros(n, Float)+ for j in range(4):+ u[j] = m[j, n - 4 + i]+ band.banbks(a, 7, 3, al, indx, u)+ for k in range(n):+ Z[k, i] = u[k]+ #Z[:,i] = u+ for j in range(4):+ VtZ[j, i] += u[n - 4 + j]+ print Z+ print VtZ+ H = la.inverse(VtZ)+ print H+ band.banbks(a, 7, 3, al, indx, v)+ return(v - dot(Z, dot(H, v[n - 4:])))++def inversedot(m, v):+ return dot(la.inverse(m), v)+ n, nn = m.shape+ if 1:+ for i in range(n):+ sys.stdout.write('% ')+ for j in range(n):+ if m[i, j] > 0: sys.stdout.write('+ ')+ elif m[i, j] < 0: sys.stdout.write('- ')+ else: sys.stdout.write(' ')+ sys.stdout.write('\n')++ cyclic = False+ for i in range(4):+ for j in range(n - 4, n):+ if m[i, j] != 0:+ cyclic = True+ print '% cyclic:', cyclic+ if not cyclic:+ a = zeros((n, 11), Float)+ for i in range(n):+ for j in range(max(-5, -i), min(6, n - i)):+ a[i, j + 5] = m[i, i + j]+ for i in range(n):+ sys.stdout.write('% ')+ for j in range(11):+ if a[i, j] > 0: sys.stdout.write('+ ')+ elif a[i, j] < 0: sys.stdout.write('- ')+ else: sys.stdout.write(' ')+ sys.stdout.write('\n')+ al, indx, d = band.bandec(a, 5, 5)+ print a+ band.banbks(a, 5, 5, al, indx, v)+ return v+ else:+ #return inversedot_woodbury(m, v)+ bign = 3 * n+ a = zeros((bign, 11), Float)+ u = zeros(bign, Float)+ for i in range(bign):+ u[i] = v[i % n]+ for j in range(-7, 4):+ a[i, j + 7] = m[i % n, (i + j + 7 * n) % n]+ #print a+ if 1:+ for i in range(bign):+ sys.stdout.write('% ')+ for j in range(11):+ if a[i, j] > 0: sys.stdout.write('+ ')+ elif a[i, j] < 0: sys.stdout.write('- ')+ else: sys.stdout.write(' ')+ sys.stdout.write('\n')+ #print u+ al, indx, d = band.bandec(a, 5, 5)+ band.banbks(a, 5, 5, al, indx, u)+ #print u+ return u[n + 2: 2 * n + 2]++def iter(segs, nodes):+ n, jincs = count_vec(nodes)+ print '%', jincs+ v = zeros(n, Float)+ m = zeros((n, n), Float)+ for i in range(len(segs)):+ segs[i].set_ends_from_ks()+ j = 0+ j0 = 0+ for i in range(len(segs)):+ i1 = (i + 1) % len(nodes)+ t0 = nodes[i].ty+ t1 = nodes[i1].ty+ seg = segs[i]++ derivs = seg.compute_pderivs()+ print '%derivs:', derivs++ jinc = jincs[i] # the number of params on this seg+ print '%', t0, t1, jinc, j0++ # The constraints are laid out as follows:+ # constraints that cross the node on the left+ # constraints on the left side+ # constraints on the right side+ # constraints that cross the node on the right++ jj = j0 # the index into the constraint row we're writing+ jthl, jk0l, jk1l, jk2l = -1, -1, -1, -1+ jthr, jk0r, jk1r, jk2r = -1, -1, -1, -1++ # constraints crossing left++ if t0 == 'o':+ jthl = jj + 0+ jk0l = jj + 1+ jk1l = jj + 2+ jk2l = jj + 3+ jj += 4+ elif t0 in ('c', '[', ']'):+ jthl = jj + 0+ jk0l = jj + 1+ jj += 2++ # constraints on left++ if t0 in ('[', 'v', '{') and jinc == 4:+ jk1l = jj+ jj += 1+ if t0 in ('[', 'v', '{', 'c') and jinc == 4:+ jk2l = jj+ jj += 1++ # constraints on right++ if t1 in (']', 'v', '}') and jinc == 4:+ jk1r = jj+ jj += 1+ if t1 in (']', 'v', '}', 'c') and jinc == 4:+ jk2r = jj+ jj += 1++ # constraints crossing right++ jj %= n+ j1 = jj++ if t1 == 'o':+ jthr = jj + 0+ jk0r = jj + 1+ jk1r = jj + 2+ jk2r = jj + 3+ jj += 4+ elif t1 in ('c', '[', ']'):+ jthr = jj + 0+ jk0r = jj + 1+ jj += 2++ print '%', jthl, jk0l, jk1l, jk2l, jthr, jk0r, jk1r, jk2r++ if jthl >= 0:+ v[jthl] += thscale * (nodes[i].th - seg.endl[0])+ if jinc == 1:+ m[jthl][j] += derivs[0][0][0]+ elif jinc == 2:+ m[jthl][j + 1] += derivs[0][0][0]+ m[jthl][j] += derivs[1][0][0]+ elif jinc == 4:+ m[jthl][j + 2] += derivs[0][0][0]+ m[jthl][j + 3] += derivs[1][0][0]+ m[jthl][j + 0] += derivs[2][0][0]+ m[jthl][j + 1] += derivs[3][0][0]+ if jk0l >= 0:+ v[jk0l] += k0scale * seg.endl[1]+ if jinc == 1:+ m[jk0l][j] -= derivs[0][0][1]+ elif jinc == 2:+ m[jk0l][j + 1] -= derivs[0][0][1]+ m[jk0l][j] -= derivs[1][0][1]+ elif jinc == 4:+ m[jk0l][j + 2] -= derivs[0][0][1]+ m[jk0l][j + 3] -= derivs[1][0][1]+ m[jk0l][j + 0] -= derivs[2][0][1]+ m[jk0l][j + 1] -= derivs[3][0][1]+ if jk1l >= 0:+ v[jk1l] += k1scale * seg.endl[2]+ m[jk1l][j + 2] -= derivs[0][0][2]+ m[jk1l][j + 3] -= derivs[1][0][2]+ m[jk1l][j + 0] -= derivs[2][0][2]+ m[jk1l][j + 1] -= derivs[3][0][2]+ if jk2l >= 0:+ v[jk2l] += k2scale * seg.endl[3]+ m[jk2l][j + 2] -= derivs[0][0][3]+ m[jk2l][j + 3] -= derivs[1][0][3]+ m[jk2l][j + 0] -= derivs[2][0][3]+ m[jk2l][j + 1] -= derivs[3][0][3]++ if jthr >= 0:+ v[jthr] -= thscale * seg.endr[0]+ if jinc == 1:+ m[jthr][j] += derivs[0][1][0]+ elif jinc == 2:+ m[jthr][j + 1] += derivs[0][1][0]+ m[jthr][j + 0] += derivs[1][1][0]+ elif jinc == 4:+ m[jthr][j + 2] += derivs[0][1][0]+ m[jthr][j + 3] += derivs[1][1][0]+ m[jthr][j + 0] += derivs[2][1][0]+ m[jthr][j + 1] += derivs[3][1][0]+ if jk0r >= 0:+ v[jk0r] -= k0scale * seg.endr[1]+ if jinc == 1:+ m[jk0r][j] += derivs[0][1][1]+ elif jinc == 2:+ m[jk0r][j + 1] += derivs[0][1][1]+ m[jk0r][j + 0] += derivs[1][1][1]+ elif jinc == 4:+ m[jk0r][j + 2] += derivs[0][1][1]+ m[jk0r][j + 3] += derivs[1][1][1]+ m[jk0r][j + 0] += derivs[2][1][1]+ m[jk0r][j + 1] += derivs[3][1][1]+ if jk1r >= 0:+ v[jk1r] -= k1scale * seg.endr[2]+ m[jk1r][j + 2] += derivs[0][1][2]+ m[jk1r][j + 3] += derivs[1][1][2]+ m[jk1r][j + 0] += derivs[2][1][2]+ m[jk1r][j + 1] += derivs[3][1][2]+ if jk2r >= 0:+ v[jk2r] -= k2scale * seg.endr[3]+ m[jk2r][j + 2] += derivs[0][1][3]+ m[jk2r][j + 3] += derivs[1][1][3]+ m[jk2r][j + 0] += derivs[2][1][3]+ m[jk2r][j + 1] += derivs[3][1][3]++ j += jinc+ j0 = j1+ #print m+ dk = inversedot(m, v)+ dkmul = 1+ j = 0+ for i in range(len(segs)):+ jinc = jincs[i]+ if jinc == 1:+ segs[i].ks[0] += dkmul * dk[j]+ elif jinc == 2:+ segs[i].ks[0] += dkmul * dk[j + 1]+ segs[i].ks[1] += dkmul * dk[j + 0]+ elif jinc == 4:+ segs[i].ks[0] += dkmul * dk[j + 2]+ segs[i].ks[1] += dkmul * dk[j + 3]+ segs[i].ks[2] += dkmul * dk[j + 0]+ segs[i].ks[3] += dkmul * dk[j + 1]+ j += jinc++ norm = 0.+ for i in range(len(dk)):+ norm += dk[i] * dk[i]+ return sqrt(norm)+++def plot_path(segs, nodes, tol = 1.0, show_cpts = False):+ if show_cpts:+ cpts = []+ j = 0+ cmd = 'moveto'+ for i in range(len(segs)):+ i1 = (i + 1) % len(nodes)+ n0 = nodes[i]+ n1 = nodes[i1]+ x0, y0, t0 = n0.x, n0.y, n0.ty+ x1, y1, t1 = n1.x, n1.y, n1.ty+ ks = segs[i].ks+ abs_ks = abs(ks[0]) + abs(ks[1] / 2) + abs(ks[2] / 8) + abs(ks[3] / 48)+ n_subdiv = int(ceil(.001 + tol * abs_ks))+ n_subhalf = (n_subdiv + 1) / 2+ if n_subdiv > 1:+ n_subdiv = n_subhalf * 2+ ksp = (ks[0] * .5, ks[1] * .25, ks[2] * .125, ks[3] * .0625)+ pside = poly3.int_3spiro_poly(ksp, n_subhalf)+ ksm = (ks[0] * -.5, ks[1] * .25, ks[2] * -.125, ks[3] * .0625)+ mside = poly3.int_3spiro_poly(ksm, n_subhalf)+ mside.reverse()+ for j in range(len(mside)):+ mside[j] = (-mside[j][0], -mside[j][1])+ if n_subdiv > 1:+ pts = mside + pside[1:]+ else:+ pts = mside[:1] + pside[1:]+ chord_th = atan2(y1 - y0, x1 - x0)+ chord_len = hypot(y1 - y0, x1 - x0)+ rot = chord_th - atan2(pts[-1][1] - pts[0][1], pts[-1][0] - pts[0][0])+ scale = chord_len / hypot(pts[-1][1] - pts[0][1], pts[-1][0] - pts[0][0])+ u, v = scale * cos(rot), scale * sin(rot)+ xt = x0 - u * pts[0][0] + v * pts[0][1]+ yt = y0 - u * pts[0][1] - v * pts[0][0]+ s = -.5+ for x, y in pts:+ xp, yp = xt + u * x - v * y, yt + u * y + v * x+ thp = (((ks[3]/24 * s + ks[2]/6) * s + ks[1] / 2) * s + ks[0]) * s + rot+ up, vp = scale / (1.5 * n_subdiv) * cos(thp), scale / (1.5 * n_subdiv) * sin(thp)+ if s == -.5:+ if cmd == 'moveto':+ print xp, yp, 'moveto'+ cmd = 'curveto'+ else:+ if show_cpts:+ cpts.append((xlast + ulast, ylast + vlast))+ cpts.append((xp - up, yp - vp))+ print xlast + ulast, ylast + vlast, xp - up, yp - vp, xp, yp, 'curveto'+ xlast, ylast, ulast, vlast = xp, yp, up, vp+ s += 1. / n_subdiv+ if t1 == 'v':+ j += 2+ else:+ j += 1+ print 'stroke'+ if show_cpts:+ for x, y in cpts:+ print 'gsave 0 0 1 setrgbcolor', x, y, 'translate circle fill grestore'++def plot_ks(segs, nodes, xo, yo, xscale, yscale):+ j = 0+ cmd = 'moveto'+ x = xo+ for i in range(len(segs)):+ i1 = (i + 1) % len(nodes)+ n0 = nodes[i]+ n1 = nodes[i1]+ x0, y0, t0 = n0.x, n0.y, n0.ty+ x1, y1, t1 = n1.x, n1.y, n1.ty+ ks = segs[i].ks+ chord, ch_th = poly3.integ_chord(ks)+ l = chord/segs[i].chord+ k0 = l * poly3.eval_cubic(ks[0], ks[1], .5 * ks[2], 1./6 * ks[3], -.5)+ print x, yo + yscale * k0, cmd+ cmd = 'lineto'+ k3 = l * poly3.eval_cubic(ks[0], ks[1], .5 * ks[2], 1./6 * ks[3], .5)+ k1 = k0 + l/3 * (ks[1] - 0.5 * ks[2] + .125 * ks[3])+ k2 = k3 - l/3 * (ks[1] + 0.5 * ks[2] + .125 * ks[3])+ print x + xscale / l / 3., yo + yscale * k1+ print x + 2 * xscale / l / 3., yo + yscale * k2+ print x + xscale / l, yo + yscale * k3, 'curveto'+ x += xscale / l+ if t1 == 'v':+ j += 2+ else:+ j += 1+ print 'stroke'+ print xo, yo, 'moveto', x, yo, 'lineto stroke'++def plot_nodes(nodes, segs):+ for i in range(len(nodes)):+ n = nodes[i]+ print 'gsave', n.x, n.y, 'translate'+ if n.ty in ('c', '[', ']'):+ th = segs[i].th - segs[i].endl[0]+ if n.ty == ']': th += pi+ print 180 * th / pi, 'rotate'+ if n.ty == 'o':+ print 'circle fill'+ elif n.ty == 'c':+ print '3 4 poly fill'+ elif n.ty in ('v', '{', '}'):+ print '45 rotate 3 4 poly fill'+ elif n.ty in ('[', ']'):+ print '0 -3 moveto 0 0 3 90 270 arc fill'+ else:+ print '5 3 poly fill'+ print 'grestore'++def prologue():+ print '/ss 2 def'+ print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'+ print '/poly {'+ print ' dup false exch {'+ print ' 0 3 index 2 index { lineto } { moveto } ifelse pop true'+ print ' 360.0 2 index div rotate'+ print ' } repeat pop pop pop'+ print '} bind def'++def run_path(path, show_iter = False, n = 10, xo = 36, yo = 550, xscale = .25, yscale = 2000, pl_nodes = True):+ segs, nodes = setup_path(path)+ print '.5 setlinewidth'+ for i in range(n):+ if i == n - 1:+ print '0 0 0 setrgbcolor 1 setlinewidth'+ elif i == 0:+ print '1 0 0 setrgbcolor'+ elif i == 1:+ print '0 0.5 0 setrgbcolor'+ elif i == 2:+ print '0.3 0.3 0.3 setrgbcolor'+ norm = iter(segs, nodes)+ print '% norm =', norm+ if show_iter or i == n - 1:+ #print '1 0 0 setrgbcolor'+ #plot_path(segs, nodes, tol = 5)+ #print '0 0 0 setrgbcolor'+ plot_path(segs, nodes, tol = 1.0)+ plot_ks(segs, nodes, xo, yo, xscale, yscale)+ if pl_nodes:+ plot_nodes(nodes, segs)++if __name__ == '__main__':+ if 1:+ path = [(100, 350, 'o'), (225, 350, 'o'), (350, 450, 'o'),+ (450, 400, 'o'), (315, 205, 'o'), (300, 200, 'o'),+ (285, 205, 'o')]++ if 1:+ path = [(100, 350, 'o'), (175, 375, '['), (250, 375, ']'), (325, 425, '['),+ (325, 450, ']'),+ (400, 475, 'o'), (350, 200, 'c')]++ if 0:+ ecc, ty, ty1 = 0.56199, 'c', 'c'+ ecc, ty, ty1 = 0.49076, 'o', 'o',+ ecc, ty, ty1 = 0.42637, 'o', 'c'+ path = [(300 - 200 * ecc, 300, ty), (300, 100, ty1),+ (300 + 200 * ecc, 300, ty), (300, 500, ty1)]++ # difficult path #3+ if 0:+ path = [(100, 300, '{'), (225, 350, 'o'), (350, 500, 'o'),+ (450, 500, 'o'), (450, 450, 'o'), (300, 200, '}')]++ if 0:+ path = [(100, 100, '{'), (200, 180, 'v'), (250, 215, 'o'),+ (300, 200, 'o'), (400, 100, '}')]++ if 0:+ praw = [+ (134, 90, 'o'),+ (192, 68, 'o'),+ (246, 66, 'o'),+ (307, 107, 'o'),+ (314, 154, '['),+ (317, 323, ']'),+ (347, 389, 'o'),+ (373, 379, 'v'),+ (386, 391, 'v'),+ (365, 409, 'o'),+ (335, 419, 'o'),+ (273, 390, 'v'),+ (251, 405, 'o'),+ (203, 423, 'o'),+ (102, 387, 'o'),+ (94, 321, 'o'),+ (143, 276, 'o'),+ (230, 251, 'o'),+ (260, 250, 'v'),+ (260, 220, '['),+ (258, 157, ']'),+ (243, 110, 'o'),+ (159, 99, 'o'),+ (141, 121, 'o'),+ (156, 158, 'o'),+ (121, 184, 'o'),+ (106, 117, 'o')]+ if 0:+ praw = [+ (275, 56, 'o'),+ (291, 75, 'v'),+ (312, 61, 'o'),+ (344, 50, 'o'),+ (373, 72, 'o'),+ (356, 91, 'o'),+ (334, 81, 'o'),+ (297, 85, 'v'),+ (306, 116, 'o'),+ (287, 180, 'o'),+ (236, 213, 'o'),+ (182, 212, 'o'),+ (157, 201, 'v'),+ (149, 209, 'o'),+ (143, 230, 'o'),+ (162, 246, 'c'),+ (202, 252, 'o'),+ (299, 260, 'o'),+ (331, 282, 'o'),+ (341, 341, 'o'),+ (308, 390, 'o'),+ (258, 417, 'o'),+ (185, 422, 'o'),+ (106, 377, 'o'),+ (110, 325, 'o'),+ (133, 296, 'o'),+ (147, 283, 'v'),+ (117, 238, 'o'),+ (133, 205, 'o'),+ (147, 191, 'v'),+ (126, 159, 'o'),+ (128, 94, 'o'),+ (167, 50, 'o'),+ (237, 39, 'o')]+ + path = []+ for x, y, ty in praw:+ #if ty == 'o': ty = 'c'+ path.append((x, 550 - y, ty))++ if 0:+ path = [(100, 300, 'o'), (300, 100, 'o'), (300, 500, 'o')]++ if 0:+ # Woodford data set+ ty = 'o'+ praw = [(0, 0, '{'), (1, 1.9, ty), (2, 2.7, ty), (3, 2.6, ty),+ (4, 1.6, ty), (5, .89, ty), (6, 1.2, '}')]+ path = []+ for x, y, t in praw:+ path.append((100 + 80 * x, 100 + 80 * y, t))++ if 0:+ ycen = 32+ yrise = 0+ path = []+ ty = '{'+ for i in range(10):+ path.append((50 + i * 30, 250 + (10 - i) * yrise, ty))+ ty = 'o'+ path.append((350, 250 + ycen, ty))+ for i in range(1, 10):+ path.append((350 + i * 30, 250 + i * yrise, ty))+ path.append((650, 250 + 10 * yrise, '}'))++ prologue()++ run_path(path, show_iter = True, n=5)