summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2970168)
raw | patch | inline | side by side (parent: 2970168)
author | acspike <acspike@users.sourceforge.net> | |
Mon, 8 May 2006 15:28:17 +0000 (15:28 +0000) | ||
committer | acspike <acspike@users.sourceforge.net> | |
Mon, 8 May 2006 15:28:17 +0000 (15:28 +0000) |
Python hates mixed whitespace
32 files changed:
index d9814e0660f7f7afa64fd97d3cba015a7147517f..e57c7566dae00809d91427365c9c92b3cdeef52a 100644 (file)
import inkex, cubicsuperpath, simplestyle, copy, math, re, bezmisc
def numsegs(csp):
- return sum([len(p)-1 for p in csp])
+ return sum([len(p)-1 for p in csp])
def tpoint((x1,y1), (x2,y2), t = 0.5):
- return [x1+t*(x2-x1),y1+t*(y2-y1)]
+ return [x1+t*(x2-x1),y1+t*(y2-y1)]
def cspbezsplit(sp1, sp2, t = 0.5):
- m1=tpoint(sp1[1],sp1[2],t)
- m2=tpoint(sp1[2],sp2[0],t)
- m3=tpoint(sp2[0],sp2[1],t)
- m4=tpoint(m1,m2,t)
- m5=tpoint(m2,m3,t)
- m=tpoint(m4,m5,t)
- return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
+ m1=tpoint(sp1[1],sp1[2],t)
+ m2=tpoint(sp1[2],sp2[0],t)
+ m3=tpoint(sp2[0],sp2[1],t)
+ m4=tpoint(m1,m2,t)
+ m5=tpoint(m2,m3,t)
+ m=tpoint(m4,m5,t)
+ return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- t = bezmisc.beziertatlength(bez, l, tolerance)
- return cspbezsplit(sp1, sp2, t)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ t = bezmisc.beziertatlength(bez, l, tolerance)
+ return cspbezsplit(sp1, sp2, t)
def cspseglength(sp1,sp2, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- return bezmisc.bezierlength(bez, tolerance)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ return bezmisc.bezierlength(bez, tolerance)
def csplength(csp):
- total = 0
- lengths = []
- for sp in csp:
- lengths.append([])
- for i in xrange(1,len(sp)):
- l = cspseglength(sp[i-1],sp[i])
- lengths[-1].append(l)
- total += l
- return lengths, total
+ total = 0
+ lengths = []
+ for sp in csp:
+ lengths.append([])
+ for i in xrange(1,len(sp)):
+ l = cspseglength(sp[i-1],sp[i])
+ lengths[-1].append(l)
+ total += l
+ return lengths, total
def numlengths(csplen):
- retval = 0
- for sp in csplen:
- for l in sp:
- if l > 0:
- retval += 1
- return retval
+ retval = 0
+ for sp in csplen:
+ for l in sp:
+ if l > 0:
+ retval += 1
+ return retval
class SplitIt(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-m", "--max",
- action="store", type="float",
- dest="max", default=0.0,
- help="maximum segment length")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = cubicsuperpath.parsePath(d.value)
-
- #lens, total = csplength(p)
- #avg = total/numlengths(lens)
- #inkex.debug("average segment length: %s" % avg)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-m", "--max",
+ action="store", type="float",
+ dest="max", default=0.0,
+ help="maximum segment length")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = cubicsuperpath.parsePath(d.value)
+
+ #lens, total = csplength(p)
+ #avg = total/numlengths(lens)
+ #inkex.debug("average segment length: %s" % avg)
- new = []
- for sub in p:
- new.append([sub[0][:]])
- i = 1
- while i <= len(sub)-1:
- length = cspseglength(new[-1][-1], sub[i])
- if length > self.options.max:
- splits = math.ceil(length/self.options.max)
- for s in xrange(int(splits),1,-1):
- new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s)
- new[-1].append(next[:])
- new[-1].append(sub[i])
- i+=1
-
- d.value = cubicsuperpath.formatPath(new)
+ new = []
+ for sub in p:
+ new.append([sub[0][:]])
+ i = 1
+ while i <= len(sub)-1:
+ length = cspseglength(new[-1][-1], sub[i])
+ if length > self.options.max:
+ splits = math.ceil(length/self.options.max)
+ for s in xrange(int(splits),1,-1):
+ new[-1][-1], next, sub[i] = cspbezsplitatlength(new[-1][-1], sub[i], 1.0/s)
+ new[-1].append(next[:])
+ new[-1].append(sub[i])
+ i+=1
+
+ d.value = cubicsuperpath.formatPath(new)
e = SplitIt()
e.affect()
index 7efafa3ea9a23c8a544b5dad6151a664b9abced3..e8cc8c2e9a2ed8ed3034bf6995fc980ffa61b137 100755 (executable)
def rootWrapper(a,b,c,d):
if a:
- #TODO: find a new cubic solver and put it here
- #return solveCubicMonic(b/a,c/a,d/a)
+ #TODO: find a new cubic solver and put it here
+ #return solveCubicMonic(b/a,c/a,d/a)
return ()
elif b:
det=c**2.0-4.0*b*d
return ()
def bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))):
- #parametric bezier
- x0=bx0
- y0=by0
- cx=3*(bx1-x0)
- bx=3*(bx2-bx1)-cx
- ax=bx3-x0-cx-bx
- cy=3*(by1-y0)
- by=3*(by2-by1)-cy
- ay=by3-y0-cy-by
-
- return ax,ay,bx,by,cx,cy,x0,y0
- #ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ #parametric bezier
+ x0=bx0
+ y0=by0
+ cx=3*(bx1-x0)
+ bx=3*(bx2-bx1)-cx
+ ax=bx3-x0-cx-bx
+ cy=3*(by1-y0)
+ by=3*(by2-by1)-cy
+ ay=by3-y0-cy-by
+
+ return ax,ay,bx,by,cx,cy,x0,y0
+ #ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
def linebezierintersect(((lx1,ly1),(lx2,ly2)),((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3))):
- #parametric line
- dd=lx1
- cc=lx2-lx1
- bb=ly1
- aa=ly2-ly1
-
- if aa:
- coef1=cc/aa
- coef2=1
- else:
- coef1=1
- coef2=aa/cc
-
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- #cubic intersection coefficients
- a=coef1*ay-coef2*ax
- b=coef1*by-coef2*bx
- c=coef1*cy-coef2*cx
- d=coef1*(y0-bb)-coef2*(x0-dd)
+ #parametric line
+ dd=lx1
+ cc=lx2-lx1
+ bb=ly1
+ aa=ly2-ly1
+
+ if aa:
+ coef1=cc/aa
+ coef2=1
+ else:
+ coef1=1
+ coef2=aa/cc
+
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ #cubic intersection coefficients
+ a=coef1*ay-coef2*ax
+ b=coef1*by-coef2*bx
+ c=coef1*cy-coef2*cx
+ d=coef1*(y0-bb)-coef2*(x0-dd)
roots = rootWrapper(a,b,c,d)
retval = []
@@ -79,53 +79,53 @@ def linebezierintersect(((lx1,ly1),(lx2,ly2)),((bx0,by0),(bx1,by1),(bx2,by2),(bx
return retval
def bezierpointatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t):
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- x=ax*(t**3)+bx*(t**2)+cx*t+x0
- y=ay*(t**3)+by*(t**2)+cy*t+y0
- return x,y
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ x=ax*(t**3)+bx*(t**2)+cx*t+x0
+ y=ay*(t**3)+by*(t**2)+cy*t+y0
+ return x,y
def bezierslopeatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t):
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- dx=3*ax*(t**2)+2*bx*t+cx
- dy=3*ay*(t**2)+2*by*t+cy
- return dx,dy
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ dx=3*ax*(t**2)+2*bx*t+cx
+ dy=3*ay*(t**2)+2*by*t+cy
+ return dx,dy
def beziertatslope(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),(dy,dx)):
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- #quadratic coefficents of slope formula
- if dx:
- slope = 1.0*(dy/dx)
- a=3*ay-3*ax*slope
- b=2*by-2*bx*slope
- c=cy-cx*slope
- elif dy:
- slope = 1.0*(dx/dy)
- a=3*ax-3*ay*slope
- b=2*bx-2*by*slope
- c=cx-cy*slope
- else:
- return []
-
- roots = rootWrapper(0,a,b,c)
- retval = []
- for i in roots:
- if type(i) is complex and i.imag==0:
- i = i.real
- if type(i) is not complex and 0<=i<=1:
- retval.append(i)
- return retval
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ #quadratic coefficents of slope formula
+ if dx:
+ slope = 1.0*(dy/dx)
+ a=3*ay-3*ax*slope
+ b=2*by-2*bx*slope
+ c=cy-cx*slope
+ elif dy:
+ slope = 1.0*(dx/dy)
+ a=3*ax-3*ay*slope
+ b=2*bx-2*by*slope
+ c=cx-cy*slope
+ else:
+ return []
+
+ roots = rootWrapper(0,a,b,c)
+ retval = []
+ for i in roots:
+ if type(i) is complex and i.imag==0:
+ i = i.real
+ if type(i) is not complex and 0<=i<=1:
+ retval.append(i)
+ return retval
def tpoint((x1,y1),(x2,y2),t):
- return x1+t*(x2-x1),y1+t*(y2-y1)
+ return x1+t*(x2-x1),y1+t*(y2-y1)
def beziersplitatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),t):
- m1=tpoint((bx0,by0),(bx1,by1),t)
- m2=tpoint((bx1,by1),(bx2,by2),t)
- m3=tpoint((bx2,by2),(bx3,by3),t)
- m4=tpoint(m1,m2,t)
- m5=tpoint(m2,m3,t)
- m=tpoint(m4,m5,t)
-
- return ((bx0,by0),m1,m4,m),(m,m5,m3,(bx3,by3))
+ m1=tpoint((bx0,by0),(bx1,by1),t)
+ m2=tpoint((bx1,by1),(bx2,by2),t)
+ m3=tpoint((bx2,by2),(bx3,by3),t)
+ m4=tpoint(m1,m2,t)
+ m5=tpoint(m2,m3,t)
+ m=tpoint(m4,m5,t)
+
+ return ((bx0,by0),m1,m4,m),(m,m5,m3,(bx3,by3))
'''
Approximating the arc length of a bezier curve
University of Denmark.
'''
def pointdistance((x1,y1),(x2,y2)):
- return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
+ return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
def Gravesen_addifclose(b, len, error = 0.001):
- box = 0
- for i in range(1,4):
- box += pointdistance(b[i-1], b[i])
- chord = pointdistance(b[0], b[3])
- if (box - chord) > error:
- first, second = beziersplitatt(b, 0.5)
- Gravesen_addifclose(first, len, error)
- Gravesen_addifclose(second, len, error)
- else:
- len[0] += (box / 2.0) + (chord / 2.0)
+ box = 0
+ for i in range(1,4):
+ box += pointdistance(b[i-1], b[i])
+ chord = pointdistance(b[0], b[3])
+ if (box - chord) > error:
+ first, second = beziersplitatt(b, 0.5)
+ Gravesen_addifclose(first, len, error)
+ Gravesen_addifclose(second, len, error)
+ else:
+ len[0] += (box / 2.0) + (chord / 2.0)
def bezierlengthGravesen(b, error = 0.001):
- len = [0]
- Gravesen_addifclose(b, len, error)
- return len[0]
+ len = [0]
+ Gravesen_addifclose(b, len, error)
+ return len[0]
# balf = Bezier Arc Length Function
balfax,balfbx,balfcx,balfay,balfby,balfcy = 0,0,0,0,0,0
def balf(t):
- retval = (balfax*(t**2) + balfbx*t + balfcx)**2 + (balfay*(t**2) + balfby*t + balfcy)**2
- return math.sqrt(retval)
+ retval = (balfax*(t**2) + balfbx*t + balfcx)**2 + (balfay*(t**2) + balfby*t + balfcy)**2
+ return math.sqrt(retval)
def Simpson(f, a, b, n_limit, tolerance):
- n = 2
- multiplier = (b - a)/6.0
- endsum = f(a) + f(b)
- interval = (b - a)/2.0
- asum = 0.0
- bsum = f(a + interval)
- est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum))
- est0 = 2.0 * est1
- #print multiplier, endsum, interval, asum, bsum, est1, est0
- while n < n_limit and abs(est1 - est0) > tolerance:
- n *= 2
- multiplier /= 2.0
- interval /= 2.0
- asum += bsum
- bsum = 0.0
- est0 = est1
- for i in xrange(1, n, 2):
- bsum += f(a + (i * interval))
- est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum))
- #print multiplier, endsum, interval, asum, bsum, est1, est0
- return est1
+ n = 2
+ multiplier = (b - a)/6.0
+ endsum = f(a) + f(b)
+ interval = (b - a)/2.0
+ asum = 0.0
+ bsum = f(a + interval)
+ est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum))
+ est0 = 2.0 * est1
+ #print multiplier, endsum, interval, asum, bsum, est1, est0
+ while n < n_limit and abs(est1 - est0) > tolerance:
+ n *= 2
+ multiplier /= 2.0
+ interval /= 2.0
+ asum += bsum
+ bsum = 0.0
+ est0 = est1
+ for i in xrange(1, n, 2):
+ bsum += f(a + (i * interval))
+ est1 = multiplier * (endsum + (2.0 * asum) + (4.0 * bsum))
+ #print multiplier, endsum, interval, asum, bsum, est1, est0
+ return est1
def bezierlengthSimpson(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)), tolerance = 0.001):
- global balfax,balfbx,balfcx,balfay,balfby,balfcy
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy
- return Simpson(balf, 0.0, 1.0, 4096, tolerance)
+ global balfax,balfbx,balfcx,balfay,balfby,balfcy
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy
+ return Simpson(balf, 0.0, 1.0, 4096, tolerance)
def beziertatlength(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)), l = 0.5, tolerance = 0.001):
- global balfax,balfbx,balfcx,balfay,balfby,balfcy
- ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
- balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy
- t = 1.0
- tdiv = t
- curlen = Simpson(balf, 0.0, t, 4096, tolerance)
- targetlen = l * curlen
- diff = curlen - targetlen
- while abs(diff) > tolerance:
- tdiv /= 2.0
- if diff < 0:
- t += tdiv
- else:
- t -= tdiv
- curlen = Simpson(balf, 0.0, t, 4096, tolerance)
- diff = curlen - targetlen
- return t
+ global balfax,balfbx,balfcx,balfay,balfby,balfcy
+ ax,ay,bx,by,cx,cy,x0,y0=bezierparameterize(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)))
+ balfax,balfbx,balfcx,balfay,balfby,balfcy = 3*ax,2*bx,cx,3*ay,2*by,cy
+ t = 1.0
+ tdiv = t
+ curlen = Simpson(balf, 0.0, t, 4096, tolerance)
+ targetlen = l * curlen
+ diff = curlen - targetlen
+ while abs(diff) > tolerance:
+ tdiv /= 2.0
+ if diff < 0:
+ t += tdiv
+ else:
+ t -= tdiv
+ curlen = Simpson(balf, 0.0, t, 4096, tolerance)
+ diff = curlen - targetlen
+ return t
#default bezier length method
bezierlength = bezierlengthSimpson
if __name__ == '__main__':
- import timing
- #print linebezierintersect(((,),(,)),((,),(,),(,),(,)))
- #print linebezierintersect(((0,1),(0,-1)),((-1,0),(-.5,0),(.5,0),(1,0)))
- tol = 0.00000001
- curves = [((0,0),(1,5),(4,5),(5,5)),
- ((0,0),(0,0),(5,0),(10,0)),
- ((0,0),(0,0),(5,1),(10,0)),
- ((-10,0),(0,0),(10,0),(10,10)),
- ((15,10),(0,0),(10,0),(-5,10))]
- '''
- for curve in curves:
- timing.start()
- g = bezierlengthGravesen(curve,tol)
- timing.finish()
- gt = timing.micro()
-
- timing.start()
- s = bezierlengthSimpson(curve,tol)
- timing.finish()
- st = timing.micro()
-
- print g, gt
- print s, st
- '''
- for curve in curves:
- print beziertatlength(curve,0.5)
+ import timing
+ #print linebezierintersect(((,),(,)),((,),(,),(,),(,)))
+ #print linebezierintersect(((0,1),(0,-1)),((-1,0),(-.5,0),(.5,0),(1,0)))
+ tol = 0.00000001
+ curves = [((0,0),(1,5),(4,5),(5,5)),
+ ((0,0),(0,0),(5,0),(10,0)),
+ ((0,0),(0,0),(5,1),(10,0)),
+ ((-10,0),(0,0),(10,0),(10,10)),
+ ((15,10),(0,0),(10,0),(-5,10))]
+ '''
+ for curve in curves:
+ timing.start()
+ g = bezierlengthGravesen(curve,tol)
+ timing.finish()
+ gt = timing.micro()
+
+ timing.start()
+ s = bezierlengthSimpson(curve,tol)
+ timing.finish()
+ st = timing.micro()
+
+ print g, gt
+ print s, st
+ '''
+ for curve in curves:
+ print beziertatlength(curve,0.5)
index acf873ae1c08b48f023845788ef4d79fc7bb1f90..427e7a494e94a136538d20a2839d7b5ff40de903 100644 (file)
from ffgeom import *
def maxdist(((p0x,p0y),(p1x,p1y),(p2x,p2y),(p3x,p3y))):
- p0 = Point(p0x,p0y)
- p1 = Point(p1x,p1y)
- p2 = Point(p2x,p2y)
- p3 = Point(p3x,p3y)
+ p0 = Point(p0x,p0y)
+ p1 = Point(p1x,p1y)
+ p2 = Point(p2x,p2y)
+ p3 = Point(p3x,p3y)
- s1 = Segment(p0,p3)
- return max(s1.distanceToPoint(p1),s1.distanceToPoint(p2))
-
+ s1 = Segment(p0,p3)
+ return max(s1.distanceToPoint(p1),s1.distanceToPoint(p2))
+
def cspsubdiv(csp,flat):
- for sp in csp:
- subdiv(sp,flat)
+ for sp in csp:
+ subdiv(sp,flat)
def subdiv(sp,flat,i=1):
- p0 = sp[i-1][1]
- p1 = sp[i-1][2]
- p2 = sp[i][0]
- p3 = sp[i][1]
-
- b = (p0,p1,p2,p3)
- m = maxdist(b)
- if m <= flat:
- try:
- subdiv(sp,flat,i+1)
- except IndexError:
- pass
- else:
- one, two = beziersplitatt(b,0.5)
- sp[i-1][2] = one[1]
- sp[i][0] = two[2]
- p = [one[2],one[3],two[1]]
- sp[i:1] = [p]
- subdiv(sp,flat,i)
-
+ p0 = sp[i-1][1]
+ p1 = sp[i-1][2]
+ p2 = sp[i][0]
+ p3 = sp[i][1]
+
+ b = (p0,p1,p2,p3)
+ m = maxdist(b)
+ if m <= flat:
+ try:
+ subdiv(sp,flat,i+1)
+ except IndexError:
+ pass
+ else:
+ one, two = beziersplitatt(b,0.5)
+ sp[i-1][2] = one[1]
+ sp[i][0] = two[2]
+ p = [one[2],one[3],two[1]]
+ sp[i:1] = [p]
+ subdiv(sp,flat,i)
\ No newline at end of file
index fdd1afc59c7080f627651362fa8bb6b863a74855..0f34ec841285bad330f9ed21c94e253012409dbe 100755 (executable)
import simplepath
def CubicSuperPath(simplepath):
- csp = []
- subpath = -1
- subpathstart = []
- last = []
- lastctrl = []
- for s in simplepath:
- cmd, params = s
- if cmd == 'M':
- if last:
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- subpath += 1
- csp.append([])
- subpathstart = params[:]
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'L':
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- last = params[:]
- lastctrl = params[:]
- elif cmd == 'C':
- csp[subpath].append([lastctrl[:],last[:],params[:2]])
- last = params[-2:]
- lastctrl = params[2:4]
- elif cmd == 'Q':
- #TODO: convert to cubic
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- last = params[-2:]
- lastctrl = params[-2:]
- elif cmd == 'A':
- #TODO: convert to cubics
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- last = params[-2:]
- lastctrl = params[-2:]
- elif cmd == 'Z':
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- last = subpathstart[:]
- lastctrl = subpathstart[:]
- #append final superpoint
- csp[subpath].append([lastctrl[:],last[:],last[:]])
- return csp
+ csp = []
+ subpath = -1
+ subpathstart = []
+ last = []
+ lastctrl = []
+ for s in simplepath:
+ cmd, params = s
+ if cmd == 'M':
+ if last:
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ subpath += 1
+ csp.append([])
+ subpathstart = params[:]
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'L':
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ last = params[:]
+ lastctrl = params[:]
+ elif cmd == 'C':
+ csp[subpath].append([lastctrl[:],last[:],params[:2]])
+ last = params[-2:]
+ lastctrl = params[2:4]
+ elif cmd == 'Q':
+ #TODO: convert to cubic
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ last = params[-2:]
+ lastctrl = params[-2:]
+ elif cmd == 'A':
+ #TODO: convert to cubics
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ last = params[-2:]
+ lastctrl = params[-2:]
+ elif cmd == 'Z':
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ last = subpathstart[:]
+ lastctrl = subpathstart[:]
+ #append final superpoint
+ csp[subpath].append([lastctrl[:],last[:],last[:]])
+ return csp
def unCubicSuperPath(csp):
- a = []
- for subpath in csp:
- if subpath:
- a.append(['M',subpath[0][1][:]])
- for i in range(1,len(subpath)):
- a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]])
- return a
+ a = []
+ for subpath in csp:
+ if subpath:
+ a.append(['M',subpath[0][1][:]])
+ for i in range(1,len(subpath)):
+ a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]])
+ return a
def parsePath(d):
- return CubicSuperPath(simplepath.parsePath(d))
+ return CubicSuperPath(simplepath.parsePath(d))
def formatPath(p):
- return simplepath.formatPath(unCubicSuperPath(p))
+ return simplepath.formatPath(unCubicSuperPath(p))
index 2e24ef2b1cdad168078b74a7caa1197681f65775..c5f6e8149b9f167ad1af65f01942d864c54c32a6 100755 (executable)
--- a/share/extensions/dots.py
+++ b/share/extensions/dots.py
import inkex, simplestyle, simplepath
class Dots(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-d", "--dotsize",
- action="store", type="string",
- dest="dotsize", default="10px",
- help="Size of the dots placed at path nodes")
- self.OptionParser.add_option("-f", "--fontsize",
- action="store", type="string",
- dest="fontsize", default="20",
- help="Size of node label numbers")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- self.group = self.document.createElement('svg:g')
- node.parentNode.appendChild(self.group)
- new = self.document.createElement('svg:path')
-
- try:
- t = node.attributes.getNamedItem('transform').value
- self.group.setAttribute('transform', t)
- except AttributeError:
- pass
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-d", "--dotsize",
+ action="store", type="string",
+ dest="dotsize", default="10px",
+ help="Size of the dots placed at path nodes")
+ self.OptionParser.add_option("-f", "--fontsize",
+ action="store", type="string",
+ dest="fontsize", default="20",
+ help="Size of node label numbers")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ self.group = self.document.createElement('svg:g')
+ node.parentNode.appendChild(self.group)
+ new = self.document.createElement('svg:path')
+
+ try:
+ t = node.attributes.getNamedItem('transform').value
+ self.group.setAttribute('transform', t)
+ except AttributeError:
+ pass
- s = simplestyle.parseStyle(node.attributes.getNamedItem('style').value)
- s['stroke-linecap']='round'
- s['stroke-width']=self.options.dotsize
- new.setAttribute('style', simplestyle.formatStyle(s))
+ s = simplestyle.parseStyle(node.attributes.getNamedItem('style').value)
+ s['stroke-linecap']='round'
+ s['stroke-width']=self.options.dotsize
+ new.setAttribute('style', simplestyle.formatStyle(s))
- a =[]
- p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
- num = 1
- for cmd,params in p:
- if cmd != 'Z':
- a.append(['M',params[-2:]])
- a.append(['L',params[-2:]])
- self.addText(self.group,params[-2],params[-1],num)
- num += 1
- new.setAttribute('d', simplepath.formatPath(a))
- self.group.appendChild(new)
- node.parentNode.removeChild(node)
+ a =[]
+ p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
+ num = 1
+ for cmd,params in p:
+ if cmd != 'Z':
+ a.append(['M',params[-2:]])
+ a.append(['L',params[-2:]])
+ self.addText(self.group,params[-2],params[-1],num)
+ num += 1
+ new.setAttribute('d', simplepath.formatPath(a))
+ self.group.appendChild(new)
+ node.parentNode.removeChild(node)
-
- def addText(self,node,x,y,text):
- new = self.document.createElement('svg:text')
- s = {'font-size': self.options.fontsize, 'fill-opacity': '1.0', 'stroke': 'none',
- 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
- new.setAttribute('style', simplestyle.formatStyle(s))
- new.setAttribute('x', str(x))
- new.setAttribute('y', str(y))
- new.appendChild(self.document.createTextNode(str(text)))
- node.appendChild(new)
+
+ def addText(self,node,x,y,text):
+ new = self.document.createElement('svg:text')
+ s = {'font-size': self.options.fontsize, 'fill-opacity': '1.0', 'stroke': 'none',
+ 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
+ new.setAttribute('style', simplestyle.formatStyle(s))
+ new.setAttribute('x', str(x))
+ new.setAttribute('y', str(y))
+ new.appendChild(self.document.createTextNode(str(text)))
+ node.appendChild(new)
e = Dots()
e.affect()
index 01e7b0633e4fce7b3a524471c6c82a801cebd442..176412ea3e279195606c14fc6fb6c447f22b38b7 100755 (executable)
\r
uuconv = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'pc':15.0}\r
def unittouu(string):\r
- unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))\r
- param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')\r
+ unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))\r
+ param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')\r
\r
- p = param.match(string)\r
- u = unit.search(string) \r
- if p:\r
- retval = float(p.string[p.start():p.end()])\r
- else:\r
- retval = 0.0\r
- if u:\r
- try:\r
- return retval * uuconv[u.string[u.start():u.end()]]\r
- except KeyError:\r
- pass\r
- return retval\r
+ p = param.match(string)\r
+ u = unit.search(string) \r
+ if p:\r
+ retval = float(p.string[p.start():p.end()])\r
+ else:\r
+ retval = 0.0\r
+ if u:\r
+ try:\r
+ return retval * uuconv[u.string[u.start():u.end()]]\r
+ except KeyError:\r
+ pass\r
+ return retval\r
class MyEffect(inkex.Effect):
def __init__(self):
index 12a0b78b28d9ca7920cbbb77aea159f957d77300..b0140719891603f854ff1d7cb05e2ac16f239eea 100644 (file)
import inkex, os, base64
class MyEffect(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
+ def __init__(self):
+ inkex.Effect.__init__(self)
- def effect(self):
- ctx = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
-
- # if there is a selection only embed selected images
- # otherwise embed all images
- if (self.options.ids):
- for id, node in self.selected.iteritems():
- if node.tagName == 'image':
- self.embedImage(node)
- else:
- path = '//image'
- for node in inkex.xml.xpath.Evaluate(path,self.document, context=ctx):
- self.embedImage(node)
- def embedImage(self, node):
- xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
- if (xlink.value[:4]!='data'):
- absref=node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'absref')
- if (os.path.isfile(absref.value)):
- file = open(absref.value,"rb").read()
- embed=True
- if (file[:4]=='\x89PNG'):
- type='image/png'
- elif (file[:2]=='\xff\xd8'):
- type='image/jpg'
- else:
- embed=False
- if (embed):
- xlink.value = 'data:%s;base64,%s' % (type, base64.encodestring(file))
- node.removeAttributeNS(inkex.NSS[u'sodipodi'],'absref')
- else:
- inkex.debug("%s is not of type image/png or image/jpg" % absref.value)
- else:
- inkex.debug("Sorry we could not locate %s" % absref.value)
+ def effect(self):
+ ctx = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
+
+ # if there is a selection only embed selected images
+ # otherwise embed all images
+ if (self.options.ids):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'image':
+ self.embedImage(node)
+ else:
+ path = '//image'
+ for node in inkex.xml.xpath.Evaluate(path,self.document, context=ctx):
+ self.embedImage(node)
+ def embedImage(self, node):
+ xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
+ if (xlink.value[:4]!='data'):
+ absref=node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'absref')
+ if (os.path.isfile(absref.value)):
+ file = open(absref.value,"rb").read()
+ embed=True
+ if (file[:4]=='\x89PNG'):
+ type='image/png'
+ elif (file[:2]=='\xff\xd8'):
+ type='image/jpg'
+ else:
+ embed=False
+ if (embed):
+ xlink.value = 'data:%s;base64,%s' % (type, base64.encodestring(file))
+ node.removeAttributeNS(inkex.NSS[u'sodipodi'],'absref')
+ else:
+ inkex.debug("%s is not of type image/png or image/jpg" % absref.value)
+ else:
+ inkex.debug("Sorry we could not locate %s" % absref.value)
e = MyEffect()
e.affect()
index 8828c8b6a9b854f19ec18fb41c3ca296e6502830..4232268af500835b14a143528ddc82511d10877e 100644 (file)
import inkex, os, tempfile
def create_equation_tex(filename, equation):
- tex = open(filename, 'w')
- tex.write("""%% processed with EqTeXSVG.py
+ tex = open(filename, 'w')
+ tex.write("""%% processed with EqTeXSVG.py
\documentclass{article}
-
+
\\thispagestyle{empty}
\\begin{document}
""")
- tex.write("$$\n")
- tex.write(equation)
- tex.write("\n$$\n")
- tex.write("\end{document}\n")
- tex.close()
+ tex.write("$$\n")
+ tex.write(equation)
+ tex.write("\n$$\n")
+ tex.write("\end{document}\n")
+ tex.close()
def svg_open(self,filename):
-# parsing of SVG file with the equation
-# real parsing XML to use!!!! it will be easier !!!
- svg = open(filename, 'r')
- svg_lines = svg.readlines()
-
-# trip top/bottom lines from svg file
- svg_lines.pop(0)
- svg_lines.pop(1)
- svg_lines.pop(len(svg_lines)-1)
-
- group = self.document.createElement('svg:g')
- self.document.documentElement.appendChild(group)
-
-# deleting "<g... >" "</g>" "<path d=" and "/>" from svg_lines
- nodegroup=''
- s_nodegroup_path=''
+ # parsing of SVG file with the equation
+ # real parsing XML to use!!!! it will be easier !!!
+ svg = open(filename, 'r')
+ svg_lines = svg.readlines()\r
+
+ # trip top/bottom lines from svg file
+ svg_lines.pop(0)
+ svg_lines.pop(1)
+ svg_lines.pop(len(svg_lines)-1)
+
+ group = self.document.createElement('svg:g')
+ self.document.documentElement.appendChild(group)
+
+ # deleting "<g... >" "</g>" "<path d=" and "/>" from svg_lines
+ nodegroup=''
+ s_nodegroup_path=''
- for i in range(1,len(svg_lines)):
- if svg_lines[i].find("<g") != -1:
- nodegroup=svg_lines[i].split("<g")
- nodegroup=nodegroup[1].split(" >")
- nodegroup=nodegroup[0]+'\n'
- elif svg_lines[i].find("<path d=") != -1:
- s_nodegroup_path=svg_lines[i].split("<path d=")
- s_nodegroup_path=s_nodegroup_path[1]
- elif svg_lines[i].find("/>") != -1:
- s_nodegroup_path=s_nodegroup_path+'"\n'
- elif svg_lines[i].find("</g>") != -1:
- nodegroup_svg = self.document.createElement('svg:g')
- nodegroup_svg.setAttribute('style',nodegroup)
- nodegroup_path = self.document.createElement('svg:path')
- nodegroup_path.setAttribute('d',s_nodegroup_path)
- group.appendChild(nodegroup_svg)
- nodegroup_svg.appendChild(nodegroup_path)
- else:
- s_nodegroup_path=s_nodegroup_path+svg_lines[i]
+ for i in range(1,len(svg_lines)):
+ if svg_lines[i].find("<g") != -1:
+ nodegroup=svg_lines[i].split("<g")
+ nodegroup=nodegroup[1].split(" >")
+ nodegroup=nodegroup[0]+'\n'
+ elif svg_lines[i].find("<path d=") != -1:
+ s_nodegroup_path=svg_lines[i].split("<path d=")
+ s_nodegroup_path=s_nodegroup_path[1]
+ elif svg_lines[i].find("/>") != -1:
+ s_nodegroup_path=s_nodegroup_path+'"\n'
+ elif svg_lines[i].find("</g>") != -1:
+ nodegroup_svg = self.document.createElement('svg:g')
+ nodegroup_svg.setAttribute('style',nodegroup)
+ nodegroup_path = self.document.createElement('svg:path')
+ nodegroup_path.setAttribute('d',s_nodegroup_path)
+ group.appendChild(nodegroup_svg)
+ nodegroup_svg.appendChild(nodegroup_path)
+ else:
+ s_nodegroup_path=s_nodegroup_path+svg_lines[i]
class EQTEXSVG(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-f", "--formule",
- action="store", type="string",
- dest="formule", default=10.0,
- help="Formule LaTeX")
- def effect(self):
-
- base_file = os.path.join(tempfile.gettempdir(), "inkscape-latex.tmp")
- latex_file = base_file + ".tex"
- create_equation_tex(latex_file, self.options.formule)
-
- out_file = os.path.join(tempfile.gettempdir(), "inkscape-latex.tmp.output")
- os.system('latex -output-directory=' + tempfile.gettempdir() + ' ' + latex_file + '> ' + out_file)
-
- ps_file = base_file + ".ps"
- dvi_file = base_file + ".dvi"
- svg_file = base_file + ".svg"
- os.system('dvips -q -f -E -D 600 -y 5000 -o ' + ps_file + ' ' + dvi_file)
- os.system('pstoedit -f svg -dt -ssp ' + ps_file + ' ' + svg_file + '>> ' + out_file)
-
- # ouvrir le svg et remplacer #7F7F7F par #000000
- svg_open(self, svg_file)
-
- # clean up
- aux_file = base_file + ".aux"
- log_file = base_file + ".log"
- os.remove(latex_file)
- os.remove(aux_file)
- os.remove(log_file)
- os.remove(dvi_file)
- os.remove(ps_file)
- os.remove(svg_file)
- os.remove(out_file)
-
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-f", "--formule",
+ action="store", type="string",
+ dest="formule", default=10.0,
+ help="Formule LaTeX")
+ def effect(self):
+
+ base_file = os.path.join(tempfile.gettempdir(), "inkscape-latex.tmp")
+ latex_file = base_file + ".tex"
+ create_equation_tex(latex_file, self.options.formule)
+
+ out_file = os.path.join(tempfile.gettempdir(), "inkscape-latex.tmp.output")
+ os.system('latex -output-directory=' + tempfile.gettempdir() + ' ' + latex_file + '> ' + out_file)
+
+ ps_file = base_file + ".ps"
+ dvi_file = base_file + ".dvi"
+ svg_file = base_file + ".svg"
+ os.system('dvips -q -f -E -D 600 -y 5000 -o ' + ps_file + ' ' + dvi_file)
+ os.system('pstoedit -f svg -dt -ssp ' + ps_file + ' ' + svg_file + '>> ' + out_file)
+
+ # ouvrir le svg et remplacer #7F7F7F par #000000
+ svg_open(self, svg_file)
+
+ # clean up
+ aux_file = base_file + ".aux"
+ log_file = base_file + ".log"
+ os.remove(latex_file)
+ os.remove(aux_file)
+ os.remove(log_file)
+ os.remove(dvi_file)
+ os.remove(ps_file)
+ os.remove(svg_file)
+ os.remove(out_file)
+
e = EQTEXSVG()
e.affect()
index 27936bf80f7dc368f6fb622e77bf9c402ff9419e..f1b0f6f7a246f2b1e8a29d1ff468690aa7c92bff 100644 (file)
import inkex, base64
class MyEffect(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("--filepath",
- action="store", type="string",
- dest="filepath", default=None,
- help="")
- def effect(self):
- ctx = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
-
- # exbed the first embedded image
- path = self.options.filepath
- if (path != ''):
- if (self.options.ids):
- for id, node in self.selected.iteritems():
- if node.tagName == 'image':
- xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
- if (xlink.value[:4]=='data'):
- comma = xlink.value.find(',')
- if comma>0:
- data = base64.decodestring(xlink.value[comma:])
- open(path,'wb').write(data)
- xlink.value = path
- else:
- inkex.debug('Difficulty finding the image data.')
- break
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("--filepath",
+ action="store", type="string",
+ dest="filepath", default=None,
+ help="")
+ def effect(self):
+ ctx = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
+
+ # exbed the first embedded image
+ path = self.options.filepath
+ if (path != ''):
+ if (self.options.ids):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'image':
+ xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
+ if (xlink.value[:4]=='data'):
+ comma = xlink.value.find(',')
+ if comma>0:
+ data = base64.decodestring(xlink.value[comma:])
+ open(path,'wb').write(data)
+ xlink.value = path
+ else:
+ inkex.debug('Difficulty finding the image data.')
+ break
e = MyEffect()
e.affect()
index ab2c74b74c46767577c24aa817fbedb3f96f0e5a..24d80a175dd7855d0e7082078b5127a275ba25b5 100755 (executable)
"""
import math
try:
- NaN = float('NaN')
+ NaN = float('NaN')
except ValueError:
- PosInf = 1e300000
- NaN = PosInf/PosInf
+ PosInf = 1e300000
+ NaN = PosInf/PosInf
class Point:
- precision = 5
- def __init__(self, x, y):
- self.__coordinates = {'x' : float(x), 'y' : float(y)}
- def __getitem__(self, key):
- return self.__coordinates[key]
- def __setitem__(self, key, value):
- self.__coordinates[key] = float(value)
- def __repr__(self):
- return '(%s, %s)' % (round(self['x'],self.precision),round(self['y'],self.precision))
- def copy(self):
- return Point(self['x'],self['y'])
- def translate(self, x, y):
- self['x'] += x
- self['y'] += y
- def move(self, x, y):
- self['x'] = float(x)
- self['y'] = float(y)
+ precision = 5
+ def __init__(self, x, y):
+ self.__coordinates = {'x' : float(x), 'y' : float(y)}
+ def __getitem__(self, key):
+ return self.__coordinates[key]
+ def __setitem__(self, key, value):
+ self.__coordinates[key] = float(value)
+ def __repr__(self):
+ return '(%s, %s)' % (round(self['x'],self.precision),round(self['y'],self.precision))
+ def copy(self):
+ return Point(self['x'],self['y'])
+ def translate(self, x, y):
+ self['x'] += x
+ self['y'] += y
+ def move(self, x, y):
+ self['x'] = float(x)
+ self['y'] = float(y)
class Segment:
- def __init__(self, e0, e1):
- self.__endpoints = [e0, e1]
- def __getitem__(self, key):
- return self.__endpoints[key]
- def __setitem__(self, key, value):
- self.__endpoints[key] = value
- def __repr__(self):
- return repr(self.__endpoints)
- def copy(self):
- return Segment(self[0],self[1])
- def translate(self, x, y):
- self[0].translate(x,y)
- self[1].translate(x,y)
- def move(self,e0,e1):
- self[0] = e0
- self[1] = e1
- def delta_x(self):
- return self[1]['x'] - self[0]['x']
- def delta_y(self):
- return self[1]['y'] - self[0]['y']
- #alias functions
- run = delta_x
- rise = delta_y
- def slope(self):
- if self.delta_x() != 0:
- return self.delta_x() / self.delta_y()
- return NaN
- def intercept(self):
- if self.delta_x() != 0:
- return self[1]['y'] - (self[0]['x'] * self.slope())
- return NaN
- def distanceToPoint(self, p):
- s2 = Segment(self[0],p)
- c1 = dot(s2,self)
- if c1 <= 0:
- return Segment(p,self[0]).length()
- c2 = dot(self,self)
- if c2 <= c1:
- return Segment(p,self[1]).length()
- return self.perpDistanceToPoint(p)
- def perpDistanceToPoint(self, p):
- len = self.length()
- if len == 0: return NaN
- return math.fabs(((self[1]['x'] - self[0]['x']) * (self[0]['y'] - p['y'])) - \
- ((self[0]['x'] - p['x']) * (self[1]['y'] - self[0]['y']))) / len
- def angle(self):
- return math.pi * (math.atan2(self.delta_y(), self.delta_x())) / 180
- def length(self):
- return math.sqrt((self.delta_x() ** 2) + (self.delta_y() ** 2))
- def pointAtLength(self, len):
- if self.length() == 0: return Point(NaN, NaN)
- ratio = len / self.length()
- x = self[0]['x'] + (ratio * self.delta_x())
- y = self[0]['y'] + (ratio * self.delta_y())
- return Point(x, y)
- def pointAtRatio(self, ratio):
- if self.length() == 0: return Point(NaN, NaN)
- x = self[0]['x'] + (ratio * self.delta_x())
- y = self[0]['y'] + (ratio * self.delta_y())
- return Point(x, y)
- def createParallel(self, p):
- return Segment(Point(p['x'] + self.delta_x(), p['y'] + self.delta_y()), p)
- def intersect(self, s):
- return intersectSegments(self, s)
+ def __init__(self, e0, e1):
+ self.__endpoints = [e0, e1]
+ def __getitem__(self, key):
+ return self.__endpoints[key]
+ def __setitem__(self, key, value):
+ self.__endpoints[key] = value
+ def __repr__(self):
+ return repr(self.__endpoints)
+ def copy(self):
+ return Segment(self[0],self[1])
+ def translate(self, x, y):
+ self[0].translate(x,y)
+ self[1].translate(x,y)
+ def move(self,e0,e1):
+ self[0] = e0
+ self[1] = e1
+ def delta_x(self):
+ return self[1]['x'] - self[0]['x']
+ def delta_y(self):
+ return self[1]['y'] - self[0]['y']
+ #alias functions
+ run = delta_x
+ rise = delta_y
+ def slope(self):
+ if self.delta_x() != 0:
+ return self.delta_x() / self.delta_y()
+ return NaN
+ def intercept(self):
+ if self.delta_x() != 0:
+ return self[1]['y'] - (self[0]['x'] * self.slope())
+ return NaN
+ def distanceToPoint(self, p):
+ s2 = Segment(self[0],p)
+ c1 = dot(s2,self)
+ if c1 <= 0:
+ return Segment(p,self[0]).length()
+ c2 = dot(self,self)
+ if c2 <= c1:
+ return Segment(p,self[1]).length()
+ return self.perpDistanceToPoint(p)
+ def perpDistanceToPoint(self, p):
+ len = self.length()
+ if len == 0: return NaN
+ return math.fabs(((self[1]['x'] - self[0]['x']) * (self[0]['y'] - p['y'])) - \
+ ((self[0]['x'] - p['x']) * (self[1]['y'] - self[0]['y']))) / len
+ def angle(self):
+ return math.pi * (math.atan2(self.delta_y(), self.delta_x())) / 180
+ def length(self):
+ return math.sqrt((self.delta_x() ** 2) + (self.delta_y() ** 2))
+ def pointAtLength(self, len):
+ if self.length() == 0: return Point(NaN, NaN)
+ ratio = len / self.length()
+ x = self[0]['x'] + (ratio * self.delta_x())
+ y = self[0]['y'] + (ratio * self.delta_y())
+ return Point(x, y)
+ def pointAtRatio(self, ratio):
+ if self.length() == 0: return Point(NaN, NaN)
+ x = self[0]['x'] + (ratio * self.delta_x())
+ y = self[0]['y'] + (ratio * self.delta_y())
+ return Point(x, y)
+ def createParallel(self, p):
+ return Segment(Point(p['x'] + self.delta_x(), p['y'] + self.delta_y()), p)
+ def intersect(self, s):
+ return intersectSegments(self, s)
def intersectSegments(s1, s2):
- x1 = s1[0]['x']
- x2 = s1[1]['x']
- x3 = s2[0]['x']
- x4 = s2[1]['x']
-
- y1 = s1[0]['y']
- y2 = s1[1]['y']
- y3 = s2[0]['y']
- y4 = s2[1]['y']
-
- denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1))
- num1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3))
- num2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3))
+ x1 = s1[0]['x']
+ x2 = s1[1]['x']
+ x3 = s2[0]['x']
+ x4 = s2[1]['x']
+
+ y1 = s1[0]['y']
+ y2 = s1[1]['y']
+ y3 = s2[0]['y']
+ y4 = s2[1]['y']
+
+ denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1))
+ num1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3))
+ num2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3))
- num = num1
+ num = num1
- if denom != 0:
- x = x1 + ((num / denom) * (x2 - x1))
- y = y1 + ((num / denom) * (y2 - y1))
- return Point(x, y)
- return Point(NaN, NaN)
+ if denom != 0:
+ x = x1 + ((num / denom) * (x2 - x1))
+ y = y1 + ((num / denom) * (y2 - y1))
+ return Point(x, y)
+ return Point(NaN, NaN)
def dot(s1, s2):
- return s1.delta_x() * s2.delta_x() + s1.delta_y() * s2.delta_y()
+ return s1.delta_x() * s2.delta_x() + s1.delta_y() * s2.delta_y()
index e5c726ced77e6401fe2273b2c6dfa693d7c939c4..b288d250d37f278bfa831466dcd5489252f83784 100755 (executable)
threshold=0.0000000001
def FindFrets(strings, meta, scale, tuning, numfrets):
- scale = scale['steps']
-
- #if the string ends don't fall on the nut and bridge
- #don't look for partial frets.
- numStrings = len(strings)
- doPartials = True
- parallelFrets = True
-
- nut = Segment(strings[0][0],strings[-1][0])
- bridge = Segment(strings[0][1],strings[-1][1])
- midline = Segment(
- Point((nut[1]['x']+nut[0]['x'])/2.0,(nut[1]['y']+nut[0]['y'])/2.0),
- Point((bridge[1]['x']+bridge[0]['x'])/2.0,(bridge[1]['y']+bridge[0]['y'])/2.0))
- for s in strings:
- if nut.perpDistanceToPoint(s[0])>=threshold or bridge.perpDistanceToPoint(s[1])>=threshold:
- doPartials = False
- break
-
- denom = ((bridge[1]['y']-bridge[0]['y'])*(nut[1]['x']-nut[0]['x']))-((bridge[1]['x']-bridge[0]['x'])*(nut[1]['y']-nut[0]['y']))
- if denom != 0:
- parallelFrets = False
-
- fretboard = []
- tones = len(scale)-1
- for i in range(len(strings)):
- base = tuning[i]
- frets = []
- if doPartials:
- frets.append(Segment(meta[i][0],meta[i+1][0]))
- else:
- frets.append(Segment(strings[i][0],strings[i][0]))
- last = strings[i][0]
-
- for j in range(numfrets):
- step=((base+j-1)%(tones))+1
- ratio=1.0-((scale[step][1]*scale[step-1][0])/(scale[step][0]*scale[step-1][1]))
- x = last['x']+(ratio*(strings[i][1]['x']-last['x']))
- y = last['y']+(ratio*(strings[i][1]['y']-last['y']))
- current = Point(x,y)
- temp = Segment(strings[i][0],current)
- totalRatio = temp.length()/strings[i].length()
-
- if doPartials:
- #partials depending on outer strings (questionable)
- if parallelFrets:
- temp = nut.createParallel(current)
- else:
- temp = Segment(strings[0].pointAtLength(strings[0].length()*totalRatio),
- strings[-1].pointAtLength(strings[-1].length()*totalRatio))
- frets.append(Segment(intersectSegments(temp,meta[i]),intersectSegments(temp,meta[i+1])))
- else:
- frets.append(Segment(current,current))
- last = current
- fretboard.append(frets)
- return fretboard
-
+ scale = scale['steps']
+
+ #if the string ends don't fall on the nut and bridge
+ #don't look for partial frets.
+ numStrings = len(strings)
+ doPartials = True
+ parallelFrets = True
+
+ nut = Segment(strings[0][0],strings[-1][0])
+ bridge = Segment(strings[0][1],strings[-1][1])
+ midline = Segment(
+ Point((nut[1]['x']+nut[0]['x'])/2.0,(nut[1]['y']+nut[0]['y'])/2.0),
+ Point((bridge[1]['x']+bridge[0]['x'])/2.0,(bridge[1]['y']+bridge[0]['y'])/2.0))
+ for s in strings:
+ if nut.perpDistanceToPoint(s[0])>=threshold or bridge.perpDistanceToPoint(s[1])>=threshold:
+ doPartials = False
+ break
+
+ denom = ((bridge[1]['y']-bridge[0]['y'])*(nut[1]['x']-nut[0]['x']))-((bridge[1]['x']-bridge[0]['x'])*(nut[1]['y']-nut[0]['y']))
+ if denom != 0:
+ parallelFrets = False
+
+ fretboard = []
+ tones = len(scale)-1
+ for i in range(len(strings)):
+ base = tuning[i]
+ frets = []
+ if doPartials:
+ frets.append(Segment(meta[i][0],meta[i+1][0]))
+ else:
+ frets.append(Segment(strings[i][0],strings[i][0]))
+ last = strings[i][0]
+
+ for j in range(numfrets):
+ step=((base+j-1)%(tones))+1
+ ratio=1.0-((scale[step][1]*scale[step-1][0])/(scale[step][0]*scale[step-1][1]))
+ x = last['x']+(ratio*(strings[i][1]['x']-last['x']))
+ y = last['y']+(ratio*(strings[i][1]['y']-last['y']))
+ current = Point(x,y)
+ temp = Segment(strings[i][0],current)
+ totalRatio = temp.length()/strings[i].length()
+
+ if doPartials:
+ #partials depending on outer strings (questionable)
+ if parallelFrets:
+ temp = nut.createParallel(current)
+ else:
+ temp = Segment(strings[0].pointAtLength(strings[0].length()*totalRatio),
+ strings[-1].pointAtLength(strings[-1].length()*totalRatio))
+ frets.append(Segment(intersectSegments(temp,meta[i]),intersectSegments(temp,meta[i+1])))
+ else:
+ frets.append(Segment(current,current))
+ last = current
+ fretboard.append(frets)
+ return fretboard
+
def FindStringsSingleScale(numStrings,scaleLength,nutWidth,bridgeWidth,oNF,oBF,oNL,oBL):
- strings = []
- meta = []
- nutHalf = nutWidth/2
- bridgeHalf = bridgeWidth/2
- nutCandidateCenter = (nutHalf) + oNL
- bridgeCandidateCenter = (bridgeHalf) + oBL
- if bridgeCandidateCenter >= nutCandidateCenter:
- center = bridgeCandidateCenter
- else:
- center = nutCandidateCenter
- nutStringSpacing = nutWidth/(numStrings-1)
- bridgeStringSpacing = bridgeWidth/(numStrings-1)
-
- for i in range(numStrings):
- strings.append(Segment(Point(center+nutHalf-(i*nutStringSpacing),0),
- Point(center+bridgeHalf-(i*bridgeStringSpacing),scaleLength)))
-
- meta.append(Segment(Point(center+nutHalf+oNF,0),Point(center+bridgeHalf+oBF,scaleLength)))
- for i in range(1,numStrings):
- meta.append(Segment(
- Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
- (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
- Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
- (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
- meta.append(Segment(Point(center-(nutHalf+oNL),0),Point(center-(bridgeHalf+oBL),scaleLength)))
-
- return strings, meta
+ strings = []
+ meta = []
+ nutHalf = nutWidth/2
+ bridgeHalf = bridgeWidth/2
+ nutCandidateCenter = (nutHalf) + oNL
+ bridgeCandidateCenter = (bridgeHalf) + oBL
+ if bridgeCandidateCenter >= nutCandidateCenter:
+ center = bridgeCandidateCenter
+ else:
+ center = nutCandidateCenter
+ nutStringSpacing = nutWidth/(numStrings-1)
+ bridgeStringSpacing = bridgeWidth/(numStrings-1)
+
+ for i in range(numStrings):
+ strings.append(Segment(Point(center+nutHalf-(i*nutStringSpacing),0),
+ Point(center+bridgeHalf-(i*bridgeStringSpacing),scaleLength)))
+
+ meta.append(Segment(Point(center+nutHalf+oNF,0),Point(center+bridgeHalf+oBF,scaleLength)))
+ for i in range(1,numStrings):
+ meta.append(Segment(
+ Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
+ (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
+ Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
+ (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
+ meta.append(Segment(Point(center-(nutHalf+oNL),0),Point(center-(bridgeHalf+oBL),scaleLength)))
+
+ return strings, meta
def FindStringsMultiScale(numStrings,scaleLengthF,scaleLengthL,nutWidth,bridgeWidth,perp,oNF,oBF,oNL,oBL):
- strings = []
- meta = []
- nutHalf = nutWidth/2
- bridgeHalf = bridgeWidth/2
- nutCandidateCenter = (nutHalf)+oNL
- bridgeCandidateCenter = (bridgeHalf)+oBL
- if bridgeCandidateCenter >= nutCandidateCenter:
- xcenter = bridgeCandidateCenter
- else:
- nutCandidateCenter
-
- fbnxf = xcenter+nutHalf+oNF
- fbbxf = xcenter+bridgeHalf+oBF
- fbnxl = xcenter-(nutHalf+oNL)
- fbbxl = xcenter-(bridgeHalf+oBL)
-
- snxf = xcenter+nutHalf
- sbxf = xcenter+bridgeHalf
- snxl = xcenter-nutHalf
- sbxl = xcenter-bridgeHalf
-
- fdeltax = sbxf-snxf
- ldeltax = sbxl-snxl
- fdeltay = math.sqrt((scaleLengthF*scaleLengthF)-(fdeltax*fdeltax))
- ldeltay = math.sqrt((scaleLengthL*scaleLengthL)-(ldeltax*ldeltax))
-
- fperp = perp*fdeltay
- lperp = perp*ldeltay
-
- #temporarily place first and last strings
- first = Segment(Point(snxf,0),Point(sbxf,fdeltay))
- last = Segment(Point(snxl,0),Point(sbxl,ldeltay))
-
- if fdeltay<=ldeltay:
- first.translate(0,(lperp-fperp))
- else:
- last.translate(0,(fperp-lperp))
-
- nut = Segment(first[0].copy(),last[0].copy())
- bridge = Segment(first[1].copy(),last[1].copy())
- #overhang measurements are now converted from delta x to along line lengths
- oNF = (oNF*nut.length())/nutWidth
- oNL = (oNL*nut.length())/nutWidth
- oBF = (oBF*bridge.length())/bridgeWidth
- oBL = (oBL*bridge.length())/bridgeWidth
- #place fretboard edges
- fbf = Segment(nut.pointAtLength(-oNF),bridge.pointAtLength(-oBF))
- fbl = Segment(nut.pointAtLength(nut.length()+oNL),bridge.pointAtLength(bridge.length()+oBL))
- #normalize values into the first quadrant via translate
- if fbf[0]['y']<0 or fbl[0]['y']<0:
- if fbf[0]['y']<=fbl[0]['y']:
- move = -fbf[0]['y']
- else:
- move = -fbl[0]['y']
-
- first.translate(0,move)
- last.translate(0,move)
- nut.translate(0,move)
- bridge.translate(0,move)
- fbf.translate(0,move)
- fbl.translate(0,move)
-
- #output values
- nutStringSpacing = nut.length()/(numStrings-1)
- bridgeStringSpacing = bridge.length()/(numStrings-1)
- strings.append(first)
- for i in range(1,numStrings-1):
- n = nut.pointAtLength(i*nutStringSpacing)
- b = bridge.pointAtLength(i*bridgeStringSpacing)
- strings.append(Segment(Point(n['x'],n['y']),Point(b['x'],b['y'])))
- strings.append(last)
-
- meta.append(fbf)
- for i in range(1,numStrings):
- meta.append(Segment(
- Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
- (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
- Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
- (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
-
- meta.append(fbl)
-
- return strings, meta
+ strings = []
+ meta = []
+ nutHalf = nutWidth/2
+ bridgeHalf = bridgeWidth/2
+ nutCandidateCenter = (nutHalf)+oNL
+ bridgeCandidateCenter = (bridgeHalf)+oBL
+ if bridgeCandidateCenter >= nutCandidateCenter:
+ xcenter = bridgeCandidateCenter
+ else:
+ nutCandidateCenter
+
+ fbnxf = xcenter+nutHalf+oNF
+ fbbxf = xcenter+bridgeHalf+oBF
+ fbnxl = xcenter-(nutHalf+oNL)
+ fbbxl = xcenter-(bridgeHalf+oBL)
+
+ snxf = xcenter+nutHalf
+ sbxf = xcenter+bridgeHalf
+ snxl = xcenter-nutHalf
+ sbxl = xcenter-bridgeHalf
+
+ fdeltax = sbxf-snxf
+ ldeltax = sbxl-snxl
+ fdeltay = math.sqrt((scaleLengthF*scaleLengthF)-(fdeltax*fdeltax))
+ ldeltay = math.sqrt((scaleLengthL*scaleLengthL)-(ldeltax*ldeltax))
+
+ fperp = perp*fdeltay
+ lperp = perp*ldeltay
+
+ #temporarily place first and last strings
+ first = Segment(Point(snxf,0),Point(sbxf,fdeltay))
+ last = Segment(Point(snxl,0),Point(sbxl,ldeltay))
+
+ if fdeltay<=ldeltay:
+ first.translate(0,(lperp-fperp))
+ else:
+ last.translate(0,(fperp-lperp))
+
+ nut = Segment(first[0].copy(),last[0].copy())
+ bridge = Segment(first[1].copy(),last[1].copy())
+ #overhang measurements are now converted from delta x to along line lengths
+ oNF = (oNF*nut.length())/nutWidth
+ oNL = (oNL*nut.length())/nutWidth
+ oBF = (oBF*bridge.length())/bridgeWidth
+ oBL = (oBL*bridge.length())/bridgeWidth
+ #place fretboard edges
+ fbf = Segment(nut.pointAtLength(-oNF),bridge.pointAtLength(-oBF))
+ fbl = Segment(nut.pointAtLength(nut.length()+oNL),bridge.pointAtLength(bridge.length()+oBL))
+ #normalize values into the first quadrant via translate
+ if fbf[0]['y']<0 or fbl[0]['y']<0:
+ if fbf[0]['y']<=fbl[0]['y']:
+ move = -fbf[0]['y']
+ else:
+ move = -fbl[0]['y']
+
+ first.translate(0,move)
+ last.translate(0,move)
+ nut.translate(0,move)
+ bridge.translate(0,move)
+ fbf.translate(0,move)
+ fbl.translate(0,move)
+
+ #output values
+ nutStringSpacing = nut.length()/(numStrings-1)
+ bridgeStringSpacing = bridge.length()/(numStrings-1)
+ strings.append(first)
+ for i in range(1,numStrings-1):
+ n = nut.pointAtLength(i*nutStringSpacing)
+ b = bridge.pointAtLength(i*bridgeStringSpacing)
+ strings.append(Segment(Point(n['x'],n['y']),Point(b['x'],b['y'])))
+ strings.append(last)
+
+ meta.append(fbf)
+ for i in range(1,numStrings):
+ meta.append(Segment(
+ Point((strings[i-1][0]['x']+strings[i][0]['x'])/2.0,
+ (strings[i-1][0]['y']+strings[i][0]['y'])/2.0),
+ Point((strings[i-1][1]['x']+strings[i][1]['x'])/2.0,
+ (strings[i-1][1]['y']+strings[i][1]['y'])/2.0)))
+
+ meta.append(fbl)
+
+ return strings, meta
index f9afa0b0206ddd6c12a6d37f61cc975d8b66f4d0..74bc6b9894be18747bd76956a783c477663b02d4 100755 (executable)
import math
def ETScale(tones, octave=2.0):
- octave, tones = float(octave), float(tones)
- scale = {'steps':[[1.0,1.0]], 'title':'', 'errors':0, 'errorstring':''}
- if not tones:
- scale['errors'] += 1
- scale['errorstring'] = 'Error: Number of tones must be non zero!'
- else:
- ratio = octave**(1/tones)
- scale['title'] = '%s root of %s Equal Temperament' % (tones, octave)
- scale['steps'].append([ratio,1])
- return scale
+ octave, tones = float(octave), float(tones)
+ scale = {'steps':[[1.0,1.0]], 'title':'', 'errors':0, 'errorstring':''}
+ if not tones:
+ scale['errors'] += 1
+ scale['errorstring'] = 'Error: Number of tones must be non zero!'
+ else:
+ ratio = octave**(1/tones)
+ scale['title'] = '%s root of %s Equal Temperament' % (tones, octave)
+ scale['steps'].append([ratio,1])
+ return scale
def ScalaScale(scala):
- #initial step 0 or 1/1 is implicit
- scale = {'steps':[[1.0,1.0]], 'title':'', 'errors':0, 'errorstring':''}
+ #initial step 0 or 1/1 is implicit
+ scale = {'steps':[[1.0,1.0]], 'title':'', 'errors':0, 'errorstring':''}
- #split scale discarding commments
- lines = [l.strip() for l in scala.strip().splitlines() if not l.strip().startswith('!')]
+ #split scale discarding commments
+ lines = [l.strip() for l in scala.strip().splitlines() if not l.strip().startswith('!')]
- #first line may be blank and contains the title
- scale['title'] = lines.pop(0)
+ #first line may be blank and contains the title
+ scale['title'] = lines.pop(0)
- #second line indicates the number of note lines that should follow
- expected = int(lines.pop(0))
+ #second line indicates the number of note lines that should follow
+ expected = int(lines.pop(0))
- #discard blank lines and anything following whitespace
- lines = [l.split()[0] for l in lines if l != '']
-
- if len(lines) != expected:
- scale['errors'] += 1
- scale['errorstring'] = 'Error: expected %s more tones but found %s!' % (expected,len(lines))
- else:
- for l in lines:
- #interpret anyline containing a dot as cents
- if l.find('.') >= 0:
- num = 2**(float(l)/1200)
- denom = 1
- #everything else is a ratio
- elif l.find('/') >=0:
- l = l.split('/')
- num = float(int(l[0]))
- denom = float(int(l[1]))
- else:
- num = float(int(l))
- denom = 1.0
- scale['steps'].append([num,denom])
-
- if (num < 0) ^ (denom <= 0):
- scale['errors'] += 1
- scale['errorstring'] += 'Error at "'+l+'": Negative and undefined ratios are not allowed!\n'
- return scale
+ #discard blank lines and anything following whitespace
+ lines = [l.split()[0] for l in lines if l != '']
+
+ if len(lines) != expected:
+ scale['errors'] += 1
+ scale['errorstring'] = 'Error: expected %s more tones but found %s!' % (expected,len(lines))
+ else:
+ for l in lines:
+ #interpret anyline containing a dot as cents
+ if l.find('.') >= 0:
+ num = 2**(float(l)/1200)
+ denom = 1
+ #everything else is a ratio
+ elif l.find('/') >=0:
+ l = l.split('/')
+ num = float(int(l[0]))
+ denom = float(int(l[1]))
+ else:
+ num = float(int(l))
+ denom = 1.0
+ scale['steps'].append([num,denom])
+
+ if (num < 0) ^ (denom <= 0):
+ scale['errors'] += 1
+ scale['errorstring'] += 'Error at "'+l+'": Negative and undefined ratios are not allowed!\n'
+ return scale
index b33591e0407af3ce16d6f884e9777c295e984660..8dc4e393b3beb958e6b280e50682d8aead138e03 100755 (executable)
import inkex, cubicsuperpath, simplepath, cspsubdiv
class MyEffect(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-f", "--flatness",
- action="store", type="float",
- dest="flat", default=10.0,
- help="Minimum flatness of the subdivided curves")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = cubicsuperpath.parsePath(d.value)
- cspsubdiv.cspsubdiv(p, self.options.flat)
- np = []
- for sp in p:
- first = True
- for csp in sp:
- cmd = 'L'
- if first:
- cmd = 'M'
- first = False
- np.append([cmd,[csp[1][0],csp[1][1]]])
- d.value = simplepath.formatPath(np)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-f", "--flatness",
+ action="store", type="float",
+ dest="flat", default=10.0,
+ help="Minimum flatness of the subdivided curves")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = cubicsuperpath.parsePath(d.value)
+ cspsubdiv.cspsubdiv(p, self.options.flat)
+ np = []
+ for sp in p:
+ first = True
+ for csp in sp:
+ cmd = 'L'
+ if first:
+ cmd = 'M'
+ first = False
+ np.append([cmd,[csp[1][0],csp[1][1]]])
+ d.value = simplepath.formatPath(np)
e = MyEffect()
-e.affect()
+e.affect()
\ No newline at end of file
index 310a09a5d59573ce3ed9d0fcd9edb2c782926827..a2ce6c961a620d1db088ea3ae493c1edcf5ebbb5 100755 (executable)
import ffscale, ffproc
def seg2path(seg):
- return "M%s,%sL%s,%s" % (seg[0]['x'],seg[0]['y'],seg[1]['x'],seg[1]['y'])
+ return "M%s,%sL%s,%s" % (seg[0]['x'],seg[0]['y'],seg[1]['x'],seg[1]['y'])
class FretFind(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.doScala = False
- self.doMultiScale = False
- self.OptionParser.add_option("--scalafile",
- action="store", type="string",
- dest="scalafile", default=None,
- help="")
- self.OptionParser.add_option("--scalascale",
- action="store", type="string",
- dest="scalascale", default=None,
- help="")
- self.OptionParser.add_option("--etbase",
- action="store", type="float",
- dest="etbase", default=2.0,
- help="")
- self.OptionParser.add_option("--etroot",
- action="store", type="float",
- dest="etroot", default=12.0,
- help="")
- self.OptionParser.add_option("--tuning",
- action="store", type="string",
- dest="tuning", default="0;0;0;0;0;0",
- help="")
- self.OptionParser.add_option("--perpdist",
- action="store", type="float",
- dest="perpdist", default=0.5,
- help="")
- self.OptionParser.add_option("--offset",
- action="store", type="float",
- dest="offset", default=0.0,
- help="")
- self.OptionParser.add_option("--scalelength",
- action="store", type="float",
- dest="scalelength", default=25.0,
- help="")
- self.OptionParser.add_option("--firstscalelength",
- action="store", type="float",
- dest="firstscalelength", default=None,
- help="")
- self.OptionParser.add_option("--lastscalelength",
- action="store", type="float",
- dest="lastscalelength", default=None,
- help="")
- self.OptionParser.add_option("--nutwidth",
- action="store", type="float",
- dest="nutwidth", default=1.5,
- help="")
- self.OptionParser.add_option("--bridgewidth",
- action="store", type="float",
- dest="bridgewidth", default=2.5,
- help="")
- self.OptionParser.add_option("--frets",
- action="store", type="int",
- dest="frets", default=24,
- help="")
- self.OptionParser.add_option("--strings",
- action="store", type="int",
- dest="strings", default=6,
- help="")
- self.OptionParser.add_option("--fbedges",
- action="store", type="float",
- dest="fbedges", default=0.0975,
- help="")
- self.OptionParser.add_option("--pxperunit",
- action="store", type="float",
- dest="pxperunit", default=90,
- help="")
- def checkopts(self):
- #scale type
- if self.options.scalascale is not None:
- self.doScala = True
- if self.options.scalafile is not None:
- if self.doScala:
- sys.stderr.write('Mutually exclusive options: if found scalafile will override scalascale.')
- else:
- self.options.scalascale = ""
- self.doScala = True
- try:
- f = open(self.options.scalafile,'r')
- self.options.scalascale = f.read()
- except:
- sys.exit('Scala scale description file expected.')
- #scale
- if self.doScala:
- self.scale = ffscale.ScalaScale(self.options.scalascale)
- else:
- self.scale = ffscale.ETScale(self.options.etroot,self.options.etbase)
-
- #string length
- first = self.options.firstscalelength is not None
- last = self.options.lastscalelength is not None
- if first and last:
- self.doMultiScale = True
- elif first:
- sys.stderr.write('Missing lastscalelength: overriding scalelength with firstscalelength.')
- self.options.scalelength = self.options.firstscalelength
- elif last:
- sys.stderr.write('Missing firstscalelength: overriding scalelength with lastscalelength.')
- self.options.scalelength = self.options.lastscalelength
-
- #tuning
- self.tuning = [int(t.strip()) for t in self.options.tuning.split(";")]
- self.tuning.extend([0 for i in range(self.options.strings - len(self.tuning))])
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.doScala = False
+ self.doMultiScale = False
+ self.OptionParser.add_option("--scalafile",
+ action="store", type="string",
+ dest="scalafile", default=None,
+ help="")
+ self.OptionParser.add_option("--scalascale",
+ action="store", type="string",
+ dest="scalascale", default=None,
+ help="")
+ self.OptionParser.add_option("--etbase",
+ action="store", type="float",
+ dest="etbase", default=2.0,
+ help="")
+ self.OptionParser.add_option("--etroot",
+ action="store", type="float",
+ dest="etroot", default=12.0,
+ help="")
+ self.OptionParser.add_option("--tuning",
+ action="store", type="string",
+ dest="tuning", default="0;0;0;0;0;0",
+ help="")
+ self.OptionParser.add_option("--perpdist",
+ action="store", type="float",
+ dest="perpdist", default=0.5,
+ help="")
+ self.OptionParser.add_option("--offset",
+ action="store", type="float",
+ dest="offset", default=0.0,
+ help="")
+ self.OptionParser.add_option("--scalelength",
+ action="store", type="float",
+ dest="scalelength", default=25.0,
+ help="")
+ self.OptionParser.add_option("--firstscalelength",
+ action="store", type="float",
+ dest="firstscalelength", default=None,
+ help="")
+ self.OptionParser.add_option("--lastscalelength",
+ action="store", type="float",
+ dest="lastscalelength", default=None,
+ help="")
+ self.OptionParser.add_option("--nutwidth",
+ action="store", type="float",
+ dest="nutwidth", default=1.5,
+ help="")
+ self.OptionParser.add_option("--bridgewidth",
+ action="store", type="float",
+ dest="bridgewidth", default=2.5,
+ help="")
+ self.OptionParser.add_option("--frets",
+ action="store", type="int",
+ dest="frets", default=24,
+ help="")
+ self.OptionParser.add_option("--strings",
+ action="store", type="int",
+ dest="strings", default=6,
+ help="")
+ self.OptionParser.add_option("--fbedges",
+ action="store", type="float",
+ dest="fbedges", default=0.0975,
+ help="")
+ self.OptionParser.add_option("--pxperunit",
+ action="store", type="float",
+ dest="pxperunit", default=90,
+ help="")
+ def checkopts(self):
+ #scale type
+ if self.options.scalascale is not None:
+ self.doScala = True
+ if self.options.scalafile is not None:
+ if self.doScala:
+ sys.stderr.write('Mutually exclusive options: if found scalafile will override scalascale.')
+ else:
+ self.options.scalascale = ""
+ self.doScala = True
+ try:
+ f = open(self.options.scalafile,'r')
+ self.options.scalascale = f.read()
+ except:
+ sys.exit('Scala scale description file expected.')
+ #scale
+ if self.doScala:
+ self.scale = ffscale.ScalaScale(self.options.scalascale)
+ else:
+ self.scale = ffscale.ETScale(self.options.etroot,self.options.etbase)
+
+ #string length
+ first = self.options.firstscalelength is not None
+ last = self.options.lastscalelength is not None
+ if first and last:
+ self.doMultiScale = True
+ elif first:
+ sys.stderr.write('Missing lastscalelength: overriding scalelength with firstscalelength.')
+ self.options.scalelength = self.options.firstscalelength
+ elif last:
+ sys.stderr.write('Missing firstscalelength: overriding scalelength with lastscalelength.')
+ self.options.scalelength = self.options.lastscalelength
+
+ #tuning
+ self.tuning = [int(t.strip()) for t in self.options.tuning.split(";")]
+ self.tuning.extend([0 for i in range(self.options.strings - len(self.tuning))])
- def effect(self):
- self.checkopts()
+ def effect(self):
+ self.checkopts()
- o = self.options.fbedges
- oNF,oBF,oNL,oBL = o,o,o,o
+ o = self.options.fbedges
+ oNF,oBF,oNL,oBL = o,o,o,o
- if self.doMultiScale:
- strings, meta = ffproc.FindStringsMultiScale(self.options.strings,self.options.firstscalelength,
- self.options.lastscalelength,self.options.nutwidth,self.options.bridgewidth,
- self.options.perpdist,oNF,oBF,oNL,oBL)
- else:
- strings, meta = ffproc.FindStringsSingleScale(self.options.strings,self.options.scalelength,
- self.options.nutwidth,self.options.bridgewidth,
- oNF,oBF,oNL,oBL)
-
- frets = ffproc.FindFrets(strings, meta, self.scale, self.tuning, self.options.frets)
-
- edgepath = seg2path(meta[0]) + seg2path(meta[-1])
- stringpath = "".join([seg2path(s) for s in strings])
- fretpath = "".join(["".join([seg2path(f) for f in s]) for s in frets])
-
- group = self.document.createElement('svg:g')
- group.setAttribute('transform',"scale(%s,%s)" % (self.options.pxperunit,self.options.pxperunit))
- self.document.documentElement.appendChild(group)
-
- edge = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#0000FF', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- edge.setAttribute('style', simplestyle.formatStyle(s))
- edge.setAttribute('d', edgepath)
+ if self.doMultiScale:
+ strings, meta = ffproc.FindStringsMultiScale(self.options.strings,self.options.firstscalelength,
+ self.options.lastscalelength,self.options.nutwidth,self.options.bridgewidth,
+ self.options.perpdist,oNF,oBF,oNL,oBL)
+ else:
+ strings, meta = ffproc.FindStringsSingleScale(self.options.strings,self.options.scalelength,
+ self.options.nutwidth,self.options.bridgewidth,
+ oNF,oBF,oNL,oBL)
+
+ frets = ffproc.FindFrets(strings, meta, self.scale, self.tuning, self.options.frets)
+
+ edgepath = seg2path(meta[0]) + seg2path(meta[-1])
+ stringpath = "".join([seg2path(s) for s in strings])
+ fretpath = "".join(["".join([seg2path(f) for f in s]) for s in frets])
+
+ group = self.document.createElement('svg:g')
+ group.setAttribute('transform',"scale(%s,%s)" % (self.options.pxperunit,self.options.pxperunit))
+ self.document.documentElement.appendChild(group)
+
+ edge = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#0000FF', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ edge.setAttribute('style', simplestyle.formatStyle(s))
+ edge.setAttribute('d', edgepath)
- string = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#FF0000', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- string.setAttribute('style', simplestyle.formatStyle(s))
- string.setAttribute('d', stringpath)
+ string = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#FF0000', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ string.setAttribute('style', simplestyle.formatStyle(s))
+ string.setAttribute('d', stringpath)
- fret = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#000000', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- fret.setAttribute('style', simplestyle.formatStyle(s))
- fret.setAttribute('d', fretpath)
+ fret = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '0.01px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#000000', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ fret.setAttribute('style', simplestyle.formatStyle(s))
+ fret.setAttribute('d', fretpath)
- group.appendChild(edge)
- group.appendChild(string)
- group.appendChild(fret)
+ group.appendChild(edge)
+ group.appendChild(string)
+ group.appendChild(fret)
e = FretFind()
-e.affect()
+e.affect()
\ No newline at end of file
index 936186d244dd9d715b0138aace0d910069a11558..f295641f3509ba13b02b5a3c99ea5f92d538904b 100755 (executable)
import sys, os, tempfile
class MyEffect(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- def output(self):
- pass
- def effect(self):
- svg_file = self.args[-1]
- node = inkex.xml.xpath.Evaluate('/svg',self.document)[0]
- docname = node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docname').value[:-4]
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ def output(self):
+ pass
+ def effect(self):
+ svg_file = self.args[-1]
+ node = inkex.xml.xpath.Evaluate('/svg',self.document)[0]
+ docname = node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docname').value[:-4]
- #create os temp dir
- tmp_dir = tempfile.mkdtemp()
+ #create os temp dir
+ tmp_dir = tempfile.mkdtemp()
- area = '--export-area-canvas'
- pngs = []
- path = "/svg/*[name()='g' or @style][@id]"
- for node in inkex.xml.xpath.Evaluate(path,self.document):
- id = node.attributes.getNamedItem('id').value
- name = "%s.png" % id
- filename = os.path.join(tmp_dir, name)
- command = "inkscape -i %s -j %s -e %s %s " % (id, area, filename, svg_file)
- f = os.popen(command,'r')
- f.read()
- f.close()
- pngs.append(filename)
+ area = '--export-area-canvas'
+ pngs = []
+ path = "/svg/*[name()='g' or @style][@id]"
+ for node in inkex.xml.xpath.Evaluate(path,self.document):
+ id = node.attributes.getNamedItem('id').value
+ name = "%s.png" % id
+ filename = os.path.join(tmp_dir, name)
+ command = "inkscape -i %s -j %s -e %s %s " % (id, area, filename, svg_file)
+ f = os.popen(command,'r')
+ f.read()
+ f.close()
+ pngs.append(filename)
- filelist = '"%s"' % '" "'.join(pngs)
- xcf = os.path.join(tmp_dir, "%s.xcf" % docname)
- script_fu = """
+ filelist = '"%s"' % '" "'.join(pngs)
+ xcf = os.path.join(tmp_dir, "%s.xcf" % docname)
+ script_fu = """
(define
(png-to-layer img png_filename)
(let*
(gimp-image-undo-enable img)
(gimp-file-save RUN-NONINTERACTIVE img (car (gimp-image-get-active-layer img)) "%s" "%s"))
(gimp-quit 0)
- """ % (filelist, xcf, xcf)
+ """ % (filelist, xcf, xcf)
- junk = os.path.join(tmp_dir, 'junk_from_gimp.txt')
- f = os.popen('gimp -i -b - > %s' % junk,'w')
- f.write(script_fu)
- f.close()
-
- x = open(xcf, 'r')
- sys.stdout.write(x.read())
- x.close()
+ junk = os.path.join(tmp_dir, 'junk_from_gimp.txt')
+ f = os.popen('gimp -i -b - > %s' % junk,'w')
+ f.write(script_fu)
+ f.close()
+
+ x = open(xcf, 'r')
+ sys.stdout.write(x.read())
+ x.close()
e = MyEffect()
-e.affect()
+e.affect()
\ No newline at end of file
index a77b84cccdf41bfdaf145989205f22b41c8baa08..5ce41b734a6a82c3e739507e8e9232924c9bfa2c 100755 (executable)
import inkex, simplepath, simplestyle
class Handles(inkex.Effect):
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
- a =[]
- pen = None
- subPathStart = None
- for cmd,params in p:
- if cmd == 'C':
- a.extend([['M', params[:2]], ['L', pen],
- ['M', params[2:4]], ['L', params[-2:]]])
- if cmd == 'Q':
- a.extend([['M', params[:2]], ['L', pen],
- ['M', params[:2]], ['L', params[-2:]]])
-
- if cmd == 'M':
- subPathStart = params
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
+ a =[]
+ pen = None
+ subPathStart = None
+ for cmd,params in p:
+ if cmd == 'C':
+ a.extend([['M', params[:2]], ['L', pen],
+ ['M', params[2:4]], ['L', params[-2:]]])
+ if cmd == 'Q':
+ a.extend([['M', params[:2]], ['L', pen],
+ ['M', params[:2]], ['L', params[-2:]]])
+
+ if cmd == 'M':
+ subPathStart = params
- if cmd == 'Z':
- pen = subPathStart
- else:
- pen = params[-2:]
-
- if len(a) > 0:
- new = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#000000', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- new.setAttribute('style', simplestyle.formatStyle(s))
- new.setAttribute('d', simplepath.formatPath(a))
- node.parentNode.appendChild(new)
+ if cmd == 'Z':
+ pen = subPathStart
+ else:
+ pen = params[-2:]
+
+ if len(a) > 0:
+ new = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#000000', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ new.setAttribute('style', simplestyle.formatStyle(s))
+ new.setAttribute('d', simplepath.formatPath(a))
+ node.parentNode.appendChild(new)
e = Handles()
e.affect()
index 5edbf026ddc34366f4b706d83c199194dfd72ae5..7e5407e6a05d52c82f2fd72b0fee588248a1d107 100755 (executable)
uuconv = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'pc':15.0}
def numsegs(csp):
- return sum([len(p)-1 for p in csp])
+ return sum([len(p)-1 for p in csp])
def interpcoord(v1,v2,p):
- return v1+((v2-v1)*p)
+ return v1+((v2-v1)*p)
def interppoints(p1,p2,p):
- return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)]
+ return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)]
def pointdistance((x1,y1),(x2,y2)):
- return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
+ return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
def bezlenapprx(sp1, sp2):
- return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1])
+ return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1])
def tpoint((x1,y1), (x2,y2), t = 0.5):
- return [x1+t*(x2-x1),y1+t*(y2-y1)]
+ return [x1+t*(x2-x1),y1+t*(y2-y1)]
def cspbezsplit(sp1, sp2, t = 0.5):
- m1=tpoint(sp1[1],sp1[2],t)
- m2=tpoint(sp1[2],sp2[0],t)
- m3=tpoint(sp2[0],sp2[1],t)
- m4=tpoint(m1,m2,t)
- m5=tpoint(m2,m3,t)
- m=tpoint(m4,m5,t)
- return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
+ m1=tpoint(sp1[1],sp1[2],t)
+ m2=tpoint(sp1[2],sp2[0],t)
+ m3=tpoint(sp2[0],sp2[1],t)
+ m4=tpoint(m1,m2,t)
+ m5=tpoint(m2,m3,t)
+ m=tpoint(m4,m5,t)
+ return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- t = bezmisc.beziertatlength(bez, l, tolerance)
- return cspbezsplit(sp1, sp2, t)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ t = bezmisc.beziertatlength(bez, l, tolerance)
+ return cspbezsplit(sp1, sp2, t)
def cspseglength(sp1,sp2, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- return bezmisc.bezierlength(bez, tolerance)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ return bezmisc.bezierlength(bez, tolerance)
def csplength(csp):
- total = 0
- lengths = []
- for sp in csp:
- lengths.append([])
- for i in xrange(1,len(sp)):
- l = cspseglength(sp[i-1],sp[i])
- lengths[-1].append(l)
- total += l
- return lengths, total
+ total = 0
+ lengths = []
+ for sp in csp:
+ lengths.append([])
+ for i in xrange(1,len(sp)):
+ l = cspseglength(sp[i-1],sp[i])
+ lengths[-1].append(l)
+ total += l
+ return lengths, total
def styleunittouu(string):
- unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
- param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
+ unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
+ param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
- p = param.match(string)
- u = unit.search(string)
- if p:
- retval = float(p.string[p.start():p.end()])
- else:
- retval = 0.0
- if u:
- try:
- return retval * uuconv[u.string[u.start():u.end()]]
- except KeyError:
- pass
- return retval
-
+ p = param.match(string)
+ u = unit.search(string)
+ if p:
+ retval = float(p.string[p.start():p.end()])
+ else:
+ retval = 0.0
+ if u:
+ try:
+ return retval * uuconv[u.string[u.start():u.end()]]
+ except KeyError:
+ pass
+ return retval
+
def tweenstylefloat(property, start, end, time):
- sp = float(start[property])
- ep = float(end[property])
- return str(sp + (time * (ep - sp)))
+ sp = float(start[property])
+ ep = float(end[property])
+ return str(sp + (time * (ep - sp)))
def tweenstyleunit(property, start, end, time):
- sp = styleunittouu(start[property])
- ep = styleunittouu(end[property])
- return str(sp + (time * (ep - sp)))
+ sp = styleunittouu(start[property])
+ ep = styleunittouu(end[property])
+ return str(sp + (time * (ep - sp)))
def tweenstylecolor(property, start, end, time):
- sr,sg,sb = parsecolor(start[property])
- er,eg,eb = parsecolor(end[property])
- return '#%s%s%s' % (tweenhex(time,sr,er),tweenhex(time,sg,eg),tweenhex(time,sb,eb))
+ sr,sg,sb = parsecolor(start[property])
+ er,eg,eb = parsecolor(end[property])
+ return '#%s%s%s' % (tweenhex(time,sr,er),tweenhex(time,sg,eg),tweenhex(time,sb,eb))
def tweenhex(time,s,e):
- s = float(int(s,16))
- e = float(int(e,16))
- retval = hex(int(math.floor(s + (time * (e - s)))))[2:]
- if len(retval)==1:
- retval = '0%s' % retval
- return retval
+ s = float(int(s,16))
+ e = float(int(e,16))
+ retval = hex(int(math.floor(s + (time * (e - s)))))[2:]
+ if len(retval)==1:
+ retval = '0%s' % retval
+ return retval
def parsecolor(c):
- r,g,b = '0','0','0'
- if c[:1]=='#':
- if len(c)==4:
- r,g,b = c[1:2],c[2:3],c[3:4]
- elif len(c)==7:
- r,g,b = c[1:3],c[3:5],c[5:7]
- return r,g,b
+ r,g,b = '0','0','0'
+ if c[:1]=='#':
+ if len(c)==4:
+ r,g,b = c[1:2],c[2:3],c[3:4]
+ elif len(c)==7:
+ r,g,b = c[1:3],c[3:5],c[5:7]
+ return r,g,b
class Interp(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-e", "--exponent",
- action="store", type="float",
- dest="exponent", default=0.0,
- help="values other than zero give non linear interpolation")
- self.OptionParser.add_option("-s", "--steps",
- action="store", type="int",
- dest="steps", default=5,
- help="number of interpolation steps")
- self.OptionParser.add_option("-m", "--method",
- action="store", type="int",
- dest="method", default=2,
- help="method of interpolation")
- self.OptionParser.add_option("-d", "--dup",
- action="store", type="inkbool",
- dest="dup", default=True,
- help="duplicate endpaths")
- self.OptionParser.add_option("--style",
- action="store", type="inkbool",
- dest="style", default=True,
- help="try interpolation of some style properties")
- def effect(self):
- exponent = self.options.exponent
- if exponent>= 0:
- exponent = 1.0 + exponent
- else:
- exponent = 1.0/(1.0 - exponent)
- steps = [1.0/(self.options.steps + 1.0)]
- for i in range(self.options.steps - 1):
- steps.append(steps[0] + steps[-1])
- steps = [step**exponent for step in steps]
-
- paths = {}
- styles = {}
- for id in self.options.ids:
- node = self.selected[id]
- if node.tagName =='path':
- paths[id] = cubicsuperpath.parsePath(node.attributes.getNamedItem('d').value)
- styles[id] = simplestyle.parseStyle(node.attributes.getNamedItem('style').value)
- else:
- self.options.ids.remove(id)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-e", "--exponent",
+ action="store", type="float",
+ dest="exponent", default=0.0,
+ help="values other than zero give non linear interpolation")
+ self.OptionParser.add_option("-s", "--steps",
+ action="store", type="int",
+ dest="steps", default=5,
+ help="number of interpolation steps")
+ self.OptionParser.add_option("-m", "--method",
+ action="store", type="int",
+ dest="method", default=2,
+ help="method of interpolation")
+ self.OptionParser.add_option("-d", "--dup",
+ action="store", type="inkbool",
+ dest="dup", default=True,
+ help="duplicate endpaths")
+ self.OptionParser.add_option("--style",
+ action="store", type="inkbool",
+ dest="style", default=True,
+ help="try interpolation of some style properties")
+ def effect(self):
+ exponent = self.options.exponent
+ if exponent>= 0:
+ exponent = 1.0 + exponent
+ else:
+ exponent = 1.0/(1.0 - exponent)
+ steps = [1.0/(self.options.steps + 1.0)]
+ for i in range(self.options.steps - 1):
+ steps.append(steps[0] + steps[-1])
+ steps = [step**exponent for step in steps]
+
+ paths = {}
+ styles = {}
+ for id in self.options.ids:
+ node = self.selected[id]
+ if node.tagName =='path':
+ paths[id] = cubicsuperpath.parsePath(node.attributes.getNamedItem('d').value)
+ styles[id] = simplestyle.parseStyle(node.attributes.getNamedItem('style').value)
+ else:
+ self.options.ids.remove(id)
- for i in range(1,len(self.options.ids)):
- start = copy.deepcopy(paths[self.options.ids[i-1]])
- end = copy.deepcopy(paths[self.options.ids[i]])
- sst = copy.deepcopy(styles[self.options.ids[i-1]])
- est = copy.deepcopy(styles[self.options.ids[i]])
- basestyle = copy.deepcopy(sst)
+ for i in range(1,len(self.options.ids)):
+ start = copy.deepcopy(paths[self.options.ids[i-1]])
+ end = copy.deepcopy(paths[self.options.ids[i]])
+ sst = copy.deepcopy(styles[self.options.ids[i-1]])
+ est = copy.deepcopy(styles[self.options.ids[i]])
+ basestyle = copy.deepcopy(sst)
- #prepare for experimental style tweening
- if self.options.style:
- dostroke = True
- dofill = True
- styledefaults = {'opacity':'1.0', 'stroke-opacity':'1.0', 'fill-opacity':'1.0',
- 'stroke-width':'1.0', 'stroke':'none', 'fill':'none'}
- for key in styledefaults.keys():
- sst.setdefault(key,styledefaults[key])
- est.setdefault(key,styledefaults[key])
- isnotplain = lambda x: not (x=='none' or x[:1]=='#')
- if isnotplain(sst['stroke']) or isnotplain(est['stroke']) or (sst['stroke']=='none' and est['stroke']=='none'):
- dostroke = False
- if isnotplain(sst['fill']) or isnotplain(est['fill']) or (sst['fill']=='none' and est['fill']=='none'):
- dofill = False
- if dostroke:
- if sst['stroke']=='none':
- sst['stroke-width'] = '0.0'
- sst['stroke-opacity'] = '0.0'
- sst['stroke'] = est['stroke']
- elif est['stroke']=='none':
- est['stroke-width'] = '0.0'
- est['stroke-opacity'] = '0.0'
- est['stroke'] = sst['stroke']
- if dofill:
- if sst['fill']=='none':
- sst['fill-opacity'] = '0.0'
- sst['fill'] = est['fill']
- elif est['fill']=='none':
- est['fill-opacity'] = '0.0'
- est['fill'] = sst['fill']
+ #prepare for experimental style tweening
+ if self.options.style:
+ dostroke = True
+ dofill = True
+ styledefaults = {'opacity':'1.0', 'stroke-opacity':'1.0', 'fill-opacity':'1.0',
+ 'stroke-width':'1.0', 'stroke':'none', 'fill':'none'}
+ for key in styledefaults.keys():
+ sst.setdefault(key,styledefaults[key])
+ est.setdefault(key,styledefaults[key])
+ isnotplain = lambda x: not (x=='none' or x[:1]=='#')
+ if isnotplain(sst['stroke']) or isnotplain(est['stroke']) or (sst['stroke']=='none' and est['stroke']=='none'):
+ dostroke = False
+ if isnotplain(sst['fill']) or isnotplain(est['fill']) or (sst['fill']=='none' and est['fill']=='none'):
+ dofill = False
+ if dostroke:
+ if sst['stroke']=='none':
+ sst['stroke-width'] = '0.0'
+ sst['stroke-opacity'] = '0.0'
+ sst['stroke'] = est['stroke']
+ elif est['stroke']=='none':
+ est['stroke-width'] = '0.0'
+ est['stroke-opacity'] = '0.0'
+ est['stroke'] = sst['stroke']
+ if dofill:
+ if sst['fill']=='none':
+ sst['fill-opacity'] = '0.0'
+ sst['fill'] = est['fill']
+ elif est['fill']=='none':
+ est['fill-opacity'] = '0.0'
+ est['fill'] = sst['fill']
-
+
- if self.options.method == 2:
- #subdivide both paths into segments of relatively equal lengths
- slengths, stotal = csplength(start)
- elengths, etotal = csplength(end)
- lengths = {}
- t = 0
- for sp in slengths:
- for l in sp:
- t += l / stotal
- lengths.setdefault(t,0)
- lengths[t] += 1
- t = 0
- for sp in elengths:
- for l in sp:
- t += l / etotal
- lengths.setdefault(t,0)
- lengths[t] += -1
- sadd = [k for (k,v) in lengths.iteritems() if v < 0]
- sadd.sort()
- eadd = [k for (k,v) in lengths.iteritems() if v > 0]
- eadd.sort()
+ if self.options.method == 2:
+ #subdivide both paths into segments of relatively equal lengths
+ slengths, stotal = csplength(start)
+ elengths, etotal = csplength(end)
+ lengths = {}
+ t = 0
+ for sp in slengths:
+ for l in sp:
+ t += l / stotal
+ lengths.setdefault(t,0)
+ lengths[t] += 1
+ t = 0
+ for sp in elengths:
+ for l in sp:
+ t += l / etotal
+ lengths.setdefault(t,0)
+ lengths[t] += -1
+ sadd = [k for (k,v) in lengths.iteritems() if v < 0]
+ sadd.sort()
+ eadd = [k for (k,v) in lengths.iteritems() if v > 0]
+ eadd.sort()
- t = 0
- s = [[]]
- for sp in slengths:
- if not start[0]:
- s.append(start.pop(0))
- s[-1].append(start[0].pop(0))
- for l in sp:
- pt = t
- t += l / stotal
- if sadd and t > sadd[0]:
- while sadd and sadd[0] < t:
- nt = (sadd[0] - pt) / (t - pt)
- bezes = cspbezsplitatlength(s[-1][-1][:],start[0][0][:], nt)
- s[-1][-1:] = bezes[:2]
- start[0][0] = bezes[2]
- pt = sadd.pop(0)
- s[-1].append(start[0].pop(0))
- t = 0
- e = [[]]
- for sp in elengths:
- if not end[0]:
- e.append(end.pop(0))
- e[-1].append(end[0].pop(0))
- for l in sp:
- pt = t
- t += l / etotal
- if eadd and t > eadd[0]:
- while eadd and eadd[0] < t:
- nt = (eadd[0] - pt) / (t - pt)
- bezes = cspbezsplitatlength(e[-1][-1][:],end[0][0][:], nt)
- e[-1][-1:] = bezes[:2]
- end[0][0] = bezes[2]
- pt = eadd.pop(0)
- e[-1].append(end[0].pop(0))
- start = s[:]
- end = e[:]
- else:
- #which path has fewer segments?
- lengthdiff = numsegs(start) - numsegs(end)
- #swap shortest first
- if lengthdiff > 0:
- start, end = end, start
- #subdivide the shorter path
- for x in range(abs(lengthdiff)):
- maxlen = 0
- subpath = 0
- segment = 0
- for y in range(len(start)):
- for z in range(1, len(start[y])):
- leng = bezlenapprx(start[y][z-1], start[y][z])
- if leng > maxlen:
- maxlen = leng
- subpath = y
- segment = z
- sp1, sp2 = start[subpath][segment - 1:segment + 1]
- start[subpath][segment - 1:segment + 1] = cspbezsplit(sp1, sp2)
- #if swapped, swap them back
- if lengthdiff > 0:
- start, end = end, start
-
- #break paths so that corresponding subpaths have an equal number of segments
- s = [[]]
- e = [[]]
- while start and end:
- if start[0] and end[0]:
- s[-1].append(start[0].pop(0))
- e[-1].append(end[0].pop(0))
- elif end[0]:
- s.append(start.pop(0))
- e[-1].append(end[0][0])
- e.append([end[0].pop(0)])
- elif start[0]:
- e.append(end.pop(0))
- s[-1].append(start[0][0])
- s.append([start[0].pop(0)])
- else:
- s.append(start.pop(0))
- e.append(end.pop(0))
-
- if self.options.dup:
- steps = [0] + steps + [1]
- #create an interpolated path for each interval
- group = self.document.createElement('svg:g')
- self.document.documentElement.appendChild(group)
- for time in steps:
- interp = []
- #process subpaths
- for ssp,esp in zip(s, e):
- if not (ssp or esp):
- break
- interp.append([])
- #process superpoints
- for sp,ep in zip(ssp, esp):
- if not (sp or ep):
- break
- interp[-1].append([])
- #process points
- for p1,p2 in zip(sp, ep):
- if not (sp or ep):
- break
- interp[-1][-1].append(interppoints(p1, p2, time))
+ t = 0
+ s = [[]]
+ for sp in slengths:
+ if not start[0]:
+ s.append(start.pop(0))
+ s[-1].append(start[0].pop(0))
+ for l in sp:
+ pt = t
+ t += l / stotal
+ if sadd and t > sadd[0]:
+ while sadd and sadd[0] < t:
+ nt = (sadd[0] - pt) / (t - pt)
+ bezes = cspbezsplitatlength(s[-1][-1][:],start[0][0][:], nt)
+ s[-1][-1:] = bezes[:2]
+ start[0][0] = bezes[2]
+ pt = sadd.pop(0)
+ s[-1].append(start[0].pop(0))
+ t = 0
+ e = [[]]
+ for sp in elengths:
+ if not end[0]:
+ e.append(end.pop(0))
+ e[-1].append(end[0].pop(0))
+ for l in sp:
+ pt = t
+ t += l / etotal
+ if eadd and t > eadd[0]:
+ while eadd and eadd[0] < t:
+ nt = (eadd[0] - pt) / (t - pt)
+ bezes = cspbezsplitatlength(e[-1][-1][:],end[0][0][:], nt)
+ e[-1][-1:] = bezes[:2]
+ end[0][0] = bezes[2]
+ pt = eadd.pop(0)
+ e[-1].append(end[0].pop(0))
+ start = s[:]
+ end = e[:]
+ else:
+ #which path has fewer segments?
+ lengthdiff = numsegs(start) - numsegs(end)
+ #swap shortest first
+ if lengthdiff > 0:
+ start, end = end, start
+ #subdivide the shorter path
+ for x in range(abs(lengthdiff)):
+ maxlen = 0
+ subpath = 0
+ segment = 0
+ for y in range(len(start)):
+ for z in range(1, len(start[y])):
+ leng = bezlenapprx(start[y][z-1], start[y][z])
+ if leng > maxlen:
+ maxlen = leng
+ subpath = y
+ segment = z
+ sp1, sp2 = start[subpath][segment - 1:segment + 1]
+ start[subpath][segment - 1:segment + 1] = cspbezsplit(sp1, sp2)
+ #if swapped, swap them back
+ if lengthdiff > 0:
+ start, end = end, start
+
+ #break paths so that corresponding subpaths have an equal number of segments
+ s = [[]]
+ e = [[]]
+ while start and end:
+ if start[0] and end[0]:
+ s[-1].append(start[0].pop(0))
+ e[-1].append(end[0].pop(0))
+ elif end[0]:
+ s.append(start.pop(0))
+ e[-1].append(end[0][0])
+ e.append([end[0].pop(0)])
+ elif start[0]:
+ e.append(end.pop(0))
+ s[-1].append(start[0][0])
+ s.append([start[0].pop(0)])
+ else:
+ s.append(start.pop(0))
+ e.append(end.pop(0))
+
+ if self.options.dup:
+ steps = [0] + steps + [1]
+ #create an interpolated path for each interval
+ group = self.document.createElement('svg:g')
+ self.document.documentElement.appendChild(group)
+ for time in steps:
+ interp = []
+ #process subpaths
+ for ssp,esp in zip(s, e):
+ if not (ssp or esp):
+ break
+ interp.append([])
+ #process superpoints
+ for sp,ep in zip(ssp, esp):
+ if not (sp or ep):
+ break
+ interp[-1].append([])
+ #process points
+ for p1,p2 in zip(sp, ep):
+ if not (sp or ep):
+ break
+ interp[-1][-1].append(interppoints(p1, p2, time))
- #remove final subpath if empty.
- if not interp[-1]:
- del interp[-1]
- new = self.document.createElement('svg:path')
+ #remove final subpath if empty.
+ if not interp[-1]:
+ del interp[-1]
+ new = self.document.createElement('svg:path')
- #basic style tweening
- if self.options.style:
- basestyle['opacity'] = tweenstylefloat('opacity',sst,est,time)
- if dostroke:
- basestyle['stroke-opacity'] = tweenstylefloat('stroke-opacity',sst,est,time)
- basestyle['stroke-width'] = tweenstyleunit('stroke-width',sst,est,time)
- basestyle['stroke'] = tweenstylecolor('stroke',sst,est,time)
- if dofill:
- basestyle['fill-opacity'] = tweenstylefloat('fill-opacity',sst,est,time)
- basestyle['fill'] = tweenstylecolor('fill',sst,est,time)
- new.setAttribute('style', simplestyle.formatStyle(basestyle))
- new.setAttribute('d', cubicsuperpath.formatPath(interp))
- group.appendChild(new)
+ #basic style tweening
+ if self.options.style:
+ basestyle['opacity'] = tweenstylefloat('opacity',sst,est,time)
+ if dostroke:
+ basestyle['stroke-opacity'] = tweenstylefloat('stroke-opacity',sst,est,time)
+ basestyle['stroke-width'] = tweenstyleunit('stroke-width',sst,est,time)
+ basestyle['stroke'] = tweenstylecolor('stroke',sst,est,time)
+ if dofill:
+ basestyle['fill-opacity'] = tweenstylefloat('fill-opacity',sst,est,time)
+ basestyle['fill'] = tweenstylecolor('fill',sst,est,time)
+ new.setAttribute('style', simplestyle.formatStyle(basestyle))
+ new.setAttribute('d', cubicsuperpath.formatPath(interp))
+ group.appendChild(new)
e = Interp()
e.affect()
index e6914278c7f5aaa19726cd15168d37b76d42c7b7..7f676cb98705b4b83fd4365c879b4753c16ca1dc 100755 (executable)
import math, tempfile, copy, cPickle, inkex, simplepath
def findend(d):
- end = []
- subPathStart = []
- for cmd,params in d:
- if cmd == 'M':
- subPathStart = params[-2:]
- if cmd == 'Z':
- end = subPathStart[:]
- else:
- end = params[-2:]
- return end
+ end = []
+ subPathStart = []
+ for cmd,params in d:
+ if cmd == 'M':
+ subPathStart = params[-2:]
+ if cmd == 'Z':
+ end = subPathStart[:]
+ else:
+ end = params[-2:]
+ return end
class Kochify(inkex.Effect):
- def effect(self):
- try:
- f = open(tempfile.gettempdir() + '/kochify.bin', 'r')
- proto = cPickle.load(f)
- f.close()
- except:
- return False
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = simplepath.parsePath(d.value)
- last = p[0][1][-2:]
- subPathStart = []
- cur = []
- new = []
- for i in range(len(p)):
- rep = copy.deepcopy(proto['path'])
- cmd, params = p[i]
- if cmd == 'M':
- subPathStart = params[-2:]
- new.append(copy.deepcopy(p[i]))
- continue
- if cmd == 'Z':
- cur = subPathStart[:]
- else:
- cur = params[-2:]
+ def effect(self):
+ try:
+ f = open(tempfile.gettempdir() + '/kochify.bin', 'r')
+ proto = cPickle.load(f)
+ f.close()
+ except:
+ return False
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = simplepath.parsePath(d.value)
+ last = p[0][1][-2:]
+ subPathStart = []
+ cur = []
+ new = []
+ for i in range(len(p)):
+ rep = copy.deepcopy(proto['path'])
+ cmd, params = p[i]
+ if cmd == 'M':
+ subPathStart = params[-2:]
+ new.append(copy.deepcopy(p[i]))
+ continue
+ if cmd == 'Z':
+ cur = subPathStart[:]
+ else:
+ cur = params[-2:]
- if last == cur:
- continue
+ if last == cur:
+ continue
- dx = cur[0]-last[0]
- dy = cur[1]-last[1]
- length = math.sqrt((dx**2) + (dy**2))
- angle = math.atan2(dy,dx)
-
- scale = length / proto['length']
- rotate = angle - proto['angle']
- simplepath.scalePath(rep,scale,scale)
- simplepath.rotatePath(rep, rotate)
- repend = findend(rep)
- transx = cur[0] - repend[0]
- transy = cur[1] - repend[1]
- simplepath.translatePath(rep, transx, transy)
-
- if proto['endsinz']:
- new.extend(rep[:])
- else:
- new.extend(rep[1:])
- last = cur[:]
-
- d.value = simplepath.formatPath(new)
+ dx = cur[0]-last[0]
+ dy = cur[1]-last[1]
+ length = math.sqrt((dx**2) + (dy**2))
+ angle = math.atan2(dy,dx)
+
+ scale = length / proto['length']
+ rotate = angle - proto['angle']
+ simplepath.scalePath(rep,scale,scale)
+ simplepath.rotatePath(rep, rotate)
+ repend = findend(rep)
+ transx = cur[0] - repend[0]
+ transy = cur[1] - repend[1]
+ simplepath.translatePath(rep, transx, transy)
+
+ if proto['endsinz']:
+ new.extend(rep[:])
+ else:
+ new.extend(rep[1:])
+ last = cur[:]
+
+ d.value = simplepath.formatPath(new)
e = Kochify()
e.affect()
index d50c498c07bcf8189ab3e06b9a9ad60a75ba911f..9c178e3c459d711c720942b9c648c33e1c3bf8e1 100755 (executable)
import math, tempfile, cPickle, inkex, simplepath
def findend(d):
- end = []
- subPathStart = []
- for cmd,params in d:
- if cmd == 'M':
- subPathStart = params[-2:]
- if cmd == 'Z':
- end = subPathStart[:]
- else:
- end = params[-2:]
- return end
+ end = []
+ subPathStart = []
+ for cmd,params in d:
+ if cmd == 'M':
+ subPathStart = params[-2:]
+ if cmd == 'Z':
+ end = subPathStart[:]
+ else:
+ end = params[-2:]
+ return end
class LoadKochify(inkex.Effect):
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = simplepath.parsePath(node.attributes.getNamedItem('d').value)
- start = d[0][1][-2:]
- end = findend(d)
- while start == end and len(d):
- d = d[:-1]
- end = findend(d)
- if not end:
- break
- dx = end[0]-start[0]
- dy = end[1]-start[1]
- length = math.sqrt((dx**2) + (dy**2))
- angle = math.atan2(dy,dx)
- endsinz = False
- if d[-1][0]=='Z':
- endsinz = True
- path = {'start': start, 'end': end, 'endsinz': endsinz,
- 'length': length, 'angle': angle, 'path': d}
- f = open(tempfile.gettempdir() + '/kochify.bin', 'w')
- cPickle.dump(path, f)
- f.close()
- break
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = simplepath.parsePath(node.attributes.getNamedItem('d').value)
+ start = d[0][1][-2:]
+ end = findend(d)
+ while start == end and len(d):
+ d = d[:-1]
+ end = findend(d)
+ if not end:
+ break
+ dx = end[0]-start[0]
+ dy = end[1]-start[1]
+ length = math.sqrt((dx**2) + (dy**2))
+ angle = math.atan2(dy,dx)
+ endsinz = False
+ if d[-1][0]=='Z':
+ endsinz = True
+ path = {'start': start, 'end': end, 'endsinz': endsinz,
+ 'length': length, 'angle': angle, 'path': d}
+ f = open(tempfile.gettempdir() + '/kochify.bin', 'w')
+ cPickle.dump(path, f)
+ f.close()
+ break
e = LoadKochify()
e.affect()
index a6848320d9b9c7cb9c5a68e89c4f50d320313f19..34c52bd989250f24ac987d708b29213d020ff4dc 100755 (executable)
import inkex, simplestyle, pturtle
class LSystem(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-o", "--order",
- action="store", type="int",
- dest="order", default=3,
- help="number of iteration")
- self.OptionParser.add_option("-a", "--angle",
- action="store", type="float",
- dest="angle", default=16.0,
- help="angle for turn commands")
- self.OptionParser.add_option("-s", "--step",
- action="store", type="float",
- dest="step", default=25.0,
- help="step size")
- self.OptionParser.add_option("-x", "--axiom",
- action="store", type="string",
- dest="axiom", default="++F",
- help="initial state of system")
- self.OptionParser.add_option("-r", "--rules",
- action="store", type="string",
- dest="rules", default="F=FF-[-F+F+F]+[+F-F-F]",
- help="replacement rules")
- self.stack = []
- self.turtle = pturtle.pTurtle()
- def iterate(self):
- self.rules = dict([i.split("=") for i in self.options.rules.upper().split(";") if i.count("=")==1])
- self.__recurse(self.options.axiom.upper(),0)
- return self.turtle.getPath()
- def __recurse(self,rule,level):
- for c in rule:
- if level < self.options.order:
- try:
- self.__recurse(self.rules[c],level+1)
- except KeyError:
- pass
-
- if c == 'F':
- self.turtle.pd()
- self.turtle.fd(self.options.step)
- elif c == 'G':
- self.turtle.pu()
- self.turtle.fd(self.options.step)
- elif c == '+':
- self.turtle.lt(self.options.angle)
- elif c == '-':
- self.turtle.rt(self.options.angle)
- elif c == '|':
- self.turtle.lt(180)
- elif c == '[':
- self.stack.append([self.turtle.getpos(), self.turtle.getheading()])
- elif c == ']':
- self.turtle.pu()
- pos,heading = self.stack.pop()
- self.turtle.setpos(pos)
- self.turtle.setheading(heading)
- def effect(self):
- new = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#000000', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- new.setAttribute('style', simplestyle.formatStyle(s))
- new.setAttribute('d', self.iterate())
- self.document.documentElement.appendChild(new)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-o", "--order",
+ action="store", type="int",
+ dest="order", default=3,
+ help="number of iteration")
+ self.OptionParser.add_option("-a", "--angle",
+ action="store", type="float",
+ dest="angle", default=16.0,
+ help="angle for turn commands")
+ self.OptionParser.add_option("-s", "--step",
+ action="store", type="float",
+ dest="step", default=25.0,
+ help="step size")
+ self.OptionParser.add_option("-x", "--axiom",
+ action="store", type="string",
+ dest="axiom", default="++F",
+ help="initial state of system")
+ self.OptionParser.add_option("-r", "--rules",
+ action="store", type="string",
+ dest="rules", default="F=FF-[-F+F+F]+[+F-F-F]",
+ help="replacement rules")
+ self.stack = []
+ self.turtle = pturtle.pTurtle()
+ def iterate(self):
+ self.rules = dict([i.split("=") for i in self.options.rules.upper().split(";") if i.count("=")==1])
+ self.__recurse(self.options.axiom.upper(),0)
+ return self.turtle.getPath()
+ def __recurse(self,rule,level):
+ for c in rule:
+ if level < self.options.order:
+ try:
+ self.__recurse(self.rules[c],level+1)
+ except KeyError:
+ pass
+
+ if c == 'F':
+ self.turtle.pd()
+ self.turtle.fd(self.options.step)
+ elif c == 'G':
+ self.turtle.pu()
+ self.turtle.fd(self.options.step)
+ elif c == '+':
+ self.turtle.lt(self.options.angle)
+ elif c == '-':
+ self.turtle.rt(self.options.angle)
+ elif c == '|':
+ self.turtle.lt(180)
+ elif c == '[':
+ self.stack.append([self.turtle.getpos(), self.turtle.getheading()])
+ elif c == ']':
+ self.turtle.pu()
+ pos,heading = self.stack.pop()
+ self.turtle.setpos(pos)
+ self.turtle.setheading(heading)
+ def effect(self):
+ new = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#000000', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ new.setAttribute('style', simplestyle.formatStyle(s))
+ new.setAttribute('d', self.iterate())
+ self.document.documentElement.appendChild(new)
e = LSystem()
e.affect()
index e8089ca055a1f92c03cb994d580cd1e3cbf5e05e..690b8658f9957492bfe7326d6478e5e4a2b9de56 100644 (file)
import inkex, simplestyle, simplepath,sys,cubicsuperpath, bezmisc
def numsegs(csp):
- return sum([len(p)-1 for p in csp])
+ return sum([len(p)-1 for p in csp])
def interpcoord(v1,v2,p):
- return v1+((v2-v1)*p)
+ return v1+((v2-v1)*p)
def interppoints(p1,p2,p):
- return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)]
+ return [interpcoord(p1[0],p2[0],p),interpcoord(p1[1],p2[1],p)]
def pointdistance((x1,y1),(x2,y2)):
- return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
+ return math.sqrt(((x2 - x1) ** 2) + ((y2 - y1) ** 2))
def bezlenapprx(sp1, sp2):
- return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1])
+ return pointdistance(sp1[1], sp1[2]) + pointdistance(sp1[2], sp2[0]) + pointdistance(sp2[0], sp2[1])
def tpoint((x1,y1), (x2,y2), t = 0.5):
- return [x1+t*(x2-x1),y1+t*(y2-y1)]
+ return [x1+t*(x2-x1),y1+t*(y2-y1)]
def cspbezsplit(sp1, sp2, t = 0.5):
- m1=tpoint(sp1[1],sp1[2],t)
- m2=tpoint(sp1[2],sp2[0],t)
- m3=tpoint(sp2[0],sp2[1],t)
- m4=tpoint(m1,m2,t)
- m5=tpoint(m2,m3,t)
- m=tpoint(m4,m5,t)
- return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
+ m1=tpoint(sp1[1],sp1[2],t)
+ m2=tpoint(sp1[2],sp2[0],t)
+ m3=tpoint(sp2[0],sp2[1],t)
+ m4=tpoint(m1,m2,t)
+ m5=tpoint(m2,m3,t)
+ m=tpoint(m4,m5,t)
+ return [[sp1[0][:],sp1[1][:],m1], [m4,m,m5], [m3,sp2[1][:],sp2[2][:]]]
def cspbezsplitatlength(sp1, sp2, l = 0.5, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- t = bezmisc.beziertatlength(bez, l, tolerance)
- return cspbezsplit(sp1, sp2, t)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ t = bezmisc.beziertatlength(bez, l, tolerance)
+ return cspbezsplit(sp1, sp2, t)
def cspseglength(sp1,sp2, tolerance = 0.001):
- bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
- return bezmisc.bezierlength(bez, tolerance)
+ bez = (sp1[1][:],sp1[2][:],sp2[0][:],sp2[1][:])
+ return bezmisc.bezierlength(bez, tolerance)
def csplength(csp):
- total = 0
- lengths = []
- for sp in csp:
- lengths.append([])
- for i in xrange(1,len(sp)):
- l = cspseglength(sp[i-1],sp[i])
- lengths[-1].append(l)
- total += l
- return lengths, total
+ total = 0
+ lengths = []
+ for sp in csp:
+ lengths.append([])
+ for i in xrange(1,len(sp)):
+ l = cspseglength(sp[i-1],sp[i])
+ lengths[-1].append(l)
+ total += l
+ return lengths, total
class Length(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-f", "--fontsize",
- action="store", type="string",
- dest="fontsize", default="20",
- help="Size of node label numbers")
- self.OptionParser.add_option("-o", "--offset",
- action="store", type="string",
- dest="offset", default="-4",
- help="The distance above the curve")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- self.group = self.document.createElement('svg:g')
- node.parentNode.appendChild(self.group)
-
- try:
- t = node.attributes.getNamedItem('transform').value
- self.group.setAttribute('transform', t)
- except AttributeError:
- pass
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-f", "--fontsize",
+ action="store", type="string",
+ dest="fontsize", default="20",
+ help="Size of node label numbers")
+ self.OptionParser.add_option("-o", "--offset",
+ action="store", type="string",
+ dest="offset", default="-4",
+ help="The distance above the curve")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ self.group = self.document.createElement('svg:g')
+ node.parentNode.appendChild(self.group)
+
+ try:
+ t = node.attributes.getNamedItem('transform').value
+ self.group.setAttribute('transform', t)
+ except AttributeError:
+ pass
- a =[]
- p = cubicsuperpath.parsePath(node.attributes.getNamedItem('d').value)
- num = 1
- slengths, stotal = csplength(p)
- self.addTextOnPath(self.group,0, 0,str(stotal), id, self.options.offset)
+ a =[]
+ p = cubicsuperpath.parsePath(node.attributes.getNamedItem('d').value)
+ num = 1
+ slengths, stotal = csplength(p)
+ self.addTextOnPath(self.group,0, 0,str(stotal), id, self.options.offset)
-
- def addTextOnPath(self,node,x,y,text, id,dy=0):
- new = self.document.createElement('svg:text')
- tp = self.document.createElement('svg:textPath')
- s = {'font-size': self.options.fontsize, 'fill-opacity': '1.0', 'stroke': 'none',
- 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
- new.setAttribute('style', simplestyle.formatStyle(s))
- new.setAttribute('x', str(x))
- new.setAttribute('y', str(y))
- tp.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href', '#'+id)
- tp.setAttribute('startOffset', "50%")
- #tp.setAttribute('dy', dy) # dubious merit
- new.appendChild(tp)
- tp.appendChild(self.document.createTextNode(str(text)))
- node.appendChild(new)
+
+ def addTextOnPath(self,node,x,y,text, id,dy=0):
+ new = self.document.createElement('svg:text')
+ tp = self.document.createElement('svg:textPath')
+ s = {'font-size': self.options.fontsize, 'fill-opacity': '1.0', 'stroke': 'none',
+ 'font-weight': 'normal', 'font-style': 'normal', 'fill': '#000000'}
+ new.setAttribute('style', simplestyle.formatStyle(s))
+ new.setAttribute('x', str(x))
+ new.setAttribute('y', str(y))
+ tp.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href', '#'+id)
+ tp.setAttribute('startOffset', "50%")
+ #tp.setAttribute('dy', dy) # dubious merit
+ new.appendChild(tp)
+ tp.appendChild(self.document.createTextNode(str(text)))
+ node.appendChild(new)
e = Length()
e.affect()
index 95100e62987894f1aaba4e2be228292718889fbb..3834c7f2b74c8563ae8b8f7556a4020351392a9d 100755 (executable)
import math, inkex, simplestyle, simplepath, bezmisc
class Motion(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-a", "--angle",
- action="store", type="float",
- dest="angle", default=45.0,
- help="direction of the motion vector")
- self.OptionParser.add_option("-m", "--magnitude",
- action="store", type="float",
- dest="magnitude", default=100.0,
- help="magnitude of the motion vector")
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-a", "--angle",
+ action="store", type="float",
+ dest="angle", default=45.0,
+ help="direction of the motion vector")
+ self.OptionParser.add_option("-m", "--magnitude",
+ action="store", type="float",
+ dest="magnitude", default=100.0,
+ help="magnitude of the motion vector")
- def makeface(self,last,(cmd, params)):
- a = []
- a.append(['M',last[:]])
- a.append([cmd, params[:]])
+ def makeface(self,last,(cmd, params)):
+ a = []
+ a.append(['M',last[:]])
+ a.append([cmd, params[:]])
- #translate path segment along vector
- np = params[:]
- defs = simplepath.pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- np[i] += self.vx
- elif defs[3][i] == 'y':
- np[i] += self.vy
+ #translate path segment along vector
+ np = params[:]
+ defs = simplepath.pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'x':
+ np[i] += self.vx
+ elif defs[3][i] == 'y':
+ np[i] += self.vy
- a.append(['L',[np[-2],np[-1]]])
-
- #reverse direction of path segment
- np[-2:] = last[0]+self.vx,last[1]+self.vy
- if cmd == 'C':
- c1 = np[:2], np[2:4] = np[2:4], np[:2]
- a.append([cmd,np[:]])
-
- a.append(['Z',[]])
- face = self.document.createElement('svg:path')
- self.facegroup.appendChild(face)
- face.setAttribute('d', simplepath.formatPath(a))
-
-
- def effect(self):
- self.vx = math.cos(math.radians(self.options.angle))*self.options.magnitude
- self.vy = math.sin(math.radians(self.options.angle))*self.options.magnitude
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- group = self.document.createElement('svg:g')
- self.facegroup = self.document.createElement('svg:g')
- node.parentNode.appendChild(group)
- group.appendChild(self.facegroup)
- group.appendChild(node)
-
- try:
- t = node.attributes.getNamedItem('transform').value
- group.setAttribute('transform', t)
- node.attributes.getNamedItem('transform').value=""
- except AttributeError:
- pass
+ a.append(['L',[np[-2],np[-1]]])
+
+ #reverse direction of path segment
+ np[-2:] = last[0]+self.vx,last[1]+self.vy
+ if cmd == 'C':
+ c1 = np[:2], np[2:4] = np[2:4], np[:2]
+ a.append([cmd,np[:]])
+
+ a.append(['Z',[]])
+ face = self.document.createElement('svg:path')
+ self.facegroup.appendChild(face)
+ face.setAttribute('d', simplepath.formatPath(a))
+
+
+ def effect(self):
+ self.vx = math.cos(math.radians(self.options.angle))*self.options.magnitude
+ self.vy = math.sin(math.radians(self.options.angle))*self.options.magnitude
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ group = self.document.createElement('svg:g')
+ self.facegroup = self.document.createElement('svg:g')
+ node.parentNode.appendChild(group)
+ group.appendChild(self.facegroup)
+ group.appendChild(node)
+
+ try:
+ t = node.attributes.getNamedItem('transform').value
+ group.setAttribute('transform', t)
+ node.attributes.getNamedItem('transform').value=""
+ except AttributeError:
+ pass
- s = node.attributes.getNamedItem('style').value
- self.facegroup.setAttribute('style', s)
+ s = node.attributes.getNamedItem('style').value
+ self.facegroup.setAttribute('style', s)
- p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
- for cmd,params in p:
- tees = []
- if cmd == 'C':
- bez = (last,params[:2],params[2:4],params[-2:])
- tees = [t for t in bezmisc.beziertatslope(bez,(self.vy,self.vx)) if 0<t<1]
- tees.sort()
+ p = simplepath.parsePath(node.attributes.getNamedItem('d').value)
+ for cmd,params in p:
+ tees = []
+ if cmd == 'C':
+ bez = (last,params[:2],params[2:4],params[-2:])
+ tees = [t for t in bezmisc.beziertatslope(bez,(self.vy,self.vx)) if 0<t<1]
+ tees.sort()
- segments = []
- if len(tees) == 0 and cmd in ['L','C']:
- segments.append([cmd,params[:]])
- elif len(tees) == 1:
- one,two = bezmisc.beziersplitatt(bez,tees[0])
- segments.append([cmd,list(one[1]+one[2]+one[3])])
- segments.append([cmd,list(two[1]+two[2]+two[3])])
- elif len(tees) == 2:
- one,two = bezmisc.beziersplitatt(bez,tees[0])
- two,three = bezmisc.beziersplitatt(two,tees[1])
- segments.append([cmd,list(one[1]+one[2]+one[3])])
- segments.append([cmd,list(two[1]+two[2]+two[3])])
- segments.append([cmd,list(three[1]+three[2]+three[3])])
+ segments = []
+ if len(tees) == 0 and cmd in ['L','C']:
+ segments.append([cmd,params[:]])
+ elif len(tees) == 1:
+ one,two = bezmisc.beziersplitatt(bez,tees[0])
+ segments.append([cmd,list(one[1]+one[2]+one[3])])
+ segments.append([cmd,list(two[1]+two[2]+two[3])])
+ elif len(tees) == 2:
+ one,two = bezmisc.beziersplitatt(bez,tees[0])
+ two,three = bezmisc.beziersplitatt(two,tees[1])
+ segments.append([cmd,list(one[1]+one[2]+one[3])])
+ segments.append([cmd,list(two[1]+two[2]+two[3])])
+ segments.append([cmd,list(three[1]+three[2]+three[3])])
- for seg in segments:
- self.makeface(last,seg)
- last = seg[1][-2:]
-
- if cmd == 'M':
- subPathStart = params[-2:]
- if cmd == 'Z':
- last = subPathStart
- else:
- last = params[-2:]
-
-
-
+ for seg in segments:
+ self.makeface(last,seg)
+ last = seg[1][-2:]
+
+ if cmd == 'M':
+ subPathStart = params[-2:]
+ if cmd == 'Z':
+ last = subPathStart
+ else:
+ last = params[-2:]
e = Motion()
e.affect()
index f1806a68bf371660d45b68537da0a58506d23528..431c216eda48800b7606494b4a0a51cf2fe0e163 100755 (executable)
'''
import math
class pTurtle:
- '''A Python path turtle'''
- def __init__(self, home=(0,0)):
- self.__home = [home[0], home[1]]
- self.__pos = self.__home[:]
- self.__heading = -90
- self.__path = ""
- self.__draw = True
- self.__new = True
- def forward(self,mag):
- self.setpos((self.__pos[0] + math.cos(math.radians(self.__heading))*mag,
- self.__pos[1] + math.sin(math.radians(self.__heading))*mag))
- def backward(self,mag):
- self.setpos((self.__pos[0] - math.cos(math.radians(self.__heading))*mag,
- self.__pos[1] - math.sin(math.radians(self.__heading))*mag))
- def right(self,deg):
- self.__heading -= deg
- def left(self,deg):
- self.__heading += deg
- def penup(self):
- self.__draw = False
- self.__new = False
- def pendown(self):
- if not self.__draw:
- self.__new = True
- self.__draw = True
- def pentoggle(self):
- if self.__draw:
- self.penup()
- else:
- self.pendown()
- def home(self):
- self.setpos(self.__home)
- def clean(self):
- self.__path = ''
- def clear(self):
- self.clean()
- self.home()
- def setpos(self,(x,y)):
- if self.__new:
- self.__path += "M"+",".join([str(i) for i in self.__pos])
- self.__new = False
- self.__pos = [x, y]
- if self.__draw:
- self.__path += "L"+",".join([str(i) for i in self.__pos])
- def getpos(self):
- return self.__pos[:]
- def setheading(self,deg):
- self.__heading = deg
- def getheading(self):
- return self.__heading
- def sethome(self,(x,y)):
- self.__home = [x, y]
- def getPath(self):
- return self.__path
- fd = forward
- bk = backward
- rt = right
- lt = left
- pu = penup
- pd = pendown
+ '''A Python path turtle'''
+ def __init__(self, home=(0,0)):
+ self.__home = [home[0], home[1]]
+ self.__pos = self.__home[:]
+ self.__heading = -90
+ self.__path = ""
+ self.__draw = True
+ self.__new = True
+ def forward(self,mag):
+ self.setpos((self.__pos[0] + math.cos(math.radians(self.__heading))*mag,
+ self.__pos[1] + math.sin(math.radians(self.__heading))*mag))
+ def backward(self,mag):
+ self.setpos((self.__pos[0] - math.cos(math.radians(self.__heading))*mag,
+ self.__pos[1] - math.sin(math.radians(self.__heading))*mag))
+ def right(self,deg):
+ self.__heading -= deg
+ def left(self,deg):
+ self.__heading += deg
+ def penup(self):
+ self.__draw = False
+ self.__new = False
+ def pendown(self):
+ if not self.__draw:
+ self.__new = True
+ self.__draw = True
+ def pentoggle(self):
+ if self.__draw:
+ self.penup()
+ else:
+ self.pendown()
+ def home(self):
+ self.setpos(self.__home)
+ def clean(self):
+ self.__path = ''
+ def clear(self):
+ self.clean()
+ self.home()
+ def setpos(self,(x,y)):
+ if self.__new:
+ self.__path += "M"+",".join([str(i) for i in self.__pos])
+ self.__new = False
+ self.__pos = [x, y]
+ if self.__draw:
+ self.__path += "L"+",".join([str(i) for i in self.__pos])
+ def getpos(self):
+ return self.__pos[:]
+ def setheading(self,deg):
+ self.__heading = deg
+ def getheading(self):
+ return self.__heading
+ def sethome(self,(x,y)):
+ self.__home = [x, y]
+ def getPath(self):
+ return self.__path
+ fd = forward
+ bk = backward
+ rt = right
+ lt = left
+ pu = penup
+ pd = pendown
index 27420a85d48aa4458e070e3c3556588d3c8424d0..0df740ad4099c4949010e29c592f7548fccd5d47 100755 (executable)
import random, math, inkex, cubicsuperpath
def randomize((x, y), r, norm):
- if norm:
- r = abs(random.normalvariate(0.0,0.5*r))
- else:
- r = random.uniform(0.0,r)
- a = random.uniform(0.0,2*math.pi)
- x += math.cos(a)*r
- y += math.sin(a)*r
- return [x, y]
+ if norm:
+ r = abs(random.normalvariate(0.0,0.5*r))
+ else:
+ r = random.uniform(0.0,r)
+ a = random.uniform(0.0,2*math.pi)
+ x += math.cos(a)*r
+ y += math.sin(a)*r
+ return [x, y]
class RadiusRandomize(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-r", "--radius",
- action="store", type="float",
- dest="radius", default=10.0,
- help="Randomly move control and end points in this radius")
- self.OptionParser.add_option("-c", "--ctrl",
- action="store", type="inkbool",
- dest="ctrl", default=True,
- help="Randomize control points")
- self.OptionParser.add_option("-e", "--end",
- action="store", type="inkbool",
- dest="end", default=True,
- help="Randomize nodes")
- self.OptionParser.add_option("-n", "--norm",
- action="store", type="inkbool",
- dest="norm", default=True,
- help="Use normal distribution")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = cubicsuperpath.parsePath(d.value)
- for subpath in p:
- for csp in subpath:
- if self.options.end:
- delta=randomize([0,0], self.options.radius, self.options.norm)
- csp[0][0]+=delta[0]
- csp[0][1]+=delta[1]
- csp[1][0]+=delta[0]
- csp[1][1]+=delta[1]
- csp[2][0]+=delta[0]
- csp[2][1]+=delta[1]
- if self.options.ctrl:
- csp[0]=randomize(csp[0], self.options.radius, self.options.norm)
- csp[2]=randomize(csp[2], self.options.radius, self.options.norm)
- d.value = cubicsuperpath.formatPath(p)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-r", "--radius",
+ action="store", type="float",
+ dest="radius", default=10.0,
+ help="Randomly move control and end points in this radius")
+ self.OptionParser.add_option("-c", "--ctrl",
+ action="store", type="inkbool",
+ dest="ctrl", default=True,
+ help="Randomize control points")
+ self.OptionParser.add_option("-e", "--end",
+ action="store", type="inkbool",
+ dest="end", default=True,
+ help="Randomize nodes")
+ self.OptionParser.add_option("-n", "--norm",
+ action="store", type="inkbool",
+ dest="norm", default=True,
+ help="Use normal distribution")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = cubicsuperpath.parsePath(d.value)
+ for subpath in p:
+ for csp in subpath:
+ if self.options.end:
+ delta=randomize([0,0], self.options.radius, self.options.norm)
+ csp[0][0]+=delta[0]
+ csp[0][1]+=delta[1]
+ csp[1][0]+=delta[0]
+ csp[1][1]+=delta[1]
+ csp[2][0]+=delta[0]
+ csp[2][1]+=delta[1]
+ if self.options.ctrl:
+ csp[0]=randomize(csp[0], self.options.radius, self.options.norm)
+ csp[2]=randomize(csp[2], self.options.radius, self.options.norm)
+ d.value = cubicsuperpath.formatPath(p)
e = RadiusRandomize()
e.affect()
index 8728ed7a37e413dc17b10c9eb930fa534af85b67..a70b2b4c08086e640736fdeb90cdef34c6ab4001 100755 (executable)
import inkex, simplestyle, pturtle, random
def rtree(turtle, size, min):
- if size < min:
- return
- turtle.fd(size)
- turn = random.uniform(20, 40)
- turtle.lt(turn)
- rtree(turtle, size*random.uniform(0.5,0.9), min)
- turtle.rt(turn)
- turn = random.uniform(20, 40)
- turtle.rt(turn)
- rtree(turtle, size*random.uniform(0.5,0.9), min)
- turtle.lt(turn)
- turtle.bk(size)
+ if size < min:
+ return
+ turtle.fd(size)
+ turn = random.uniform(20, 40)
+ turtle.lt(turn)
+ rtree(turtle, size*random.uniform(0.5,0.9), min)
+ turtle.rt(turn)
+ turn = random.uniform(20, 40)
+ turtle.rt(turn)
+ rtree(turtle, size*random.uniform(0.5,0.9), min)
+ turtle.lt(turn)
+ turtle.bk(size)
class RTreeTurtle(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-s", "--size",
- action="store", type="float",
- dest="size", default=100.0,
- help="initial branch size")
- self.OptionParser.add_option("-m", "--minimum",
- action="store", type="float",
- dest="minimum", default=4.0,
- help="minimum branch size")
- def effect(self):
- new = self.document.createElement('svg:path')
- s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
- 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
- 'stroke': '#000000', 'stroke-linecap': 'butt',
- 'fill': 'none'}
- new.setAttribute('style', simplestyle.formatStyle(s))
- t = pturtle.pTurtle()
- rtree(t, self.options.size, self.options.minimum)
- new.setAttribute('d', t.getPath())
- self.document.documentElement.appendChild(new)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-s", "--size",
+ action="store", type="float",
+ dest="size", default=100.0,
+ help="initial branch size")
+ self.OptionParser.add_option("-m", "--minimum",
+ action="store", type="float",
+ dest="minimum", default=4.0,
+ help="minimum branch size")
+ def effect(self):
+ new = self.document.createElement('svg:path')
+ s = {'stroke-linejoin': 'miter', 'stroke-width': '1.0px',
+ 'stroke-opacity': '1.0', 'fill-opacity': '1.0',
+ 'stroke': '#000000', 'stroke-linecap': 'butt',
+ 'fill': 'none'}
+ new.setAttribute('style', simplestyle.formatStyle(s))
+ t = pturtle.pTurtle()
+ rtree(t, self.options.size, self.options.minimum)
+ new.setAttribute('d', t.getPath())
+ self.document.documentElement.appendChild(new)
e = RTreeTurtle()
e.affect()
index 06ed73672db59f2d7c80a487e0da7f851fa19e88..bfca242f6bc3faa366f7f0d83ec691dfeb90b5dc 100755 (executable)
import re, math
def lexPath(d):
- """
- returns and iterator that breaks path data
- identifies command and parameter tokens
- """
- offset = 0
- length = len(d)
- delim = re.compile(r'[ \t\r\n,]+')
- command = re.compile(r'[MLHVCSQTAZmlhvcsqtaz]')
- parameter = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
- while 1:
- m = delim.match(d, offset)
- if m:
- offset = m.end()
- if offset >= length:
- break
- m = command.match(d, offset)
- if m:
- yield [d[offset:m.end()], True]
- offset = m.end()
- continue
- m = parameter.match(d, offset)
- if m:
- yield [d[offset:m.end()], False]
- offset = m.end()
- continue
- #TODO: create new exception
- raise Exception, 'Invalid path data!'
+ """
+ returns and iterator that breaks path data
+ identifies command and parameter tokens
+ """
+ offset = 0
+ length = len(d)
+ delim = re.compile(r'[ \t\r\n,]+')
+ command = re.compile(r'[MLHVCSQTAZmlhvcsqtaz]')
+ parameter = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
+ while 1:
+ m = delim.match(d, offset)
+ if m:
+ offset = m.end()
+ if offset >= length:
+ break
+ m = command.match(d, offset)
+ if m:
+ yield [d[offset:m.end()], True]
+ offset = m.end()
+ continue
+ m = parameter.match(d, offset)
+ if m:
+ yield [d[offset:m.end()], False]
+ offset = m.end()
+ continue
+ #TODO: create new exception
+ raise Exception, 'Invalid path data!'
'''
pathdefs = {commandfamily:
- [
- implicitnext,
- #params,
- [casts,cast,cast],
- [coord type,x,y,0]
- ]}
+ [
+ implicitnext,
+ #params,
+ [casts,cast,cast],
+ [coord type,x,y,0]
+ ]}
'''
pathdefs = {
- 'M':['L', 2, [float, float], ['x','y']],
- 'L':['L', 2, [float, float], ['x','y']],
- 'H':['H', 1, [float], ['x']],
- 'V':['V', 1, [float], ['y']],
- 'C':['C', 6, [float, float, float, float, float, float], ['x','y','x','y','x','y']],
- 'S':['S', 4, [float, float, float, float], ['x','y','x','y']],
- 'Q':['Q', 4, [float, float, float, float], ['x','y','x','y']],
- 'T':['T', 2, [float, float], ['x','y']],
- 'A':['A', 7, [float, float, float, int, int, float, float], [0,0,0,0,0,'x','y']],
- 'Z':['L', 0, [], []]
- }
+ 'M':['L', 2, [float, float], ['x','y']],
+ 'L':['L', 2, [float, float], ['x','y']],
+ 'H':['H', 1, [float], ['x']],
+ 'V':['V', 1, [float], ['y']],
+ 'C':['C', 6, [float, float, float, float, float, float], ['x','y','x','y','x','y']],
+ 'S':['S', 4, [float, float, float, float], ['x','y','x','y']],
+ 'Q':['Q', 4, [float, float, float, float], ['x','y','x','y']],
+ 'T':['T', 2, [float, float], ['x','y']],
+ 'A':['A', 7, [float, float, float, int, int, float, float], [0,0,0,0,0,'x','y']],
+ 'Z':['L', 0, [], []]
+ }
def parsePath(d):
- """
- Parse SVG path and return an array of segments.
- Removes all shorthand notation.
- Converts coordinates to absolute.
- """
- retval = []
- lexer = lexPath(d)
+ """
+ Parse SVG path and return an array of segments.
+ Removes all shorthand notation.
+ Converts coordinates to absolute.
+ """
+ retval = []
+ lexer = lexPath(d)
- pen = (0.0,0.0)
- subPathStart = pen
- lastControl = pen
- lastCommand = ''
-
- while 1:
- try:
- token, isCommand = lexer.next()
- except StopIteration:
- break
- params = []
- needParam = True
- if isCommand:
- if not lastCommand and token.upper() != 'M':
- raise Exception, 'Invalid path, must begin with moveto.'
- else:
- command = token
- else:
- #command was omited
- #use last command's implicit next command
- needParam = False
- if lastCommand:
- if token.isupper():
- command = pathdefs[lastCommand.upper()][0]
- else:
- command = pathdefs[lastCommand.upper()][0].lower()
- else:
- raise Exception, 'Invalid path, no initial command.'
- numParams = pathdefs[command.upper()][1]
- while numParams > 0:
- if needParam:
- try:
- token, isCommand = lexer.next()
- if isCommand:
- raise Exception, 'Invalid number of parameters'
- except StopIteration:
- raise Exception, 'Unexpected end of path'
- cast = pathdefs[command.upper()][2][-numParams]
- param = cast(token)
- if command.islower():
- if pathdefs[command.upper()][3][-numParams]=='x':
- param += pen[0]
- elif pathdefs[command.upper()][3][-numParams]=='y':
- param += pen[1]
- params.append(param)
- needParam = True
- numParams -= 1
- #segment is now absolute so
- outputCommand = command.upper()
-
- #Flesh out shortcut notation
- if outputCommand in ('H','V'):
- if outputCommand == 'H':
- params.append(pen[1])
- if outputCommand == 'V':
- params.insert(0,pen[0])
- outputCommand = 'L'
- if outputCommand in ('S','T'):
- params.insert(0,pen[1]+(pen[1]-lastControl[1]))
- params.insert(0,pen[0]+(pen[0]-lastControl[0]))
- if outputCommand == 'S':
- outputCommand = 'C'
- if outputCommand == 'T':
- outputCommand = 'Q'
+ pen = (0.0,0.0)
+ subPathStart = pen
+ lastControl = pen
+ lastCommand = ''
+
+ while 1:
+ try:
+ token, isCommand = lexer.next()
+ except StopIteration:
+ break
+ params = []
+ needParam = True
+ if isCommand:
+ if not lastCommand and token.upper() != 'M':
+ raise Exception, 'Invalid path, must begin with moveto.'
+ else:
+ command = token
+ else:
+ #command was omited
+ #use last command's implicit next command
+ needParam = False
+ if lastCommand:
+ if token.isupper():
+ command = pathdefs[lastCommand.upper()][0]
+ else:
+ command = pathdefs[lastCommand.upper()][0].lower()
+ else:
+ raise Exception, 'Invalid path, no initial command.'
+ numParams = pathdefs[command.upper()][1]
+ while numParams > 0:
+ if needParam:
+ try:
+ token, isCommand = lexer.next()
+ if isCommand:
+ raise Exception, 'Invalid number of parameters'
+ except StopIteration:
+ raise Exception, 'Unexpected end of path'
+ cast = pathdefs[command.upper()][2][-numParams]
+ param = cast(token)
+ if command.islower():
+ if pathdefs[command.upper()][3][-numParams]=='x':
+ param += pen[0]
+ elif pathdefs[command.upper()][3][-numParams]=='y':
+ param += pen[1]
+ params.append(param)
+ needParam = True
+ numParams -= 1
+ #segment is now absolute so
+ outputCommand = command.upper()
+
+ #Flesh out shortcut notation
+ if outputCommand in ('H','V'):
+ if outputCommand == 'H':
+ params.append(pen[1])
+ if outputCommand == 'V':
+ params.insert(0,pen[0])
+ outputCommand = 'L'
+ if outputCommand in ('S','T'):
+ params.insert(0,pen[1]+(pen[1]-lastControl[1]))
+ params.insert(0,pen[0]+(pen[0]-lastControl[0]))
+ if outputCommand == 'S':
+ outputCommand = 'C'
+ if outputCommand == 'T':
+ outputCommand = 'Q'
- #current values become "last" values
- if outputCommand == 'M':
- subPathStart = tuple(params[0:2])
- if outputCommand == 'Z':
- pen = subPathStart
- else:
- pen = tuple(params[-2:])
+ #current values become "last" values
+ if outputCommand == 'M':
+ subPathStart = tuple(params[0:2])
+ if outputCommand == 'Z':
+ pen = subPathStart
+ else:
+ pen = tuple(params[-2:])
- if outputCommand in ('Q','C'):
- lastControl = tuple(params[-4:-2])
- else:
- lastControl = pen
- lastCommand = command
+ if outputCommand in ('Q','C'):
+ lastControl = tuple(params[-4:-2])
+ else:
+ lastControl = pen
+ lastCommand = command
- retval.append([outputCommand,params])
- return retval
+ retval.append([outputCommand,params])
+ return retval
def formatPath(a):
- """Format SVG path data from an array"""
- return "".join([cmd + " ".join([str(p) for p in params]) for cmd, params in a])
+ """Format SVG path data from an array"""
+ return "".join([cmd + " ".join([str(p) for p in params]) for cmd, params in a])
def translatePath(p, x, y):
- for cmd,params in p:
- defs = pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- params[i] += x
- elif defs[3][i] == 'y':
- params[i] += y
+ for cmd,params in p:
+ defs = pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'x':
+ params[i] += x
+ elif defs[3][i] == 'y':
+ params[i] += y
def scalePath(p, x, y):
- for cmd,params in p:
- defs = pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- params[i] *= x
- elif defs[3][i] == 'y':
- params[i] *= y
+ for cmd,params in p:
+ defs = pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'x':
+ params[i] *= x
+ elif defs[3][i] == 'y':
+ params[i] *= y
def rotatePath(p, a, cx = 0, cy = 0):
- if a == 0:
- return p
- for cmd,params in p:
- defs = pathdefs[cmd]
- for i in range(defs[1]):
- if defs[3][i] == 'x':
- x = params[i] - cx
- y = params[i + 1] - cy
- r = math.sqrt((x**2) + (y**2))
- if r != 0:
- theta = math.atan2(y, x) + a
- params[i] = (r * math.cos(theta)) + cx
- params[i + 1] = (r * math.sin(theta)) + cy
+ if a == 0:
+ return p
+ for cmd,params in p:
+ defs = pathdefs[cmd]
+ for i in range(defs[1]):
+ if defs[3][i] == 'x':
+ x = params[i] - cx
+ y = params[i + 1] - cy
+ r = math.sqrt((x**2) + (y**2))
+ if r != 0:
+ theta = math.atan2(y, x) + a
+ params[i] = (r * math.cos(theta)) + cx
+ params[i + 1] = (r * math.sin(theta)) + cy
index 32fd987b7529306f2bc0396da0ddb24c810487a4..22b4c3e8b21d1ecc0dff56488f361d14a83ca540 100755 (executable)
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
def parseStyle(s):
- """Create a dictionary from the value of an inline style attribute"""
- return dict([i.split(":") for i in s.split(";")])
+ """Create a dictionary from the value of an inline style attribute"""
+ return dict([i.split(":") for i in s.split(";")])
def formatStyle(a):
- """Format an inline style attribute from a dictionary"""
- return ";".join([":".join(i) for i in a.iteritems()])
+ """Format an inline style attribute from a dictionary"""
+ return ";".join([":".join(i) for i in a.iteritems()])
index 692160e4de5ff64bc861db0e694eaf9c78cdaab9..dcec88e2c76510091b178c5253e9a270c1f0cf81 100755 (executable)
import math, inkex, simplepath, sys
def pointAtPercent((x1, y1), (x2, y2), percent):
- percent /= 100.0
- x = x1 + (percent * (x2 - x1))
- y = y1 + (percent * (y2 - y1))
- return [x,y]
+ percent /= 100.0
+ x = x1 + (percent * (x2 - x1))
+ y = y1 + (percent * (y2 - y1))
+ return [x,y]
class SegmentStraightener(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-p", "--percent",
- action="store", type="float",
- dest="percent", default=10.0,
- help="move curve handles PERCENT percent closer to a straight line")
- self.OptionParser.add_option("-b", "--behavior",
- action="store", type="int",
- dest="behave", default=1,
- help="straightening behavior for cubic segments")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = simplepath.parsePath(d.value)
- last = []
- subPathStart = []
- for cmd,params in p:
- if cmd == 'C':
- if self.options.behave <= 1:
- #shorten handles towards end points
- params[:2] = pointAtPercent(params[:2],last[:],self.options.percent)
- params[2:4] = pointAtPercent(params[2:4],params[-2:],self.options.percent)
- else:
- #shorten handles towards thirds of the segment
- dest1 = pointAtPercent(last[:],params[-2:],33.3)
- dest2 = pointAtPercent(params[-2:],last[:],33.3)
- params[:2] = pointAtPercent(params[:2],dest1[:],self.options.percent)
- params[2:4] = pointAtPercent(params[2:4],dest2[:],self.options.percent)
- elif cmd == 'Q':
- dest = pointAtPercent(last[:],params[-2:],50)
- params[:2] = pointAtPercent(params[:2],dest,self.options.percent)
- if cmd == 'M':
- subPathStart = params[-2:]
- if cmd == 'Z':
- last = subPathStart[:]
- else:
- last = params[-2:]
- d.value = simplepath.formatPath(p)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-p", "--percent",
+ action="store", type="float",
+ dest="percent", default=10.0,
+ help="move curve handles PERCENT percent closer to a straight line")
+ self.OptionParser.add_option("-b", "--behavior",
+ action="store", type="int",
+ dest="behave", default=1,
+ help="straightening behavior for cubic segments")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = simplepath.parsePath(d.value)
+ last = []
+ subPathStart = []
+ for cmd,params in p:
+ if cmd == 'C':
+ if self.options.behave <= 1:
+ #shorten handles towards end points
+ params[:2] = pointAtPercent(params[:2],last[:],self.options.percent)
+ params[2:4] = pointAtPercent(params[2:4],params[-2:],self.options.percent)
+ else:
+ #shorten handles towards thirds of the segment
+ dest1 = pointAtPercent(last[:],params[-2:],33.3)
+ dest2 = pointAtPercent(params[-2:],last[:],33.3)
+ params[:2] = pointAtPercent(params[:2],dest1[:],self.options.percent)
+ params[2:4] = pointAtPercent(params[2:4],dest2[:],self.options.percent)
+ elif cmd == 'Q':
+ dest = pointAtPercent(last[:],params[-2:],50)
+ params[:2] = pointAtPercent(params[:2],dest,self.options.percent)
+ if cmd == 'M':
+ subPathStart = params[-2:]
+ if cmd == 'Z':
+ last = subPathStart[:]
+ else:
+ last = params[-2:]
+ d.value = simplepath.formatPath(p)
e = SegmentStraightener()
e.affect()
index 7ddfdf275fb74feb1e97d3c641e7b669d499f1c1..6f39170ebdc617a4b6d46f5c25f1ffdb7b4d015a 100755 (executable)
uuconv = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'pc':15.0}
def unittouu(string):
- unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
- param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
+ unit = re.compile('(%s)$' % '|'.join(uuconv.keys()))
+ param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
- p = param.match(string)
- u = unit.search(string)
- if p:
- retval = float(p.string[p.start():p.end()])
- else:
- retval = 0.0
- if u:
- try:
- return retval * uuconv[u.string[u.start():u.end()]]
- except KeyError:
- pass
- return retval
+ p = param.match(string)
+ u = unit.search(string)
+ if p:
+ retval = float(p.string[p.start():p.end()])
+ else:
+ retval = 0.0
+ if u:
+ try:
+ return retval * uuconv[u.string[u.start():u.end()]]
+ except KeyError:
+ pass
+ return retval
class Project(inkex.Effect):
def __init__(self):
inkex.Effect.__init__(self)
def effect(self):
- if len(self.options.ids) < 2:
- inkex.debug("Requires two selected paths. The second must be exctly four nodes long.")
- exit()
-
- #obj is selected second
- obj = self.selected[self.options.ids[0]]
- trafo = self.selected[self.options.ids[1]]
- if obj.tagName == 'path' and trafo.tagName == 'path':
- #distil trafo into four node points
- trafo = cubicsuperpath.parsePath(trafo.attributes.getNamedItem('d').value)
- trafo = [[Point(csp[1][0],csp[1][1]) for csp in subs] for subs in trafo][0][:4]
+ if len(self.options.ids) < 2:
+ inkex.debug("Requires two selected paths. The second must be exctly four nodes long.")
+ exit()
+
+ #obj is selected second
+ obj = self.selected[self.options.ids[0]]
+ trafo = self.selected[self.options.ids[1]]
+ if obj.tagName == 'path' and trafo.tagName == 'path':
+ #distil trafo into four node points
+ trafo = cubicsuperpath.parsePath(trafo.attributes.getNamedItem('d').value)
+ trafo = [[Point(csp[1][0],csp[1][1]) for csp in subs] for subs in trafo][0][:4]
- #vectors pointing away from the trafo origin
- self.t1 = Segment(trafo[0],trafo[1])
- self.t2 = Segment(trafo[1],trafo[2])
- self.t3 = Segment(trafo[3],trafo[2])
- self.t4 = Segment(trafo[0],trafo[3])
-
- #query inkscape about the bounding box of obj
- self.q = {'x':0,'y':0,'width':0,'height':0}
- file = self.args[-1]
- id = self.options.ids[0]
- for query in self.q.keys():
- f = os.popen("inkscape --query-%s --query-id=%s %s" % (query,id,file))
- self.q[query] = float(f.read())
- f.close()
- #glean document height from the SVG
- docheight = unittouu(inkex.xml.xpath.Evaluate('/svg/@height',self.document)[0].value)
- #Flip inkscapes transposed renderer coords
- self.q['y'] = docheight - self.q['y'] - self.q['height']
+ #vectors pointing away from the trafo origin
+ self.t1 = Segment(trafo[0],trafo[1])
+ self.t2 = Segment(trafo[1],trafo[2])
+ self.t3 = Segment(trafo[3],trafo[2])
+ self.t4 = Segment(trafo[0],trafo[3])
+
+ #query inkscape about the bounding box of obj
+ self.q = {'x':0,'y':0,'width':0,'height':0}
+ file = self.args[-1]
+ id = self.options.ids[0]
+ for query in self.q.keys():
+ f = os.popen("inkscape --query-%s --query-id=%s %s" % (query,id,file))
+ self.q[query] = float(f.read())
+ f.close()
+ #glean document height from the SVG
+ docheight = unittouu(inkex.xml.xpath.Evaluate('/svg/@height',self.document)[0].value)
+ #Flip inkscapes transposed renderer coords
+ self.q['y'] = docheight - self.q['y'] - self.q['height']
- #process path
- d = obj.attributes.getNamedItem('d')
- p = cubicsuperpath.parsePath(d.value)
- for subs in p:
- for csp in subs:
- csp[0] = self.trafopoint(csp[0])
- csp[1] = self.trafopoint(csp[1])
- csp[2] = self.trafopoint(csp[2])
- d.value = cubicsuperpath.formatPath(p)
+ #process path
+ d = obj.attributes.getNamedItem('d')
+ p = cubicsuperpath.parsePath(d.value)
+ for subs in p:
+ for csp in subs:
+ csp[0] = self.trafopoint(csp[0])
+ csp[1] = self.trafopoint(csp[1])
+ csp[2] = self.trafopoint(csp[2])
+ d.value = cubicsuperpath.formatPath(p)
- def trafopoint(self,(x,y)):
- #Transform algorithm thanks to Jose Hevia (freon)
- vector = Segment(Point(self.q['x'],self.q['y']),Point(x,y))
- xratio = abs(vector.delta_x())/self.q['width']
- yratio = abs(vector.delta_y())/self.q['height']
-
- horz = Segment(self.t1.pointAtRatio(xratio),self.t3.pointAtRatio(xratio))
- vert = Segment(self.t4.pointAtRatio(yratio),self.t2.pointAtRatio(yratio))
+ def trafopoint(self,(x,y)):
+ #Transform algorithm thanks to Jose Hevia (freon)
+ vector = Segment(Point(self.q['x'],self.q['y']),Point(x,y))
+ xratio = abs(vector.delta_x())/self.q['width']
+ yratio = abs(vector.delta_y())/self.q['height']
+
+ horz = Segment(self.t1.pointAtRatio(xratio),self.t3.pointAtRatio(xratio))
+ vert = Segment(self.t4.pointAtRatio(yratio),self.t2.pointAtRatio(yratio))
- p = intersectSegments(vert,horz)
- return [p['x'],p['y']]
+ p = intersectSegments(vert,horz)
+ return [p['x'],p['y']]
e = Project()
e.affect()
diff --git a/share/extensions/svg_and_media_zip_output.py b/share/extensions/svg_and_media_zip_output.py
index 09ecb5f99d596072ef5c977de9e8683b96cc2214..93bf2ebadc2fec7a8491fcb5d456958e12ce85b5 100644 (file)
TODO
- fix bug: not saving existing .zip after a Collect for Output is run
- this bug occurs because after running an effect extention the inkscape:output_extension is reset to svg.inkscape
- the file name is still xxx.zip. after saving again the file xxx.zip is written with a plain .svg which
- looks like a corrupt zip
+ this bug occurs because after running an effect extention the inkscape:output_extension is reset to svg.inkscape
+ the file name is still xxx.zip. after saving again the file xxx.zip is written with a plain .svg which
+ looks like a corrupt zip
- maybe add better extention
"""
import tempfile
class MyEffect(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
-
- self.documentDst=None
-
- def parseTmp(self,file=None):
- """Parse document in specified file or on stdin"""
- reader = inkex.xml.dom.ext.reader.Sax2.Reader()
- try:
- try:
- stream = open(file,'r')
- except:
- stream = open(self.args[-1],'r')
- except:
- stream = sys.stdin
- self.documentDst = reader.fromStream(stream)
- stream.close()
-
- def output(self):
- pass
-
- def effect(self):
-
- #get needed info from orig document
- ctx_orig = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
-
- ttmp_orig = inkex.xml.xpath.Evaluate('/svg',self.document, context=ctx_orig)
-
- docbase = ttmp_orig[0].attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docbase')
- docname = ttmp_orig[0].attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docname')
-
- orig_tmpfile = sys.argv[1]
-
- # create destination zip in same directory as the document
- z = zipfile.ZipFile(docbase.value + '/'+ docname.value + '.zip', 'w')
-
- #create os temp dir
- tmp_dir = tempfile.mkdtemp()
-
- #fixme replace whatever extention
- docstripped = docname.value.replace('.zip', '')
-
- #read tmpdoc and copy all images to temp dir
- for node in inkex.xml.xpath.Evaluate('//image',self.document, context=ctx_orig):
- self.collectAndZipImages(node, tmp_dir, docname, z)
-
- ##copy tmpdoc to tempdir
- dst_file = os.path.join(tmp_dir, docstripped)
- stream = open(dst_file,'w')
-
- inkex.xml.dom.ext.Print(self.document,stream)
-
- stream.close()
-
- z.write(dst_file.encode("latin-1"),docstripped.encode("latin-1")+'.svg')
- z.close()
-
- shutil.move(docbase.value + '/'+ docname.value + '.zip',docbase.value + '/'+ docname.value)
-
- shutil.rmtree(tmp_dir)
-
- def collectAndZipImages(self, node, tmp_dir, docname, z):
- xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
- if (xlink.value[:4]!='data'):
- absref=node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'absref')
-
- if (os.path.isfile(absref.value)):
- shutil.copy(absref.value,tmp_dir)
- z.write(absref.value.encode("latin-1"),os.path.basename(absref.value).encode("latin-1"))
-
- elif (os.path.isfile(tmp_dir + '/' + absref.value)):
- shutil.copy(tmp_dir + '/' + absref.value,tmp_dir)
- z.write(tmp_dir + '/' + absref.value.encode("latin-1"),os.path.basename(absref.value).encode("latin-1"))
-
- xlink.value = os.path.basename(absref.value)
- absref.value = os.path.basename(absref.value)
-
-
+ def __init__(self):
+ inkex.Effect.__init__(self)
+
+ self.documentDst=None
+
+ def parseTmp(self,file=None):
+ """Parse document in specified file or on stdin"""
+ reader = inkex.xml.dom.ext.reader.Sax2.Reader()
+ try:
+ try:
+ stream = open(file,'r')
+ except:
+ stream = open(self.args[-1],'r')
+ except:
+ stream = sys.stdin
+ self.documentDst = reader.fromStream(stream)
+ stream.close()
+
+ def output(self):
+ pass
+
+ def effect(self):
+
+ #get needed info from orig document
+ ctx_orig = inkex.xml.xpath.Context.Context(self.document,processorNss=inkex.NSS)
+
+ ttmp_orig = inkex.xml.xpath.Evaluate('/svg',self.document, context=ctx_orig)
+
+ docbase = ttmp_orig[0].attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docbase')
+ docname = ttmp_orig[0].attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'docname')
+
+ orig_tmpfile = sys.argv[1]
+
+ # create destination zip in same directory as the document
+ z = zipfile.ZipFile(docbase.value + '/'+ docname.value + '.zip', 'w')
+
+ #create os temp dir
+ tmp_dir = tempfile.mkdtemp()
+
+ #fixme replace whatever extention
+ docstripped = docname.value.replace('.zip', '')
+
+ #read tmpdoc and copy all images to temp dir
+ for node in inkex.xml.xpath.Evaluate('//image',self.document, context=ctx_orig):
+ self.collectAndZipImages(node, tmp_dir, docname, z)
+
+ ##copy tmpdoc to tempdir
+ dst_file = os.path.join(tmp_dir, docstripped)
+ stream = open(dst_file,'w')
+
+ inkex.xml.dom.ext.Print(self.document,stream)
+
+ stream.close()
+
+ z.write(dst_file.encode("latin-1"),docstripped.encode("latin-1")+'.svg')
+ z.close()
+
+ shutil.move(docbase.value + '/'+ docname.value + '.zip',docbase.value + '/'+ docname.value)
+
+ shutil.rmtree(tmp_dir)
+
+ def collectAndZipImages(self, node, tmp_dir, docname, z):
+ xlink = node.attributes.getNamedItemNS(inkex.NSS[u'xlink'],'href')
+ if (xlink.value[:4]!='data'):
+ absref=node.attributes.getNamedItemNS(inkex.NSS[u'sodipodi'],'absref')
+
+ if (os.path.isfile(absref.value)):
+ shutil.copy(absref.value,tmp_dir)
+ z.write(absref.value.encode("latin-1"),os.path.basename(absref.value).encode("latin-1"))
+
+ elif (os.path.isfile(tmp_dir + '/' + absref.value)):
+ shutil.copy(tmp_dir + '/' + absref.value,tmp_dir)
+ z.write(tmp_dir + '/' + absref.value.encode("latin-1"),os.path.basename(absref.value).encode("latin-1"))
+
+ xlink.value = os.path.basename(absref.value)
+ absref.value = os.path.basename(absref.value)
+
+
e = MyEffect()
e.affect()
index aa438e12142ea72d57451244e869c2246f483d2b..c74e7d71e53347186dd231c1b4697b52b8ed207a 100755 (executable)
--- a/share/extensions/wavy.py
+++ b/share/extensions/wavy.py
from random import *
def drawwave(samples, periods, width, height, left, top,
- fx = "sin(x)", fpx = "cos(x)", fponum = True):
-
- # step is the distance between nodes on x
- step = 2*pi / samples
- third = step / 3.0
-
- # coords and scales based on the source rect
- xoff = left
- yoff = top + (height / 2)
- scalex = width / (2*pi * periods)
- scaley = height / 2
- procx = lambda x: x * scalex + xoff
- procy = lambda y: y * scaley + yoff
-
- # functions specified by the user
- if fx != "":
- f = eval('lambda x: ' + fx)
- if fpx != "":
- fp = eval('lambda x: ' + fpx)
-
- # initialize function and derivative for 0;
- # they are carried over from one iteration to the next, to avoid extra function calculations
- y0 = f(0)
- if fponum == True: # numerical derivative, using 0.001*step as the small differential
- d0 = (f(0 + 0.001*step) - y0)/(0.001*step)
- else: # derivative given by the user
- d0 = fp(0)
-
- a = [] # path array
- a.append(['M',[procx(0.0), procy(y0)]]) # initial moveto
-
- for i in range(int(samples * periods)):
- x = i * step
- y1 = f(x + step)
- if fponum == True: # numerical derivative
- d1 = (y1 - f(x + step - 0.001*step))/(0.001*step)
- else: # derivative given by the user
- d1 = fp(x + step)
- # create curve
- a.append(['C',[procx(x + third), procy(y0 + (d0 * third)),
- procx(x + (step - third)), procy(y1 - (d1 * third)),
- procx(x + step), procy(y1)]])
- y0 = y1 # next segment's y0 is this segment's y1
- d0 = d1 # we assume the function is smooth everywhere, so carry over the derivative too
-
- return a
+ fx = "sin(x)", fpx = "cos(x)", fponum = True):
+
+ # step is the distance between nodes on x
+ step = 2*pi / samples
+ third = step / 3.0
+
+ # coords and scales based on the source rect
+ xoff = left
+ yoff = top + (height / 2)
+ scalex = width / (2*pi * periods)
+ scaley = height / 2
+ procx = lambda x: x * scalex + xoff
+ procy = lambda y: y * scaley + yoff
+
+ # functions specified by the user
+ if fx != "":
+ f = eval('lambda x: ' + fx)
+ if fpx != "":
+ fp = eval('lambda x: ' + fpx)
+
+ # initialize function and derivative for 0;
+ # they are carried over from one iteration to the next, to avoid extra function calculations
+ y0 = f(0)
+ if fponum == True: # numerical derivative, using 0.001*step as the small differential
+ d0 = (f(0 + 0.001*step) - y0)/(0.001*step)
+ else: # derivative given by the user
+ d0 = fp(0)
+
+ a = [] # path array
+ a.append(['M',[procx(0.0), procy(y0)]]) # initial moveto
+
+ for i in range(int(samples * periods)):
+ x = i * step
+ y1 = f(x + step)
+ if fponum == True: # numerical derivative
+ d1 = (y1 - f(x + step - 0.001*step))/(0.001*step)
+ else: # derivative given by the user
+ d1 = fp(x + step)
+ # create curve
+ a.append(['C',[procx(x + third), procy(y0 + (d0 * third)),
+ procx(x + (step - third)), procy(y1 - (d1 * third)),
+ procx(x + step), procy(y1)]])
+ y0 = y1 # next segment's y0 is this segment's y1
+ d0 = d1 # we assume the function is smooth everywhere, so carry over the derivative too
+
+ return a
class Wavy(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-p", "--periods",
- action="store", type="float",
- dest="periods", default=4.0,
- help="Periods (2*Pi each)")
- self.OptionParser.add_option("-s", "--samples",
- action="store", type="int",
- dest="samples", default=8,
- help="Samples per period")
- self.OptionParser.add_option("--fofx",
- action="store", type="string",
- dest="fofx", default="sin(x)",
- help="f(x) for plotting")
- self.OptionParser.add_option("--fponum",
- action="store", type="inkbool",
- dest="fponum", default=True,
- help="Calculate the first derivative numerically")
- self.OptionParser.add_option("--fpofx",
- action="store", type="string",
- dest="fpofx", default="cos(x)",
- help="f'(x) for plotting")
- def effect(self):
- for id, node in self.selected.iteritems():
- if node.tagName == 'rect':
- new = self.document.createElement('svg:path')
- x = float(node.attributes.getNamedItem('x').value)
- y = float(node.attributes.getNamedItem('y').value)
- w = float(node.attributes.getNamedItem('width').value)
- h = float(node.attributes.getNamedItem('height').value)
-
- s = node.attributes.getNamedItem('style').value
- new.setAttribute('style', s)
- try:
- t = node.attributes.getNamedItem('transform').value
- new.setAttribute('transform', t)
- except AttributeError:
- pass
- new.setAttribute('d', simplepath.formatPath(
- drawwave(self.options.samples,
- self.options.periods,
- w,h,x,y,
- self.options.fofx,
- self.options.fpofx,
- self.options.fponum)))
- node.parentNode.appendChild(new)
- node.parentNode.removeChild(node)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-p", "--periods",
+ action="store", type="float",
+ dest="periods", default=4.0,
+ help="Periods (2*Pi each)")
+ self.OptionParser.add_option("-s", "--samples",
+ action="store", type="int",
+ dest="samples", default=8,
+ help="Samples per period")
+ self.OptionParser.add_option("--fofx",
+ action="store", type="string",
+ dest="fofx", default="sin(x)",
+ help="f(x) for plotting")
+ self.OptionParser.add_option("--fponum",
+ action="store", type="inkbool",
+ dest="fponum", default=True,
+ help="Calculate the first derivative numerically")
+ self.OptionParser.add_option("--fpofx",
+ action="store", type="string",
+ dest="fpofx", default="cos(x)",
+ help="f'(x) for plotting")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ if node.tagName == 'rect':
+ new = self.document.createElement('svg:path')
+ x = float(node.attributes.getNamedItem('x').value)
+ y = float(node.attributes.getNamedItem('y').value)
+ w = float(node.attributes.getNamedItem('width').value)
+ h = float(node.attributes.getNamedItem('height').value)
+
+ s = node.attributes.getNamedItem('style').value
+ new.setAttribute('style', s)
+ try:
+ t = node.attributes.getNamedItem('transform').value
+ new.setAttribute('transform', t)
+ except AttributeError:
+ pass
+ new.setAttribute('d', simplepath.formatPath(
+ drawwave(self.options.samples,
+ self.options.periods,
+ w,h,x,y,
+ self.options.fofx,
+ self.options.fpofx,
+ self.options.fponum)))
+ node.parentNode.appendChild(new)
+ node.parentNode.removeChild(node)
e = Wavy()
e.affect()
index 4b234d0143f4b1d0a8f5ff3c0179449afe46bf35..b2014191708785d791a56b77c38a26e45772b35f 100644 (file)
import math, inkex, cubicsuperpath
class Whirl(inkex.Effect):
- def __init__(self):
- inkex.Effect.__init__(self)
- self.OptionParser.add_option("-x", "--centerx",
- action="store", type="float",
- dest="centerx", default=10.0,
- help="")
- self.OptionParser.add_option("-y", "--centery",
- action="store", type="float",
- dest="centery", default=0.0,
- help="")
- self.OptionParser.add_option("-t", "--whirl",
- action="store", type="float",
- dest="whirl", default=1.0,
- help="amount of whirl")
- self.OptionParser.add_option("-r", "--rotation",
- action="store", type="inkbool",
- dest="rotation", default=True,
- help="direction of rotation")
- def effect(self):
- for id, node in self.selected.iteritems():
- rotation = -1
- if self.options.rotation == True:
- rotation = 1
- whirl = self.options.whirl / 1000
- if node.tagName == 'path':
- d = node.attributes.getNamedItem('d')
- p = cubicsuperpath.parsePath(d.value)
- for sub in p:
- for csp in sub:
- for point in csp:
- point[0] -= self.options.centerx
- point[1] -= self.options.centery
- dist = math.sqrt((point[0] ** 2) + (point[1] ** 2))
- if dist != 0:
- a = rotation * dist * whirl
- theta = math.atan2(point[1], point[0]) + a
- point[0] = (dist * math.cos(theta))
- point[1] = (dist * math.sin(theta))
- point[0] += self.options.centerx
- point[1] += self.options.centery
- d.value = cubicsuperpath.formatPath(p)
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.OptionParser.add_option("-x", "--centerx",
+ action="store", type="float",
+ dest="centerx", default=10.0,
+ help="")
+ self.OptionParser.add_option("-y", "--centery",
+ action="store", type="float",
+ dest="centery", default=0.0,
+ help="")
+ self.OptionParser.add_option("-t", "--whirl",
+ action="store", type="float",
+ dest="whirl", default=1.0,
+ help="amount of whirl")
+ self.OptionParser.add_option("-r", "--rotation",
+ action="store", type="inkbool",
+ dest="rotation", default=True,
+ help="direction of rotation")
+ def effect(self):
+ for id, node in self.selected.iteritems():
+ rotation = -1
+ if self.options.rotation == True:
+ rotation = 1
+ whirl = self.options.whirl / 1000
+ if node.tagName == 'path':
+ d = node.attributes.getNamedItem('d')
+ p = cubicsuperpath.parsePath(d.value)
+ for sub in p:
+ for csp in sub:
+ for point in csp:
+ point[0] -= self.options.centerx
+ point[1] -= self.options.centery
+ dist = math.sqrt((point[0] ** 2) + (point[1] ** 2))
+ if dist != 0:
+ a = rotation * dist * whirl
+ theta = math.atan2(point[1], point[0]) + a
+ point[0] = (dist * math.cos(theta))
+ point[1] = (dist * math.sin(theta))
+ point[0] += self.options.centerx
+ point[1] += self.options.centery
+ d.value = cubicsuperpath.formatPath(p)
e = Whirl()
e.affect()