diff options
Diffstat (limited to 'third_party/spiro/curves/mecsolve.py')
-rw-r--r-- | third_party/spiro/curves/mecsolve.py | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/third_party/spiro/curves/mecsolve.py b/third_party/spiro/curves/mecsolve.py new file mode 100644 index 0000000..3840cea --- /dev/null +++ b/third_party/spiro/curves/mecsolve.py @@ -0,0 +1,859 @@ +from math import * +import array +import sys +import random + +import numarray as N +import numarray.linear_algebra as la + +def eps_prologue(x0, y0, x1, y1, draw_box = False): + print '%!PS-Adobe-3.0 EPSF' + print '%%BoundingBox:', x0, y0, x1, y1 + print '%%EndComments' + print '%%EndProlog' + print '%%Page: 1 1' + if draw_box: + print x0, y0, 'moveto', x0, y1, 'lineto', x1, y1, 'lineto', x1, y0, 'lineto closepath stroke' + +def eps_trailer(): + print '%%EOF' + +# One step of 4th-order Runge-Kutta numerical integration - update y in place +def rk4(y, dydx, x, h, derivs): + hh = h * .5 + h6 = h * (1./6) + xh = x + hh + yt = [] + for i in range(len(y)): + yt.append(y[i] + hh * dydx[i]) + dyt = derivs(xh, yt) + for i in range(len(y)): + yt[i] = y[i] + hh * dyt[i] + dym = derivs(xh, yt) + for i in range(len(y)): + yt[i] = y[i] + h * dym[i] + dym[i] += dyt[i] + dyt = derivs(x + h, yt) + for i in range(len(y)): + y[i] += h6 * (dydx[i] + dyt[i] + 2 * dym[i]) + +def run_elastica_half(sp, k0, lam1, lam2, n): + def mec_derivs(x, ys): + th, k = ys[2], ys[3] + dx, dy = cos(th), sin(th) + return [dx, dy, k, lam1 * dx + lam2 * dy, k * k] + ys = [0, 0, 0, k0, 0] + xyk = [(ys[0], ys[1], ys[3])] + n = max(1, int(sp * n)) + h = float(sp) / n + s = 0 + for i in range(n): + dydx = mec_derivs(s, ys) + rk4(ys, dydx, s, h, mec_derivs) + xyk.append((ys[0], ys[1], ys[3])) + return xyk, ys[2], ys[4] + +def run_elastica(sm, sp, k0, lam1, lam2, n = 100): + xykm, thm, costm = run_elastica_half(-sm, k0, -lam1, lam2, n) + xykp, thp, costp = run_elastica_half(sp, k0, lam1, lam2, n) + xyk = [] + for i in range(1, len(xykm)): + x, y, k = xykm[i] + xyk.append((-x, y, k)) + xyk.reverse() + xyk.extend(xykp) + x = xyk[-1][0] - xyk[0][0] + y = xyk[-1][1] - xyk[0][1] + th = thm + thp + sth, cth = sin(thm), cos(thm) + x, y = x * cth - y * sth, x * sth + y * cth + result = [] + maxk = 0 + for xt, yt, kt in xyk: + maxk = max(maxk, kt) + result.append((xt, yt, kt)) + cost = costm + costp + return result, cost, x, y, th + +def run_mec_cos_pos(k, lam1, lam2, n = 1000): + cost = 0 + th = 0 + x = 0 + y = 0 + dt = 1.0 / n + result = [(0, 0)] + for i in range(n): + k1 = lam1 * cos(th) + lam2 * sin(th) + + cost += dt * k * k + x += dt * cos(th) + y += dt * sin(th) + th += dt * k + + k += dt * k1 + result.append((x, y)) + return result, cost, x, y, th + +def run_mec_cos(k, lam1, lam2, n = 1000): + resp, costp, xp, yp, thp = run_mec_cos_pos(k*.5, lam1*.25, lam2*.25, n) + resm, costm, xm, ym, thm = run_mec_cos_pos(k*.5, lam1*-.25, lam2*.25, n) + cost = (costp + costm) * .5 + x, y = xp + xm, yp - ym + th = thp + thm + sth, cth = .5 * sin(thm), .5 * cos(thm) + x, y = x * cth - y * sth, x * sth + y * cth + result = [] + for i in range(1, n): + xt, yt = resm[n - i - 1] + result.append((-xt * cth - yt * sth, -xt * sth + yt * cth)) + for i in range(n): + xt, yt = resp[i] + result.append((xt * cth - yt * sth, xt * sth + yt * cth)) + return result, cost, x, y, th + +def cross_prod(a, b): + return [a[1] * b[2] - a[2] * b[1], + a[2] * b[0] - a[0] * b[2], + a[0] * b[1] - a[1] * b[0]] + +def solve_mec(constraint_fnl): + delta = 1e-3 + params = [pi, 0, 0] + for i in range(20): + k, lam1, lam2 = params + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + #print i * .05, 'setgray' + #plot(xys) + c1c, c2c, costc = constraint_fnl(cost, x, y, th) + print '% constraint_fnl =', c1c, c2c, 'cost =', costc + + dc1s = [] + dc2s = [] + for j in range(len(params)): + params1 = N.array(params) + params1[j] += delta + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1p, c2p, costp = constraint_fnl(cost, x, y, th) + params1 = N.array(params) + params1[j] -= delta + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1m, c2m, costm = constraint_fnl(cost, x, y, th) + dc1s.append((c1p - c1m) / (2 * delta)) + dc2s.append((c2p - c2m) / (2 * delta)) + xp = cross_prod(dc1s, dc2s) + xp = N.divide(xp, sqrt(N.dot(xp, xp))) # Normalize to unit length + + print '% dc1s =', dc1s + print '% dc2s =', dc2s + print '% xp =', xp + + # Compute second derivative wrt orthogonal vec + params1 = N.array(params) + for j in range(len(params)): + params1[j] += delta * xp[j] + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1p, c2p, costp = constraint_fnl(cost, x, y, th) + print '% constraint_fnl+ =', c1p, c2p, 'cost =', costp + params1 = N.array(params) + for j in range(len(params)): + params1[j] -= delta * xp[j] + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1m, c2m, costm = constraint_fnl(cost, x, y, th) + print '% constraint_fnl- =', c1m, c2m, 'cost =', costm + d2cost = (costp + costm - 2 * costc) / (delta * delta) + dcost = (costp - costm) / (2 * delta) + + print '% dcost =', dcost, 'd2cost =', d2cost + if d2cost < 0: d2cost = .1 + # Make Jacobian matrix to invert + jm = N.array([dc1s, dc2s, [x * d2cost for x in xp]]) + #print jm + ji = la.inverse(jm) + #print ji + + dp = N.dot(ji, [c1c, c2c, dcost]) + print '% dp =', dp + print '% [right]=', [c1c, c2c, dcost] + params -= dp * .1 + print '%', params + sys.stdout.flush() + return params + +def solve_mec_3constr(constraint_fnl, n = 30, initparams = None): + delta = 1e-3 + if initparams: + params = N.array(initparams) + else: + params = [3.14, 0, 0] + for i in range(n): + k, lam1, lam2 = params + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1c, c2c, c3c = constraint_fnl(cost, x, y, th) + print '% constraint_fnl =', c1c, c2c, c3c + + dc1s = [] + dc2s = [] + dc3s = [] + for j in range(len(params)): + params1 = N.array(params) + params1[j] += delta + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1p, c2p, c3p = constraint_fnl(cost, x, y, th) + params1 = N.array(params) + params1[j] -= delta + k, lam1, lam2 = params1 + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + c1m, c2m, c3m = constraint_fnl(cost, x, y, th) + dc1s.append((c1p - c1m) / (2 * delta)) + dc2s.append((c2p - c2m) / (2 * delta)) + dc3s.append((c3p - c3m) / (2 * delta)) + + # Make Jacobian matrix to invert + jm = N.array([dc1s, dc2s, dc3s]) + #print jm + ji = la.inverse(jm) + + dp = N.dot(ji, [c1c, c2c, c3c]) + if i < n/2: scale = .25 + else: scale = 1 + params -= scale * dp + print '%', params + return params + +def mk_ths_fnl(th0, th1): + def fnl(cost, x, y, th): + actual_th0 = atan2(y, x) + actual_th1 = th - actual_th0 + print '% x =', x, 'y =', y, 'hypot =', hypot(x, y) + return th0 - actual_th0, th1 - actual_th1, cost + return fnl + +def mk_y_fnl(th0, th1, ytarg): + def fnl(cost, x, y, th): + actual_th0 = atan2(y, x) + actual_th1 = th - actual_th0 + return th0 - actual_th0, th1 - actual_th1, ytarg - hypot(x, y) + return fnl + +def solve_mec_nested_inner(th0, th1, y, fnl): + innerfnl = mk_y_fnl(th0, th1, y) + params = [th0 + th1, 1e-6, 1e-6] + params = solve_mec_3constr(innerfnl, 10, params) + k, lam1, lam2 = params + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100) + c1, c2, c3 = fnl(cost, x, y, th) + return c3, params + +# Solve (th0, th1) mec to minimize fnl; use solve_mec_3constr as inner loop +# Use golden section search +def solve_mec_nested(th0, th1, fnl): + R = .61803399 + C = 1 - R + ax, cx = .6, .85 + bx = .5 * (ax + cx) + + x0, x3 = ax, cx + if abs(cx - bx) > abs(bx - ax): + x1, x2 = bx, bx + C * (cx - bx) + else: + x1, x2 = bx - C * (bx - ax), bx + f1, p = solve_mec_nested_inner(th0, th1, x1, fnl) + f2, p = solve_mec_nested_inner(th0, th1, x2, fnl) + for i in range(10): + print '%', x0, x1, x2, x3, ':', f1, f2 + if f2 < f1: + x0, x1, x2 = x1, x2, R * x2 + C * x3 + f1 = f2 + f2, p = solve_mec_nested_inner(th0, th1, x2, fnl) + else: + x1, x2, x3 = R * x1 + C * x0, x1, x2 + f2 = f1 + f1, p = solve_mec_nested_inner(th0, th1, x1, fnl) + if f1 < f2: + x = x1 + else: + x = x2 + cc, p = solve_mec_nested_inner(th0, th1, x, fnl) + return p + +def plot(xys): + cmd = 'moveto' + for xy in xys: + print 306 + 200 * xy[0], 396 - 200 * xy[1], cmd + cmd = 'lineto' + print 'stroke' + +def mec_test(): + th0, th1 = 0, pi / 4 + fnl = mk_ths_fnl(th0, th1) + params = solve_mec_nested(th0, th1, fnl) + k, lam1, lam2 = params + xys, cost, x, y, th = run_mec_cos(k, lam1, lam2, 1000) + plot(xys) + print '% run_mec_cos:', cost, x, y, th + print '1 0 0 setrgbcolor' + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2) + print '%', xys + plot(xys) + print '% run_elastica:', cost, x, y, th + print 'showpage' + print '%', params + +def lenfig(): + print '306 720 translate' + th0, th1 = pi / 2, pi / 2 + for i in range(1, 10): + y = .1 * i + .003 + fnl = mk_y_fnl(th0, th1, y) + params = solve_mec_3constr(fnl) + k, lam1, lam2 = params + print 'gsave 0.5 dup scale -306 -396 translate' + xys, cost, x, y, th = run_elastica(-2, 2, k, lam1, lam2, 100) + print 'gsave [2] 0 setdash' + plot(xys) + print 'grestore' + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100) + plot(xys) + print 'grestore' + print '% y =', y, 'params =', params + if lam2 < 0: + mymaxk = k + else: + mymaxk = sqrt(k * k + 4 * lam2) + lam = abs(lam2) / (mymaxk * mymaxk) + print '-200 0 moveto /Symbol 12 selectfont (l) show' + print '/Times-Roman 12 selectfont ( = %.4g) show' % lam + print '0 -70 translate' + print 'showpage' + +def lenplot(figno, th0, th1): + result = [] + if figno in (1, 2): + imax = 181 + elif figno == 3: + imax = 191 + for i in range(1, imax): + yy = .005 * i + if figno in (1, 2) and i == 127: + yy = 2 / pi + if figno == 3 and i == 165: + yy = .8270 + fnl = mk_y_fnl(th0, th1, yy) + params = solve_mec_3constr(fnl) + k, lam1, lam2 = params + xys, cost, x0, y0, th = run_elastica(-.5, .5, k, lam1, lam2, 100) + if lam2 < 0: + mymaxk = k + else: + mymaxk = sqrt(k * k + 4 * lam2) + lam = abs(lam2) / (mymaxk * mymaxk) + result.append((yy, lam, cost)) + return result + +def lengraph(figno): + if figno in (1, 2): + eps_prologue(15, 47, 585, 543) + th0, th1 = pi / 2, pi / 2 + yscale = 900 + ytic = .05 + ymax = 10 + elif figno == 3: + eps_prologue(15, 47, 585, 592) + th0, th1 = pi / 3, pi / 3 + yscale = 500 + ytic = .1 + ymax = 10 + x0 = 42 + xscale = 7.5 * 72 + y0 = 72 + print '/Times-Roman 12 selectfont' + print '/ss 1.5 def' + print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def' + print '.5 setlinewidth' + print x0, y0, 'moveto', xscale, '0 rlineto 0', yscale * ytic * ymax, 'rlineto', -xscale, '0 rlineto closepath stroke' + for i in range(0, 11): + print x0 + .1 * i * xscale, y0, 'moveto 0 6 rlineto stroke' + print x0 + .1 * i * xscale, y0 + ytic * ymax * yscale, 'moveto 0 -6 rlineto stroke' + print x0 + .1 * i * xscale, y0 - 12, 'moveto' + print '(%.1g) dup stringwidth exch -.5 mul exch rmoveto show' % (.1 * i) + for i in range(0, 11): + print x0, y0 + ytic * i * yscale, 'moveto 6 0 rlineto stroke' + print x0 + xscale, y0 + ytic * i * yscale, 'moveto -6 0 rlineto stroke' + print x0 - 3, y0 + ytic * i * yscale - 3.5, 'moveto' + print '(%.2g) dup stringwidth exch neg exch rmoveto show' % (ytic * i) + print x0 + .25 * xscale, y0 - 24, 'moveto (chordlen / arclen) show' + print x0 - 14, y0 + ytic * ymax * yscale + 10, 'moveto /Symbol 12 selectfont (l) show' + if figno in (1, 2): + print x0 + 2 / pi * xscale, y0 - 18, 'moveto' + print '(2/p) dup stringwidth exch -.5 mul exch rmoveto show' + print 'gsave [3] 0 setdash' + print x0, y0 + .25 * yscale, 'moveto', xscale, '0 rlineto stroke' + if figno == 3: + print x0, y0 + .5 * yscale, 'moveto', xscale, '0 rlineto stroke' + xinterest = .81153 + print x0 + xinterest * xscale, y0, 'moveto 0', yscale * .5, 'rlineto stroke' + print 'grestore' + print '.75 setlinewidth' + if 1: + if figno in (1, 2): + costscale = .01 * yscale + elif figno == 3: + costscale = .0187 * yscale + lenresult = lenplot(figno, th0, th1) + cmd = 'moveto' + for x, y, cost in lenresult: + print x0 + xscale * x, y0 + yscale * y, cmd + cmd = 'lineto' + print 'stroke' + if figno in (2, 3): + cmd = 'moveto' + for x, y, cost in lenresult: + print x0 + xscale * x, y0 + costscale * cost, cmd + cmd = 'lineto' + print 'stroke' + cmd = 'moveto' + for x, y, cost in lenresult: + print x0 + xscale * x, y0 + costscale * x * cost, cmd + cmd = 'lineto' + print 'stroke' + print '/Times-Roman 12 selectfont' + if figno == 2: + xlm, ylm = .75, 7 + xls, yls = .42, 15 + elif figno == 3: + xlm, ylm = .6, 3 + xls, yls = .37, 15 + print x0 + xscale * xlm, y0 + costscale * ylm, 'moveto' + print '(MEC cost) show' + print x0 + xscale * xls, y0 + costscale * yls, 'moveto' + print '(SIMEC cost) show' + if figno == 1: + minis = [(.05, 5, -5), + (.26, -40, 10), + (.4569466, -5, -10), + (.55, 35, 12), + + (.6026, -60, 45), + (.6046, -60, 15), + (.6066, -60, -15), + + (.6213, -22, 10), + (.6366198, 15, 22), + (.66, 20, 10), + (.9, 0, -10)] + elif figno == 2: + minis = [(.4569466, -5, -10), + (.6366198, 15, 22)] + elif figno == 3: + minis = [(.741, 55, -10), + (.81153, -30, 20), + (.8270, 20, 30)] + + for yy, xo, yo in minis: + fnl = mk_y_fnl(th0, th1, yy) + params = solve_mec_3constr(fnl) + k, lam1, lam2 = params + if lam2 < 0: + mymaxk = k + else: + mymaxk = sqrt(k * k + 4 * lam2) + lam = abs(lam2) / (mymaxk * mymaxk) + x = x0 + xscale * yy + y = y0 + yscale * lam + print 'gsave %g %g translate circle fill' % (x, y) + print '%g %g translate 0.15 dup scale' % (xo, yo) + print '-306 -396 translate' + print '2 setlinewidth' + if yy < .6 or yy > .61: + s = 2 + elif yy == .6046: + s = 2.8 + else: + s = 5 + xys, cost, x, y, th = run_elastica(-s, s, k, lam1, lam2, 100) + print 'gsave [10] 0 setdash' + plot(xys) + print 'grestore 6 setlinewidth' + xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100) + plot(xys) + print 'grestore' + + print 'showpage' + eps_trailer() + +def draw_axes(x0, y0, xscale, yscale, xmax, ymax, nx, ny): + print '.5 setlinewidth' + print '/Times-Roman 12 selectfont' + print x0, y0, 'moveto', xscale * xmax, '0 rlineto 0', yscale * ymax, 'rlineto', -xscale * xmax, '0 rlineto closepath stroke' + xinc = (xmax * xscale * 1.) / nx + yinc = (ymax * yscale * 1.) / ny + for i in range(0, nx + 1): + if i > 0 and i < nx + 1: + print x0 + xinc * i, y0, 'moveto 0 6 rlineto stroke' + print x0 + xinc * i, y0 + ymax * yscale, 'moveto 0 -6 rlineto stroke' + print x0 + xinc * i, y0 - 12, 'moveto' + print '(%.2g) dup stringwidth exch -.5 mul exch rmoveto show' % ((i * xmax * 1.) / nx) + for i in range(0, ny + 1): + if i > 0 and i < ny + 1: + print x0, y0 + yinc * i, 'moveto 6 0 rlineto stroke' + print x0 + xmax * xscale, y0 + yinc * i, 'moveto -6 0 rlineto stroke' + print x0 - 3, y0 + yinc * i - 3.5, 'moveto' + print '(%.2g) dup stringwidth exch neg exch rmoveto show' % ((i * ymax * 1.) / ny) + + +def mecchord(): + x0 = 72 + y0 = 72 + thscale = 150 + chscale = 400 + print '.5 setlinewidth' + print '/ss 1.5 def' + print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def' + draw_axes(x0, y0, thscale, chscale, 3.2, 1, 16, 10) + print x0 + 1 * thscale, y0 - 28, 'moveto (angle) show' + print 'gsave', x0 - 32, y0 + .25 * chscale, 'translate' + print '90 rotate 0 0 moveto (chordlen / arclen) show' + print 'grestore' + + cmd = 'moveto' + for i in range(0, 67): + s = i * .01 + xys, cost, x, y, th = run_elastica(-s, s, 4, 0, -8, 100) + #plot(xys) + if s > 0: + ch = hypot(x, y) / (2 * s) + else: + ch = 1 + print '%', s, x, y, th, ch + print x0 + thscale * th / 2, y0 + ch * chscale, cmd + cmd = 'lineto' + print 'stroke' + + print 'gsave %g %g translate circle fill' % (x0 + thscale * th / 2, y0 + ch * chscale) + print '-30 15 translate 0.25 dup scale' + print '-306 -396 translate' + print '2 setlinewidth' + plot(xys) + print 'grestore' + + print 'gsave [2] 0 setdash' + cmd = 'moveto' + for i in range(0, 151): + th = pi * i / 150. + if th > 0: + ch = sin(th) / th + else: + ch = 1 + print x0 + thscale * th, y0 + ch * chscale, cmd + cmd = 'lineto' + print 'stroke' + print 'grestore' + + k0 = 4 * .4536 / (2 / pi) + s = pi / (2 * k0) + xys, cost, x, y, th = run_elastica(-s, s, k0, 0, 0, 100) + th = pi + ch = 2 / pi + print 'gsave %g %g translate circle fill' % (x0 + thscale * th / 2, y0 + ch * chscale) + print '30 15 translate 0.25 dup scale' + print '-306 -396 translate' + print '2 setlinewidth' + plot(xys) + print 'grestore' + + print x0 + 1.25 * thscale, y0 + .55 * chscale, 'moveto (MEC) show' + print x0 + 2.3 * thscale, y0 + .35 * chscale, 'moveto (SIMEC) show' + + print 'showpage' + +def trymec(sm, sp): + xys, thm, cost = run_elastica_half(abs(sm), 0, 1, 0, 10) + xm, ym, km = xys[-1] + if sm < 0: + xm = -xm + ym = -ym + thm = -thm + xys, thp, cost = run_elastica_half(abs(sp), 0, 1, 0, 10) + xp, yp, kp = xys[-1] + if sp < 0: + xp = -xp + yp = -yp + thp = -thp + chth = atan2(yp - ym, xp - xm) + #print xm, ym, xp, yp, chth, thm, thp + actual_th0 = chth - thm + actual_th1 = thp - chth + return actual_th0, actual_th1 + +def findmec_old(th0, th1): + guess_ds = sqrt(6 * (th1 - th0)) + guess_savg = 2 * (th1 + th0) / guess_ds + sm = .5 * (guess_savg - guess_ds) + sp = .5 * (guess_savg + guess_ds) + #sm, sp = th0, th1 + for i in range(1): + actual_th0, actual_th1 = trymec(sm, sp) + guess_dth = 1./6 * (sp - sm) ** 2 + guess_avth = .5 * (sp + sm) * (sp - sm) + guess_th0 = .5 * (guess_avth - guess_dth) + guess_th1 = .5 * (guess_avth + guess_dth) + print sm, sp, actual_th0, actual_th1, guess_th0, guess_th1 + +def mecplots(): + print '2 dup scale' + print '-153 -296 translate' + scale = 45 + print '0.25 setlinewidth' + print 306 - scale * pi/2, 396, 'moveto', 306 + scale * pi/2, 396, 'lineto stroke' + print 306, 396 - scale * pi/2, 'moveto', 306, 396 + scale * pi/2, 'lineto stroke' + print '/ss .5 def' + print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def' + + tic = .1 + maj = 5 + r0, r1 = 0, 81 + + for i in range(r0, r1, maj): + sm = i * tic + cmd = 'moveto' + for j in range(i, r1): + sp = j * tic + 1e-3 + th0, th1 = trymec(sm, sp) + print '%', sm, sp, th0, th1 + print 306 + scale * th0, 396 + scale * th1, cmd + cmd = 'lineto' + print 'stroke' + for j in range(r0, r1, maj): + sp = j * tic + 1e-3 + cmd = 'moveto' + for i in range(0, j + 1): + sm = i * tic + th0, th1 = trymec(sm, sp) + print '%', sm, sp, th0, th1 + print 306 + scale * th0, 396 + scale * th1, cmd + cmd = 'lineto' + print 'stroke' + + for i in range(r0, r1, maj): + sm = i * tic + for j in range(i, r1, maj): + sp = j * tic + 1e-3 + th0, th1 = trymec(sm, sp) + print 'gsave' + print 306 + scale * th0, 596 + scale * th1, 'translate' + print 'circle fill' + uscale = 3 + xys, thm, cost = run_elastica_half(abs(sm), 0, 1, 0, 100) + x0, y0 = xys[-1][0], xys[-1][1] + if sm < 0: + x0, y0 = -x0, -y0 + xys, thm, cost = run_elastica_half(abs(sp), 0, 1, 0, 100) + x1, y1 = xys[-1][0], xys[-1][1] + if sp < 0: + x1, y1 = -x1, -y1 + cmd = 'moveto' + for xy in xys: + print xy[0] * uscale, xy[1] * uscale, cmd + cmd = 'lineto' + print 'stroke' + print '1 0 0 setrgbcolor' + print x0 * uscale, y0 * uscale, 'moveto' + print x1 * uscale, y1 * uscale, 'lineto stroke' + print 'grestore' + + print 'showpage' + +def findmec(th0, th1): + delta = 1e-3 + if th0 < 0 and th0 - th1 < .1: + sm = 5. + sp = 6. + else: + sm = 3. + sp = 5. + params = [sm, sp] + lasterr = 1e6 + for i in range(25): + sm, sp = params + ath0, ath1 = trymec(sm, sp) + c1c, c2c = th0 - ath0, th1 - ath1 + + err = c1c * c1c + c2c * c2c + if 0: + print '%findmec', sm, sp, ath0, ath1, err + sys.stdout.flush() + + if err < 1e-9: + return params + if err > lasterr: + return None + lasterr = err + + + dc1s = [] + dc2s = [] + for j in range(len(params)): + params1 = N.array(params) + params1[j] += delta + sm, sp = params1 + ath0, ath1 = trymec(sm, sp) + c1p, c2p = th0 - ath0, th1 - ath1 + + params1 = N.array(params) + params1[j] -= delta + sm, sp = params1 + ath0, ath1 = trymec(sm, sp) + c1m, c2m = th0 - ath0, th1 - ath1 + + dc1s.append((c1p - c1m) / (2 * delta)) + dc2s.append((c2p - c2m) / (2 * delta)) + + jm = N.array([dc1s, dc2s]) + ji = la.inverse(jm) + dp = N.dot(ji, [c1c, c2c]) + + if i < 4: + scale = .5 + else: + scale = 1 + params -= scale * dp + if params[0] < 0: params[0] = 0. + return params + +def mecrange(figtype): + scale = 130 + eps_prologue(50, 110, 570, 630) + print -50, 0, 'translate' + print '0.5 setlinewidth' + thlmin, thlmax = -pi/2, 2.4 + thrmin, thrmax = -2.2, pi / 2 + .2 + print 306 + scale * thlmin, 396, 'moveto', 306 + scale * thlmax, 396, 'lineto stroke' + print 306, 396 + scale * thrmin, 'moveto', 306, 396 + scale * thrmax, 'lineto stroke' + + print 'gsave [2] 0 setdash' + print 306, 396 + scale * pi / 2, 'moveto' + print 306 + scale * thlmax, 396 + scale * pi / 2, 'lineto stroke' + print 306 + scale * thlmin, 396 - scale * pi / 2, 'moveto' + print 306 + scale * thlmax, 396 - scale * pi / 2, 'lineto stroke' + print 306 + scale * pi / 2, 396 + scale * thrmin, 'moveto' + print 306 + scale * pi / 2, 396 + scale * thrmax, 'lineto stroke' + print 'grestore' + + print 306 + 3, 396 + scale * thrmax - 10, 'moveto' + print '/Symbol 12 selectfont (q) show' + print 0, -2, 'rmoveto' + print '/Times-Italic 9 selectfont (right) show' + + print 306 - 18, 396 + scale * pi / 2 - 4, 'moveto' + print '/Symbol 12 selectfont (p/2) show' + print 306 + scale * 2.2, 396 - scale * pi / 2 + 2, 'moveto' + print '/Symbol 12 selectfont (-p/2) show' + + print 306 + scale * pi/2 + 2, 396 + scale * thrmax - 10, 'moveto' + print '/Symbol 12 selectfont (p/2) show' + + print 306 + scale * 2.2, 396 + 6, 'moveto' + print '/Symbol 12 selectfont (q) show' + print 0, -2, 'rmoveto' + print '/Times-Italic 9 selectfont (left) show' + + print '/ss 0.8 def' + print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def' + cmd = 'moveto' + for i in range(0, 201): + th = (i * .005 - .75 )* pi + rmin = 1.5 + rmax = 2.5 + for j in range(20): + r = (rmin + rmax) * .5 + th0 = r * cos(th) + th1 = r * sin(th) + if findmec(th0, th1) == None: + rmax = r + else: + rmin = r + r = (rmin + rmax) * .5 + th0 = r * cos(th) + th1 = r * sin(th) + print '%', r, th, th0, th1 + print 306 + scale * th0, 396 + scale * th1, cmd + cmd = 'lineto' + sys.stdout.flush() + print 'stroke' + sys.stdout.flush() + + for i in range(-11, 12): + for j in range(-11, i + 1): + th0, th1 = i * .196, j * .196 + print '%', th0, th1 + params = findmec(th0, th1) + if params != None: + sm, sp = params + print 'gsave' + print 306 + scale * th0, 396 + scale * th1, 'translate' + uscale = 22 + k0, lam1, lam2 = justify_mec(sm, sp) + xys, cost, x, y, th = run_elastica(-.5, .5, k0, lam1, lam2) + cmdm = 'moveto' + dx = xys[-1][0] - xys[0][0] + dy = xys[-1][1] - xys[0][1] + ch = hypot(dx, dy) + chth = atan2(dy, dx) + if figtype == 'mecrange': + print 'circle fill' + s = uscale * sin(chth) / ch + c = uscale * cos(chth) / ch + h = -xys[0][0] * s + xys[0][1] * c + for xy in xys: + print xy[0] * c + xy[1] * s, h + xy[0] * s - xy[1] * c, cmdm + cmdm = 'lineto' + elif figtype == 'mecrangek': + ds = 1. / (len(xys) - 1) + sscale = 13. / ch + kscale = 3 * ch + print 'gsave .25 setlinewidth' + print sscale * -.5, 0, 'moveto', sscale, 0, 'rlineto stroke' + print 'grestore' + for l in range(len(xys)): + print sscale * (ds * l - 0.5), kscale * xys[l][2], cmdm + cmdm = 'lineto' + print 'stroke' + print 'grestore' + sys.stdout.flush() + print 'showpage' + eps_trailer() + +# given sm, sp in [0, 1, 0] mec, return params for -0.5..0.5 segment +def justify_mec(sm, sp): + sc = (sm + sp) * 0.5 + xys, thc, cost = run_elastica_half(sc, 0, 1, 0, 100) + print '% sc =', sc, 'thc =', thc + k0, lam1, lam2 = xys[-1][2], cos(thc), -sin(thc) + ds = sp - sm + k0 *= ds + lam1 *= ds * ds + lam2 *= ds * ds + return [k0, lam1, lam2] + +import sys +figname = sys.argv[1] +if len(figname) > 4 and figname[-4:] == '.pdf': figname = figname[:-4] +if figname in ('lengraph1', 'lengraph2', 'lengraph3'): + lengraph(int(figname[-1])) + #mec_test() + #lenfig() +elif figname == 'mecchord': + mecchord() +elif figname in ('mecrange', 'mecrangek'): + mecrange(figname) +elif figname == 'mecplots': + mecplots() +elif figname == 'findmec': + findmec(-.1, -.1) + findmec(-.2, -.2) + |