summaryrefslogtreecommitdiff
path: root/third_party/spiro/curves/fromcubic.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/spiro/curves/fromcubic.py')
-rw-r--r--third_party/spiro/curves/fromcubic.py208
1 files changed, 208 insertions, 0 deletions
diff --git a/third_party/spiro/curves/fromcubic.py b/third_party/spiro/curves/fromcubic.py
new file mode 100644
index 0000000..210f9d4
--- /dev/null
+++ b/third_party/spiro/curves/fromcubic.py
@@ -0,0 +1,208 @@
+# Convert piecewise cubic into piecewise clothoid representation.
+
+from math import *
+
+import clothoid
+import pcorn
+import tocubic
+
+import offset
+
+def read_bz(f):
+ result = []
+ for l in f.xreadlines():
+ s = l.split()
+ if len(s) > 0:
+ cmd = s[-1]
+ #print s[:-1], cmd
+ if cmd == 'm':
+ sp = []
+ result.append(sp)
+ curpt = [float(x) for x in s[0:2]]
+ startpt = curpt
+ elif cmd == 'l':
+ newpt = [float(x) for x in s[0:2]]
+ sp.append((curpt, newpt))
+ curpt = newpt
+ elif cmd == 'c':
+ c1 = [float(x) for x in s[0:2]]
+ c2 = [float(x) for x in s[2:4]]
+ newpt = [float(x) for x in s[4:6]]
+ sp.append((curpt, c1, c2, newpt))
+ curpt = newpt
+ return result
+
+def plot_bzs(bzs, z0, scale, fancy = False):
+ for sp in bzs:
+ for i in range(len(sp)):
+ bz = sp[i]
+ tocubic.plot_bz(bz, z0, scale, i == 0)
+ print 'stroke'
+ if fancy:
+ for i in range(len(sp)):
+ bz = sp[i]
+
+ x0, y0 = z0[0] + scale * bz[0][0], z0[1] + scale * bz[0][1]
+ print 'gsave', x0, y0, 'translate circle fill grestore'
+ if len(bz) == 4:
+ x1, y1 = z0[0] + scale * bz[1][0], z0[1] + scale * bz[1][1]
+ x2, y2 = z0[0] + scale * bz[2][0], z0[1] + scale * bz[2][1]
+ x3, y3 = z0[0] + scale * bz[3][0], z0[1] + scale * bz[3][1]
+ print 'gsave 0.5 setlinewidth', x0, y0, 'moveto'
+ print x1, y1, 'lineto stroke'
+ print x2, y2, 'moveto'
+ print x3, y3, 'lineto stroke grestore'
+ print 'gsave', x1, y1, 'translate 0.75 dup scale circle fill grestore'
+ print 'gsave', x2, y2, 'translate 0.75 dup scale circle fill grestore'
+ print 'gsave', x3, y3, 'translate 0.75 dup scale circle fill grestore'
+
+
+
+def measure_bz_cloth(seg, bz, n = 100):
+ bz_arclen = tocubic.bz_arclength_rk4(bz)
+ arclen_ratio = seg.arclen / bz_arclen
+ dbz = tocubic.bz_deriv(bz)
+
+ def measure_derivs(x, ys):
+ dx, dy = tocubic.bz_eval(dbz, x)
+ ds = hypot(dx, dy)
+ s = ys[0] * arclen_ratio
+ dscore = ds * (tocubic.mod_2pi(atan2(dy, dx) - seg.th(s)) ** 2)
+ #print s, atan2(dy, dx), seg.th(s)
+ return [ds, dscore]
+ dt = 1./n
+ t = 0
+ ys = [0, 0]
+ for i in range(n):
+ dydx = measure_derivs(t, ys)
+ tocubic.rk4(ys, dydx, t, dt, measure_derivs)
+ t += dt
+ return ys[1]
+
+def cubic_bz_to_pcorn(bz, thresh):
+ dx = bz[3][0] - bz[0][0]
+ dy = bz[3][1] - bz[0][1]
+ dx1 = bz[1][0] - bz[0][0]
+ dy1 = bz[1][1] - bz[0][1]
+ dx2 = bz[3][0] - bz[2][0]
+ dy2 = bz[3][1] - bz[2][1]
+ chth = atan2(dy, dx)
+ th0 = tocubic.mod_2pi(chth - atan2(dy1, dx1))
+ th1 = tocubic.mod_2pi(atan2(dy2, dx2) - chth)
+ seg = pcorn.Segment(bz[0], bz[3], th0, th1)
+ err = measure_bz_cloth(seg, bz)
+ if err < thresh:
+ return [seg]
+ else:
+ # de Casteljau
+ x01, y01 = 0.5 * (bz[0][0] + bz[1][0]), 0.5 * (bz[0][1] + bz[1][1])
+ x12, y12 = 0.5 * (bz[1][0] + bz[2][0]), 0.5 * (bz[1][1] + bz[2][1])
+ x23, y23 = 0.5 * (bz[2][0] + bz[3][0]), 0.5 * (bz[2][1] + bz[3][1])
+ xl2, yl2 = 0.5 * (x01 + x12), 0.5 * (y01 + y12)
+ xr1, yr1 = 0.5 * (x12 + x23), 0.5 * (y12 + y23)
+ xm, ym = 0.5 * (xl2 + xr1), 0.5 * (yl2 + yr1)
+ bzl = [bz[0], (x01, y01), (xl2, yl2), (xm, ym)]
+ bzr = [(xm, ym), (xr1, yr1), (x23, y23), bz[3]]
+ segs = cubic_bz_to_pcorn(bzl, 0.5 * thresh)
+ segs.extend(cubic_bz_to_pcorn(bzr, 0.5 * thresh))
+ return segs
+
+def bzs_to_pcorn(bzs, thresh = 1e-9):
+ result = []
+ for sp in bzs:
+ rsp = []
+ for bz in sp:
+ if len(bz) == 2:
+ dx = bz[1][0] - bz[0][0]
+ dy = bz[1][1] - bz[0][1]
+ th = atan2(dy, dx)
+ rsp.append(pcorn.Segment(bz[0], bz[1], 0, 0))
+ else:
+ rsp.extend(cubic_bz_to_pcorn(bz, thresh))
+ result.append(rsp)
+ return result
+
+def plot_segs(segs):
+ for i in range(len(segs)):
+ seg = segs[i]
+ if i == 0:
+ print seg.z0[0], seg.z0[1], 'moveto'
+ print seg.z1[0], seg.z1[1], 'lineto'
+ print 'stroke'
+ for i in range(len(segs)):
+ seg = segs[i]
+ if i == 0:
+ print 'gsave', seg.z0[0], seg.z0[1], 'translate circle fill grestore'
+ print 'gsave', seg.z1[0], seg.z1[1], 'translate circle fill grestore'
+
+import sys
+
+def test_to_pcorn():
+ C1 = 0.55228
+ bz = [(100, 100), (100 + 400 * C1, 100), (500, 500 - 400 * C1), (500, 500)]
+ for i in range(0, 13):
+ thresh = .1 ** i
+ segs = cubic_bz_to_pcorn(bz, thresh)
+ plot_segs(segs)
+ print >> sys.stderr, thresh, len(segs)
+ print '0 20 translate'
+
+if __name__ == '__main__':
+ f = file(sys.argv[1])
+ bzs = read_bz(f)
+ rsps = bzs_to_pcorn(bzs, 1)
+ #print rsps
+ tocubic.plot_prolog()
+ print 'grestore'
+ print '1 -1 scale 0 -720 translate'
+ print '/ss 1.5 def'
+ print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'
+ tot = 0
+ for segs in rsps:
+ curve = pcorn.Curve(segs)
+ #curve = offset.offset(curve, 10)
+ print '%', curve.arclen
+ print '%', curve.sstarts
+ if 0:
+ print 'gsave 1 0 0 setrgbcolor'
+ cmd = 'moveto'
+ for i in range(100):
+ s = i * .01 * curve.arclen
+ x, y = curve.xy(s)
+ th = curve.th(s)
+ sth = 5 * sin(th)
+ cth = 5 * cos(th)
+ print x, y, cmd
+ cmd = 'lineto'
+ print 'closepath stroke grestore'
+ for i in range(100):
+ s = i * .01 * curve.arclen
+ x, y = curve.xy(s)
+ th = curve.th(s)
+ sth = 5 * sin(th)
+ cth = 5 * cos(th)
+ if 0:
+ print x - cth, y - sth, 'moveto'
+ print x + cth, y + sth, 'lineto stroke'
+ if 1:
+ for s in curve.find_breaks():
+ print 'gsave 0 1 0 setrgbcolor'
+ x, y = curve.xy(s)
+ print x, y, 'translate 2 dup scale circle fill'
+ print 'grestore'
+ #plot_segs(segs)
+
+ print 'gsave 0 0 0 setrgbcolor'
+ optim = 3
+ thresh = 1e-2
+ new_bzs = tocubic.pcorn_curve_to_bzs(curve, optim, thresh)
+ tot += len(new_bzs)
+ plot_bzs([new_bzs], (0, 0), 1, True)
+ print 'grestore'
+ print 'grestore'
+ print '/Helvetica 12 selectfont'
+ print '36 720 moveto (thresh=%g optim=%d) show' % (thresh, optim)
+ print '( tot segs=%d) show' % tot
+ print 'showpage'
+
+ #plot_bzs(bzs, (100, 100), 1)