summaryrefslogtreecommitdiffstats
path: root/src/toys/pw-toy.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
commit61f3ab8f23f4c924d455757bf3e65f8487521b5a (patch)
tree885599a36a308f422af98616bc733a0494fe149a /src/toys/pw-toy.py
parentInitial commit. (diff)
downloadlib2geom-61f3ab8f23f4c924d455757bf3e65f8487521b5a.tar.xz
lib2geom-61f3ab8f23f4c924d455757bf3e65f8487521b5a.zip
Adding upstream version 1.3.upstream/1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/toys/pw-toy.py')
-rw-r--r--src/toys/pw-toy.py180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/toys/pw-toy.py b/src/toys/pw-toy.py
new file mode 100644
index 0000000..011c917
--- /dev/null
+++ b/src/toys/pw-toy.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+
+import py2geom
+import toyframework
+import random,gtk
+from py2geom_glue import *
+
+def cairo_pw(cr, p):
+ for i in range(p.size()):
+ a,b = p.cuts[i], p.cuts[i+1]
+ bez = sbasis_to_bezier(p[i], 0)
+ cr.move_to(a, bez[0])
+ cr.curve_to(lerp(a, b, 1./3), bez[1],
+ lerp(a,b, 2./3), bez[2],
+ b, bez[3])
+
+def cairo_horiz(cr, y, ps):
+ for p in ps:
+ cr.move_to(p, y);
+ cr.rel_line_to(0, 10)
+
+def cairo_vert(cr, x, ps):
+ for p in ps:
+ cr.move_to(x, p)
+ cr.rel_line_to(10, 0)
+
+def l2s(l):
+ sb = py2geom.SBasis(l)
+ return sb
+
+def constant(l):
+ pws = py2geom.PiecewiseSBasis()
+
+ pws.push_cut(0)
+ pws.push_seg(l2s(py2geom.Linear(l,l)) )
+ pws.push_cut(1000)
+ return pws
+
+X = l2s(py2geom.Linear(0, 1))
+OmX = l2s(py2geom.Linear(1, 0))
+def bezier_to_sbasis(handles, order):
+ if(order == 0):
+ return l2s(py2geom.Linear(handles[0]))
+ elif(order == 1):
+ return l2s(py2geom.Linear(handles[0], handles[1]))
+ else:
+ return (py2geom.multiply(OmX, bezier_to_sbasis(handles[:-1], order-1)) +
+ py2geom.multiply(X, bezier_to_sbasis(handles[1:], order-1)))
+
+
+def bez_to_sbasis(handles, order):
+ return bezier_to_sbasis([h[1] for h in handles], order)
+
+class PWSBHandle(toyframework.Handle):
+ def __init__(self, cs, segs):
+ self.handles_per_curve = cs*segs
+ self.curve_size = cs
+ self.segs = segs
+ self.pts = []
+ def append(self, x, y):
+ self.pts.append(py2geom.Point(x,y))
+ def value(self, y_0=0):
+ pws = py2geom.PiecewiseSBasis()
+ for i in range(0, self.handles_per_curve, self.curve_size):
+ pws.push_cut(self.pts[i][0]);
+ for j in range(i, i + self.curve_size):
+ self.pts[j] = py2geom.Point(self.pts[j][0], self.pts[j][1] - y_0)
+ hnd = self.pts[i:i+self.curve_size]
+ pws.push_seg( bez_to_sbasis(hnd, self.curve_size-1));
+ for j in range(i, i + self.curve_size):
+ self.pts[j] = py2geom.Point(self.pts[j][0], self.pts[j][1] + y_0);
+
+ pws.push_cut(self.pts[self.handles_per_curve - 1][0]);
+ assert(pws.invariants());
+ return pws
+
+ def draw(self, cr, annotes):
+ for p in self.pts:
+ toyframework.draw_circ(cr, p)
+
+ def hit(self, mouse):
+ for i,p in enumerate(self.pts):
+ if(py2geom.distance(py2geom.Point(*mouse), p) < 5):
+ return i
+ return None
+
+ def move_to(self, hit, om, m):
+ om = py2geom.Point(*om)
+ m = py2geom.Point(*m)
+ if hit != None:
+ i,hand = hit
+ self.pts[hand] = m
+ for i in range(self.curve_size, self.handles_per_curve, self.curve_size):
+ self.pts[i-1] = py2geom.Point(self.pts[i][0],self.pts[i-1][1])
+
+ for i in range(0, self.handles_per_curve, self.curve_size):
+ for j in range(1, (self.curve_size-1)):
+ t = float(j)/(self.curve_size-1)
+ x = lerp(self.pts[i][0], self.pts[i+self.curve_size-1][0],t)
+ self.pts[i+j] = py2geom.Point(x, self.pts[i+j][1])
+
+
+
+class PwToy(toyframework.Toy):
+ def __init__(self):
+ toyframework.Toy.__init__(self)
+ self.segs = 2
+ self.handles_per_curve = 4 * self.segs
+ self.curves = 2
+ self.pwsbh = []
+ self.interval_test = []
+ for a in range(self.curves):
+ self.pwsbh.append(PWSBHandle(4, self.curves))
+ self.handles.append(self.pwsbh[a])
+ for i in range(self.handles_per_curve):
+ t = 150 + 300*i/(4*self.segs)
+ self.pwsbh[a].append(t, random.uniform(0,1) * 150 + 150 - 50 * a)
+ self.interval_test.append(toyframework.PointHandle(150, 400))
+ self.interval_test.append(toyframework.PointHandle(300, 400))
+ self.handles.append(self.interval_test[0])
+ self.handles.append(self.interval_test[1])
+ self.func = "pws[0] + pws[1]"
+ def gtk_ready(self):
+ import gtk
+ self.sb_entry = gtk.Entry()
+ self.sb_entry.connect("changed", self.sb_changed)
+ toyframework.get_vbox().add(self.sb_entry)
+ toyframework.get_vbox().show_all()
+ self.sb_entry.set_text(self.func)
+ def sb_changed(self, sb):
+ self.func = sb.get_text()
+ self.redraw()
+ def draw(self, cr, pos, save):
+ cr.set_source_rgba (0., 0., 0., 1)
+ cr.set_line_width (1)
+
+ pws = [self.pwsbh[i].value() for i in range(self.curves)]
+ for p in pws:
+ cairo_pw(cr, p)
+ cr.stroke()
+
+ d = locals().copy()
+ for i in dir(py2geom):
+ d[i] = py2geom.__dict__[i]
+ d['l2s'] = l2s
+ d['constant'] = constant
+ pw_out = eval(self.func, d)
+
+ bs = py2geom.bounds_local(pw_out, py2geom.OptInterval(
+ py2geom.Interval(self.interval_test[0].pos[0],
+ self.interval_test[1].pos[0])));
+ if not bs.isEmpty():
+ bs = bs.toInterval()
+ for ph in self.interval_test:
+ ph.pos= py2geom.Point(ph.pos[0], bs.middle())
+ cr.save()
+ cr.set_source_rgba (.0, 0.25, 0.5, 1.)
+ cr.rectangle(self.interval_test[0].pos[0], bs.min(),
+ self.interval_test[1].pos[0]-self.interval_test[0].pos[0], bs.extent())
+ cr.stroke()
+ bs = py2geom.bounds_exact(pw_out);
+ cr.set_source_rgba (0.25, 0.25, .5, 1.);
+ if not bs.isEmpty():
+ bs = bs.toInterval()
+ cairo_horiz(cr, bs.middle(), pw_out.cuts);
+ cr.stroke()
+ cr.restore()
+
+ cr.set_source_rgba (0., 0., .5, 1.);
+ cairo_pw(cr, pw_out)
+ cr.stroke()
+
+
+ self.notify = str(bs)
+ toyframework.Toy.draw(self, cr, pos, save)
+
+t = PwToy()
+import sys
+
+toyframework.init(sys.argv, t, 500, 500)